#include "vmevent_invalidstate.h"
#include "realmodeemu.h"
#include "pmodeemu.h"
#include "vmreadwrite.h"
#include "mm.h"
void fixInterruptabilityState(void)
{
DWORD is=vmread(vm_guest_interruptability_state);
RFLAGS guestrflags;
VMEntry_interruption_information entryinterrupt;
guestrflags.value=vmread(vm_guest_rflags);
is=is & 0x1f;
if (guestrflags.IF==0) is=is & 0x1e;
if ((is & 3)==3)
{
is=is & 0x1e; }
entryinterrupt.interruption_information=vmread(vm_entry_interruptioninfo);
if (entryinterrupt.valid)
{
if (entryinterrupt.type==0) is = is & 0x1c;
if (entryinterrupt.type==2) is = is & 0x1d;
}
vmwrite(vm_guest_interruptability_state, is);
}
int handleInvalidEntryState(pcpuinfo currentcpuinfo,VMRegisters *vmregisters)
{
sendstring("Handling invalid entry state\n\r");
fixInterruptabilityState();
if (ISREALMODE(currentcpuinfo))
{
int result;
sendstring("Inside realmode. Trying to emulate instructions\n\r");
result=emulateRealMode(currentcpuinfo, vmregisters)==0;
sendstringf("emulateRealMode(...) returned %d\n\r",result);
if (result==0)
{
sendstring("emulation was handled properly\n");
return 0; }
else
sendstring("emulation was a total failure. Not one instruction got emulated. Trying to fix the state");
if (ISREALMODE(currentcpuinfo)) {
Access_Rights reg_rmaccessrights,reg_traccessrights;
RFLAGS guestrflags;
DWORD gdtbase, idtbase;
guestrflags.value=0;
gdtbase=VirtualToPhysical(getGDTbase());
idtbase=VirtualToPhysical((UINT64)idttable32);
sendstring("Still in realmode, enabling VMx86 mode if not already in it and fixing possible other bugs\n\r");
vmwrite(vm_guest_gdtr_base, gdtbase);
vmwrite(vm_guest_gdt_limit, getGDTsize());
vmwrite(vm_guest_idtr_base, idtbase);
vmwrite(vm_guest_idt_limit, 256*8);
setupTSS8086();
vmwrite(vm_guest_tr_base,(UINT64)VirtualToPhysical((UINT64)VirtualMachineTSS_V8086)); vmwrite(vm_guest_tr_limit,(ULONG)sizeof(TSS)+32+8192+1); vmwrite(vm_guest_tr,64);
#ifdef DEBUG
UINT64 idtbase2, gdtbase2;
gdtbase2=vmread(vm_guest_gdtr_base);
idtbase2=vmread(vm_guest_idtr_base);
sendstringf("Set vm_guest_gdtr_base to %6 while I wanted to set it to %6\n\r",gdtbase2, gdtbase);
sendstringf("Set vm_guest_idtr_base to %6 while I wanted to set it to %6\n\r",idtbase2, idtbase);
#endif
reg_rmaccessrights.AccessRights=0;
reg_rmaccessrights.Segment_type=3;
reg_rmaccessrights.S=1;
reg_rmaccessrights.DPL=3;
reg_rmaccessrights.P=1;
reg_rmaccessrights.G=0;
reg_rmaccessrights.D_B=0;
reg_traccessrights.AccessRights=0;
reg_traccessrights.Segment_type=11; reg_traccessrights.S=0;
reg_traccessrights.DPL=0;
reg_traccessrights.P=1;
reg_traccessrights.G=0;
reg_traccessrights.D_B=1;
vmwrite(vm_guest_es_access_rights,(ULONG)reg_rmaccessrights.AccessRights); vmwrite(vm_guest_cs_access_rights,(ULONG)reg_rmaccessrights.AccessRights); vmwrite(vm_guest_ss_access_rights,(ULONG)reg_rmaccessrights.AccessRights); vmwrite(vm_guest_ds_access_rights,(ULONG)reg_rmaccessrights.AccessRights); vmwrite(vm_guest_fs_access_rights,(ULONG)reg_rmaccessrights.AccessRights); vmwrite(vm_guest_gs_access_rights,(ULONG)reg_rmaccessrights.AccessRights); vmwrite(vm_guest_ldtr_access_rights,(ULONG)(1<<16)); vmwrite(vm_guest_tr_access_rights,(ULONG)reg_traccessrights.AccessRights);
vmwrite(vm_guest_es,(ULONG)vmread(vm_guest_es_base) >> 4); vmwrite(vm_guest_cs,(ULONG)vmread(vm_guest_cs_base) >> 4); vmwrite(vm_guest_ss,(ULONG)vmread(vm_guest_ss_base) >> 4); vmwrite(vm_guest_ds,(ULONG)vmread(vm_guest_ds_base) >> 4); vmwrite(vm_guest_fs,(ULONG)vmread(vm_guest_fs_base) >> 4); vmwrite(vm_guest_gs,(ULONG)vmread(vm_guest_gs_base) >> 4); vmwrite(vm_guest_ldtr,(ULONG)0); vmwrite(vm_guest_tr,(ULONG)0);
vmwrite(vm_guest_es_limit,(ULONG)0xffff); vmwrite(vm_guest_cs_limit,(ULONG)0xffff); vmwrite(vm_guest_ss_limit,(ULONG)0xffff); vmwrite(vm_guest_ds_limit,(ULONG)0xffff); vmwrite(vm_guest_fs_limit,(ULONG)0xffff); vmwrite(vm_guest_gs_limit,(ULONG)0xffff);
guestrflags.value=vmread(vm_guest_rflags);
guestrflags.IOPL=3;
guestrflags.VM=1;
vmwrite(vm_guest_rflags,guestrflags.value);
return 0;
}
}
else
{
WORD segment,segment2;
Access_Rights tempAR;
int handled=0;
sendstring("Not in realmode and in an invalid entry state\n");
sendstring("Emulating instruction\n");
handled=emulateProtectedMode(currentcpuinfo, vmregisters);
if (handled)
return 0;
sendstring("Emulation failed, trying to force state to be valid\n");
tempAR.AccessRights=vmread(vm_guest_cs_access_rights);
if ((tempAR.Segment_type & 1)==0)
{
sendstringf("Code segment was usable but not accessed (Let me guess, it's Bochs?)\n");
tempAR.Segment_type=tempAR.Segment_type | 1;
vmwrite(vm_guest_cs_access_rights, tempAR.AccessRights);
handled=1;
}
tempAR.AccessRights=vmread(vm_guest_ds_access_rights);
if ((tempAR.unusable==0) && ((tempAR.Segment_type & 1)==0))
{
sendstringf("DS segment was usable but not accessed\n");
tempAR.Segment_type=tempAR.Segment_type | 1;
vmwrite(vm_guest_ds_access_rights, tempAR.AccessRights);
handled=1;
}
tempAR.AccessRights=vmread(vm_guest_es_access_rights);
if ((tempAR.unusable==0) && ((tempAR.Segment_type & 1)==0))
{
sendstringf("ES segment was usable but not accessed\n");
tempAR.Segment_type=tempAR.Segment_type | 1;
vmwrite(vm_guest_es_access_rights, tempAR.AccessRights);
handled=1;
}
tempAR.AccessRights=vmread(vm_guest_fs_access_rights);
if ((tempAR.unusable==0) && ((tempAR.Segment_type & 1)==0))
{
sendstringf("FS segment was usable but not accessed\n");
tempAR.Segment_type=tempAR.Segment_type | 1;
vmwrite(vm_guest_fs_access_rights, tempAR.AccessRights);
handled=1;
}
tempAR.AccessRights=vmread(vm_guest_gs_access_rights);
if ((tempAR.unusable==0) && ((tempAR.Segment_type & 1)==0))
{
sendstringf("GS segment was usable but not accessed\n");
tempAR.Segment_type=tempAR.Segment_type | 1;
vmwrite(vm_guest_gs_access_rights, tempAR.AccessRights);
handled=1;
}
segment=vmread(vm_guest_ss);
segment2=vmread(vm_guest_cs);
if ((segment & 3) != (segment2 & 3))
{
sendstringf("SS(%x).rpl != CS(%x).rpl\n",segment,segment2);
segment=(segment & 0xfffc) | (segment2 & 3);
sendstringf("Setting SS to %x\n",segment);
vmwrite(vm_guest_ss, segment);
tempAR.AccessRights=vmread(vm_guest_ss_access_rights);
tempAR.DPL=(segment & 3);
vmwrite(vm_guest_ss_access_rights, tempAR.AccessRights);
handled=1;
}
if (handled==1)
{
UINT64 rflags=vmread(vm_guest_rflags);
PRFLAGS prflags=(PRFLAGS)&rflags;
prflags->RF=1;
vmwrite(vm_guest_rflags,rflags);
}
return (handled==0);
}
return 0;
}