C userspace programs

This commit is contained in:
2025-09-04 23:20:30 +02:00
parent afa4d383e0
commit 90266f044b
51 changed files with 259 additions and 174 deletions

View File

@ -1,10 +1,15 @@
.PHONY: clean prepare cleanall iso base kernel user test .PHONY: clean prepare cleanall iso base kernel user test
ARCH ?= x86_64
kernel: kernel:
make -C kernel ROOT=$(PWD) all make -C kernel ARCH=$(ARCH) ROOT=$(PWD) all
user: user:
make -C user ROOT=$(PWD) all make -C user ARCH=$(ARCH) ROOT=$(PWD) all
ulib:
make -C ulib ARCH=$(ARCH) ROOT=$(PWD) all
prepare: prepare:
if [ ! -d limine ]; then \ if [ ! -d limine ]; then \
@ -18,8 +23,9 @@ cleanall:
rm -rf limine rm -rf limine
clean: clean:
make -C kernel ROOT=$(PWD) clean make -C kernel ARCH=$(ARCH) ROOT=$(PWD) clean
make -C user ROOT=$(PWD) clean make -C user ARCH=$(ARCH) ROOT=$(PWD) clean
make -C ulib ARCH=$(ARCH) ROOT=$(PWD) clean
rm -f mop2.iso base.img rm -f mop2.iso base.img
base: base:

View File

@ -2,14 +2,14 @@ include $(ROOT)/mk/grabsrc.mk
.PHONY: all clean .PHONY: all clean
ARCH ?= x86_64
PUTCHAR_ ?= fb PUTCHAR_ ?= fb
CFLAGS := -ffreestanding -Wall -Wextra -g -fcommon -nostdinc CFLAGS := -ffreestanding -Wall -Wextra -g -fcommon -nostdinc
CFLAGS += -I. \ CFLAGS += -I. \
-I$(ROOT)/limine \ -I$(ROOT)/limine \
-I./std/include \ -I$(ROOT)/std/include \
-I./std \
-I./flanterm/src \ -I./flanterm/src \
-DPRINTF_INCLUDE_CONFIG_H=1 \ -DPRINTF_INCLUDE_CONFIG_H=1 \
-DLFS_NO_ASSERT \ -DLFS_NO_ASSERT \

View File

@ -1,5 +1,4 @@
CC := x86_64-elf-gcc include $(ROOT)/mk/arch/toolchain-x86_64.mk
LD := x86_64-elf-ld
CFLAGS += -m64 \ CFLAGS += -m64 \
-fPIE \ -fPIE \

View File

