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-common.h"
12 #include "qemu/error-report.h"
14 #include "sysemu/hvf.h"
19 #include "x86_descr.h"
21 #include "x86_decode.h"
26 #include <Hypervisor/hv.h>
27 #include <Hypervisor/hv_vmx.h>
29 #include "exec/address-spaces.h"
30 #include "exec/exec-all.h"
31 #include "exec/ioport.h"
32 #include "hw/i386/apic_internal.h"
33 #include "hw/boards.h"
34 #include "qemu/main-loop.h"
35 #include "sysemu/accel.h"
36 #include "sysemu/sysemu.h"
37 #include "target/i386/cpu.h"
39 // TODO: taskswitch handling
40 static void save_state_to_tss32(CPUState
*cpu
, struct x86_tss_segment32
*tss
)
42 X86CPU
*x86_cpu
= X86_CPU(cpu
);
43 CPUX86State
*env
= &x86_cpu
->env
;
45 /* CR3 and ldt selector are not saved intentionally */
47 tss
->eflags
= EFLAGS(env
);
57 tss
->es
= vmx_read_segment_selector(cpu
, R_ES
).sel
;
58 tss
->cs
= vmx_read_segment_selector(cpu
, R_CS
).sel
;
59 tss
->ss
= vmx_read_segment_selector(cpu
, R_SS
).sel
;
60 tss
->ds
= vmx_read_segment_selector(cpu
, R_DS
).sel
;
61 tss
->fs
= vmx_read_segment_selector(cpu
, R_FS
).sel
;
62 tss
->gs
= vmx_read_segment_selector(cpu
, R_GS
).sel
;
65 static void load_state_from_tss32(CPUState
*cpu
, struct x86_tss_segment32
*tss
)
67 X86CPU
*x86_cpu
= X86_CPU(cpu
);
68 CPUX86State
*env
= &x86_cpu
->env
;
70 wvmcs(cpu
->hvf_fd
, VMCS_GUEST_CR3
, tss
->cr3
);
73 EFLAGS(env
) = tss
->eflags
| 2;
75 /* General purpose registers */
85 vmx_write_segment_selector(cpu
, (x68_segment_selector
){{tss
->ldt
}}, R_LDTR
);
86 vmx_write_segment_selector(cpu
, (x68_segment_selector
){{tss
->es
}}, R_ES
);
87 vmx_write_segment_selector(cpu
, (x68_segment_selector
){{tss
->cs
}}, R_CS
);
88 vmx_write_segment_selector(cpu
, (x68_segment_selector
){{tss
->ss
}}, R_SS
);
89 vmx_write_segment_selector(cpu
, (x68_segment_selector
){{tss
->ds
}}, R_DS
);
90 vmx_write_segment_selector(cpu
, (x68_segment_selector
){{tss
->fs
}}, R_FS
);
91 vmx_write_segment_selector(cpu
, (x68_segment_selector
){{tss
->gs
}}, R_GS
);
94 static int task_switch_32(CPUState
*cpu
, x68_segment_selector tss_sel
, x68_segment_selector old_tss_sel
,
95 uint64_t old_tss_base
, struct x86_segment_descriptor
*new_desc
)
97 struct x86_tss_segment32 tss_seg
;
98 uint32_t new_tss_base
= x86_segment_base(new_desc
);
99 uint32_t eip_offset
= offsetof(struct x86_tss_segment32
, eip
);
100 uint32_t ldt_sel_offset
= offsetof(struct x86_tss_segment32
, ldt
);
102 vmx_read_mem(cpu
, &tss_seg
, old_tss_base
, sizeof(tss_seg
));
103 save_state_to_tss32(cpu
, &tss_seg
);
105 vmx_write_mem(cpu
, old_tss_base
+ eip_offset
, &tss_seg
.eip
, ldt_sel_offset
- eip_offset
);
106 vmx_read_mem(cpu
, &tss_seg
, new_tss_base
, sizeof(tss_seg
));
108 if (old_tss_sel
.sel
!= 0xffff) {
109 tss_seg
.prev_tss
= old_tss_sel
.sel
;
111 vmx_write_mem(cpu
, new_tss_base
, &tss_seg
.prev_tss
, sizeof(tss_seg
.prev_tss
));
113 load_state_from_tss32(cpu
, &tss_seg
);
117 void vmx_handle_task_switch(CPUState
*cpu
, x68_segment_selector tss_sel
, int reason
, bool gate_valid
, uint8_t gate
, uint64_t gate_type
)
119 uint64_t rip
= rreg(cpu
->hvf_fd
, HV_X86_RIP
);
120 if (!gate_valid
|| (gate_type
!= VMCS_INTR_T_HWEXCEPTION
&&
121 gate_type
!= VMCS_INTR_T_HWINTR
&&
122 gate_type
!= VMCS_INTR_T_NMI
)) {
123 int ins_len
= rvmcs(cpu
->hvf_fd
, VMCS_EXIT_INSTRUCTION_LENGTH
);
124 macvm_set_rip(cpu
, rip
+ ins_len
);
130 struct x86_segment_descriptor curr_tss_desc
, next_tss_desc
;
132 x68_segment_selector old_tss_sel
= vmx_read_segment_selector(cpu
, R_TR
);
133 uint64_t old_tss_base
= vmx_read_segment_base(cpu
, R_TR
);
135 struct x86_call_gate task_gate_desc
;
136 struct vmx_segment vmx_seg
;
138 X86CPU
*x86_cpu
= X86_CPU(cpu
);
139 CPUX86State
*env
= &x86_cpu
->env
;
141 x86_read_segment_descriptor(cpu
, &next_tss_desc
, tss_sel
);
142 x86_read_segment_descriptor(cpu
, &curr_tss_desc
, old_tss_sel
);
144 if (reason
== TSR_IDT_GATE
&& gate_valid
) {
147 ret
= x86_read_call_gate(cpu
, &task_gate_desc
, gate
);
149 dpl
= task_gate_desc
.dpl
;
150 x68_segment_selector cs
= vmx_read_segment_selector(cpu
, R_CS
);
151 if (tss_sel
.rpl
> dpl
|| cs
.rpl
> dpl
)
152 ;//DPRINTF("emulate_gp");
155 desc_limit
= x86_segment_limit(&next_tss_desc
);
156 if (!next_tss_desc
.p
|| ((desc_limit
< 0x67 && (next_tss_desc
.type
& 8)) || desc_limit
< 0x2b)) {
157 VM_PANIC("emulate_ts");
160 if (reason
== TSR_IRET
|| reason
== TSR_JMP
) {
161 curr_tss_desc
.type
&= ~(1 << 1); /* clear busy flag */
162 x86_write_segment_descriptor(cpu
, &curr_tss_desc
, old_tss_sel
);
165 if (reason
== TSR_IRET
)
166 EFLAGS(env
) &= ~RFLAGS_NT
;
168 if (reason
!= TSR_CALL
&& reason
!= TSR_IDT_GATE
)
169 old_tss_sel
.sel
= 0xffff;
171 if (reason
!= TSR_IRET
) {
172 next_tss_desc
.type
|= (1 << 1); /* set busy flag */
173 x86_write_segment_descriptor(cpu
, &next_tss_desc
, tss_sel
);
176 if (next_tss_desc
.type
& 8)
177 ret
= task_switch_32(cpu
, tss_sel
, old_tss_sel
, old_tss_base
, &next_tss_desc
);
179 //ret = task_switch_16(cpu, tss_sel, old_tss_sel, old_tss_base, &next_tss_desc);
180 VM_PANIC("task_switch_16");
182 macvm_set_cr0(cpu
->hvf_fd
, rvmcs(cpu
->hvf_fd
, VMCS_GUEST_CR0
) | CR0_TS
);
183 x86_segment_descriptor_to_vmx(cpu
, tss_sel
, &next_tss_desc
, &vmx_seg
);
184 vmx_write_segment_descriptor(cpu
, &vmx_seg
, R_TR
);
188 hv_vcpu_invalidate_tlb(cpu
->hvf_fd
);
189 hv_vcpu_flush(cpu
->hvf_fd
);