1*996feed4SSergio Andres Gomez Del Real // This software is licensed under the terms of the GNU General Public 2*996feed4SSergio Andres Gomez Del Real // License version 2, as published by the Free Software Foundation, and 3*996feed4SSergio Andres Gomez Del Real // may be copied, distributed, and modified under those terms. 4*996feed4SSergio Andres Gomez Del Real // 5*996feed4SSergio Andres Gomez Del Real // This program is distributed in the hope that it will be useful, 6*996feed4SSergio Andres Gomez Del Real // but WITHOUT ANY WARRANTY; without even the implied warranty of 7*996feed4SSergio Andres Gomez Del Real // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 8*996feed4SSergio Andres Gomez Del Real // GNU General Public License for more details. 9*996feed4SSergio Andres Gomez Del Real #include "qemu/osdep.h" 10*996feed4SSergio Andres Gomez Del Real #include "qemu-common.h" 11*996feed4SSergio Andres Gomez Del Real #include "qemu/error-report.h" 12*996feed4SSergio Andres Gomez Del Real 13*996feed4SSergio Andres Gomez Del Real #include "sysemu/hvf.h" 14*996feed4SSergio Andres Gomez Del Real #include "hvf-i386.h" 15*996feed4SSergio Andres Gomez Del Real #include "hvf-utils/vmcs.h" 16*996feed4SSergio Andres Gomez Del Real #include "hvf-utils/vmx.h" 17*996feed4SSergio Andres Gomez Del Real #include "hvf-utils/x86.h" 18*996feed4SSergio Andres Gomez Del Real #include "hvf-utils/x86_descr.h" 19*996feed4SSergio Andres Gomez Del Real #include "hvf-utils/x86_mmu.h" 20*996feed4SSergio Andres Gomez Del Real #include "hvf-utils/x86_decode.h" 21*996feed4SSergio Andres Gomez Del Real #include "hvf-utils/x86_emu.h" 22*996feed4SSergio Andres Gomez Del Real #include "hvf-utils/x86_task.h" 23*996feed4SSergio Andres Gomez Del Real #include "hvf-utils/x86hvf.h" 24*996feed4SSergio Andres Gomez Del Real 25*996feed4SSergio Andres Gomez Del Real #include <Hypervisor/hv.h> 26*996feed4SSergio Andres Gomez Del Real #include <Hypervisor/hv_vmx.h> 27*996feed4SSergio Andres Gomez Del Real 28*996feed4SSergio Andres Gomez Del Real #include "exec/address-spaces.h" 29*996feed4SSergio Andres Gomez Del Real #include "exec/exec-all.h" 30*996feed4SSergio Andres Gomez Del Real #include "exec/ioport.h" 31*996feed4SSergio Andres Gomez Del Real #include "hw/i386/apic_internal.h" 32*996feed4SSergio Andres Gomez Del Real #include "hw/boards.h" 33*996feed4SSergio Andres Gomez Del Real #include "qemu/main-loop.h" 34*996feed4SSergio Andres Gomez Del Real #include "strings.h" 35*996feed4SSergio Andres Gomez Del Real #include "sysemu/accel.h" 36*996feed4SSergio Andres Gomez Del Real #include "sysemu/sysemu.h" 37*996feed4SSergio Andres Gomez Del Real #include "target/i386/cpu.h" 38*996feed4SSergio Andres Gomez Del Real 39*996feed4SSergio Andres Gomez Del Real // TODO: taskswitch handling 40*996feed4SSergio Andres Gomez Del Real static void save_state_to_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) 41*996feed4SSergio Andres Gomez Del Real { 42*996feed4SSergio Andres Gomez Del Real X86CPU *x86_cpu = X86_CPU(cpu); 43*996feed4SSergio Andres Gomez Del Real CPUX86State *env = &x86_cpu->env; 44*996feed4SSergio Andres Gomez Del Real 45*996feed4SSergio Andres Gomez Del Real /* CR3 and ldt selector are not saved intentionally */ 46*996feed4SSergio Andres Gomez Del Real tss->eip = EIP(env); 47*996feed4SSergio Andres Gomez Del Real tss->eflags = EFLAGS(env); 48*996feed4SSergio Andres Gomez Del Real tss->eax = EAX(env); 49*996feed4SSergio Andres Gomez Del Real tss->ecx = ECX(env); 50*996feed4SSergio Andres Gomez Del Real tss->edx = EDX(env); 51*996feed4SSergio Andres Gomez Del Real tss->ebx = EBX(env); 52*996feed4SSergio Andres Gomez Del Real tss->esp = ESP(env); 53*996feed4SSergio Andres Gomez Del Real tss->ebp = EBP(env); 54*996feed4SSergio Andres Gomez Del Real tss->esi = ESI(env); 55*996feed4SSergio Andres Gomez Del Real tss->edi = EDI(env); 56*996feed4SSergio Andres Gomez Del Real 57*996feed4SSergio Andres Gomez Del Real tss->es = vmx_read_segment_selector(cpu, REG_SEG_ES).sel; 58*996feed4SSergio Andres Gomez Del Real tss->cs = vmx_read_segment_selector(cpu, REG_SEG_CS).sel; 59*996feed4SSergio Andres Gomez Del Real tss->ss = vmx_read_segment_selector(cpu, REG_SEG_SS).sel; 60*996feed4SSergio Andres Gomez Del Real tss->ds = vmx_read_segment_selector(cpu, REG_SEG_DS).sel; 61*996feed4SSergio Andres Gomez Del Real tss->fs = vmx_read_segment_selector(cpu, REG_SEG_FS).sel; 62*996feed4SSergio Andres Gomez Del Real tss->gs = vmx_read_segment_selector(cpu, REG_SEG_GS).sel; 63*996feed4SSergio Andres Gomez Del Real } 64*996feed4SSergio Andres Gomez Del Real 65*996feed4SSergio Andres Gomez Del Real static void load_state_from_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) 66*996feed4SSergio Andres Gomez Del Real { 67*996feed4SSergio Andres Gomez Del Real X86CPU *x86_cpu = X86_CPU(cpu); 68*996feed4SSergio Andres Gomez Del Real CPUX86State *env = &x86_cpu->env; 69*996feed4SSergio Andres Gomez Del Real 70*996feed4SSergio Andres Gomez Del Real wvmcs(cpu->hvf_fd, VMCS_GUEST_CR3, tss->cr3); 71*996feed4SSergio Andres Gomez Del Real 72*996feed4SSergio Andres Gomez Del Real RIP(env) = tss->eip; 73*996feed4SSergio Andres Gomez Del Real EFLAGS(env) = tss->eflags | 2; 74*996feed4SSergio Andres Gomez Del Real 75*996feed4SSergio Andres Gomez Del Real /* General purpose registers */ 76*996feed4SSergio Andres Gomez Del Real RAX(env) = tss->eax; 77*996feed4SSergio Andres Gomez Del Real RCX(env) = tss->ecx; 78*996feed4SSergio Andres Gomez Del Real RDX(env) = tss->edx; 79*996feed4SSergio Andres Gomez Del Real RBX(env) = tss->ebx; 80*996feed4SSergio Andres Gomez Del Real RSP(env) = tss->esp; 81*996feed4SSergio Andres Gomez Del Real RBP(env) = tss->ebp; 82*996feed4SSergio Andres Gomez Del Real RSI(env) = tss->esi; 83*996feed4SSergio Andres Gomez Del Real RDI(env) = tss->edi; 84*996feed4SSergio Andres Gomez Del Real 85*996feed4SSergio Andres Gomez Del Real vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ldt}}, REG_SEG_LDTR); 86*996feed4SSergio Andres Gomez Del Real vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->es}}, REG_SEG_ES); 87*996feed4SSergio Andres Gomez Del Real vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->cs}}, REG_SEG_CS); 88*996feed4SSergio Andres Gomez Del Real vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ss}}, REG_SEG_SS); 89*996feed4SSergio Andres Gomez Del Real vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ds}}, REG_SEG_DS); 90*996feed4SSergio Andres Gomez Del Real vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->fs}}, REG_SEG_FS); 91*996feed4SSergio Andres Gomez Del Real vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->gs}}, REG_SEG_GS); 92*996feed4SSergio Andres Gomez Del Real 93*996feed4SSergio Andres Gomez Del Real #if 0 94*996feed4SSergio Andres Gomez Del Real load_segment(cpu, REG_SEG_LDTR, tss->ldt); 95*996feed4SSergio Andres Gomez Del Real load_segment(cpu, REG_SEG_ES, tss->es); 96*996feed4SSergio Andres Gomez Del Real load_segment(cpu, REG_SEG_CS, tss->cs); 97*996feed4SSergio Andres Gomez Del Real load_segment(cpu, REG_SEG_SS, tss->ss); 98*996feed4SSergio Andres Gomez Del Real load_segment(cpu, REG_SEG_DS, tss->ds); 99*996feed4SSergio Andres Gomez Del Real load_segment(cpu, REG_SEG_FS, tss->fs); 100*996feed4SSergio Andres Gomez Del Real load_segment(cpu, REG_SEG_GS, tss->gs); 101*996feed4SSergio Andres Gomez Del Real #endif 102*996feed4SSergio Andres Gomez Del Real } 103*996feed4SSergio Andres Gomez Del Real 104*996feed4SSergio Andres Gomez Del Real static int task_switch_32(CPUState *cpu, x68_segment_selector tss_sel, x68_segment_selector old_tss_sel, 105*996feed4SSergio Andres Gomez Del Real uint64_t old_tss_base, struct x86_segment_descriptor *new_desc) 106*996feed4SSergio Andres Gomez Del Real { 107*996feed4SSergio Andres Gomez Del Real struct x86_tss_segment32 tss_seg; 108*996feed4SSergio Andres Gomez Del Real uint32_t new_tss_base = x86_segment_base(new_desc); 109*996feed4SSergio Andres Gomez Del Real uint32_t eip_offset = offsetof(struct x86_tss_segment32, eip); 110*996feed4SSergio Andres Gomez Del Real uint32_t ldt_sel_offset = offsetof(struct x86_tss_segment32, ldt); 111*996feed4SSergio Andres Gomez Del Real 112*996feed4SSergio Andres Gomez Del Real vmx_read_mem(cpu, &tss_seg, old_tss_base, sizeof(tss_seg)); 113*996feed4SSergio Andres Gomez Del Real save_state_to_tss32(cpu, &tss_seg); 114*996feed4SSergio Andres Gomez Del Real 115*996feed4SSergio Andres Gomez Del Real vmx_write_mem(cpu, old_tss_base + eip_offset, &tss_seg.eip, ldt_sel_offset - eip_offset); 116*996feed4SSergio Andres Gomez Del Real vmx_read_mem(cpu, &tss_seg, new_tss_base, sizeof(tss_seg)); 117*996feed4SSergio Andres Gomez Del Real 118*996feed4SSergio Andres Gomez Del Real if (old_tss_sel.sel != 0xffff) { 119*996feed4SSergio Andres Gomez Del Real tss_seg.prev_tss = old_tss_sel.sel; 120*996feed4SSergio Andres Gomez Del Real 121*996feed4SSergio Andres Gomez Del Real vmx_write_mem(cpu, new_tss_base, &tss_seg.prev_tss, sizeof(tss_seg.prev_tss)); 122*996feed4SSergio Andres Gomez Del Real } 123*996feed4SSergio Andres Gomez Del Real load_state_from_tss32(cpu, &tss_seg); 124*996feed4SSergio Andres Gomez Del Real return 0; 125*996feed4SSergio Andres Gomez Del Real } 126*996feed4SSergio Andres Gomez Del Real 127*996feed4SSergio Andres Gomez Del Real void vmx_handle_task_switch(CPUState *cpu, x68_segment_selector tss_sel, int reason, bool gate_valid, uint8_t gate, uint64_t gate_type) 128*996feed4SSergio Andres Gomez Del Real { 129*996feed4SSergio Andres Gomez Del Real uint64_t rip = rreg(cpu->hvf_fd, HV_X86_RIP); 130*996feed4SSergio Andres Gomez Del Real if (!gate_valid || (gate_type != VMCS_INTR_T_HWEXCEPTION && 131*996feed4SSergio Andres Gomez Del Real gate_type != VMCS_INTR_T_HWINTR && 132*996feed4SSergio Andres Gomez Del Real gate_type != VMCS_INTR_T_NMI)) { 133*996feed4SSergio Andres Gomez Del Real int ins_len = rvmcs(cpu->hvf_fd, VMCS_EXIT_INSTRUCTION_LENGTH); 134*996feed4SSergio Andres Gomez Del Real macvm_set_rip(cpu, rip + ins_len); 135*996feed4SSergio Andres Gomez Del Real return; 136*996feed4SSergio Andres Gomez Del Real } 137*996feed4SSergio Andres Gomez Del Real 138*996feed4SSergio Andres Gomez Del Real load_regs(cpu); 139*996feed4SSergio Andres Gomez Del Real 140*996feed4SSergio Andres Gomez Del Real struct x86_segment_descriptor curr_tss_desc, next_tss_desc; 141*996feed4SSergio Andres Gomez Del Real int ret; 142*996feed4SSergio Andres Gomez Del Real x68_segment_selector old_tss_sel = vmx_read_segment_selector(cpu, REG_SEG_TR); 143*996feed4SSergio Andres Gomez Del Real uint64_t old_tss_base = vmx_read_segment_base(cpu, REG_SEG_TR); 144*996feed4SSergio Andres Gomez Del Real uint32_t desc_limit; 145*996feed4SSergio Andres Gomez Del Real struct x86_call_gate task_gate_desc; 146*996feed4SSergio Andres Gomez Del Real struct vmx_segment vmx_seg; 147*996feed4SSergio Andres Gomez Del Real 148*996feed4SSergio Andres Gomez Del Real X86CPU *x86_cpu = X86_CPU(cpu); 149*996feed4SSergio Andres Gomez Del Real CPUX86State *env = &x86_cpu->env; 150*996feed4SSergio Andres Gomez Del Real 151*996feed4SSergio Andres Gomez Del Real x86_read_segment_descriptor(cpu, &next_tss_desc, tss_sel); 152*996feed4SSergio Andres Gomez Del Real x86_read_segment_descriptor(cpu, &curr_tss_desc, old_tss_sel); 153*996feed4SSergio Andres Gomez Del Real 154*996feed4SSergio Andres Gomez Del Real if (reason == TSR_IDT_GATE && gate_valid) { 155*996feed4SSergio Andres Gomez Del Real int dpl; 156*996feed4SSergio Andres Gomez Del Real 157*996feed4SSergio Andres Gomez Del Real ret = x86_read_call_gate(cpu, &task_gate_desc, gate); 158*996feed4SSergio Andres Gomez Del Real 159*996feed4SSergio Andres Gomez Del Real dpl = task_gate_desc.dpl; 160*996feed4SSergio Andres Gomez Del Real x68_segment_selector cs = vmx_read_segment_selector(cpu, REG_SEG_CS); 161*996feed4SSergio Andres Gomez Del Real if (tss_sel.rpl > dpl || cs.rpl > dpl) 162*996feed4SSergio Andres Gomez Del Real ;//DPRINTF("emulate_gp"); 163*996feed4SSergio Andres Gomez Del Real } 164*996feed4SSergio Andres Gomez Del Real 165*996feed4SSergio Andres Gomez Del Real desc_limit = x86_segment_limit(&next_tss_desc); 166*996feed4SSergio Andres Gomez Del Real if (!next_tss_desc.p || ((desc_limit < 0x67 && (next_tss_desc.type & 8)) || desc_limit < 0x2b)) { 167*996feed4SSergio Andres Gomez Del Real VM_PANIC("emulate_ts"); 168*996feed4SSergio Andres Gomez Del Real } 169*996feed4SSergio Andres Gomez Del Real 170*996feed4SSergio Andres Gomez Del Real if (reason == TSR_IRET || reason == TSR_JMP) { 171*996feed4SSergio Andres Gomez Del Real curr_tss_desc.type &= ~(1 << 1); /* clear busy flag */ 172*996feed4SSergio Andres Gomez Del Real x86_write_segment_descriptor(cpu, &curr_tss_desc, old_tss_sel); 173*996feed4SSergio Andres Gomez Del Real } 174*996feed4SSergio Andres Gomez Del Real 175*996feed4SSergio Andres Gomez Del Real if (reason == TSR_IRET) 176*996feed4SSergio Andres Gomez Del Real EFLAGS(env) &= ~RFLAGS_NT; 177*996feed4SSergio Andres Gomez Del Real 178*996feed4SSergio Andres Gomez Del Real if (reason != TSR_CALL && reason != TSR_IDT_GATE) 179*996feed4SSergio Andres Gomez Del Real old_tss_sel.sel = 0xffff; 180*996feed4SSergio Andres Gomez Del Real 181*996feed4SSergio Andres Gomez Del Real if (reason != TSR_IRET) { 182*996feed4SSergio Andres Gomez Del Real next_tss_desc.type |= (1 << 1); /* set busy flag */ 183*996feed4SSergio Andres Gomez Del Real x86_write_segment_descriptor(cpu, &next_tss_desc, tss_sel); 184*996feed4SSergio Andres Gomez Del Real } 185*996feed4SSergio Andres Gomez Del Real 186*996feed4SSergio Andres Gomez Del Real if (next_tss_desc.type & 8) 187*996feed4SSergio Andres Gomez Del Real ret = task_switch_32(cpu, tss_sel, old_tss_sel, old_tss_base, &next_tss_desc); 188*996feed4SSergio Andres Gomez Del Real else 189*996feed4SSergio Andres Gomez Del Real //ret = task_switch_16(cpu, tss_sel, old_tss_sel, old_tss_base, &next_tss_desc); 190*996feed4SSergio Andres Gomez Del Real VM_PANIC("task_switch_16"); 191*996feed4SSergio Andres Gomez Del Real 192*996feed4SSergio Andres Gomez Del Real macvm_set_cr0(cpu->hvf_fd, rvmcs(cpu->hvf_fd, VMCS_GUEST_CR0) | CR0_TS); 193*996feed4SSergio Andres Gomez Del Real x86_segment_descriptor_to_vmx(cpu, tss_sel, &next_tss_desc, &vmx_seg); 194*996feed4SSergio Andres Gomez Del Real vmx_write_segment_descriptor(cpu, &vmx_seg, REG_SEG_TR); 195*996feed4SSergio Andres Gomez Del Real 196*996feed4SSergio Andres Gomez Del Real store_regs(cpu); 197*996feed4SSergio Andres Gomez Del Real 198*996feed4SSergio Andres Gomez Del Real hv_vcpu_invalidate_tlb(cpu->hvf_fd); 199*996feed4SSergio Andres Gomez Del Real hv_vcpu_flush(cpu->hvf_fd); 200*996feed4SSergio Andres Gomez Del Real } 201