mirror of
https://github.com/StepanovPlaton/OSin1000Lines.git
synced 2026-04-03 12:20:46 +04:00
Virtual memory
This commit is contained in:
52
src/kernel.c
52
src/kernel.c
@@ -35,6 +35,24 @@ paddr_t alloc_pages(uint32_t n) {
|
|||||||
return paddr;
|
return paddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void map_page(uint32_t *table1, uint32_t vaddr, paddr_t paddr, uint32_t flags) {
|
||||||
|
if (!is_aligned(vaddr, PAGE_SIZE))
|
||||||
|
PANIC("unaligned vaddr %x", vaddr);
|
||||||
|
|
||||||
|
if (!is_aligned(paddr, PAGE_SIZE))
|
||||||
|
PANIC("unaligned paddr %x", paddr);
|
||||||
|
|
||||||
|
uint32_t vpn1 = (vaddr >> 22) & 0x3ff;
|
||||||
|
if ((table1[vpn1] & PAGE_V) == 0) {
|
||||||
|
uint32_t pt_paddr = alloc_pages(1);
|
||||||
|
table1[vpn1] = ((pt_paddr / PAGE_SIZE) << 10) | PAGE_V;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t vpn0 = (vaddr >> 12) & 0x3ff;
|
||||||
|
uint32_t *table0 = (uint32_t *)((table1[vpn1] >> 10) * PAGE_SIZE);
|
||||||
|
table0[vpn0] = ((paddr / PAGE_SIZE) << 10) | flags | PAGE_V;
|
||||||
|
}
|
||||||
|
|
||||||
// ===== Exception handler =====
|
// ===== Exception handler =====
|
||||||
void kernel_entry(void) {
|
void kernel_entry(void) {
|
||||||
__asm__ __volatile__("csrrw sp, sscratch, sp\n"
|
__asm__ __volatile__("csrrw sp, sscratch, sp\n"
|
||||||
@@ -192,9 +210,15 @@ struct process *create_process(uint32_t pc) {
|
|||||||
*--sp = 0; // s0
|
*--sp = 0; // s0
|
||||||
*--sp = (uint32_t)pc; // ra
|
*--sp = (uint32_t)pc; // 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);
|
||||||
|
|
||||||
proc->pid = i + 1;
|
proc->pid = i + 1;
|
||||||
proc->state = PROC_RUNNABLE;
|
proc->state = PROC_RUNNABLE;
|
||||||
proc->sp = (uint32_t)sp;
|
proc->sp = (uint32_t)sp;
|
||||||
|
proc->page_table = page_table;
|
||||||
return proc;
|
return proc;
|
||||||
}
|
}
|
||||||
void yield(void) {
|
void yield(void) {
|
||||||
@@ -211,9 +235,13 @@ void yield(void) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
|
"sfence.vma\n"
|
||||||
|
"csrw satp, %[satp]\n"
|
||||||
|
"sfence.vma\n"
|
||||||
"csrw sscratch, %[sscratch]\n"
|
"csrw sscratch, %[sscratch]\n"
|
||||||
:
|
:
|
||||||
: [sscratch] "r"((uint32_t)&next->stack[sizeof(next->stack)]));
|
: [satp] "r"(SATP_SV32 | ((uint32_t)next->page_table / PAGE_SIZE)),
|
||||||
|
[sscratch] "r"((uint32_t)&next->stack[sizeof(next->stack)]));
|
||||||
|
|
||||||
struct process *prev = current_proc;
|
struct process *prev = current_proc;
|
||||||
current_proc = next;
|
current_proc = next;
|
||||||
@@ -221,17 +249,35 @@ void yield(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ===== ENTRY POINT =====
|
// ===== ENTRY POINT =====
|
||||||
|
struct process *proc_a;
|
||||||
|
struct process *proc_b;
|
||||||
|
|
||||||
|
void proc_a_entry(void) {
|
||||||
|
while (1) {
|
||||||
|
putchar('A');
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void proc_b_entry(void) {
|
||||||
|
while (1) {
|
||||||
|
putchar('B');
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void kernel_main(void) {
|
void kernel_main(void) {
|
||||||
memset(__bss, 0, (size_t)__bss_end - (size_t)__bss);
|
memset(__bss, 0, (size_t)__bss_end - (size_t)__bss);
|
||||||
|
|
||||||
printf("\n\n");
|
|
||||||
|
|
||||||
WRITE_CSR(stvec, (uint32_t)kernel_entry);
|
WRITE_CSR(stvec, (uint32_t)kernel_entry);
|
||||||
|
|
||||||
idle_proc = create_process((uint32_t)NULL);
|
idle_proc = create_process((uint32_t)NULL);
|
||||||
idle_proc->pid = -1;
|
idle_proc->pid = -1;
|
||||||
current_proc = idle_proc;
|
current_proc = idle_proc;
|
||||||
|
|
||||||
|
proc_a = create_process((uint32_t)proc_a_entry);
|
||||||
|
proc_b = create_process((uint32_t)proc_b_entry);
|
||||||
|
|
||||||
yield();
|
yield();
|
||||||
PANIC("switched to idle process");
|
PANIC("switched to idle process");
|
||||||
}
|
}
|
||||||
|
|||||||
10
src/kernel.h
10
src/kernel.h
@@ -6,6 +6,7 @@
|
|||||||
extern char __bss[], __bss_end[];
|
extern char __bss[], __bss_end[];
|
||||||
extern char __stack_top[];
|
extern char __stack_top[];
|
||||||
extern char __free_ram[], __free_ram_end[];
|
extern char __free_ram[], __free_ram_end[];
|
||||||
|
extern char __kernel_base[];
|
||||||
|
|
||||||
// ===== SBI data ======
|
// ===== SBI data ======
|
||||||
struct sbiret {
|
struct sbiret {
|
||||||
@@ -58,12 +59,21 @@ struct process {
|
|||||||
int pid;
|
int pid;
|
||||||
int state;
|
int state;
|
||||||
vaddr_t sp;
|
vaddr_t sp;
|
||||||
|
uint32_t *page_table;
|
||||||
uint8_t stack[8192];
|
uint8_t stack[8192];
|
||||||
};
|
};
|
||||||
struct process procs[PROCS_MAX];
|
struct process procs[PROCS_MAX];
|
||||||
struct process *current_proc;
|
struct process *current_proc;
|
||||||
struct process *idle_proc;
|
struct process *idle_proc;
|
||||||
|
|
||||||
|
// ===== Memory allocation =====
|
||||||
|
#define SATP_SV32 (1u << 31)
|
||||||
|
#define PAGE_V (1 << 0)
|
||||||
|
#define PAGE_R (1 << 1)
|
||||||
|
#define PAGE_W (1 << 2)
|
||||||
|
#define PAGE_X (1 << 3)
|
||||||
|
#define PAGE_U (1 << 4)
|
||||||
|
|
||||||
// ===== Macros =====
|
// ===== Macros =====
|
||||||
#define READ_CSR(reg) \
|
#define READ_CSR(reg) \
|
||||||
({ \
|
({ \
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ ENTRY(boot)
|
|||||||
|
|
||||||
SECTIONS {
|
SECTIONS {
|
||||||
. = 0x80200000;
|
. = 0x80200000;
|
||||||
|
__kernel_base = .;
|
||||||
|
|
||||||
.text :{
|
.text :{
|
||||||
KEEP(*(.text.boot));
|
KEEP(*(.text.boot));
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -xue
|
set -xue
|
||||||
|
|
||||||
make kernel
|
make kernel && qemu-system-riscv32 -machine virt -bios default -nographic -serial mon:stdio --no-reboot -kernel kernel.elf
|
||||||
qemu-system-riscv32 -machine virt -bios default -nographic -serial mon:stdio --no-reboot -kernel kernel.elf
|
|
||||||
|
|||||||
Reference in New Issue
Block a user