commit 17683e896fc6162a038d5fb2711ca94055188dfb from: Onana Onana Xavier Manuel date: Fri Sep 11 08:36:44 2026 UTC xhci server is now loaded into memory. Added local apic timer interrupt with idt entry to handle it. commit - e5731e19a513e6a92d2b1d5dd1e57d1ef9c0a632 commit + 17683e896fc6162a038d5fb2711ca94055188dfb blob - f1119d53a193b4a502931fdab8067c0e0c8ea8bf blob + 89788503a89a7d78c692d45b4e8240c5b2eaa64f --- alpha/main.c +++ alpha/main.c @@ -4,6 +4,7 @@ #include "syscalls/syscalls.h" #define MAX_TASKS 64 +#define XHCI_ENTRY 0xC00000 struct task { u8 assigned; @@ -15,17 +16,24 @@ struct task { static struct task tasks[MAX_TASKS]; static void send_msg(const u8 *); -static struct task* task_new(void); +static struct task* task_new(void *); void alpha_main(struct mmap *km) { - struct task *p = task_new(); + struct task *t = task_new((void *)XHCI_ENTRY); + struct sysc_context_switch scs; - if (p == nil) - send_msg("Alpha: failed to create task!\n"); + if (t == nil) + send_msg("alpha: failed to create task!\n"); - send_msg("Alpha: running\n"); + send_msg("alpha: running\n"); + + scs.sysc.type = SYSC_CONTEXT_SWITCH; + scs.threadid = t->thread; + + sys_send((struct sysc *)&scs); + for (;;); } @@ -39,11 +47,22 @@ send_msg (const u8 *msg) } static struct task* -task_new() +task_new(void *entry) { + struct sysc_new_thread snt; + + snt.sysc.type = SYSC_NEW_THREAD; + snt.entry = entry; + for (int i = 0; i < MAX_TASKS; i++) { if (tasks[i].assigned == 0) { + sys_send((struct sysc *)&snt); + + if (snt.retid == -1) + break; + tasks[i].assigned = 1; + tasks[i].thread = snt.retid; return &tasks[i]; } } blob - bffe5353e7d660182869ce421266cdebae9f98f8 blob + 206e351a6d3de7a304a5f92746e4f0296d04920a --- boot.s +++ boot.s @@ -8,6 +8,8 @@ start: ; Safety first! xor ax, ax mov ds, ax + mov es, ax + mov ss, ax mov sp, 0x7c00 ; Stack under boot sector ; Save drive on boot and check LBA support blob - a807dab563e01d327f6db6396f87182ce01d29fe blob + ec4e1f9a0f50deb7371b258265b8470d750e8dec --- boot2.s +++ boot2.s @@ -19,6 +19,9 @@ start: mov si, alpha_dap call load_dap + mov si, xhci_dap + call load_dap + ; Loading e820 blocks and values at kernel's entry ; ; Segmentation is required due to Real Mode limited @@ -90,6 +93,14 @@ alpha_dap: dw ALPHA_LOAD_ADDR >> 4 dq 1 + STAGE2_SECTORS + KERNEL_SECTORS +xhci_dap: + db 0x10 + db 0 + dw XHCI_SECTORS + dw 0 + dw XHCI_LOAD_ADDR >> 4 + dq 1 + STAGE2_SECTORS + KERNEL_SECTORS + ALPHA_SECTORS + load_dap: mov dl, [boot_drive] mov ah, 0x42 @@ -208,6 +219,12 @@ protected_mode: mov ecx, (ALPHA_SECTORS * 512) / 4 rep movsd + ; Copy xhci + mov esi, XHCI_LOAD_ADDR + mov edi, XHCI_ENTRY + mov ecx, (XHCI_SECTORS * 512) / 4 + rep movsd + ; Update kernel module mov DWORD [BINFO_KERNEL_ADDR], KERNEL_ENTRY mov DWORD [BINFO_KERNEL_ADDR + 4], KERNEL_SECTORS * 512 @@ -215,6 +232,10 @@ protected_mode: ; Update alpha module mov DWORD [BINFO_ALPHA_ADDR], ALPHA_ENTRY mov DWORD [BINFO_ALPHA_ADDR + 4], ALPHA_SECTORS * 32 + + ; Update xhci module + mov DWORD [BINFO_XHCI_ADDR], XHCI_ENTRY + mov DWORD [BINFO_XHCI_ADDR + 4], XHCI_SECTORS * 32 ; Check for longmode support mov eax, 0x80000000 @@ -334,6 +355,7 @@ long_phase: mov rsp, 0x90000 mov rdi, BINFO_ADDR ; Kernel info + movzx rsi, byte [abs boot_drive] mov rax, KERNEL_ENTRY jmp rax @@ -343,7 +365,7 @@ align 512, db 0 end: STAGE2_SECTORS equ (end - start) / 512 -E820_COUNT_ADDR equ BINFO_ALPHA_ADDR + 8 +E820_COUNT_ADDR equ BINFO_XHCI_ADDR + 8 E820_PTR_ADDR equ E820_COUNT_ADDR + 8 E820_BLOCK_ADDR equ E820_PTR_ADDR + 8 blob - 8a3993143a938b35c65caf3c670a52119187d2d2 blob + 56896c243a94edf9e13fba720973564503dbf7c1 --- build.sh +++ build.sh @@ -22,6 +22,10 @@ ALPHA_BIN=alpha/alpha.bin ALPHA_SIZE=$(wc -c < $ALPHA_BIN) ALPHA_SECTORS=$(( (ALPHA_SIZE + SECTOR_SIZE - 1) / SECTOR_SIZE)) +XHCI_BIN=servers/xhci/xhci.bin +XHCI_SIZE=$(wc -c < $XHCI_BIN) +XHCI_SECTORS=$(( (XHCI_SIZE + SECTOR_SIZE - 1) / SECTOR_SIZE)) + echo "$OS_NAME: building" nasm -f elf64 -o io.o $KERNEL_DIR/io.s @@ -48,7 +52,7 @@ ld \ sysentry.o kthreads.o KSIZE=$(wc -c < kerneli.bin) -KSECTORS=$(( (KSIZE + SECTOR_SIZE - 1) / SECTOR_SIZE + 1)) # Extra sector +KSECTORS=$(( (KSIZE + SECTOR_SIZE - 1) / SECTOR_SIZE + 2)) # Extra sector KSIZE=$((KSECTORS * SECTOR_SIZE)) cat kerneli.bin /dev/zero | dd of=kernel.bin bs=$KSIZE count=1 @@ -58,11 +62,15 @@ nasm \ -D ALPHA_SECTORS=$ALPHA_SECTORS \ -D KERNEL_ENTRY=$KERNEL_ENTRY \ -D ALPHA_ENTRY=$ALPHA_ENTRY \ + -D XHCI_ENTRY=$XHCI_ENTRY \ + -D XHCI_SECTORS=$XHCI_SECTORS \ -D BINFO_ADDR=$BINFO_ADDR \ -D KERNEL_LOAD_ADDR=$KERNEL_LOAD_ADDR \ -D ALPHA_LOAD_ADDR=$ALPHA_LOAD_ADDR \ + -D XHCI_LOAD_ADDR=$XHCI_LOAD_ADDR \ -D BINFO_KERNEL_ADDR=$BINFO_KERNEL_ADDR \ -D BINFO_ALPHA_ADDR=$BINFO_ALPHA_ADDR \ + -D BINFO_XHCI_ADDR=$BINFO_XHCI_ADDR \ boot2.s -o boot2.bin STAGE2_SIZE=$(wc -c < boot2.bin) @@ -71,21 +79,12 @@ STAGE2_SIZE=$((STAGE2_SECTORS * SECTOR_SIZE)) BOOT_SECTORS=$((STAGE2_SECTORS + 1)) # Boot sector is 1 sector so we add BOOT_SIZE=$((BOOT_SECTORS * SECTOR_SIZE)) -IMGSIZE=$(((KSECTORS * SECTOR_SIZE) + BOOT_SIZE + ALPHA_SIZE)) +IMGSIZE=$(((KSECTORS * SECTOR_SIZE) + BOOT_SIZE + ALPHA_SIZE + XHCI_SIZE)) -nasm \ - -D STAGE2_SECTORS=$STAGE2_SECTORS \ - -D KERNEL_SECTORS=$KSECTORS \ - -D ALPHA_SECTORS=$ALPHA_SECTORS \ - -D KERNEL_LOAD_ADDR=$KERNEL_LOAD_ADDR \ - -D ALPHA_LOAD_ADDR=$ALPHA_LOAD_ADDR \ - -D BINFO_ADDR=$BINFO_ADDR \ - -D BINFO_KERNEL_ADDR=$BINFO_KERNEL_ADDR \ - -D BINFO_ALPHA_ADDR=$BINFO_ALPHA_ADDR \ - boot.s -o boot.bin +nasm -D STAGE2_SECTORS=$STAGE2_SECTORS boot.s -o boot.bin cat boot2.bin /dev/zero | dd of=boot2i.bin bs=$STAGE2_SIZE count=1 -cat boot.bin boot2i.bin kernel.bin $ALPHA_BIN /dev/zero | dd of=$OS_NAME bs=$IMGSIZE count=1 +cat boot.bin boot2i.bin kernel.bin $ALPHA_BIN $XHCI_BIN /dev/zero | dd of=$OS_NAME bs=$IMGSIZE count=1 # This is so qemu doesn't bother us but really the OS is not that size if (( IMG_SIZE < 0x100000 )) then blob - 954a99bc381daa4b70b5b6f0b7dd6fae9e8d1040 blob + fa5d1ad7b193b5c6d07d406a9aaaac250743e385 --- include +++ include @@ -23,3 +23,4 @@ XHCI_ENTRY=0xC00000 BINFO_ADDR=0x20000 BINFO_KERNEL_ADDR=$((BINFO_ADDR)) BINFO_ALPHA_ADDR=$((BINFO_KERNEL_ADDR + 8)) +BINFO_XHCI_ADDR=$((BINFO_ALPHA_ADDR + 8)) blob - 6c27160322ee571ec650f882cdcdf8100e2b06d0 blob + c03eeaa10e4b75159709cacf3ae014e5987bf1f1 --- kernel/idt.c +++ kernel/idt.c @@ -1,6 +1,8 @@ #include "kdebug.h" #include "types.h" +#define APIC_EOI_REG ((volatile u32*)0xFEE000B0) + struct idt_desc { u16 offset_1; u16 selector; @@ -16,12 +18,13 @@ struct idt_ptr { u64 base; } __packed; -static struct idt_desc desc[32]; +static struct idt_desc desc[256]; void debug_exception_handler(void); void page_fault_handler(void); void double_fault_handler(void); void general_protection_handler(void); +void timer_handler(void); void load_idt(struct idt_ptr *); /* set lidt.s */ @@ -69,6 +72,15 @@ idt_init() desc[14].offset_3 = (u32)(((u64)(page_fault_handler) >> 32)); desc[14].zero = 0; + // TIMER INTERRUPT (custom) + desc[0x20].offset_1 = (u16)((u64)(timer_handler) & 0xffff); + desc[0x20].selector = 0x08; + desc[0x20].ist = 0; + desc[0x20].type_attributes = 0x8E; + desc[0x20].offset_2 = (u16)(((u64)(timer_handler) & 0xffff0000) >> 16); + desc[0x20].offset_3 = (u32)(((u64)(timer_handler) >> 32)); + desc[0x20].zero = 0; + load_idt(&ptr); return 0; @@ -97,3 +109,13 @@ general_protection_handler_c() { kprint("#GP interrupt\n"); } + +u64 tint = 0; + +void +timer_handler_c() +{ + kprint("Timer interrupt: "); kprinti(tint++); kprint("\n"); + + *APIC_EOI_REG = 0; // Tells register interrupt was received +} blob - 088c815aa876b54b6d2a83a4386af126be315d9e blob + 5ebcf6e1480e25bb0cbe91bb902bdc7fb8c72303 --- kernel/kmain.c +++ kernel/kmain.c @@ -11,7 +11,7 @@ static void kloop(struct module *, struct mmap *); void -kmain(struct kinfo *kinfo) +kmain(struct kinfo *kinfo, u8 drive) { struct mmap *ammap; kprint("Only 10 remote holes in a heck of a long time!\n"); @@ -23,7 +23,6 @@ kmain(struct kinfo *kinfo) kprint("GDT configured!\n"); - kpic_setup(); syscalls_init(); if (idt_init() == -1) { @@ -39,15 +38,13 @@ kmain(struct kinfo *kinfo) return; } + kpic_setup(); + kprint("Page tables configured!\n"); kprint("Free memory U/S bit set!\n"); kloop(&kinfo->modules[1], ammap); } -// Defined in switch.s -void start_alpha(struct mmap *ammap, struct thread *thread); -void switch_context(struct thread *old, struct thread *new); - static void kloop(struct module *amodule, struct mmap *ammap) { @@ -55,10 +52,8 @@ kloop(struct module *amodule, struct mmap *ammap) if (athread == nil) { kprint("Failed to create thread\n"); - goto repeat; + repeat: goto repeat; } - kprint("Jumping to alpha!\n"); - start_alpha(ammap, athread); - repeat: goto repeat; + thread_schedule(ammap, athread); } blob - 51f6b639c87130e8f972813419c6eddbccfa9829 blob + 3334258cf25f3e68aae8d615009bfc9bba95d272 --- kernel/kmmap.c +++ kernel/kmmap.c @@ -132,6 +132,8 @@ kmmap_init(struct kinfo *kinfo) struct module *kmodule = &kinfo->modules[0]; struct module *amodule = &kinfo->modules[1]; + struct module *xhci_module = &kinfo->modules[2]; + u64 nmodules = sizeof(kinfo->modules) / sizeof(*kinfo->modules); u64 memsize = 0; for (u64 i = 0; i < kinfo->e820_bcount; i++) { @@ -172,11 +174,14 @@ kmmap_init(struct kinfo *kinfo) for (u64 i = 0; i < kmodule->entry + kmodule->size; i += PAGE_SIZE) set_bitmap(i); - // Alpha module is occupied + // Occupy other modules - for (u64 i = amodule->entry; i < amodule->entry + amodule->size; i += PAGE_SIZE) - set_bitmap(i); + for (u64 i = 1; i < nmodules; i++) { + struct module *m = &kinfo->modules[i]; + for (u64 j = m->entry; j < m->entry + m->size; j += PAGE_SIZE) + set_bitmap(j); + } PageTableCount = kminfo.frames; PageDirCount = (PageTableCount + P_ENTRIES - 1) / P_ENTRIES; @@ -214,11 +219,15 @@ kmmap_init(struct kinfo *kinfo) if (kminfo.amap == nil) return nil; - // Changing amodule to user + // Changing modules to user mode - for (u64 i = amodule->entry; i < amodule->entry + amodule->size; i += PAGE_SIZE) - kmmap_addr_touser(i); + for (u64 i = 1; i < nmodules; i++) { + struct module *m = &kinfo->modules[i]; + for (u64 j = m->entry; j < m->entry + m->size; j += PAGE_SIZE) + kmmap_addr_touser(j); + } + kmmap_usermode(); return kminfo.amap; blob - 5275b82f081415d89d7f8233b0b66fc381ddc828 blob + 22b22d08c60f36ee2e5a4ddf1e2557d122dde1f1 --- kernel/kmmap.h +++ kernel/kmmap.h @@ -9,7 +9,7 @@ struct module { }; struct kinfo { - struct module modules[2]; + struct module modules[3]; u64 e820_bcount; struct e820h *e820_headers; }; blob - 23604f521342f4d853c24fc4cbe9630ac1979487 blob + 5b711f5a26c269a6ec68fd7615236c460ef62d09 --- kernel/kpic.c +++ kernel/kpic.c @@ -2,14 +2,76 @@ #include "types.h" #include "kdebug.h" +#define APIC_TIMER_CUR ((u32 *)0xFEE00390) +#define APIC_TIMER_INI ((u32 *)0xFEE00380) +#define APIC_TIMER_DIV ((u32 *)0xFEE003E0) +#define APIC_TIMER_LVT ((u32 *)0xFEE00320) + +#define APIC_LVT_PERIODIC 0x20000 +#define TIMER_VECTOR 0x20 + +#define IA32_APIC_BASE_MSR 0x1B +#define IA32_APIC_BASE_MSR_ENABLE 0x800 + #define PIC1 0x20 #define PIC2 0xA0 #define PIC1_DATA (PIC1+1) #define PIC2_DATA (PIC2+1) -void -kpic_setup() +// See sysentry.s +u64 rdmsr(u32 msr); +void wrmsr(u32 msr, u64 value); + +static void apic_setup_timer(void); + +static void +pic_disable() { outb(PIC1_DATA, 0xff); outb(PIC2_DATA, 0xff); } + +// Enable local APIC for a core + +void +kpic_setup() +{ + u64 apic_base; + u32 *spivptr; + u32 spiv; + + pic_disable(); + + // Enable local APIC + + apic_base = rdmsr(IA32_APIC_BASE_MSR); + + apic_base |= IA32_APIC_BASE_MSR_ENABLE; + + wrmsr(IA32_APIC_BASE_MSR, apic_base); + + // Start receiving interrupts + + spivptr = (u32 *)0xFEE000F0; + spiv = *spivptr; + + spiv |= 0x100; + spiv |= 0xFF; + + *spivptr = spiv; + + apic_setup_timer(); +} + +static void +apic_setup_timer() +{ + // Clock divider + *APIC_TIMER_DIV = 0x03; + + // Setup register + *APIC_TIMER_LVT = APIC_LVT_PERIODIC | TIMER_VECTOR; + + // Initial countdown + *APIC_TIMER_INI = 10000000; +} blob - ad5151966c615d05cc3610d39e1438f46e7e5c1d blob + 2accf334df9298693dd6ee50980ab5275610c0a0 --- kernel/kthreads.c +++ kernel/kthreads.c @@ -6,6 +6,7 @@ #define MAX_USER_THREADS 64 static struct thread uthreads[MAX_USER_THREADS]; +static struct thread *cthread; struct thread* thread_create(void (*entry)(void)) @@ -27,7 +28,6 @@ thread_create(void (*entry)(void)) return nil; } - kprint("Creating thread\n"); thread->base = allocate_memory(PAGE_SIZE); if (thread->base == nil) { @@ -53,3 +53,51 @@ thread_create(void (*entry)(void)) return thread; } + +s64 +thread_getuid(struct thread *th) +{ + for (int i = 0; i < MAX_USER_THREADS; i++) { + if (&uthreads[i] == th) + return i; + } + + return -1; +} + +// This is defined in switch.s + +void start_alpha(struct mmap *ammap, struct thread *thread); +void switch_context(struct thread *old, struct thread *new); + +void +thread_schedule(struct mmap *ammap, struct thread *th) +{ + cthread = th; + start_alpha(ammap, th); + + repeat: goto repeat; +} + +void +thread_switch(struct thread *th) +{ + struct thread *othread; + + if (th == cthread) { + kprint("Huh?\n"); + return; + } + + othread = cthread; + cthread = th; + switch_context(othread, cthread); +} + +struct thread* +thread_get_uthread(u64 id) +{ + if (id < MAX_USER_THREADS && uthreads[id].assigned == 1) + return &uthreads[id]; + return nil; +} blob - 911e2269adde81f02054325a01a8d4f4c36b56a3 blob + b962ab43fc5883d0f878a41c640fde2977e15761 --- kernel/kthreads.h +++ kernel/kthreads.h @@ -1,10 +1,23 @@ #pragma once +#include "kmmap.h" + +enum thread_state { + THREAD_READY, + THREAD_RUNNING, +}; + struct thread { u64 *base; u64 *top; u64 rsp; + u8 assigned; + enum thread_state sate; }; struct thread *thread_create(void (*entry)(void)); +s64 thread_getuid(struct thread *th); +void thread_schedule(struct mmap *, struct thread *); +void thread_switch(struct thread *); +struct thread *thread_get_uthread(u64 id); blob - 956758d0e646b87b571b9d62ab69efe230287cfb blob + 086afdfc65590671baca91ac1a342feeec475041 --- kernel/lidt.s +++ kernel/lidt.s @@ -14,6 +14,9 @@ extern double_fault_handler_c global general_protection_handler extern general_protection_handler_c +global timer_handler +extern timer_handler_c + load_idt: lidt [rdi] ret @@ -33,3 +36,7 @@ double_fault_handler: general_protection_handler: call general_protection_handler_c hlt + +timer_handler: + call timer_handler_c + iretq blob - 96cdf2ec8e0f43812f162b177f0270aa9aa8fb4a blob + 97983d5a50a7c11a00eb9b8167610e5a3babe57c --- kernel/syscalls.c +++ kernel/syscalls.c @@ -1,5 +1,6 @@ #include "types.h" #include "kdebug.h" +#include "kthreads.h" #include "syscalls/syscalls.h" #define IA32_EFER 0xC0000080 @@ -35,12 +36,46 @@ syscall_echo_h(struct sysc_echo *echo) } void +syscall_new_thread_h(struct sysc_new_thread *nthread) +{ + struct thread *th = thread_create(nthread->entry); + s64 threadid; + + if (th == nil) + kprint("failed to create thread from syscall!\n"); + + threadid = thread_getuid(th); + nthread->retid = threadid; + + kprint("Thread (id="); kprinti(threadid); kprint(") created!\n"); +} + +void +syscall_context_switch_h(struct sysc_context_switch *scs) +{ + struct thread *cthread = thread_get_uthread(scs->threadid); + + if (cthread == nil) { + kprint("No current thread :/\n"); + return; + } + + thread_switch(cthread); +} + +void syscall_handler(struct sysc *call) { switch (call->type) { case SYSC_ECHO: syscall_echo_h((struct sysc_echo *)call); break; + case SYSC_NEW_THREAD: + syscall_new_thread_h((struct sysc_new_thread *)call); + break; + case SYSC_CONTEXT_SWITCH: + syscall_context_switch_h((struct sysc_context_switch *)call); + break; default: break; } blob - 3d5477f9fc4ebb1e5081b30b5d0558fc90973efc blob + a63060857332e965651f8484c979a5233d2346eb --- servers/xhci/main.c +++ servers/xhci/main.c @@ -1,8 +1,22 @@ #include "types.h" #include "syscalls/syscalls.h" +static void send_msg (const u8 *msg); + void xhci_main() { + send_msg("xhci: driver started\n"); + for (;;); } + +static void +send_msg (const u8 *msg) +{ + struct sysc_echo echo; + echo.sysc.type = SYSC_ECHO; + echo.msg = msg; + sys_send((struct sysc *)&echo); +} + blob - f4d21d3b8483f50020a2d4112286b187c1cd34d5 blob + 4ed19f7d29b986549d6fec7d04fe784cbd0226cc --- syscalls/syscalls.h +++ syscalls/syscalls.h @@ -2,6 +2,9 @@ enum sysc_type { SYSC_ECHO, + SYSC_NEW_THREAD, + SYSC_FREE_THREAD, + SYSC_CONTEXT_SWITCH, // This shouldn't be a thing its for testing before APIC and thread states }; struct sysc { @@ -13,5 +16,23 @@ struct sysc_echo { const char *msg; }; +struct sysc_new_thread { + struct sysc sysc; + void *entry; + u64 size; // Unused for now + + s64 retid; // The threadId returned +}; + +struct sysc_free_thread { + struct sysc sysc; + u64 id; +}; + +struct sysc_context_switch { + struct sysc sysc; + u64 threadid; +}; + void sys_send(struct sysc *); void sys_recv(void);