aboutsummaryrefslogtreecommitdiff
path: root/target/i386/hvf/x86.h
blob: bacade7b658d402bfade1b431dd0e7e765592621 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
/*
 * Copyright (C) 2016 Veertu Inc,
 * Copyright (C) 2017 Veertu Inc,
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

#ifndef HVF_X86_H
#define HVF_X86_H

typedef struct x86_register {
    union {
        struct {
            uint64_t rrx;               /* full 64 bit */
        };
        struct {
            uint32_t erx;               /* low 32 bit part */
            uint32_t hi32_unused1;
        };
        struct {
            uint16_t rx;                /* low 16 bit part */
            uint16_t hi16_unused1;
            uint32_t hi32_unused2;
        };
        struct {
            uint8_t lx;                 /* low 8 bit part */
            uint8_t hx;                 /* high 8 bit */
            uint16_t hi16_unused2;
            uint32_t hi32_unused3;
        };
    };
} __attribute__ ((__packed__)) x86_register;

typedef enum x86_reg_cr0 {
    CR0_PE =            (1L << 0),
    CR0_MP =            (1L << 1),
    CR0_EM =            (1L << 2),
    CR0_TS =            (1L << 3),
    CR0_ET =            (1L << 4),
    CR0_NE =            (1L << 5),
    CR0_WP =            (1L << 16),
    CR0_AM =            (1L << 18),
    CR0_NW =            (1L << 29),
    CR0_CD =            (1L << 30),
    CR0_PG =            (1L << 31),
} x86_reg_cr0;

typedef enum x86_reg_cr4 {
    CR4_VME =            (1L << 0),
    CR4_PVI =            (1L << 1),
    CR4_TSD =            (1L << 2),
    CR4_DE  =            (1L << 3),
    CR4_PSE =            (1L << 4),
    CR4_PAE =            (1L << 5),
    CR4_MSE =            (1L << 6),
    CR4_PGE =            (1L << 7),
    CR4_PCE =            (1L << 8),
    CR4_OSFXSR =         (1L << 9),
    CR4_OSXMMEXCPT =     (1L << 10),
    CR4_VMXE =           (1L << 13),
    CR4_SMXE =           (1L << 14),
    CR4_FSGSBASE =       (1L << 16),
    CR4_PCIDE =          (1L << 17),
    CR4_OSXSAVE =        (1L << 18),
    CR4_SMEP =           (1L << 20),
} x86_reg_cr4;

/* 16 bit Task State Segment */
typedef struct x86_tss_segment16 {
    uint16_t link;
    uint16_t sp0;
    uint16_t ss0;
    uint32_t sp1;
    uint16_t ss1;
    uint32_t sp2;
    uint16_t ss2;
    uint16_t ip;
    uint16_t flags;
    uint16_t ax;
    uint16_t cx;
    uint16_t dx;
    uint16_t bx;
    uint16_t sp;
    uint16_t bp;
    uint16_t si;
    uint16_t di;
    uint16_t es;
    uint16_t cs;
    uint16_t ss;
    uint16_t ds;
    uint16_t ldtr;
} __attribute__((packed)) x86_tss_segment16;

/* 32 bit Task State Segment */
typedef struct x86_tss_segment32 {
    uint32_t prev_tss;
    uint32_t esp0;
    uint32_t ss0;
    uint32_t esp1;
    uint32_t ss1;
    uint32_t esp2;
    uint32_t ss2;
    uint32_t cr3;
    uint32_t eip;
    uint32_t eflags;
    uint32_t eax;
    uint32_t ecx;
    uint32_t edx;
    uint32_t ebx;
    uint32_t esp;
    uint32_t ebp;
    uint32_t esi;
    uint32_t edi;
    uint32_t es;
    uint32_t cs;
    uint32_t ss;
    uint32_t ds;
    uint32_t fs;
    uint32_t gs;
    uint32_t ldt;
    uint16_t trap;
    uint16_t iomap_base;
} __attribute__ ((__packed__)) x86_tss_segment32;

