diff --git a/src/Makefile b/src/Makefile index 409cadc..5726ed3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,5 +1,11 @@ CC = clang +OBJCOPY=llvm-objcopy CFLAGS = -std=c11 -O2 -g3 -Wall -Wextra --target=riscv32 -ffreestanding -nostdlib -kernel: - $(CC) $(CFLAGS) -Wl,-Tkernel.ld -Wl,-Map=kernel.map -o kernel.elf kernel.c common.c \ No newline at end of file +kernel: shell + $(CC) $(CFLAGS) -Wl,-Tkernel.ld -Wl,-Map=kernel.map -o kernel.elf kernel.c common.c shell.bin.o + +shell: + $(CC) $(CFLAGS) -Wl,-Tuser.ld -Wl,-Map=shell.map -o shell.elf shell.c user.c common.c + $(OBJCOPY) --set-section-flags .bss=alloc,contents -O binary shell.elf shell.bin + $(OBJCOPY) -Ibinary -Oelf32-littleriscv shell.bin shell.bin.o diff --git a/src/common.h b/src/common.h index cc3687a..c7e803b 100644 --- a/src/common.h +++ b/src/common.h @@ -28,6 +28,10 @@ typedef uint32_t vaddr_t; #define PAGE_SIZE 4096 +#define USER_BASE 0x1000000 + +#define SSTATUS_SPIE (1 << 5) + void *memset(void *buf, char c, size_t n); void *memcpy(void *dst, const void *src, size_t n); diff --git a/src/kernel.c b/src/kernel.c index aff1fcc..59720eb 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -54,7 +54,7 @@ void map_page(uint32_t *table1, uint32_t vaddr, paddr_t paddr, uint32_t flags) { } // ===== Exception handler ===== -void kernel_entry(void) { +__attribute__((naked)) __attribute__((aligned(4))) void kernel_entry(void) { __asm__ __volatile__("csrrw sp, sscratch, sp\n" "addi sp, sp, -4 * 31\n" @@ -89,9 +89,11 @@ void kernel_entry(void) { "sw s10, 4 * 28(sp)\n" "sw s11, 4 * 29(sp)\n" + // Извлечение и сохранение sp в момент исключения. "csrr a0, sscratch\n" "sw a0, 4 * 30(sp)\n" + // Сброс стека ядра. "addi a0, sp, 4 * 31\n" "csrw sscratch, a0\n" @@ -182,7 +184,15 @@ __attribute__((naked)) void switch_context(uint32_t *prev_sp, "ret\n"); } -struct process *create_process(uint32_t pc) { +__attribute__((naked)) void user_entry(void) { + __asm__ __volatile__("csrw sepc, %[sepc] \n" + "csrw sstatus, %[sstatus] \n" + "sret \n" + : + : [sepc] "r"(USER_BASE), [sstatus] "r"(SSTATUS_SPIE)); +} + +struct process *create_process(const void *image, size_t image_size) { struct process *proc = NULL; int i; for (i = 0; i < PROCS_MAX; i++) { @@ -196,25 +206,36 @@ struct process *create_process(uint32_t pc) { 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 + *--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)user_entry; // ra uint32_t *page_table = (uint32_t *)alloc_pages(1); + for (paddr_t paddr = (paddr_t)__kernel_base; paddr < (paddr_t)__free_ram_end; paddr += PAGE_SIZE) map_page(page_table, paddr, paddr, PAGE_R | PAGE_W | PAGE_X); + for (uint32_t off = 0; off < image_size; off += PAGE_SIZE) { + paddr_t page = alloc_pages(1); + + size_t remaining = image_size - off; + size_t copy_size = PAGE_SIZE <= remaining ? PAGE_SIZE : remaining; + + memcpy((void *)page, image + off, copy_size); + map_page(page_table, USER_BASE + off, page, + PAGE_U | PAGE_R | PAGE_W | PAGE_X); + } proc->pid = i + 1; proc->state = PROC_RUNNABLE; proc->sp = (uint32_t)sp; @@ -269,14 +290,15 @@ void proc_b_entry(void) { void kernel_main(void) { memset(__bss, 0, (size_t)__bss_end - (size_t)__bss); + printf("\n\n"); + WRITE_CSR(stvec, (uint32_t)kernel_entry); - idle_proc = create_process((uint32_t)NULL); + idle_proc = create_process(NULL, 0); idle_proc->pid = -1; current_proc = idle_proc; - proc_a = create_process((uint32_t)proc_a_entry); - proc_b = create_process((uint32_t)proc_b_entry); + create_process(_binary_shell_bin_start, (size_t)_binary_shell_bin_size); yield(); PANIC("switched to idle process"); diff --git a/src/kernel.h b/src/kernel.h index db2bdb3..c0e523a 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -7,6 +7,7 @@ extern char __bss[], __bss_end[]; extern char __stack_top[]; extern char __free_ram[], __free_ram_end[]; extern char __kernel_base[]; +extern char _binary_shell_bin_start[], _binary_shell_bin_size[]; // ===== SBI data ====== struct sbiret { diff --git a/src/shell.c b/src/shell.c new file mode 100644 index 0000000..ae077c4 --- /dev/null +++ b/src/shell.c @@ -0,0 +1,7 @@ +#include "user.h" + +void main(void) { + *((volatile int *)0x80200000) = 0x1234; // new! + for (;;) + ; +} diff --git a/src/user.c b/src/user.c new file mode 100644 index 0000000..a8f4710 --- /dev/null +++ b/src/user.c @@ -0,0 +1,18 @@ +#include "user.h" + +extern char __stack_top[]; + +__attribute__((noreturn)) void exit(void) { + for (;;) + ; +} + +void putchar(char c) { /* Доделать*/ } + +__attribute__((section(".text.start"))) __attribute__((naked)) void +start(void) { + __asm__ __volatile__( + "mv sp, %[stack_top] \n" + "call main \n" + "call exit \n" ::[stack_top] "r"(__stack_top)); +} diff --git a/src/user.h b/src/user.h new file mode 100644 index 0000000..c28ef51 --- /dev/null +++ b/src/user.h @@ -0,0 +1,6 @@ +#pragma once + +#include "common.h" + +__attribute__((noreturn)) void exit(void); +void putchar(char ch); diff --git a/src/user.ld b/src/user.ld new file mode 100644 index 0000000..014bbba --- /dev/null +++ b/src/user.ld @@ -0,0 +1,28 @@ +ENTRY(start) + +SECTIONS { + . = 0x1000000; + + .text :{ + KEEP(*(.text.start)); + *(.text .text.*); + } + + .rodata : ALIGN(4) { + *(.rodata .rodata.*); + } + + .data : ALIGN(4) { + *(.data .data.*); + } + + .bss : ALIGN(4) { + *(.bss .bss.* .sbss .sbss.*); + + . = ALIGN(16); + . += 64 * 1024; /* 64KB */ + __stack_top = .; + + ASSERT(. < 0x1800000, "too large executable"); + } +}