1996feed4SSergio Andres Gomez Del Real // This software is licensed under the terms of the GNU General Public 2996feed4SSergio Andres Gomez Del Real // License version 2, as published by the Free Software Foundation, and 3996feed4SSergio Andres Gomez Del Real // may be copied, distributed, and modified under those terms. 4996feed4SSergio Andres Gomez Del Real // 5996feed4SSergio Andres Gomez Del Real // This program is distributed in the hope that it will be useful, 6996feed4SSergio Andres Gomez Del Real // but WITHOUT ANY WARRANTY; without even the implied warranty of 7996feed4SSergio Andres Gomez Del Real // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 8996feed4SSergio Andres Gomez Del Real // GNU General Public License for more details. 9996feed4SSergio Andres Gomez Del Real #include "qemu/osdep.h" 10895f9fdfSPaolo Bonzini #include "panic.h" 11996feed4SSergio Andres Gomez Del Real #include "qemu/error-report.h" 12996feed4SSergio Andres Gomez Del Real 1332cad1ffSPhilippe Mathieu-Daudé #include "system/hvf.h" 14996feed4SSergio Andres Gomez Del Real #include "hvf-i386.h" 1569e0a03cSPaolo Bonzini #include "vmcs.h" 1669e0a03cSPaolo Bonzini #include "vmx.h" 1769e0a03cSPaolo Bonzini #include "x86.h" 1869e0a03cSPaolo Bonzini #include "x86_descr.h" 1969e0a03cSPaolo Bonzini #include "x86_mmu.h" 2069e0a03cSPaolo Bonzini #include "x86_decode.h" 2169e0a03cSPaolo Bonzini #include "x86_emu.h" 2269e0a03cSPaolo Bonzini #include "x86_task.h" 2369e0a03cSPaolo Bonzini #include "x86hvf.h" 24996feed4SSergio Andres Gomez Del Real 25996feed4SSergio Andres Gomez Del Real #include <Hypervisor/hv.h> 26996feed4SSergio Andres Gomez Del Real #include <Hypervisor/hv_vmx.h> 27996feed4SSergio Andres Gomez Del Real 28996feed4SSergio Andres Gomez Del Real #include "hw/i386/apic_internal.h" 29996feed4SSergio Andres Gomez Del Real #include "qemu/main-loop.h" 30940e43aaSClaudio Fontana #include "qemu/accel.h" 31996feed4SSergio Andres Gomez Del Real #include "target/i386/cpu.h" 32996feed4SSergio Andres Gomez Del Real 33996feed4SSergio Andres Gomez Del Real // TODO: taskswitch handling 34996feed4SSergio Andres Gomez Del Real static void save_state_to_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) 35996feed4SSergio Andres Gomez Del Real { 36996feed4SSergio Andres Gomez Del Real X86CPU *x86_cpu = X86_CPU(cpu); 37996feed4SSergio Andres Gomez Del Real CPUX86State *env = &x86_cpu->env; 38996feed4SSergio Andres Gomez Del Real 39996feed4SSergio Andres Gomez Del Real /* CR3 and ldt selector are not saved intentionally */ 405d32173fSRoman Bolshakov tss->eip = (uint32_t)env->eip; 41967f4da2SRoman Bolshakov tss->eflags = (uint32_t)env->eflags; 42996feed4SSergio Andres Gomez Del Real tss->eax = EAX(env); 43996feed4SSergio Andres Gomez Del Real tss->ecx = ECX(env); 44996feed4SSergio Andres Gomez Del Real tss->edx = EDX(env); 45996feed4SSergio Andres Gomez Del Real tss->ebx = EBX(env); 46996feed4SSergio Andres Gomez Del Real tss->esp = ESP(env); 47996feed4SSergio Andres Gomez Del Real tss->ebp = EBP(env); 48996feed4SSergio Andres Gomez Del Real tss->esi = ESI(env); 49996feed4SSergio Andres Gomez Del Real tss->edi = EDI(env); 50996feed4SSergio Andres Gomez Del Real 516701d81dSPaolo Bonzini tss->es = vmx_read_segment_selector(cpu, R_ES).sel; 526701d81dSPaolo Bonzini tss->cs = vmx_read_segment_selector(cpu, R_CS).sel; 536701d81dSPaolo Bonzini tss->ss = vmx_read_segment_selector(cpu, R_SS).sel; 546701d81dSPaolo Bonzini tss->ds = vmx_read_segment_selector(cpu, R_DS).sel; 556701d81dSPaolo Bonzini tss->fs = vmx_read_segment_selector(cpu, R_FS).sel; 566701d81dSPaolo Bonzini tss->gs = vmx_read_segment_selector(cpu, R_GS).sel; 57996feed4SSergio Andres Gomez Del Real } 58996feed4SSergio Andres Gomez Del Real 59996feed4SSergio Andres Gomez Del Real static void load_state_from_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) 60996feed4SSergio Andres Gomez Del Real { 61996feed4SSergio Andres Gomez Del Real X86CPU *x86_cpu = X86_CPU(cpu); 62996feed4SSergio Andres Gomez Del Real CPUX86State *env = &x86_cpu->env; 63996feed4SSergio Andres Gomez Del Real 643b295bcbSPhilippe Mathieu-Daudé wvmcs(cpu->accel->fd, VMCS_GUEST_CR3, tss->cr3); 65996feed4SSergio Andres Gomez Del Real 665d32173fSRoman Bolshakov env->eip = tss->eip; 67967f4da2SRoman Bolshakov env->eflags = tss->eflags | 2; 68996feed4SSergio Andres Gomez Del Real 69996feed4SSergio Andres Gomez Del Real /* General purpose registers */ 70996feed4SSergio Andres Gomez Del Real RAX(env) = tss->eax; 71996feed4SSergio Andres Gomez Del Real RCX(env) = tss->ecx; 72996feed4SSergio Andres Gomez Del Real RDX(env) = tss->edx; 73996feed4SSergio Andres Gomez Del Real RBX(env) = tss->ebx; 74996feed4SSergio Andres Gomez Del Real RSP(env) = tss->esp; 75996feed4SSergio Andres Gomez Del Real RBP(env) = tss->ebp; 76996feed4SSergio Andres Gomez Del Real RSI(env) = tss->esi; 77996feed4SSergio Andres Gomez Del Real RDI(env) = tss->edi; 78996feed4SSergio Andres Gomez Del Real 7925409172SWei Liu vmx_write_segment_selector(cpu, (x86_segment_selector){{tss->ldt}}, R_LDTR); 8025409172SWei Liu vmx_write_segment_selector(cpu, (x86_segment_selector){{tss->es}}, R_ES); 8125409172SWei Liu vmx_write_segment_selector(cpu, (x86_segment_selector){{tss->cs}}, R_CS); 8225409172SWei Liu vmx_write_segment_selector(cpu, (x86_segment_selector){{tss->ss}}, R_SS); 8325409172SWei Liu vmx_write_segment_selector(cpu, (x86_segment_selector){{tss->ds}}, R_DS); 8425409172SWei Liu vmx_write_segment_selector(cpu, (x86_segment_selector){{tss->fs}}, R_FS); 8525409172SWei Liu vmx_write_segment_selector(cpu, (x86_segment_selector){{tss->gs}}, R_GS); 86996feed4SSergio Andres Gomez Del Real } 87996feed4SSergio Andres Gomez Del Real 8825409172SWei Liu static int task_switch_32(CPUState *cpu, x86_segment_selector tss_sel, x86_segment_selector old_tss_sel, 89996feed4SSergio Andres Gomez Del Real uint64_t old_tss_base, struct x86_segment_descriptor *new_desc) 90996feed4SSergio Andres Gomez Del Real { 91996feed4SSergio Andres Gomez Del Real struct x86_tss_segment32 tss_seg; 92996feed4SSergio Andres Gomez Del Real uint32_t new_tss_base = x86_segment_base(new_desc); 93996feed4SSergio Andres Gomez Del Real uint32_t eip_offset = offsetof(struct x86_tss_segment32, eip); 94996feed4SSergio Andres Gomez Del Real uint32_t ldt_sel_offset = offsetof(struct x86_tss_segment32, ldt); 95996feed4SSergio Andres Gomez Del Real 96996feed4SSergio Andres Gomez Del Real vmx_read_mem(cpu, &tss_seg, old_tss_base, sizeof(tss_seg)); 97996feed4SSergio Andres Gomez Del Real save_state_to_tss32(cpu, &tss_seg); 98996feed4SSergio Andres Gomez Del Real 99996feed4SSergio Andres Gomez Del Real vmx_write_mem(cpu, old_tss_base + eip_offset, &tss_seg.eip, ldt_sel_offset - eip_offset); 100996feed4SSergio Andres Gomez Del Real vmx_read_mem(cpu, &tss_seg, new_tss_base, sizeof(tss_seg)); 101996feed4SSergio Andres Gomez Del Real 102996feed4SSergio Andres Gomez Del Real if (old_tss_sel.sel != 0xffff) { 103996feed4SSergio Andres Gomez Del Real tss_seg.prev_tss = old_tss_sel.sel; 104996feed4SSergio Andres Gomez Del Real 105996feed4SSergio Andres Gomez Del Real vmx_write_mem(cpu, new_tss_base, &tss_seg.prev_tss, sizeof(tss_seg.prev_tss)); 106996feed4SSergio Andres Gomez Del Real } 107996feed4SSergio Andres Gomez Del Real load_state_from_tss32(cpu, &tss_seg); 108996feed4SSergio Andres Gomez Del Real return 0; 109996feed4SSergio Andres Gomez Del Real } 110996feed4SSergio Andres Gomez Del Real 11125409172SWei Liu void vmx_handle_task_switch(CPUState *cpu, x86_segment_selector tss_sel, int reason, bool gate_valid, uint8_t gate, uint64_t gate_type) 112996feed4SSergio Andres Gomez Del Real { 1133b295bcbSPhilippe Mathieu-Daudé uint64_t rip = rreg(cpu->accel->fd, HV_X86_RIP); 114996feed4SSergio Andres Gomez Del Real if (!gate_valid || (gate_type != VMCS_INTR_T_HWEXCEPTION && 115996feed4SSergio Andres Gomez Del Real gate_type != VMCS_INTR_T_HWINTR && 116996feed4SSergio Andres Gomez Del Real gate_type != VMCS_INTR_T_NMI)) { 1173b295bcbSPhilippe Mathieu-Daudé int ins_len = rvmcs(cpu->accel->fd, VMCS_EXIT_INSTRUCTION_LENGTH); 118996feed4SSergio Andres Gomez Del Real macvm_set_rip(cpu, rip + ins_len); 119996feed4SSergio Andres Gomez Del Real return; 120996feed4SSergio Andres Gomez Del Real } 121996feed4SSergio Andres Gomez Del Real 122*dbccd48dSWei Liu hvf_load_regs(cpu); 123996feed4SSergio Andres Gomez Del Real 124996feed4SSergio Andres Gomez Del Real struct x86_segment_descriptor curr_tss_desc, next_tss_desc; 12525409172SWei Liu x86_segment_selector old_tss_sel = vmx_read_segment_selector(cpu, R_TR); 1266701d81dSPaolo Bonzini uint64_t old_tss_base = vmx_read_segment_base(cpu, R_TR); 127996feed4SSergio Andres Gomez Del Real uint32_t desc_limit; 128996feed4SSergio Andres Gomez Del Real struct x86_call_gate task_gate_desc; 129996feed4SSergio Andres Gomez Del Real struct vmx_segment vmx_seg; 130996feed4SSergio Andres Gomez Del Real 131996feed4SSergio Andres Gomez Del Real X86CPU *x86_cpu = X86_CPU(cpu); 132996feed4SSergio Andres Gomez Del Real CPUX86State *env = &x86_cpu->env; 133996feed4SSergio Andres Gomez Del Real 134996feed4SSergio Andres Gomez Del Real x86_read_segment_descriptor(cpu, &next_tss_desc, tss_sel); 135996feed4SSergio Andres Gomez Del Real x86_read_segment_descriptor(cpu, &curr_tss_desc, old_tss_sel); 136996feed4SSergio Andres Gomez Del Real 137996feed4SSergio Andres Gomez Del Real if (reason == TSR_IDT_GATE && gate_valid) { 138996feed4SSergio Andres Gomez Del Real int dpl; 139996feed4SSergio Andres Gomez Del Real 14019d542ccSPierrick Bouvier x86_read_call_gate(cpu, &task_gate_desc, gate); 141996feed4SSergio Andres Gomez Del Real 142996feed4SSergio Andres Gomez Del Real dpl = task_gate_desc.dpl; 14325409172SWei Liu x86_segment_selector cs = vmx_read_segment_selector(cpu, R_CS); 144996feed4SSergio Andres Gomez Del Real if (tss_sel.rpl > dpl || cs.rpl > dpl) 145996feed4SSergio Andres Gomez Del Real ;//DPRINTF("emulate_gp"); 146996feed4SSergio Andres Gomez Del Real } 147996feed4SSergio Andres Gomez Del Real 148996feed4SSergio Andres Gomez Del Real desc_limit = x86_segment_limit(&next_tss_desc); 149996feed4SSergio Andres Gomez Del Real if (!next_tss_desc.p || ((desc_limit < 0x67 && (next_tss_desc.type & 8)) || desc_limit < 0x2b)) { 150996feed4SSergio Andres Gomez Del Real VM_PANIC("emulate_ts"); 151996feed4SSergio Andres Gomez Del Real } 152996feed4SSergio Andres Gomez Del Real 153996feed4SSergio Andres Gomez Del Real if (reason == TSR_IRET || reason == TSR_JMP) { 154996feed4SSergio Andres Gomez Del Real curr_tss_desc.type &= ~(1 << 1); /* clear busy flag */ 155996feed4SSergio Andres Gomez Del Real x86_write_segment_descriptor(cpu, &curr_tss_desc, old_tss_sel); 156996feed4SSergio Andres Gomez Del Real } 157996feed4SSergio Andres Gomez Del Real 158996feed4SSergio Andres Gomez Del Real if (reason == TSR_IRET) 159ea48ae91SRoman Bolshakov env->eflags &= ~NT_MASK; 160996feed4SSergio Andres Gomez Del Real 161996feed4SSergio Andres Gomez Del Real if (reason != TSR_CALL && reason != TSR_IDT_GATE) 162996feed4SSergio Andres Gomez Del Real old_tss_sel.sel = 0xffff; 163996feed4SSergio Andres Gomez Del Real 164996feed4SSergio Andres Gomez Del Real if (reason != TSR_IRET) { 165996feed4SSergio Andres Gomez Del Real next_tss_desc.type |= (1 << 1); /* set busy flag */ 166996feed4SSergio Andres Gomez Del Real x86_write_segment_descriptor(cpu, &next_tss_desc, tss_sel); 167996feed4SSergio Andres Gomez Del Real } 168996feed4SSergio Andres Gomez Del Real 16919d542ccSPierrick Bouvier if (next_tss_desc.type & 8) { 17019d542ccSPierrick Bouvier task_switch_32(cpu, tss_sel, old_tss_sel, old_tss_base, &next_tss_desc); 17119d542ccSPierrick Bouvier } else { 172996feed4SSergio Andres Gomez Del Real //ret = task_switch_16(cpu, tss_sel, old_tss_sel, old_tss_base, &next_tss_desc); 173996feed4SSergio Andres Gomez Del Real VM_PANIC("task_switch_16"); 17419d542ccSPierrick Bouvier } 175996feed4SSergio Andres Gomez Del Real 1763b295bcbSPhilippe Mathieu-Daudé macvm_set_cr0(cpu->accel->fd, rvmcs(cpu->accel->fd, VMCS_GUEST_CR0) | 177704afe34SCameron Esfahani CR0_TS_MASK); 178996feed4SSergio Andres Gomez Del Real x86_segment_descriptor_to_vmx(cpu, tss_sel, &next_tss_desc, &vmx_seg); 1796701d81dSPaolo Bonzini vmx_write_segment_descriptor(cpu, &vmx_seg, R_TR); 180996feed4SSergio Andres Gomez Del Real 181*dbccd48dSWei Liu hvf_store_regs(cpu); 182996feed4SSergio Andres Gomez Del Real 1833b295bcbSPhilippe Mathieu-Daudé hv_vcpu_invalidate_tlb(cpu->accel->fd); 184996feed4SSergio Andres Gomez Del Real } 185