mirror of
https://github.com/StepanovPlaton/OSin1000Lines.git
synced 2026-04-03 12:20:46 +04:00
Compare commits
2 Commits
fde896f371
...
8710577d42
| Author | SHA1 | Date | |
|---|---|---|---|
| 8710577d42 | |||
| 6043cc0d5c |
@@ -26,6 +26,8 @@ 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);
|
||||
|
||||
|
||||
212
src/kernel.c
212
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,11 +22,218 @@ 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); }
|
||||
|
||||
// ===== 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"
|
||||
"sw tp, 4 * 2(sp)\n"
|
||||
"sw t0, 4 * 3(sp)\n"
|
||||
"sw t1, 4 * 4(sp)\n"
|
||||
"sw t2, 4 * 5(sp)\n"
|
||||
"sw t3, 4 * 6(sp)\n"
|
||||
"sw t4, 4 * 7(sp)\n"
|
||||
"sw t5, 4 * 8(sp)\n"
|
||||
"sw t6, 4 * 9(sp)\n"
|
||||
"sw a0, 4 * 10(sp)\n"
|
||||
"sw a1, 4 * 11(sp)\n"
|
||||
"sw a2, 4 * 12(sp)\n"
|
||||
"sw a3, 4 * 13(sp)\n"
|
||||
"sw a4, 4 * 14(sp)\n"
|
||||
"sw a5, 4 * 15(sp)\n"
|
||||
"sw a6, 4 * 16(sp)\n"
|
||||
"sw a7, 4 * 17(sp)\n"
|
||||
"sw s0, 4 * 18(sp)\n"
|
||||
"sw s1, 4 * 19(sp)\n"
|
||||
"sw s2, 4 * 20(sp)\n"
|
||||
"sw s3, 4 * 21(sp)\n"
|
||||
"sw s4, 4 * 22(sp)\n"
|
||||
"sw s5, 4 * 23(sp)\n"
|
||||
"sw s6, 4 * 24(sp)\n"
|
||||
"sw s7, 4 * 25(sp)\n"
|
||||
"sw s8, 4 * 26(sp)\n"
|
||||
"sw s9, 4 * 27(sp)\n"
|
||||
"sw s10, 4 * 28(sp)\n"
|
||||
"sw s11, 4 * 29(sp)\n"
|
||||
|
||||
"csrr a0, sscratch\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"
|
||||
|
||||
"lw ra, 4 * 0(sp)\n"
|
||||
"lw gp, 4 * 1(sp)\n"
|
||||
"lw tp, 4 * 2(sp)\n"
|
||||
"lw t0, 4 * 3(sp)\n"
|
||||
"lw t1, 4 * 4(sp)\n"
|
||||
"lw t2, 4 * 5(sp)\n"
|
||||
"lw t3, 4 * 6(sp)\n"
|
||||
"lw t4, 4 * 7(sp)\n"
|
||||
"lw t5, 4 * 8(sp)\n"
|
||||
"lw t6, 4 * 9(sp)\n"
|
||||
"lw a0, 4 * 10(sp)\n"
|
||||
"lw a1, 4 * 11(sp)\n"
|
||||
"lw a2, 4 * 12(sp)\n"
|
||||
"lw a3, 4 * 13(sp)\n"
|
||||
"lw a4, 4 * 14(sp)\n"
|
||||
"lw a5, 4 * 15(sp)\n"
|
||||
"lw a6, 4 * 16(sp)\n"
|
||||
"lw a7, 4 * 17(sp)\n"
|
||||
"lw s0, 4 * 18(sp)\n"
|
||||
"lw s1, 4 * 19(sp)\n"
|
||||
"lw s2, 4 * 20(sp)\n"
|
||||
"lw s3, 4 * 21(sp)\n"
|
||||
"lw s4, 4 * 22(sp)\n"
|
||||
"lw s5, 4 * 23(sp)\n"
|
||||
"lw s6, 4 * 24(sp)\n"
|
||||
"lw s7, 4 * 25(sp)\n"
|
||||
"lw s8, 4 * 26(sp)\n"
|
||||
"lw s9, 4 * 27(sp)\n"
|
||||
"lw s10, 4 * 28(sp)\n"
|
||||
"lw s11, 4 * 29(sp)\n"
|
||||
"lw sp, 4 * 30(sp)\n"
|
||||
"sret\n");
|
||||
}
|
||||
|
||||
void handle_trap(struct trap_frame *f) {
|
||||
uint32_t scause = READ_CSR(scause);
|
||||
uint32_t stval = READ_CSR(stval);
|
||||
uint32_t user_pc = READ_CSR(sepc);
|
||||
|
||||
PANIC("unexpected trap scause=%x, stval=%x, sepc=%x\n", scause, stval,
|
||||
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);
|
||||
|
||||
PANIC("booted!");
|
||||
printf("unreachable here!\n");
|
||||
printf("\n\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) {
|
||||
|
||||
71
src/kernel.h
71
src/kernel.h
@@ -2,13 +2,82 @@
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
// ===== Exception handler =====
|
||||
struct trap_frame {
|
||||
uint32_t ra;
|
||||
uint32_t gp;
|
||||
uint32_t tp;
|
||||
uint32_t t0;
|
||||
uint32_t t1;
|
||||
uint32_t t2;
|
||||
uint32_t t3;
|
||||
uint32_t t4;
|
||||
uint32_t t5;
|
||||
uint32_t t6;
|
||||
uint32_t a0;
|
||||
uint32_t a1;
|
||||
uint32_t a2;
|
||||
uint32_t a3;
|
||||
uint32_t a4;
|
||||
uint32_t a5;
|
||||
uint32_t a6;
|
||||
uint32_t a7;
|
||||
uint32_t s0;
|
||||
uint32_t s1;
|
||||
uint32_t s2;
|
||||
uint32_t s3;
|
||||
uint32_t s4;
|
||||
uint32_t s5;
|
||||
uint32_t s6;
|
||||
uint32_t s7;
|
||||
uint32_t s8;
|
||||
uint32_t s9;
|
||||
uint32_t s10;
|
||||
uint32_t s11;
|
||||
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; \
|
||||
__asm__ __volatile__("csrr %0, " #reg : "=r"(__tmp)); \
|
||||
__tmp; \
|
||||
})
|
||||
|
||||
#define WRITE_CSR(reg, value) \
|
||||
do { \
|
||||
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__); \
|
||||
|
||||
@@ -25,4 +25,9 @@ SECTIONS {
|
||||
. = ALIGN(4);
|
||||
. += 128 * 1024; /* 128KB */
|
||||
__stack_top = .;
|
||||
|
||||
. = ALIGN(4096);
|
||||
__free_ram = .;
|
||||
. += 64 * 1024 * 1024; /* 64MB */
|
||||
__free_ram_end = .;
|
||||
}
|
||||
1
src/run.sh
Normal file → Executable file
1
src/run.sh
Normal file → Executable file
@@ -1,4 +1,5 @@
|
||||
#!/bin/bash
|
||||
set -xue
|
||||
|
||||
make kernel
|
||||
qemu-system-riscv32 -machine virt -bios default -nographic -serial mon:stdio --no-reboot -kernel kernel.elf
|
||||
Reference in New Issue
Block a user