here it is.
/*
* plex86: run multiple x86 operating systems concurrently
* Copyright (C) 1999-2001 Kevin P. Lawton
*
* monitor.h: main VM monitor defines
*
* 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
*/
#ifndef __MONITOR_H__
#define __MONITOR_H__
#if defined(__NetBSD__) || defined(__FreeBSD__)
#include <machine/stdarg.h>
#else
#include <stdarg.h>
#endif
#include "descriptor.h"
#include "descriptor2.h"
#include "tss.h"
#include "paging.h"
#include "eflags.h"
#include "guest_context.h"
#include "fetchdecode.h"
#include "crx.h"
#include "fetchdecode.h"
//#include "dt.h"
#include "instrument.h"
/* setjmp/longjmp stuff */
typedef struct {
long blah[6]; /* Was 5, I made it 6 to be safe. Can't find documentation. */
} vm_jmp_buf_t;
#define SetJmp(jmp_buf) __builtin_setjmp(&jmp_buf)
#define LongJmp(jmp_buf, ret) __builtin_longjmp(&jmp_buf, ret)
#if 0
/* Opcode Virtualization Map. This type defines a map of IA32 */
/* instructions, and virtualization attributes for each instruction. */
typedef struct {
Bit8u standard[512]; /* 1 (1st 256) and 2 byte (2nd 256) opcode maps */
Bit8u groups[NumGroups][8];
} vOpcodeMap_t;
extern vOpcodeMap_t vOpcodeMapStrongest;
typedef struct {
Bit8u *tcodePtr;
Bit32u tcodeOff;
} dtRelocRec_t;
#endif
/* Method1: push event info (CPU pushes error code before) */
typedef struct
{
Bit8u pushl; /* Always 0x68 == pushl */
Bit32u vector; /* Interrupt vector number */
Bit8u jmp; /* Always 0xe9 == jmp */
Bit32u reloc; /* Relative offset of destination */
} __attribute__ ((packed)) idt_method1_t;
/* Method2: push a dummy error first, then event info */
typedef struct
{
Bit8u pushla; /* Always 0x68 == pushl */
Bit32u dummy; /* Dummy error code */
Bit8u pushlb; /* Always 0x68 == pushl */
Bit32u vector; /* Interrupt vector number */
Bit8u jmp; /* Always 0xe9 == jmp */
Bit32u reloc; /* Relative offset of destination */
} __attribute__ ((packed)) idt_method2_t;
typedef union
{
idt_method1_t m1;
idt_method2_t m2;
} idt_stub_t;
/* Bitmap handling macros */
#define BMAP_SZ(y) (y>>3)
#define BMAP_GET(x,y) ((((Bit8u *)x)[y>>3]>>(y&7))&1)
#define BMAP_SET(x,y) (((Bit8u *)x)[y>>3]|=(1<<(y&7)))
#define BMAP_CLR(x,y) (((Bit8u *)x)[y>>3]&=~(1<<(y&7)))
/* Nexus fields. This C structure maps to identical assembly */
/* fields in nexus.S. Make sure to update both! These fields */
/* are accessible to the nexus code during the transition from */
/* host<->guest and are stored in a single page. */
typedef struct {
/* guest pointer to vm_t structure. */
void *vm;
/* These fields are only used by the transition code. */
/* They hold all info necessary to switch back to the host. */
gdt_info_t host_gdt_info;
gdt_info_t host_idt_info;
far_jmp_info_t host_jmp_info;
far_jmp_info_t host_stack_info;
Bit16u host_ldt_sel;
Bit16u host_tss_sel;
Bit32u host_cr0;
Bit32u host_cr2;
Bit32u host_cr3;
Bit32u host_cr4;
/* These fields are filled by the host-side code, and used */
/* by the transition code. They contain all info necessary */
/* to switch to the monitor/guest address space. */
/* This info changes whenever the monitor migrates. */
gdt_info_t mon_gdt_info;
gdt_info_t mon_idt_info;
far_jmp_info_t mon_jmp_info;
far_jmp_info_t mon_stack_info;
Bit16u mon_ldt_sel;
Bit16u mon_tss_sel;
Bit32u mon_base;
Bit32u mon_cr0;
Bit32u mon_cr3;
Bit32u mon_cr4;
Bit32u mon_eflags;
/* These fields contain info used by the transition code to */
/* create the temporary identity mapping. They never change. */
pageEntry_t transition_pde;
pageEntry_t *transition_pde_p_host;
pageEntry_t *transition_pde_p_mon;
Bit32u transition_laddr;
Bit32u espUpperNormal;
Bit32u espUpper16BitSSHack;
Bit32u SS16BitSSHack;
Bit32u SSNormal;
} __attribute__ ((packed)) nexus_t;
/* For reference, the following describes where bits from the guest */
/* eflags register are stored/managed. */
/* */
/* Key: */
/* g: Flag value as requested by guest */
/* V: Virtualized flag value, as loaded in eflags when guest is executing */
/* ?: Unhandled yet, request of set bit causes panic for now */
/* */
/* === ======= ====== ======= ======= ======= */
/* |I|V|V|A|V|R|0|N|IO|O|D|I|T|S|Z|0|A|0|P|1|C| flag */
/* |D|I|I|C|M|F| |T|PL|F|F|F|F|F|F| |F| |F| |F| */
/* | |P|F| | | | | | | | | | | | | | | | | | | */
/* |g|?|?|g|V|g|g|g|VV|g|g|V|g|g|g|g|g|g|g|g|g| context->eflags */
/* | |?|?| |g| | | |gg| | |g| | | | | | | | | | guest_cpu.veflags */
//#define VirtualizedEflags 0x001a3200
#define VirtualizedEflags 0x001a3300
/* This defines certain CPU state info as _requested_ by the guest OS. */
/* The state of the general registers and segment selectors is stored */
/* on the monitor stack by the monitor exception handler. */
typedef struct {
cr0_t cr0;
Bit32u cr1;
Bit32u cr2;
Bit32u cr3;
cr4_t cr4;
/* Eflags which must be virtualized in guest_context->eflags. Only */
/* those bits which must be virtualized are stored here. */
eflags_t veflags;
unsigned cpl; /* for now */
gdt_info_t gdtr;
gdt_info_t idtr;
/* Maintain values of the selectors and shadow descriptor */
/* caches as requested by the guest OS. */
selector_t selector[6]; /* ES,CS,SS,DS,FS,GS */
descriptor_cache_t desc_cache[6]; /* ES,CS,SS,DS,FS,GS */
selector_t tr_selector;
descriptor_cache_t tr_cache;
selector_t ldtr_selector;
descriptor_cache_t ldtr_cache;
Bit32u prev_eip; /* for rewinding during emulation of instructions */
Bit32u prev_esp; /* for rewinding during emulation of instructions */
/* for saving/restoring during interrupt/exception handling... */
/* +++ see if we need this or can recode without it. */
descriptor_cache_t save_cs;
descriptor_cache_t save_ss;
Bit32u save_eip;
Bit32u save_esp;
unsigned curr_exception[2];
unsigned errorno;
#define INHIBIT_INTERRUPTS 0x01
#define INHIBIT_DEBUG 0x02
/* What events to inhibit at any given time. Certain instructions */
/* inhibit interrupts, some debug exceptions and single-step traps. */
unsigned inhibit_mask;
Boolean EXT; /* 1 if processing external interrupt or exception */
/* or if not related to current instruction, */
/* 0 if current CS:IP caused exception */
Bit32u debug_trap; /* holds DR6 value to be set as well */
volatile unsigned async_event;
struct {
/* physical address after translation of 1st len1 bytes of data */
Bit32u paddress1;
/* physical address after translation of 2nd len2 bytes of data */
Bit32u paddress2;
Bit32u len1; /* number of bytes in page 1 */
Bit32u len2; /* number of bytes in page 2 */
unsigned pages; /* number of pages access spans (1 or 2) */
} address_xlation;
Bit32u dr0;
Bit32u dr1;
Bit32u dr2;
Bit32u dr3;
Bit32u dr6;
Bit32u dr7;
Bit32u tr3;
Bit32u tr4;
Bit32u tr5;
Bit32u tr6;
Bit32u tr7;
} guest_cpu_state_t;
/* I define the 'nexus' as the set of data structures which */
/* must exist in the current linear guest address space. The */
/* host linear address space is not available while the current */
/* guest code is running, since we are using a completely */
/* different set of page mappings for the guest. However, */
/* at some point an exception/interrupt will occur. The */
/* interrupt mechanisms require that several structures exist in */
/* the current linear address space in order to service such */
/* an event. These data structures make up part of our VM, */
/* a thin layer which exists in the guest. Following is a */
/* list of what data structures compose this 'nexus': */
/* */
/* - IDT (max 2048 bytes) */
/* - GDT (max 65536 bytes) */
/* - LDT (max 65536 bytes) */
/* - TSS (max 8328 = 104 + 32 int redir + 8192 I/O permissions) */
/* - kernel stack page */
/* - transition code (host <--> guest) */
/* - interrupt handler stubs */
/* - Page Tables; PDE & PTE pages. */
/* */
/* Sizes of various nexus data structures used by the monitor */
/* */
#define PLEX86_MAX_PHY_MEGS 32
#define PAGESIZE 4096
#define IDT_STUB_SIZE 15
#define BYTES2PAGES(b) ( ((b)+4095) >> 12 )
// xxx convert references to above macro
#define BytesToPages(b) ( ((b)+4095) >> 12 )
#define MON_IDT_SIZE (8*256)
#define MON_GDT_SIZE (8*512)
#define MON_LDT_SIZE (8*1)
#define MON_IDT_STUBS_SIZE (IDT_STUB_SIZE*256)
#define MON_TSS_SIZE (104)
#define MON_IDT_PAGES BYTES2PAGES(MON_IDT_SIZE)
#define MON_GDT_PAGES BYTES2PAGES(MON_GDT_SIZE)
#define MON_LDT_PAGES BYTES2PAGES(MON_LDT_SIZE)
#define MON_IDT_STUBS_PAGES BYTES2PAGES(MON_IDT_STUBS_SIZE)
#define MON_TSS_PAGES BYTES2PAGES(MON_TSS_SIZE)
#define MON_GUEST_PAGES (PLEX86_MAX_PHY_MEGS * 256)
/* +++ MON_PAGE_TABLES is kind of random */
#define MON_PAGE_TABLES (10*((PLEX86_MAX_PHY_MEGS+3) >> 2))
#define MAX_VM_STRUCT_PAGES (36)
#define LOG_BUFF_PAGES 1
#define LOG_BUFF_SIZE ((LOG_BUFF_PAGES)*4096)
/*
* Pages allocated for the VM by the host kernel driver.
* N Megs of physical memory are allocated, per the user's
* request, for the guest OS/application code.
* Additionally, some other overhead pages are allocated
* for structures such as the page directory, page tables,
* and other virtualized facilities.
*/
typedef struct {
/* requested size of the guest[] array in megs and pages */
unsigned guest_n_megs;
unsigned guest_n_pages;
unsigned guest_n_bytes;
/* pages comprising the vm_t struct itself. */
Bit32u vm[MAX_VM_STRUCT_PAGES];
/* for the guest OS/app code */
Bit32u guest[MON_GUEST_PAGES];
/* for the monitor's page directory */
Bit32u page_dir;
/* for the monitor's page table */
Bit32u page_tbl[MON_PAGE_TABLES];
/* Map of the linear addresses of page tables currently */
/* mapped into the monitor space. */
Bit32u page_tbl_laddr_map;
/* for the extra page table that maps our nexus code and structures */
Bit32u nexus_page_tbl;
/* We need a Page Table for identity mapping the transition code */
/* between host and monitor spaces. */
Bit32u transition_PT;
Bit32u log_buffer[LOG_BUFF_PAGES];
/* Physical addresses of host pages which comprise the actual */
/* monitor structures. These will be mapped into the current */
/* guest task's linear address space as well. */
Bit32u nexus;
Bit32u idt[MON_IDT_PAGES];
Bit32u gdt[MON_GDT_PAGES];
Bit32u ldt[MON_LDT_PAGES];
Bit32u tss[MON_TSS_PAGES];
Bit32u idt_stubs[MON_IDT_STUBS_PAGES];
#if 0
Bit32u r3hData;
Bit32u dtL2MHash[DTL2MMaxPages];
unsigned dtL2MHashNPages;
Bit32u dtG2THash[DTG2TMaxPages];
unsigned dtG2THashNPages;
Bit32u dtPageMetaTable[DTMetaTableMaxPages];
unsigned dtPageMetaTableNPages;
Bit32u dtPageMetaTableUsage[DTMetaTableUsageMaxPages];
unsigned dtPageMetaTableUsageNPages;
Bit32u tcodeChunk[DTTcodeChunkMaxPages];
unsigned tcodeChunkNPages;
Bit32u tcodeChunkUsage[DTTcodeChunkUsageMaxPages];
unsigned tcodeChunkUsageNPages;
#endif
} vm_pages_t;
typedef struct {
void *guest;
pageEntry_t *page_dir;
page_t *page_tbl;
unsigned *page_tbl_laddr_map;
page_t *nexus_page_tbl;
page_t *transition_PT;
unsigned char *log_buffer;
Bit8u *code_phy_page; /* only use in mon space */
Bit8u *tmp_phy_page0; /* only use in mon space */
Bit8u *tmp_phy_page1; /* only use in mon space */
nexus_t *nexus;
/* Pointer into the monitor stack, so we can easily retrieve the */
/* stack snapshot upon interrupt/exception. */
guest_context_t *guest_context;
gate_t *idt;
descriptor_t *gdt;
descriptor_t *ldt;
tss_t *tss;
idt_stub_t *idt_stubs;
#if 0
// xxx change prefix tcodeChunk* with dt
r3hData_t *r3hData;
dtL2MHash_t *dtL2MHash;
dtG2THash_t *dtG2THash;
dtPageMeta_t *dtPageMetaTable;
Bit8u *dtPageMetaTableUsage;
tcodeChunk_t *tcodeChunk;
Bit8u *tcodeChunkUsage;
#endif
} vm_addr_t;
/* These bits define the possible usage and attributes assigned */
/* to a particular guest physical page. These are useful for keeping */
/* track of what kinds of system structures are contained in a page */
/* at a given time, and if the page has associated cached code */
/* information in the prescan logic. We can also tag particular */
/* pages with other more static attributes. */
typedef union {
struct {
Bit32u access_perm:2; /* */
Bit32u lmap_count:2; /* */
Bit32u ptbl:1; /* page table */
Bit32u pdir:1; /* page directory */
Bit32u vcode:1; /* vcode */
Bit32u memMapIO:1; /* MemMapIO */
Bit32u RO:1; /* RO */
Bit32u allocated:1; /* Allocated */
Bit32u swappable:1; /* Swappable */
Bit32u spare:1; /* (spare) */
Bit32u laddr_backlink:20; /* 1st unvirtualized laddr backlink */
} __attribute__ ((packed)) fields;
Bit32u raw;
} __attribute__ ((packed)) phy_page_attr_t;
typedef struct {
phy_page_attr_t attr;
Bit64u tsc; /* for comparing to CR3 timestamp counter */
} __attribute__ ((packed)) phy_page_usage_t;
/* Possible values of the access_perm field above. */
#define PagePermRW 0
#define PagePermRO 1
#define PagePermEmulate 2
#define PagePermNA PagePermEmulate /* No Access is synomym */
/* Bitmasks to access fields in structure above. */
#define PageUsagePTbl 0x010
#define PageUsagePDir 0x020
#define PageUsageVCode 0x040
#define PageUsageMemMapIO 0x080
#define PageUsageRO 0x100
#define PageUsageAllocated 0x200
#define PageUsageSwappable 0x400
/* Group of attributes which retain their value, even when CR3 */
/* is reloaded and the page mappings are flushed. */
#define PageUsageSticky \
( PageUsageMemMapIO | PageUsageRO | \
PageUsageAllocated | PageUsageSwappable )
/* Group of attributes which are not compatible with a Page Table */
/* occupying a physical page. */
#define PageBadUsage4PTbl \
( PageUsagePDir | PageUsageMemMapIO | PageUsageRO )
/* Group of attributes which are not compatible with a Page Directory */
/* occupying a physical page. Keep in mind, when the PDir is marked, */
/* no other dynamic bits will be set. */
#define PageBadUsage4PDir \
( PageUsageMemMapIO | PageUsageRO )
#define PageUsageCausesNA \
( PageUsagePTbl | PageUsagePDir | PageUsageMemMapIO )
#define PageUsageCausesRO \
( PageUsageVCode | PageUsageRO )
#define PDEUnhandled 0x000001d8
#define PTEUnhandled 0x00000198
#define OP_READ 0
#define OP_WRITE 1
#define OP_RW 2
#define VCodeSuccess 0
#define VCodePanic 1
#define VCodePhyPageNotPresent 2
#define VCodeEmulateInUserSpace 3
#define VCodeRemapMonitor 4
#define VCodeGuestFault 5
#define ExceptionDE 0 /* Divide Error (fault) */
#define ExceptionDB 1 /* Debug (fault/trap) */
#define ExceptionBP 3 /* Breakpoint (trap) */
#define ExceptionOF 4 /* Overflow (trap) */
#define ExceptionBR 5 /* BOUND (fault) */
#define ExceptionUD 6
#define ExceptionNM 7
#define ExceptionDF 8
#define ExceptionTS 10
#define ExceptionNP 11
#define ExceptionSS 12
#define ExceptionGP 13
#define ExceptionPF 14
#define ExceptionMF 16
#define ExceptionAC 17
#define CR0_PE (1<<0)
#define CR0_MP (1<<1)
#define CR0_EM (1<<2)
#define CR0_TS (1<<3)
#define CR0_ET (1<<4)
#define CR0_NE (1<<5)
#define CR0_WP (1<<16)
#define CR0_AM (1<<18)
#define CR0_NW (1<<29)
#define CR0_CD (1<<30)
#define CR0_PG (1<<31)
#define ProtectedMode(vm) \
(vm->guest_cpu.cr0.fields.pe && !vm->guest_cpu.veflags.fields.vm)
#define RealMode(vm) \
(!vm->guest_cpu.cr0.fields.pe)
#define V8086Mode(vm) \
(vm->guest_cpu.veflags.fields.vm)
typedef struct {
Bit64u period;
Bit64u remaining;
Bit64u inServiceElapsed;
Boolean active;
Boolean continuous;
Boolean triggered;
void (*callback)(void *, unsigned);
void *thisPtr;
unsigned space;
} timer_t;
/* */
/* Complete state of the VM (Virtual Machine) */
/* */
typedef struct {
unsigned executeMethod;
icount_t executeN;
unsigned dbg_force_int;
struct {
unsigned runRMAsVM86;
unsigned runVM86Native;
unsigned runPMR3Native;
} userOptions;
instruction_t i; /* Current instruction */
#define MON_STATE_UNINITIALIZED 0
#define MON_STATE_PANIC 1
#define MON_STATE_RUNNABLE 2
#define MON_REQ_NONE 0
#define MON_REQ_NOP 1
#define MON_REQ_REDIRECT 4
#define MON_REQ_REMAP_MONITOR 5
#define MON_REQ_RESPONSE_PENDING 6
#define MON_REQ_NO_RESPONSE 7
#define MON_REQ_PANIC 8
unsigned mon_state;
unsigned mon_request;
#if 0
#define RemapHintModeEstablished 2
unsigned remapHints;
#endif
unsigned redirect_vector;
#define ModeChangeEventTransition 0x1
#define ModeChangeEventPaging 0x2
#define ModeChangeEventCS 0x4
#define ModeChangeRequestPaging 0x8
unsigned modeChange;
/* Bitlists of which selectors and descriptors are currently
* stored in the guest_cpu structure, and which ones have been
* updated.
*/
unsigned selectorInEmu;
unsigned descriptorInEmu;
unsigned segmentUpdated;
Bit32u kernel_offset;
vm_jmp_buf_t jmp_buf_env;
#define MAX_TIMERS 16
#define MonitorSpace 0
#define UserSpace 1
#define HostSpace 2
//vOpcodeMap_t *vOpcodeMap; // xxx For DT
//unsigned eipModified;
volatile unsigned inMonFault;
//tcodeChunk_t tempTcodeChunk;
//tcodeSnippet_t tcodeSnippets[MaxTcodeSnippets];
#if 0
/* Some fields used for relocating branch offsets in tcode during
* translation.
*/
#define MaxRelocEntries 32
dtRelocRec_t reloc[MaxRelocEntries];
unsigned relocN;
#endif
/* Extra info on aborts, especially when a message can't
* be printed out
*/
unsigned abort_code;
/* System bus oriented info */
struct {
unsigned intr; /* INTR bus line */
unsigned hrq; /* Hold ReQuest bus line for DMA */
timer_t timer[MAX_TIMERS];
unsigned num_timers;
Bit64u cyclesInPeriod;
Bit64u cyclesRemaining;
Bit64u t0; /* TSC before excecution of guest code */
Bit64u cyclesElapsed; /* Cycles of guest execution */
unsigned a20; /* address 20 line enabled */
Bit32u a20AddrMask; /* mask to apply to phy address */
Bit32u a20IndexMask; /* mask to apply to phy address */
} system;
/* This macro yields a physical address after applying the A20 line
* enable mask to the original physical address.
*/
#define A20Addr(vm, paddr) ( (paddr) & ((vm)->system.a20AddrMask) )
#define A20PageIndex(vm, pi) ( (pi) & ((vm)->system.a20IndexMask) )
/* Keep an index of the next available Page Table */
unsigned ptbl_laddr_map_i;
#if 0
pageEntry_t *codepage_pte_p;
pageEntry_t codepage_pte_saved;
Bit32u codepage_laddr;
#endif
vm_messages_t mon_msgs;
/* These fields contain info set by the host (forwarding info) */
Bit8u host_fwd_ints[BMAP_SZ(256)];
guest_cpu_state_t guest_cpu;
Bit32u mon_pde_mask; /* Upper 10 bits of monitor lin addr space */
Bit32u mon_pdi; /* Same value shifted down 22 bits. */
unsigned prescanDepth;
unsigned prescanRing3;
Bit64u vpaging_tsc; /* time stamp of last page mappings flush */
/* We need to keep track of what each of the guest's physical */
/* pages contains, and maintain some additional attributes. */
/* We determine which kinds of information reside in the page, */
/* dynamically. */
phy_page_usage_t page_usage[MON_GUEST_PAGES];
struct {
volatile unsigned event; /* Any log event occurred. */
/* Inactive, OK to dump to host and change */
volatile unsigned locked;
/* Number of times buffer wrapped since last print to kernel */
/* debug facility */
volatile unsigned offset; /* Current index within buffer */
volatile unsigned error; /* Error printing. (ex. string too long) */
} log_buffer_info;
vm_addr_t *addr;
vm_pages_t pages; /* memory pages allocated by the host */
/* Host specific fields. These fields should NOT be accessed */
/* from code which may execute in either host or monitor/guest */
/* spaces, unless you need to _specifically_ manipulate a */
/* host-specific field. */
struct {
vm_addr_t addr; /* addresses of data structures in host space */
void (*__host2mon)(void); /* Host to guest nexus entry point */
pageEntry_t nexus_pde; /* PDE pointing to nexus page table */
} host;
/* Guest specific fields. These fields should NOT be accessed */
/* from code which may execute in either host or monitor/guest */
/* spaces, unless you need to _specifically_ manipulate a */
/* guest-specific field. */
struct {
vm_addr_t addr; /* addresses of data structures in guest space */
void (*__mon2host)(void); /* monitor to host entry point */
} guest;
} vm_t;
extern char __nexus_start, __nexus_end, __mon_cs;
extern char __host2mon, __mon2host, __handle_fault, __handle_int;
extern char __ret_to_guest;
/*
* This structure describes the pages containing the code/data
* of the monitor itself (inside the kernel module)
*/
#define PLEX86_MAX_MONITOR_PAGES 52
typedef struct {
/* virtual address space occupied by the module */
Bit32u startOffset;
Bit32u startOffsetPageAligned;
/* number of pages */
unsigned n_pages;
/* the pages themselves */
Bit32u page[PLEX86_MAX_MONITOR_PAGES];
} monitor_pages_t;
extern monitor_pages_t monitor_pages;
typedef struct {
Bit32u maxval; /* maximum val to pass to CPUID instruction */
Bit8u vendorID[12+1]; /* 12 packed Vendor ID string bytes plus null */
union {
Bit32u raw;
struct {
Bit32u stepping:4;
Bit32u model:4;
Bit32u family:4;
Bit32u procType:2;
Bit32u Reserved31_14:18;
} __attribute__ ((packed)) fields;
} __attribute__ ((packed)) procSignature;
union {
Bit32u raw;
struct {
Bit32u fpu:1;
Bit32u vme:1;
Bit32u de:1;
Bit32u pse:1;
Bit32u tsc:1;
Bit32u msr:1;
Bit32u pae:1;
Bit32u mce:1;
Bit32u cx8:1;
Bit32u apic:1;
Bit32u Reserved10:1;
Bit32u sep:1;
Bit32u mtrr:1;
Bit32u pge:1;
Bit32u mca:1;
Bit32u cmov:1;
Bit32u pat:1;
Bit32u pse36:1;
Bit32u Reserved22_18:5;
Bit32u mmx:1;
Bit32u fxsr:1;
Bit32u Reserved31_25:7;
} __attribute__ ((packed)) fields;
} __attribute__ ((packed)) featureFlags;
} cpuid_info_t;
extern cpuid_info_t cpuid_info;
#if !defined(IN_HOST_SPACE) && !defined(IN_MONITOR_SPACE) && \
!defined(IN_NEXUS_SPACE) && !defined(IN_R3_SPACE)
#error "No space defined for this file"
#endif
#if defined(IN_NEXUS_SPACE) || defined(IN_MONITOR_SPACE)
void sysFlushPrintBuf(vm_t *);
#include "emulation.h"
#endif /* {NEXUS, MONITOR} */
#if defined(IN_HOST_SPACE) || defined(IN_MONITOR_SPACE) || \
defined(IN_NEXUS_SPACE)
int monprint(vm_t *, char *fmt, ...);
int mon_vsnprintf(char *str, unsigned size, const char *fmt,
va_list args);
void flushPrintBuffer(vm_t *);
void resetPrintBuf(vm_t *);
void cache_sreg(vm_t *, unsigned sreg);
void cache_selector(vm_t *, unsigned sreg);
void mon_memzero(void *ptr, int size);
void mon_memcpy(void *dst, void *src, int size);
void *mon_memset(void *s, unsigned c, unsigned n);
unsigned isV86MCompatible(vm_t *);
#define MON_BASE_FROM_LADDR(laddr) \
((laddr) - monitor_pages.startOffsetPageAligned)
void write_eflags(vm_t *, Bit32u raw, Bit32u change_mask);
Bit32u read_eflags(vm_t *);
#if 0
void dtInitialize(vm_t *vm);
void dtInitHashTables(vm_t *vm);
void dtInitG2THashTable(vm_t *vm);
unsigned isPMR3NativeCompatible(vm_t *);
#define DoZero (1<<0)
#define DontZero (0<<0)
#define AtHead (1<<1)
#define AtTail (0<<1)
Bit32u
dtTranslateG2T(vm_t *vm, Bit32u guestOff, Bit32u guestLinAddr,
Bit32u guestPhyAddr);
#endif
void initTimers(vm_t *vm);
int registerTimer(vm_t *, unsigned space, timerRegister_t *timer);
int activateTimer(vm_t *, unsigned space, timerRegister_t *timer);
int deactivateTimer(vm_t *, unsigned space, int id);
#endif /* {HOST, MONITOR, NEXUS} */
#if defined(IN_HOST_SPACE) || defined(IN_MONITOR_SPACE)
/* ============================================================
* These are the functions which are available in either of the
* host or monitor/guest spaces.
*/
/* Access to label offsets in nexus.S... From the host address perspective */
#define HOST_NEXUS_OFFSET(vm, field) \
( ((Bit32u)vm->host.addr.nexus) + \
(((Bit32u) &field) - ((Bit32u) &__nexus_start)) )
/* From the monitor/guest address perspective. */
#define MON_NEXUS_OFFSET(vm, field) \
( ((Bit32u)vm->guest.addr.nexus) + \
(((Bit32u) &field) - ((Bit32u) &__nexus_start)) )
/* Translate from guest laddr to monitor laddr */
#define Guest2Monitor(vm, laddr) ( ((Bit32u) (laddr)) - \
vm->addr->nexus->mon_base )
#define MonOff2Lin(vm, off) ( ((Bit32u) (off)) + \
vm->addr->nexus->mon_base )
#define PrescanDepthMax 5
#define PrescanDepthMin 1
#define PrescanDepthDefault PrescanDepthMin
#define ClearMonMessageQ(vm) ({ \
vm->mon_msgs.header.msg_type = VMMessageNone; \
vm->mon_msgs.header.msg_len = 0; \
})
#endif /* {HOST, MONITOR} */
#ifdef IN_HOST_SPACE
/* ==========================================================
* These are the functions which are available to the monitor
* running in the host space.
*/
/*
* Generate a software interrupt
*/
#define soft_int(n) \
asm volatile ( \
" movb %b0, __soft_int_vector \n\t" \
" jmp __soft_int_n \n\t" \
"__soft_int_n: \n\t" \
" sti \n\t" \
" .byte 0xcd \n\t" \
"__soft_int_vector: \n\t" \
" .byte 0x00 \n\t" \
: \
: "r" ((Bit8u) (n) ) \
: "memory" \
)
int initMonitor(vm_t *, Bit32u kernel_offset, unsigned reason,
guest_cpu_t *);
int setGuestCPU(vm_t *, unsigned reason,
guest_cpu_t *guest_cpu);
unsigned mapMonitor(vm_t *, Bit32u eflags, unsigned remapHints);
unsigned initGuestPhyMem(vm_t *);
void getCpuResetValues(guest_cpu_t *);
void set_guest_context(vm_t *, guest_context_t *context);
void get_guest_context(vm_t *, guest_context_t *context);
int runGuestLoop(vm_t *);
void unallocVmPages(vm_t *);
int allocVmPages(vm_t *, unsigned nmegs);
void getGuestCpuState(vm_t *, guest_cpu_t *);
void ioctlSetIntr(vm_t *, unsigned long intr);
int ioctlSetA20E(vm_t *, unsigned long val);
int ioctlMessageQ(vm_t *, vm_messages_t *user_msgs);
unsigned host_idle(void);
void *host_alloc(unsigned long size);
void host_free(void *ptr);
unsigned host_map(Bit32u *page, int max_pages, void *ptr, unsigned size);
void *host_alloc_page(void);
void host_free_page(void *ptr);
Bit32u host_map_page(void *ptr);
void hostprint(char *fmt, ...);
unsigned hostModuleInit(void);
void hostDeviceOpenInit(vm_t *);
unsigned getCpuCapabilities(void);
//void dtInitVOpcodeMaps(void);
#define vm_save_flags(x) \
asm volatile("pushfl ; popl %0": "=g" (x): :"memory")
#define vm_restore_flags(x) \
asm volatile("pushl %0 ; popfl": :"g" (x): "memory", "cc")
void init_guest_linux(vm_t *);
void init_guest_test(vm_t *);
void init_guest_normal(vm_t *);
#endif /* {HOST} */
#ifdef IN_MONITOR_SPACE
/* ==========================================================
* These are the functions which are available to the monitor
* running in the monitor/guest space.
*/
void monpanic(vm_t *, char *fmt, ...) __attribute__ ((noreturn));
void monpanic_nomess(vm_t *);
/* PC system logic */
Bit32u sysIOIn(vm_t *, Bit32u port, unsigned len);
void sysIOOut(vm_t *, Bit32u port, unsigned len, Bit32u data);
unsigned sysIOInBatch(vm_t *, Bit32u port, unsigned len, unsigned n,
Bit32u paddr);
Bit32u sysMemMapIORead(vm_t *, Bit32u addr, unsigned len);
void sysMemMapIOWrite(vm_t *, Bit32u addr, unsigned len, Bit32u data);
unsigned sysReflectInt(vm_t *, unsigned vector);
unsigned sysIAC(vm_t *);
void sysRaiseHLDA(vm_t *);
void sysEOICount(vm_t *);
void sysReqComplete(vm_t *);
void sysRemapMonitor(vm_t *);
void sysNOP(vm_t *);
void sysTimerCallback(vm_t *, void *thisPtr, void *fptr, unsigned id);
void monPageFault(vm_t *, guest_context_t *context, Bit32u cr2);
void *open_guest_phy_page(vm_t *, Bit32u ppage_index, Bit8u *mon_offset);
void close_guest_phy_page(vm_t *, Bit32u ppage_index);
/* When a guest segment register has been modified, mark that selector
* and descriptor cache values are now stored in the guest_cpu
* structure.
*/
#define monSegmentUpdated(vm, sreg) ({ \
unsigned mask = 1 << (sreg); \
(vm)->selectorInEmu |= mask; \
(vm)->descriptorInEmu |= mask; \
(vm)->segmentUpdated |= mask; \
if ((sreg) == SRegCS) \
(vm)->modeChange |= ModeChangeEventCS; \
})
#define MapLinOK 0
#define MapLinMonConflict 1
#define MapLinAlreadyMapped 2
#define MapLinPPageOOB 3
#define MapLinException 4
#define MapLinEmulate 5
unsigned map_guest_laddr(vm_t *, Bit32u guest_laddr,
Bit32u *guest_ppage_index, unsigned us,
unsigned rw, Bit32u attr, Bit32u *error);
void monPagingRemap(vm_t *);
void removePageAttributes(vm_t *, Bit32u ppi, Bit32u attr);
unsigned addPageAttributes(vm_t *, Bit32u ppi, Bit32u attr);
phy_page_usage_t *getPageUsage(vm_t *, Bit32u ppage_index);
void virtualize_lconstruct(vm_t *, Bit32u l0, Bit32u l1, unsigned perm);
void updateGuestPTbl(vm_t *, Bit32u ppi);
void updateGuestPDir(vm_t *, Bit32u ppi);
unsigned getMonPTi(vm_t *, unsigned pdi, unsigned source);
#define invlpg_mon_offset(mon_offset) \
asm volatile ("invlpg (%0)": :"r" (mon_offset): "memory")
//void dtDumpCodePage(vm_t *, Bit32u ppage_index, phy_page_usage_t *);
int handleTimers(vm_t *);
/* Eyal Lotem: Removed the old unupdated comment, and fixed this macro */
#define VM_ASSERT(vm, expression) \
if ( !(expression) ) monpanic(vm, "Assertion (%s) failed at %s:%u", #expression, __FILE__, __LINE__)
#define CLI() asm volatile ("cli": : : "memory")
#define STI() asm volatile ("sti": : : "memory")
static __inline__ Bit64u
vm_rdtsc(void) {
Bit64u ret;
asm volatile (
"rdtsc"
: "=A" (ret)
);
return ret;
}
void monModeChange(vm_t *);
extern const selector_t nullSelector;
extern const descriptor_t nullDescriptor;
#if 0
void dtFixContext(vm_t *, guest_context_t *context);
extern Bit32u
dtTranslateSequence(vm_t *vm, unsigned metaI, Bit32u guestOff,
Bit32u guestLinAddr, Bit32u monLinAddr);
extern Bit8u *
dtAddTcode(vm_t *vm, unsigned metaI, Bit8u *tcode, unsigned tcodeLen,
tcodeSnippet_t *, unsigned tcodeSnippetsN, Bit32u guestOff);
extern void *
dtAllocTcodeSpace(vm_t *vm, unsigned metaI, unsigned size, unsigned requests,
tcodeChunk_t **chunk);
extern tcodeChunk_t *
dtAllocTcodeChunk(vm_t *vm, unsigned metaI);
unsigned dtGenJcc(vm_t *, Bit8u *p, unsigned remain, instruction_t *i,
Bit32u eip);
unsigned dtGenJCXZ(vm_t *, Bit8u *p, unsigned remain, instruction_t *i,
Bit32u eip);
unsigned dtGenLoopJb(vm_t *, Bit8u *p, unsigned remain, instruction_t *i,
Bit32u eip);
void instrEmulateOpcode(vm_t *);
#endif
extern unsigned __readVirtualByteNative(unsigned sel, Bit32u off, void *data);
extern unsigned __readVirtualWordNative(unsigned sel, Bit32u off, void *data);
extern unsigned __readVirtualDWordNative(unsigned sel, Bit32u off, void *data);
extern void __readVirtualByteAttempt(void);
extern void __readVirtualByteError(void);
extern void __readVirtualWordAttempt(void);
extern void __readVirtualWordError(void);
extern void __readVirtualDWordAttempt(void);
extern void __readVirtualDWordError(void);
extern unsigned __writeVirtualByteNative(unsigned sel, Bit32u off, void *data);
extern unsigned __writeVirtualWordNative(unsigned sel, Bit32u off, void *data);
extern unsigned __writeVirtualDWordNative(unsigned sel, Bit32u off, void *data);
extern void __writeVirtualByteAttempt(void);
extern void __writeVirtualByteError(void);
extern void __writeVirtualWordAttempt(void);
extern void __writeVirtualWordError(void);
extern void __writeVirtualDWordAttempt(void);
extern void __writeVirtualDWordError(void);
#endif /* {MONITOR} */
#endif /* __MONITOR_H__ */