📄 monitor-host.c
字号:
if ( guest_cpu->sreg[s].des.dpl != 3 ) { retval = Plex86NoExecute_DPL; /* Fail. */ goto handleFail; } } } /* EFlags constraints: * VIP/VIF==0 * VM==0 * RF==0 * NT==0 * IOPL==0 (We may be able to allow this to be 0..2) * IF==1 * TF==0 * bit1==1 */ if ( (guest_cpu->eflags & (0x001b7302)) != (0x00000202) ) { retval = Plex86NoExecute_EFlags; /* Fail. */ goto handleFail; } /* Notes on other stuff: * - CPUID emulation vs virtualization match. */ /* NOTE: We should commit to executing the guest at this point. * We must not leave stray entries in the GDT. *//* Install virtualized guest descriptors in GDT. * Either use descriptor caches from guest space, or we have * to chase down the GDT entries using the guest's paging * system. Might be a cheaper/safe bet to just use the * descriptor caches. If the guest reloads a descriptor, * just let the user space deal with it. */ for (s=0; s<6; s++) { if ( (guest_cpu->sreg[s].sel.raw & 0xfffc) != 0) { vm->host.addr.gdt[ guest_cpu->sreg[s].sel.fields.index ] = guest_cpu->sreg[s].des; } }#warning "Have to clear out GDT" guest_stack_context->gs = guest_cpu->sreg[SRegGS].sel.raw; guest_stack_context->fs = guest_cpu->sreg[SRegFS].sel.raw; guest_stack_context->ds = guest_cpu->sreg[SRegDS].sel.raw; guest_stack_context->es = guest_cpu->sreg[SRegES].sel.raw; /* Could use memcpy(); both are in order. Pack both structs. */ guest_stack_context->edi = guest_cpu->edi; guest_stack_context->esi = guest_cpu->esi; guest_stack_context->ebp = guest_cpu->ebp; guest_stack_context->dummy_esp = 0; /* Not needed. */ guest_stack_context->ebx = guest_cpu->ebx; guest_stack_context->edx = guest_cpu->edx; guest_stack_context->ecx = guest_cpu->ecx; guest_stack_context->eax = guest_cpu->eax; /* Fields vector/error are ignored for return to guest. */ /* CS:EIP */ guest_stack_context->eip = guest_cpu->eip; guest_stack_context->cs = guest_cpu->sreg[SRegCS].sel.raw; guest_stack_context->eflags.raw = guest_cpu->eflags; vm->veflags.raw = 0; /* Virtualized EFLAGS - implement later. */ guest_stack_context->esp = guest_cpu->esp; guest_stack_context->ss = guest_cpu->sreg[SRegSS].sel.raw; /* Pointer to the fields in the nexus.S assembly code. */ nexus = vm->host.addr.nexus;#warning "Monitor CRx hacks" nexus->mon_cr0 = 0x8001003b | /* PG/WP/NE/ET/TS/MP/PE */ (guest_cpu->cr0.raw & 0x00040000); /* Pass-thru AM from guest. */ /* Could move mon_cr3 load to mapMonitor. */ nexus->mon_cr3 = vm->pages.page_dir << 12; nexus->mon_cr4 = 0x00000004; /* TSD=1 *//* vm->guest_cpu.cr0.raw = guest_cpu->cr0 | 0x32; */ /* +++ hack for now */// Notes:// - Implement some of monPagingRemap from old code, since that// was intended to be run/triggered by an initial mode change.// - After execution of 1st timeslice, need to copy dynamic state// from VM to guest_cpu area.// - Deal with cycle counts etc. hostInitShadowPaging(vm); for (;;) { unsigned long eflags;#if 0 /* If print buffer has contents, return to user space to print. */ if (vm->log_buffer_info.offset) { vm->mon_msgs.header.msg_type = VMMessagePrintBuf; vm->mon_msgs.header.msg_len = 0; vm->mon_request = MonReqNone; /* Request satisfied */ resetPrintBuf(vm); /* xxx Fix print mess */ retval = 100; goto handleFail; }#endif vm_save_flags(eflags); vm_restore_flags(eflags & ~0x00004300); /* clear NT/IF/TF */#if ANAL_CHECKS if (!(eflags & 0x200)) { vm_restore_flags(eflags); hostOSPrint("ioctlExecute: EFLAGS.IF==0\n"); retval = 101; /* Fail. */ goto handlePanic; }#endif /* Call assembly routine to effect transition. */ vm->host.__host2mon(); /* First check for an asynchronous event (interrupt redirection) */ if ( vm->mon_request == MonReqRedirect ) { vm_restore_flags(eflags & ~0x00000200); /* restore all but IF */ soft_int(vm->redirect_vector); /* sets IF to 1 */ hostOSInstrumentIntRedirCount(vm->redirect_vector); vm->mon_request = MonReqNone; /* Request satisfied */ } /* Event was synchronous; monitor requested a switch back to host. */ else { vm_restore_flags(eflags); /* Perform action requested by monitor. */ switch ( vm->mon_request ) { case MonReqRemapMonitor:#if 0 if ( mapMonitor(vm) ) { vm->mon_request = MonReqNone; /* Request satisfied */ break; } else { hostOSPrint("mapMonitor failed.\n"); hostOSPrint("Panic w/ abort_code=%u\n", vm->abort_code); retval = 102; goto handlePanic; }#endif hostOSPrint("ioctlExecute: case MonReqRemapMonitor.\n"); retval = 103; goto handlePanic; case MonReqFlushPrintBuf: hostOSPrint("ioctlExecute: case MonReqFlushPrintBuf.\n"); retval = 104; goto handlePanic; case MonReqGuestFault: /* Encountered a guest fault. */ hostCopyGuestStateToUserSpace(vm); executeMsg->cyclesExecuted = 0; /* Handle later. */ executeMsg->instructionsExecuted = 0; /* Handle later. */ executeMsg->monitorState.state = vm->vmState; executeMsg->monitorState.request = vm->mon_request; executeMsg->monitorState.guestFaultNo = vm->guestFaultNo; vm->mon_request = MonReqNone; return 0; case MonReqPanic: if (vm->abort_code) hostOSPrint("Panic w/ abort_code=%u\n", vm->abort_code); hostOSPrint("ioctlExecute: case MonReqPanic.\n"); retval = 106; goto handlePanic; case MonReqPinUserPage: if ( !hostHandlePagePinRequest(vm, vm->pinReqPPI) ) { retval = 108; goto handlePanic; } continue; /* Back to VM monitor. */ default: hostOSPrint("ioctlExecute: default case (%u).\n", vm->mon_request); retval = 107; goto handlePanic; } } /* Let host decide whether we are allowed another timeslice */ if ( !hostOSIdle() ) { /* We are returning only because the host wants to * schedule other work. */ executeMsg->monitorState.state = vm->vmState; executeMsg->monitorState.request = MonReqNone; return 0; } } /* Should not get here. */ retval = 109; goto handlePanic;handleFail: /* Handle inabilitiy to execute the guest due to certain state. */ executeMsg->monitorState.state = vm->vmState; executeMsg->monitorState.request = vm->mon_request; return(retval);handlePanic: vm->vmState |= VMStatePanic; vm->mon_request = MonReqPanic; executeMsg->monitorState.state = vm->vmState; executeMsg->monitorState.request = vm->mon_request; return(retval);} voidhostCopyGuestStateToUserSpace(vm_t *vm){ guest_cpu_t *guest_cpu; guest_context_t *guest_stack_context; /* A pointer to the guest CPU state as passed from host-user space. * This structure is memory mapped between user and kernel/monitor space. */ guest_cpu = vm->host.addr.guest_cpu; /* A pointer to the guest CPU state saved on the monitor stack. */ guest_stack_context = vm->host.addr.guest_context; guest_cpu->sreg[SRegES].sel.raw = guest_stack_context->es; if ( (guest_stack_context->es & 0xfffc) == 0 ) { guest_cpu->sreg[SRegES].des = nullDescriptor; guest_cpu->sreg[SRegES].valid = 0; } else { guest_cpu->sreg[SRegES].des = vm->host.addr.gdt[ guest_cpu->sreg[SRegES].sel.fields.index ]; guest_cpu->sreg[SRegES].valid = 1; } guest_cpu->sreg[SRegCS].sel.raw = guest_stack_context->cs; if ( (guest_stack_context->cs & 0xfffc) == 0 ) { guest_cpu->sreg[SRegCS].des = nullDescriptor; guest_cpu->sreg[SRegCS].valid = 0; } else { guest_cpu->sreg[SRegCS].des = vm->host.addr.gdt[ guest_cpu->sreg[SRegCS].sel.fields.index ]; guest_cpu->sreg[SRegCS].valid = 1; } guest_cpu->sreg[SRegSS].sel.raw = guest_stack_context->ss; if ( (guest_stack_context->ss & 0xfffc) == 0 ) { guest_cpu->sreg[SRegSS].des = nullDescriptor; guest_cpu->sreg[SRegSS].valid = 0; } else { guest_cpu->sreg[SRegSS].des = vm->host.addr.gdt[ guest_cpu->sreg[SRegSS].sel.fields.index ]; guest_cpu->sreg[SRegSS].valid = 1; } guest_cpu->sreg[SRegDS].sel.raw = guest_stack_context->ds; if ( (guest_stack_context->ds & 0xfffc) == 0 ) { guest_cpu->sreg[SRegDS].des = nullDescriptor; guest_cpu->sreg[SRegDS].valid = 0; } else { guest_cpu->sreg[SRegDS].des = vm->host.addr.gdt[ guest_cpu->sreg[SRegDS].sel.fields.index ]; guest_cpu->sreg[SRegDS].valid = 1; } guest_cpu->sreg[SRegFS].sel.raw = guest_stack_context->fs; if ( (guest_stack_context->fs & 0xfffc) == 0 ) { guest_cpu->sreg[SRegFS].des = nullDescriptor; guest_cpu->sreg[SRegFS].valid = 0; } else { guest_cpu->sreg[SRegFS].des = vm->host.addr.gdt[ guest_cpu->sreg[SRegFS].sel.fields.index ]; guest_cpu->sreg[SRegFS].valid = 1; } guest_cpu->sreg[SRegGS].sel.raw = guest_stack_context->gs; if ( (guest_stack_context->gs & 0xfffc) == 0 ) { guest_cpu->sreg[SRegGS].des = nullDescriptor; guest_cpu->sreg[SRegGS].valid = 0; } else { guest_cpu->sreg[SRegGS].des = vm->host.addr.gdt[ guest_cpu->sreg[SRegGS].sel.fields.index ]; guest_cpu->sreg[SRegGS].valid = 1; } /* Could use memcpy(); both are in order. Pack both structs. */ guest_cpu->edi = guest_stack_context->edi; guest_cpu->esi = guest_stack_context->esi; guest_cpu->ebp = guest_stack_context->ebp; guest_cpu->esp = guest_stack_context->esp; guest_cpu->ebx = guest_stack_context->ebx; guest_cpu->edx = guest_stack_context->edx; guest_cpu->ecx = guest_stack_context->ecx; guest_cpu->eax = guest_stack_context->eax; /* CS:EIP */ guest_cpu->eip = guest_stack_context->eip; guest_cpu->eflags = guest_stack_context->eflags.raw; /* vm->veflags.raw = 0; */ /* Virtualized EFLAGS - implement later. */} inthostIoctlRegisterMem(vm_t *vm, plex86IoctlRegisterMem_t *registerMemMsg){ unsigned error; /* Do not allow duplicate allocation. The file descriptor must be * opened. The guest CPUID info can be filled in later. */ if ( (vm->vmState & ~VMStateGuestCPUID) != VMStateFDOpened ) return -Plex86ErrnoEBUSY; if (vm->pages.guest_n_megs != 0) return -Plex86ErrnoEBUSY; /* Check that the amount of memory is reasonable. */ if ( (registerMemMsg->nMegs > PLEX86_MAX_PHY_MEGS) || (registerMemMsg->nMegs < 4) || (registerMemMsg->nMegs & 0x3) ) return -Plex86ErrnoEINVAL; /* Check that the guest memory vector is page aligned. */ if ( registerMemMsg->guestPhyMemVector & 0xfff ) return -Plex86ErrnoEINVAL; /* Check that the log buffer area is page aligned. */ if ( registerMemMsg->logBufferWindow & 0xfff ) return -Plex86ErrnoEINVAL; /* Check that the guest CPU area is page aligned. */ if ( registerMemMsg->guestCPUWindow & 0xfff ) return -Plex86ErrnoEINVAL; /* Check that none of the user areas overlap. In case we have a * number of regions, use some generic code to handle N regions. */ {#define NumUserRegions 3 struct { Bit32u min, max; } userRegion[NumUserRegions]; unsigned i,j; userRegion[0].min = registerMemMsg->guestPhyMemVector; userRegion[0].max = userRegion[0].min + (registerMemMsg->nMegs<<20) - 1; userRegion[1].min = registerMemMsg->logBufferWindow; userRegion[1].max = userRegion[1].min + LOG_BUFF_SIZE - 1; userRegion[2].min = registerMemMsg->guestCPUWindow; userRegion[2].max = userRegion[2].min + (4096) - 1; for (i=1; i<NumUserRegions; i++) { for (j=1; j<NumUserRegions; j++) { if (j == i) continue; /* Don't compare at the same region. */ /* Check for min(j) contained in region(i). */ if ( (userRegion[j].min >= userRegion[i].min) && (userRegion[j].min <= userRegion[i].max) ) return -Plex86ErrnoEINVAL; /* Check for max(j) contained in region(i). */ if ( (userRegion[j].max >= userRegion[i].min) && (userRegion[j].max <= userRegion[i].max) ) return -Plex86ErrnoEINVAL; } } } /* Allocate memory */ if ( (error = hostAllocVmPages(vm, registerMemMsg)) != 0 ) { hostOSPrint("plex86: allocVmPages failed at %u\n", error); return -Plex86ErrnoENOMEM; } /* Initialize the guests physical memory. */ if ( hostInitGuestPhyMem(vm) ) { hostUnallocVmPages(vm); return -Plex86ErrnoEFAULT; } /* Initialize the monitor. */ if ( !hostInitMonitor(vm) || !hostMapMonitor(vm) ) { hostUnallocVmPages(vm); return -Plex86ErrnoEFAULT; } return 0;}/* * Allocate various pages/memory needed by monitor. */ inthostAllocVmPages(vm_t *vm, plex86IoctlRegisterMem_t *registerMemMsg){ vm_pages_t *pg = &vm->pages; vm_addr_t *ad = &vm->host.addr;#warning "Fix these shortcuts" unsigned where = 1; /* clear out allocated pages lists */ mon_memzero(pg, sizeof(*pg)); mon_memzero(ad, sizeof(*ad)); /* Guest physical memory pages */ pg->guest_n_megs = registerMemMsg->nMegs; pg->guest_n_pages = registerMemMsg->nMegs * 256; pg->guest_n_bytes = registerMemMsg->nMegs * 1024 * 1024; if ( pg->guest_n_pages > MAX_MON_GUEST_PAGES) { /* The size of the user-space allocated guest physical memory must * fit within the maximum number of guest pages that the VM monitor * supports. */ goto error; } where++; vm->guestPhyMemAddr = registerMemMsg->guestPhyMemVector; vm->vmState |= VMStateRegisteredPhyMem; /* Bogus for now. */ where++; { Bit32u hostPPI, kernelAddr; /* Guest CPU state (malloc()'d in user space). */ if ( !hostOSGetAndPinUserPage(vm, registerMemMsg->guestCPUWindow, &pg->guest_cpu_hostOSPtr, &hostPPI, &kernelAddr) ) { goto error; } ad->guest_cpu = (guest_cpu_t *) kernelAddr; pg->guest_cpu = hostPPI;vm->vmState |= VMStateRegisteredGuestCPU; /* For now. */ where++; /* Log buffer area (malloc()'d in user space). */ /* LOG_BUFF_PAGES */ if ( !hostOSGetAndPinUserPage(vm, registerMemMsg->logBufferWindow, &pg->log_buffer_hostOSPtr[0], &hostPPI, &kernelAddr) ) { goto error; } ad->log_buffer = (Bit8u *) kernelAddr; pg->log_buffer[0] = hostPPI; where++;vm->vmState |= VMStateRegisteredPrintBuffer; /* For now. */ } /* Monitor page directory */ if ( !(ad->page_dir = (pageEntry_t *) hostOSAllocZeroedPage()) ) { goto error; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -