⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 monitor-host.c

📁 bochs : one pc simulator.
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *  plex86: run multiple x86 operating systems concurrently *  Copyright (C) 1999-2003 Kevin P. Lawton * *  monitor-host.c:  This file contains the top-level monitor code, *    accessible from the host space. (kernel independent code) * *  This library is free software; you can redistribute it and/or *  modify it under the terms of the GNU Lesser General Public *  License as published by the Free Software Foundation; either *  version 2 of the License, or (at your option) any later version. * *  This library is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *  Lesser General Public License for more details. * *  You should have received a copy of the GNU Lesser General Public *  License along with this library; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */#include "plex86.h"#define IN_HOST_SPACE#include "monitor.h"/* ===================================================================== * Plex86 module global variables.  This should be the _only_ place * where globals are declared.  Since plex86 supports multiple VMs, almost * all data is stored per-VM.  For the few variables which are global * to all VMs, we have to be careful to access them in SMP friendly ways. * The ones which are written upon kernel module initialization are fine, * since they are only written once. * ===================================================================== *//* Info regarding the physical pages that comprise the kernel module, * including physical page information.  This is written (once) at * kernel module initialization time.  Thus there are no SMP access issues. */kernelModulePages_t kernelModulePages;/* Information of the host processor as returned by the CPUID * instruction.  This is written (once) at kernel module initialization time. * Thus there no are SMP access issues. */cpuid_info_t hostCpuIDInfo;/* Some constants used by the VM logic.  Since they're "const", there are * no problems with SMP access. */static const selector_t nullSelector = { raw: 0 };static const descriptor_t nullDescriptor = {  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  };static int  hostInitIDTSlot(vm_t *vm, unsigned vec, int type);static void hostMapMonPages(vm_t *vm, Bit32u *, unsigned, Bit32u *, page_t *,                            unsigned user, unsigned writable, char *name);#if ANAL_CHECKSstatic void hostMapBlankPage(vm_t *vm, Bit32u *laddr_p, page_t *pageTable);#endif#define RW0 0#define RW1 1#define US0 0#define US1 1#define IDT_INTERRUPT          0#define IDT_EXCEPTION_ERROR    1#define IDT_EXCEPTION_NOERROR  2  unsignedhostModuleInit(void){  /* Kernel independent stuff to do at kernel module load time. */  if (!hostGetCpuCapabilities()) {    hostOSPrint("getCpuCapabilities returned error\n");    return(0); /* Fail. */    }  else {#if 0    hostOSPrint("ptype:%u, family:%u, model:%u stepping:%u\n",        hostCpuIDInfo.procSignature.fields.procType,        hostCpuIDInfo.procSignature.fields.family,        hostCpuIDInfo.procSignature.fields.model,        hostCpuIDInfo.procSignature.fields.stepping);#endif    }  /* xxx Should check that host CS.base is page aligned here. */#if 1  {  Bit32u cr0;  asm volatile ( "movl %%cr0, %0" : "=r" (cr0) );  hostOSPrint("host CR0=0x%x\n", cr0);  }#endif  return(1); /* Pass. */}  voidhostDeviceOpen(vm_t *vm){  /* Kernel independent stuff to do at device open time. */  /* Zero out entire VM structure. */  mon_memzero( vm, sizeof(vm_t) );  vm->vmState = VMStateFDOpened;}  inthostInitMonitor(vm_t *vm){  unsigned pdi, pti;  unsigned int i;  Bit32u nexus_size;  page_t  *pageTable;  Bit32u laddr, base;  int r;  vm->kernel_offset = hostOSKernelOffset();  vm->system.a20Enable = 1; /* Start with A20 line enabled. */  vm->system.a20AddrMask  = 0xffffffff; /* All address lines contribute. */  vm->system.a20IndexMask = 0x000fffff; /* All address lines contribute. */  /* Initialize nexus */  mon_memzero(vm->host.addr.nexus, 4096);  /* Copy transition code (nexus) into code page allocated for this VM. */  nexus_size = ((Bit32u) &__nexus_end) - ((Bit32u) &__nexus_start);  if (nexus_size > 4096)    goto error;  mon_memcpy(vm->host.addr.nexus, &__nexus_start, nexus_size);  /* Init the convenience pointers. */  /* Pointer to host2mon routine inside nexus page */  vm->host.__host2mon = (void (*)(void)) HOST_NEXUS_OFFSET(vm, __host2mon);  /* Pointer to guest context on monitor stack */  vm->host.addr.guest_context = (guest_context_t *)    ( (Bit32u)vm->host.addr.nexus + PAGESIZE - sizeof(guest_context_t) );  /* Zero out various monitor data structures */  mon_memzero(vm->host.addr.log_buffer, 4096*LOG_BUFF_PAGES);  mon_memzero(&vm->log_buffer_info,              sizeof(vm->log_buffer_info));  mon_memzero(vm->host.addr.page_dir, 4096);  mon_memzero(vm->host.addr.guest_cpu, 4096);  mon_memzero(vm->host.addr.idt, MON_IDT_PAGES*4096);  mon_memzero(vm->host.addr.gdt, MON_GDT_PAGES*4096);  mon_memzero(vm->host.addr.ldt, MON_LDT_PAGES*4096);  mon_memzero(vm->host.addr.tss, MON_TSS_PAGES*4096);  mon_memzero(vm->host.addr.idt_stubs, MON_IDT_STUBS_PAGES*4096);  vm->guestPhyPagePinQueue.nEntries = 0;  vm->guestPhyPagePinQueue.tail = 0;  /*   *  ================   *  Nexus Page Table   *  ================   *   *  All structures needed by the monitor inside the guest environment   *  (code to perform the transition between host<-->guest, fault handler   *  code, various processor data structures like page directory, GDT,   *  IDT, TSS etc.) are mapped into a single Page Table.   *   *  This allows us to migrate the complete nexus to anywhere in the   *  guest address space by just updating a single (unused) page directory   *  entry in the monitor/guest page directory to point to this nexus   *  page table.   *   *  To simplify nexus migration, we try to avoid storing guest linear   *  addresses to nexus structures as far as possible.  Instead, we use   *  offsets relative to the monitor code/data segments.  As we update   *  the base of these segments whenever the monitor migrates, the net   *  effect is that those *offsets* remain valid across nexus migration.    */  /* Fill in the PDE flags.  The US bit is set to 1 (user access).   * All of the US bits in the monitor PTEs are set to 0 (system access).   */  vm->host.nexus_pde.fields.base = vm->pages.nexus_page_tbl;  vm->host.nexus_pde.fields.avail = 0;  vm->host.nexus_pde.fields.G = 0;      /* not global */  vm->host.nexus_pde.fields.PS = 0;     /* 4K pages */  vm->host.nexus_pde.fields.D = 0;      /* (unused in pde) */  vm->host.nexus_pde.fields.A = 0;      /* not accessed */  vm->host.nexus_pde.fields.PCD = 0;    /* normal caching */  vm->host.nexus_pde.fields.PWT = 0;    /* normal write-back */  vm->host.nexus_pde.fields.US = 1;     /* user access (see above) */  vm->host.nexus_pde.fields.RW = 1;     /* read or write */  vm->host.nexus_pde.fields.P = 1;      /* present in memory */  /* Clear Page Table. */  pageTable = vm->host.addr.nexus_page_tbl;  mon_memzero(pageTable, 4096);  /* xxx Comment here */  laddr = 0;  base = MON_BASE_FROM_LADDR(laddr);  hostMapMonPages(vm, kernelModulePages.ppi, kernelModulePages.nPages, &laddr,                  pageTable, US0, RW1, "Monitor code/data pages");#if ANAL_CHECKS  hostMapBlankPage(vm, &laddr, pageTable);#endif  vm->guest.addr.nexus = (nexus_t *) (laddr - base);  hostMapMonPages(vm, &vm->pages.nexus, 1, &laddr, pageTable, US0, RW1, "Nexus");  vm->guest.addr.guest_context = (guest_context_t *)    ( (Bit32u)vm->guest.addr.nexus + PAGESIZE - sizeof(guest_context_t) );#if ANAL_CHECKS  hostMapBlankPage(vm, &laddr, pageTable);#endif  vm->host.addr.nexus->vm = (void *) (laddr - base);  hostMapMonPages(vm, vm->pages.vm, BytesToPages(sizeof(*vm)),                  &laddr, pageTable, US0, RW1, "VM structure");#if ANAL_CHECKS  hostMapBlankPage(vm, &laddr, pageTable);#endif  vm->guest.addr.idt = (gate_t *) (laddr - base);  hostMapMonPages(vm, vm->pages.idt, MON_IDT_PAGES, &laddr, pageTable, US0, RW1,                  "IDT");#if ANAL_CHECKS  hostMapBlankPage(vm, &laddr, pageTable);#endif  vm->guest.addr.gdt = (descriptor_t *) (laddr - base);  hostMapMonPages(vm, vm->pages.gdt, MON_GDT_PAGES, &laddr, pageTable, US0, RW1,                  "GDT");#if ANAL_CHECKS  hostMapBlankPage(vm, &laddr, pageTable);#endif  vm->guest.addr.ldt = (descriptor_t *) (laddr - base);  hostMapMonPages(vm, vm->pages.ldt, MON_LDT_PAGES, &laddr, pageTable, US0, RW1,                  "LDT");#if ANAL_CHECKS  hostMapBlankPage(vm, &laddr, pageTable);#endif  vm->guest.addr.tss = (tss_t *) (laddr - base);  hostMapMonPages(vm, vm->pages.tss, MON_TSS_PAGES, &laddr, pageTable, US0, RW1,                  "TSS");#if ANAL_CHECKS  hostMapBlankPage(vm, &laddr, pageTable);#endif  vm->guest.addr.idt_stubs = (idt_stub_t *) (laddr - base);  hostMapMonPages(vm, vm->pages.idt_stubs, MON_IDT_STUBS_PAGES, &laddr,                  pageTable, US0, RW1, "IDT stubs");#if ANAL_CHECKS  hostMapBlankPage(vm, &laddr, pageTable);#endif  /* Monitor Page Directory */  vm->guest.addr.page_dir = (pageEntry_t *) (laddr - base);  hostMapMonPages(vm, &vm->pages.page_dir, 1, &laddr, pageTable, US0, RW1,                  "Monitor Page Directory");#if ANAL_CHECKS  hostMapBlankPage(vm, &laddr, pageTable);#endif  /* Nexus Page Table */  vm->guest.addr.nexus_page_tbl = (page_t *) (laddr - base);  hostMapMonPages(vm, &vm->pages.nexus_page_tbl, 1, &laddr, pageTable, US0, RW1,                  "Nexus Page Table");#if ANAL_CHECKS  hostMapBlankPage(vm, &laddr, pageTable);#endif  /* Map virtualized guest page tables into monitor. */  vm->guest.addr.page_tbl = (page_t *) (laddr - base);  hostMapMonPages(vm, vm->pages.page_tbl, MON_PAGE_TABLES,                  &laddr, pageTable, US0, RW1, "Guest Page Tables");#if ANAL_CHECKS  hostMapBlankPage(vm, &laddr, pageTable);#endif  /* Map of linear addresses of page tables mapped into monitor */  vm->guest.addr.page_tbl_laddr_map = (unsigned *) (laddr - base);  hostMapMonPages(vm, &vm->pages.page_tbl_laddr_map, 1, &laddr, pageTable,                  US0, RW1, "Page Table Laddr Map");#if ANAL_CHECKS  hostMapBlankPage(vm, &laddr, pageTable);#endif  /* Guest CPU state (mapped RW into user space also). */  vm->guest.addr.guest_cpu = (guest_cpu_t *) (laddr - base);  hostMapMonPages(vm, &vm->pages.guest_cpu, 1, &laddr,                  pageTable, US0, RW1, "Guest CPU State");#if ANAL_CHECKS  hostMapBlankPage(vm, &laddr, pageTable);#endif  /*   *  We need a buffer to implement a debug print facility which   *  can work in either host or monitor space.  Map the buffer   *  into monitor/guest space.   */  vm->guest.addr.log_buffer = (unsigned char *) (laddr - base);  hostMapMonPages(vm, vm->pages.log_buffer, LOG_BUFF_PAGES, &laddr,                  pageTable, US0, RW1, "Log Buffer");  {  /* The physical addresses of the following pages are not */  /* yet established.  Pass dummy info until they are mapped. */  Bit32u tmp[1];  tmp[0] = 0;#if ANAL_CHECKS  hostMapBlankPage(vm, &laddr, pageTable);#endif  /* Window into the guest's current physical code page */  vm->guest.addr.code_phy_page = (unsigned char *) (laddr - base);  hostMapMonPages(vm, tmp, 1, &laddr, pageTable, US0, RW1, "Code Phy Page");#if ANAL_CHECKS  hostMapBlankPage(vm, &laddr, pageTable);#endif  /* Temporary window into a guest physical page, for accessing */  /* guest GDT, IDT, etc info. */  vm->guest.addr.tmp_phy_page0 = (unsigned char *) (laddr - base);  hostMapMonPages(vm, tmp, 1, &laddr, pageTable, US0, RW1, "Tmp Phy Page0");  vm->guest.addr.tmp_phy_page1 = (unsigned char *) (laddr - base);  hostMapMonPages(vm, tmp, 1, &laddr, pageTable, US0, RW1, "Tmp Phy Page1");  }#if ANAL_CHECKS  hostMapBlankPage(vm, &laddr, pageTable);#endif  hostOSPrint("Using %u/1024 PTE slots in 4Meg monitor range.\n",              (laddr >> 12) & 0x3ff);  /* Pointer to mon2host routine inside nexus page */  vm->guest.__mon2host = (void (*)(void)) MON_NEXUS_OFFSET(vm, __mon2host);  /*   *  =====================   *  Transition Page Table   *  =====================   *   *  To aid in the transition between host<-->monitor/guest spaces,   *  we need to have an address identity map situation for at least   *  one page; the page containing the transition code.   As we do   *  not know in advance whether this linear address range is in use   *  by the guest as well, we set aside a complete additional Page   *  Table, which contains only a single PTE pointing to the nexus page.   *   *  To create the identity map, we simply change the corresponding   *  monitor page directory entry to point to this transition Page Table.   *  This happens transparently inside the host<-->guest transition code;    *  both the guest/monitor code and the host side code never see this    *  transition page table entered into the page directory!   *   *  NOTE: We need to ensure that the nexus page table never spans the   *        same 4Meg linear address space region as this page table!   *        As we are free to choose the nexus linear address, this is   *        not a problem.   */  /* Get full linear address of nexus code page, as seen in host space. */  laddr = (Bit32u)vm->host.addr.nexus + vm->kernel_offset;  pdi = laddr >> 22;  pti = (laddr >> 12) & 0x3ff;  /*   *  We need to be able to access the PDE in the monitor page directory   *  that corresponds to this linear address from both host and monitor    *  address spaces.   */  vm->host.addr.nexus->transition_pde_p_host = vm->host.addr.page_dir + pdi;  vm->host.addr.nexus->transition_pde_p_mon  = (pageEntry_t *)                        (((Bit32u)vm->guest.addr.page_dir) + (pdi << 2));  vm->host.addr.nexus->transition_laddr = laddr;  /* Fill in the PDE flags */  vm->host.addr.nexus->transition_pde.fields.base = vm->pages.transition_PT;  vm->host.addr.nexus->transition_pde.fields.avail = 0;  vm->host.addr.nexus->transition_pde.fields.G = 0;   /* not global */  vm->host.addr.nexus->transition_pde.fields.PS = 0;  /* 4K pages */  vm->host.addr.nexus->transition_pde.fields.D = 0;   /* (unused in pde) */  vm->host.addr.nexus->transition_pde.fields.A = 0;   /* not accessed */  vm->host.addr.nexus->transition_pde.fields.PCD = 0; /* normal caching */  vm->host.addr.nexus->transition_pde.fields.PWT = 0; /* normal write-back*/  vm->host.addr.nexus->transition_pde.fields.US = 0;  /* no user access  */  vm->host.addr.nexus->transition_pde.fields.RW = 1;  /* read or write */  vm->host.addr.nexus->transition_pde.fields.P = 1;   /* present in memory*/  /* Clear Page Table; only one PTE is used. */  pageTable = vm->host.addr.transition_PT;  mon_memzero(pageTable, 4096);  /* Fill in the PTE for identity mapping the code page */  pageTable->pte[pti].fields.base = vm->pages.nexus;  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;     /* user can not access */  pageTable->pte[pti].fields.RW = 1;     /* read or write       */  pageTable->pte[pti].fields.P = 1;      /* present in memory   */  /*    *  Setup the TSS for the monitor/guest environment.   *   *  We don't need to set the pagedir in the TSS, because we don't    *  actually jump to it anyway.  The TSS is just used to set the kernel    *  stack and in a later stage, perhaps the I/O permission bitmap.   */  /* No task chain. */  vm->host.addr.tss->back = 0;  /* No debugging or I/O, for now. */  vm->host.addr.tss->trap = 0;  vm->host.addr.tss->io = sizeof(tss_t);  /* Monitor stack offset. */  vm->host.addr.tss->esp0 =    ((Bit32u)vm->guest.addr.nexus) + PAGESIZE;  /*   * Set up initial monitor code and stack offset.   */  vm->host.addr.nexus->mon_jmp_info.offset   = MON_NEXUS_OFFSET(vm, __mon_cs);  vm->host.addr.nexus->mon_stack_info.offset =      vm->host.addr.tss->esp0 - (sizeof(guest_context_t) + 48);/* xxx 48 above should be calculated from code below which winds * xxx up monitor stack. */  /*   *  Setup the IDT for the monitor/guest environment   */  r = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -