Chinaunix首页 | 论坛 | 博客
  • 博客访问: 38924
  • 博文数量: 23
  • 博客积分: 1065
  • 博客等级: 少尉
  • 技术积分: 185
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-14 15:32
文章分类

全部博文(23)

文章存档

2010年(20)

2008年(3)

我的朋友
最近访客

分类: LINUX

2010-03-02 00:02:37

当一个进程在内核空间发生缺页故障的时候,在其处理程序中,就要通过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) |
0

上一篇:内核页目录的修改

下一篇:mmap()的问题

给主人留下些什么吧!~~