Я работаю с упрощенной сборкой Linux 3.18.20, и мне нужно создать два новых системных вызова: один, который читает запись в таблице страниц для данного виртуального адреса, и тот, который записывает запись в таблицу страниц, соответствующую данному виртуальному адресу. Я использую Справочное руководство по архитектуре Intel, том. 3, глава 4, раздел 5, чтобы понять, как виртуальные адреса преобразуются в физические адреса, и для реализации моих системных вызовов я создал вспомогательную функцию, которая возвращает виртуальный адрес запрашиваемой записи таблицы страниц (или NULL, если эта запись в таблице страниц не существует).Bit-Shifting для поиска записи таблицы страниц для данного виртуального адреса в Linux
Я создал тестовую программу, которая создает локальную переменную (предположительно сохраненную в стеке, правильно?) И передает свой виртуальный адрес моему системному вызову, чтобы убедиться, что мой перевод выполнен правильно. Затем я делаю все, что нужно сделать, чтобы убедиться, что мой код делает то, что я думаю; и это кажется правильным, поэтому единственный вывод, который я могу прийти к этому вопросу, заключается в том, что я не знаю, чего я не знаю; Мне нужна важная информация, которую я даже не понимал, что мне нужно.
Можете ли вы посмотреть на мой код и рассказать мне, есть ли что-то очевидное, что я делаю неправильно?
unsigned long *find_pte(unsigned long vaddr) {
unsigned long cr3, pml4_addr, pml4e, pml4e_addr;
unsigned long pdpt_addr, pdpte_addr, pdpte;
unsigned long pd_addr, pde_addr, pde;
unsigned long pt_addr, pte_addr;
unsigned long vaddr30thru38, vaddr39thru47, vaddr21thru29, vaddr12thru20;
cr3 = (unsigned long) get_pagetable();
/* get_pageable() is a helper function, provided by my professor,
that supposedly returns the contents of the CR3 register, with the most
significant and least significant 12 bits replaced with 0.*/
printk("in syscall: vaddr=%lx, cr3=%lx\n", vaddr, cr3);//DEBUG
pml4_addr = cr3;
vaddr39thru47 = (vaddr >> 36) & 0xff8;
printk("in syscall: vaddr39thru47=%lx\n", vaddr39thru47);//DEBUG
pml4e_addr = pml4_addr | vaddr39thru47;
printk("in syscall: physical pml4e_addr=%lx\n", pml4e_addr);//DEBUG
pml4e_addr = (unsigned long) __va(pml4e_addr);
printk("in syscall: virtual pml4e_addr=%lx\n", pml4e_addr);//DEBUG
pml4e = *((unsigned long*) pml4e_addr);
printk("in syscall: pml4e=%lx\n", pml4e);//DEBUG
if ((pml4e & 1) == 0) {
printk("in syscall: pml4e's valid bit is not set\n");//DEBUG
return NULL;
}
printk("in syscall: pml4e's valid bit is set\n");//DEBUG
vaddr30thru38 = (vaddr >> 27) & 0xff8;
printk("in syscall: vaddr30thru38=%lx\n", vaddr30thru38);
pdpte_addr = (pdpt_addr | vaddr30thru38);
printk("in syscall: physical pdpte_addr=%lx\n", pdpte_addr);//DEBUG
pdpte_addr = (unsigned long) __va(pdpte_addr);
printk("in syscall: virtual pdpte_addr=%lx\n", pdpte_addr);//DEBUG
pdpte = *((unsigned long*) pdpte_addr);
printk("in syscall: pdpte=%lx\n", pdpte);//DEBUG
if (((pdpte >> 7) & 1) == 1) {
printk("in syscall: pdpte's ps flag is 1\n");//DEBUG
return (unsigned long*) pdpte_addr;
}
printk("in syscall: pdpte's ps flag is 0\n");//DEBUG
if ((pdpte & 1) == 0) {
printk("in syscall: pdpte's valid bit is not set\n");//DEBUG
return NULL;
}
printk("in syscall: pdpte's valid bit is set\n");//DEBUG
pd_addr = pdpte & 0x000ffffffffff000;
printk("in syscall: pd_addr=%lx\n", pd_addr);//DEBUG
vaddr21thru29 = (vaddr >> 18) & 0xff8;
printk("in syscall: vaddr21thru29=%lx\n", vaddr21thru29);//DEBUG
pde_addr = pd_addr | vaddr21thru29;
printk("in syscall: physical pde_addr=%lx\n", pde_addr);//DEBUG
pde_addr = (unsigned long) __va(pde_addr);
printk("in syscall: virtual pde_addr=%lx\n", pde_addr);//DEBUG
pde = *((unsigned long*) pde_addr);
printk("in syscall: pde=%lx\n", pde);//DEBUG
if (((pde >> 7) & 1) == 1) {
printk("in syscall: pde's ps flag is 1\n");//DEBUG
return (unsigned long*) pde_addr;
}
printk("in syscall: pde's ps flag is 0\n");//DEBUG
if ((pde & 1) == 0) {
printk("in syscall: pde's valid bit is not set\n");//DEBUG
return NULL;
}
printk("in syscall: pde's valid bit is set\n");//DEBUG
pt_addr = pde & 0x000ffffffffff000;
printk("in syscall: pt_addr=%lx\n", pt_addr);//DEBUG
vaddr12thru20 = (vaddr >> 9) & 0xff8;
printk("in syscall: vaddr12thru20=%lx\n", vaddr12thru20);//DEBUG
pte_addr = pt_addr | vaddr12thru20;
printk("in syscall: physical pte_addr=%lx\n", pte_addr);//DEBUG
pte_addr = (unsigned long) __va(pte_addr);
return (unsigned long*) pte_addr;