📄 paging-mon.c
字号:
/* See if present, before fetching PTE */ if (guestPDE.fields.P==0) { *error = 0x00000000; /* RSVD=0, P=0 */ goto np_exception; }#if 0 if (vm->guestCpuIDInfo.procSignature.fields.family < 6) { /* Update A bit of PDE memory image if not already */ if ( guestPDE.fields.A == 0 ) { guestPDE.fields.A = 1; guestPDir[pdi] = guestPDE; } }#endif /* Second, get the guest PDE */ ptbl_ppi = A20PageIndex(vm, guestPDE.fields.base); if (ptbl_ppi >= vm->pages.guest_n_pages) monpanic(vm, "mapGuestLinAddr: PG=1 guest PTE OOB\n"); guestPTbl = open_guest_phy_page(vm, ptbl_ppi, vm->guest.addr.tmp_phy_page1); guestPTE = guestPTbl[pti]; if (guestPTE.fields.P==0) { *error = 0x00000000; /* RSVD=0, P=0 */ goto np_exception; }#if 0/* +++ */ if (guestPDE.raw & PDEUnhandled) monpanic(vm, "mapGuestLinAddr: guestPDE 0x%08x\n", guestPDE.raw);#endif /* See if requested guest priv is weaker than guest PDE priv */ if (req_us > guestPDE.fields.US) { *error = 0x00000001; /* RSVD=0, P=1 */ goto access_exception; } if ( (req_rw > guestPDE.fields.RW) && (vm->guest.addr.guest_cpu->cr0.fields.wp || req_us) ) { *error = 0x00000001; /* RSVD=0, P=1 */ goto access_exception; }#warning "ignoring PTEUnhandled bits"#if 0 if (guestPTE.raw & PTEUnhandled) monpanic(vm, "mapGuestLinAddr: guestPTE 0x%08x\n", guestPTE.raw);#endif if (req_us > guestPTE.fields.US) { *error = 0x00000001; /* RSVD=0, P=1 */ goto access_exception; } if ( (req_rw > guestPTE.fields.RW) && (vm->guest.addr.guest_cpu->cr0.fields.wp || req_us) ) { *error = 0x00000001; /* RSVD=0, P=1 */ goto access_exception; }#if 0 if (vm->guestCpuIDInfo.procSignature.fields.family >= 6) { /* Update A bit of PDE memory image if not already */ if ( guestPDE.fields.A == 0 ) { guestPDE.fields.A = 1; guestPDir[pdi] = guestPDE; } } /* Update A bit in PTE memory image if not already */ if ( (guestPTE.fields.A == 0) || ((req_rw==1) && !guestPTE.fields.D) ) { guestPTE.fields.A = 1; if (req_rw==1) guestPTE.fields.D = 1; guestPTbl[pti] = guestPTE; }#endif *guest_ppi = A20PageIndex(vm, guestPTE.fields.base); } else { /* guest paging is off, linear address is physical address */ guest_pdir_page_index = 0; /* keep compiler quiet */ *guest_ppi = A20PageIndex(vm, guest_lpage_index); } if (*guest_ppi >= vm->pages.guest_n_pages) return(MapLinPPageOOB);/* +++ mapping in guest pages, check static phy_attr bits first before *//* +++ allowing non-protected. */mapIntoMonitor: /* At this point, we know that the guest's paging system * (if enabled) would allow for this access. Now we have to * see about mapping it into the monitor linear address space. */ pusage = getPageUsage(vm, *guest_ppi); if (wasRemap > 1) monpanic(vm, "wasRemap>1\n"); /* * Check monitor PDE */ if (monPDE->fields.P == 0) { /* OK, Lazy PT map/allocate */ if (vm->guest.addr.guest_cpu->cr0.fields.pg) { phyPageInfo_t *pde_pusage; pde_pusage = getPageUsage(vm, A20PageIndex(vm, guestPDE.fields.base)); if (pde_pusage->attr.raw & PageBadUsage4PTbl) {#warning "PDE->PDir hack"/*monprint(vm, "PDE.base=0x%x CR3=0x%x\n", * A20PageIndex(vm, guestPDE.fields.base), * A20Addr(vm, vm->guest_cpu.cr3)); */return(MapLinEmulate); } if (pde_pusage->attr.raw & PageUsagePTbl) { /* It is possible that multiple PDE entries will point to */ /* the same Page Table. In this case, we need to search to */ /* find which one the monitor already mapped in, and get */ /* a pointer to the Page Table allocated by the monitor. */ Bit32u guest_ptbl_index; unsigned i; guestPDir = open_guest_phy_page(vm, guest_pdir_page_index, vm->guest.addr.tmp_phy_page0); guest_ptbl_index = A20PageIndex(vm, guestPDir[pdi].fields.base); monPTbl = (void *) 0; pt_index = 0; /* keep compiler quiet */ for (i=0; i<1024; i++) { if (i==pdi) continue; /* skip current PDI */ guestPDE = guestPDir[i]; if ( guestPDE.fields.P && (A20PageIndex(vm, guestPDE.fields.base)==guest_ptbl_index) ) { /* OK, guest has a PDE which matches. If it is mapped into */ /* the monitor already, then we are done searching. */ if (vm->guest.addr.page_dir[i].fields.P) { pt_index = getMonPTi(vm, i, 11); vm->guest.addr.page_tbl_laddr_map[pdi] = pt_index; monPTbl = &vm->guest.addr.page_tbl[pt_index]; break; } } } close_guest_phy_page(vm, guest_pdir_page_index); if (i>=1024) monpanic(vm, "mapGuestLinAddr: PDE maps to existing PTbl.\n"); } else { /* Allocate PT using paged scheme. */ pt_index = allocatePT(vm, pdi); monPTbl = &vm->guest.addr.page_tbl[pt_index]; mon_memzero(monPTbl, sizeof(*monPTbl)); } if (vm->guest.addr.guest_cpu->sreg[SRegCS].des.dpl==3) { /* For user code, we can use the guest US & RW values as-is, */ /* since they are honored as such with either CR0.WP value. */ us = guestPDE.fields.US; rw = guestPDE.fields.RW; } else { /* guest supervisor code */ /* For supervisor code, access rules are different dependent on */ /* the value of CR0.WP. */ if (vm->guest.addr.guest_cpu->cr0.fields.wp==0) { /* If CR0.WP=0, then supervisor code can write to any page, */ /* and permissions are effectively ignored. */ us = 1; rw = 1; } else { /* CR0.WP==1 */ /* If CR0.WP=0, then supervisor code can read from any page, */ /* but write permission depends on the RW bit. */ us = 1; rw = guestPDE.fields.RW; } } /* Base/Avail=0/G=0/PS=0/D=d/A=a/PCD=0/PWT=0/US=us/RW=rw/P=1 */ monPDE->raw = (vm->pages.page_tbl[pt_index] << 12) | (guestPDE.raw & 0x60) | (us<<2) | (rw<<1) | 1; if ( addPageAttributes(vm, A20PageIndex(vm, guestPDE.fields.base), PageUsagePTbl) ) { wasRemap++; goto mapIntoMonitor; } } else { /* Allocate PT using non-paged scheme. */ pt_index = allocatePT(vm, pdi); monPTbl = &vm->guest.addr.page_tbl[pt_index]; mon_memzero(monPTbl, 4096); /* Base/Avail=0/G=0/PS=0/D=0/A=0/PCD=0/PWT=0/US=1/RW=1/P=1 */ monPDE->raw = (vm->pages.page_tbl[pt_index] << 12) | 0x7; } } else { /* monPDE->P == 1 */ /* Make sure this laddr does not conflict with monitor space */ /* This can only happen when monPDE.P==1, since the monitor */ /* is always mapped in. */ if ( (guest_laddr & 0xffc00000) == vm->mon_pde_mask ) return(MapLinMonConflict); pt_index = getMonPTi(vm, pdi, 12); monPTbl = &vm->guest.addr.page_tbl[pt_index]; } monPTE = &monPTbl->pte[pti]; /* * Check monitor PTE */ if (monPTE->fields.P == 0) { if (vm->guest.addr.guest_cpu->cr0.fields.pg) { if (vm->guest.addr.guest_cpu->sreg[SRegCS].des.dpl==3) { /* For user code, we can use the guest US & RW values as-is, */ /* since they are honored as such with either CR0.WP value. */ us = guestPTE.fields.US; rw = guestPTE.fields.RW; } else { /* guest supervisor code */ /* For supervisor code, access rules are different dependent on */ /* the value of CR0.WP. */ if (vm->guest.addr.guest_cpu->cr0.fields.wp==0) { /* If CR0.WP=0, then supervisor code can write to any page, */ /* and permissions are effectively ignored. */ us = 1; rw = 1; } else { /* CR0.WP==1 */ /* If CR0.WP=0, then supervisor code can read from any page, */ /* but write permission depends on the RW bit. */ us = 1; rw = guestPTE.fields.RW; } } if (pusage->attr.fields.access_perm==PagePermRO) { rw = 0; if (req_rw) return(MapLinEmulate); } else if (pusage->attr.fields.access_perm==PagePermNA) return(MapLinEmulate); /* Base/Avail=0/G=0/PS=0/D=d/A=a/PCD=0/PWT=0/US=1/RW=rw/P=1 */ monPTE->raw = (getHostOSPinnedPage(vm, *guest_ppi) << 12) | (guestPTE.raw & 0x60) | 0x5 | (rw<<1); } else { /* CR0.PG==0 */ rw = 1; /* Paging off is effectively RW */ if (pusage->attr.fields.access_perm==PagePermRO) { rw = 0; if (req_rw) return(MapLinEmulate); } else if (pusage->attr.fields.access_perm==PagePermNA) return(MapLinEmulate); /* Base/Avail=0/G=0/PS=0/D=0/A=0/PCD=0/PWT=0/US=1/RW=rw/P=1 */ monPTE->raw = (getHostOSPinnedPage(vm, *guest_ppi) << 12) | 0x5 | (rw<<1); } /* Mark physical page as having an unvirtualized linear address * mapped to it. */ if (pusage->attr.fields.lmap_count == 0) { pusage->attr.fields.lmap_count = 1; pusage->attr.fields.laddr_backlink = guest_lpage_index; } else if (pusage->attr.fields.lmap_count == 1) { pusage->attr.fields.lmap_count = 2; /* max out count */ /* Count maxed out, we only store laddr_backlink of 1st mapping. */ } else { /* Count maxed out, we don't store any more info. */ } invlpg_mon_offset( Guest2Monitor(vm, guest_laddr) ); return(MapLinOK); } else { /* PTE.P == 1 */ return(MapLinAlreadyMapped); }np_exception:access_exception: *error |= (req_us<<2) | (req_rw<<1); return(MapLinException);} voidguestPageFault(vm_t *vm, guest_context_t *context, Bit32u cr2){ Bit32u guest_ppi, error, gerror; unsigned us, rw; /* Make sure this laddr does not conflict with monitor space */ if ( (cr2 & 0xffc00000) == vm->mon_pde_mask ) monpanic(vm, "PageFault: guest access to monitor space\n"); error = context->error; if (error & 0x8) /* If RSVD bits used in PDir */ monpanic(vm, "guestPageFault: RSVD\n"); us = vm->guest.addr.guest_cpu->sreg[SRegCS].des.dpl == 3; rw = (error >> 1) & 1;/* +++ should base attr (currently 0) on whether this is *//* code or data??? only if siv==1 */ switch (mapGuestLinAddr(vm, cr2, &guest_ppi, us, rw, 0, &gerror)) { case MapLinOK: return; case MapLinMonConflict: monpanic(vm, "guestPageFault: MapLinMonConflict:\n"); case MapLinAlreadyMapped: monpanic(vm, "guestPageFault: MapLinAlreadyMapped:\n"); /*emulate_instr(vm, context, 2);*/ return; case MapLinPPageOOB: monpanic(vm, "guestPageFault: MapLinPPageOOB (0x%x):\n", cr2); case MapLinEmulate: monpanic(vm, "guestPageFault: MapLinEmulate:\n"); /*emulate_instr(vm, context, 3);*/ return; case MapLinException: /*monpanic(vm, "guestPageFault: emulate_exception was here.\n");*/ /*emulate_exception(vm, ExceptionPF, gerror);*/ toHostGuestFault(vm, ExceptionPF); return; default: monpanic(vm, "guestPageFault: MapLin: default case:\n"); }}#if 0 voidsanity_check_pdir(vm_t *vm, unsigned id, Bit32u guest_laddr){ pageEntry_t *monPDE; Bit32u pdi; unsigned pt_index; for (pdi=0; pdi<1024; pdi++) { monPDE = &vm->guest.addr.page_dir[pdi]; if ( (pdi!=vm->mon_pdi) && monPDE->fields.P ) { pt_index = vm->guest.addr.page_tbl_laddr_map[pdi]; if (pt_index == -1) monpanic(vm, "sanity_check_pdir: pt_index==-1\n"); if (pt_index >= vm->pages.guest_n_pages) monpanic(vm, "sanity_check_pdir: pt_index OOB\n"); if ( monPDE->fields.base != vm->pages.page_tbl[pt_index] ) { monprint(vm, "gaddr=0x%x\n", guest_laddr); monprint(vm, "pt_index=%u\n", pt_index); monprint(vm, "map[0x302]=%u\n", vm->guest.addr.page_tbl_laddr_map[0x302]); monpanic(vm, "sanity_check_pdir: id=%u " "pdi=0x%x\n", id, pdi); } } }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -