1 // This software is licensed under the terms of the GNU General Public
2 // License version 2, as published by the Free Software Foundation, and
3 // may be copied, distributed, and modified under those terms.
5 // This program is distributed in the hope that it will be useful,
6 // but WITHOUT ANY WARRANTY; without even the implied warranty of
7 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8 // GNU General Public License for more details.
9 #include "qemu/osdep.h"
11 #include "qemu/error-report.h"
13 #include "sysemu/hvf.h"
18 #include "x86_descr.h"
20 #include "x86_decode.h"
25 #include <Hypervisor/hv.h>
26 #include <Hypervisor/hv_vmx.h>
28 #include "hw/i386/apic_internal.h"
29 #include "qemu/main-loop.h"
30 #include "qemu/accel.h"
31 #include "target/i386/cpu.h"
33 // TODO: taskswitch handling
34 static void save_state_to_tss32(CPUState
*cpu
, struct x86_tss_segment32
*tss
)
36 X86CPU
*x86_cpu
= X86_CPU(cpu
);
37 CPUX86State
*env
= &x86_cpu
->env
;
39 /* CR3 and ldt selector are not saved intentionally */
40 tss
->eip
= (uint32_t)env
->eip
;
41 tss
->eflags
= (uint32_t)env
->eflags
;
51 tss
->es
= vmx_read_segment_selector(cpu
, R_ES
).sel
;
52 tss
->cs
= vmx_read_segment_selector(cpu
, R_CS
).sel
;
53 tss
->ss
= vmx_read_segment_selector(cpu
, R_SS
).sel
;
54 tss
->ds
= vmx_read_segment_selector(cpu
, R_DS
).sel
;
55 tss
->fs
= vmx_read_segment_selector(cpu
, R_FS
).sel
;
56 tss
->gs
= vmx_read_segment_selector(cpu
, R_GS
).sel
;
59 static void load_state_from_tss32(CPUState
*cpu
, struct x86_tss_segment32
*tss
)
61 X86CPU
*x86_cpu
= X86_CPU(cpu
);
62 CPUX86State
*env
= &x86_cpu
->env
;
64 wvmcs(cpu
->hvf
->fd
, VMCS_GUEST_CR3
, tss
->cr3
);
67 env
->eflags
= tss
->eflags
| 2;
69 /* General purpose registers */
79 vmx_write_segment_selector(cpu
, (x68_segment_selector
){{tss
->ldt
}}, R_LDTR
);
80 vmx_write_segment_selector(cpu
, (x68_segment_selector
){{tss
->es
}}, R_ES
);
81 vmx_write_segment_selector(cpu
, (x68_segment_selector
){{tss
->cs
}}, R_CS
);
82 vmx_write_segment_selector(cpu
, (x68_segment_selector
){{tss
->ss
}}, R_SS
);
83 vmx_write_segment_selector(cpu
, (x68_segment_selector
){{tss
->ds
}}, R_DS
);
84 vmx_write_segment_selector(cpu
, (x68_segment_selector
){{tss
->fs
}}, R_FS
);
85 vmx_write_segment_selector(cpu
, (x68_segment_selector
){{tss
->gs
}}, R_GS
);
88 static int task_switch_32(CPUState
*cpu
, x68_segment_selector tss_sel
, x68_segment_selector old_tss_sel
,
89 uint64_t old_tss_base
, struct x86_segment_descriptor
*new_desc
)
91 struct x86_tss_segment32 tss_seg
;
92 uint32_t new_tss_base
= x86_segment_base(new_desc
);
93 uint32_t eip_offset
= offsetof(struct x86_tss_segment32
, eip
);
94 uint32_t ldt_sel_offset
= offsetof(struct x86_tss_segment32
, ldt
);
96 vmx_read_mem(cpu
, &tss_seg
, old_tss_base
, sizeof(tss_seg
));
97 save_state_to_tss32(cpu
, &tss_seg
);
99 vmx_write_mem(cpu
, old_tss_base
+ eip_offset
, &tss_seg
.eip
, ldt_sel_offset
- eip_offset
);
100 vmx_read_mem(cpu
, &tss_seg
, new_tss_base
, sizeof(tss_seg
));
102 if (old_tss_sel
.sel
!= 0xffff) {
103 tss_seg
.prev_tss
= old_tss_sel
.sel
;
105 vmx_write_mem(cpu
, new_tss_base
, &tss_seg
.prev_tss
, sizeof(tss_seg
.prev_tss
));
107 load_state_from_tss32(cpu
, &tss_seg
);
111 void vmx_handle_task_switch(CPUState
*cpu
, x68_segment_selector tss_sel
, int reason
, bool gate_valid
, uint8_t gate
, uint64_t gate_type
)
113 uint64_t rip
= rreg(cpu
->hvf
->fd
, HV_X86_RIP
);
114 if (!gate_valid
|| (gate_type
!= VMCS_INTR_T_HWEXCEPTION
&&
115 gate_type
!= VMCS_INTR_T_HWINTR
&&
116 gate_type
!= VMCS_INTR_T_NMI
)) {
117 int ins_len
= rvmcs(cpu
->hvf
->fd
, VMCS_EXIT_INSTRUCTION_LENGTH
);
118 macvm_set_rip(cpu
, rip
+ ins_len
);
124 struct x86_segment_descriptor curr_tss_desc
, next_tss_desc
;
126 x68_segment_selector old_tss_sel
= vmx_read_segment_selector(cpu
, R_TR
);
127 uint64_t old_tss_base
= vmx_read_segment_base(cpu
, R_TR
);
129 struct x86_call_gate task_gate_desc
;
130 struct vmx_segment vmx_seg
;
132 X86CPU
*x86_cpu
= X86_CPU(cpu
);
133 CPUX86State
*env
= &x86_cpu
->env
;
135 x86_read_segment_descriptor(cpu
, &next_tss_desc
, tss_sel
);
136 x86_read_segment_descriptor(cpu
, &curr_tss_desc
, old_tss_sel
);
138 if (reason
== TSR_IDT_GATE
&& gate_valid
) {
141 ret
= x86_read_call_gate(cpu
, &task_gate_desc
, gate
);
143 dpl
= task_gate_desc
.dpl
;
144 x68_segment_selector cs
= vmx_read_segment_selector(cpu
, R_CS
);
145 if (tss_sel
.rpl
> dpl
|| cs
.rpl
> dpl
)
146 ;//DPRINTF("emulate_gp");
149 desc_limit
= x86_segment_limit(&next_tss_desc
);
150 if (!next_tss_desc
.p
|| ((desc_limit
< 0x67 && (next_tss_desc
.type
& 8)) || desc_limit
< 0x2b)) {
151 VM_PANIC("emulate_ts");
154 if (reason
== TSR_IRET
|| reason
== TSR_JMP
) {
155 curr_tss_desc
.type
&= ~(1 << 1); /* clear busy flag */
156 x86_write_segment_descriptor(cpu
, &curr_tss_desc
, old_tss_sel
);
159 if (reason
== TSR_IRET
)
160 env
->eflags
&= ~NT_MASK
;
162 if (reason
!= TSR_CALL
&& reason
!= TSR_IDT_GATE
)
163 old_tss_sel
.sel
= 0xffff;
165 if (reason
!= TSR_IRET
) {
166 next_tss_desc
.type
|= (1 << 1); /* set busy flag */
167 x86_write_segment_descriptor(cpu
, &next_tss_desc
, tss_sel
);
170 if (next_tss_desc
.type
& 8)
171 ret
= task_switch_32(cpu
, tss_sel
, old_tss_sel
, old_tss_base
, &next_tss_desc
);
173 //ret = task_switch_16(cpu, tss_sel, old_tss_sel, old_tss_base, &next_tss_desc);
174 VM_PANIC("task_switch_16");
176 macvm_set_cr0(cpu
->hvf
->fd
, rvmcs(cpu
->hvf
->fd
, VMCS_GUEST_CR0
) |
178 x86_segment_descriptor_to_vmx(cpu
, tss_sel
, &next_tss_desc
, &vmx_seg
);
179 vmx_write_segment_descriptor(cpu
, &vmx_seg
, R_TR
);
183 hv_vcpu_invalidate_tlb(cpu
->hvf
->fd
);