/* 64 bit Task State Segment */
typedef struct x86_tss_segment64 {
    uint32_t unused;
    uint64_t rsp0;
    uint64_t rsp1;
    uint64_t rsp2;
    uint64_t unused1;
    uint64_t ist1;
    uint64_t ist2;
    uint64_t ist3;
    uint64_t ist4;
    uint64_t ist5;
    uint64_t ist6;
    uint64_t ist7;
    uint64_t unused2;
    uint16_t unused3;
    uint16_t iomap_base;
} __attribute__ ((__packed__)) x86_tss_segment64;

/* segment descriptors */
typedef struct x86_segment_descriptor {
    uint64_t    limit0:16;
    uint64_t    base0:16;
    uint64_t    base1:8;
    uint64_t    type:4;
    uint64_t    s:1;
    uint64_t    dpl:2;
    uint64_t    p:1;
    uint64_t    limit1:4;
    uint64_t    avl:1;
    uint64_t    l:1;
    uint64_t    db:1;
    uint64_t    g:1;
    uint64_t    base2:8;
} __attribute__ ((__packed__)) x86_segment_descriptor;

static inline uint32_t x86_segment_base(x86_segment_descriptor *desc)
{
    return (uint32_t)((desc->base2 << 24) | (desc->base1 << 16) | desc->base0);
}

static inline void x86_set_segment_base(x86_segment_descriptor *desc,
                                        uint32_t base)
{
    desc->base2 = base >> 24;
    desc->base1 = (base >> 16) & 0xff;
    desc->base0 = base & 0xffff;
}

static inline uint32_t x86_segment_limit(x86_segment_descriptor *desc)
{
    uint32_t limit = (uint32_t)((desc->limit1 << 16) | desc->limit0);
    if (desc->g) {
        return (limit << 12) | 0xfff;
    }
    return limit;
}

static inline void x86_set_segment_limit(x86_segment_descriptor *desc,
                                         uint32_t limit)
{
    desc->limit0 = limit & 0xffff;
    desc->limit1 = limit >> 16;
}

typedef struct x86_call_gate {
    uint64_t offset0:16;
    uint64_t selector:16;
    uint64_t param_count:4;
    uint64_t reserved:3;
    uint64_t type:4;
    uint64_t dpl:1;
    uint64_t p:1;
    uint64_t offset1:16;
} __attribute__ ((__packed__)) x86_call_gate;

static inline uint32_t x86_call_gate_offset(x86_call_gate *gate)
{
    return (uint32_t)((gate->offset1 << 16) | gate->offset0);
}

#define LDT_SEL     0
#define GDT_SEL     1

typedef struct x68_segment_selector {
    union {
        uint16_t sel;
        struct {
            uint16_t rpl:3;
            uint16_t ti:1;
            uint16_t index:12;
        };
    };
} __attribute__ ((__packed__)) x68_segment_selector;

/* useful register access  macros */
#define x86_reg(cpu, reg) ((x86_register *) &cpu->regs[reg])

#define RRX(cpu, reg)   (x86_reg(cpu, reg)->rrx)
#define RAX(cpu)        RRX(cpu, R_EAX)
#define RCX(cpu)        RRX(cpu, R_ECX)
#define RDX(cpu)        RRX(cpu, R_EDX)
#define RBX(cpu)        RRX(cpu, R_EBX)
#define RSP(cpu)        RRX(cpu, R_ESP)
#define RBP(cpu)        RRX(cpu, R_EBP)
#define RSI(cpu)        RRX(cpu, R_ESI)
#define RDI(cpu)        RRX(cpu, R_EDI)
#define R8(cpu)         RRX(cpu, R_R8)
#define R9(cpu)         RRX(cpu, R_R9)
#define R10(cpu)        RRX(cpu, R_R10)
#define R11(cpu)        RRX(cpu, R_R11)
#define R12(cpu)        RRX(cpu, R_R12)
#define R13(cpu)        RRX(cpu, R_R13)
#define R14(cpu)        RRX(cpu, R_R14)
#define R15(cpu)        RRX(cpu, R_R15)

