📄 monitor-host.c
字号:
r |= hostInitIDTSlot(vm, 0, IDT_EXCEPTION_NOERROR); /* Divide error */ r |= hostInitIDTSlot(vm, 1, IDT_EXCEPTION_NOERROR); /* Debug exceptions */ r |= hostInitIDTSlot(vm, 2, IDT_INTERRUPT); /* NMI */ r |= hostInitIDTSlot(vm, 3, IDT_EXCEPTION_NOERROR); /* Breakpoint */ r |= hostInitIDTSlot(vm, 4, IDT_EXCEPTION_NOERROR); /* Overflow */ r |= hostInitIDTSlot(vm, 5, IDT_EXCEPTION_NOERROR); /* Bounds check */ r |= hostInitIDTSlot(vm, 6, IDT_EXCEPTION_NOERROR); /* Invalid opcode */ r |= hostInitIDTSlot(vm, 7, IDT_EXCEPTION_NOERROR); /* FPU not available */ r |= hostInitIDTSlot(vm, 8, IDT_EXCEPTION_ERROR); /* Double fault */ r |= hostInitIDTSlot(vm, 9, IDT_EXCEPTION_NOERROR); /* FPU segment overrun */ r |= hostInitIDTSlot(vm, 10, IDT_EXCEPTION_ERROR); /* Invalid TSS */ r |= hostInitIDTSlot(vm, 11, IDT_EXCEPTION_ERROR); /* Segment not present */ r |= hostInitIDTSlot(vm, 12, IDT_EXCEPTION_ERROR); /* Stack exception */ r |= hostInitIDTSlot(vm, 13, IDT_EXCEPTION_ERROR); /* GP fault */ r |= hostInitIDTSlot(vm, 14, IDT_EXCEPTION_ERROR); /* Page fault */ r |= hostInitIDTSlot(vm, 15, IDT_EXCEPTION_NOERROR); /* reserved */ r |= hostInitIDTSlot(vm, 16, IDT_EXCEPTION_NOERROR); /* Coprocessor error */ r |= hostInitIDTSlot(vm, 17, IDT_EXCEPTION_ERROR); /* Alignment check */ r |= hostInitIDTSlot(vm, 18, IDT_EXCEPTION_NOERROR); /* Machine check */ /* Reserved exceptions */ for (i = 19; i < 32; i++) r |= hostInitIDTSlot(vm, i, IDT_EXCEPTION_NOERROR); /* Hardware interrupts */ for (i = 32; i < 256; i++) r |= hostInitIDTSlot(vm, i, IDT_INTERRUPT); if (r!=0) goto error; /* * Setup the initial guest context */ mon_memzero(vm->host.addr.guest_context, sizeof(guest_context_t)); /* Wind up the monitor stack for the initial transition via * __host2mon. At the tail end, monitor state is popped from the * stack and a RET is executed. */ { Bit32u *ptr; ptr = (Bit32u *) (((unsigned char *) vm->host.addr.guest_context) - 4); *ptr-- = (Bit32u) &__ret_to_guest; *ptr-- = 0x02; /* eflags: only reserved bit on */ *ptr-- = 0; /* eax */ *ptr-- = 0; /* ecx */ *ptr-- = 0; /* edx */ *ptr-- = 0; /* ebx */ *ptr-- = 0; /* esp dummy */ *ptr-- = 0; /* ebp */ *ptr-- = 0; /* esi */ *ptr-- = 0; /* edi */ *ptr-- = 0; /* FS; start with null value. */ *ptr-- = 0; /* GS; start with null value. */ } vm->vmState |= VMStateInitMonitor; vm->mon_request = MonReqNone; return(1); /* all OK */error: return(0); /* error */} unsignedhostInitGuestPhyMem(vm_t *vm){ unsigned i; mon_memzero(vm->pageInfo, sizeof(vm->pageInfo)); for (i=0; i<vm->pages.guest_n_pages; i++) { /* For now, we start out by preallocating physical pages */ /* for the guest, though not necessarily mapped into linear */ /* space. */ vm->pageInfo[i].attr.raw = 0; vm->pageInfo[i].tsc = 0; vm->pageInfo[i].attr.fields.allocated = 1; } { Bit32u rom_page; unsigned npages; /* Mark BIOS ROM area as ReadOnly */ rom_page = 0xf0000 >> 12; npages = (1 + 0xfffff - 0xf0000) / 4096; for (i=0; i<npages; i++) vm->pageInfo[rom_page + i].attr.fields.RO = 1; /* Mark VGA BIOS ROM area as ReadOnly */ rom_page = 0xc0000 >> 12; npages = (1 + 0xc7fff - 0xc0000) / 4096; for (i=0; i<npages; i++) vm->pageInfo[rom_page + i].attr.fields.RO = 1; } #if 1 /* Mark VGA framebuffer area as Memory Mapped IO */ { Bit32u vga_page; unsigned npages; vga_page = 0xa0000 >> 12; npages = (1 + 0xbffff - 0xa0000) / 4096; for (i=0; i<npages; i++) vm->pageInfo[vga_page + i].attr.fields.memMapIO = 1; }#endif return(0);} inthostInitIDTSlot(vm_t *vm, unsigned vec, int type)/* * initIDTSlot(): Initialize a monitor IDT slot. */{ /* IDT slot stubs */ idt_stub_t *stub = &vm->host.addr.idt_stubs[vec]; Bit32u stub_mon = ((Bit32u) vm->guest.addr.idt_stubs) + vec*sizeof(idt_stub_t); if (sizeof(idt_stub_t) != IDT_STUB_SIZE) return( -1 ); switch (type) { case IDT_INTERRUPT: stub->m2.pushla = 0x68; stub->m2.dummy = 0; stub->m2.pushlb = 0x68; stub->m2.vector = vec; stub->m2.jmp = 0xe9; stub->m2.reloc = ((Bit32u) &__handle_int) - (stub_mon + sizeof(idt_method2_t)); break; case IDT_EXCEPTION_ERROR: stub->m1.pushl = 0x68; stub->m1.vector = vec; stub->m1.jmp = 0xe9; stub->m1.reloc = ((Bit32u) &__handle_fault) - (stub_mon + sizeof(idt_method1_t)); break; case IDT_EXCEPTION_NOERROR: stub->m2.pushla = 0x68; stub->m2.dummy = 0; stub->m2.pushlb = 0x68; stub->m2.vector = vec; stub->m2.jmp = 0xe9; stub->m2.reloc = ((Bit32u) &__handle_fault) - (stub_mon + sizeof(idt_method2_t)); break; default: return -1; } /* Set the interrupt gate */ SET_INT_GATE(vm->host.addr.idt[vec], nullSelector, stub_mon, D_PRESENT, D_DPL0, D_D32); return 0;}/* * Map pages allocated by host, into the linear address space of * the monitor/guest, given the Page Table supplied. */ voidhostMapMonPages(vm_t *vm, Bit32u *pages, unsigned n, Bit32u *laddr_p, page_t *pageTable, unsigned user, unsigned writable, char *name){ unsigned i, pti;#if 0hostOSPrint("hostMapMonPages: '%s' mapped at 0x%x .. 0x%x.\n", name, (*laddr_p) - MON_BASE_FROM_LADDR(0), ((*laddr_p) + (n*4096)) - MON_BASE_FROM_LADDR(0) );#endif pti = (*laddr_p >> 12) & 0x3ff; for (i = 0; i < n; i++, pti++) { if (pti > 1024) break; /* This should not happen! */ /* Fill in the PTE flags */ pageTable->pte[pti].fields.base = pages[i]; pageTable->pte[pti].fields.avail = 0; pageTable->pte[pti].fields.G = 0; /* not global */ pageTable->pte[pti].fields.PS = 0; /* (unused in pte) */ pageTable->pte[pti].fields.D = 0; /* clean */ pageTable->pte[pti].fields.A = 0; /* not accessed */ pageTable->pte[pti].fields.PCD = 0; /* normal caching */ pageTable->pte[pti].fields.PWT = 0; /* normal write-back */ pageTable->pte[pti].fields.US = user; /* 0=system, 1=user */ pageTable->pte[pti].fields.RW = writable; /* 0=RO, 1=RW */ pageTable->pte[pti].fields.P = 1; /* present in memory */ } /* * Advance linear address pointer, for the next set of pages * to be mapped. */ *laddr_p += 4096 * n;}#if ANAL_CHECKS voidhostMapBlankPage(vm_t *vm, Bit32u *laddr_p, page_t *pageTable){ unsigned pti; pti = (*laddr_p >> 12) & 0x3ff; if (pti > 1024) return; /* This should not happen! */ /* Fill in the PTE flags */ pageTable->pte[pti].fields.base = 0; pageTable->pte[pti].fields.avail = 0; pageTable->pte[pti].fields.G = 0; /* not global */ pageTable->pte[pti].fields.PS = 0; /* (unused in pte) */ pageTable->pte[pti].fields.D = 0; /* clean */ pageTable->pte[pti].fields.A = 0; /* not accessed */ pageTable->pte[pti].fields.PCD = 0; /* normal caching */ pageTable->pte[pti].fields.PWT = 0; /* normal write-back */ pageTable->pte[pti].fields.US = 0; pageTable->pte[pti].fields.RW = 0; pageTable->pte[pti].fields.P = 0; /* * Advance linear address pointer, for the next set of pages * to be mapped. */ *laddr_p += 4096;}#endif inthostIoctlGeneric(vm_t *vm, void *inode, void *filp, unsigned int cmd, unsigned long arg){ switch (cmd) { /* * Set the guest CPUID info. */ case PLEX86_CPUID: { if ( vm->vmState & VMStateGuestCPUID ) { /* Can't change guest CPUID. */ return -Plex86ErrnoEINVAL; } if ( hostOSCopyFromUser(&vm->guestCPUIDInfo, (void *)arg, sizeof(vm->guestCPUIDInfo)) ) return -Plex86ErrnoEFAULT;/* xxx Value checks here. */ vm->vmState |= VMStateGuestCPUID; return 0; } case PLEX86_REGISTER_MEMORY: { plex86IoctlRegisterMem_t registerMemMsg; if ( hostOSCopyFromUser(®isterMemMsg, (void *)arg, sizeof(registerMemMsg)) ) return -Plex86ErrnoEFAULT; return( hostIoctlRegisterMem(vm, ®isterMemMsg) ); } /* * Tear down the VM environment. */ case PLEX86_TEARDOWN: if ( vm->vmState & VMStateRegisteredAll ) { hostOSPrint("plex86: guest memory is still registered!\n"); /* Could effect the unpinning here and then do: * vm->vmState &= ~VMStateRegisteredAll; */ return -Plex86ErrnoEBUSY; } hostUnallocVmPages(vm); /* Fixme: deal with state better here. */ /* Reset state to only FD opened. */ vm->vmState = VMStateFDOpened; return 0; /* * Execute the guest in the VM for a while. The guest CPU state * is specified in a memory window mmap()'d to user space. */ case PLEX86_EXECUTE: { plex86IoctlExecute_t executeMsg; int ret; if ( hostOSCopyFromUser(&executeMsg, (void *)arg, sizeof(executeMsg)) ) return -Plex86ErrnoEFAULT; ret = hostIoctlExecute(vm, &executeMsg); if ( hostOSCopyToUser((void *)arg, &executeMsg, sizeof(executeMsg)) ) return -Plex86ErrnoEFAULT; return ret; }#warning "PLEX86_RESET should only conditionally compiled for debugging." /* * For debugging, when the module gets hosed, this is a way * to reset the in-use count, so we can rmmod it. */ case PLEX86_RESET: hostOSModuleCountReset(vm, inode, filp); return 0; default: hostOSPrint("plex86: unknown ioctl(%d) called\n", cmd); return -Plex86ErrnoEINVAL; }} inthostIoctlExecute(vm_t *vm, plex86IoctlExecute_t *executeMsg){ guest_cpu_t *guest_cpu; guest_context_t *guest_stack_context; nexus_t *nexus; unsigned s; int retval; if ( (vm->vmState != VMStateReady) || (vm->mon_request != MonReqNone) ) { retval = Plex86NoExecute_VMState; /* Fail. */ goto handlePanic; } /* Only (virtualized) native execution is supported currently. * Later, it will be interesting to breakpoint one instruction * at-a-time using Plex86ExecuteMethodBreakpoint, for * cosimulation. */ if (executeMsg->executeMethod != Plex86ExecuteMethodNative) { retval = Plex86NoExecute_Method; /* Fail. */ goto handleFail; } /* 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; /* ================================================================= * Before executing the guest in the VM, we must check that * the guest conditions meet the requirements of the user-level-only * VM. * ================================================================= */ /* CR0: * PG(31)==1 * CD(30)==? (look into this later) * NW(29)==? (look into this later) * AM(18)==pass-thru from guest * WP(16)==Don't care. Monitor always sets this to 1. * NE( 5)==? (look into this later) * ET( 4)==? (look into this later) * TS( 3)==? (look into this later) * EM( 2)==? (look into this later) * MP( 1)==? (look into this later) * PE( 0)==1 */ /* 0x8005003b */ if ( (guest_cpu->cr0.raw & 0xe0000037) != 0x80000033 ) { hostOSPrint("plex86: guest CR0=0x%x\n", guest_cpu->cr0.raw); retval = Plex86NoExecute_CR0; /* Fail. */ goto handleFail; } /* CR4: * OSXMMEXCPT(10)==? (look into this later) * OSFXSR(9)==? (look into this later) * PCE(8)==? (look into this later) * PGE(7)==? (look into this later) * MCE(6)==? (look into this later) * PAE(5)==? (look into this later) * PSE(4)==? (look into this later) * DE(3)==? (look into this later) * TSD(2)==? (look into this later) * PVI(1)==? (look into this later) * VME(0)==? (look into this later) */ if ( (guest_cpu->cr4.raw & 0x000007ff) != 0x00000000 ) { hostOSPrint("plex86: guest CR4=0x%x\n", guest_cpu->cr4.raw); retval = Plex86NoExecute_CR4; /* Fail. */ goto handleFail; } /* Guest CPL must be 3 (user-level). * CS selector must not be NULL. */ if ( (guest_cpu->sreg[SRegCS].sel.fields.rpl != 3) || (guest_cpu->sreg[SRegCS].sel.fields.index == 0) || (guest_cpu->sreg[SRegCS].des.dpl != 3) ) { retval = Plex86NoExecute_CS; /* Fail. */ goto handleFail; } /* A20 line must be enabled. */ if ( guest_cpu->a20Enable != 1 ) { retval = Plex86NoExecute_A20; /* Fail. */ goto handleFail; } /* Some code not really used now, since we only support A20 being enabled. */ { unsigned newA20Enable; newA20Enable = guest_cpu->a20Enable > 0; /* Make 0 or 1. */ if ( newA20Enable != vm->system.a20Enable ) { if ( (!newA20Enable) && guest_cpu->cr0.fields.pg ) { /* A20 disabled, paging on not supported. Well, really I have to * see if it matters. This check was in old plex86 code. */ retval = Plex86NoExecute_A20; /* Fail. */ goto handleFail; } vm->system.a20Enable = newA20Enable; vm->system.a20AddrMask = 0xffefffff | (newA20Enable << 20); vm->system.a20IndexMask = 0x000ffeff | (newA20Enable << 8); } } /* LDT not supported. * Monitor uses GDT slots 1,2,3, so guest segments can not. * Segment descriptor cache DPL should equal 3. */ for (s=0; s<6; s++) { unsigned selector = guest_cpu->sreg[s].sel.raw; unsigned index; /* Only care if selector is not NULL. */ if ( selector & 0xfffc ) { if ( (selector & 0x0007) != 3 ) { /* Either TI=1 (LDT usage) or RPL!=3. */ retval = Plex86NoExecute_Selector; /* Fail. */ goto handleFail; } index = selector >> 3; if ( index <= 3 ) { /* Selector index field uses one of the monitor GDT slots. */ retval = Plex86NoExecute_Selector; /* Fail. */ goto handleFail; } if ( index >= (MON_GDT_SIZE/8) ) { /* Selector index field uses a slot beyond the monitor GDT size. */ retval = Plex86NoExecute_Selector; /* Fail. */ goto handleFail; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -