Linux project - PGD present bit

前情提要

延續上一篇,這篇記錄Project主要內容的實作過程。

題目的要求是:For each page directory entry with an index located in the group of indexes specified by the parameters, this system call shows the value of the present field of the entry.

簡單說就是新增一個system call
讓它可以取得當前process的page global directory entry中的present bit
參數包含兩個integer代表起始和結尾index
和一個陣列指標參數,存放結果

過程

新增system call和compile kernel的方法都在上一篇中,這邊不再贅述。


首先我們得先知道kernel中有個current指標能取得目前執行process的task_struct
而current->mm則會取得跟這個process memory management相關的mm_struct
current->mm->pgd就指向我們page directory table的開頭位址



再來我們先觀察Linux在32位元下的Linear address

Directory有10 bits、page table 10 bits、offset 22 bits
最左邊10 bits其實就可看作page directory的index
總共1024個page directory



我們的目標就是directory中entry的present
要得到某個page directory table中的entry可以用下面這種方式:
current->mm->pgd[index]
它是一條長度1024的pgd_t陣列



有了page directory entry後
page directory entry的value第一位bit其實就是present bit

那就可以像下面這樣子取得present bit:
pgd_val(current->mm->pgd[index]) & 0x01

pgd_val是取得pgd_t實際的值

最後的程式碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <linux/sched.h>
#include <asm/current.h>
#include <asm/pgtable.h>
asmlinkage int sys_address_space_survey(int first, int last, int *result) {
pgd_t *pgd = current->mm->pgd; //base address of pgd table
int pst;
int addr = first;
while(addr <= last) {
pst = pgd_val(pgd[addr]) & 0x1; //get present bit
result[addr] = pst;
printk("pgd[%d] present bit is %x\n", addr, pst);
addr++;
}
}

然後編譯kernel時PAE記得關
不然結果會不正確
make meunconfig時取消PAE(Ubuntu這版本預設有開)
Processor type and features -> High Memory Support -> off

結果


從768以下的present bit結果可觀察出三份程式中
都各有一段連續的present bit是1
但所在位置都不同,這段連續的1其實就是對應到a[SIZE]
仔細觀察可發現三份code的a[SIZE]陣列剛好分別在stack、bss、heap段
而從present bit分布狀況來看的確符合不同區段的相對位置



註1: 這邊必須設定過a[SIZE]陣列中的元素才會使pgd present bit被設定
例如:for(int i = 0; i < SIZE; ++i) a[i] = i; 即可



註2: 因為原本SIZE有點小,可以設大一點方便觀察結果,例如設10000000
但因為SIZE很大,所以可能會Segmentation fault,可以用ulimit -s來增大stack size
(這部分感謝jxcode大神指點)



註3: 觀察可發現三份code在index 32那個pgd present bit都是1
是因為code也需要有地方存放,那其實就是存放code的區段

而三個程式在entry 768以上的present bit都是相同的
驗證了我們學過的: Kernel是映射到0xc0000000以上
(0xc0000000 >> 22 = 768)

整體似乎沒啥難度,主要是編kernel太花時間還有細節很多要注意的地方…
當初熬夜3天才做完QQ