Download presentation
Presentation is loading. Please wait.
1
獨孤派作業系統 main memory 中正大學 作業系統實驗室 指導教授:羅習五
2
負責助教 作業目標: 懶人包: 負責助教 繳交期限:107/12/13 23:59:59,繳交方式:助教於12/6前公佈
了解Linux的paging機制 了解x86的paging機制 懶人包: 和上一次作業相同 負責助教 吳孟昕 繳交期限:107/12/13 23:59:59,繳交方式:助教於12/6前公佈
3
設定核心 make menuconfig 進入kernel hacking,並選擇下面二個選項 再次確認
<*> Export kernel pagetable layout to userspace via debugfs [*] Dump the EFI pagetable 這二個選項預設不會打開,因為打開以後可能會造成系統漏洞 再次確認 > cat .config | grep CONFIG_X86_PTDUMP CONFIG_X86_PTDUMP_CORE=y CONFIG_X86_PTDUMP=y
4
預備編譯核心的環境 $ sudo apt install git flex bison bc libssl-dev gawk libudev-dev ocl-icd-opencl-dev libpci-dev libelf- dev python2.7 libncurses-dev fakeroot kernel-wedge binfmt-support ksh lsscsi binfmt-support libpcre16-3 libpcre3-dev libpcre32-3 libpcrecpp0v5 libsepol1-dev libattr1-dev libblkid-dev libpcre16-3 libpcre3-dev libpcre32-3 libpcrecpp0v5 libselinux1-dev libsepol1-dev uuid-dev debugedit libarchive13 libdw1 liblua5.2-0 liblzo2-2 libnspr4 libnss3 librpm8 librpmbuild8 librpmio8 librpmsign8 rpm rpm-common rpm2cpio spl-dkms kernel-package
5
編譯核心 sudo update-alternatives --config gcc
/*如果編譯kernel 4.0,請選擇gcc 4.8*/ make -j8 /*-j8代表產生8個task讓系統平行化編譯核心*/ /*一般來說,4核心就選8或16編譯的整體速度較快*/ /*如果使用QEMU,下面三個步驟不用做*/ make modules sudo make modules_install sudo make install
6
核心記憶體 如果是kernel 4.0請使用 右方的指令 pgd是512GB的映射 pud是1GB的映射 pmd是2MB的映射
cat /sys/kernel/debug/kernel_page_tables ---[ User Space ]--- 0x xffff T pgd ---[ Kernel Space ]--- 0xffff xffff T pgd ---[ Low Kernel Mapping ]--- 0xffff xffff K RW GLB NX pte 0xffff xffff a K ro GLB NX pte 0xffff a000-0xffff b K ro GLB x pte 0xffff b000-0xffff K RW GLB NX pte 0xffff xffff M RW PSE GLB NX pmd 0xffff xffff880001c M ro PSE GLB NX pmd 0xffff880001c xffff880001d K ro GLB NX pte 0xffff880001d xffff880001e K RW GLB NX pte 0xffff880001e xffff M ro PSE GLB NX pmd 0xffff xffff d K ro GLB NX pte 0xffff d2000-0xffff K RW GLB NX pte 0xffff xffff88000fc M RW PSE GLB NX pmd 0xffff88000fc xffff88000ffe K RW GLB NX pte 0xffff88000ffe0000-0xffff K pte 0xffff xffff M pmd 0xffff xffff G pud 0xffff xffffc G pgd /*後面有些被截斷*/ 核心記憶體 如果是kernel 4.0請使用 右方的指令 pgd是512GB的映射 pud是1GB的映射 pmd是2MB的映射 pte是4KB的映射
7
核心記憶體 如果是kernel 4.19請使用 右方的指令 pud是1GB的映射 pmd是2MB的映射 pte是4KB的映射
cat /sys/kernel/debug/page_tables/kernel ---[ User Space ]--- 0x xffff T pgd ---[ Kernel Space ]--- 0xffff xffff T pgd ---[ Low Kernel Mapping ]--- 0xffff xffff K RW GLB NX pte 0xffff xffff a K ro GLB NX pte 0xffff a000-0xffff b K ro GLB x pte 0xffff b000-0xffff K RW GLB NX pte 0xffff xffff M RW PSE GLB NX pmd 0xffff xffff880001c M ro PSE GLB NX pmd 0xffff880001c xffff880001d K ro GLB NX pte 0xffff880001d xffff880001e K RW GLB NX pte 0xffff880001e xffff M ro PSE GLB NX pmd 0xffff xffff d K ro GLB NX pte 0xffff d2000-0xffff K RW GLB NX pte 0xffff xffff88000fc M RW PSE GLB NX pmd 0xffff88000fc xffff88000ffe K RW GLB NX pte 0xffff88000ffe0000-0xffff K pte 0xffff xffff M pmd 0xffff xffff G pud 0xffff xffffc G pgd /*後面有些被截斷*/ 核心記憶體 如果是kernel 4.19請使用 右方的指令 pud是1GB的映射 pmd是2MB的映射 pte是4KB的映射
8
paging with multiple page size: x86-Linux,pte page
pgd_offset, 9 bits pud_offset, 9 bits pmd_offset, 9 bits pte_offset, 9 bits offset, 12 bits 4k data page cr3 task_struct->mm->pgd
9
paging with multiple page size: x86-Linux,pmd page
pgd_offset, 9 bits pud_offset, 9 bits pmd_offset, 9 bits offset, 12+9 = 21 bits 2M data page cr3 task_struct->mm->pgd
10
paging with multiple page size: x86-Linux,pud page
pgd_offset, 9 bits pud_offset, 9 bits offset, = 30 bits 1GB data page cr3 task_struct->mm->pgd
11
paging with multiple page size: x86-Linux ,pgd page (軟體上存在,硬體上沒有)
pgd_offset, 9 bits offset, = 39 bits 512 GB data page cr3 task_struct->mm->pgd
12
Linux如何印出kernel page table
程式碼在 /arch/x86/mm/dump_pagetables.c 以下投影片全部都用kernel 4.10舉例 4.19的程式碼註解比較清楚 但4.10是我們可以直接拿來用QEMU除錯的核心,因此用4.10舉例
13
dump_pagetables.c的初始化 /arch/x86/mm/dump_pagetables.c
static int __init pt_dump_init(void) { //PAGE_OFFSET就是核心的開始位址,注意是virtual address address_markers[LOW_KERNEL_NR].start_address = PAGE_OFFSET; address_markers[VMALLOC_START_NR].start_address = VMALLOC_START; address_markers[VMEMMAP_START_NR].start_address = VMEMMAP_START; } //告訴核心,使用pt_dump_init這個函數初始化這個「功能模組」 __initcall(pt_dump_init);
14
註冊檔案操作 /arch/x86/mm/debug_pagetables.c
static const struct file_operations ptdump_fops = { .owner = THIS_MODULE, .open = ptdump_open, /*當有人要打開這個檔案,就呼叫ptdump_open*/ .read = seq_read, /*當要read*/ .llseek = seq_lseek, /*當要lseek*/ .release = single_release, /*不需要這個檔案時,例如:close*/ /*沒有.write,表示這個檔案不支援寫入*/ }; static int __init pt_dump_debug_init(void){ /*告訴核心當有人要打開kernel_page_tables這個檔案時應該呼叫哪些函數,函數定義在ptdump_fops*/ pe = debugfs_create_file("kernel_page_tables", S_IRUSR, NULL, NULL, &ptdump_fops); } module_init(pt_dump_debug_init);
15
(gdb) b ptdump_show (QEMU) $ cat /sys/kernel/debug/kernel_page_tables
16
附錄:記憶體位址轉換 //for kernel mapping only
phys_addr = virt_to_phys(virt_addr); virt_addr = phys_to_virt(phys_addr); bus_addr = virt_to_bus(virt_addr); virt_addr = bus_to_virt(bus_addr); #define virt_to_bus virt_to_phys #define bus_to_virt phys_to_virt void *phys_to_virt(phys_addr_t address) { return __va(address); } #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) phys_addr_t virt_to_phys(volatile void *address) { return __pa(address);} #define __pa(x) __phys_addr((unsigned long)(x))
17
cr2 = read_cr2(); cr3 = read_cr3();
18
control registers https://en.wikipedia.org/wiki/Control_register
我們只用到CR2與CR3
19
與MMU相關的暫存器 - CR2與CR3
20
4KB page
21
2MB page
22
1GB page
23
CR3 & PTE
24
format of 4KB page table entry
25
關於x86-64的paging機制 更詳細的資料請參考Intel技術手冊 Volume 3, Chapter 4.5
閱讀文件時,請注意一下日期, 如右圖紅色的標示
26
Default fault handlers
do_anonymous_page: no page and no file do_linear_fault: vm_ops registered? do_swap_page: page backed by swap do_nonlinear_fault: page backed by file do_wp_page: write protected page (CoW)
Similar presentations