/// -*- mode: asm; asm-comment-char: ?/ -*- /// /// CPU dispatch support for x86 /// /// (c) 2019 Straylight/Edgeware /// ///----- Licensing notice --------------------------------------------------- /// /// This file is part of Catacomb. /// /// Catacomb is free software: you can redistribute it and/or modify it /// under the terms of the GNU Library General Public License as published /// by the Free Software Foundation; either version 2 of the License, or /// (at your option) any later version. /// /// Catacomb 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 /// Library General Public License for more details. /// /// You should have received a copy of the GNU Library General Public /// License along with Catacomb. If not, write to the Free Software /// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, /// USA. ///-------------------------------------------------------------------------- /// Preliminaries. #include "config.h" #include "asm-common.h" EFLAGS_ID = 1 << 21 .text ///-------------------------------------------------------------------------- /// Probing for CPUID. FUNC(dispatch_x86ish_cpuid) // Enter with a pointer to 16 bytes of storage for the output A, B, // C, D values in the first argument, and input A and C values in the // second and third. Fill the output buffer with `cpuid' results and // return zero if we can; otherwise fill with zero and return -1. #if CPUFAM_X86 pushreg ebx pushreg edi mov edi, [esp + 12] mov eax, [esp + 16] mov ecx, [esp + 20] # define OUT edi #endif #if CPUFAM_AMD64 && ABI_SYSV pushreg rbx mov eax, esi mov ecx, edx # define OUT rdi #endif #if CPUFAM_AMD64 && ABI_WIN pushreg rbx mov r9, rcx mov eax, edx mov ecx, r8d # define OUT r9 #endif endprologue // First, check that this is even a thing, using the complicated // dance with the flags register. pushf pop R_d(r) // current flags in d or R_d(r), EFLAGS_ID // force the id bit on and check it push R_d(r) popf pushf pop R_d(r) test edx, EFLAGS_ID jz 8f and R_d(r), ~EFLAGS_ID // force the id bit off and check it push R_d(r) popf pushf pop R_d(r) test edx, EFLAGS_ID jnz 8f // OK, that seemed to work. cpuid mov [OUT + 0], eax mov [OUT + 4], ebx mov [OUT + 8], ecx mov [OUT + 12], edx xor eax, eax // We're done. 9: #if CPUFAM_X86 popreg edi popreg ebx #endif #if CPUFAM_AMD64 popreg rbx #endif ret // Failed. 8: xor eax, eax mov [OUT + 0], eax mov [OUT + 4], eax mov [OUT + 8], eax mov [OUT + 12], eax mov eax, -1 jmp 9b ENDFUNC ///-------------------------------------------------------------------------- /// Probing for XMM register availability. FUNC(dispatch_x86ish_xmmregisters_p) // Enter with no arguments. Return nonzero if the XMM registers are // usable. pushreg R_bp(r) setfp stalloc 512 and R_sp(r), ~15 endprologue // Save the floating point and SIMD registers, and try to clobber // xmm0. fxsave [R_sp(r)] mov eax, [R_sp(r) + 160] xor dword ptr [R_sp(r) + 160], 0xaaaa5555 fxrstor [R_sp(r)] // Save them again, and read back the low word of xmm0. Undo the // clobbering and restore. fxsave [R_sp(r)] mov ecx, [R_sp(r) + 160] mov [R_sp(r) + 160], eax fxrstor [R_sp(r)] // The register are live if we read different things. xor eax, ecx // Done. dropfp popreg R_bp(r) ret ENDFUNC ///-------------------------------------------------------------------------- /// Checking `rdrand'. FUNC(dispatch_x86ish_rdrand) // Enter with one argument: a pointer X_OUT to a 32-bit word. Try to // generate a random word using `rdrand'. If successful, set *X_OUT // to the generated word, and return zero; otherwise, return -1. #if CPUFAM_X86 # define X_OUT edx # define COUNT ecx mov X_OUT, [SP + 4] #endif #if CPUFAM_AMD64 && ABI_SYSV # define X_OUT rdi # define COUNT ecx #endif #if CPUFAM_AMD64 && ABI_WIN # define X_OUT rcx # define COUNT edx #endif endprologue mov COUNT, 16 // fairly persistent 0: rdrand eax jc 9f dec COUNT jnz 0b // Failed to come up with a random value. mov eax, -1 ret // Success. 9: mov [X_OUT], eax xor eax, eax ret #undef X_OUT #undef COUNT ENDFUNC ///----- That's all, folks --------------------------------------------------