| /* |
| * 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 |