From 6b69f2836d2e6a79ef10a395331b44a7e37f4b2c Mon Sep 17 00:00:00 2001 From: Zhiyuan Shao Date: Thu, 22 Oct 2020 14:56:44 +0800 Subject: [PATCH] add chapter4 --- chapter4.md | 122 ++++++++------------------------------------ pictures/fig4_1.png | Bin 0 -> 3691 bytes pictures/fig4_2.png | Bin 0 -> 13489 bytes 3 files changed, 20 insertions(+), 102 deletions(-) create mode 100644 pictures/fig4_1.png create mode 100644 pictures/fig4_2.png diff --git a/chapter4.md b/chapter4.md index 1b351a3..87c23e5 100644 --- a/chapter4.md +++ b/chapter4.md @@ -125,6 +125,7 @@ Score: 20/20 其次,我们现在管理的可用内存是那一部分? 代理内核的本质也是一段程序,他本身是需要内存空间的,而这一段空间自然不能再被分配。除去内核本身占的空间,内核可支配的物理空间从0x80016000开始,大小在PKE设定为8M,2048个页面,故而供内核支配的的内存的范围为(first_free_page~first_free_paddr)。如下图所示。 +``` KERNTOP------->+---------------------------------+ 0x80816000 (first_free_paddr) | | @@ -166,22 +167,20 @@ kernel/user ​ | | first_free_paddr->+------------------------------------------------------+ 0x80816000 +``` 最后,我们来看物理内存分配的单位:操作系统中,物理页是物理内存分配的基本单位。一个物理页的大小是4KB,我们使用结构体Page来表示,其结构如图: +``` struct Page { - sint_t ref; - uint_t flags; - uint_t property; - list_entry_t page_link; - }; +``` l ref表示这样页被页表的引用记数 @@ -193,11 +192,11 @@ l page_link是维持空闲物理页链表的重要结构。 Page结构体对应着物理页,我们来看Page结构体同物理地址之间是如何转换的。首先,我们需要先了解一下物理地址。 -​ +fig4_1 -​ 图4.1 RISCV64 物理地址 +图4.1 RISCV64 物理地址 -总的来说,物理地址分为两部分,页号(PPN)+offset +总的来说,物理地址分为两部分:页号(PPN)和offset 页号可以理解为物理页的编码,而offset则为页内偏移量。现在考虑一下12位的offset对应的内存大小是多少呢? @@ -207,7 +206,9 @@ Page结构体对应着物理页,我们来看Page结构体同物理地址之间 实际上在初始化空闲页链表之前,系统会定义一个Page结构体的数组,而链表的节点也正是来自于这些数组,这个数组的每一项代表着一个物理页,而且它们的数组下标就代表着每一项具体代表的是哪一个物理页,就如下图所示: - + fig4_2 + + @@ -217,65 +218,43 @@ Page结构体对应着物理页,我们来看Page结构体同物理地址之间 在PK的machine/minit.c中间中,便通过delegate_traps(),将部分中断及同步异常委托给S模式。(同学们可以查看具体是哪些中断及同步异常) +``` 43 // send S-mode interrupts and most exceptions straight to S-mode - 44 static void delegate_traps() - 45 { - 46 if (!supports_extension('S')) - 47 return; - 48 - 49 uintptr_t interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP; - 50 uintptr_t exceptions = - 51 (1U << CAUSE_MISALIGNED_FETCH) | - 52 (1U << CAUSE_FETCH_PAGE_FAULT) | - 53 (1U << CAUSE_BREAKPOINT) | - 54 (1U << CAUSE_LOAD_PAGE_FAULT) | - 55 (1U << CAUSE_STORE_PAGE_FAULT) | - 56 (1U << CAUSE_USER_ECALL); - 57 - 58 write_csr(mideleg, interrupts); - 59 write_csr(medeleg, exceptions); - 60 assert(read_csr(mideleg) == interrupts); - 61 assert(read_csr(medeleg) == exceptions); - 62 } +``` ​ 这里介绍一下RISCV的中断委托机制,在默认的情况下,所有的异常都会被交由机器模式处理。但正如我们知道的那样,大部分的系统调用都是在S模式下处理的,因此RISCV提供了这一委托机制,可以选择性的将中断交由S模式处理,从而完全绕过M模式。 ​ 接下,我们继续看S模式下的中断处理。在pk目录下的pk.c文件中的boot_loader函数中将&trap_entry写入了stvec寄存器中,stvec保存着发生异常时处理器需要跳转到的地址,也就是说当中断发生,我们将跳转至trap_entry,现在我们继续跟踪trap_entry。trap_entry在pk目录下的entry.S中,其代码如下: +``` 60 trap_entry: - 61 csrrw sp, sscratch, sp - 62 bnez sp, 1f - 63 csrr sp, sscratch - 64 1:addi sp,sp,-320 - 65 save_tf - 66 move a0,sp - 67 jal handle_trap +``` ​ 在61行,交换了sp与sscratch的值,这里是为了根据sscratch的值判断该中断是来源于U模式还是S模式。 @@ -283,148 +262,87 @@ Page结构体对应着物理页,我们来看Page结构体同物理地址之间 ​ 接着在64,65行保存上下文,最后跳转至67行处理trap。handle_trap在pk目录下的handlers.c文件中,代码如下: +``` 112 void handle_trap(trapframe_t* tf) - 113 { - 114 if ((intptr_t)tf->cause < 0) - 115 return handle_interrupt(tf); - 116 - 117 typedef void (*trap_handler)(trapframe_t*); - 118 - 119 const static trap_handler trap_handlers[] = { - 120 [CAUSE_MISALIGNED_FETCH] = handle_misaligned_fetch, - 121 [CAUSE_FETCH_ACCESS] = handle_instruction_access_fault, - 122 [CAUSE_LOAD_ACCESS] = handle_load_access_fault, - 123 [CAUSE_STORE_ACCESS] = handle_store_access_fault, - 124 [CAUSE_FETCH_PAGE_FAULT] = handle_fault_fetch, - 125 [CAUSE_ILLEGAL_INSTRUCTION] = handle_illegal_instruction, - 126 [CAUSE_USER_ECALL] = handle_syscall, - 127 [CAUSE_BREAKPOINT] = handle_breakpoint, - 128 [CAUSE_MISALIGNED_LOAD] = handle_misaligned_load, - 129 [CAUSE_MISALIGNED_STORE] = handle_misaligned_store, - 130 [CAUSE_LOAD_PAGE_FAULT] = handle_fault_load, - 131 [CAUSE_STORE_PAGE_FAULT] = handle_fault_store, - 132 }; +``` ​ handle_trap函数中实现了S模式下各类中断的处理。可以看到,代码的126行就对应着系统调用的处理,handle_syscall的实现如下: +``` 100 static void handle_syscall(trapframe_t* tf) - 101 { - 102 tf->gpr[10] = do_syscall(tf->gpr[10], tf->gpr[11], tf->gpr[12], tf->gpr[13], - 103 tf->gpr[14], tf->gpr[15], tf->gpr[17]); - 104 tf->epc += 4; - 105 } +``` ​ 还记得我们在例3.1中是将中断号写入x17寄存器嘛?其对应的就是这里do_syscall的最后一个参数,我们跟踪进入do_syscall函数,其代码如下: +``` 313 long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, unsigned long n) - 314 { - 315 const static void* syscall_table[] = { - 316 // your code here: - 317 // add get_init_memsize syscall - 318 [SYS_init_memsize ] = sys_get_init_memsize, - 319 [SYS_exit] = sys_exit, - 320 [SYS_exit_group] = sys_exit, - 321 [SYS_read] = sys_read, - 322 [SYS_pread] = sys_pread, - 323 [SYS_write] = sys_write, - 324 [SYS_openat] = sys_openat, - 325 [SYS_close] = sys_close, - 326 [SYS_fstat] = sys_fstat, - 327 [SYS_lseek] = sys_lseek, - 328 [SYS_renameat] = sys_renameat, - 329 [SYS_mkdirat] = sys_mkdirat, - 330 [SYS_getcwd] = sys_getcwd, - 331 [SYS_brk] = sys_brk, - 332 [SYS_uname] = sys_uname, - 333 [SYS_prlimit64] = sys_stub_nosys, - 334 [SYS_rt_sigaction] = sys_rt_sigaction, - 335 [SYS_times] = sys_times, - 336 [SYS_writev] = sys_writev, - 337 [SYS_readlinkat] = sys_stub_nosys, - 338 [SYS_rt_sigprocmask] = sys_stub_success, - 339 [SYS_ioctl] = sys_stub_nosys, - 340 [SYS_getrusage] = sys_stub_nosys, - 341 [SYS_getrlimit] = sys_stub_nosys, - 342 [SYS_setrlimit] = sys_stub_nosys, - 343 [SYS_set_tid_address] = sys_stub_nosys, - 344 [SYS_set_robust_list] = sys_stub_nosys, - 345 }; - 346 - 347 syscall_t f = 0; - 348 - 349 if (n < ARRAY_SIZE(syscall_table)) - 350 f = syscall_table[n]; - 351 if (!f) - 352 panic("bad syscall #%ld!",n); - 353 - 354 return f(a0, a1, a2, a3, a4, a5, n); - 355 } +``` ​ do_syscall中通过传入的系统调用号n,查询syscall_table得到对应的函数,并最终执行系统调用。 \ No newline at end of file diff --git a/pictures/fig4_1.png b/pictures/fig4_1.png new file mode 100644 index 0000000000000000000000000000000000000000..7bd272eb1c17cffcc91ab0b8505b0e606d0665b6 GIT binary patch literal 3691 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 b#p|~C#&$i%iYCxTzg1S|s7rJ+kNE!rXXO-l literal 0 HcmV?d00001 diff --git a/pictures/fig4_2.png b/pictures/fig4_2.png new file mode 100644 index 0000000000000000000000000000000000000000..a50b8ba64833a6b99e4be7e7a1d37a332cded0cd GIT binary patch literal 13489 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 i3eYJD}8frY<_EBm|tW}`?fu-fnN`P&U> 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