diff --git a/src/arch/x86_64/apic.c b/src/arch/x86_64/apic.c index 83dbbade..107b2b0f 100644 --- a/src/arch/x86_64/apic.c +++ b/src/arch/x86_64/apic.c @@ -5,15 +5,26 @@ #include #include #include +#include #define APIC_REGISTER_ID 0x20 #define APIC_REGISTER_EOI 0xB0 #define APIC_REGISTER_SPURIOUS 0xF0 +#define APIC_REGISTER_ICR_LO 0x300 +#define APIC_REGISTER_ICR_HI 0x310 #define APIC_TIMER_LVT 0x320 +#define APIC_THERMAL_LVT 0x330 +#define APIC_PERFORMANCE_LVT 0x340 +#define APIC_LINT0_LVT 0x350 +#define APIC_LINT1_LVT 0x360 +#define APIC_ERROR_LVT 0x370 #define APIC_TIMER_INITIALCOUNT 0x380 #define APIC_TIMER_COUNT 0x390 #define APIC_TIMER_DIVIDE 0x3E0 +#define LVT_DELIVERY_NMI (0b100 << 8) +#define LVT_MASK (1 << 16) + #define TYPE_LAPIC 0 #define TYPE_IOAPIC 1 #define TYPE_OVERRIDE 2 @@ -95,6 +106,7 @@ static size_t localnmi_count = 0; static size_t x2apic_count = 0; void* lapicaddr; +bool done = false; ioapic_descriptor* ioapics; void* tablestart; @@ -158,6 +170,18 @@ static inline void lapic_writereg(size_t reg, uint32_t data){ *(uint32_t volatile*)(lapicaddr + reg) = data; } +void apic_sendipi(uint8_t cpu, uint8_t vec, uint8_t dest, uint8_t mode, uint8_t level){ + + if(!done) return; // this function will be called before the apic initialization code is run so we need this safeguard + + lapic_writereg(APIC_REGISTER_ICR_HI, (uint32_t)cpu << 24); + lapic_writereg(APIC_REGISTER_ICR_LO, vec | (level << 14) | (mode << 15) | (dest << 18)); +} + +void apic_eoi(){ + lapic_writereg(APIC_REGISTER_EOI, 0); +} + void apic_timerstart(size_t ticks){ lapic_writereg(APIC_TIMER_INITIALCOUNT, ticks); } @@ -187,13 +211,40 @@ size_t apic_timercalibrate(size_t ms){ void apic_lapicinit(){ + // mask everything off besides the timer + + lapic_writereg(APIC_THERMAL_LVT, LVT_MASK); + lapic_writereg(APIC_PERFORMANCE_LVT, LVT_MASK); + lapic_writereg(APIC_LINT0_LVT, LVT_MASK); + lapic_writereg(APIC_LINT1_LVT, LVT_MASK); + lapic_writereg(APIC_ERROR_LVT, LVT_MASK); + + arch_getcls()->lapicid = (lapic_readreg(APIC_REGISTER_ID)); arch_getcls()->lapicid >>= 24; + + lapic_entry* current; + // get the acpi id for the local nmi sources + for(size_t i = 0; i < lapic_count; ++i){ + current = findstructure(TYPE_LAPIC, i); + if(arch_getcls()->lapicid == current->apicid) + break; + } + + arch_getcls()->acpi_id = current->acpi_id; + lapic_writereg(APIC_REGISTER_SPURIOUS, 0x1FF); lapic_writereg(APIC_TIMER_LVT, 1 << 16); // mask timer interrupt off - + for(size_t i = 0; i < localnmi_count; ++i){ + lapicnmi_entry* e = findstructure(TYPE_LAPICNMI, i); + if(e->acpi_id == current->acpi_id || e->acpi_id == 0xFF){ + lapic_writereg(APIC_LINT0_LVT + 0x10*e->lint, 0x30 | LVT_DELIVERY_NMI | (e->flags << 12)); + } + } + + asm("sti"); } @@ -275,6 +326,6 @@ void apic_init(){ ioapic_writeiored(&ioapics[i], j, 0, 0, 0, 0, 0, 0, 1, 0); } - + done = true; } diff --git a/src/arch/x86_64/idt.c b/src/arch/x86_64/idt.c index 9ca48d7d..4913c7af 100644 --- a/src/arch/x86_64/idt.c +++ b/src/arch/x86_64/idt.c @@ -2,7 +2,15 @@ #include #include #include -#include + +// the IDT should look like this: +// +// 0-0x19 -> exceptions +// 0x20 -> panic ipi +// 0x21 -> lapic nmi +// 0x22 -> mmu invalidate page ipi +// ... +// 0x80 -> timer idtentry_t idt[256]; @@ -37,8 +45,14 @@ void idt_bspinit(){ idt_setentry(&idt[VECTOR_PF], asmisr_pagefault, 0x28, FLAGS_PRESENT | FLAGS_TYPE_TRAP, 0); - idt_setentry(&idt[SCHEDTIMER_VECTOR], asmisr_schedtimer, 0x28, FLAGS_PRESENT | FLAGS_TYPE_INTERRUPT, 0); + idt_setentry(&idt[VECTOR_PANIC], asmisr_panic, 0x28, FLAGS_PRESENT | FLAGS_TYPE_INTERRUPT, 0); + idt_setentry(&idt[VECTOR_MMUINVAL], asmisr_mmuinval, 0x28, FLAGS_PRESENT | FLAGS_TYPE_INTERRUPT, 0); + + idt_setentry(&idt[VECTOR_LAPICNMI], asmisr_lapicnmi, 0x28, FLAGS_PRESENT | FLAGS_TYPE_INTERRUPT, 0); + + idt_setentry(&idt[VECTOR_TIMER], asmisr_timer, 0x28, FLAGS_PRESENT | FLAGS_TYPE_INTERRUPT, 0); + idt_reload(); } diff --git a/src/arch/x86_64/include/arch/apic.h b/src/arch/x86_64/include/arch/apic.h index 4cafb38f..82b81c44 100644 --- a/src/arch/x86_64/include/arch/apic.h +++ b/src/arch/x86_64/include/arch/apic.h @@ -4,6 +4,8 @@ #include #include +void apic_sendipi(uint8_t cpu, uint8_t vec, uint8_t dest, uint8_t mode, uint8_t level); +void apic_eoi(); void apic_timerstop(); void apic_timerstart(size_t ticks); void apic_timerinterruptset(uint8_t vector); diff --git a/src/arch/x86_64/include/arch/cls.h b/src/arch/x86_64/include/arch/cls.h index 3ad078e6..a3253674 100644 --- a/src/arch/x86_64/include/arch/cls.h +++ b/src/arch/x86_64/include/arch/cls.h @@ -6,6 +6,7 @@ #include #include #include +#include // cpu level storage // this will be pointed to by GS and will contain per cpu info @@ -14,8 +15,10 @@ typedef struct{ gdt_t gdt; ist_t ist; int lapicid; + int acpi_id; arch_regs *laststate; vmm_context *context; + thread_t* thread; size_t schedtimerticksperms; } cls_t; diff --git a/src/arch/x86_64/include/arch/idt.h b/src/arch/x86_64/include/arch/idt.h index 3eabcfde..c07f2105 100644 --- a/src/arch/x86_64/include/arch/idt.h +++ b/src/arch/x86_64/include/arch/idt.h @@ -24,6 +24,10 @@ #define VECTOR_GPF 13 #define VECTOR_PF 14 +#define VECTOR_PANIC 0x20 +#define VECTOR_LAPICNMI 0x21 +#define VECTOR_MMUINVAL 0x22 +#define VECTOR_TIMER 0x80 typedef struct{ uint16_t size; diff --git a/src/arch/x86_64/include/arch/isr.h b/src/arch/x86_64/include/arch/isr.h index 235a31d6..fbbef535 100644 --- a/src/arch/x86_64/include/arch/isr.h +++ b/src/arch/x86_64/include/arch/isr.h @@ -3,10 +3,13 @@ #include -extern void asmisr_schedtimer(arch_regs*); -extern void asmisr_general(arch_regs*); -extern void asmisr_except(arch_regs*); -extern void asmisr_pagefault(arch_regs*); - +extern void asmisr_timer(); +extern void asmisr_general(); +extern void asmisr_except(); +extern void asmisr_pagefault(); +extern void asmisr_panic(); +extern void asmisr_lapicnmi(); +extern void asmisr_mmuinval(); +extern void asmisr_timer(); #endif diff --git a/src/arch/x86_64/include/arch/schedtimer.h b/src/arch/x86_64/include/arch/schedtimer.h deleted file mode 100644 index 3685d71d..00000000 --- a/src/arch/x86_64/include/arch/schedtimer.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _SCHEDTIMER_H_INCLUDE -#define _SCHEDTIMER_H_INCLUDE - -#include - -#define SCHEDTIMER_VECTOR 0x50 - -void arch_schedtimer_run(size_t ms); -void arch_schedtimer_stop(); -void arch_schedtimer_calibrate(); - -#endif diff --git a/src/arch/x86_64/include/arch/smp.h b/src/arch/x86_64/include/arch/smp.h index 01194410..ddad282d 100644 --- a/src/arch/x86_64/include/arch/smp.h +++ b/src/arch/x86_64/include/arch/smp.h @@ -3,6 +3,12 @@ void smp_init(); +#define IPI_CPU_ALLBUTSELF 3 +#define IPI_CPU_ALL 2 +#define IPI_CPU_SELF 1 +#define IPI_CPU_TARGET 0 + +void arch_smp_sendipi(int cpu, int vector, int mode); diff --git a/src/arch/x86_64/isr.asm b/src/arch/x86_64/isr.asm index 4d3af8e2..b07ddac3 100644 --- a/src/arch/x86_64/isr.asm +++ b/src/arch/x86_64/isr.asm @@ -126,7 +126,18 @@ section .text iretq %endmacro +extern asmisr_panic +asmisr_panic: + + cli + .hlt: + hlt + jmp .hlt ; NMI stuff + except asmisr_pagefault, isr_pagefault isr asmisr_general, isr_general except asmisr_except, isr_except isr asmisr_schedtimer, isr_schedtimer +isr asmisr_lapicnmi, isr_lapicnmi +isr asmisr_mmuinval, isr_mmuinval +isr asmisr_timer, isr_timer diff --git a/src/arch/x86_64/isr.c b/src/arch/x86_64/isr.c index 41c83bc4..3ba20afb 100644 --- a/src/arch/x86_64/isr.c +++ b/src/arch/x86_64/isr.c @@ -1,9 +1,13 @@ #include #include #include +#include void isr_schedtimer(arch_regs *reg){ printf("schedtimer irq\n"); + + apic_eoi(); + } void isr_general(arch_regs *reg){ @@ -22,3 +26,15 @@ void isr_pagefault(arch_regs *reg){ _panic("Page fault!", reg); } + +void isr_lapicnmi(){ + _panic("Local apic NMI", 0); +} + +void isr_mmuinval(){ + arch_mmu_invalidateipi(); +} + +void isr_timer(arch_regs* reg){ + +} diff --git a/src/arch/x86_64/main.c b/src/arch/x86_64/main.c index 5e0d96ee..eed8f6d4 100644 --- a/src/arch/x86_64/main.c +++ b/src/arch/x86_64/main.c @@ -61,8 +61,6 @@ void kmain(){ apic_lapicinit(); hpet_init(); - - arch_schedtimer_calibrate(); vfs_init(); @@ -78,7 +76,7 @@ void kmain(){ pci_enumerate(); smp_init(); - + _panic("End of kmain()", 0); } diff --git a/src/arch/x86_64/mmu.c b/src/arch/x86_64/mmu.c index 5ed8abe0..1dc20d3c 100644 --- a/src/arch/x86_64/mmu.c +++ b/src/arch/x86_64/mmu.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include volatile struct limine_kernel_address_request kaddrreq = { .id = LIMINE_KERNEL_ADDRESS_REQUEST, @@ -27,8 +29,20 @@ static void switchcontext(arch_mmu_tableptr context){ asm("mov %%rax, %%cr3" : : "a"(context)); } +// FIXME add a semaphore here + +// XXX only do this on an unmap or other specific situations + +void* inv = NULL; + +void arch_mmu_invalidateipi(){ + asm("invlpg (%%rax)" : : "a"(inv)); +} + static void invalidate(void* addr){ asm("invlpg (%%rax)" : : "a"(addr)); + inv = addr; + arch_smp_sendipi(0, VECTOR_MMUINVAL, IPI_CPU_ALLBUTSELF); } @@ -236,7 +250,6 @@ void arch_mmu_init(){ switchcontext(context); - arch_getcls()->context->context = context; printf("In bootstrap context\n"); diff --git a/src/arch/x86_64/panic.c b/src/arch/x86_64/panic.c index 57685735..99fef7ce 100644 --- a/src/arch/x86_64/panic.c +++ b/src/arch/x86_64/panic.c @@ -1,7 +1,9 @@ #include +#include #include #include #include +#include #define TRACE_MAXDEPTH 10 @@ -19,8 +21,11 @@ static void tracestack(uint64_t** addr){ } __attribute((noreturn)) void _panic(char* reason, arch_regs *reg){ - + printf("PANIC: %s\n", reason); + + // XXX maybe this should be an NMI? + arch_smp_sendipi(0, VECTOR_PANIC, IPI_CPU_ALLBUTSELF); if(reg){ printf("Register dump:\nRAX: %p RBX: %p RCX: %p RDX: %p R8: %p R9: %p R10: %p R11: %p R12: %p R13: %p R14: %p R15: %p RDI: %p RSP: %p RBP: %p DS: %p ES: %p FS: %p GS: %p CR2: %p ERR: %p RIP: %p CS: %p RFLAGS: %p SS: %p\n", diff --git a/src/arch/x86_64/schedtimer.c b/src/arch/x86_64/schedtimer.c deleted file mode 100644 index 575266cb..00000000 --- a/src/arch/x86_64/schedtimer.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include -#include - -void arch_schedtimer_waitms(size_t ms){ - - apic_timerstart(cls->schedtimerticksperms * ms); - -} - -void arch_schedtimer_stop(){ - - apic_timerstop(); - -} - -void arch_schedtimer_calibrate(){ - - cls->schedtimerticksperms = apic_timercalibrate(1); - - apic_timerinterruptset(SCHEDTIMER_VECTOR); - -} diff --git a/src/arch/x86_64/smp.c b/src/arch/x86_64/smp.c index 63c99cf2..b3e0ab0a 100644 --- a/src/arch/x86_64/smp.c +++ b/src/arch/x86_64/smp.c @@ -13,6 +13,8 @@ cls_t* apcls; + +size_t oncpucount = 1; static int lock = 0; static size_t cpucount = 1; @@ -27,14 +29,15 @@ static void apstartup(struct limine_smp_info *info){ arch_mmu_apinit(); apic_lapicinit(); - - arch_schedtimer_calibrate(); printf("CPU %lu ready!\n", info->lapic_id); + + for(;;) asm("hlt"); +} - asm("cli;hlt"); - +void arch_smp_sendipi(int processor, int vector, int mode){ + apic_sendipi(processor, vector, mode, 0, 1); } static volatile struct limine_smp_request smpreq = { diff --git a/src/include/kernel/sched.h b/src/include/kernel/sched.h new file mode 100644 index 00000000..39b16401 --- /dev/null +++ b/src/include/kernel/sched.h @@ -0,0 +1,33 @@ +#ifndef _SCHED_H_INCLUDE +#define _SCHED_H_INCLUDE + +#include +#include +#include + +#define THREAD_STATE_WAITING 0 +#define THREAD_STATE_RUNNING 1 +#define THREAD_STATE_BLOCKED 2 + +struct _proc_t; + +typedef struct _thread_t{ + struct _thread_t* next; + struct _proc_t* proc; + arch_regs* regs; + size_t state; + void* kernelstack; +} thread_t; + +typedef struct _proc_t{ + struct _proc_t* parent; + struct _proc_t* sibling; + struct _proc_t* child; + pid_t pid; + gid_t gid; + uid_t uid; + dirnode_t* root; + dirnode_t* cwd; +} proc_t; + +#endif diff --git a/src/sys/Makefile b/src/sys/Makefile index 307e3f33..d8f94e82 100644 --- a/src/sys/Makefile +++ b/src/sys/Makefile @@ -1,5 +1,5 @@ objects := $(patsubst %.c,%.o,$(wildcard *.c)) -subdirs := mm +subdirs := mm sched OBJPATH=$(OBJDIR) export diff --git a/src/sys/sched/Makefile b/src/sys/sched/Makefile new file mode 100644 index 00000000..1d6ce393 --- /dev/null +++ b/src/sys/sched/Makefile @@ -0,0 +1,12 @@ +objects := $(patsubst %.c,%.o,$(wildcard *.c)) +subdirs := +OBJPATH=$(OBJDIR) +export + +all: $(subdirs) $(objects) + for subdir in $(subdirs) ; do $(MAKE) -C $${subdir} ; done + +%.o: %.c + $(CC) $(CFLAGS) -o $@ $< + mkdir -p $(OBJPATH) + cp $@ $(OBJPATH)/$@ diff --git a/src/sys/sched/scheduler.c b/src/sys/sched/scheduler.c new file mode 100644 index 00000000..24ab179a --- /dev/null +++ b/src/sys/sched/scheduler.c @@ -0,0 +1,49 @@ +#include +#include + +thread_t* queue; +thread_t* blocked; + +static thread_t* next_thread(){ + + thread_t* thread = queue; + + while(1){ + + while(thread != NULL && thread->state != THREAD_STATE_WAITING) + thread = thread->next; + + if(!thread) + asm("hlt"); // wait until something happens that would allow a thread to be scheduled + + } + + return thread; + +} + +__attribute__((noreturn)) static void sched_switch(thread_t* thread){ + + thread_t* current = arch_getcls()->thread; + + if(current->proc != thread->proc){ + + // change address spaces and all + + } + + arch_switchcontext(thread->regs); + + __builtin_unreachable(); +} + +__attribute__((noreturn)) void sched_timerhook(arch_regs* c){ + + thread_t* current = arch_getcls()->thread; + + memcpy(current->regs, c, sizeof(arch_regs)); + + ; + + __builtin_unreachable(); +}