Sergio Andres Gomez Del Real | c97d6d2 | 2017-09-13 04:05:09 -0500 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 Veertu Inc, |
| 3 | * Copyright (C) 2017 Veertu Inc, |
| 4 | * |
| 5 | * This program is free software; you can redistribute it and/or |
Sergio Andres Gomez Del Real | 996feed | 2017-09-13 04:05:11 -0500 | [diff] [blame] | 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. |
Sergio Andres Gomez Del Real | c97d6d2 | 2017-09-13 04:05:09 -0500 | [diff] [blame] | 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 |
Sergio Andres Gomez Del Real | 996feed | 2017-09-13 04:05:11 -0500 | [diff] [blame] | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 | * Lesser General Public License for more details. |
Sergio Andres Gomez Del Real | c97d6d2 | 2017-09-13 04:05:09 -0500 | [diff] [blame] | 14 | * |
Sergio Andres Gomez Del Real | 996feed | 2017-09-13 04:05:11 -0500 | [diff] [blame] | 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/>. |
Sergio Andres Gomez Del Real | c97d6d2 | 2017-09-13 04:05:09 -0500 | [diff] [blame] | 17 | */ |
| 18 | |
Paolo Bonzini | f9fea77 | 2017-10-03 15:36:05 +0200 | [diff] [blame] | 19 | #ifndef HVF_X86_H |
| 20 | #define HVF_X86_H 1 |
Sergio Andres Gomez Del Real | c97d6d2 | 2017-09-13 04:05:09 -0500 | [diff] [blame] | 21 | |
Sergio Andres Gomez Del Real | c97d6d2 | 2017-09-13 04:05:09 -0500 | [diff] [blame] | 22 | #include "x86_gen.h" |
| 23 | |
Sergio Andres Gomez Del Real | c97d6d2 | 2017-09-13 04:05:09 -0500 | [diff] [blame] | 24 | typedef struct x86_register { |
| 25 | union { |
| 26 | struct { |
| 27 | uint64_t rrx; /* full 64 bit */ |
| 28 | }; |
| 29 | struct { |
| 30 | uint32_t erx; /* low 32 bit part */ |
| 31 | uint32_t hi32_unused1; |
| 32 | }; |
| 33 | struct { |
| 34 | uint16_t rx; /* low 16 bit part */ |
| 35 | uint16_t hi16_unused1; |
| 36 | uint32_t hi32_unused2; |
| 37 | }; |
| 38 | struct { |
| 39 | uint8_t lx; /* low 8 bit part */ |
| 40 | uint8_t hx; /* high 8 bit */ |
| 41 | uint16_t hi16_unused2; |
| 42 | uint32_t hi32_unused3; |
| 43 | }; |
| 44 | }; |
| 45 | } __attribute__ ((__packed__)) x86_register; |
| 46 | |
| 47 | typedef enum x86_rflags { |
| 48 | RFLAGS_CF = (1L << 0), |
| 49 | RFLAGS_PF = (1L << 2), |
| 50 | RFLAGS_AF = (1L << 4), |
| 51 | RFLAGS_ZF = (1L << 6), |
| 52 | RFLAGS_SF = (1L << 7), |
| 53 | RFLAGS_TF = (1L << 8), |
| 54 | RFLAGS_IF = (1L << 9), |
| 55 | RFLAGS_DF = (1L << 10), |
| 56 | RFLAGS_OF = (1L << 11), |
| 57 | RFLAGS_IOPL = (3L << 12), |
| 58 | RFLAGS_NT = (1L << 14), |
| 59 | RFLAGS_RF = (1L << 16), |
| 60 | RFLAGS_VM = (1L << 17), |
| 61 | RFLAGS_AC = (1L << 18), |
| 62 | RFLAGS_VIF = (1L << 19), |
| 63 | RFLAGS_VIP = (1L << 20), |
| 64 | RFLAGS_ID = (1L << 21), |
| 65 | } x86_rflags; |
| 66 | |
| 67 | /* rflags register */ |
| 68 | typedef struct x86_reg_flags { |
| 69 | union { |
| 70 | struct { |
| 71 | uint64_t rflags; |
| 72 | }; |
| 73 | struct { |
| 74 | uint32_t eflags; |
| 75 | uint32_t hi32_unused1; |
| 76 | }; |
| 77 | struct { |
| 78 | uint32_t cf:1; |
| 79 | uint32_t unused1:1; |
| 80 | uint32_t pf:1; |
| 81 | uint32_t unused2:1; |
| 82 | uint32_t af:1; |
| 83 | uint32_t unused3:1; |
| 84 | uint32_t zf:1; |
| 85 | uint32_t sf:1; |
| 86 | uint32_t tf:1; |
| 87 | uint32_t ief:1; |
| 88 | uint32_t df:1; |
| 89 | uint32_t of:1; |
| 90 | uint32_t iopl:2; |
| 91 | uint32_t nt:1; |
| 92 | uint32_t unused4:1; |
| 93 | uint32_t rf:1; |
| 94 | uint32_t vm:1; |
| 95 | uint32_t ac:1; |
| 96 | uint32_t vif:1; |
| 97 | uint32_t vip:1; |
| 98 | uint32_t id:1; |
| 99 | uint32_t unused5:10; |
| 100 | uint32_t hi32_unused2; |
| 101 | }; |
| 102 | }; |
| 103 | } __attribute__ ((__packed__)) x86_reg_flags; |
| 104 | |
Sergio Andres Gomez Del Real | c97d6d2 | 2017-09-13 04:05:09 -0500 | [diff] [blame] | 105 | typedef enum x86_reg_cr0 { |
| 106 | CR0_PE = (1L << 0), |
| 107 | CR0_MP = (1L << 1), |
| 108 | CR0_EM = (1L << 2), |
| 109 | CR0_TS = (1L << 3), |
| 110 | CR0_ET = (1L << 4), |
| 111 | CR0_NE = (1L << 5), |
| 112 | CR0_WP = (1L << 16), |
| 113 | CR0_AM = (1L << 18), |
| 114 | CR0_NW = (1L << 29), |
| 115 | CR0_CD = (1L << 30), |
| 116 | CR0_PG = (1L << 31), |
| 117 | } x86_reg_cr0; |
| 118 | |
| 119 | typedef enum x86_reg_cr4 { |
| 120 | CR4_VME = (1L << 0), |
| 121 | CR4_PVI = (1L << 1), |
| 122 | CR4_TSD = (1L << 2), |
| 123 | CR4_DE = (1L << 3), |
| 124 | CR4_PSE = (1L << 4), |
| 125 | CR4_PAE = (1L << 5), |
| 126 | CR4_MSE = (1L << 6), |
| 127 | CR4_PGE = (1L << 7), |
| 128 | CR4_PCE = (1L << 8), |
| 129 | CR4_OSFXSR = (1L << 9), |
| 130 | CR4_OSXMMEXCPT = (1L << 10), |
| 131 | CR4_VMXE = (1L << 13), |
| 132 | CR4_SMXE = (1L << 14), |
| 133 | CR4_FSGSBASE = (1L << 16), |
| 134 | CR4_PCIDE = (1L << 17), |
| 135 | CR4_OSXSAVE = (1L << 18), |
| 136 | CR4_SMEP = (1L << 20), |
| 137 | } x86_reg_cr4; |
| 138 | |
| 139 | /* 16 bit Task State Segment */ |
| 140 | typedef struct x86_tss_segment16 { |
| 141 | uint16_t link; |
| 142 | uint16_t sp0; |
| 143 | uint16_t ss0; |
| 144 | uint32_t sp1; |
| 145 | uint16_t ss1; |
| 146 | uint32_t sp2; |
| 147 | uint16_t ss2; |
| 148 | uint16_t ip; |
| 149 | uint16_t flags; |
| 150 | uint16_t ax; |
| 151 | uint16_t cx; |
| 152 | uint16_t dx; |
| 153 | uint16_t bx; |
| 154 | uint16_t sp; |
| 155 | uint16_t bp; |
| 156 | uint16_t si; |
| 157 | uint16_t di; |
| 158 | uint16_t es; |
| 159 | uint16_t cs; |
| 160 | uint16_t ss; |
| 161 | uint16_t ds; |
| 162 | uint16_t ldtr; |
| 163 | } __attribute__((packed)) x86_tss_segment16; |
| 164 | |
| 165 | /* 32 bit Task State Segment */ |
| 166 | typedef struct x86_tss_segment32 { |
| 167 | uint32_t prev_tss; |
| 168 | uint32_t esp0; |
| 169 | uint32_t ss0; |
| 170 | uint32_t esp1; |
| 171 | uint32_t ss1; |
| 172 | uint32_t esp2; |
| 173 | uint32_t ss2; |
| 174 | uint32_t cr3; |
| 175 | uint32_t eip; |
| 176 | uint32_t eflags; |
| 177 | uint32_t eax; |
| 178 | uint32_t ecx; |
| 179 | uint32_t edx; |
| 180 | uint32_t ebx; |
| 181 | uint32_t esp; |
| 182 | uint32_t ebp; |
| 183 | uint32_t esi; |
| 184 | uint32_t edi; |
| 185 | uint32_t es; |
| 186 | uint32_t cs; |
| 187 | uint32_t ss; |
| 188 | uint32_t ds; |
| 189 | uint32_t fs; |
| 190 | uint32_t gs; |
| 191 | uint32_t ldt; |
| 192 | uint16_t trap; |
| 193 | uint16_t iomap_base; |
| 194 | } __attribute__ ((__packed__)) x86_tss_segment32; |
| 195 | |
| 196 | /* 64 bit Task State Segment */ |
| 197 | typedef struct x86_tss_segment64 { |
| 198 | uint32_t unused; |
| 199 | uint64_t rsp0; |
| 200 | uint64_t rsp1; |
| 201 | uint64_t rsp2; |
| 202 | uint64_t unused1; |
| 203 | uint64_t ist1; |
| 204 | uint64_t ist2; |
| 205 | uint64_t ist3; |
| 206 | uint64_t ist4; |
| 207 | uint64_t ist5; |
| 208 | uint64_t ist6; |
| 209 | uint64_t ist7; |
| 210 | uint64_t unused2; |
| 211 | uint16_t unused3; |
| 212 | uint16_t iomap_base; |
| 213 | } __attribute__ ((__packed__)) x86_tss_segment64; |
| 214 | |
| 215 | /* segment descriptors */ |
| 216 | typedef struct x86_segment_descriptor { |
| 217 | uint64_t limit0:16; |
| 218 | uint64_t base0:16; |
| 219 | uint64_t base1:8; |
| 220 | uint64_t type:4; |
| 221 | uint64_t s:1; |
| 222 | uint64_t dpl:2; |
| 223 | uint64_t p:1; |
| 224 | uint64_t limit1:4; |
| 225 | uint64_t avl:1; |
| 226 | uint64_t l:1; |
| 227 | uint64_t db:1; |
| 228 | uint64_t g:1; |
| 229 | uint64_t base2:8; |
| 230 | } __attribute__ ((__packed__)) x86_segment_descriptor; |
| 231 | |
| 232 | static inline uint32_t x86_segment_base(x86_segment_descriptor *desc) |
| 233 | { |
| 234 | return (uint32_t)((desc->base2 << 24) | (desc->base1 << 16) | desc->base0); |
| 235 | } |
| 236 | |
| 237 | static inline void x86_set_segment_base(x86_segment_descriptor *desc, |
| 238 | uint32_t base) |
| 239 | { |
| 240 | desc->base2 = base >> 24; |
| 241 | desc->base1 = (base >> 16) & 0xff; |
| 242 | desc->base0 = base & 0xffff; |
| 243 | } |
| 244 | |
| 245 | static inline uint32_t x86_segment_limit(x86_segment_descriptor *desc) |
| 246 | { |
| 247 | uint32_t limit = (uint32_t)((desc->limit1 << 16) | desc->limit0); |
| 248 | if (desc->g) { |
| 249 | return (limit << 12) | 0xfff; |
| 250 | } |
| 251 | return limit; |
| 252 | } |
| 253 | |
| 254 | static inline void x86_set_segment_limit(x86_segment_descriptor *desc, |
| 255 | uint32_t limit) |
| 256 | { |
| 257 | desc->limit0 = limit & 0xffff; |
| 258 | desc->limit1 = limit >> 16; |
| 259 | } |
| 260 | |
| 261 | typedef struct x86_call_gate { |
| 262 | uint64_t offset0:16; |
| 263 | uint64_t selector:16; |
| 264 | uint64_t param_count:4; |
| 265 | uint64_t reserved:3; |
| 266 | uint64_t type:4; |
| 267 | uint64_t dpl:1; |
| 268 | uint64_t p:1; |
| 269 | uint64_t offset1:16; |
| 270 | } __attribute__ ((__packed__)) x86_call_gate; |
| 271 | |
| 272 | static inline uint32_t x86_call_gate_offset(x86_call_gate *gate) |
| 273 | { |
| 274 | return (uint32_t)((gate->offset1 << 16) | gate->offset0); |
| 275 | } |
| 276 | |
| 277 | #define LDT_SEL 0 |
| 278 | #define GDT_SEL 1 |
| 279 | |
| 280 | typedef struct x68_segment_selector { |
| 281 | union { |
| 282 | uint16_t sel; |
| 283 | struct { |
| 284 | uint16_t rpl:3; |
| 285 | uint16_t ti:1; |
| 286 | uint16_t index:12; |
| 287 | }; |
| 288 | }; |
| 289 | } __attribute__ ((__packed__)) x68_segment_selector; |
| 290 | |
| 291 | typedef struct lazy_flags { |
Paolo Bonzini | ff2de16 | 2017-10-03 15:17:37 +0200 | [diff] [blame^] | 292 | target_ulong result; |
| 293 | target_ulong auxbits; |
Sergio Andres Gomez Del Real | c97d6d2 | 2017-09-13 04:05:09 -0500 | [diff] [blame] | 294 | } lazy_flags; |
| 295 | |
| 296 | /* Definition of hvf_x86_state is here */ |
| 297 | struct HVFX86EmulatorState { |
| 298 | int interruptable; |
| 299 | uint64_t fetch_rip; |
| 300 | uint64_t rip; |
| 301 | struct x86_register regs[16]; |
| 302 | struct x86_reg_flags rflags; |
| 303 | struct lazy_flags lflags; |
Sergio Andres Gomez Del Real | c97d6d2 | 2017-09-13 04:05:09 -0500 | [diff] [blame] | 304 | uint8_t mmio_buf[4096]; |
| 305 | }; |
| 306 | |
Sergio Andres Gomez Del Real | c97d6d2 | 2017-09-13 04:05:09 -0500 | [diff] [blame] | 307 | /* useful register access macros */ |
| 308 | #define RIP(cpu) (cpu->hvf_emul->rip) |
| 309 | #define EIP(cpu) ((uint32_t)cpu->hvf_emul->rip) |
| 310 | #define RFLAGS(cpu) (cpu->hvf_emul->rflags.rflags) |
| 311 | #define EFLAGS(cpu) (cpu->hvf_emul->rflags.eflags) |
| 312 | |
| 313 | #define RRX(cpu, reg) (cpu->hvf_emul->regs[reg].rrx) |
Paolo Bonzini | 6701d81 | 2017-10-03 13:59:15 +0200 | [diff] [blame] | 314 | #define RAX(cpu) RRX(cpu, R_EAX) |
| 315 | #define RCX(cpu) RRX(cpu, R_ECX) |
| 316 | #define RDX(cpu) RRX(cpu, R_EDX) |
| 317 | #define RBX(cpu) RRX(cpu, R_EBX) |
| 318 | #define RSP(cpu) RRX(cpu, R_ESP) |
| 319 | #define RBP(cpu) RRX(cpu, R_EBP) |
| 320 | #define RSI(cpu) RRX(cpu, R_ESI) |
| 321 | #define RDI(cpu) RRX(cpu, R_EDI) |
| 322 | #define R8(cpu) RRX(cpu, R_R8) |
| 323 | #define R9(cpu) RRX(cpu, R_R9) |
| 324 | #define R10(cpu) RRX(cpu, R_R10) |
| 325 | #define R11(cpu) RRX(cpu, R_R11) |
| 326 | #define R12(cpu) RRX(cpu, R_R12) |
| 327 | #define R13(cpu) RRX(cpu, R_R13) |
| 328 | #define R14(cpu) RRX(cpu, R_R14) |
| 329 | #define R15(cpu) RRX(cpu, R_R15) |
Sergio Andres Gomez Del Real | c97d6d2 | 2017-09-13 04:05:09 -0500 | [diff] [blame] | 330 | |
| 331 | #define ERX(cpu, reg) (cpu->hvf_emul->regs[reg].erx) |
Paolo Bonzini | 6701d81 | 2017-10-03 13:59:15 +0200 | [diff] [blame] | 332 | #define EAX(cpu) ERX(cpu, R_EAX) |
| 333 | #define ECX(cpu) ERX(cpu, R_ECX) |
| 334 | #define EDX(cpu) ERX(cpu, R_EDX) |
| 335 | #define EBX(cpu) ERX(cpu, R_EBX) |
| 336 | #define ESP(cpu) ERX(cpu, R_ESP) |
| 337 | #define EBP(cpu) ERX(cpu, R_EBP) |
| 338 | #define ESI(cpu) ERX(cpu, R_ESI) |
| 339 | #define EDI(cpu) ERX(cpu, R_EDI) |
Sergio Andres Gomez Del Real | c97d6d2 | 2017-09-13 04:05:09 -0500 | [diff] [blame] | 340 | |
| 341 | #define RX(cpu, reg) (cpu->hvf_emul->regs[reg].rx) |
Paolo Bonzini | 6701d81 | 2017-10-03 13:59:15 +0200 | [diff] [blame] | 342 | #define AX(cpu) RX(cpu, R_EAX) |
| 343 | #define CX(cpu) RX(cpu, R_ECX) |
| 344 | #define DX(cpu) RX(cpu, R_EDX) |
| 345 | #define BP(cpu) RX(cpu, R_EBP) |
| 346 | #define SP(cpu) RX(cpu, R_ESP) |
| 347 | #define BX(cpu) RX(cpu, R_EBX) |
| 348 | #define SI(cpu) RX(cpu, R_ESI) |
| 349 | #define DI(cpu) RX(cpu, R_EDI) |
Sergio Andres Gomez Del Real | c97d6d2 | 2017-09-13 04:05:09 -0500 | [diff] [blame] | 350 | |
| 351 | #define RL(cpu, reg) (cpu->hvf_emul->regs[reg].lx) |
Paolo Bonzini | 6701d81 | 2017-10-03 13:59:15 +0200 | [diff] [blame] | 352 | #define AL(cpu) RL(cpu, R_EAX) |
| 353 | #define CL(cpu) RL(cpu, R_ECX) |
| 354 | #define DL(cpu) RL(cpu, R_EDX) |
| 355 | #define BL(cpu) RL(cpu, R_EBX) |
Sergio Andres Gomez Del Real | c97d6d2 | 2017-09-13 04:05:09 -0500 | [diff] [blame] | 356 | |
| 357 | #define RH(cpu, reg) (cpu->hvf_emul->regs[reg].hx) |
Paolo Bonzini | 6701d81 | 2017-10-03 13:59:15 +0200 | [diff] [blame] | 358 | #define AH(cpu) RH(cpu, R_EAX) |
| 359 | #define CH(cpu) RH(cpu, R_ECX) |
| 360 | #define DH(cpu) RH(cpu, R_EDX) |
| 361 | #define BH(cpu) RH(cpu, R_EBX) |
Sergio Andres Gomez Del Real | c97d6d2 | 2017-09-13 04:05:09 -0500 | [diff] [blame] | 362 | |
| 363 | /* deal with GDT/LDT descriptors in memory */ |
| 364 | bool x86_read_segment_descriptor(struct CPUState *cpu, |
| 365 | struct x86_segment_descriptor *desc, |
| 366 | x68_segment_selector sel); |
| 367 | bool x86_write_segment_descriptor(struct CPUState *cpu, |
| 368 | struct x86_segment_descriptor *desc, |
| 369 | x68_segment_selector sel); |
| 370 | |
| 371 | bool x86_read_call_gate(struct CPUState *cpu, struct x86_call_gate *idt_desc, |
| 372 | int gate); |
| 373 | |
| 374 | /* helpers */ |
| 375 | bool x86_is_protected(struct CPUState *cpu); |
| 376 | bool x86_is_real(struct CPUState *cpu); |
| 377 | bool x86_is_v8086(struct CPUState *cpu); |
| 378 | bool x86_is_long_mode(struct CPUState *cpu); |
| 379 | bool x86_is_long64_mode(struct CPUState *cpu); |
| 380 | bool x86_is_paging_mode(struct CPUState *cpu); |
| 381 | bool x86_is_pae_enabled(struct CPUState *cpu); |
| 382 | |
Paolo Bonzini | 6701d81 | 2017-10-03 13:59:15 +0200 | [diff] [blame] | 383 | enum X86Seg; |
Paolo Bonzini | ff2de16 | 2017-10-03 15:17:37 +0200 | [diff] [blame^] | 384 | target_ulong linear_addr(struct CPUState *cpu, target_ulong addr, enum X86Seg seg); |
| 385 | target_ulong linear_addr_size(struct CPUState *cpu, target_ulong addr, int size, |
| 386 | enum X86Seg seg); |
| 387 | target_ulong linear_rip(struct CPUState *cpu, target_ulong rip); |
Sergio Andres Gomez Del Real | c97d6d2 | 2017-09-13 04:05:09 -0500 | [diff] [blame] | 388 | |
| 389 | static inline uint64_t rdtscp(void) |
| 390 | { |
| 391 | uint64_t tsc; |
| 392 | __asm__ __volatile__("rdtscp; " /* serializing read of tsc */ |
| 393 | "shl $32,%%rdx; " /* shift higher 32 bits stored in rdx up */ |
| 394 | "or %%rdx,%%rax" /* and or onto rax */ |
| 395 | : "=a"(tsc) /* output to tsc variable */ |
| 396 | : |
| 397 | : "%rcx", "%rdx"); /* rcx and rdx are clobbered */ |
| 398 | |
| 399 | return tsc; |
| 400 | } |
| 401 | |
Paolo Bonzini | f9fea77 | 2017-10-03 15:36:05 +0200 | [diff] [blame] | 402 | #endif |