1c97d6d2cSSergio Andres Gomez Del Real /*
2c97d6d2cSSergio Andres Gomez Del Real * Copyright (C) 2016 Veertu Inc,
3c97d6d2cSSergio Andres Gomez Del Real * Copyright (C) 2017 Google Inc,
4c97d6d2cSSergio Andres Gomez Del Real *
5c97d6d2cSSergio Andres Gomez Del Real * This program is free software; you can redistribute it and/or
6996feed4SSergio Andres Gomez Del Real * modify it under the terms of the GNU Lesser General Public
7996feed4SSergio Andres Gomez Del Real * License as published by the Free Software Foundation; either
88af82b8eSChetan Pant * version 2.1 of the License, or (at your option) any later version.
9c97d6d2cSSergio Andres Gomez Del Real *
10c97d6d2cSSergio Andres Gomez Del Real * This program is distributed in the hope that it will be useful,
11c97d6d2cSSergio Andres Gomez Del Real * but WITHOUT ANY WARRANTY; without even the implied warranty of
12996feed4SSergio Andres Gomez Del Real * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13996feed4SSergio Andres Gomez Del Real * Lesser General Public License for more details.
14c97d6d2cSSergio Andres Gomez Del Real *
15996feed4SSergio Andres Gomez Del Real * You should have received a copy of the GNU Lesser General Public
16996feed4SSergio Andres Gomez Del Real * License along with this program; if not, see <http://www.gnu.org/licenses/>.
17c97d6d2cSSergio Andres Gomez Del Real */
18c97d6d2cSSergio Andres Gomez Del Real
19c97d6d2cSSergio Andres Gomez Del Real #include "qemu/osdep.h"
20c97d6d2cSSergio Andres Gomez Del Real
21ff2de166SPaolo Bonzini #include "cpu.h"
22*27458df8SWei Liu #include "emulate/x86_decode.h"
23*27458df8SWei Liu #include "emulate/x86_emu.h"
24c97d6d2cSSergio Andres Gomez Del Real #include "vmcs.h"
25c97d6d2cSSergio Andres Gomez Del Real #include "vmx.h"
26c97d6d2cSSergio Andres Gomez Del Real #include "x86_mmu.h"
27c97d6d2cSSergio Andres Gomez Del Real #include "x86_descr.h"
28c97d6d2cSSergio Andres Gomez Del Real
29c97d6d2cSSergio Andres Gomez Del Real /* static uint32_t x86_segment_access_rights(struct x86_segment_descriptor *var)
30c97d6d2cSSergio Andres Gomez Del Real {
31c97d6d2cSSergio Andres Gomez Del Real uint32_t ar;
32c97d6d2cSSergio Andres Gomez Del Real
33c97d6d2cSSergio Andres Gomez Del Real if (!var->p) {
34c97d6d2cSSergio Andres Gomez Del Real ar = 1 << 16;
35c97d6d2cSSergio Andres Gomez Del Real return ar;
36c97d6d2cSSergio Andres Gomez Del Real }
37c97d6d2cSSergio Andres Gomez Del Real
38c97d6d2cSSergio Andres Gomez Del Real ar = var->type & 15;
39c97d6d2cSSergio Andres Gomez Del Real ar |= (var->s & 1) << 4;
40c97d6d2cSSergio Andres Gomez Del Real ar |= (var->dpl & 3) << 5;
41c97d6d2cSSergio Andres Gomez Del Real ar |= (var->p & 1) << 7;
42c97d6d2cSSergio Andres Gomez Del Real ar |= (var->avl & 1) << 12;
43c97d6d2cSSergio Andres Gomez Del Real ar |= (var->l & 1) << 13;
44c97d6d2cSSergio Andres Gomez Del Real ar |= (var->db & 1) << 14;
45c97d6d2cSSergio Andres Gomez Del Real ar |= (var->g & 1) << 15;
46c97d6d2cSSergio Andres Gomez Del Real return ar;
47c97d6d2cSSergio Andres Gomez Del Real }*/
48c97d6d2cSSergio Andres Gomez Del Real
x86_read_segment_descriptor(CPUState * cpu,struct x86_segment_descriptor * desc,x86_segment_selector sel)49f8436a16SPhilippe Mathieu-Daudé bool x86_read_segment_descriptor(CPUState *cpu,
50c97d6d2cSSergio Andres Gomez Del Real struct x86_segment_descriptor *desc,
5125409172SWei Liu x86_segment_selector sel)
52c97d6d2cSSergio Andres Gomez Del Real {
53ff2de166SPaolo Bonzini target_ulong base;
54c97d6d2cSSergio Andres Gomez Del Real uint32_t limit;
55c97d6d2cSSergio Andres Gomez Del Real
56715f396dSPaolo Bonzini memset(desc, 0, sizeof(*desc));
57715f396dSPaolo Bonzini
58c97d6d2cSSergio Andres Gomez Del Real /* valid gdt descriptors start from index 1 */
59c97d6d2cSSergio Andres Gomez Del Real if (!sel.index && GDT_SEL == sel.ti) {
60c97d6d2cSSergio Andres Gomez Del Real return false;
61c97d6d2cSSergio Andres Gomez Del Real }
62c97d6d2cSSergio Andres Gomez Del Real
63c97d6d2cSSergio Andres Gomez Del Real if (GDT_SEL == sel.ti) {
643b295bcbSPhilippe Mathieu-Daudé base = rvmcs(cpu->accel->fd, VMCS_GUEST_GDTR_BASE);
653b295bcbSPhilippe Mathieu-Daudé limit = rvmcs(cpu->accel->fd, VMCS_GUEST_GDTR_LIMIT);
66c97d6d2cSSergio Andres Gomez Del Real } else {
673b295bcbSPhilippe Mathieu-Daudé base = rvmcs(cpu->accel->fd, VMCS_GUEST_LDTR_BASE);
683b295bcbSPhilippe Mathieu-Daudé limit = rvmcs(cpu->accel->fd, VMCS_GUEST_LDTR_LIMIT);
69c97d6d2cSSergio Andres Gomez Del Real }
70c97d6d2cSSergio Andres Gomez Del Real
71c97d6d2cSSergio Andres Gomez Del Real if (sel.index * 8 >= limit) {
72c97d6d2cSSergio Andres Gomez Del Real return false;
73c97d6d2cSSergio Andres Gomez Del Real }
74c97d6d2cSSergio Andres Gomez Del Real
75c97d6d2cSSergio Andres Gomez Del Real vmx_read_mem(cpu, desc, base + sel.index * 8, sizeof(*desc));
76c97d6d2cSSergio Andres Gomez Del Real return true;
77c97d6d2cSSergio Andres Gomez Del Real }
78c97d6d2cSSergio Andres Gomez Del Real
x86_write_segment_descriptor(CPUState * cpu,struct x86_segment_descriptor * desc,x86_segment_selector sel)79f8436a16SPhilippe Mathieu-Daudé bool x86_write_segment_descriptor(CPUState *cpu,
80c97d6d2cSSergio Andres Gomez Del Real struct x86_segment_descriptor *desc,
8125409172SWei Liu x86_segment_selector sel)
82c97d6d2cSSergio Andres Gomez Del Real {
83ff2de166SPaolo Bonzini target_ulong base;
84c97d6d2cSSergio Andres Gomez Del Real uint32_t limit;
85c97d6d2cSSergio Andres Gomez Del Real
86c97d6d2cSSergio Andres Gomez Del Real if (GDT_SEL == sel.ti) {
873b295bcbSPhilippe Mathieu-Daudé base = rvmcs(cpu->accel->fd, VMCS_GUEST_GDTR_BASE);
883b295bcbSPhilippe Mathieu-Daudé limit = rvmcs(cpu->accel->fd, VMCS_GUEST_GDTR_LIMIT);
89c97d6d2cSSergio Andres Gomez Del Real } else {
903b295bcbSPhilippe Mathieu-Daudé base = rvmcs(cpu->accel->fd, VMCS_GUEST_LDTR_BASE);
913b295bcbSPhilippe Mathieu-Daudé limit = rvmcs(cpu->accel->fd, VMCS_GUEST_LDTR_LIMIT);
92c97d6d2cSSergio Andres Gomez Del Real }
93c97d6d2cSSergio Andres Gomez Del Real
94c97d6d2cSSergio Andres Gomez Del Real if (sel.index * 8 >= limit) {
95c97d6d2cSSergio Andres Gomez Del Real printf("%s: gdt limit\n", __func__);
96c97d6d2cSSergio Andres Gomez Del Real return false;
97c97d6d2cSSergio Andres Gomez Del Real }
98c97d6d2cSSergio Andres Gomez Del Real vmx_write_mem(cpu, base + sel.index * 8, desc, sizeof(*desc));
99c97d6d2cSSergio Andres Gomez Del Real return true;
100c97d6d2cSSergio Andres Gomez Del Real }
101c97d6d2cSSergio Andres Gomez Del Real
x86_read_call_gate(CPUState * cpu,struct x86_call_gate * idt_desc,int gate)102f8436a16SPhilippe Mathieu-Daudé bool x86_read_call_gate(CPUState *cpu, struct x86_call_gate *idt_desc,
103c97d6d2cSSergio Andres Gomez Del Real int gate)
104c97d6d2cSSergio Andres Gomez Del Real {
1053b295bcbSPhilippe Mathieu-Daudé target_ulong base = rvmcs(cpu->accel->fd, VMCS_GUEST_IDTR_BASE);
1063b295bcbSPhilippe Mathieu-Daudé uint32_t limit = rvmcs(cpu->accel->fd, VMCS_GUEST_IDTR_LIMIT);
107c97d6d2cSSergio Andres Gomez Del Real
108715f396dSPaolo Bonzini memset(idt_desc, 0, sizeof(*idt_desc));
109c97d6d2cSSergio Andres Gomez Del Real if (gate * 8 >= limit) {
110c97d6d2cSSergio Andres Gomez Del Real printf("%s: idt limit\n", __func__);
111c97d6d2cSSergio Andres Gomez Del Real return false;
112c97d6d2cSSergio Andres Gomez Del Real }
113c97d6d2cSSergio Andres Gomez Del Real
114c97d6d2cSSergio Andres Gomez Del Real vmx_read_mem(cpu, idt_desc, base + gate * 8, sizeof(*idt_desc));
115c97d6d2cSSergio Andres Gomez Del Real return true;
116c97d6d2cSSergio Andres Gomez Del Real }
117c97d6d2cSSergio Andres Gomez Del Real
x86_is_protected(CPUState * cpu)118f8436a16SPhilippe Mathieu-Daudé bool x86_is_protected(CPUState *cpu)
119c97d6d2cSSergio Andres Gomez Del Real {
1203b295bcbSPhilippe Mathieu-Daudé uint64_t cr0 = rvmcs(cpu->accel->fd, VMCS_GUEST_CR0);
121704afe34SCameron Esfahani return cr0 & CR0_PE_MASK;
122c97d6d2cSSergio Andres Gomez Del Real }
123c97d6d2cSSergio Andres Gomez Del Real
x86_is_real(CPUState * cpu)124f8436a16SPhilippe Mathieu-Daudé bool x86_is_real(CPUState *cpu)
125c97d6d2cSSergio Andres Gomez Del Real {
126c97d6d2cSSergio Andres Gomez Del Real return !x86_is_protected(cpu);
127c97d6d2cSSergio Andres Gomez Del Real }
128c97d6d2cSSergio Andres Gomez Del Real
x86_is_v8086(CPUState * cpu)129f8436a16SPhilippe Mathieu-Daudé bool x86_is_v8086(CPUState *cpu)
130c97d6d2cSSergio Andres Gomez Del Real {
131c97d6d2cSSergio Andres Gomez Del Real X86CPU *x86_cpu = X86_CPU(cpu);
132c97d6d2cSSergio Andres Gomez Del Real CPUX86State *env = &x86_cpu->env;
133ea48ae91SRoman Bolshakov return x86_is_protected(cpu) && (env->eflags & VM_MASK);
134c97d6d2cSSergio Andres Gomez Del Real }
135c97d6d2cSSergio Andres Gomez Del Real
x86_is_long_mode(CPUState * cpu)136f8436a16SPhilippe Mathieu-Daudé bool x86_is_long_mode(CPUState *cpu)
137c97d6d2cSSergio Andres Gomez Del Real {
1383b295bcbSPhilippe Mathieu-Daudé return rvmcs(cpu->accel->fd, VMCS_GUEST_IA32_EFER) & MSR_EFER_LMA;
139c97d6d2cSSergio Andres Gomez Del Real }
140c97d6d2cSSergio Andres Gomez Del Real
x86_is_long64_mode(CPUState * cpu)141f8436a16SPhilippe Mathieu-Daudé bool x86_is_long64_mode(CPUState *cpu)
142c97d6d2cSSergio Andres Gomez Del Real {
143c97d6d2cSSergio Andres Gomez Del Real struct vmx_segment desc;
1446701d81dSPaolo Bonzini vmx_read_segment_descriptor(cpu, &desc, R_CS);
145c97d6d2cSSergio Andres Gomez Del Real
146c97d6d2cSSergio Andres Gomez Del Real return x86_is_long_mode(cpu) && ((desc.ar >> 13) & 1);
147c97d6d2cSSergio Andres Gomez Del Real }
148c97d6d2cSSergio Andres Gomez Del Real
x86_is_paging_mode(CPUState * cpu)149f8436a16SPhilippe Mathieu-Daudé bool x86_is_paging_mode(CPUState *cpu)
150c97d6d2cSSergio Andres Gomez Del Real {
1513b295bcbSPhilippe Mathieu-Daudé uint64_t cr0 = rvmcs(cpu->accel->fd, VMCS_GUEST_CR0);
152704afe34SCameron Esfahani return cr0 & CR0_PG_MASK;
153c97d6d2cSSergio Andres Gomez Del Real }
154c97d6d2cSSergio Andres Gomez Del Real
x86_is_pae_enabled(CPUState * cpu)155f8436a16SPhilippe Mathieu-Daudé bool x86_is_pae_enabled(CPUState *cpu)
156c97d6d2cSSergio Andres Gomez Del Real {
1573b295bcbSPhilippe Mathieu-Daudé uint64_t cr4 = rvmcs(cpu->accel->fd, VMCS_GUEST_CR4);
158704afe34SCameron Esfahani return cr4 & CR4_PAE_MASK;
159c97d6d2cSSergio Andres Gomez Del Real }
160c97d6d2cSSergio Andres Gomez Del Real
linear_addr(CPUState * cpu,target_ulong addr,X86Seg seg)161f8436a16SPhilippe Mathieu-Daudé target_ulong linear_addr(CPUState *cpu, target_ulong addr, X86Seg seg)
162c97d6d2cSSergio Andres Gomez Del Real {
163c97d6d2cSSergio Andres Gomez Del Real return vmx_read_segment_base(cpu, seg) + addr;
164c97d6d2cSSergio Andres Gomez Del Real }
165c97d6d2cSSergio Andres Gomez Del Real
linear_addr_size(CPUState * cpu,target_ulong addr,int size,X86Seg seg)166f8436a16SPhilippe Mathieu-Daudé target_ulong linear_addr_size(CPUState *cpu, target_ulong addr, int size,
1676701d81dSPaolo Bonzini X86Seg seg)
168c97d6d2cSSergio Andres Gomez Del Real {
169c97d6d2cSSergio Andres Gomez Del Real switch (size) {
170c97d6d2cSSergio Andres Gomez Del Real case 2:
171c97d6d2cSSergio Andres Gomez Del Real addr = (uint16_t)addr;
172c97d6d2cSSergio Andres Gomez Del Real break;
173c97d6d2cSSergio Andres Gomez Del Real case 4:
174c97d6d2cSSergio Andres Gomez Del Real addr = (uint32_t)addr;
175c97d6d2cSSergio Andres Gomez Del Real break;
176c97d6d2cSSergio Andres Gomez Del Real default:
177c97d6d2cSSergio Andres Gomez Del Real break;
178c97d6d2cSSergio Andres Gomez Del Real }
179c97d6d2cSSergio Andres Gomez Del Real return linear_addr(cpu, addr, seg);
180c97d6d2cSSergio Andres Gomez Del Real }
181c97d6d2cSSergio Andres Gomez Del Real
linear_rip(CPUState * cpu,target_ulong rip)182f8436a16SPhilippe Mathieu-Daudé target_ulong linear_rip(CPUState *cpu, target_ulong rip)
183c97d6d2cSSergio Andres Gomez Del Real {
1846701d81dSPaolo Bonzini return linear_addr(cpu, rip, R_CS);
185c97d6d2cSSergio Andres Gomez Del Real }
186