add chapter4

pull/1/head
Zhiyuan Shao 4 years ago
parent 13c7e3b428
commit 6b69f2836d

@ -125,6 +125,7 @@ Score: 20/20
其次,我们现在管理的可用内存是那一部分? 代理内核的本质也是一段程序他本身是需要内存空间的而这一段空间自然不能再被分配。除去内核本身占的空间内核可支配的物理空间从0x80016000开始大小在PKE设定为8M2048个页面故而供内核支配的的内存的范围为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结构体同物理地址之间是如何转换的。首先我们需要先了解一下物理地址。
<img src="pictures/fig4_1.png" alt="fig4_1" style="zoom:80%;" />
图4.1 RISCV64 物理地址
图4.1 RISCV64 物理地址
总的来说,物理地址分为两部分页号PPN+offset
总的来说,物理地址分为两部分页号PPNoffset
页号可以理解为物理页的编码而offset则为页内偏移量。现在考虑一下12位的offset对应的内存大小是多少呢
@ -207,7 +206,9 @@ Page结构体对应着物理页我们来看Page结构体同物理地址之间
实际上在初始化空闲页链表之前系统会定义一个Page结构体的数组而链表的节点也正是来自于这些数组这个数组的每一项代表着一个物理页而且它们的数组下标就代表着每一项具体代表的是哪一个物理页就如下图所示
<img src="pictures/fig4_2.png" alt="fig4_2" style="zoom:80%;" />
@ -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得到对应的函数并最终执行系统调用。

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Loading…
Cancel
Save