- 论坛徽章:
- 0
|
原帖由 kikanjuu 于 2008-2-26 14:14 发表
是不是客户操作系统修改客户页表会引发两次Page Fault?
第一次:
因为还没有建立起客户页表对应的影子页表,即客户页表的guest physical frame还没有对应的machine frame for guest page table,所以引起Pa ...
以32位下4KB页面及HVM为例:
初始情况下HVM运行在virtual 8086模式用于模拟实地址模式,
这时SPT指针位于P2M表,
此时客户操作系统引导代码会准备页表,
此时客户操作系统对页表的操作无法进行监控。
当客户操作系统页表准备完毕准备切换的保护模式时,
客户操作系统会使用mov to cr3指令,此指令由VT捕获,
被传递到影子页表的sh_update_cr3()函数,
这个函数负责所有HVM中客户操作系统更改CR3时的处理。
这个函数会首先会查询客户页表对应的机器地址 gmfn = pagetable_get_mfn(v->arch.guest_table);
|
之后会扫描domain所有的shadow page table,将gmfn对应的shadow页面设置为只读,如果没有对应的shadow,则创建一个
代码来自sh_update_cr3()
#if GUEST_PAGING_LEVELS == 2
if ( sh_remove_write_access(v, gmfn, 2, 0) != 0 )
flush_tlb_mask(v->domain->domain_dirty_cpumask);
sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l2_shadow);
#elif GUEST_PAGING_LEVELS == 3 |
由此保证了当前domain所有顶级页表对应的页面,在SPT中只读。
之后每次捕获#PF进行的客户页表遍历时,Xen总是同时将遍历客户页表对应的机器页面设置为只读,
代码来自guest_walk_tables():
if ( guest_op && sh_remove_write_access(v, gw->l2mfn, 2, va) != 0 )
flush_tlb_mask(v->domain->domain_dirty_cpumask);
|
通过这种渐进的方式确保了所有客户页表所在页面在SPT中的映射项都是只读的,
之后如果客户操作系统试图修改客户页表会引发#PF,
此时由Xen捕获并模拟其执行,在模拟的同时同步SPT与GPT:
代码来自sh_page_fault()
/* Need to emulate accesses to page tables */
/* 需要模拟对客户页表的写操作 */
if ( sh_mfn_is_a_page_table(gmfn) )
{
if ( ft == ft_demand_write )
{
perfc_incr(shadow_fault_emulate_write);
goto emulate;
}
else if ( shadow_mode_trap_reads(d) && ft == ft_demand_read )
{ /* Xen 暂时不支持读页表的模拟 */
perfc_incr(shadow_fault_emulate_read);
goto emulate;
}
} |
由此可见,客户操作系统修改客户页表仅会产生一次#PF,
Xen捕获#PF并模拟其执行,同时进行同步. |
|