]>
Commit | Line | Data |
---|---|---|
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 | |
8af82b8e | 8 | * version 2.1 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 | ||
f9fea777 | 21 | #include "qemu-common.h" |
c97d6d2c SAGDR |
22 | #include "vmx.h" |
23 | #include "x86_descr.h" | |
24 | ||
6701d81d PB |
25 | #define VMX_SEGMENT_FIELD(seg) \ |
26 | [R_##seg] = { \ | |
27 | .selector = VMCS_GUEST_##seg##_SELECTOR, \ | |
28 | .base = VMCS_GUEST_##seg##_BASE, \ | |
29 | .limit = VMCS_GUEST_##seg##_LIMIT, \ | |
30 | .ar_bytes = VMCS_GUEST_##seg##_ACCESS_RIGHTS, \ | |
c97d6d2c SAGDR |
31 | } |
32 | ||
33 | static const struct vmx_segment_field { | |
34 | int selector; | |
35 | int base; | |
36 | int limit; | |
37 | int ar_bytes; | |
38 | } vmx_segment_fields[] = { | |
39 | VMX_SEGMENT_FIELD(ES), | |
40 | VMX_SEGMENT_FIELD(CS), | |
41 | VMX_SEGMENT_FIELD(SS), | |
42 | VMX_SEGMENT_FIELD(DS), | |
43 | VMX_SEGMENT_FIELD(FS), | |
44 | VMX_SEGMENT_FIELD(GS), | |
45 | VMX_SEGMENT_FIELD(LDTR), | |
46 | VMX_SEGMENT_FIELD(TR), | |
47 | }; | |
48 | ||
6701d81d | 49 | uint32_t vmx_read_segment_limit(CPUState *cpu, X86Seg seg) |
c97d6d2c | 50 | { |
b533450e | 51 | return (uint32_t)rvmcs(cpu->hvf->fd, vmx_segment_fields[seg].limit); |
c97d6d2c SAGDR |
52 | } |
53 | ||
6701d81d | 54 | uint32_t vmx_read_segment_ar(CPUState *cpu, X86Seg seg) |
c97d6d2c | 55 | { |
b533450e | 56 | return (uint32_t)rvmcs(cpu->hvf->fd, vmx_segment_fields[seg].ar_bytes); |
c97d6d2c SAGDR |
57 | } |
58 | ||
6701d81d | 59 | uint64_t vmx_read_segment_base(CPUState *cpu, X86Seg seg) |
c97d6d2c | 60 | { |
b533450e | 61 | return rvmcs(cpu->hvf->fd, vmx_segment_fields[seg].base); |
c97d6d2c SAGDR |
62 | } |
63 | ||
6701d81d | 64 | x68_segment_selector vmx_read_segment_selector(CPUState *cpu, X86Seg seg) |
c97d6d2c SAGDR |
65 | { |
66 | x68_segment_selector sel; | |
b533450e | 67 | sel.sel = rvmcs(cpu->hvf->fd, vmx_segment_fields[seg].selector); |
c97d6d2c SAGDR |
68 | return sel; |
69 | } | |
70 | ||
6701d81d | 71 | void vmx_write_segment_selector(struct CPUState *cpu, x68_segment_selector selector, X86Seg seg) |
c97d6d2c | 72 | { |
b533450e | 73 | wvmcs(cpu->hvf->fd, vmx_segment_fields[seg].selector, selector.sel); |
c97d6d2c SAGDR |
74 | } |
75 | ||
6701d81d | 76 | void vmx_read_segment_descriptor(struct CPUState *cpu, struct vmx_segment *desc, X86Seg seg) |
c97d6d2c | 77 | { |
b533450e AG |
78 | desc->sel = rvmcs(cpu->hvf->fd, vmx_segment_fields[seg].selector); |
79 | desc->base = rvmcs(cpu->hvf->fd, vmx_segment_fields[seg].base); | |
80 | desc->limit = rvmcs(cpu->hvf->fd, vmx_segment_fields[seg].limit); | |
81 | desc->ar = rvmcs(cpu->hvf->fd, vmx_segment_fields[seg].ar_bytes); | |
c97d6d2c SAGDR |
82 | } |
83 | ||
6701d81d | 84 | void vmx_write_segment_descriptor(CPUState *cpu, struct vmx_segment *desc, X86Seg seg) |
c97d6d2c SAGDR |
85 | { |
86 | const struct vmx_segment_field *sf = &vmx_segment_fields[seg]; | |
87 | ||
b533450e AG |
88 | wvmcs(cpu->hvf->fd, sf->base, desc->base); |
89 | wvmcs(cpu->hvf->fd, sf->limit, desc->limit); | |
90 | wvmcs(cpu->hvf->fd, sf->selector, desc->sel); | |
91 | wvmcs(cpu->hvf->fd, sf->ar_bytes, desc->ar); | |
c97d6d2c SAGDR |
92 | } |
93 | ||
94 | void x86_segment_descriptor_to_vmx(struct CPUState *cpu, x68_segment_selector selector, struct x86_segment_descriptor *desc, struct vmx_segment *vmx_desc) | |
95 | { | |
96 | vmx_desc->sel = selector.sel; | |
97 | vmx_desc->base = x86_segment_base(desc); | |
98 | vmx_desc->limit = x86_segment_limit(desc); | |
99 | ||
100 | vmx_desc->ar = (selector.sel ? 0 : 1) << 16 | | |
101 | desc->g << 15 | | |
102 | desc->db << 14 | | |
103 | desc->l << 13 | | |
104 | desc->avl << 12 | | |
105 | desc->p << 7 | | |
106 | desc->dpl << 5 | | |
107 | desc->s << 4 | | |
108 | desc->type; | |
109 | } | |
110 | ||
111 | void vmx_segment_to_x86_descriptor(struct CPUState *cpu, struct vmx_segment *vmx_desc, struct x86_segment_descriptor *desc) | |
112 | { | |
113 | x86_set_segment_limit(desc, vmx_desc->limit); | |
114 | x86_set_segment_base(desc, vmx_desc->base); | |
115 | ||
116 | desc->type = vmx_desc->ar & 15; | |
117 | desc->s = (vmx_desc->ar >> 4) & 1; | |
118 | desc->dpl = (vmx_desc->ar >> 5) & 3; | |
119 | desc->p = (vmx_desc->ar >> 7) & 1; | |
120 | desc->avl = (vmx_desc->ar >> 12) & 1; | |
121 | desc->l = (vmx_desc->ar >> 13) & 1; | |
122 | desc->db = (vmx_desc->ar >> 14) & 1; | |
123 | desc->g = (vmx_desc->ar >> 15) & 1; | |
124 | } | |
125 |