diff options
Diffstat (limited to 'src/kernel')
-rw-r--r-- | src/kernel/arch/amd64/32/32 | 130 | ||||
-rw-r--r-- | src/kernel/arch/amd64/32/boot.s | 1 | ||||
-rw-r--r-- | src/kernel/arch/amd64/interrupts/irq.c | 9 | ||||
-rw-r--r-- | src/kernel/arch/amd64/interrupts/irq.h | 1 | ||||
-rw-r--r-- | src/kernel/arch/amd64/interrupts/isr.c | 6 | ||||
-rw-r--r-- | src/kernel/arch/amd64/time.c | 50 | ||||
-rw-r--r-- | src/kernel/arch/amd64/time.h | 4 | ||||
-rw-r--r-- | src/kernel/arch/generic.h | 6 | ||||
-rw-r--r-- | src/kernel/proc.c | 17 | ||||
-rw-r--r-- | src/kernel/proc.h | 6 | ||||
-rw-r--r-- | src/kernel/syscalls.c | 8 |
11 files changed, 102 insertions, 136 deletions
diff --git a/src/kernel/arch/amd64/32/32 b/src/kernel/arch/amd64/32/32 deleted file mode 100644 index 9bd97e6..0000000 --- a/src/kernel/arch/amd64/32/32 +++ /dev/null @@ -1,130 +0,0 @@ -#include <kernel/arch/generic.h> -#include <kernel/arch/amd64/gdt.h> -#include <shared/mem.h> -#include <stdbool.h> -#include <stdint.h> - -extern char _isr_mini_stack; - -struct gdt_entry { - uint64_t limit_low : 16; - uint64_t base_low : 24; - uint64_t accessed : 1; // set by the processor - // CODE | DATA - uint64_t rw : 1; // readable? | writeable? - uint64_t conforming : 1; // conforming? | expands down? - uint64_t code : 1; // 1 | 0 - - uint64_t codeordata : 1; // 1 for everything other than TSS and LDT - uint64_t ring : 2; - uint64_t present : 1; // always 1 - uint64_t limit_high : 4; - uint64_t available : 1; // ??? - uint64_t long_mode : 1; - uint64_t x32 : 1; - uint64_t gran : 1; // 1 - 4kb, 0 - 1b - uint64_t base_high : 8; -} __attribute__((packed)); - -struct tss_entry { - uint32_t _unused0; - uint32_t esp0; // kernel mode stack pointer - uint32_t ss0; // kernel mode stack segment - uint8_t _unused1[0x5c]; -} __attribute__((packed)); - -struct lgdt_arg { - uint16_t limit; - uint32_t base; -} __attribute__((packed)); - -__attribute__((section(".shared"))) -static struct gdt_entry GDT[SEG_end]; -__attribute__((section(".shared"))) -static struct tss_entry TSS; -static struct lgdt_arg lgdt_arg; // probably doesn't need to be global - -static void gdt_fillout(struct gdt_entry* entry, uint8_t ring, bool code); -static void gdt_prepare(void); -static void gdt_load(void); - - -static void gdt_fillout(struct gdt_entry* entry, uint8_t ring, bool code) { - *entry = (struct gdt_entry) { - // set up the identity mapping - .limit_low = 0xFFFF, - .limit_high = 0xF, - .gran = 1, // 4KB * 0xFFFFF = (almost) 4GB - .base_low = 0, - .base_high = 0, - - .ring = ring, - .code = code, - - .accessed = 0, - .rw = 1, - .conforming = 0, - .codeordata = 1, - .present = 1, - .long_mode = 0, // ??? - .available = 1, // ??? - .x32 = 1, - }; -} - -static void gdt_prepare(void) { - GDT[SEG_null].present = 0; - - gdt_fillout(&GDT[SEG_r0code], 0, true); - gdt_fillout(&GDT[SEG_r0data], 0, false); - gdt_fillout(&GDT[SEG_r3code], 3, true); - gdt_fillout(&GDT[SEG_r3data], 3, false); - - // tss - memset(&TSS, 0, sizeof(TSS)); - TSS.ss0 = SEG_r0data << 3; // kernel data segment - TSS.esp0 = (uintptr_t) &_isr_mini_stack; - - GDT[SEG_TSS] = (struct gdt_entry) { - .limit_low = sizeof(TSS), - .limit_high = sizeof(TSS) >> 16, - .gran = 0, - .base_low = (uintptr_t) &TSS, - .base_high = ((uintptr_t) &TSS) >> 24, - - .accessed = 1, // 1 for TSS - .rw = 0, // 1 busy / 0 not busy - .conforming = 0, // 0 for TSS - .code = 1, // 32bit - .codeordata = 0, // is a system entry - .ring = 3, - .present = 1, - .available = 0, // 0 for TSS - .long_mode = 0, - .x32 = 0, // idk - }; -} - -static void gdt_load(void) { - lgdt_arg.limit = sizeof(GDT) - 1; - lgdt_arg.base = (uintptr_t) &GDT; - asm("lgdt (%0)" - : : "r" (&lgdt_arg) : "memory"); - - asm("ltr %%ax" - : : "a" (SEG_TSS << 3 | 3) : "memory"); - - // update all segment registers - gdt_farjump(SEG_r0code << 3); - asm("mov %0, %%ds;" - "mov %0, %%ss;" - "mov %0, %%es;" - "mov %0, %%fs;" - "mov %0, %%gs;" - : : "r" (SEG_r0data << 3) : "memory"); -} - -void gdt_init(void) { - gdt_prepare(); - gdt_load(); -} diff --git a/src/kernel/arch/amd64/32/boot.s b/src/kernel/arch/amd64/32/boot.s index 0e21036..0621038 100644 --- a/src/kernel/arch/amd64/32/boot.s +++ b/src/kernel/arch/amd64/32/boot.s @@ -2,6 +2,7 @@ .global _start .type _start, @function _start: + cli mov $_stack_top, %esp push %ebx // save the address of the multiboot struct diff --git a/src/kernel/arch/amd64/interrupts/irq.c b/src/kernel/arch/amd64/interrupts/irq.c index b5e9255..9872ec7 100644 --- a/src/kernel/arch/amd64/interrupts/irq.c +++ b/src/kernel/arch/amd64/interrupts/irq.c @@ -5,6 +5,12 @@ static const int PIC1 = 0x20; static const int PIC2 = 0xA0; +static void pit_init(void) { + uint16_t divisor = 1193; + port_out8(0x40, divisor & 0xFF); + port_out8(0x40, divisor >> 8); +} + void irq_init(void) { port_out8(PIC1, 0x11); /* start init sequence */ port_out8(PIC2, 0x11); @@ -18,11 +24,14 @@ void irq_init(void) { port_out8(PIC2+1, 0x1); uint8_t mask = 0xff; + mask &= ~(1 << IRQ_PIT); mask &= ~(1 << IRQ_PS2); mask &= ~(1 << IRQ_COM1); port_out8(PIC1+1, mask); port_out8(PIC2+1, 0xff); + + pit_init(); } void irq_eoi(uint8_t line) { diff --git a/src/kernel/arch/amd64/interrupts/irq.h b/src/kernel/arch/amd64/interrupts/irq.h index 3340101..2a4b12d 100644 --- a/src/kernel/arch/amd64/interrupts/irq.h +++ b/src/kernel/arch/amd64/interrupts/irq.h @@ -3,6 +3,7 @@ #include <stdint.h> #define IRQ_IBASE 0x20 +#define IRQ_PIT 0 #define IRQ_PS2 1 #define IRQ_COM1 4 diff --git a/src/kernel/arch/amd64/interrupts/isr.c b/src/kernel/arch/amd64/interrupts/isr.c index 71da27b..0bfd865 100644 --- a/src/kernel/arch/amd64/interrupts/isr.c +++ b/src/kernel/arch/amd64/interrupts/isr.c @@ -3,6 +3,7 @@ #include <kernel/arch/amd64/interrupts/irq.h> #include <kernel/arch/amd64/interrupts/isr.h> #include <kernel/arch/amd64/port_io.h> +#include <kernel/arch/amd64/time.h> #include <kernel/arch/generic.h> #include <kernel/panic.h> #include <kernel/proc.h> @@ -28,6 +29,11 @@ void isr_stage3(int interrupt, uint64_t *stackframe) { isr_test_interrupt_called = true; return; + case IRQ_IBASE + IRQ_PIT: + pit_irq(); + irq_eoi(IRQ_PIT); + return; + case IRQ_IBASE + IRQ_PS2: ps2_irq(); irq_eoi(IRQ_PS2); diff --git a/src/kernel/arch/amd64/time.c b/src/kernel/arch/amd64/time.c new file mode 100644 index 0000000..d6e53dd --- /dev/null +++ b/src/kernel/arch/amd64/time.c @@ -0,0 +1,50 @@ +#include <kernel/arch/amd64/time.h> +#include <kernel/panic.h> +#include <kernel/proc.h> + +static uint64_t uptime = 0, goal = ~0; +static struct process *scheduled = NULL; + +uint64_t uptime_ms(void) { return uptime; } + +static void update_goal(void) { + goal = scheduled ? scheduled->waits4timer.goal : ~(uint64_t)0; +} + +void pit_irq(void) { + // TODO inefficient - getting here executes a lot of code which could just be a few lines of asm + uptime++; + if (uptime < goal) return; + + struct process *p = scheduled; + assert(p); + scheduled = p->waits4timer.next; + process_transition(p, PS_RUNNING); + update_goal(); +} + +void timer_schedule(struct process *p, uint64_t time) { + process_transition(p, PS_WAITS4TIMER); + p->waits4timer.goal = time; + + struct process **slot = &scheduled; + while (*slot && (*slot)->waits4timer.goal <= time) { + assert((*slot)->state == PS_WAITS4TIMER); + slot = &(*slot)->waits4timer.next; + } + p->waits4timer.next = *slot; + *slot = p; + update_goal(); +} + +void timer_deschedule(struct process *p) { + assert(p->state == PS_WAITS4TIMER); + + struct process **slot = &scheduled; + while (*slot && *slot != p) + slot = &(*slot)->waits4timer.next; + assert(*slot); + *slot = p->waits4timer.next; + + update_goal(); +} diff --git a/src/kernel/arch/amd64/time.h b/src/kernel/arch/amd64/time.h new file mode 100644 index 0000000..04ba9b0 --- /dev/null +++ b/src/kernel/arch/amd64/time.h @@ -0,0 +1,4 @@ +#pragma once +#include <kernel/arch/generic.h> + +void pit_irq(void); diff --git a/src/kernel/arch/generic.h b/src/kernel/arch/generic.h index 4a4f632..0b7b2f2 100644 --- a/src/kernel/arch/generic.h +++ b/src/kernel/arch/generic.h @@ -6,6 +6,8 @@ #include <stdbool.h> #include <stddef.h> +struct process; + // i have no idea where else to put it // some code assumes that it's a power of 2 #define PAGE_SIZE 4096 @@ -22,6 +24,10 @@ void cpu_shutdown(void); /** on x86: waits for an IRQ */ void cpu_pause(void); +uint64_t uptime_ms(void); +void timer_schedule(struct process *p, uint64_t time); +void timer_deschedule(struct process *p); + // src/arch/i386/sysenter.s _Noreturn void sysexit(struct registers); diff --git a/src/kernel/proc.c b/src/kernel/proc.c index e7a5ed6..3bf2b0d 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -132,6 +132,9 @@ void process_kill(struct process *p, int ret) { *iter = p->waits4pipe.next; } + if (p->state == PS_WAITS4TIMER) + timer_deschedule(p); + for (handle_t h = 0; h < HANDLE_MAX; h++) handle_close(p->handles[h]); @@ -217,14 +220,15 @@ static _Noreturn void process_switch(struct process *proc) { } _Noreturn void process_switch_any(void) { - if (process_current && process_current->state == PS_RUNNING) - process_switch(process_current); + for (;;) { + if (process_current && process_current->state == PS_RUNNING) + process_switch(process_current); - struct process *found = process_find(PS_RUNNING); - if (found) process_switch(found); + struct process *found = process_find(PS_RUNNING); + if (found) process_switch(found); - cpu_pause(); - process_switch_any(); + cpu_pause(); + } } struct process *process_next(struct process *p) { @@ -284,6 +288,7 @@ void process_transition(struct process *p, enum process_state state) { case PS_WAITS4FS: case PS_WAITS4REQUEST: case PS_WAITS4PIPE: + case PS_WAITS4TIMER: assert(last == PS_RUNNING); break; diff --git a/src/kernel/proc.h b/src/kernel/proc.h index d6f84bd..fb14e35 100644 --- a/src/kernel/proc.h +++ b/src/kernel/proc.h @@ -15,6 +15,7 @@ enum process_state { PS_WAITS4FS, PS_WAITS4REQUEST, PS_WAITS4PIPE, + PS_WAITS4TIMER, PS_LAST, }; @@ -46,6 +47,11 @@ struct process { size_t len; struct process *next; } waits4pipe; + struct { + /* managed by timer_schedule */ + uint64_t goal; + struct process *next; + } waits4timer; }; struct vfs_request *handled_req; diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index 4537ff5..ceba528 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -363,6 +363,11 @@ long _syscall_pipe(handle_t __user user_ends[2], int flags) { SYSCALL_RETURN(0); } +void _syscall_sleep(long ms) { + // TODO no overflow check - can leak current uptime + timer_schedule(process_current, uptime_ms() + ms); +} + long _syscall_execbuf(void __user *ubuf, size_t len) { if (len == 0) SYSCALL_RETURN(0); if (len > sizeof(uint64_t) * 6 * 4) // TODO specify max size somewhere @@ -434,6 +439,9 @@ long _syscall(long num, long a, long b, long c, long d, long e) { case _SYSCALL_PIPE: _syscall_pipe((userptr_t)a, b); break; + case _SYSCALL_SLEEP: + _syscall_sleep(a); + break; case _SYSCALL_EXECBUF: _syscall_execbuf((userptr_t)a, b); break; |