@ -6,8 +6,6 @@
#include "hal/hal.h" #include "hal/hal.h"
#include "bootinfo/bootinfo.h" #include "bootinfo/bootinfo.h"
LocalCpuData HAL_CPUS[HAL_CPUS_MAX];
uint64_t hal_cpu_rdmsr(uint32_t id) { uint64_t hal_cpu_rdmsr(uint32_t id) {
uint32_t lo, hi; uint32_t lo, hi;
asm volatile("rdmsr" : "=a"(lo), "=d"(hi) : "c"(id)); asm volatile("rdmsr" : "=a"(lo), "=d"(hi) : "c"(id));
@ -21,8 +19,3 @@ uint64_t hal_cpu_wrmsr(uint32_t id, uint64_t val) {
return val; return val;
} }
void hal_cpu_init(uint32_t cpu) {
void *addr = pmm_alloc(16) + (16 * HAL_PAGE_SIZE);
HAL_CPUS[cpu].syscall_kstack = (uint64_t *)VIRT(addr);
HAL_CPUS[cpu].kcr3 = hal_vmm_current_cr3();
}

View File

@ -13,24 +13,13 @@
#define HAL_CPU_STAR 0xC0000081 #define HAL_CPU_STAR 0xC0000081
#define HAL_CPU_LSTAR 0xC0000082 #define HAL_CPU_LSTAR 0xC0000082
#define HAL_CPU_CSTAR 0xC0000083 #define HAL_CPU_CSTAR 0xC0000083
#define HAL_CPU_SFMASK 0xC0000084 #define HAL_CPU_FMASK 0xC0000084
#define HAL_CPU_FSBASE 0xC0000100 #define HAL_CPU_FSBASE 0xC0000100
#define HAL_CPU_GSBASE 0xC0000101 #define HAL_CPU_GSBASE 0xC0000101
#define HAL_CPU_KGSBASE 0xC0000102 #define HAL_CPU_KGSBASE 0xC0000102
typedef struct {
uint64_t *syscall_kstack;
uint64_t *syscall_ustack;
PgTable *kcr3;
PgTable *pcr3;
IntrStackFrame *frame;
} PACKED LocalCpuData;
uint64_t hal_cpu_rdmsr(uint32_t id); uint64_t hal_cpu_rdmsr(uint32_t id);
uint64_t hal_cpu_wrmsr(uint32_t id, uint64_t val); uint64_t hal_cpu_wrmsr(uint32_t id, uint64_t val);
void hal_cpu_init(uint32_t cpu);
extern LocalCpuData HAL_CPUS[HAL_CPUS_MAX];
#endif // HAL_CPU_H_ #endif // HAL_CPU_H_

View File

@ -9,7 +9,6 @@
#include "pic.h" #include "pic.h"
#include "apic.h" #include "apic.h"
#include "pit.h" #include "pit.h"
#include "syscall.h"
void hal_init(void) { void hal_init(void) {
if (!serial_init()) { if (!serial_init()) {
@ -33,7 +32,6 @@ void hal_init_withmalloc(void) {
pit_init(); pit_init();
ioapic_setentry(IOAPIC, acpi_remapirq(0x00), INTR_TIMER); ioapic_setentry(IOAPIC, acpi_remapirq(0x00), INTR_TIMER);
hal_intr_disable(); hal_intr_disable();
hal_syscall_init();
} }
void hal_wait(uint32_t ms) { void hal_wait(uint32_t ms) {

View File

@ -11,6 +11,8 @@
#include "apic.h" #include "apic.h"
#include "pit.h" #include "pit.h"
#include "proc/proc.h" #include "proc/proc.h"
#include "syscall/syscall.h"
#include "errors.h"
void hal_intr_disable(void) { void hal_intr_disable(void) {
asm volatile("cli"); asm volatile("cli");
@ -122,6 +124,9 @@ void intr_init(void) {
MKINTR(45, 0); MKINTR(45, 0);
MKINTR(46, 0); MKINTR(46, 0);
MKINTR(47, 0); MKINTR(47, 0);
extern void intr_vec128(void);
idt_setentry(0x80, (uint64_t)&intr_vec128, 0, 0xEE);
idt_init(); idt_init();
} }
@ -149,14 +154,33 @@ void intr_dumpframe(IntrStackFrame *frame) {
); );
} }
void hal_syscalldispatch(IntrStackFrame *frame) {
uint64_t sysnum = frame->regs.rax;
if (sysnum < SYSCALLS_MAX) {
SyscallFn fn = SYSCALL_TABLE[sysnum];
if (fn == NULL) {
frame->regs.rax = E_BADSYSCALL;
return;
}
int32_t ret = fn(frame->regs.rdi, frame->regs.rsi, frame->regs.rdx,
frame->regs.r10, frame->regs.r8, frame->regs.r9);
if (sysnum == SYS_QUITPROC) {
proc_sched((void *)frame);
}
frame->regs.rax = *(uint64_t *)&ret;
}
}
void intr_handleintr(IntrStackFrame *frame) { void intr_handleintr(IntrStackFrame *frame) {
if (frame->trapnum <= 31) { if (frame->trapnum <= 31) {
kprintf("ERROR %s, 0x%lX\n", exceptions[frame->trapnum], frame->errnum);
intr_dumpframe(frame);
if (frame->trapnum == 14 && frame->errnum & 0x4) { if (frame->trapnum == 14 && frame->errnum & 0x4) {
kprintf("killed pid %ld %s\n", PROCS.current->pid, PROCS.current->name);
proc_killself(); proc_killself();
proc_sched((void *)frame); proc_sched((void *)frame);
} }
kprintf("ERROR %s, 0x%lX\n", exceptions[frame->trapnum], frame->errnum);
intr_dumpframe(frame);
hal_hang(); hal_hang();
} else if (frame->trapnum >= 32 && frame->trapnum <= 47) { } else if (frame->trapnum >= 32 && frame->trapnum <= 47) {
if (frame->trapnum == INTR_TIMER) { if (frame->trapnum == INTR_TIMER) {
@ -167,6 +191,8 @@ void intr_handleintr(IntrStackFrame *frame) {
lapic_write(LAPIC_EOI, 0x00); lapic_write(LAPIC_EOI, 0x00);
proc_sched((void *)frame); proc_sched((void *)frame);
} else if (frame->trapnum == 0x80) {
hal_syscalldispatch(frame);
} }
} }

View File

@ -50,6 +50,7 @@
.global intr_vec45 .global intr_vec45
.global intr_vec46 .global intr_vec46
.global intr_vec47 .global intr_vec47
.global intr_vec128
.macro _vecintr_errorcode_present_save num .macro _vecintr_errorcode_present_save num
pushq $\num pushq $\num
@ -215,3 +216,6 @@ intr_vec46:
intr_vec47: intr_vec47:
_vecintr_plain_save 47 _vecintr_plain_save 47
_vecintr_bodygen _vecintr_bodygen
intr_vec128:
_vecintr_plain_save 128
_vecintr_bodygen

View File

@ -1,43 +0,0 @@
#include <stdint.h>
#include "syscall.h"
#include "cpu.h"
#include "intr.h"
#include "syscall/syscall.h"
#include "proc/proc.h"
#include "kprintf.h"
#include "errors.h"
extern void hal_enable_syscallentry(void);
extern void hal_syscallentry(void);
void hal_syscalldispatch(IntrStackFrame *frame) {
uint64_t sysnum = frame->regs.rax;
if (sysnum < SYSCALLS_MAX) {
SyscallFn fn = SYSCALL_TABLE[sysnum];
if (fn == NULL) {
frame->regs.rax = E_BADSYSCALL;
return;
}
int32_t ret = fn(frame->regs.rdi, frame->regs.rsi, frame->regs.rdx,
frame->regs.r10, frame->regs.r8, frame->regs.r9);
if (sysnum == SYS_QUITPROC) {
proc_sched((void *)frame);
}
frame->regs.rax = *(uint64_t *)&ret;
}
}
void hal_syscall_init(void) {
hal_cpu_init(0);
LocalCpuData *lcd = &HAL_CPUS[0];
hal_cpu_wrmsr(HAL_CPU_EFER, hal_cpu_rdmsr(HAL_CPU_EFER) | 0x1);
hal_enable_syscallentry();
hal_cpu_wrmsr(HAL_CPU_GSBASE, (uint64_t)lcd);
hal_cpu_wrmsr(HAL_CPU_KGSBASE, (uint64_t)lcd);
hal_cpu_wrmsr(HAL_CPU_SFMASK, (uint64_t)0);
hal_cpu_wrmsr(HAL_CPU_LSTAR, (uint64_t)&hal_syscallentry);
}

View File

@ -1,6 +0,0 @@
#ifndef HAL_SYSCALL_H_
#define HAL_SYSCALL_H_
void hal_syscall_init(void);
#endif // HAL_SYSCALL_H_

View File

@ -1,48 +0,0 @@
#include "regs.S"
.extern hal_syscalldispatch
.global hal_enable_syscallentry
hal_enable_syscallentry:
movq $0xC0000080, %rcx
rdmsr
or $0x1, %eax
wrmsr
movq $0xC0000081, %rcx
rdmsr
movl $0x180008, %edx
wrmsr
ret
.global hal_syscallentry
hal_syscallentry:
cli
swapgs
movq %rsp, %gs:0x8
movq %gs:0x0, %rsp
pushq $0x23
pushq %gs:0x8
swapgs
pushq %r11
pushq $0x1b
pushq %rcx
_push_regs
mov %rsp, %rdi
mov $0x0, %rbp
call hal_syscalldispatch
cli
_pop_regs
popq %rcx
add $0x8, %rsp
popq %r11
popq %rsp
sysret

View File

@ -155,7 +155,7 @@ Proc *proc_spawnuser(char *mountpoint, char *path) {
ElfAuxval aux = proc_load_elf_segs(proc, data); ElfAuxval aux = proc_load_elf_segs(proc, data);
proc->platformdata.trapframe.ss = 0x20 | 0x3; proc->platformdata.trapframe.ss = 0x20 | 0x3;
proc->platformdata.trapframe.rsp = (uint64_t)VIRT(sp); proc->platformdata.trapframe.rsp = (uint64_t)sp;
proc->platformdata.trapframe.rflags = 0x202; proc->platformdata.trapframe.rflags = 0x202;
proc->platformdata.trapframe.cs = 0x18 | 0x3; proc->platformdata.trapframe.cs = 0x18 | 0x3;
proc->platformdata.trapframe.rip = aux.entry; proc->platformdata.trapframe.rip = aux.entry;
@ -231,13 +231,10 @@ void proc_sched(void *cpustate) {
IntrStackFrame *frame = cpustate; IntrStackFrame *frame = cpustate;
PROCS.current->platformdata.trapframe = *frame; PROCS.current->platformdata.trapframe = *frame;
PROCS.current->platformdata.fsbase = hal_cpu_rdmsr(HAL_CPU_FSBASE);
PROCS.current = proc_nextready(); PROCS.current = proc_nextready();
PROCS.current->state = PROC_RUNNING; PROCS.current->state = PROC_RUNNING;
hal_cpu_wrmsr(HAL_CPU_FSBASE, PROCS.current->platformdata.fsbase);
HAL_CPUS[0].syscall_kstack = VIRT(PROCS.current->platformdata.kstack);
hal_switchproc(&PROCS.current->platformdata.trapframe, (void *)PROCS.current->platformdata.cr3); hal_switchproc(&PROCS.current->platformdata.trapframe, (void *)PROCS.current->platformdata.cr3);
} }
@ -282,8 +279,8 @@ void proc_init(void) {
proc_register(idle); proc_register(idle);
PROCS.current = idle; PROCS.current = idle;
proc_register(proc_spawnkern(&proc_status, "status")); /* proc_register(proc_spawnkern(&proc_status, "status")); */
proc_register(proc_spawnuser("base", "/bin/hello")); proc_register(proc_spawnuser("base", "/bin/init"));
hal_switchproc(&PROCS.current->platformdata.trapframe, (void *)PROCS.current->platformdata.cr3); hal_switchproc(&PROCS.current->platformdata.trapframe, (void *)PROCS.current->platformdata.cr3);
} }

View File

@ -14,7 +14,6 @@
#define PROC_MAX 0x100 // max amount of processes #define PROC_MAX 0x100 // max amount of processes
typedef struct { typedef struct {
uint64_t fsbase;
IntrStackFrame trapframe; IntrStackFrame trapframe;
uint8_t *kstack; uint8_t *kstack;
PgTable *cr3; PgTable *cr3;

View File

@ -5,14 +5,9 @@
#include "kprintf.h" #include "kprintf.h"
#include "proc/proc.h" #include "proc/proc.h"
int32_t SYSCALL2(sys_debugprint, string1, len) { int32_t SYSCALL1(sys_debugprint, string) {
char *buf = dlmalloc(len); char *p = (char *)string;
if (buf == NULL) { kprintf("%s\n", p);
return E_NOMEMORY;
}
ksnprintf(buf, len, "%s", string1);
kprintf("%s\n", buf);
dlfree(buf);
return E_OK; return E_OK;
} }

View File

@ -0,0 +1,3 @@
CC := x86_64-elf-gcc
LD := x86_64-elf-ld
AR := x86_64-elf-ar

13
mk/user/x86_64.mk Normal file
View File

@ -0,0 +1,13 @@
CFLAGS += -m64 \
-fPIE \
-mno-80387 \
-mno-mmx \
-mno-sse \
-nostartfiles \
-nostdlib \
-mno-sse2 \
-mno-red-zone \
-fno-stack-protector \
-fno-stack-check \
-fno-builtin \
-Os \

View File

@ -1,3 +1,3 @@
#!/bin/sh #!/bin/sh
make -B kernel && make -B user && make base && make iso make -B kernel && make -B ulib && make -B user && make base && make iso

View File

@ -20,6 +20,6 @@
#define atomic_compare_exchange_strong(p, old, new) \ #define atomic_compare_exchange_strong(p, old, new) \
__atomic_compare_exchange_n(p, old, new, false, memory_order_relaxed, memory_order_relaxed) __atomic_compare_exchange_n(p, old, new, false, memory_order_relaxed, memory_order_relaxed)
#define atomic_bool volatile bool #define atomic_bool _Atomic(bool)
#endif #endif

1
ulib/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.o

33
ulib/Makefile Normal file
View File

@ -0,0 +1,33 @@
include $(ROOT)/mk/grabsrc.mk
include $(ROOT)/mk/arch/toolchain-$(ARCH).mk
include $(ROOT)/mk/user/$(ARCH).mk
.PHONY: all clean
SRCFILES := $(call GRABSRC, \
. \
syscall \
string \
system \
)
CFLAGS += -isystem $(ROOT)/ulib -isystem $(ROOT)/std/include
ASFILES := $(call GET_ASFILES, $(SRCFILES))
CFILES := $(call GET_CFILES, $(SRCFILES))
OBJ := $(call GET_OBJ, $(SRCFILES))
%.o: %.S
$(CC) $(CFLAGS) -c $< -o $@
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
libulib.a: $(OBJ)
$(AR) rcs libulib.a $(OBJ)
all: libulib.a
clean:
rm -f $(OBJ)
rm -f libulib.a

22
ulib/_premain.c Normal file
View File

@ -0,0 +1,22 @@
#include <stdint.h>
#include <stddef.h>
extern void main(void);
extern uint8_t _bss_start[];
extern uint8_t _bss_end[];
void bss_clear(void) {
uint8_t *p = _bss_start;
while (p != _bss_end) {
*p = 0;
p++;
}
}
// ulib initialization goes here
void _premain(void) {
bss_clear();
main();
}

10
ulib/_start.S Normal file
View File

@ -0,0 +1,10 @@
#include <syscall/syscall.h>
.extern _premain
.global _start
_start:
call _premain
mov $SYS_QUITPROC, %rax
int $0x80

BIN
ulib/libulib.a Normal file

Binary file not shown.

11
ulib/string/string.c Normal file
View File

@ -0,0 +1,11 @@
#include <stddef.h>
#include <string/string.h>
size_t string_len(const char *s) {
size_t l = 0;
while (*s != '\0') {
l++;
s++;
}
return l;
}

8
ulib/string/string.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef ULIB_STRING_STRING_H_
#define ULIB_STRING_STRING_H_
#include <stddef.h>
size_t string_len(const char *s);
#endif // ULIB_STRING_STRING_H_

27
ulib/syscall/syscall.c Normal file
View File

@ -0,0 +1,27 @@
#include <stdint.h>
uint64_t syscall(uint64_t num, uint64_t arg1, uint64_t arg2,
uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6) {
uint64_t ret = 0;
asm volatile (
"mov %[SYSNUM], %%rax\n"
"mov %[ARG1], %%rdi\n"
"mov %[ARG2], %%rsi\n"
"mov %[ARG3], %%rdx\n"
"mov %[ARG4], %%r10\n"
"mov %[ARG5], %%r8\n"
"mov %[ARG6], %%r9\n"
"int $0x80\n"
"mov %%rax, %[RESULT]\n"
: [RESULT]"=r"(ret)
: [SYSNUM]"r"(num),
[ARG1]"r"(arg1),
[ARG2]"r"(arg2),
[ARG3]"r"(arg3),
[ARG4]"r"(arg4),
[ARG5]"r"(arg5),
[ARG6]"r"(arg6)
: "%rax", "%rdi", "%rsi", "%rdx", "%r10", "%r8", "%r9", "memory"
);
return ret;
}

14
ulib/syscall/syscall.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef ULIB_SYSCALL_SYSCALL_H_
#define ULIB_SYSCALL_SYSCALL_H_
#define SYS_DEBUGPRINT 1
#define SYS_QUITPROC 2
#if !defined(__ASSEMBLER__)
uint64_t syscall(uint64_t num, uint64_t arg1, uint64_t arg2,
uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6);
#endif // ! __ASSEMBLER__
#endif // ULIB_SYSCALL_SYSCALL_H_

9
ulib/system/system.c Normal file
View File

@ -0,0 +1,9 @@
#include <stdint.h>
#include <system/system.h>
#include <syscall/syscall.h>
void sys_debugprint(const char *string) {
syscall(SYS_DEBUGPRINT, (uint64_t)string, 0, 0, 0, 0, 0);
}

6
ulib/system/system.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef ULIB_SYSTEM_SYSTEM_H_
#define ULIB_SYSTEM_SYSTEM_H_
void sys_debugprint(const char *string);
#endif // ULIB_SYSTEM_SYSTEM_H_

View File

@ -1,6 +1,5 @@
ARCH ?= x86_64 CFLAGS := -ffreestanding -Wall -Wextra -g -fcommon -nostdinc \
-isystem $(ROOT)/std/include -isystem $(ROOT)/ulib
CFLAGS := -ffreestanding -Wall -Wextra -g -fcommon -nostdinc
CURRENT_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) CURRENT_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))

View File

@ -1,17 +1,17 @@
ENTRY(_start) ENTRY(_start)
SECTIONS { SECTIONS {
. = 0x0000000000000000; /* . = 0x0000000000000000; */
.rodata ALIGN(4K):
{
*(.rodata .rodata.*)
}
.text ALIGN(4K): .text ALIGN(4K):
{ {
*(.text .text.*) *(.text .text.*)
} }
.rodata (READONLY): ALIGN(4K)
{
*(.rodata .rodata.*)
}
.data ALIGN(4K): .data ALIGN(4K):
{ {
@ -20,6 +20,8 @@ SECTIONS {
.bss ALIGN(4K): .bss ALIGN(4K):
{ {
_bss_start = .;
*(.bss .bss.*) *(.bss .bss.*)
_bss_end = .;
} }
} }

View File

@ -1,18 +1,5 @@
CC := x86_64-elf-gcc include $(ROOT)/mk/user/x86_64.mk
LD := x86_64-elf-ld include $(ROOT)/mk/arch/toolchain-x86_64.mk
CFLAGS += -m64 \
-fPIE \
-mno-80387 \
-mno-mmx \
-mno-sse \
-nostartfiles \
-nostdlib \
-mno-sse2 \
-mno-red-zone \
-fno-stack-protector \
-fno-stack-check \
-Os \
LDFLAGS += -m elf_x86_64 \ LDFLAGS += -m elf_x86_64 \
-pie \ -pie \

View File

@ -14,9 +14,9 @@ OBJ := $(call GET_OBJ, $(SRCFILES))
all: $(TARGET) all: $(TARGET)
hello: $(OBJ) $(TARGET): $(OBJ)
$(LD) $^ $(LDFLAGS) -o $@ $(LD) $^ $(LDFLAGS) -o $@
echo $(realpath hello) >> $(FILES) echo $$(realpath $(TARGET)) >> $(FILES)
clean: clean:
rm -f $(OBJ) $(TARGET) rm -f $(OBJ) $(TARGET)

View File

@ -11,8 +11,7 @@ _start:
movq $1, %rax movq $1, %rax
lea STRING(%rip), %rdi lea STRING(%rip), %rdi
lea STRING_LEN(%rip), %rsi lea STRING_LEN(%rip), %rsi
syscall int $0x80
movq $2, %rax movq $2, %rax
syscall int $0x80

2
user/init/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.o
init

24
user/init/Makefile Normal file
View File

@ -0,0 +1,24 @@
include $(ROOT)/mk/grabsrc.mk
include ../Makefile.inc
.PHONY: all clean
TARGET := init
LDFLAGS += -L$(ROOT)/ulib -l:libulib.a
SRCFILES := $(call GRABSRC, .)
CFILES := $(call GET_CFILES, $(SRCFILES))
OBJ := $(call GET_OBJ, $(SRCFILES))
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
all: $(TARGET)
$(TARGET): $(OBJ)
$(LD) $^ $(LDFLAGS) -o $@
echo $$(realpath $(TARGET)) >> $(FILES)
clean:
rm -f $(OBJ) $(TARGET)

6
user/init/main.c Normal file
View File

@ -0,0 +1,6 @@
#include <system/system.h>
void main(void) {
sys_debugprint("Hello world from userspace in C");
}