#define ERX(cpu, reg)   (x86_reg(cpu, reg)->erx)
#define EAX(cpu)        ERX(cpu, R_EAX)
#define ECX(cpu)        ERX(cpu, R_ECX)
#define EDX(cpu)        ERX(cpu, R_EDX)
#define EBX(cpu)        ERX(cpu, R_EBX)
#define ESP(cpu)        ERX(cpu, R_ESP)
#define EBP(cpu)        ERX(cpu, R_EBP)
#define ESI(cpu)        ERX(cpu, R_ESI)
#define EDI(cpu)        ERX(cpu, R_EDI)

#define RX(cpu, reg)   (x86_reg(cpu, reg)->rx)
#define AX(cpu)        RX(cpu, R_EAX)
#define CX(cpu)        RX(cpu, R_ECX)
#define DX(cpu)        RX(cpu, R_EDX)
#define BP(cpu)        RX(cpu, R_EBP)
#define SP(cpu)        RX(cpu, R_ESP)
#define BX(cpu)        RX(cpu, R_EBX)
#define SI(cpu)        RX(cpu, R_ESI)
#define DI(cpu)        RX(cpu, R_EDI)

#define RL(cpu, reg)   (x86_reg(cpu, reg)->lx)
#define AL(cpu)        RL(cpu, R_EAX)
#define CL(cpu)        RL(cpu, R_ECX)
#define DL(cpu)        RL(cpu, R_EDX)
#define BL(cpu)        RL(cpu, R_EBX)

#define RH(cpu, reg)   (x86_reg(cpu, reg)->hx)
#define AH(cpu)        RH(cpu, R_EAX)
#define CH(cpu)        RH(cpu, R_ECX)
#define DH(cpu)        RH(cpu, R_EDX)
#define BH(cpu)        RH(cpu, R_EBX)

/* deal with GDT/LDT descriptors in memory */
bool x86_read_segment_descriptor(struct CPUState *cpu,
                                 struct x86_segment_descriptor *desc,
                                 x68_segment_selector sel);
bool x86_write_segment_descriptor(struct CPUState *cpu,
                                  struct x86_segment_descriptor *desc,
                                  x68_segment_selector sel);

bool x86_read_call_gate(struct CPUState *cpu, struct x86_call_gate *idt_desc,
                        int gate);

/* helpers */
bool x86_is_protected(struct CPUState *cpu);
bool x86_is_real(struct CPUState *cpu);
bool x86_is_v8086(struct CPUState *cpu);
bool x86_is_long_mode(struct CPUState *cpu);
bool x86_is_long64_mode(struct CPUState *cpu);
bool x86_is_paging_mode(struct CPUState *cpu);
bool x86_is_pae_enabled(struct CPUState *cpu);

enum X86Seg;
target_ulong linear_addr(struct CPUState *cpu, target_ulong addr, enum X86Seg seg);
target_ulong linear_addr_size(struct CPUState *cpu, target_ulong addr, int size,
                              enum X86Seg seg);
target_ulong linear_rip(struct CPUState *cpu, target_ulong rip);

static inline uint64_t rdtscp(void)
{
    uint64_t tsc;
    __asm__ __volatile__("rdtscp; "         /* serializing read of tsc */
                         "shl $32,%%rdx; "  /* shift higher 32 bits stored in rdx up */
                         "or %%rdx,%%rax"   /* and or onto rax */
                         : "=a"(tsc)        /* output to tsc variable */
                         :
                         : "%rcx", "%rdx"); /* rcx and rdx are clobbered */

    return tsc;
}

#endif