]> Git Repo - qemu.git/blame - target/i386/hvf/x86.c
KVM: add support for AMD nested live migration
[qemu.git] / target / i386 / hvf / x86.c
CommitLineData
c97d6d2c
SAGDR
1/*
2 * Copyright (C) 2016 Veertu Inc,
3 * Copyright (C) 2017 Google Inc,
4 *
5 * This program is free software; you can redistribute it and/or
996feed4
SAGDR
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
c97d6d2c
SAGDR
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
996feed4
SAGDR
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
c97d6d2c 14 *
996feed4
SAGDR
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
c97d6d2c
SAGDR
17 */
18
19#include "qemu/osdep.h"
20
ff2de166 21#include "cpu.h"
c97d6d2c
SAGDR
22#include "qemu-common.h"
23#include "x86_decode.h"
24#include "x86_emu.h"
25#include "vmcs.h"
26#include "vmx.h"
27#include "x86_mmu.h"
28#include "x86_descr.h"
29
30/* static uint32_t x86_segment_access_rights(struct x86_segment_descriptor *var)
31{
32 uint32_t ar;
33
34 if (!var->p) {
35 ar = 1 << 16;
36 return ar;
37 }
38
39 ar = var->type & 15;
40 ar |= (var->s & 1) << 4;
41 ar |= (var->dpl & 3) << 5;
42 ar |= (var->p & 1) << 7;
43 ar |= (var->avl & 1) << 12;
44 ar |= (var->l & 1) << 13;
45 ar |= (var->db & 1) << 14;
46 ar |= (var->g & 1) << 15;
47 return ar;
48}*/
49
50bool x86_read_segment_descriptor(struct CPUState *cpu,
51 struct x86_segment_descriptor *desc,
52 x68_segment_selector sel)
53{
ff2de166 54 target_ulong base;
c97d6d2c
SAGDR
55 uint32_t limit;
56
715f396d
PB
57 memset(desc, 0, sizeof(*desc));
58
c97d6d2c
SAGDR
59 /* valid gdt descriptors start from index 1 */
60 if (!sel.index && GDT_SEL == sel.ti) {
61 return false;
62 }
63
64 if (GDT_SEL == sel.ti) {
65 base = rvmcs(cpu->hvf_fd, VMCS_GUEST_GDTR_BASE);
66 limit = rvmcs(cpu->hvf_fd, VMCS_GUEST_GDTR_LIMIT);
67 } else {
68 base = rvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_BASE);
69 limit = rvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_LIMIT);
70 }
71
72 if (sel.index * 8 >= limit) {
73 return false;
74 }
75
76 vmx_read_mem(cpu, desc, base + sel.index * 8, sizeof(*desc));
77 return true;
78}
79
80bool x86_write_segment_descriptor(struct CPUState *cpu,
81 struct x86_segment_descriptor *desc,
82 x68_segment_selector sel)
83{
ff2de166 84 target_ulong base;
c97d6d2c
SAGDR
85 uint32_t limit;
86
87 if (GDT_SEL == sel.ti) {
88 base = rvmcs(cpu->hvf_fd, VMCS_GUEST_GDTR_BASE);
89 limit = rvmcs(cpu->hvf_fd, VMCS_GUEST_GDTR_LIMIT);
90 } else {
91 base = rvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_BASE);
92 limit = rvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_LIMIT);
93 }
94
95 if (sel.index * 8 >= limit) {
96 printf("%s: gdt limit\n", __func__);
97 return false;
98 }
99 vmx_write_mem(cpu, base + sel.index * 8, desc, sizeof(*desc));
100 return true;
101}
102
103bool x86_read_call_gate(struct CPUState *cpu, struct x86_call_gate *idt_desc,
104 int gate)
105{
ff2de166 106 target_ulong base = rvmcs(cpu->hvf_fd, VMCS_GUEST_IDTR_BASE);
c97d6d2c
SAGDR
107 uint32_t limit = rvmcs(cpu->hvf_fd, VMCS_GUEST_IDTR_LIMIT);
108
715f396d 109 memset(idt_desc, 0, sizeof(*idt_desc));
c97d6d2c
SAGDR
110 if (gate * 8 >= limit) {
111 printf("%s: idt limit\n", __func__);
112 return false;
113 }
114
115 vmx_read_mem(cpu, idt_desc, base + gate * 8, sizeof(*idt_desc));
116 return true;
117}
118
119bool x86_is_protected(struct CPUState *cpu)
120{
121 uint64_t cr0 = rvmcs(cpu->hvf_fd, VMCS_GUEST_CR0);
122 return cr0 & CR0_PE;
123}
124
125bool x86_is_real(struct CPUState *cpu)
126{
127 return !x86_is_protected(cpu);
128}
129
130bool x86_is_v8086(struct CPUState *cpu)
131{
132 X86CPU *x86_cpu = X86_CPU(cpu);
133 CPUX86State *env = &x86_cpu->env;
ea48ae91 134 return x86_is_protected(cpu) && (env->eflags & VM_MASK);
c97d6d2c
SAGDR
135}
136
137bool x86_is_long_mode(struct CPUState *cpu)
138{
6701d81d 139 return rvmcs(cpu->hvf_fd, VMCS_GUEST_IA32_EFER) & MSR_EFER_LMA;
c97d6d2c
SAGDR
140}
141
142bool x86_is_long64_mode(struct CPUState *cpu)
143{
144 struct vmx_segment desc;
6701d81d 145 vmx_read_segment_descriptor(cpu, &desc, R_CS);
c97d6d2c
SAGDR
146
147 return x86_is_long_mode(cpu) && ((desc.ar >> 13) & 1);
148}
149
150bool x86_is_paging_mode(struct CPUState *cpu)
151{
152 uint64_t cr0 = rvmcs(cpu->hvf_fd, VMCS_GUEST_CR0);
153 return cr0 & CR0_PG;
154}
155
156bool x86_is_pae_enabled(struct CPUState *cpu)
157{
158 uint64_t cr4 = rvmcs(cpu->hvf_fd, VMCS_GUEST_CR4);
159 return cr4 & CR4_PAE;
160}
161
ff2de166 162target_ulong linear_addr(struct CPUState *cpu, target_ulong addr, X86Seg seg)
c97d6d2c
SAGDR
163{
164 return vmx_read_segment_base(cpu, seg) + addr;
165}
166
ff2de166
PB
167target_ulong linear_addr_size(struct CPUState *cpu, target_ulong addr, int size,
168 X86Seg seg)
c97d6d2c
SAGDR
169{
170 switch (size) {
171 case 2:
172 addr = (uint16_t)addr;
173 break;
174 case 4:
175 addr = (uint32_t)addr;
176 break;
177 default:
178 break;
179 }
180 return linear_addr(cpu, addr, seg);
181}
182
ff2de166 183target_ulong linear_rip(struct CPUState *cpu, target_ulong rip)
c97d6d2c 184{
6701d81d 185 return linear_addr(cpu, rip, R_CS);
c97d6d2c 186}
This page took 0.152368 seconds and 4 git commands to generate.