248 lines
5.9 KiB
D
248 lines
5.9 KiB
D
/**
|
|
* CPU functionality.
|
|
*/
|
|
module hulk.cpu;
|
|
|
|
import ldc.llvmasm;
|
|
|
|
/** CR0 bits. @{ */
|
|
enum ulong CR0_PE = 0x1u;
|
|
enum ulong CR0_MP = 0x2u;
|
|
enum ulong CR0_EM = 0x4u;
|
|
enum ulong CR0_TS = 0x8u;
|
|
enum ulong CR0_ET = 0x10u;
|
|
enum ulong CR0_NE = 0x20u;
|
|
enum ulong CR0_WP = 0x1_0000u;
|
|
enum ulong CR0_AM = 0x4_0000u;
|
|
enum ulong CR0_NW = 0x2000_0000u;
|
|
enum ulong CR0_CD = 0x4000_0000u;
|
|
enum ulong CR0_PG = 0x8000_0000u;
|
|
/** @} */
|
|
|
|
/** CR4 bits. @{ */
|
|
enum ulong CR4_VME = 0x1u;
|
|
enum ulong CR4_PVI = 0x2u;
|
|
enum ulong CR4_TSD = 0x4u;
|
|
enum ulong CR4_DE = 0x8u;
|
|
enum ulong CR4_PSE = 0x10u;
|
|
enum ulong CR4_PAE = 0x20u;
|
|
enum ulong CR4_MCE = 0x40u;
|
|
enum ulong CR4_PGE = 0x80u;
|
|
enum ulong CR4_PCE = 0x100u;
|
|
enum ulong CR4_OSFXSR = 0x200u;
|
|
enum ulong CR4_OSXMMEXCPT = 0x400u;
|
|
enum ulong CR4_UMIP = 0x800u;
|
|
enum ulong CR4_VMXE = 0x2000u;
|
|
enum ulong CR4_SMXE = 0x4000u;
|
|
enum ulong CR4_FSGSBASE = 0x1_0000u;
|
|
enum ulong CR4_PCIDE = 0x2_0000u;
|
|
enum ulong CR4_OSXSAVE = 0x4_0000u;
|
|
enum ulong CR4_SMEP = 0x10_0000u;
|
|
enum ulong CR4_SMAP = 0x20_0000u;
|
|
enum ulong CR4_PKE = 0x40_0000u;
|
|
enum ulong CR4_CET = 0x80_0000u;
|
|
enum ulong CR4_PKS = 0x100_0000u;
|
|
/** @} */
|
|
|
|
/** XCR0 bits. @{ */
|
|
enum ulong XCR0_X87 = 0x1u;
|
|
enum ulong XCR0_SSE = 0x2u;
|
|
enum ulong XCR0_AVX = 0x4u;
|
|
enum ulong XCR0_BNDREG = 0x8u;
|
|
enum ulong XCR0_BNDSCR = 0x10u;
|
|
enum ulong XCR0_OPMASK = 0x20u;
|
|
enum ulong XCR0_ZMM_HI256 = 0x40u;
|
|
enum ulong XCR0_HI16_ZMM = 0x80u;
|
|
enum ulong XCR0_PKRU = 0x100u;
|
|
/** @} */
|
|
|
|
/** MSR register numbers. @{ */
|
|
enum uint MSR_EFER = 0xC000_0080u;
|
|
/** @} */
|
|
|
|
/** EFER flags. @{ */
|
|
enum uint EFER_SCE = 0x1u;
|
|
enum uint EFER_LME = 0x100u;
|
|
enum uint EFER_LMA = 0x400u;
|
|
enum uint EFER_NXE = 0x800u;
|
|
enum uint EFER_SVME = 0x1000u;
|
|
enum uint EFER_LMSLE = 0x2000u;
|
|
enum uint EFER_FFXSR = 0x4000u;
|
|
enum uint EFER_TCE = 0x8000u;
|
|
/** @} */
|
|
|
|
/** CPUID 1 bits. @{ */
|
|
enum uint CPUID_1_EDX_FPU = 0x1u;
|
|
enum uint CPUID_1_EDX_VME = 0x2u;
|
|
enum uint CPUID_1_EDX_DE = 0x4u;
|
|
enum uint CPUID_1_EDX_PSE = 0x8u;
|
|
enum uint CPUID_1_EDX_TSC = 0x10u;
|
|
enum uint CPUID_1_EDX_MSR = 0x20u;
|
|
enum uint CPUID_1_EDX_PAE = 0x40u;
|
|
enum uint CPUID_1_EDX_MCE = 0x80u;
|
|
enum uint CPUID_1_EDX_CX8 = 0x100u;
|
|
enum uint CPUID_1_EDX_APIC = 0x200u;
|
|
enum uint CPUID_1_EDX_SEP = 0x800u;
|
|
enum uint CPUID_1_EDX_MTRR = 0x1000u;
|
|
enum uint CPUID_1_EDX_PGE = 0x2000u;
|
|
enum uint CPUID_1_EDX_MCA = 0x4000u;
|
|
enum uint CPUID_1_EDX_CMOV = 0x8000u;
|
|
enum uint CPUID_1_EDX_PAT = 0x1_0000u;
|
|
enum uint CPUID_1_EDX_PSE36 = 0x2_0000u;
|
|
enum uint CPUID_1_EDX_PSN = 0x4_0000u;
|
|
enum uint CPUID_1_EDX_CLFSH = 0x8_0000u;
|
|
enum uint CPUID_1_EDX_DS = 0x20_0000u;
|
|
enum uint CPUID_1_EDX_ACPI = 0x40_0000u;
|
|
enum uint CPUID_1_EDX_MMX = 0x80_0000u;
|
|
enum uint CPUID_1_EDX_FXSR = 0x100_0000u;
|
|
enum uint CPUID_1_EDX_SSE = 0x200_0000u;
|
|
enum uint CPUID_1_EDX_SSE2 = 0x400_0000u;
|
|
enum uint CPUID_1_EDX_SS = 0x800_0000u;
|
|
enum uint CPUID_1_EDX_HTT = 0x1000_0000u;
|
|
enum uint CPUID_1_EDX_TM = 0x2000_0000u;
|
|
enum uint CPUID_1_EDX_IA64 = 0x4000_0000u;
|
|
enum uint CPUID_1_EDX_PBE = 0x8000_0000u;
|
|
enum uint CPUID_1_ECX_SSE3 = 0x1u;
|
|
enum uint CPUID_1_ECX_PCLMULQDQ = 0x2u;
|
|
enum uint CPUID_1_ECX_DTES64 = 0x4u;
|
|
enum uint CPUID_1_ECX_MONITOR = 0x8u;
|
|
enum uint CPUID_1_ECX_DSCPL = 0x10u;
|
|
enum uint CPUID_1_ECX_VMX = 0x20u;
|
|
enum uint CPUID_1_ECX_SMX = 0x40u;
|
|
enum uint CPUID_1_ECX_EST = 0x80u;
|
|
enum uint CPUID_1_ECX_TM2 = 0x100u;
|
|
enum uint CPUID_1_ECX_SSSE3 = 0x200u;
|
|
enum uint CPUID_1_ECX_CNXTID = 0x400u;
|
|
enum uint CPUID_1_ECX_SDBG = 0x800u;
|
|
enum uint CPUID_1_ECX_FMA = 0x1000u;
|
|
enum uint CPUID_1_ECX_CX16 = 0x2000u;
|
|
enum uint CPUID_1_ECX_XTPR = 0x4000u;
|
|
enum uint CPUID_1_ECX_PDCM = 0x8000u;
|
|
enum uint CPUID_1_ECX_PCID = 0x2_0000u;
|
|
enum uint CPUID_1_ECX_DCA = 0x4_0000u;
|
|
enum uint CPUID_1_ECX_SSE41 = 0x8_0000u;
|
|
enum uint CPUID_1_ECX_SSE42 = 0x10_0000u;
|
|
enum uint CPUID_1_ECX_X2APIC = 0x20_0000u;
|
|
enum uint CPUID_1_ECX_MOVBE = 0x40_0000u;
|
|
enum uint CPUID_1_ECX_POPCNT = 0x80_0000u;
|
|
enum uint CPUID_1_ECX_TSCDEADLINE = 0x100_0000u;
|
|
enum uint CPUID_1_ECX_AES = 0x200_0000u;
|
|
enum uint CPUID_1_ECX_XSAVE = 0x400_0000u;
|
|
enum uint CPUID_1_ECX_OSXSAVE = 0x800_0000u;
|
|
enum uint CPUID_1_ECX_AVX = 0x1000_0000u;
|
|
enum uint CPUID_1_ECX_F16C = 0x2000_0000u;
|
|
enum uint CPUID_1_ECX_RDRND = 0x4000_0000u;
|
|
enum uint CPUID_1_ECX_HYPERVISOR = 0x8000_0000u;
|
|
/** @} */
|
|
|
|
void cli()
|
|
{
|
|
__asm("cli", "");
|
|
}
|
|
|
|
void sti()
|
|
{
|
|
__asm("sti", "");
|
|
}
|
|
|
|
void hlt()
|
|
{
|
|
__asm("hlt", "");
|
|
}
|
|
|
|
ulong read_cr0()
|
|
{
|
|
return __asm!ulong("mov %cr0, %rax", "={rax}");
|
|
}
|
|
|
|
void write_cr0(ulong v)
|
|
{
|
|
__asm("mov $0, %cr0", "r", v);
|
|
}
|
|
|
|
ulong read_cr2()
|
|
{
|
|
return __asm!ulong("mov %cr2, %rax", "={rax}");
|
|
}
|
|
|
|
ulong read_cr3()
|
|
{
|
|
return __asm!ulong("mov %cr3, %rax", "={rax}");
|
|
}
|
|
|
|
void write_cr3(ulong v)
|
|
{
|
|
__asm("mov $0, %cr3", "r", v);
|
|
}
|
|
|
|
ulong read_cr4()
|
|
{
|
|
return __asm!ulong("mov %cr4, %rax", "={rax}");
|
|
}
|
|
|
|
void write_cr4(ulong v)
|
|
{
|
|
__asm("mov $0, %cr4", "r", v);
|
|
}
|
|
|
|
ulong rdmsr(uint msr)
|
|
{
|
|
return __asm!ulong(`
|
|
rdmsr
|
|
shl $$32, %rdx
|
|
or %rdx, %rax`, "={rax},{ecx},~{rdx}", msr);
|
|
}
|
|
|
|
void wrmsr(uint msr, ulong value)
|
|
{
|
|
__asm(`wrmsr`, "{ecx},{edx},{eax}", msr, value >> 32u, value);
|
|
}
|
|
|
|
ulong xgetbv(uint xcr)
|
|
{
|
|
return __asm!ulong(`
|
|
xgetbv
|
|
shl $$32, %rdx
|
|
or %rdx, %rax`, "={rax},{ecx},~{rdx}", xcr);
|
|
}
|
|
|
|
void xsetbv(uint xcr, ulong value)
|
|
{
|
|
__asm(`xsetbv`, "{ecx},{edx},{eax}", xcr, value >> 32u, value);
|
|
}
|
|
|
|
ubyte in8(ushort ioaddr)
|
|
{
|
|
return __asm!ubyte("inb %dx, %al", "={al},{dx}", ioaddr);
|
|
}
|
|
|
|
ushort in16(ushort ioaddr)
|
|
{
|
|
return __asm!ushort("inw %dx, %ax", "={ax},{dx}", ioaddr);
|
|
}
|
|
|
|
uint in32(ushort ioaddr)
|
|
{
|
|
return __asm!uint("inl %dx, %eax", "={eax},{dx}", ioaddr);
|
|
}
|
|
|
|
void out8(ushort ioaddr, ubyte v)
|
|
{
|
|
__asm("outb %al, %dx", "{dx},{al}", ioaddr, v);
|
|
}
|
|
|
|
void out16(ushort ioaddr, ushort v)
|
|
{
|
|
__asm("outw %ax, %dx", "{dx},{ax}", ioaddr, v);
|
|
}
|
|
|
|
void out32(ushort ioaddr, uint v)
|
|
{
|
|
__asm("outl %eax, %dx", "{dx},{eax}", ioaddr, v);
|
|
}
|
|
|
|
void cpuid1(uint * ebx, uint * ecx, uint * edx)
|
|
{
|
|
__asm("cpuid", "=*{ebx},=*{ecx},=*{edx},{eax}", ebx, ecx, edx, 1u);
|
|
}
|