Skip to content

Commit

Permalink
feat: implement user-space virtual memory
Browse files Browse the repository at this point in the history
  • Loading branch information
alanjian85 committed Jul 25, 2024
1 parent c2ffe3a commit a73bc0d
Show file tree
Hide file tree
Showing 14 changed files with 25,073 additions and 24,937 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ if (ARCH STREQUAL RISCV)
src/arch/riscv/timer.c
src/arch/riscv/trap.c
src/arch/riscv/trap.S
src/arch/riscv/vm.c
)
endif()

Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion include/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#define BOOT_STACK_BASE 0x88000000
#define DRIVER_DEV_CAPACITY 8
#define INTR_ISR_CAPACITY 256
#define KHEAP_SIZE 0x400000
#define KHEAP_SIZE 0x800000
#define LOG_BUF_SIZE 4096
#define PROC_FD_CAPACITY 64
#define PROC_TABLE_SIZE 256
Expand Down
3 changes: 2 additions & 1 deletion include/elf.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#pragma once

extern void *elf_entry;
extern void *init_elf_entry;
extern void *init_page_table;
4 changes: 4 additions & 0 deletions include/math.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma once

#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
2 changes: 2 additions & 0 deletions include/mm/page_alloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@

#define PAGE_SIZE 4096

#ifndef __ASSEMBLER__
void *page_alloc(void);
void page_free(void *ptr);
#endif
11 changes: 11 additions & 0 deletions include/mm/vm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

#include <types.h>

#define VM_FLAG_READABLE 0x1
#define VM_FLAG_WRITABLE 0x2
#define VM_FLAG_EXECUTABLE 0x4
#define VM_FLAG_USER 0x8

void *vm_create_page_table(void);
i32 vm_map_page(void *page_table, usize virt_addr, void *phys_addr, u32 flags);
8 changes: 5 additions & 3 deletions src/arch/riscv/trap.S
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#include <mm/page_alloc.h>

.section .text

.global trap_entry
.align 2
trap_entry:
.global trampoline
.balign PAGE_SIZE
trampoline:
csrrw sp, sscratch, sp
add sp, sp, -176

Expand Down
6 changes: 3 additions & 3 deletions src/arch/riscv/trap.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <trap.h>

#include <arch/riscv/constants.h>
#include <arch/riscv/csr.h>
#include <arch/riscv/riscv.h>
#include <drivers/plic.h>
#include <errno.h>
#include <intr.h>
Expand All @@ -13,8 +13,8 @@
MODULE_NAME("trap");

static i32 init(void) {
void trap_entry(void);
csr_write(stvec, trap_entry);
void trampoline(void);
csr_write(stvec, trampoline);
return 0;
}

Expand Down
74 changes: 74 additions & 0 deletions src/arch/riscv/vm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#include <mm/vm.h>

#include <errno.h>
#include <mm/page_alloc.h>
#include <utils/mem.h>

typedef struct {
u8 flags;
u8 reserved : 2;
u64 ppn : 44;
u16 padding : 10;
} pte_t;

#define PTE_FLAG_V 0x01
#define PTE_FLAG_R 0x02
#define PTE_FLAG_W 0x04
#define PTE_FLAG_X 0x08
#define PTE_FLAG_U 0x10
#define PTE_FLAG_G 0x20
#define PTE_FLAG_A 0x40
#define PTE_FLAG_D 0x80

static void init_pte(pte_t *pte, void *page, u32 flags) {
pte->flags |= PTE_FLAG_V;

if (flags & VM_FLAG_READABLE)
pte->flags |= PTE_FLAG_R;
if (flags & VM_FLAG_WRITABLE)
pte->flags |= PTE_FLAG_W;
if (flags & VM_FLAG_EXECUTABLE)
pte->flags |= PTE_FLAG_X;
if (flags & VM_FLAG_USER)
pte->flags |= PTE_FLAG_U;

pte->ppn = (usize) page >> 12;
}

void *vm_create_page_table(void) {
pte_t *page_table = (pte_t *) page_alloc();
if (!page_table)
return nullptr;
mem_set(page_table, 0, PAGE_SIZE);
return page_table;
}

