xref: /qemu/target/i386/hvf/x86.c (revision f8436a16)
169e0a03cSPaolo Bonzini /*
269e0a03cSPaolo Bonzini  * Copyright (C) 2016 Veertu Inc,
369e0a03cSPaolo Bonzini  * Copyright (C) 2017 Google Inc,
469e0a03cSPaolo Bonzini  *
569e0a03cSPaolo Bonzini  * This program is free software; you can redistribute it and/or
669e0a03cSPaolo Bonzini  * modify it under the terms of the GNU Lesser General Public
769e0a03cSPaolo Bonzini  * License as published by the Free Software Foundation; either
88af82b8eSChetan Pant  * version 2.1 of the License, or (at your option) any later version.
969e0a03cSPaolo Bonzini  *
1069e0a03cSPaolo Bonzini  * This program is distributed in the hope that it will be useful,
1169e0a03cSPaolo Bonzini  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1269e0a03cSPaolo Bonzini  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1369e0a03cSPaolo Bonzini  * Lesser General Public License for more details.
1469e0a03cSPaolo Bonzini  *
1569e0a03cSPaolo Bonzini  * You should have received a copy of the GNU Lesser General Public
1669e0a03cSPaolo Bonzini  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
1769e0a03cSPaolo Bonzini  */
1869e0a03cSPaolo Bonzini 
1969e0a03cSPaolo Bonzini #include "qemu/osdep.h"
2069e0a03cSPaolo Bonzini 
21ff2de166SPaolo Bonzini #include "cpu.h"
2269e0a03cSPaolo Bonzini #include "x86_decode.h"
2369e0a03cSPaolo Bonzini #include "x86_emu.h"
2469e0a03cSPaolo Bonzini #include "vmcs.h"
2569e0a03cSPaolo Bonzini #include "vmx.h"
2669e0a03cSPaolo Bonzini #include "x86_mmu.h"
2769e0a03cSPaolo Bonzini #include "x86_descr.h"
2869e0a03cSPaolo Bonzini 
2969e0a03cSPaolo Bonzini /* static uint32_t x86_segment_access_rights(struct x86_segment_descriptor *var)
3069e0a03cSPaolo Bonzini {
3169e0a03cSPaolo Bonzini    uint32_t ar;
3269e0a03cSPaolo Bonzini 
3369e0a03cSPaolo Bonzini    if (!var->p) {
3469e0a03cSPaolo Bonzini        ar = 1 << 16;
3569e0a03cSPaolo Bonzini        return ar;
3669e0a03cSPaolo Bonzini    }
3769e0a03cSPaolo Bonzini 
3869e0a03cSPaolo Bonzini    ar = var->type & 15;
3969e0a03cSPaolo Bonzini    ar |= (var->s & 1) << 4;
4069e0a03cSPaolo Bonzini    ar |= (var->dpl & 3) << 5;
4169e0a03cSPaolo Bonzini    ar |= (var->p & 1) << 7;
4269e0a03cSPaolo Bonzini    ar |= (var->avl & 1) << 12;
4369e0a03cSPaolo Bonzini    ar |= (var->l & 1) << 13;
4469e0a03cSPaolo Bonzini    ar |= (var->db & 1) << 14;
4569e0a03cSPaolo Bonzini    ar |= (var->g & 1) << 15;
4669e0a03cSPaolo Bonzini    return ar;
4769e0a03cSPaolo Bonzini }*/
4869e0a03cSPaolo Bonzini 
x86_read_segment_descriptor(CPUState * cpu,struct x86_segment_descriptor * desc,x68_segment_selector sel)49f8436a16SPhilippe Mathieu-Daudé bool x86_read_segment_descriptor(CPUState *cpu,
5069e0a03cSPaolo Bonzini                                  struct x86_segment_descriptor *desc,
5169e0a03cSPaolo Bonzini                                  x68_segment_selector sel)
5269e0a03cSPaolo Bonzini {
53ff2de166SPaolo Bonzini     target_ulong base;
5469e0a03cSPaolo Bonzini     uint32_t limit;
5569e0a03cSPaolo Bonzini 
56715f396dSPaolo Bonzini     memset(desc, 0, sizeof(*desc));
57715f396dSPaolo Bonzini 
5869e0a03cSPaolo Bonzini     /* valid gdt descriptors start from index 1 */
5969e0a03cSPaolo Bonzini     if (!sel.index && GDT_SEL == sel.ti) {
6069e0a03cSPaolo Bonzini         return false;
6169e0a03cSPaolo Bonzini     }
6269e0a03cSPaolo Bonzini 
6369e0a03cSPaolo Bonzini     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);
6669e0a03cSPaolo Bonzini     } 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);
6969e0a03cSPaolo Bonzini     }
7069e0a03cSPaolo Bonzini 
7169e0a03cSPaolo Bonzini     if (sel.index * 8 >= limit) {
7269e0a03cSPaolo Bonzini         return false;
7369e0a03cSPaolo Bonzini     }
7469e0a03cSPaolo Bonzini 
7569e0a03cSPaolo Bonzini     vmx_read_mem(cpu, desc, base + sel.index * 8, sizeof(*desc));
7669e0a03cSPaolo Bonzini     return true;
7769e0a03cSPaolo Bonzini }
7869e0a03cSPaolo Bonzini 
x86_write_segment_descriptor(CPUState * cpu,struct x86_segment_descriptor * desc,x68_segment_selector sel)79f8436a16SPhilippe Mathieu-Daudé bool x86_write_segment_descriptor(CPUState *cpu,
8069e0a03cSPaolo Bonzini                                   struct x86_segment_descriptor *desc,
8169e0a03cSPaolo Bonzini                                   x68_segment_selector sel)
8269e0a03cSPaolo Bonzini {
83ff2de166SPaolo Bonzini     target_ulong base;
8469e0a03cSPaolo Bonzini     uint32_t limit;
8569e0a03cSPaolo Bonzini 
8669e0a03cSPaolo Bonzini     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);
8969e0a03cSPaolo Bonzini     } 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);
9269e0a03cSPaolo Bonzini     }
9369e0a03cSPaolo Bonzini 
9469e0a03cSPaolo Bonzini     if (sel.index * 8 >= limit) {
9569e0a03cSPaolo Bonzini         printf("%s: gdt limit\n", __func__);
9669e0a03cSPaolo Bonzini         return false;
9769e0a03cSPaolo Bonzini     }
9869e0a03cSPaolo Bonzini     vmx_write_mem(cpu, base + sel.index * 8, desc, sizeof(*desc));
9969e0a03cSPaolo Bonzini     return true;
10069e0a03cSPaolo Bonzini }
10169e0a03cSPaolo Bonzini 
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,
10369e0a03cSPaolo Bonzini                         int gate)
10469e0a03cSPaolo Bonzini {
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);
10769e0a03cSPaolo Bonzini 
108715f396dSPaolo Bonzini     memset(idt_desc, 0, sizeof(*idt_desc));
10969e0a03cSPaolo Bonzini     if (gate * 8 >= limit) {
11069e0a03cSPaolo Bonzini         printf("%s: idt limit\n", __func__);
11169e0a03cSPaolo Bonzini         return false;
11269e0a03cSPaolo Bonzini     }
11369e0a03cSPaolo Bonzini 
11469e0a03cSPaolo Bonzini     vmx_read_mem(cpu, idt_desc, base + gate * 8, sizeof(*idt_desc));
11569e0a03cSPaolo Bonzini     return true;
11669e0a03cSPaolo Bonzini }
11769e0a03cSPaolo Bonzini 
x86_is_protected(CPUState * cpu)118f8436a16SPhilippe Mathieu-Daudé bool x86_is_protected(CPUState *cpu)
11969e0a03cSPaolo Bonzini {
1203b295bcbSPhilippe Mathieu-Daudé     uint64_t cr0 = rvmcs(cpu->accel->fd, VMCS_GUEST_CR0);
121704afe34SCameron Esfahani     return cr0 & CR0_PE_MASK;
12269e0a03cSPaolo Bonzini }
12369e0a03cSPaolo Bonzini 
x86_is_real(CPUState * cpu)124f8436a16SPhilippe Mathieu-Daudé bool x86_is_real(CPUState *cpu)
12569e0a03cSPaolo Bonzini {
12669e0a03cSPaolo Bonzini     return !x86_is_protected(cpu);
12769e0a03cSPaolo Bonzini }
12869e0a03cSPaolo Bonzini 
x86_is_v8086(CPUState * cpu)129f8436a16SPhilippe Mathieu-Daudé bool x86_is_v8086(CPUState *cpu)
13069e0a03cSPaolo Bonzini {
13169e0a03cSPaolo Bonzini     X86CPU *x86_cpu = X86_CPU(cpu);
13269e0a03cSPaolo Bonzini     CPUX86State *env = &x86_cpu->env;
133ea48ae91SRoman Bolshakov     return x86_is_protected(cpu) && (env->eflags & VM_MASK);
13469e0a03cSPaolo Bonzini }
13569e0a03cSPaolo Bonzini 
x86_is_long_mode(CPUState * cpu)136f8436a16SPhilippe Mathieu-Daudé bool x86_is_long_mode(CPUState *cpu)
13769e0a03cSPaolo Bonzini {
1383b295bcbSPhilippe Mathieu-Daudé     return rvmcs(cpu->accel->fd, VMCS_GUEST_IA32_EFER) & MSR_EFER_LMA;
13969e0a03cSPaolo Bonzini }
14069e0a03cSPaolo Bonzini 
x86_is_long64_mode(CPUState * cpu)141f8436a16SPhilippe Mathieu-Daudé bool x86_is_long64_mode(CPUState *cpu)
14269e0a03cSPaolo Bonzini {
14369e0a03cSPaolo Bonzini     struct vmx_segment desc;
1446701d81dSPaolo Bonzini     vmx_read_segment_descriptor(cpu, &desc, R_CS);
14569e0a03cSPaolo Bonzini 
14669e0a03cSPaolo Bonzini     return x86_is_long_mode(cpu) && ((desc.ar >> 13) & 1);
14769e0a03cSPaolo Bonzini }
14869e0a03cSPaolo Bonzini 
x86_is_paging_mode(CPUState * cpu)149f8436a16SPhilippe Mathieu-Daudé bool x86_is_paging_mode(CPUState *cpu)
15069e0a03cSPaolo Bonzini {
1513b295bcbSPhilippe Mathieu-Daudé     uint64_t cr0 = rvmcs(cpu->accel->fd, VMCS_GUEST_CR0);
152704afe34SCameron Esfahani     return cr0 & CR0_PG_MASK;
15369e0a03cSPaolo Bonzini }
15469e0a03cSPaolo Bonzini 
x86_is_pae_enabled(CPUState * cpu)155f8436a16SPhilippe Mathieu-Daudé bool x86_is_pae_enabled(CPUState *cpu)
15669e0a03cSPaolo Bonzini {
1573b295bcbSPhilippe Mathieu-Daudé     uint64_t cr4 = rvmcs(cpu->accel->fd, VMCS_GUEST_CR4);
158704afe34SCameron Esfahani     return cr4 & CR4_PAE_MASK;
15969e0a03cSPaolo Bonzini }
16069e0a03cSPaolo Bonzini 
linear_addr(CPUState * cpu,target_ulong addr,X86Seg seg)161f8436a16SPhilippe Mathieu-Daudé target_ulong linear_addr(CPUState *cpu, target_ulong addr, X86Seg seg)
16269e0a03cSPaolo Bonzini {
16369e0a03cSPaolo Bonzini     return vmx_read_segment_base(cpu, seg) + addr;
16469e0a03cSPaolo Bonzini }
16569e0a03cSPaolo Bonzini 
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)
16869e0a03cSPaolo Bonzini {
16969e0a03cSPaolo Bonzini     switch (size) {
17069e0a03cSPaolo Bonzini     case 2:
17169e0a03cSPaolo Bonzini         addr = (uint16_t)addr;
17269e0a03cSPaolo Bonzini         break;
17369e0a03cSPaolo Bonzini     case 4:
17469e0a03cSPaolo Bonzini         addr = (uint32_t)addr;
17569e0a03cSPaolo Bonzini         break;
17669e0a03cSPaolo Bonzini     default:
17769e0a03cSPaolo Bonzini         break;
17869e0a03cSPaolo Bonzini     }
17969e0a03cSPaolo Bonzini     return linear_addr(cpu, addr, seg);
18069e0a03cSPaolo Bonzini }
18169e0a03cSPaolo Bonzini 
linear_rip(CPUState * cpu,target_ulong rip)182f8436a16SPhilippe Mathieu-Daudé target_ulong linear_rip(CPUState *cpu, target_ulong rip)
18369e0a03cSPaolo Bonzini {
1846701d81dSPaolo Bonzini     return linear_addr(cpu, rip, R_CS);
18569e0a03cSPaolo Bonzini }
186