blob: 9f231e71fbd69f5674508977301dfc3bcf30b4a1 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#pragma once
// This header is intended to be included in both C and ASM
#define X86_CR0_PE 0x00000001 /* protected mode enable */
#define X86_CR0_MP 0x00000002 /* monitor coprocessor */
#define X86_CR0_EM 0x00000004 /* emulation */
#define X86_CR0_TS 0x00000008 /* task switched */
#define X86_CR0_NE 0x00000020 /* enable x87 exception */
#define X86_CR0_WP 0x00010000 /* supervisor write protect */
#define X86_CR0_NW 0x20000000 /* not write-through */
#define X86_CR0_CD 0x40000000 /* cache disable */
#define X86_CR0_PG 0x80000000 /* enable paging */
#define X86_CR4_PAE 0x00000020 /* PAE paging */
#define X86_CR4_PGE 0x00000080 /* page global enable */
#define X86_CR4_OSFXSR 0x00000200 /* os supports fxsave */
#define X86_CR4_OSXMMEXPT 0x00000400 /* os supports xmm exception */
#define X86_CR4_UMIP 0x00000800 /* User-mode instruction prevention */
#define X86_CR4_VMXE 0x00002000 /* enable vmx */
#define X86_CR4_FSGSBASE 0x00010000 /* enable {rd,wr}{fs,gs}base */
#define X86_CR4_PCIDE 0x00020000 /* Process-context ID enable */
#define X86_CR4_OSXSAVE 0x00040000 /* os supports xsave */
#define X86_CR4_SMEP 0x00100000 /* SMEP protection enabling */
#define X86_CR4_SMAP 0x00200000 /* SMAP protection enabling */
#define X86_EFER_SCE 0x00000001 /* enable SYSCALL */
#define X86_EFER_LME 0x00000100 /* long mode enable */
#define X86_EFER_LMA 0x00000400 /* long mode active */
#define X86_EFER_NXE 0x00000800 /* to enable execute disable bit */
#define X86_MSR_IA32_PLATFORM_ID 0x00000017 /* platform id */
#define X86_MSR_IA32_APIC_BASE 0x0000001b /* APIC base physical address */
#define X86_MSR_IA32_TSC_ADJUST 0x0000003b /* TSC adjust */
#define X86_MSR_IA32_BIOS_SIGN_ID 0x0000008b /* BIOS update signature */
#define X86_MSR_IA32_MTRRCAP 0x000000fe /* MTRR capability */
#define X86_MSR_IA32_SYSENTER_CS 0x00000174 /* SYSENTER CS */
#define X86_MSR_IA32_SYSENTER_ESP 0x00000175 /* SYSENTER ESP */
#define X86_MSR_IA32_SYSENTER_EIP 0x00000176 /* SYSENTER EIP */
#define X86_MSR_IA32_MCG_CAP 0x00000179 /* global machine check capability */
#define X86_MSR_IA32_MCG_STATUS 0x0000017a /* global machine check status */
#define X86_MSR_IA32_MISC_ENABLE 0x000001a0 /* enable/disable misc processor features */
#define X86_MSR_IA32_TEMPERATURE_TARGET 0x000001a2 /* Temperature target */
#define X86_MSR_IA32_MTRR_PHYSBASE0 0x00000200 /* MTRR PhysBase0 */
#define X86_MSR_IA32_MTRR_PHYSMASK0 0x00000201 /* MTRR PhysMask0 */
#define X86_MSR_IA32_MTRR_PHYSMASK9 0x00000213 /* MTRR PhysMask9 */
#define X86_MSR_IA32_MTRR_DEF_TYPE 0x000002ff /* MTRR default type */
#define X86_MSR_IA32_MTRR_FIX64K_00000 0x00000250 /* MTRR FIX64K_00000 */
#define X86_MSR_IA32_MTRR_FIX16K_80000 0x00000258 /* MTRR FIX16K_80000 */
#define X86_MSR_IA32_MTRR_FIX16K_A0000 0x00000259 /* MTRR FIX16K_A0000 */
#define X86_MSR_IA32_MTRR_FIX4K_C0000 0x00000268 /* MTRR FIX4K_C0000 */
#define X86_MSR_IA32_MTRR_FIX4K_F8000 0x0000026f /* MTRR FIX4K_F8000 */
#define X86_MSR_IA32_PAT 0x00000277 /* PAT */
#define X86_MSR_IA32_TSC_DEADLINE 0x000006e0 /* TSC deadline */
#define X86_MSR_IA32_EFER 0xc0000080 /* EFER */
#define X86_MSR_IA32_STAR 0xc0000081 /* system call address */
#define X86_MSR_IA32_LSTAR 0xc0000082 /* long mode call address */
#define X86_MSR_IA32_CSTAR 0xc0000083 /* ia32-e compat call address */
#define X86_MSR_IA32_FMASK 0xc0000084 /* system call flag mask */
#define X86_MSR_IA32_FS_BASE 0xc0000100 /* fs base address */
#define X86_MSR_IA32_GS_BASE 0xc0000101 /* gs base address */
#define X86_MSR_IA32_KERNEL_GS_BASE 0xc0000102 /* kernel gs base */
#define X86_MSR_IA32_TSC_AUX 0xc0000103 /* TSC aux */
#define X86_MSR_IA32_PM_ENABLE 0x00000770 /* enable/disable HWP */
#define X86_MSR_IA32_HWP_CAPABILITIES 0x00000771 /* HWP performance range enumeration */
#define X86_MSR_IA32_HWP_REQUEST 0x00000774 /* power manage control hints */
#define X86_CR4_PSE 0xffffffef /* Disabling PSE bit in the CR4 */
// Non-architectural MSRs
#define X86_MSR_RAPL_POWER_UNIT 0x00000606 /* RAPL unit multipliers */
#define X86_MSR_PKG_POWER_LIMIT 0x00000610 /* Package power limits */
#define X86_MSR_PKG_POWER_LIMIT_PL1_CLAMP (1 << 16)
#define X86_MSR_PKG_POWER_LIMIT_PL1_ENABLE (1 << 15)
#define X86_MSR_PKG_ENERGY_STATUS 0x00000611 /* Package energy status */
#define X86_MSR_PKG_POWER_INFO 0x00000614 /* Package power range info */
#define X86_MSR_DRAM_POWER_LIMIT 0x00000618 /* DRAM RAPL power limit control */
#define X86_MSR_DRAM_ENERGY_STATUS 0x00000619 /* DRAM energy status */
#define X86_MSR_PP0_POWER_LIMIT 0x00000638 /* PP0 RAPL power limit control */
#define X86_MSR_PP0_ENERGY_STATUS 0x00000639 /* PP0 energy status */
#define X86_MSR_PP1_POWER_LIMIT 0x00000640 /* PP1 RAPL power limit control */
#define X86_MSR_PP1_ENERGY_STATUS 0x00000641 /* PP1 energy status */
#define X86_MSR_PLATFORM_ENERGY_COUNTER 0x0000064d /* Platform energy counter */
#define X86_MSR_PLATFORM_POWER_LIMIT 0x0000065c /* Platform power limit control */
/* EFLAGS/RFLAGS */
#define X86_FLAGS_CF (1<<0)
#define X86_FLAGS_PF (1<<2)
#define X86_FLAGS_AF (1<<4)
#define X86_FLAGS_ZF (1<<6)
#define X86_FLAGS_SF (1<<7)
#define X86_FLAGS_TF (1<<8)
#define X86_FLAGS_IF (1<<9)
#define X86_FLAGS_DF (1<<10)
#define X86_FLAGS_OF (1<<11)
#define X86_FLAGS_STATUS_MASK (0xfff)
#define X86_FLAGS_IOPL_MASK (3<<12)
#define X86_FLAGS_IOPL_SHIFT (12)
#define X86_FLAGS_NT (1<<14)
#define X86_FLAGS_RF (1<<16)
#define X86_FLAGS_VM (1<<17)
#define X86_FLAGS_AC (1<<18)
#define X86_FLAGS_VIF (1<<19)
#define X86_FLAGS_VIP (1<<20)
#define X86_FLAGS_ID (1<<21)
#define X86_FLAGS_RESERVED_ONES 0x2
#define X86_FLAGS_RESERVED 0xffc0802a
#define X86_FLAGS_USER (X86_FLAGS_CF | \
X86_FLAGS_PF | \
X86_FLAGS_AF | \
X86_FLAGS_ZF | \
X86_FLAGS_SF | \
X86_FLAGS_TF | \
X86_FLAGS_DF | \
X86_FLAGS_OF | \
X86_FLAGS_NT | \
X86_FLAGS_AC | \
X86_FLAGS_ID)
/* DR6 */
#define X86_DR6_B0 (1ul << 0)
#define X86_DR6_B1 (1ul << 1)
#define X86_DR6_B2 (1ul << 2)
#define X86_DR6_B3 (1ul << 3)
#define X86_DR6_BD (1ul << 13)
#define X86_DR6_BS (1ul << 14)
#define X86_DR6_BT (1ul << 15)
// NOTE: DR6 is used as a read-only status registers, and it is not writeable through userspace.
// Any bits attempted to be written will be ignored.
#define X86_DR6_USER_MASK (X86_DR6_B0 | \
X86_DR6_B1 | \
X86_DR6_B2 | \
X86_DR6_B3 | \
X86_DR6_BD | \
X86_DR6_BS | \
X86_DR6_BT)
/* Only bits in X86_DR6_USER_MASK are writeable.
* Bits 12 and 32:63 must be written with 0, the rest as 1s */
#define X86_DR6_MASK (0xffff0ff0ul)
/* DR7 */
#define X86_DR7_L0 (1ul << 0)
#define X86_DR7_G0 (1ul << 1)
#define X86_DR7_L1 (1ul << 2)
#define X86_DR7_G1 (1ul << 3)
#define X86_DR7_L2 (1ul << 4)
#define X86_DR7_G2 (1ul << 5)
#define X86_DR7_L3 (1ul << 6)
#define X86_DR7_G3 (1ul << 7)
#define X86_DR7_LE (1ul << 8)
#define X86_DR7_GE (1ul << 9)
#define X86_DR7_GD (1ul << 13)
#define X86_DR7_RW0 (3ul << 16)
#define X86_DR7_LEN0 (3ul << 18)
#define X86_DR7_RW1 (3ul << 20)
#define X86_DR7_LEN1 (3ul << 22)
#define X86_DR7_RW2 (3ul << 24)
#define X86_DR7_LEN2 (3ul << 26)
#define X86_DR7_RW3 (3ul << 28)
#define X86_DR7_LEN3 (3ul << 30)
// NOTE1: Even though the GD bit is writable, we disable it for the write_state syscall because it
// complicates a lot the reasoning about how to access the registers. This is because
// enabling this bit would make any other access to debug registers to issue an exception.
// New syscalls should be define to lock/unlock debug registers.
// NOTE2: LE/GE bits are normally ignored, but the manual recommends always setting it to 1 in
// order to be backwards compatible. Hence they are not writable from userspace.
#define X86_DR7_USER_MASK (X86_DR7_L0 | \
X86_DR7_G0 | \
X86_DR7_L1 | \
X86_DR7_G1 | \
X86_DR7_L2 | \
X86_DR7_G2 | \
X86_DR7_L3 | \
X86_DR7_G3 | \
X86_DR7_RW0 | \
X86_DR7_LEN0 | \
X86_DR7_RW1 | \
X86_DR7_LEN1 | \
X86_DR7_RW2 | \
X86_DR7_LEN2 | \
X86_DR7_RW3 | \
X86_DR7_LEN3)
/* Bits 11:12, 14:15 and 32:63 must be cleared to 0. Bit 10 must be set to 1. */
#define X86_DR7_MASK ((1ul << 10) | X86_DR7_LE | X86_DR7_GE)
#define HW_DEBUG_REGISTERS_COUNT 4
#ifndef __ASSEMBLER__
#include <zircon/compiler.h>
#include <sys/types.h>
__BEGIN_CDECLS
/* Indices of xsave feature states; state components are
* enumerated in Intel Vol 1 section 13.1 */
#define X86_XSAVE_STATE_INDEX_X87 0
#define X86_XSAVE_STATE_INDEX_SSE 1
#define X86_XSAVE_STATE_INDEX_AVX 2
#define X86_XSAVE_STATE_INDEX_MPX_BNDREG 3
#define X86_XSAVE_STATE_INDEX_MPX_BNDCSR 4
#define X86_XSAVE_STATE_INDEX_AVX512_OPMASK 5
#define X86_XSAVE_STATE_INDEX_AVX512_LOWERZMM_HIGH 6
#define X86_XSAVE_STATE_INDEX_AVX512_HIGHERZMM 7
#define X86_XSAVE_STATE_INDEX_PT 8
#define X86_XSAVE_STATE_INDEX_PKRU 9
/* Bit masks for xsave feature states. */
#define X86_XSAVE_STATE_BIT_X87 (1 << X86_XSAVE_STATE_INDEX_X87)
#define X86_XSAVE_STATE_BIT_SSE (1 << X86_XSAVE_STATE_INDEX_SSE)
#define X86_XSAVE_STATE_BIT_AVX (1 << X86_XSAVE_STATE_INDEX_AVX)
#define X86_XSAVE_STATE_BIT_MPX_BNDREG (1 << X86_XSAVE_STATE_INDEX_MPX_BNDREG)
#define X86_XSAVE_STATE_BIT_MPX_BNDCSR (1 << X86_XSAVE_STATE_INDEX_MPX_BNDCSR)
#define X86_XSAVE_STATE_BIT_AVX512_OPMASK (1 << X86_XSAVE_STATE_INDEX_AVX512_OPMASK)
#define X86_XSAVE_STATE_BIT_AVX512_LOWERZMM_HIGH (1 << X86_XSAVE_STATE_INDEX_AVX512_LOWERZMM_HIGH)
#define X86_XSAVE_STATE_BIT_AVX512_HIGHERZMM (1 << X86_XSAVE_STATE_INDEX_AVX512_HIGHERZMM)
#define X86_XSAVE_STATE_BIT_PT (1 << X86_XSAVE_STATE_INDEX_PT)
#define X86_XSAVE_STATE_BIT_PKRU (1 << X86_XSAVE_STATE_INDEX_PKRU)
// Maximum buffer size needed for xsave and variants. To allocate, see ...BUFFER_SIZE below.
#define X86_MAX_EXTENDED_REGISTER_SIZE 1024
enum x86_extended_register_feature {
X86_EXTENDED_REGISTER_X87,
X86_EXTENDED_REGISTER_SSE,
X86_EXTENDED_REGISTER_AVX,
X86_EXTENDED_REGISTER_MPX,
X86_EXTENDED_REGISTER_AVX512,
X86_EXTENDED_REGISTER_PT,
X86_EXTENDED_REGISTER_PKRU,
};
/* Identify which extended registers are supported. Also initialize
* the FPU if present */
void x86_extended_register_init(void);
/* Enable the requested feature on this CPU, return true on success.
* It is currently assumed that if a feature is enabled on one CPU, the caller
* will ensure it is enabled on all CPUs */
bool x86_extended_register_enable_feature(enum x86_extended_register_feature);
size_t x86_extended_register_size(void);
/* Initialize a state vector. The passed in buffer must be X86_EXTENDED_REGISTER_SIZE big and it
* must be 64-byte aligned. This function will initialize it for use in save and restore. */
void x86_extended_register_init_state(void* buffer);
/* Save current state to state vector */
void x86_extended_register_save_state(void *register_state);
/* Restore a state created by x86_extended_register_init_state or
* x86_extended_register_save_state */
void x86_extended_register_restore_state(void *register_state);
typedef struct thread thread_t;
void x86_extended_register_context_switch(
thread_t *old_thread, thread_t *new_thread);
void x86_set_extended_register_pt_state(bool threads);
uint64_t x86_xgetbv(uint32_t reg);
void x86_xsetbv(uint32_t reg, uint64_t val);
struct x86_xsave_legacy_area {
uint16_t fcw; /* FPU control word. */
uint16_t fsw; /* FPU status word. */
uint8_t ftw; /* Abridged FPU tag word (not the same as the FTW register, see
* Intel manual sec 10.5.1.1: "x87 State". */
uint8_t reserved;
uint16_t fop; /* FPU opcode. */
uint64_t fip; /* FPU instruction pointer. */
uint64_t fdp; /* FPU data pointer. */
uint32_t mxcsr; /* SSE control status register. */
uint32_t mxcsr_mask;
/* The x87/MMX state. For x87 the each "st" entry has the low 80 bits used for the register
* contents. For MMX, the low 64 bits are used. The higher bits are unused. */
struct {
uint64_t low;
uint64_t high;
} st[8];
/* SSE registers. */
struct {
uint64_t low;
uint64_t high;
} xmm[16];
} __PACKED;
/* Returns the address within the given xsave area of the requested state component. The state
* component indexes formats are described in section 13.4 of the Intel Software Developer's manual.
* Use the X86_XSAVE_STATE_INDEX_* macros above for the component indices.
*
* The given register state must have previously been filled with the variant of XSAVE that the
* system is using. Since the save area can be compressed, the offset of each component can vary
* depending on the contents.
*
* The components 0 and 1 are special and refer to the legacy area. In both cases a pointer to the
* x86_xsave_legacy_area will be returned. Note that "mark_present=true" will only affect the
* requested component, so if you're writing to both x87 and SSE states, make two separate calls
* even though the returned pointer will be the same.
*
* Some parts of the xsave area are can be marked as unused to optimize. If you plan on
* writing to the area, set mark_present = true which will ensure that the corresponding area is
* marked used. Without this, the registers might not be restored when the thread is resumed. This
* is not currently supported for components >= 2. This means that to set AVX registers, for
* example, AVX needed to have been previously used by the thread in question. This capability can
* be added in the future if required.
*
* The size of the component will be placed in *size.
*
* This function will return null and fill 0 into *size if the component is not present. */
void* x86_get_extended_register_state_component(void* register_state, uint32_t component,
bool mark_present, uint32_t* size);
/* Kernel tracking of the current state of the x86 debug registers for a particular thread */
typedef struct x86_debug_state {
uint64_t dr[4];
uint64_t dr6;
uint64_t dr7;
} x86_debug_state_t;
/* Disables the HW debug functionalities for the current thread.
* There is no "enable" call. To do this, use the x86_write_debug_state call. */
void x86_disable_debug_state(void);
/* Checks whether the given state is valid to install on a running thread.
* Will mask out reserved values on DR6 and DR7. This is for the caller convenience, considering
* that we don't have a good mechanism to communicate back to the user what went wrong with the
* call. */
bool x86_validate_debug_state(x86_debug_state_t* debug_state);
/* Only update the status section of |debug_state| (DR6). All other state will not be modified */
void x86_read_debug_status(x86_debug_state_t* debug_state);
/* Read from the CPU registers into |debug_state|. */
void x86_read_hw_debug_regs(x86_debug_state_t* debug_state);
/* Write from the |debug_state| into the CPU registers.
*
* IMPORTANT: This function is used in the context switch, so no validation is done, just writing.
* In any other context (eg. setting debug values from a syscall), you *MUST* call
* x86_validate_debug_state first. */
void x86_write_hw_debug_regs(const x86_debug_state_t* debug_state);
/* Handles the context switch for debug HW functionality (drN registers).
* Will only copy over state if it's enabled (non-zero) for |new_thread|. */
void x86_debug_state_context_switch(thread_t* old_thread, thread_t* new_thread);
__END_CDECLS
#endif