1.系統理解

INnoVation-V2發表於2024-04-21

第二章

2.1、xv6程式碼結構

程式碼主要有三個部分組成:

  1. kernel: 我們可以ls kernel,裡面包含了所有的核心檔案。因為XV6是一個單核心結構,這裡所有的檔案會被編譯成一個叫做kernel的二進位制檔案,然後這個二進位制檔案會被執行在kernel mode中。
  2. use: 基本上是執行在user mode的程式。這也是為什麼一個目錄稱為kernel,另一個目錄稱為user的原因。
  3. mkfs: 它會建立一個空的檔案映象,我們會將這個映象存在磁碟上,這樣我們就可以直接使用一個空的檔案系統。

2.2、xv6如何切換不同模式(user/kernel..)

2.3、xv6啟動流程

entry.S開始啟動,在末尾跳轉到start.c

start.c主要完成以下功能:

  1. 在暫存器mstatus中把之前的特權模式設定為監督者模式

  2. 透過把main的地址寫入暫存器mepc來設定返回地址為main

  3. 透過在頁表暫存器satp中寫入0來禁止監督者模式下的虛擬地址轉換

  4. 把所有中斷和異常委託給監督者模式

  5. 對時鐘晶片進行程式設計以產生時鐘中斷

  6. 在完成這些工作後,start透過呼叫mret "返回"到監督者模式。之後程式會跳轉到main(kernel/main.c:11)

main.c中完成以下設定:

consoleinit();
printfinit();
printf("\n");
printf("xv6 kernel is booting\n");
printf("\n");
kinit();         // physical page allocator
kvminit();       // create kernel page table
kvminithart();   // turn on paging
procinit();      // process table
trapinit();      // trap vectors
trapinithart();  // install kernel trap vector
plicinit();      // set up interrupt controller
plicinithart();  // ask PLIC for device interrupts
binit();         // buffer cache
iinit();         // inode table
fileinit();      // file table
virtio_disk_init(); // emulated hard disk
userinit();      // first user process
__sync_synchronize();

之後跳轉到userinit()

透過userinit()中的initcode.s跳轉到user/init.c,(initcode是一段翻譯好的機器碼,彙編格式見user/initcode.S)

init.c中呼叫執行sh.c,啟動完成,

2.4 呼叫系統呼叫的流程

在使用者態中,所有的系統介面都定義在user.h中,透過usys.pl將標頭檔案中的系統介面與真正的系統介面實現連線起來,核心態的系統呼叫介面定義在syscall.h中,具體實現分佈在核心各個檔案中,透過陣列下標索引在syscall.c中引用和呼叫

第三章

3.1 頁表工作流程總結

  1. 三級頁表

  2. 同一個物理頁可對映到多個虛擬地址

  3. 將根頁表實體地址放到satp暫存器中供cpu翻譯地址使用

  4. 核心和每個程序都有自己的頁表

3.2 地址空間

每一頁4KB,需要12位進行索引

虛擬地址

image-20220921014023506

虛擬地址64位,高25位不使用,低12位時頁內索引,中間27位索引三級頁表,每一級頁表使用9位,所以每級頁表最多\(2^9 = 512\)個頁表項,又因為頁大小為4KB = \(2^{12}\)B,所以每一個頁表項大小為\(2^3B=8B=64bit\)

實體地址

核心頁表

image-20220921022817320

程序頁表

image-20220922201251797
程序頁表和虛擬地址空間之間的關係
每個程序的頁表是何時被建立的
虛擬地址空間何時被建立
那些事是CPU指令完成的,那些事是作業系統完成的?

相關文章