i32 vm_map_page(void *page_table, usize virt_addr, void *phys_addr, u32 flags) {
pte_t *page_table0 = (pte_t *) page_table;
u16 idx0 = virt_addr >> 30;
pte_t *pte0 = page_table0 + idx0;

pte_t *page_table1 = (pte_t *) (usize) (pte0->ppn << 12);
if (!(pte0->flags & PTE_FLAG_V)) {
page_table1 = (pte_t *) vm_create_page_table();
if (!page_table1)
return -ENOMEM;
init_pte(pte0, page_table1, 0);
}
u16 idx1 = (virt_addr >> 21) & 0x1FF;
pte_t *pte1 = page_table1 + idx1;

pte_t *page_table2 = (pte_t *) (usize) (pte1->ppn << 12);
if (!(pte1->flags & PTE_FLAG_V)) {
page_table2 = (pte_t *) vm_create_page_table();
if (!page_table2)
return -ENOMEM;
init_pte(pte1, page_table2, 0);
}
u16 idx2 = (virt_addr >> 12) & 0x1FF;
pte_t *pte2 = page_table2 + idx2;

init_pte(pte2, phys_addr, flags);

return 0;
}
70 changes: 50 additions & 20 deletions src/elf.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
#include <errno.h>
#include <init.h>
#include <math.h>
#include <mm/page_alloc.h>
#include <mm/vm.h>
#include <module/init.h>
#include <module/log.h>
#include <module/module.h>
#include <utils/mem.h>

MODULE_NAME("elf");

enum {
EI_MAG0,
EI_MAG1,
EI_MAG2,
EI_MAG3,
EI_CLASS,
EI_DATA,
EI_VERSION,
};

typedef struct {
u8 ident[16];
u16 type;
Expand All @@ -24,6 +37,14 @@ typedef struct {
u16 shstrndx;
} elf_hdr_t;

enum {
PT_LOAD = 1,
};

#define PF_X 0x1
#define PF_W 0x2
#define PF_R 0x4

typedef struct {
u32 type;
u32 flags;
Expand All @@ -35,21 +56,8 @@ typedef struct {
usize align;
} prog_hdr_t;

enum {
EI_MAG0,
EI_MAG1,
EI_MAG2,
EI_MAG3,
EI_CLASS,
EI_DATA,
EI_VERSION,
};

enum {
PT_LOAD = 0x00000001,
};

void *elf_entry;
void *init_elf_entry;
void *init_page_table;

static i32 check_ident(const u8 *ident) {
if (ident[EI_MAG0] != 0x7F)
Expand All @@ -75,25 +83,47 @@ static i32 check_compat(const u8 *ident) {

static i32 init(void) {
const elf_hdr_t *elf_hdr = (const elf_hdr_t *) INIT_ELF;
elf_entry = (void *) elf_hdr->entry;
init_elf_entry = (void *) elf_hdr->entry;

if (!check_ident(elf_hdr->ident))
return -EACCES;

if (!check_compat(elf_hdr->ident) || elf_hdr->type != 2)
return -EINVAL;

init_page_table = vm_create_page_table();
if (!init_page_table)
return -ENOMEM;

const prog_hdr_t *prog_hdrs =
(const prog_hdr_t *) (INIT_ELF + elf_hdr->phoff);
for (u16 i = 0; i < elf_hdr->phnum; i++) {
const prog_hdr_t *prog_hdr = prog_hdrs + i;
if (prog_hdr->type != PT_LOAD)
continue;

const void *src = INIT_ELF + prog_hdr->offset;
void *dst = (void *) prog_hdr->paddr;
mem_set(dst, 0x00, prog_hdr->memsz);
mem_copy(dst, src, prog_hdr->filesz);
u32 flags = VM_FLAG_USER;
if (prog_hdr->flags & PF_X)
flags |= VM_FLAG_EXECUTABLE;
if (prog_hdr->flags & PF_W)
flags |= VM_FLAG_WRITABLE;
if (prog_hdr->flags & PF_R)
flags |= VM_FLAG_READABLE;

for (usize offset = 0; offset < prog_hdr->memsz; offset += PAGE_SIZE) {
void *page = page_alloc();
if (!page)
return -ENOMEM;
mem_set(page, 0, PAGE_SIZE);
if (offset < prog_hdr->filesz) {
const void *src = INIT_ELF + prog_hdr->offset + offset;
mem_copy(page, src, min(prog_hdr->filesz - offset, PAGE_SIZE));
}
i32 res = vm_map_page(init_page_table, prog_hdr->vaddr + offset,
page, flags);
if (res < 0)
return res;
}
}

return 0;
Expand Down
Loading

0 comments on commit a73bc0d

Please sign in to comment.