需要注意的是,对于我们的模拟RISC-V机器而言,2GB的物理内存并不是从0地址开始编址,而是从0x80000000(见kernel/memlayout.h文件中的DRAM_BASE宏定义)开始编址的。这样做的理由是,部分低物理地址[0x0, 0x80000000]并无物理内存与之对应,该空间留作了MMIO的用途。例如,我们在lab1_3中遇到的CLINT(Core Local Interrupter,timer中断的产生就是通过往这个地址写数据控制的),见kernel/riscv.h文件中的CLINT定义,的地址是0x2000000,就位于这一空间。从0x80000000开始对物理内存进行编址的好处是,避免类似x86平台那样产生内存空洞(memory hole,如640KB~1MB的BIOS空间),从而导致内存的浪费和管理上的复杂性。
10 // the maximum memory space that PKE is allowed to manage 11 #define PKE_MAX_ALLOWABLE_RAM 128 * 1024 * 1024 12 13 // the ending physical address that PKE observes 14 #define PHYS_TOP (DRAM_BASE + PKE_MAX_ALLOWABLE_RAM)
Elf file type is EXEC (Executable file) Entry point 0x100f6 There is 1 program header, starting at offset 64
Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000000000000 0x0000000000010000 0x0000000000010000 0x0000000000000360 0x0000000000000360 R E 0x1000
Section to Segment mapping: Segment Sections... 00 .text .rodata
pte_t *page_walk(pagetable_t page_dir, uint64 va, int alloc);
该函数的第一个输入参数page_dir为根目录所在物理页面的首地址,第二个参数va为所要查找(walk)的逻辑地址,第三个参数实际上是一个bool类型:当它为1时,如果它所要查找的逻辑地址并未建立与物理地址的映射(图4.1中的Page Medium Directory)不存在,则通过分配内存空间建立从根目录到页表的完整映射,并最终返回va所对应的页表项;当它为0时,如果它所要查找的逻辑地址并未建立与物理地址的映射,则返回NULL,否则返回va所对应的页表项。
1 /\* 2 \* Below is the given application for lab2_1. 3 \* This app runs in its own address space, in contrast with in direct mapping. 4 \*/ 5 6 #include "user_lib.h" 7 #include "util/types.h" 8 9 **int** **main**(**void**) { 10 printu("Hello world!\\n"); 11 exit(0); 12 }
//继承lab1_3以及之前的答案 $ git merge lab1_3_irq -m "continue to work on lab2_1"
//重新构造 $ make clean; make
//运行构造结果 $ spike ./obj/riscv-pke ./obj/app_helloworld_no_lds In m_start, hartid:0 HTIF is available! (Emulated) memory size: 2048 MB Enter supervisor mode... PKE kernel start 0x0000000080000000, PKE kernel end: 0x000000008000e000, PKE kernel size: 0x000000000000e000 . free physical memory address: [0x000000008000e000, 0x0000000087ffffff] kernel memory manager is initializing ... KERN_BASE 0x0000000080000000 physical address of _etext is: 0x0000000080004000 kernel page table is on User application is loading. user frame 0x0000000087fbc000, user stack 0x000000007ffff000, user kstack 0x0000000087fbb000 Application: ./obj/app_helloworld_no_lds Application program entry point (virtual address): 0x00000000000100f6 Switching to user mode... You have to implement user_va_to_pa (convert user va to pa) to print messages **in** lab2_1.
$ spike ./obj/riscv-pke ./obj/app_helloworld_no_lds In m_start, hartid:0 HTIF is available! (Emulated) memory size: 2048 MB Enter supervisor mode... PKE kernel start 0x0000000080000000, PKE kernel end: 0x000000008000e000, PKE kernel size: 0x000000000000e000 . free physical memory address: [0x000000008000e000, 0x0000000087ffffff] kernel memory manager is initializing ... KERN_BASE 0x0000000080000000 physical address of _etext is: 0x0000000080004000 kernel page table is on User application is loading. user frame 0x0000000087fbc000, user stack 0x000000007ffff000, user kstack 0x0000000087fbb000 Application: ./obj/app_helloworld_no_lds Application program entry point (virtual address): 0x00000000000100f6 Switching to user mode... Hello world! User exit with code:0. System is shutting down with exit code 0.
21 **ssize_t** **sys_user_print**(**const** **char**\* buf, **size_t** n) { 22 //buf is an address in user space on user stack, 23 //so we have to transfer it into phisical address (kernel is running in direct mapping). 24 assert( current ); 25 **char**\* pa = (**char**\*)user_va_to_pa((pagetable_t)(current->pagetable), (**void**\*)buf); 26 sprint(pa); 27 **return** 0; 28 }
150 **void** \***user_va_to_pa**(pagetable_t page_dir, **void** \*va) { 151 // TODO (lab2_1): implement user_va_to_pa to convert a given user virtual address "va" 152 // to its corresponding physical address, i.e., "pa". To do it, we need to walk 153 // through the page table, starting from its directory "page_dir", to locate the PTE 154 // that maps "va". If found, returns the "pa" by using: 155 // pa = PYHS_ADDR(PTE) + (va - va & (1<<PGSHIFT -1)) 156 // Here, PYHS_ADDR() means retrieving the starting address (4KB aligned), and 157 // (va - va & (1<<PGSHIFT -1)) means computing the offset of "va" in its page. 158 // Also, it is possible that "va" is not mapped at all. in such case, we can find 159 // invalid PTE, and should return NULL. 160 panic( "You have to implement user_va_to_pa (convert user va to pa) to print messages in lab2_1.\\n" ); 161 162 }
//继承lab2_1以及之前的答案 $ git merge lab2_1_pagetable -m "continue to work on lab2_2"
//重新构造 $ make clean; make
//运行构造结果 $ spike ./obj/riscv-pke ./obj/app_naive_malloc In m_start, hartid:0 HTIF is available! (Emulated) memory size: 2048 MB Enter supervisor mode... PKE kernel start 0x0000000080000000, PKE kernel end: 0x000000008000e000, PKE kernel size: 0x000000000000e000 . free physical memory address: [0x000000008000e000, 0x0000000087ffffff] kernel memory manager is initializing ... KERN_BASE 0x0000000080000000 physical address of _etext is: 0x0000000080004000 kernel page table is on User application is loading. user frame 0x0000000087fbc000, user stack 0x000000007ffff000, user kstack 0x0000000087fbb000 Application: ./obj/app_naive_malloc Application program entry point (virtual address): 0x0000000000010078 Switching to user mode... s: 0000000000400000, {a 1} You have to implement user_vm_unmap to free pages using naive_free **in** lab2_2.
$ spike ./obj/riscv-pke ./obj/app_naive_malloc In m_start, hartid:0 HTIF is available! (Emulated) memory size: 2048 MB Enter supervisor mode... PKE kernel start 0x0000000080000000, PKE kernel end: 0x000000008000e000, PKE kernel size: 0x000000000000e000 . free physical memory address: [0x000000008000e000, 0x0000000087ffffff] kernel memory manager is initializing ... KERN_BASE 0x0000000080000000 physical address of _etext is: 0x0000000080004000 kernel page table is on User application is loading. user frame 0x0000000087fbc000, user stack 0x000000007ffff000, user kstack 0x0000000087fbb000 Application: ./obj/app_naive_malloc Application program entry point (virtual address): 0x0000000000010078 Switching to user mode... s: 0000000000400000, {a 1} User exit with code:0. System is shutting down with exit code 0.
1 /\* 2 \* The application of lab2_3. 3 \*/ 4 5 #include "user_lib.h" 6 #include "util/types.h" 7 8 // 9 // compute the summation of an arithmetic sequence. for a given "n", compute 10 // result = n + (n-1) + (n-2) + ... + 0 11 // sum_sequence() calls itself recursively till 0. The recursive call, however, 12 // may consume more memory (from stack) than a physical 4KB page, leading to a page fault. 13 // PKE kernel needs to improved to handle such page fault by expanding the stack. 14 // 15 uint64 **sum_sequence**(uint64 n) { 16 **if** (n == 0) 17 **return** 0; 18 **else** 19 **return** sum_sequence( n-1 ) + n; 20 } 21 22 **int** **main**(**void**) { 23 // we need a large enough "n" to trigger pagefaults in the user stack 24 uint64 n = 1000; 25 26 printu("Summation of an arithmetic sequence from 0 to %ld is: %ld \\n", n, sum_sequence(1000) ); 27 exit(0); 28 }
//继承lab2_2以及之前的答案 $ git merge lab2_2_allocatepage -m "continue to work on lab2_3"
//重新构造 $ make clean; make
//运行构造结果 $ spike ./obj/riscv-pke ./obj/app_sum_sequence In m_start, hartid:0 HTIF is available! (Emulated) memory size: 2048 MB Enter supervisor mode... PKE kernel start 0x0000000080000000, PKE kernel end: 0x000000008000e000, PKE kernel size: 0x000000000000e000 . free physical memory address: [0x000000008000e000, 0x0000000087ffffff] kernel memory manager is initializing ... KERN_BASE 0x0000000080000000 physical address of _etext is: 0x0000000080004000 kernel page table is on User application is loading. user frame 0x0000000087fbc000, user stack 0x000000007ffff000, user kstack 0x0000000087fbb000 Application: ./obj/app_sum_sequence Application program entry point (virtual address): 0x0000000000010096 Switching to user mode... handle_page_fault: 000000007fffdff8 You need to implement the operations that actually handle the page fault **in** lab2_3.
$ spike ./obj/riscv-pke ./obj/app_sum_sequence In m_start, hartid:0 HTIF is available! (Emulated) memory size: 2048 MB Enter supervisor mode... PKE kernel start 0x0000000080000000, PKE kernel end: 0x000000008000e000, PKE kernel size: 0x000000000000e000 . free physical memory address: [0x000000008000e000, 0x0000000087ffffff] kernel memory manager is initializing ... KERN_BASE 0x0000000080000000 physical address of _etext is: 0x0000000080004000 kernel page table is on User application is loading. user frame 0x0000000087fbc000, user stack 0x000000007ffff000, user kstack 0x0000000087fbb000 Application: ./obj/app_sum_sequence Application program entry point (virtual address): 0x0000000000010096 Switching to user mode... handle_page_fault: 000000007fffdff8 handle_page_fault: 000000007fffcff8 handle_page_fault: 000000007fffbff8 Summation of an arithmetic sequence from 0 to 1000 is: 500500 User exit with code:0. System is shutting down with exit code 0.
49 **void** **handle_user_page_fault**(uint64 mcause, uint64 sepc, uint64 stval) { 50 sprint("handle_page_fault: %lx\\n", stval); 51 **switch** (mcause) { 52 **case** CAUSE_STORE_PAGE_FAULT: 53 // TODO (lab2_3): implement the operations that solve the page fault to 54 // dynamically increase application stack. 55 // hint: first allocate a new physical page, and then, maps the new page to the 56 // virtual address that causes the page fault. 57 panic( "You need to implement the operations that actually handle the page fault in lab2_3.\\n" ); 58 59 **break**; 60 **default**: 61 sprint("unknown page fault.\\n"); 62 **break**; 63 } 64 }