Mostly abolish inline assembler code in favour of dedicated files.
[catacomb] / base / dispatch-x86ish.S
diff --git a/base/dispatch-x86ish.S b/base/dispatch-x86ish.S
new file mode 100644 (file)
index 0000000..2c267b6
--- /dev/null
@@ -0,0 +1,156 @@
+/// -*- 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
+
+///----- That's all, folks --------------------------------------------------