diff --git a/src/common.h b/src/common.h index 9327b59..cc3687a 100644 --- a/src/common.h +++ b/src/common.h @@ -26,10 +26,12 @@ typedef uint32_t vaddr_t; #define va_end __builtin_va_end #define va_arg __builtin_va_arg +#define PAGE_SIZE 4096 + void *memset(void *buf, char c, size_t n); void *memcpy(void *dst, const void *src, size_t n); char *strcpy(char *dst, const char *src); int strcmp(const char *s1, const char *s2); -void printf(const char *fmt, ...); \ No newline at end of file +void printf(const char *fmt, ...); diff --git a/src/kernel.c b/src/kernel.c index 4c05fcc..cfbf293 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1,5 +1,6 @@ #include "kernel.h" +// ===== SBI CALLS ===== struct sbiret sbi_call(long arg0, long arg1, long arg2, long arg3, long arg4, long arg5, long fid, long eid) { register long a0 __asm__("a0") = arg0; @@ -21,8 +22,23 @@ struct sbiret sbi_call(long arg0, long arg1, long arg2, long arg3, long arg4, void putchar(char ch) { sbi_call(ch, 0, 0, 0, 0, 0, 0, 1); } -__attribute__((naked)) __attribute__((aligned(4))) void kernel_entry(void) { - __asm__ __volatile__("csrw sscratch, sp\n" +// ===== MEMORY ALLOCATION ===== +paddr_t alloc_pages(uint32_t n) { + static paddr_t next_paddr = (paddr_t)__free_ram; + paddr_t paddr = next_paddr; + next_paddr += n * PAGE_SIZE; + + if (next_paddr > (paddr_t)__free_ram_end) + PANIC("out of memory"); + + memset((void *)paddr, 0, n * PAGE_SIZE); + return paddr; +} + +// ===== Exception handler ===== +void kernel_entry(void) { + __asm__ __volatile__("csrrw sp, sscratch, sp\n" + "addi sp, sp, -4 * 31\n" "sw ra, 4 * 0(sp)\n" "sw gp, 4 * 1(sp)\n" @@ -56,7 +72,10 @@ __attribute__((naked)) __attribute__((aligned(4))) void kernel_entry(void) { "sw s11, 4 * 29(sp)\n" "csrr a0, sscratch\n" - "sw a0, 4 * 30(sp)\n" + "sw a0, 4 * 30(sp)\n" + + "addi a0, sp, 4 * 31\n" + "csrw sscratch, a0\n" "mv a0, sp\n" "call handle_trap\n" @@ -104,14 +123,117 @@ void handle_trap(struct trap_frame *f) { user_pc); } +// ===== Multiprocessing ===== +__attribute__((naked)) void switch_context(uint32_t *prev_sp, + uint32_t *next_sp) { + __asm__ __volatile__("addi sp, sp, -13 * 4\n" + + "sw ra, 0 * 4(sp)\n" + + "sw s0, 1 * 4(sp)\n" + "sw s1, 2 * 4(sp)\n" + "sw s2, 3 * 4(sp)\n" + "sw s3, 4 * 4(sp)\n" + "sw s4, 5 * 4(sp)\n" + "sw s5, 6 * 4(sp)\n" + "sw s6, 7 * 4(sp)\n" + "sw s7, 8 * 4(sp)\n" + "sw s8, 9 * 4(sp)\n" + "sw s9, 10 * 4(sp)\n" + "sw s10, 11 * 4(sp)\n" + "sw s11, 12 * 4(sp)\n" + + "sw sp, (a0)\n" + "lw sp, (a1)\n" + + "lw ra, 0 * 4(sp)\n" + + "lw s0, 1 * 4(sp)\n" + "lw s1, 2 * 4(sp)\n" + "lw s2, 3 * 4(sp)\n" + "lw s3, 4 * 4(sp)\n" + "lw s4, 5 * 4(sp)\n" + "lw s5, 6 * 4(sp)\n" + "lw s6, 7 * 4(sp)\n" + "lw s7, 8 * 4(sp)\n" + "lw s8, 9 * 4(sp)\n" + "lw s9, 10 * 4(sp)\n" + "lw s10, 11 * 4(sp)\n" + "lw s11, 12 * 4(sp)\n" + "addi sp, sp, 13 * 4\n" + "ret\n"); +} + +struct process *create_process(uint32_t pc) { + struct process *proc = NULL; + int i; + for (i = 0; i < PROCS_MAX; i++) { + if (procs[i].state == PROC_UNUSED) { + proc = &procs[i]; + break; + } + } + + if (!proc) + PANIC("no free process slots"); + + uint32_t *sp = (uint32_t *)&proc->stack[sizeof(proc->stack)]; + *--sp = 0; // s11 + *--sp = 0; // s10 + *--sp = 0; // s9 + *--sp = 0; // s8 + *--sp = 0; // s7 + *--sp = 0; // s6 + *--sp = 0; // s5 + *--sp = 0; // s4 + *--sp = 0; // s3 + *--sp = 0; // s2 + *--sp = 0; // s1 + *--sp = 0; // s0 + *--sp = (uint32_t)pc; // ra + + proc->pid = i + 1; + proc->state = PROC_RUNNABLE; + proc->sp = (uint32_t)sp; + return proc; +} +void yield(void) { + struct process *next = idle_proc; + for (int i = 0; i < PROCS_MAX; i++) { + struct process *proc = &procs[(current_proc->pid + i) % PROCS_MAX]; + if (proc->state == PROC_RUNNABLE && proc->pid > 0) { + next = proc; + break; + } + } + + if (next == current_proc) + return; + + __asm__ __volatile__( + "csrw sscratch, %[sscratch]\n" + : + : [sscratch] "r"((uint32_t)&next->stack[sizeof(next->stack)])); + + struct process *prev = current_proc; + current_proc = next; + switch_context(&prev->sp, &next->sp); +} + +// ===== ENTRY POINT ===== void kernel_main(void) { memset(__bss, 0, (size_t)__bss_end - (size_t)__bss); - WRITE_CSR(stvec, (uint32_t)kernel_entry); - __asm__ __volatile__("unimp"); + printf("\n\n"); - PANIC("booted!"); - printf("unreachable here!\n"); + WRITE_CSR(stvec, (uint32_t)kernel_entry); + + idle_proc = create_process((uint32_t)NULL); + idle_proc->pid = -1; + current_proc = idle_proc; + + yield(); + PANIC("switched to idle process"); } __attribute__((section(".text.boot"))) __attribute__((naked)) void boot(void) { diff --git a/src/kernel.h b/src/kernel.h index 0987469..5b5fe7b 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -2,20 +2,18 @@ #include "common.h" -extern char __bss[], __bss_end[], __stack_top[]; +// ===== Linker data ===== +extern char __bss[], __bss_end[]; +extern char __stack_top[]; +extern char __free_ram[], __free_ram_end[]; +// ===== SBI data ====== struct sbiret { long error; long value; }; -#define PANIC(fmt, ...) \ - do { \ - printf("PANIC: %s:%d: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ - while (1) { \ - } \ - } while (0) - +// ===== Exception handler ===== struct trap_frame { uint32_t ra; uint32_t gp; @@ -50,6 +48,23 @@ struct trap_frame { uint32_t sp; } __attribute__((packed)); +// ===== Multiprocessing ===== +#define PROCS_MAX 8 + +#define PROC_UNUSED 0 +#define PROC_RUNNABLE 1 + +struct process { + int pid; + int state; + vaddr_t sp; + uint8_t stack[8192]; +}; +struct process procs[PROCS_MAX]; +struct process *current_proc; +struct process *idle_proc; + +// ===== Macros ===== #define READ_CSR(reg) \ ({ \ unsigned long __tmp; \ @@ -62,3 +77,10 @@ struct trap_frame { uint32_t __tmp = (value); \ __asm__ __volatile__("csrw " #reg ", %0" ::"r"(__tmp)); \ } while (0) + +#define PANIC(fmt, ...) \ + do { \ + printf("PANIC: %s:%d: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ + while (1) { \ + } \ + } while (0) diff --git a/src/kernel.ld b/src/kernel.ld index f4b4a9a..c4aee9e 100644 --- a/src/kernel.ld +++ b/src/kernel.ld @@ -25,4 +25,9 @@ SECTIONS { . = ALIGN(4); . += 128 * 1024; /* 128KB */ __stack_top = .; -} \ No newline at end of file + + . = ALIGN(4096); + __free_ram = .; + . += 64 * 1024 * 1024; /* 64MB */ + __free_ram_end = .; +}