1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
|
/*
* plex86: run multiple x86 operating systems concurrently
* Copyright (C) 1999-2001 Kevin P. Lawton
*
* ctrl_xfer_pro.c: protected mode control transfer mechanisms
*
* 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"
#include "monitor.h"
void
stack_return_to_v86(vm_t *vm, Bit32u new_eip, selector_t cs_selector,
Bit32u flags32)
{
Bit32u temp_ESP, new_esp, esp_laddr, changeMask;
selector_t es_selector, ds_selector, fs_selector,
gs_selector, ss_selector;
unsigned sreg;
cache_sreg(vm, SRegSS);
/* Must be 32bit effective opsize, VM is in upper 16bits of eFLAGS
* CPL = 0 to get here
*
* ----------------
* | | OLD GS | eSP+32
* | | OLD FS | eSP+28
* | | OLD DS | eSP+24
* | | OLD ES | eSP+20
* | | OLD SS | eSP+16
* | OLD ESP | eSP+12
* | OLD EFLAGS | eSP+8
* | | OLD CS | eSP+4
* | OLD EIP | eSP+0
* ----------------
*/
if (vm->guest_cpu.desc_cache[SRegSS].desc.d_b)
temp_ESP = G_ESP(vm);
else
temp_ESP = G_SP(vm);
/* top 36 bytes of stack must be within stack limits, else #GP(0) */
if ( !can_pop(vm, 36) ) {
monpanic(vm, "iret: VM: top 36 bytes not within limits\n");
exception(vm, ExceptionSS, 0);
}
if ( new_eip & 0xffff0000 ) {
monprint(vm, "IRET to V86-mode: ignoring upper 16-bits\n");
new_eip = new_eip & 0xffff;
}
esp_laddr = vm->guest_cpu.desc_cache[SRegSS].base + temp_ESP;
/* load SS:ESP from stack */
access_linear(vm, esp_laddr + 12, 4, 0, OP_READ, &new_esp);
access_linear(vm, esp_laddr + 16, 2, 0, OP_READ, &ss_selector.raw);
/* load ES,DS,FS,GS from stack */
access_linear(vm, esp_laddr + 20, 2, 0, OP_READ, &es_selector.raw);
access_linear(vm, esp_laddr + 24, 2, 0, OP_READ, &ds_selector.raw);
access_linear(vm, esp_laddr + 28, 2, 0, OP_READ, &fs_selector.raw);
access_linear(vm, esp_laddr + 32, 2, 0, OP_READ, &gs_selector.raw);
/* always modify: ID,AC,VM,RF,NT,IOPL,OF,DF,IF,TF,SF,ZF,AF,PF,CF */
/* unmodified: (VIP,VIF) */
changeMask = 0x00277fd5;
write_eflags(vm, flags32, changeMask);
/* load CS:EIP from stack; already read and passed as args */
vm->guest_cpu.selector[SRegES] = es_selector;
vm->guest_cpu.selector[SRegCS] = cs_selector;
vm->guest_cpu.selector[SRegSS] = ss_selector;
vm->guest_cpu.selector[SRegDS] = ds_selector;
vm->guest_cpu.selector[SRegFS] = fs_selector;
vm->guest_cpu.selector[SRegGS] = gs_selector;
G_EIP(vm) = new_eip;
G_ESP(vm) = new_esp; /* Full 32bits are loaded. */
for (sreg=0; sreg<6; sreg++) {
load_seg_reg(vm, sreg, vm->guest_cpu.selector[sreg].raw);
}
}
void
stack_return_from_v86(vm_t *vm)
{
exception(vm, ExceptionGP, 0);
}
|