/** * 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; /** @} */ /** Interrupt suspend level (0 when interrupts are enabled). */ private __gshared size_t intr_suspend_level; /** * Suspend interrupts. * * This function disables interrupts. Calls can be nested and interrupts will * be enabled only when the outermost pair of * suspend_interrupts()/resume_interrupts() is complete. */ void suspend_interrupts() { cli(); intr_suspend_level++; } /** * Resume interrupts. * * Calls can be nested and interrupts will be enabled only when the outermost * pair of suspend_interrupts()/resume_interrupts() is complete. */ void resume_interrupts() { intr_suspend_level--; if (intr_suspend_level == 0) { sti(); } } 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 read_rflags() { return __asm!ulong(` pushf mov (%rsp), %rax add $$8, %rsp`, "={rax}"); } 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); } void swint(int swint_id)() { static assert((0 <= swint_id) && (swint_id <= 255)); mixin(`__asm("int $$`, swint_id, `", "");`); }