xref: /openbmc/qemu/target/i386/hvf/x86.c (revision 6016b7b4)
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
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.1 of the License, or (at your option) any later version.
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
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
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/>.
17  */
18 
19 #include "qemu/osdep.h"
20 
21 #include "cpu.h"
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 
50 bool x86_read_segment_descriptor(struct CPUState *cpu,
51                                  struct x86_segment_descriptor *desc,
52                                  x68_segment_selector sel)
53 {
54     target_ulong base;
55     uint32_t limit;
56 
57     memset(desc, 0, sizeof(*desc));
58 
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 
80 bool x86_write_segment_descriptor(struct CPUState *cpu,
81                                   struct x86_segment_descriptor *desc,
82                                   x68_segment_selector sel)
83 {
84     target_ulong base;
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 
103 bool x86_read_call_gate(struct CPUState *cpu, struct x86_call_gate *idt_desc,
104                         int gate)
105 {
106     target_ulong base  = rvmcs(cpu->hvf->fd, VMCS_GUEST_IDTR_BASE);
107     uint32_t limit = rvmcs(cpu->hvf->fd, VMCS_GUEST_IDTR_LIMIT);
108 
109     memset(idt_desc, 0, sizeof(*idt_desc));
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 
119 bool 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 
125 bool x86_is_real(struct CPUState *cpu)
126 {
127     return !x86_is_protected(cpu);
128 }
129 
130 bool x86_is_v8086(struct CPUState *cpu)
131 {
132     X86CPU *x86_cpu = X86_CPU(cpu);
133     CPUX86State *env = &x86_cpu->env;
134     return x86_is_protected(cpu) && (env->eflags & VM_MASK);
135 }
136 
137 bool x86_is_long_mode(struct CPUState *cpu)
138 {
139     return rvmcs(cpu->hvf->fd, VMCS_GUEST_IA32_EFER) & MSR_EFER_LMA;
140 }
141 
142 bool x86_is_long64_mode(struct CPUState *cpu)
143 {
144     struct vmx_segment desc;
145     vmx_read_segment_descriptor(cpu, &desc, R_CS);
146 
147     return x86_is_long_mode(cpu) && ((desc.ar >> 13) & 1);
148 }
149 
150 bool 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 
156 bool 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 
162 target_ulong linear_addr(struct CPUState *cpu, target_ulong addr, X86Seg seg)
163 {
164     return vmx_read_segment_base(cpu, seg) + addr;
165 }
166 
167 target_ulong linear_addr_size(struct CPUState *cpu, target_ulong addr, int size,
168                               X86Seg seg)
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 
183 target_ulong linear_rip(struct CPUState *cpu, target_ulong rip)
184 {
185     return linear_addr(cpu, rip, R_CS);
186 }
187