1
0
mirror of https://github.com/deadw00d/AROS.git synced 2026-03-20 04:00:58 +00:00
Files
AROS-v0/arch/x86_64-all/include/asm/cpu.h
2025-11-09 16:56:39 +01:00

368 lines
12 KiB
C

#ifndef ASM_X86_64_CPU_H
#define ASM_X86_64_CPU_H
/*
Copyright © 1995-2025, The AROS Development Team. All rights reserved.
$Id$
Desc: assembler-level specific definitions for x86-64 CPU
Lang: english
*/
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
/* CR0 bits */
#define _CR0_PE_B 0 /* RW: Protected mode enable */
#define _CR0_MP_B 1 /* RW: Monitor FPU? If 1 then #NM exception may be generated */
#define _CR0_EM_B 2 /* RW: Emulate FPU */
#define _CR0_TS_B 3 /* RW: Task switched */
#define _CR0_ET_B 4 /* RO: Exception type */
#define _CR0_NE_B 5 /* RW: Numeric error */
#define _CR0_WP_B 16 /* RW: Write protect for RO pages in supervisor mode */
#define _CR0_AM_B 18 /* RW: Require data alignment */
#define _CR0_NW_B 29 /* RW: IGNORED: Not writethrough */
#define _CR0_CD_B 30 /* RW: Cache disable */
#define _CR0_PG_B 31 /* RW: Paging enable */
#define _CR0_PE (1 << _CR0_PE_B)
#define _CR0_MP (1 << _CR0_MP_B)
#define _CR0_EM (1 << _CR0_EM_B)
#define _CR0_TS (1 << _CR0_TS_B)
#define _CR0_ET (1 << _CR0_ET_B)
#define _CR0_NE (1 << _CR0_NE_B)
#define _CR0_WP (1 << _CR0_WP_B)
#define _CR0_AM (1 << _CR0_AM_B)
#define _CR0_NW (1 << _CR0_NW_B)
#define _CR0_CD (1 << _CR0_CD_B)
#define _CR0_PG (1 << _CR0_PG_B)
/* CR3 bits */
#define _CR3_PWT_B 3 /* RW: Page writethrough */
#define _CR3_PCD_B 4 /* RW: Cache disable */
#define _CR3_PWT (1 << _CR3_PWT_B)
#define _CR3_PCD (1 << _CR3_PCD_B)
/* CR4 bits */
#define _CR4_VME_B 0 /* RW: Virtual-8086 enable */
#define _CR4_PVI_B 1 /* RW: Protected mode virtual interrupts */
#define _CR4_TSD_B 2 /* RW: Time stamp disable for usermode */
#define _CR4_DE_B 3 /* RW: Debug extensions */
#define _CR4_PSE_B 4 /* RW: Page size extensions */
#define _CR4_PAE_B 5 /* RW: Physical-address extensions */
#define _CR4_MCE_B 6 /* RW: Machine check enable */
#define _CR4_PGE_B 7 /* RW: Page-Global enable */
#define _CR4_PCE_B 8 /* RW: Performance monitoring counter enable */
#define _CR4_OSFXSR_B 9 /* RW: Operating system fxsave/fsrstor support */
#define _CR4_OSXMMEXCPT_B 10 /* RW: Operating system unmasked exception support */
#define _CR4_OSXSBV_B 18 /* RW: Operating system xsetbv/xgetbv support */
#define _CR4_VME (1 << _CR4_VME_B)
#define _CR4_PVI (1 << _CR4_PVI_B)
#define _CR4_TSD (1 << _CR4_TSD_B)
#define _CR4_DE (1 << _CR4_DE_B)
#define _CR4_PSE (1 << _CR4_PSE_B)
#define _CR4_PAE (1 << _CR4_PAE_B)
#define _CR4_MCE (1 << _CR4_MCE_B)
#define _CR4_PGE (1 << _CR4_PGE_B)
#define _CR4_PCE (1 << _CR4_PCE_B)
#define _CR4_OSFXSR (1 << _CR4_OSFXSR_B)
#define _CR4_OSXMMEXCPT (1 << _CR4_OSXMMEXCPT_B)
#define _CR4_OSXSBV (1 << _CR4_OSXSBV_B)
/* EFER */
#define EFER 0xc0000080 /* EFER number for rsmsr/wrmsr */
#define _EFER_SCE_B 0 /* RW: System call extensions */
#define _EFER_LME_B 8 /* RW: Long mode enable */
#define _EFER_LMA_B 10 /* RW: Long mode activated */
#define _EFER_NXE_B 11 /* RW: No-execute bit enable */
#define _EFER_FFXSR_B 14 /* RW: Fast fxsave/fxrstor */
/* SYSCALL/SYSRET registers */
#define IA32_STAR 0xc0000081
#define IA32_LSTAR 0xc0000082
#define IA32_FMASK 0xc0000084
#define _EFER_SCE (1 << _EFER_SCE_B)
#define _EFER_LME (1 << _EFER_LME_B)
#define _EFER_LMA (1 << _EFER_LMA_B)
#define _EFER_NXE (1 << _EFER_NXE_B)
#define _EFER_FFXSR (1 << _EFER_FFXSR_B)
#define HALT asm volatile("hlt")
/*
* Selector used for lgdt and lidt commands.
* Intentionally use unsigned long for base address since this file can be compiled also in 32-bit mode.
*/
struct segment_selector
{
unsigned short size;
unsigned long base;
} __attribute__((packed));
struct int_gate_64bit {
uint16_t offset_low;
uint16_t selector;
unsigned ist:3, __pad0:5, type:5, dpl:2, p:1;
uint16_t offset_mid;
uint32_t offset_high;
uint32_t __pad1;
} __attribute__((packed));
/* Segment descriptor in the GDT */
struct segment_desc
{
uint16_t limit_low;
uint16_t base_low;
uint8_t base_mid;
unsigned type:5, dpl:2, p:1;
unsigned limit_high:4, avl:1, l:1, d:1, g:1;
uint8_t base_high:8;
} __attribute__((packed));
struct segment_ext {
uint32_t base_ext;
uint32_t __pad0;
} __attribute__((packed));
struct tss_64bit {
uint32_t __pad0;
uint64_t rsp0;
uint64_t rsp1;
uint64_t rsp2;
uint64_t __pad1;
uint64_t ist1;
uint64_t ist2;
uint64_t ist3;
uint64_t ist4;
uint64_t ist5;
uint64_t ist6;
uint64_t ist7;
uint64_t __pad2;
uint16_t __pad3;
uint16_t iopb;
uint32_t bmp[];
} __attribute__((packed));
struct segment_tss
{
struct segment_desc tss_low;
struct segment_ext tss_high;
} __attribute__((packed));
struct gdt_64bit
{
struct segment_desc seg0; /* seg 0x00 */
struct segment_desc super_cs; /* seg 0x08 */
struct segment_desc super_ds; /* seg 0x10 */
struct segment_desc user_cs32; /* seg 0x18 */
struct segment_desc user_ds; /* seg 0x20 */
struct segment_desc user_cs; /* seg 0x28 */
struct segment_desc gs; /* seg 0x30 */
struct segment_desc ldt; /* seg 0x38 */
struct segment_tss tss[0];
} __attribute__((packed));
#define MMU_PAGEB_P 0
#define MMU_PAGEB_RW 1
#define MMU_PAGEB_US 2
#define MMU_PAGEB_PWT 3
#define MMU_PAGEB_PCD 4
#define MMU_PAGEB_A 5
struct PML4E
{
unsigned p:1,rw:1,us:1,pwt:1,pcd:1,a:1,mbz:3,avl:3,base_low:20;
unsigned base_high:20,avail:11,nx:1;
} __attribute__((packed));
struct PDPE {
unsigned p:1,rw:1,us:1,pwt:1,pcd:1,a:1,__pad0:1,mbz:2,avl:3,base_low:20;
unsigned base_high:20,avail:11,nx:1;
} __attribute__((packed));
struct PDE4K {
unsigned p:1,rw:1,us:1,pwt:1,pcd:1,a:1,__pad0:1,ps:1,_pad1:1,avl:3,base_low:20;
unsigned base_high:20,avail:11,nx:1;
} __attribute__((packed));
struct PDE2M {
unsigned p:1,rw:1,us:1,pwt:1,pcd:1,a:1,d:1,ps:1,g:1,avl:3,pat:1,base_low:19;
unsigned base_high:20,avail:11,nx:1;
} __attribute__((packed));
struct PTE {
unsigned p:1,rw:1,us:1,pwt:1,pcd:1,a:1,d:1,pat:1,g:1,avl:3,base_low:20;
unsigned base_high:20,avail:11,nx:1;
} __attribute__((packed));
#define _ljmp(seg, addr) \
do { asm volatile("ljmp $" #seg ", $" #addr); }while(0)
#define ljmp(s, a) _ljmp(s, a)
#define _ljmp_arg(seg, addr, arg) \
do { asm volatile("ljmp $" #seg ", $" #addr ::"D"(arg)); }while(0)
#define ljmp_arg(s, a, p) _ljmp_arg(s, a, p)
#define rdcr(reg) \
({ long val; asm volatile("mov %%" #reg ",%0":"=r"(val)); val; })
#define wrcr(reg, val) \
do { asm volatile("mov %0,%%" #reg::"r"(val)); } while(0)
#define cpuid(num, eax, ebx, ecx, edx) \
do { asm volatile("cpuid":"=a"(eax),"=b"(ebx),"=c"(ecx),"=d"(edx):"a"(num)); } while(0)
static inline __attribute__((always_inline))
void cpuid2(unsigned int leaf, unsigned int subleaf,
unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx)
{
#if defined(__x86_64__)
unsigned int a = leaf, b, c = subleaf, d;
__asm__ volatile(
"mov %%rbx, %%rdi\n\t" /* save RBX (used by PIC) */
"cpuid\n\t"
"xchg %%rbx, %%rdi\n\t" /* restore RBX */
: "+a"(a), "=D"(b), "+c"(c), "=d"(d)
:
: "memory");
if (eax) *eax = a;
if (ebx) *ebx = b;
if (ecx) *ecx = c;
if (edx) *edx = d;
#elif defined(__i386__)
unsigned int a = leaf, b, c = subleaf, d;
__asm__ volatile(
"xchg %%ebx, %%edi\n\t" /* save EBX (PIC-safe) */
"cpuid\n\t"
"xchg %%ebx, %%edi\n\t" /* restore EBX */
: "=a"(a), "=D"(b), "=c"(c), "=d"(d)
: "a"(leaf), "c"(subleaf)
: "memory");
if (eax) *eax = a;
if (ebx) *ebx = b;
if (ecx) *ecx = c;
if (edx) *edx = d;
#else
# error "x86 only"
#endif
}
static inline void __attribute__((always_inline)) rdmsr(uint32_t msr_no, uint32_t *ret_lo, uint32_t *ret_hi)
{
uint32_t ret1,ret2;
asm volatile("rdmsr":"=a"(ret1),"=d"(ret2):"c"(msr_no));
*ret_lo=ret1;
*ret_hi=ret2;
}
static inline uint64_t __attribute__((always_inline)) rdmsrq(uint32_t msr_no)
{
uint32_t ret1,ret2;
asm volatile("rdmsr":"=a"(ret1),"=d"(ret2):"c"(msr_no));
return ((uint64_t)ret1 | ((uint64_t)ret2 << 32));
}
#define rdmsri rdmsrq
static inline void __attribute__((always_inline)) wrmsr(uint32_t msr_no, uint32_t val_lo, uint32_t val_hi)
{
asm volatile("wrmsr"::"a"(val_lo),"d"(val_hi),"c"(msr_no));
}
static inline void __attribute__((always_inline)) wrmsrq(uint32_t msr_no, uint64_t val)
{
asm volatile("wrmsr"::"a"((uint32_t)(val & 0xffffffff)),"d"((uint32_t)(val >> 32)),"c"(msr_no));
}
/*
Compare value stored at "addr" with "expected". If they are equal, function returns 1 and stores "xchg" value
at "addr". If *addr != expected, function returns 0. Either "expected" or current value at *addr are stored back
at *found. The operation is atomic
*/
static inline int compare_and_exchange_long(uint32_t *addr, uint32_t expected, uint32_t xchg, uint32_t *found)
{
char flag;
uint32_t ret;
asm volatile("lock cmpxchg %4, %0; setz %1":"+m"(*addr),"=r"(flag),"=a"(ret):"2"(expected),"r"(xchg):"memory","cc");
if (found)
*found = ret;
return flag;
}
static inline int compare_and_exchange_short(uint16_t *lock, uint16_t expected, uint16_t xchg, uint16_t *found)
{
char flag;
uint16_t ret;
asm volatile("lock cmpxchg %4, %0; setz %1":"+m"(*lock),"=r"(flag),"=a"(ret):"2"(expected),"r"(xchg):"memory","cc");
if (found)
*found = ret;
return flag;
}
static inline int compare_and_exchange_byte(uint8_t *lock, uint8_t expected, uint8_t xchg, uint8_t *found)
{
char flag;
uint16_t ret;
asm volatile("lock cmpxchg %4, %0; setz %1":"+m"(*lock),"=r"(flag),"=a"(ret):"2"(expected),"r"(xchg):"memory","cc");
if (found)
*found = ret;
return flag;
}
static inline int bit_test_and_set_long(uint32_t *addr, int32_t bit)
{
char retval = 0;
asm volatile("lock btsl %2, %0; setc %1":"+m"(*addr),"=q"(retval):"Ir"(bit):"memory");
return retval;
}
static inline int bit_test_and_set_short(uint16_t *addr, int32_t bit)
{
char retval = 0;
asm volatile("lock btsw %2, %0; setc %1":"+m"(*addr),"=q"(retval):"Ir"(bit):"memory");
return retval;
}
static inline int bit_test_and_clear_long(uint32_t *addr, int32_t bit)
{
char retval = 0;
asm volatile("lock btrl %2, %0; setc %1":"+m"(*addr),"=q"(retval):"Ir"(bit):"memory");
return retval;
}
static inline int bit_test_and_clear_short(uint16_t *addr, int32_t bit)
{
char retval = 0;
asm volatile("lock btrw %2, %0; setc %1":"+m"(*addr),"=q"(retval):"Ir"(bit):"memory");
return retval;
}
static inline int bit_test_and_complement_long(uint32_t *addr, int32_t bit)
{
char retval = 0;
asm volatile("lock btcl %2, %0; setc %1":"+m"(*addr),"=q"(retval):"Ir"(bit):"memory");
return retval;
}
static inline int bit_test_and_complement_short(uint16_t *addr, int32_t bit)
{
char retval = 0;
asm volatile("lock btcw %2, %0; setc %1":"+m"(*addr),"=q"(retval):"Ir"(bit):"memory");
return retval;
}
#ifdef __cplusplus
}
#endif
#endif /*ASM_CPU_H*/