当一个进程在内核空间发生缺页故障的时候,在其处理程序中,就要通过0号进程的页目录来同步本进程的内核页目录,实际上就是拷贝0号进程的内核页目录到本
进程中(内核页表与进程0共享,故不需要复制)。如下:
asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
。。。。。。。。
>>> 缺页故障产生的地址
/* get the address */
__asm__("movl %%cr2,%0":"=r" (address));
tsk = current;
/*
* We fault-in kernel-space virtual memory on-demand. The
* 'reference' page table is init_mm.pgd.
*/
>>> 如果缺页故障在内核空间
if (address >= TASK_SIZE)
goto vmalloc_fault;
。。。。。。。。。
vmalloc_fault:
{
/*
* Synchronize this task's top level page-table
* with the 'reference' page table.
*/
int offset = __pgd_offset(address);
pgd_t *pgd, *pgd_k;
pmd_t *pmd, *pmd_k;
pgd = tsk->active_mm->pgd + offset;
pgd_k = init_mm.pgd + offset;
>>> /*
>>> * (pmds are folded into pgds so this doesnt get actually called,
>>> * but the define is needed for a generic inline function.)
>>> */
>>> #define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
>>> #define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval)
>>> 如果本进程的该地址的内核页目录不存在
if (!pgd_present(*pgd)) {
>>> 如果进程0的该地址处的内核页目录也不存在,则出错
if (!pgd_present(*pgd_k))
goto bad_area_nosemaphore;
>>> 复制进程0的该地址的内核页目录到本进程的相应页目录中
set_pgd(pgd, *pgd_k);
return;
}
>>> extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
>>> {
>>> return (pmd_t *) dir;
>>> }
pmd = pmd_offset(pgd, address);
pmd_k = pmd_offset(pgd_k, address);
>>> 对中间页目录,如果是两级页表,下面的几步操作与上面的重复
if (pmd_present(*pmd) || !pmd_present(*pmd_k))
goto bad_area_nosemaphore;
set_pmd(pmd, *pmd_k);
return;
}
/*
* Switch to real mode and then execute the code
* specified by the code and length parameters.
* We assume that length will aways be less that 100!
*/
void machine_real_restart(unsigned char *code, int length)
{
。。。。。。。。。。。。。
/* Remap the kernel at virtual address zero, as well as offset zero
from the kernel segment. This assumes the kernel segment starts at
virtual address PAGE_OFFSET. */
memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
/* Make sure the first page is mapped to the start of physical memory.
It is normally not mapped, to trap kernel NULL pointer dereferences. */
pg0[0] = _PAGE_RW | _PAGE_PRESENT;
/*
* Use `swapper_pg_dir' as our page directory.
*/
asm volatile("movl %0,%%cr3": :"r" (__pa(swapper_pg_dir)));
。。。。。。。。。。。。。
}
阅读(627) | 评论(0) | 转发(0) |