init commit of lab2_1

lab2_1_pagetable
Zhiyuan Shao 3 years ago
parent 9c8cbfaa3b
commit 769c280d05

@ -63,7 +63,6 @@ SPIKE_INF_LIB := $(OBJ_DIR)/spike_interface.a
#--------------------- user -----------------------
USER_LDS := user/user.lds
USER_CPPS := user/*.c
USER_CPPS := $(wildcard $(USER_CPPS))
@ -71,7 +70,7 @@ USER_OBJS := $(addprefix $(OBJ_DIR)/, $(patsubst %.c,%.o,$(USER_CPPS)))
USER_TARGET := $(OBJ_DIR)/app_long_loop
USER_TARGET := $(OBJ_DIR)/app_helloworld_no_lds
#------------------------targets------------------------
$(OBJ_DIR):
@-mkdir -p $(OBJ_DIR)
@ -103,9 +102,9 @@ $(KERNEL_TARGET): $(OBJ_DIR) $(UTIL_LIB) $(SPIKE_INF_LIB) $(KERNEL_OBJS) $(KERNE
@$(COMPILE) $(KERNEL_OBJS) $(UTIL_LIB) $(SPIKE_INF_LIB) -o $@ -T $(KERNEL_LDS)
@echo "PKE core has been built into" \"$@\"
$(USER_TARGET): $(OBJ_DIR) $(UTIL_LIB) $(USER_OBJS) $(USER_LDS)
$(USER_TARGET): $(OBJ_DIR) $(UTIL_LIB) $(USER_OBJS)
@echo "linking" $@ ...
@$(COMPILE) $(USER_OBJS) $(UTIL_LIB) -o $@ -T $(USER_LDS)
@$(COMPILE) --entry=main $(USER_OBJS) $(UTIL_LIB) -o $@
@echo "User app has been built into" \"$@\"
-include $(wildcard $(OBJ_DIR)/*/*.d)

@ -7,17 +7,10 @@
//interval of timer interrupt. added @lab1_3
#define TIMER_INTERVAL 1000000
#define DRAM_BASE 0x80000000
// the maximum memory space that PKE is allowed to manage. added @lab2_1
#define PKE_MAX_ALLOWABLE_RAM 128 * 1024 * 1024
/* we use fixed physical (also logical) addresses for the stacks and trap frames as in
Bare memory-mapping mode */
// user stack top
#define USER_STACK 0x81100000
// the stack used by PKE kernel when a syscall happens
#define USER_KSTACK 0x81200000
// the trap frame used to assemble the user "process"
#define USER_TRAP_FRAME 0x81300000
// the ending physical address that PKE observes. added @lab2_1
#define PHYS_TOP (DRAM_BASE + PKE_MAX_ALLOWABLE_RAM)
#endif

