linux缺页异常处理--内核空间(二)

2014-11-24 10:57:02 · 作者: · 浏览: 1
if (!pte_present(*pte_k))//判断pte项是否存在,不存在则失败
return -1;

return 0;
}
同步处理:

[cpp]
static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
{
unsigned index = pgd_index(address);
pgd_t *pgd_k;
pud_t *pud, *pud_k;
pmd_t *pmd, *pmd_k;

pgd += index; //记录当前页表pgd对应address的偏移
pgd_k = init_mm.pgd + index;//记录内核页表对应address的偏移

if (!pgd_present(*pgd_k))//内核PGD页表对应的项不存在,则无法进行下一步,返回NULL
return NULL;

/*
* set_pgd(pgd, *pgd_k); here would be useless on PAE
* and redundant with the set_pmd() on non-PAE. As would
* set_pud.
*/

/*获取当前页表对应address的PUD地址和内核页表对应address的地址,并判断pud_k对应的项是否存在*/
pud = pud_offset(pgd, address);
pud_k = pud_offset(pgd_k, address);
if (!pud_present(*pud_k))
return NULL;

/*对pmd进行和上面类似的操作*/
pmd = pmd_offset(pud, address);
pmd_k = pmd_offset(pud_k, address);
if (!pmd_present(*pmd_k))
return NULL;

if (!pmd_present(*pmd))//当前使用页表对应的pmd项不存在,则修正pmd项使其和内核页表的pmd_k项相同
set_pmd(pmd, *pmd_k);
else
BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k));

return pmd_k;
}


如果do_page_fault()函数执行到了bad_area_nosemaphore(),那么就表明这次异常是由于对非法的地址访问造成的。在内核中产生这样的结果的情况一般有两种:

1.内核通过用户空间传递的系统调用参数,访问了无效的地址

2.内核的程序设计缺陷

第一种情况内核尚且能通过异常修正机制来进行修复,而第二种情况就会导致OOPS错误了,内核将强制用SIGKILL结束当前进程。

内核态的bad_area_nosemaphore()的实际处理函数为bad_area_nosemaphore()-->__bad_area_nosemaphore()-->no_context()

[cpp]
static noinline void
no_context(struct pt_regs *regs, unsigned long error_code,
unsigned long address)
{
struct task_struct *tsk = current;
unsigned long *stackend;
unsigned long flags;
int sig;

/* Are we prepared to handle this kernel fault */
/*fixup_exception()用于搜索异常表,并试图找到一个对应该异常的例程来进行修正,
这个例程在fixup_exception()返回后执行*/
if (fixup_exception(regs))
return;

/*
* 32-bit:
*
* Valid to do another page fault here, because if this fault
* had been triggered by is_prefetch fixup_exception would have
* handled it.
*
* 64-bit:
*
* Hall of shame of CPU/BIOS bugs.
*/
if (is_prefetch(regs, error_code, address))
return;

if (is_errata93(regs, address))
return;

/*
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice:
*/
/* 走到这里就说明异常确实是由于内核的程序设计缺陷导致的了,内核将
产生一个oops,下面的工作就是打印CPU寄存器和内核态堆栈的信息到控制台并
终结当前的进程*/
flags = oops_begin();

show_fault_oops(regs, error_code, address);

stackend = end_of_stack(tsk);
if (*stackend != STACK_END_MAGIC)
printk(KERN_ALERT "Thread overran stack, or stack corrupted\n");

tsk->thread.cr2 = address;
tsk->thread.trap_no = 14;
tsk->thread.error_code = error_code;

sig = SIGKILL;
if (__die("Oops", regs, error_code))
sig = 0;

/* Executive summary in case the body of the oops scrolled away */
printk(KERN_EMERG "CR2: %016lx\n", address);

oops_end(flags, regs, sig);
}


作者:vanbreaker