xref: /qemu/target/i386/hvf/x86.c (revision 27458df871097d7fc14b19d9e01c35d29737b9b3)
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