@ -6,6 +6,8 @@
#include "elf.h"
#include "string.h"
#include "riscv.h"
#include "vmm.h"
#include "pmm.h"
#include "spike_interface/spike_utils.h"
typedef struct elf_info_t {
@ -14,11 +16,21 @@ typedef struct elf_info_t {
} elf_info;
//
// the implementation of allocater. allocates memory space for later segment loading
// the implementation of allocater. allocates memory space for later segment loading.
// this allocater is heavily modified @lab2_1, where we do NOT work in bare mode.
//
static void *elf_alloc_mb(elf_ctx *ctx, uint64 elf_pa, uint64 elf_va, uint64 size) {
// directly returns the virtual address as we are in the Bare mode in lab1_x
return (void *)elf_va;
elf_info *msg = (elf_info *)ctx->info;
// we assume that size of proram segment is smaller than a page.
kassert(size < PGSIZE);
void *pa = alloc_page();
if (pa == 0) panic("uvmalloc mem alloc falied\n");
memset((void *)pa, 0, PGSIZE);
user_vm_map((pagetable_t)msg->p->pagetable, elf_va, PGSIZE, (uint64)pa,
prot_to_type(PROT_WRITE | PROT_READ | PROT_EXEC, 1));
return pa;
}
//
@ -48,7 +60,7 @@ elf_status elf_init(elf_ctx *ctx, void *info) {
}
//
// load the elf segments to memory regions as we are in Bare mode in lab1
// load the elf segments to memory regions.
//
elf_status elf_load(elf_ctx *ctx) {
// elf_prog_header structure is defined in kernel/elf.h

@ -6,26 +6,71 @@
#include "string.h"
#include "elf.h"
#include "process.h"
#include "pmm.h"
#include "vmm.h"
#include "memlayout.h"
#include "spike_interface/spike_utils.h"
// process is a structure defined in kernel/process.h
process user_app;
//
// trap_sec_start points to the beginning of S-mode trap segment (i.e., the entry point of
// S-mode trap vector). added @lab2_1
//
extern char trap_sec_start[];
//
// turn on paging. added @lab2_1
//
void enable_paging() {
// write the pointer to kernel page (table) directory into the CSR of "satp".
write_csr(satp, MAKE_SATP(g_kernel_pagetable));
// refresh tlb to invalidate its content.
flush_tlb();
}
//
// load the elf, and construct a "process" (with only a trapframe).
// load_bincode_from_host_elf is defined in elf.c
//
void load_user_program(process *proc) {
// USER_TRAP_FRAME is a physical address defined in kernel/config.h
proc->trapframe = (trapframe *)USER_TRAP_FRAME;
sprint("User application is loading.\n");
// allocate a page to store the trapframe. alloc_page is defined in kernel/pmm.c. added @lab2_1
proc->trapframe = (trapframe *)alloc_page();
memset(proc->trapframe, 0, sizeof(trapframe));
// USER_KSTACK is also a physical address defined in kernel/config.h
proc->kstack = USER_KSTACK;
proc->trapframe->regs.sp = USER_STACK;
// allocate a page to store page directory. added @lab2_1
proc->pagetable = (pagetable_t)alloc_page();
memset((void *)proc->pagetable, 0, PGSIZE);
// allocate pages to both user-kernel stack and user app itself. added @lab2_1
proc->kstack = (uint64)alloc_page() + PGSIZE; //user kernel stack top
uint64 user_stack = (uint64)alloc_page(); //phisical address of user stack bottom
// USER_STACK_TOP = 0x7ffff000, defined in kernel/memlayout.h
proc->trapframe->regs.sp = USER_STACK_TOP; //virtual address of user stack top
sprint("user frame 0x%lx, user stack 0x%lx, user kstack 0x%lx \n", proc->trapframe,
proc->trapframe->regs.sp, proc->kstack);
// load_bincode_from_host_elf() is defined in kernel/elf.c
load_bincode_from_host_elf(proc);
// populate the page table of user application. added @lab2_1
// map user stack in userspace, user_vm_map is defined in kernel/vmm.c
user_vm_map((pagetable_t)proc->pagetable, USER_STACK_TOP - PGSIZE, PGSIZE, user_stack,
prot_to_type(PROT_WRITE | PROT_READ, 1));
// map trapframe in user space (direct mapping as in kernel space).
user_vm_map((pagetable_t)proc->pagetable, (uint64)proc->trapframe, PGSIZE, (uint64)proc->trapframe,
prot_to_type(PROT_WRITE | PROT_READ, 0));
// map S-mode trap vector section in user space (direct mapping as in kernel space)
// here, we assume that the size of usertrap.S is smaller than a page.
user_vm_map((pagetable_t)proc->pagetable, (uint64)trap_sec_start, PGSIZE, (uint64)trap_sec_start,
prot_to_type(PROT_READ | PROT_EXEC, 0));
}
//
@ -33,13 +78,22 @@ void load_user_program(process *proc) {
//
int s_start(void) {
sprint("Enter supervisor mode...\n");
// Note: we use direct (i.e., Bare mode) for memory mapping in lab1.
// which means: Virtual Address = Physical Address
// therefore, we need to set satp to be 0 for now. we will enable paging in lab2_x.
//
// write_csr is a macro defined in kernel/riscv.h
// in the beginning, we use Bare mode (direct) memory mapping as in lab1.
// but now, we are going to switch to the paging mode @lab2_1.
// note, the code still works in Bare mode when calling pmm_init() and kern_vm_init().
write_csr(satp, 0);
// init phisical memory manager
pmm_init();
// build the kernel page table
kern_vm_init();
// now, switch to paging mode by turning on paging (SV39)
enable_paging();
// the code now formally works in paging mode, meaning the page table is now in use.
sprint("kernel page table is on \n");
// the application code (elf) is first loaded into memory, and then put into execution
load_user_program(&user_app);

@ -0,0 +1,16 @@
#ifndef _MEMLAYOUT_H
#define _MEMLAYOUT_H
// RISC-V machine places its physical memory above DRAM_BASE
#define DRAM_BASE 0x80000000
// the beginning virtual address of PKE kernel
#define KERN_BASE 0x80000000
// default stack size
#define STACK_SIZE 4096
// virtual address of stack top of user process
#define USER_STACK_TOP 0x7ffff000
#endif

@ -0,0 +1,88 @@
#include "pmm.h"
#include "util/functions.h"
#include "riscv.h"
#include "config.h"
#include "util/string.h"
#include "memlayout.h"
#include "spike_interface/spike_utils.h"
// _end is defined in kernel/kernel.lds, it marks the ending (virtual) address of PKE kernel
extern char _end[];
// g_mem_size is defined in spike_interface/spike_memory.c, it indicates the size of our
// (emulated) spike machine. g_mem_size's value is obtained when initializing HTIF.
extern uint64 g_mem_size;
static uint64 free_mem_start_addr; //beginning address of free memory
static uint64 free_mem_end_addr; //end address of free memory (not included)
typedef struct node {
struct node *next;
} list_node;
// g_free_mem_list is the head of the list of free physical memory pages
static list_node g_free_mem_list;
//
// actually creates the freepage list. each page occupies 4KB (PGSIZE), i.e., small page.
// PGSIZE is defined in kernel/riscv.h, ROUNDUP is defined in util/functions.h.
//
static void create_freepage_list(uint64 start, uint64 end) {
g_free_mem_list.next = 0;
for (uint64 p = ROUNDUP(start, PGSIZE); p + PGSIZE < end; p += PGSIZE)
free_page( (void *)p );
}
//
// place a physical page at *pa to the free list of g_free_mem_list (to reclaim the page)
//
void free_page(void *pa) {
if (((uint64)pa % PGSIZE) != 0 || (uint64)pa < free_mem_start_addr || (uint64)pa >= free_mem_end_addr)
panic("free_page 0x%lx \n", pa);
// insert a physical page to g_free_mem_list
list_node *n = (list_node *)pa;
n->next = g_free_mem_list.next;
g_free_mem_list.next = n;
}
//
// takes the first free page from g_free_mem_list, and returns (allocates) it.
// Allocates only ONE page!
//
void *alloc_page(void) {
list_node *n = g_free_mem_list.next;
if (n) g_free_mem_list.next = n->next;
return (void *)n;
}
//
// pmm_init() establishes the list of free physical pages according to available
// physical memory space.
//
void pmm_init() {
// start of kernel program segment
uint64 g_kernel_start = KERN_BASE;
uint64 g_kernel_end = (uint64)&_end;
uint64 pke_kernel_size = g_kernel_end - g_kernel_start;
sprint("PKE kernel start 0x%lx, PKE kernel end: 0x%lx, PKE kernel size: 0x%lx .\n",
g_kernel_start, g_kernel_end, pke_kernel_size);
// free memory starts from the end of PKE kernel and must be page-aligined
free_mem_start_addr = ROUNDUP(g_kernel_end , PGSIZE);
// recompute g_mem_size to limit the physical memory space that our riscv-pke kernel
// needs to manage
g_mem_size = MIN(PKE_MAX_ALLOWABLE_RAM, g_mem_size);
if( g_mem_size < pke_kernel_size )
panic( "Error when recomputing physical memory size (g_mem_size).\n" );
free_mem_end_addr = g_mem_size + DRAM_BASE;
sprint("free physical memory address: [0x%lx, 0x%lx] \n", free_mem_start_addr,
free_mem_end_addr - 1);
sprint("kernel memory manager is initializing ...\n");
// create the list of free pages
create_freepage_list(free_mem_start_addr, free_mem_end_addr);
}

@ -0,0 +1,11 @@
#ifndef _PMM_H_
#define _PMM_H_
// Initialize phisical memeory manager
void pmm_init();
// Allocate a free phisical page
void* alloc_page();
// Free an allocated page
void free_page(void* pa);
#endif

@ -12,12 +12,14 @@
#include "process.h"
#include "elf.h"
#include "string.h"
#include "vmm.h"
#include "pmm.h"
#include "memlayout.h"
#include "spike_interface/spike_utils.h"
//Two functions defined in kernel/usertrap.S
extern char smode_trap_vector[];
extern void return_to_user(trapframe*);
extern void return_to_user(trapframe *, uint64 satp);
// current points to the currently running user-mode application.
process* current = NULL;
@ -36,7 +38,8 @@ void switch_to(process* proc) {
// set up trapframe values (in process structure) that smode_trap_vector will need when
// the process next re-enters the kernel.
proc->trapframe->kernel_sp = proc->kstack; // process's kernel stack
proc->trapframe->kernel_sp = proc->kstack; // process's kernel stack
proc->trapframe->kernel_satp = read_csr(satp); // kernel page table
proc->trapframe->kernel_trap = (uint64)smode_trap_handler;
// SSTATUS_SPP and SSTATUS_SPIE are defined in kernel/riscv.h
@ -51,6 +54,10 @@ void switch_to(process* proc) {
// set S Exception Program Counter (sepc register) to the elf entry pc.
write_csr(sepc, proc->trapframe->epc);
// make user page table. macro MAKE_SATP is defined in kernel/riscv.h. added @lab2_1
uint64 user_satp = MAKE_SATP(proc->pagetable);
// return_to_user() is defined in kernel/strap_vector.S. switch to user mode with sret.
return_to_user(proc->trapframe);
// note, return_to_user takes two parameters @ and after lab2_1.
return_to_user(proc->trapframe, user_satp);
}

@ -13,18 +13,25 @@ typedef struct trapframe_t {
/* offset:256 */ uint64 kernel_trap;
// saved user process counter
/* offset:264 */ uint64 epc;
// kernel page table. added @lab2_1
/* offset:272 */ uint64 kernel_satp;
}trapframe;
// the extremely simple definition of process, used for begining labs of PKE
typedef struct process_t {
// pointing to the stack used in trap handling.
uint64 kstack;
// user page table
pagetable_t pagetable;
// trapframe storing the context of a (User mode) process.
trapframe* trapframe;
}process;
// switch to run user app
void switch_to(process*);
// current running process
extern process* current;
#endif

@ -181,4 +181,46 @@ typedef struct riscv_regs_t {
/* 240 */ uint64 t6;
}riscv_regs;
// following lines are added @lab2_1
static inline void flush_tlb(void) { asm volatile("sfence.vma zero, zero"); }
#define PGSIZE 4096 // bytes per page
#define PGSHIFT 12 // offset bits within a page
// use riscv's sv39 page table scheme.
#define SATP_SV39 (8L << 60)
#define MAKE_SATP(pagetable) (SATP_SV39 | (((uint64)pagetable) >> 12))
#define PTE_V (1L << 0) // valid
#define PTE_R (1L << 1) // readable
#define PTE_W (1L << 2) // writable
#define PTE_X (1L << 3) // executable
#define PTE_U (1L << 4) // 1->user can access, 0->otherwise
#define PTE_G (1L << 5) // global
#define PTE_A (1L << 6) // accessed
#define PTE_D (1L << 7) // dirty
// shift a physical address to the right place for a PTE.
#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)
// convert a pte content into its corresponding physical address
#define PTE2PA(pte) (((pte) >> 10) << 12)
// extract the property bits of a pte
#define PTE_FLAGS(pte) ((pte)&0x3FF)
// extract the three 9-bit page table indices from a virtual address.
#define PXMASK 0x1FF // 9 bits
#define PXSHIFT(level) (PGSHIFT + (9 * (level)))
#define PX(level, va) ((((uint64)(va)) >> PXSHIFT(level)) & PXMASK)
// one beyond the highest possible virtual address.
// MAXVA is actually one bit less than the max allowed by
// Sv39, to avoid having to sign-extend virtual addresses
// that have the high bit set.
#define MAXVA (1L << (9 + 9 + 9 + 12 - 1))
typedef uint64 pte_t;
typedef uint64 *pagetable_t; // 512 PTEs
#endif

@ -37,6 +37,11 @@ smode_trap_vector:
# load the address of smode_trap_handler() from p->trapframe->kernel_trap
ld t0, 256(a0)
# restore kernel page table from p->trapframe->kernel_satp. added @lab2_1
ld t1, 272(a0)
csrw satp, t1
sfence.vma zero, zero
# jump to smode_trap_handler() that is defined in kernel/trap.c
jr t0
@ -48,6 +53,13 @@ smode_trap_vector:
#
.globl return_to_user
return_to_user:
# a0: TRAPFRAME
# a1: user page table, for satp.
# switch to the user page table. added @lab2_1
csrw satp, a1
sfence.vma zero, zero
# [sscratch]=[a0], save a0 in sscratch, so sscratch points to a trapframe now.
csrw sscratch, a0

@ -10,14 +10,19 @@
#include "string.h"
#include "process.h"
#include "util/functions.h"
#include "pmm.h"
#include "vmm.h"
#include "spike_interface/spike_utils.h"
//
// implement the SYS_user_print syscall
//
ssize_t sys_user_print(const char* buf, size_t n) {
sprint(buf);
// buf is now an address in user space of the given app's user stack,
// so we have to transfer it into phisical address (kernel is running in direct mapping).
assert( current );
char* pa = (char*)user_va_to_pa((pagetable_t)(current->pagetable), (void*)buf);
sprint(pa);
return 0;
}

@ -0,0 +1,173 @@
/*
* virtual address mapping related functions.
*/
#include "vmm.h"
#include "riscv.h"
#include "pmm.h"
#include "util/types.h"
#include "memlayout.h"
#include "util/string.h"
#include "spike_interface/spike_utils.h"
#include "util/functions.h"
/* --- utility functions for virtual address mapping --- */
//
// establish mapping of virtual address [va, va+size] to phyiscal address [pa, pa+size]
// with the permission of "perm".
//
int map_pages(pagetable_t page_dir, uint64 va, uint64 size, uint64 pa, int perm) {
uint64 first, last;
pte_t *pte;
for (first = ROUNDDOWN(va, PGSIZE), last = ROUNDDOWN(va + size - 1, PGSIZE);
first <= last; first += PGSIZE, pa += PGSIZE) {
if ((pte = page_walk(page_dir, first, 1)) == 0) return -1;
if (*pte & PTE_V)
panic("map_pages fails on mapping va (0x%lx) to pa (0x%lx)", first, pa);
*pte = PA2PTE(pa) | perm | PTE_V;
}
return 0;
}
//
// convert permission code to permission types of PTE
//
uint64 prot_to_type(int prot, int user) {
uint64 perm = 0;
if (prot & PROT_READ) perm |= PTE_R | PTE_A;
if (prot & PROT_WRITE) perm |= PTE_W | PTE_D;
if (prot & PROT_EXEC) perm |= PTE_X | PTE_A;
if (perm == 0) perm = PTE_R;
if (user) perm |= PTE_U;
return perm;
}
//
// traverse the page table (starting from page_dir) to find the corresponding pte of va.
// returns: PTE (page table entry) pointing to va.
//
pte_t *page_walk(pagetable_t page_dir, uint64 va, int alloc) {
if (va >= MAXVA) panic("page_walk");
// starting from the page directory
pagetable_t pt = page_dir;
// traverse from page directory to page table.
// as we use risc-v sv39 paging scheme, there will be 3 layers: page dir,
// page medium dir, and page table.
for (int level = 2; level > 0; level--) {
// macro "PX" gets the PTE index in page table of current level
// "pte" points to the entry of current level
pte_t *pte = pt + PX(level, va);
// now, we need to know if above pte is valid (established mapping to a phyiscal page)
// or not.
if (*pte & PTE_V) { //PTE valid
// phisical address of pagetable of next level
pt = (pagetable_t)PTE2PA(*pte);
} else { //PTE invalid (not exist).
// allocate a page (to be the new pagetable), if alloc == 1
if( alloc && ((pt = (pte_t *)alloc_page(1)) != 0) ){
memset(pt, 0, PGSIZE);
// writes the physical address of newly allocated page to pte, to establish the
// page table tree.
*pte = PA2PTE(pt) | PTE_V;
}else //returns NULL, if alloc == 0, or no more physical page remains
return 0;
}
}
// return a PTE which contains phisical address of a page
return pt + PX(0, va);
}
//
// look up a virtual page address, return the physical page address or 0 if not mapped.
//
uint64 lookup_pa(pagetable_t pagetable, uint64 va) {
pte_t *pte;
uint64 pa;
if (va >= MAXVA) return 0;
pte = page_walk(pagetable, va, 0);
if (pte == 0 || (*pte & PTE_V) == 0 || ((*pte & PTE_R) == 0 && (*pte & PTE_W) == 0))
return 0;
pa = PTE2PA(*pte);
return pa;
}
/* --- kernel page table part --- */
// _etext is defined in kernel.lds, it points to the address after text and rodata segments.
extern char _etext[];
// pointer to kernel page director
pagetable_t g_kernel_pagetable;
//
// maps virtual address [va, va+sz] to [pa, pa+sz] (for kernel).
//
void kern_vm_map(pagetable_t page_dir, uint64 va, uint64 pa, uint64 sz, int perm) {
// map_pages is defined in kernel/vmm.c
if (map_pages(page_dir, va, sz, pa, perm) != 0) panic("kern_vm_map");
}
//
// kern_vm_init() constructs the kernel page table.
//
void kern_vm_init(void) {
// pagetable_t is defined in kernel/riscv.h. it's actually uint64*
pagetable_t t_page_dir;
// allocate a page (t_page_dir) to be the page directory for kernel. alloc_page is defined in kernel/pmm.c
t_page_dir = (pagetable_t)alloc_page();
// memset is defined in util/string.c
memset(t_page_dir, 0, PGSIZE);
// map virtual address [KERN_BASE, _etext] to physical address [DRAM_BASE, DRAM_BASE+(_etext - KERN_BASE)],
// to maintain (direct) text section kernel address mapping.
kern_vm_map(t_page_dir, KERN_BASE, DRAM_BASE, (uint64)_etext - KERN_BASE,
prot_to_type(PROT_READ | PROT_EXEC, 0));
sprint("KERN_BASE 0x%lx\n", lookup_pa(t_page_dir, KERN_BASE));
// also (direct) map remaining address space, to make them accessable from kernel.
// this is important when kernel needs to access the memory content of user's app
// without copying pages between kernel and user spaces.
kern_vm_map(t_page_dir, (uint64)_etext, (uint64)_etext, PHYS_TOP - (uint64)_etext,
prot_to_type(PROT_READ | PROT_WRITE, 0));
sprint("physical address of _etext is: 0x%lx\n", lookup_pa(t_page_dir, (uint64)_etext));
g_kernel_pagetable = t_page_dir;
}
/* --- user page table part --- */
//
// convert and return the corresponding physical address of a virtual address (va) of
// application.
//
void *user_va_to_pa(pagetable_t page_dir, void *va) {
// TODO (lab2_1): implement user_va_to_pa to convert a given user virtual address "va"
// to its corresponding physical address, i.e., "pa". To do it, we need to walk
// through the page table, starting from its directory "page_dir", to locate the PTE
// that maps "va". If found, returns the "pa" by using:
// pa = PYHS_ADDR(PTE) + (va & (1<<PGSHIFT -1))
// Here, PYHS_ADDR() means retrieving the starting address (4KB aligned), and
// (va & (1<<PGSHIFT -1)) means computing the offset of "va" inside its page.
// Also, it is possible that "va" is not mapped at all. in such case, we can find
// invalid PTE, and should return NULL.
panic( "You have to implement user_va_to_pa (convert user va to pa) to print messages in lab2_1.\n" );
}
//
// maps virtual address [va, va+sz] to [pa, pa+sz] (for user application).
//
void user_vm_map(pagetable_t page_dir, uint64 va, uint64 size, uint64 pa, int perm) {
if (map_pages(page_dir, va, size, pa, perm) != 0) {
panic("fail to user_vm_map .\n");
}
}

@ -0,0 +1,33 @@
#ifndef _VMM_H_
#define _VMM_H_
#include "riscv.h"
/* --- utility functions for virtual address mapping --- */
int map_pages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm);
// permission codes.
enum VMPermision {
PROT_NONE = 0,
PROT_READ = 1,
PROT_WRITE = 2,
PROT_EXEC = 4,
};
uint64 prot_to_type(int prot, int user);
pte_t *page_walk(pagetable_t pagetable, uint64 va, int alloc);
uint64 lookup_pa(pagetable_t pagetable, uint64 va);
/* --- kernel page table --- */
// pointer to kernel page directory
extern pagetable_t g_kernel_pagetable;
void kern_vm_map(pagetable_t page_dir, uint64 va, uint64 pa, uint64 sz, int perm);
// Initialize the kernel pagetable
void kern_vm_init(void);
/* --- user page table --- */
void *user_va_to_pa(pagetable_t page_dir, void *va);
void user_vm_map(pagetable_t page_dir, uint64 va, uint64 size, uint64 pa, int perm);
#endif

@ -0,0 +1,12 @@
/*
* Below is the given application for lab2_1.
* This app runs in its own address space, in contrast with in direct mapping.
*/
#include "user_lib.h"
#include "util/types.h"
int main(void) {
printu("Hello world!\n");
exit(0);
}

@ -1,20 +0,0 @@
/*
* Below is the given application for lab1_3.
* This app performs a long loop, during which, timers are
* generated and pop messages to our screen.
*/
#include "user_lib.h"
#include "util/types.h"
int main(void) {
printu("Hello world!\n");
int i;
for (i = 0; i < 100000000; ++i) {
if (i % 5000000 == 0) printu("wait %d\n", i);
}
exit(0);
return 0;
}

@ -1,14 +0,0 @@
OUTPUT_ARCH( "riscv" )
ENTRY(main)
SECTIONS
{
. = 0x81000000;
. = ALIGN(0x1000);
.text : { *(.text) }
. = ALIGN(16);
.data : { *(.data) }
. = ALIGN(16);
.bss : { *(.bss) }
}
Loading…
Cancel
Save