From 4af2468b82bd6d6a28742f94746c1af832227f1a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 5 May 2026 23:21:33 +0200 Subject: [PATCH 01/25] x86: Mark AMD Geode support as orphaned Andres mentioned that he no longer has access to Geode hardware including the OLPC XO-1, so the MAINTAINERS entry is no longer accurate. I also noticed that the documentation link no longer works, as the product was finally discontinued a few years ago. Aside from the XO-1, there are still a few embeded boards with custom code in arch/x86/platforms/geode and a number of Geode based thin clients were shipped that may continue to work without any custom kernel code. Mark the platform as orphaned, remove the dead link, and update the files list to include the platform code. Signed-off-by: Arnd Bergmann Signed-off-by: Dave Hansen Signed-off-by: Ingo Molnar Acked-by: Andres Salomon Link: https://lore.kernel.org/all/fddba1c8-a95a-490f-962e-8505cb948672@queued.net/ Link: https://patch.msgid.link/20260505212458.2263891-1-arnd@kernel.org --- MAINTAINERS | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 882214b0e7db..3db882dae319 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1115,10 +1115,9 @@ S: Orphan F: drivers/usb/gadget/udc/amd5536udc.* AMD GEODE PROCESSOR/CHIPSET SUPPORT -M: Andres Salomon L: linux-geode@lists.infradead.org (moderated for non-subscribers) -S: Supported -W: http://www.amd.com/us-en/ConnectivitySolutions/TechnicalResources/0,,50_2334_2452_11363,00.html +S: Orphaned +F: arch/x86/platform/geode/ F: arch/x86/include/asm/geode.h F: drivers/char/hw_random/geode-rng.c F: drivers/crypto/geode* From aaa3c14d11345f330f32ef4e837923d0932a809d Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 25 Apr 2025 10:41:59 +0200 Subject: [PATCH 02/25] x86/cpu: Remove CONFIG_MWINCHIP3D/MWINCHIPC6 These CPUs lack CMPXCHG8B support, according to Arnd Bergmann: | "Winchip6 (486-class, no tsc, no cx8) and Winchip3D | (486-class, with tsc but no cx8)" Any still available derivatives, if they have TSC and CX8 support, would work with regular Pentium builds, there's no need to have a separate build option for them. Signed-off-by: Ingo Molnar Reviewed-by: Arnd Bergmann Acked-by: Dave Hansen Cc: Linus Torvalds Link: https://lore.kernel.org/r/20250425084216.3913608-3-mingo@kernel.org --- arch/x86/Kconfig.cpu | 28 ++++------------------------ arch/x86/Makefile_32.cpu | 2 -- arch/x86/include/asm/vermagic.h | 4 ---- 3 files changed, 4 insertions(+), 30 deletions(-) diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index d7ba9219cb47..8868aa19d88a 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -32,8 +32,6 @@ choice - "Athlon" for the AMD K7 family (Athlon/Duron/Thunderbird). - "Crusoe" for the Transmeta Crusoe series. - "Efficeon" for the Transmeta Efficeon series. - - "Winchip-C6" for original IDT Winchip. - - "Winchip-2" for IDT Winchips with 3dNow! capabilities. - "AMD Elan" for the 32-bit AMD Elan embedded CPU. - "GeodeGX1" for Geode GX1 (Cyrix MediaGX). - "Geode GX/LX" For AMD Geode GX and LX processors. @@ -155,24 +153,6 @@ config MEFFICEON help Select this for a Transmeta Efficeon processor. -config MWINCHIPC6 - bool "Winchip-C6" - depends on X86_32 - help - Select this for an IDT Winchip C6 chip. Linux and GCC - treat this chip as a 586TSC with some extended instructions - and alignment requirements. - -config MWINCHIP3D - bool "Winchip-2/Winchip-2A/Winchip-3" - depends on X86_32 - help - Select this for an IDT Winchip-2, 2A or 3. Linux and GCC - treat this chip as a 586TSC with some extended instructions - and alignment requirements. Also enable out of order memory - stores for this CPU, which can increase performance of some - operations. - config MGEODEGX1 bool "GeodeGX1" depends on X86_32 @@ -270,7 +250,7 @@ config X86_L1_CACHE_SHIFT default "7" if MPENTIUM4 default "6" if MK7 || MPENTIUMM || MATOM || MVIAC7 || X86_GENERIC || X86_64 default "4" if MGEODEGX1 - default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX + default "5" if MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX config X86_F00F_BUG def_bool y @@ -282,7 +262,7 @@ config X86_INVD_BUG config X86_ALIGNMENT_16 def_bool y - depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK6 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODEGX1 + depends on MCYRIXIII || MK6 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODEGX1 config X86_INTEL_USERCOPY def_bool y @@ -290,7 +270,7 @@ config X86_INTEL_USERCOPY config X86_USE_PPRO_CHECKSUM def_bool y - depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MEFFICEON || MGEODE_LX || MATOM + depends on MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MEFFICEON || MGEODE_LX || MATOM config X86_TSC def_bool y @@ -318,7 +298,7 @@ config X86_MINIMUM_CPU_FAMILY config X86_DEBUGCTLMSR def_bool y - depends on !(MK6 || MWINCHIPC6 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586) && !UML + depends on !(MK6 || MCYRIXIII || M586MMX || M586TSC || M586) && !UML config IA32_FEAT_CTL def_bool y diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu index 7c9898c15376..707827f555d1 100644 --- a/arch/x86/Makefile_32.cpu +++ b/arch/x86/Makefile_32.cpu @@ -24,8 +24,6 @@ cflags-$(CONFIG_MK6) += -march=k6 cflags-$(CONFIG_MK7) += -march=athlon cflags-$(CONFIG_MCRUSOE) += -march=i686 $(align) cflags-$(CONFIG_MEFFICEON) += -march=i686 $(call tune,pentium3) $(align) -cflags-$(CONFIG_MWINCHIPC6) += $(call cc-option,-march=winchip-c6,-march=i586) -cflags-$(CONFIG_MWINCHIP3D) += $(call cc-option,-march=winchip2,-march=i586) cflags-$(CONFIG_MCYRIXIII) += $(call cc-option,-march=c3,-march=i486) $(align) cflags-$(CONFIG_MVIAC3_2) += $(call cc-option,-march=c3-2,-march=i686) cflags-$(CONFIG_MVIAC7) += -march=i686 diff --git a/arch/x86/include/asm/vermagic.h b/arch/x86/include/asm/vermagic.h index eda233a90ea8..b3a8beb32dfd 100644 --- a/arch/x86/include/asm/vermagic.h +++ b/arch/x86/include/asm/vermagic.h @@ -31,10 +31,6 @@ #define MODULE_PROC_FAMILY "CRUSOE " #elif defined CONFIG_MEFFICEON #define MODULE_PROC_FAMILY "EFFICEON " -#elif defined CONFIG_MWINCHIPC6 -#define MODULE_PROC_FAMILY "WINCHIPC6 " -#elif defined CONFIG_MWINCHIP3D -#define MODULE_PROC_FAMILY "WINCHIP3D " #elif defined CONFIG_MCYRIXIII #define MODULE_PROC_FAMILY "CYRIXIII " #elif defined CONFIG_MVIAC3_2 From 7d328c5de43a9e29dc6cd1ba3e578c1a32ebc486 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 25 Apr 2025 10:42:00 +0200 Subject: [PATCH 03/25] x86/cpu: Remove CPU_SUP_UMC_32 support These are 486 based CPUs, which build option (M486) is now gone upstream. Signed-off-by: Ingo Molnar Reviewed-by: Arnd Bergmann Acked-by: Dave Hansen Cc: Linus Torvalds Link: https://lore.kernel.org/r/20250425084216.3913608-4-mingo@kernel.org --- arch/x86/Kconfig.cpu | 14 -------------- arch/x86/kernel/cpu/umc.c | 26 -------------------------- 2 files changed, 40 deletions(-) delete mode 100644 arch/x86/kernel/cpu/umc.c diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index 8868aa19d88a..71f264443d78 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -399,20 +399,6 @@ config CPU_SUP_TRANSMETA_32 If unsure, say N. -config CPU_SUP_UMC_32 - default y - bool "Support UMC processors" if PROCESSOR_SELECT - depends on M486SX || M486 || (EXPERT && !64BIT) - help - This enables detection, tunings and quirks for UMC processors - - You need this enabled if you want your kernel to run on a - UMC CPU. Disabling this option on other types of CPUs - makes the kernel a tiny bit smaller. Disabling it on a UMC - CPU might render the kernel unbootable. - - If unsure, say N. - config CPU_SUP_ZHAOXIN default y bool "Support Zhaoxin processors" if PROCESSOR_SELECT diff --git a/arch/x86/kernel/cpu/umc.c b/arch/x86/kernel/cpu/umc.c deleted file mode 100644 index 65a58a390fc3..000000000000 --- a/arch/x86/kernel/cpu/umc.c +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include "cpu.h" - -/* - * UMC chips appear to be only either 386 or 486, - * so no special init takes place. - */ - -static const struct cpu_dev umc_cpu_dev = { - .c_vendor = "UMC", - .c_ident = { "UMC UMC UMC" }, - .legacy_models = { - { .family = 4, .model_names = - { - [1] = "U5D", - [2] = "U5S", - } - }, - }, - .c_x86_vendor = X86_VENDOR_UMC, -}; - -cpu_dev_register(umc_cpu_dev); - From dbafa16ec2b6be40055db181c99f2529b20dd951 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 25 Apr 2025 10:42:01 +0200 Subject: [PATCH 04/25] x86/cpu: Remove TSC-less CONFIG_M586 support Remove support for TSC-less Pentium variants. All TSC-capable Pentium variants, derivatives and clones should still work under the M586TSC or M586MMX options. Signed-off-by: Ingo Molnar Reviewed-by: Arnd Bergmann Acked-by: Dave Hansen Cc: Linus Torvalds Link: https://lore.kernel.org/r/20250425084216.3913608-5-mingo@kernel.org --- arch/x86/Kconfig.cpu | 10 +--------- arch/x86/Makefile_32.cpu | 1 - arch/x86/include/asm/vermagic.h | 2 -- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index 71f264443d78..9b912091dabd 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -43,14 +43,6 @@ choice See each option's help text for additional details. If you don't know what to do, choose "Pentium-Pro". -config M586 - bool "586/K5/5x86/6x86/6x86MX" - depends on X86_32 - help - Select this for an 586 or 686 series processor such as the AMD K5, - the Cyrix 5x86, 6x86 and 6x86MX. This choice does not - assume the RDTSC (Read Time Stamp Counter) instruction. - config M586TSC bool "Pentium-Classic" depends on X86_32 @@ -250,7 +242,7 @@ config X86_L1_CACHE_SHIFT default "7" if MPENTIUM4 default "6" if MK7 || MPENTIUMM || MATOM || MVIAC7 || X86_GENERIC || X86_64 default "4" if MGEODEGX1 - default "5" if MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX + default "5" if MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MVIAC3_2 || MGEODE_LX config X86_F00F_BUG def_bool y diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu index 707827f555d1..ec9f34db9a8b 100644 --- a/arch/x86/Makefile_32.cpu +++ b/arch/x86/Makefile_32.cpu @@ -10,7 +10,6 @@ else align := -falign-functions=0 -falign-jumps=0 -falign-loops=0 endif -cflags-$(CONFIG_M586) += -march=i586 cflags-$(CONFIG_M586TSC) += -march=i586 cflags-$(CONFIG_M586MMX) += -march=pentium-mmx cflags-$(CONFIG_M686) += -march=i686 diff --git a/arch/x86/include/asm/vermagic.h b/arch/x86/include/asm/vermagic.h index b3a8beb32dfd..e26061df0c9b 100644 --- a/arch/x86/include/asm/vermagic.h +++ b/arch/x86/include/asm/vermagic.h @@ -5,8 +5,6 @@ #ifdef CONFIG_X86_64 /* X86_64 does not define MODULE_PROC_FAMILY */ -#elif defined CONFIG_M586 -#define MODULE_PROC_FAMILY "586 " #elif defined CONFIG_M586TSC #define MODULE_PROC_FAMILY "586TSC " #elif defined CONFIG_M586MMX From db1931e39ba15827eb1889594916b80227b7956c Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 25 Apr 2025 10:42:02 +0200 Subject: [PATCH 05/25] x86/cpu, x86/platform, watchdog: Remove CONFIG_X86_RDC321X support This depends on M486 CPU support, which has been removed. Note that we still keep the RDC321X MFD, watchdog and GPIO drivers, because apparently there were 586/686 CPUs offered with the RDC321X, according to Arnd Bergmann: | "the [RDC321X] product line is still actively developed by RDC | and DM&P, and I suspect that some of the drivers are still used | on 586tsc-class (vortex86dx, vortex86mx) and 686-class | (vortex86dx3, vortex86ex) SoCs that do run modern kernels and | get updates." For this reason, update the watchdog driver and offer it on the broader 32-bit landscape, which has been COMPILE_TEST=y build-tested previously already: - depends on X86_RDC321X || COMPILE_TEST + depends on X86_32 || COMPILE_TEST The MFD and GPIO drivers were already independent of CONFIG_X86_RDC321X. Signed-off-by: Ingo Molnar Reviewed-by: Arnd Bergmann Acked-by: Dave Hansen Cc: Linus Torvalds Cc: Wim Van Sebroeck Cc: Guenter Roeck Link: https://lore.kernel.org/r/20250425084216.3913608-6-mingo@kernel.org --- arch/x86/Kconfig | 11 ----------- drivers/watchdog/Kconfig | 2 +- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index f3f7cb01d69d..68654712e9fc 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -695,17 +695,6 @@ config X86_INTEL_QUARK Say Y here if you have a Quark based system such as the Arduino compatible Intel Galileo. -config X86_RDC321X - bool "RDC R-321x SoC" - depends on X86_32 - depends on X86_EXTENDED_PLATFORM - select M486 - select X86_REBOOTFIXUPS - help - This option is needed for RDC R-321x system-on-chip, also known - as R-8610-(G). - If you don't have one of these chips, you should say N here. - config X86_INTEL_LPSS bool "Intel Low Power Subsystem Support" depends on X86 && ACPI && PCI diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index dc78729ba2a5..6a9695a16d5e 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1547,7 +1547,7 @@ config NV_TCO config RDC321X_WDT tristate "RDC R-321x SoC watchdog" - depends on X86_RDC321X || COMPILE_TEST + depends on X86_32 || COMPILE_TEST depends on PCI help This is the driver for the built in hardware watchdog From 2ed46bccac394fd960c20dd9dc4c5fe0a9d7c0ef Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 25 Apr 2025 10:42:03 +0200 Subject: [PATCH 06/25] x86/cpu: Remove the CONFIG_X86_INVD_BUG quirk Now that support for 486 CPUs is gone, remove this quirk as well. Signed-off-by: Ingo Molnar Reviewed-by: Arnd Bergmann Acked-by: Dave Hansen Cc: Ahmed S. Darwish Cc: Ard Biesheuvel Cc: Linus Torvalds Link: https://lore.kernel.org/r/20250425084216.3913608-7-mingo@kernel.org --- arch/x86/Kconfig.cpu | 4 ---- arch/x86/kernel/traps.c | 7 ------- 2 files changed, 11 deletions(-) diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index 9b912091dabd..1377edd9a997 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -248,10 +248,6 @@ config X86_F00F_BUG def_bool y depends on M586MMX || M586TSC || M586 -config X86_INVD_BUG - def_bool y - depends on M486SX || M486 - config X86_ALIGNMENT_16 def_bool y depends on MCYRIXIII || MK6 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODEGX1 diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 0ca3912ecb7f..52177bce0802 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -1475,13 +1475,6 @@ DEFINE_IDTENTRY(exc_coprocessor_error) DEFINE_IDTENTRY(exc_simd_coprocessor_error) { - if (IS_ENABLED(CONFIG_X86_INVD_BUG)) { - /* AMD 486 bug: INVD in CPL 0 raises #XF instead of #GP */ - if (!static_cpu_has(X86_FEATURE_XMM)) { - __exc_general_protection(regs, 0); - return; - } - } math_error(regs, X86_TRAP_XF); } From 7b49a3fb69e785a2425c8dc7dbd0779a0a4c0eb2 Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Fri, 27 Mar 2026 03:15:18 +0100 Subject: [PATCH 07/25] treewide: Explicitly include the x86 CPUID headers Modify all CPUID call sites which implicitly include any of the CPUID headers to explicitly include them instead. For KVM's reverse_cpuid.h, just include since it references the CPUID_EAX..EDX symbols without using the CPUID APIs. Note, this allows removing the inclusion of from within next. That allows the CPUID API headers to include without introducing a circular dependency. Signed-off-by: Ahmed S. Darwish Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/20260327021645.555257-1-darwi@linutronix.de --- arch/x86/boot/compressed/pgtable_64.c | 1 + arch/x86/boot/startup/sme.c | 1 + arch/x86/coco/tdx/tdx.c | 1 + arch/x86/events/amd/core.c | 2 ++ arch/x86/events/amd/ibs.c | 1 + arch/x86/events/amd/lbr.c | 2 ++ arch/x86/events/amd/power.c | 3 +++ arch/x86/events/amd/uncore.c | 1 + arch/x86/events/intel/core.c | 1 + arch/x86/events/intel/lbr.c | 1 + arch/x86/events/zhaoxin/core.c | 1 + arch/x86/include/asm/acrn.h | 2 ++ arch/x86/include/asm/microcode.h | 1 + arch/x86/include/asm/xen/hypervisor.h | 1 + arch/x86/kernel/apic/apic.c | 1 + arch/x86/kernel/cpu/amd.c | 1 + arch/x86/kernel/cpu/centaur.c | 1 + arch/x86/kernel/cpu/hygon.c | 1 + arch/x86/kernel/cpu/mce/core.c | 1 + arch/x86/kernel/cpu/mce/inject.c | 1 + arch/x86/kernel/cpu/microcode/amd.c | 1 + arch/x86/kernel/cpu/microcode/core.c | 1 + arch/x86/kernel/cpu/microcode/intel.c | 1 + arch/x86/kernel/cpu/mshyperv.c | 1 + arch/x86/kernel/cpu/resctrl/core.c | 1 + arch/x86/kernel/cpu/resctrl/monitor.c | 1 + arch/x86/kernel/cpu/scattered.c | 1 + arch/x86/kernel/cpu/sgx/driver.c | 3 +++ arch/x86/kernel/cpu/sgx/main.c | 3 +++ arch/x86/kernel/cpu/topology_amd.c | 1 + arch/x86/kernel/cpu/topology_common.c | 1 + arch/x86/kernel/cpu/topology_ext.c | 1 + arch/x86/kernel/cpu/transmeta.c | 3 +++ arch/x86/kernel/cpu/vmware.c | 1 + arch/x86/kernel/cpu/zhaoxin.c | 1 + arch/x86/kernel/cpuid.c | 1 + arch/x86/kernel/jailhouse.c | 1 + arch/x86/kernel/kvm.c | 1 + arch/x86/kernel/paravirt.c | 1 + arch/x86/kvm/mmu/mmu.c | 1 + arch/x86/kvm/mmu/spte.c | 1 + arch/x86/kvm/reverse_cpuid.h | 2 ++ arch/x86/kvm/svm/sev.c | 1 + arch/x86/kvm/svm/svm.c | 1 + arch/x86/kvm/vmx/pmu_intel.c | 1 + arch/x86/kvm/vmx/sgx.c | 1 + arch/x86/kvm/vmx/vmx.c | 1 + arch/x86/mm/pti.c | 1 + arch/x86/pci/xen.c | 1 + arch/x86/xen/enlighten_hvm.c | 1 + arch/x86/xen/pmu.c | 1 + arch/x86/xen/time.c | 1 + drivers/char/agp/efficeon-agp.c | 1 + drivers/cpufreq/longrun.c | 1 + drivers/cpufreq/powernow-k7.c | 1 + drivers/cpufreq/powernow-k8.c | 1 + drivers/cpufreq/speedstep-lib.c | 1 + drivers/firmware/efi/libstub/x86-5lvl.c | 1 + drivers/gpu/drm/gma500/mmu.c | 2 ++ drivers/hwmon/fam15h_power.c | 1 + drivers/hwmon/k10temp.c | 2 ++ drivers/hwmon/k8temp.c | 1 + drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c | 1 + drivers/ras/amd/fmpm.c | 1 + drivers/thermal/intel/intel_hfi.c | 1 + drivers/thermal/intel/x86_pkg_temp_thermal.c | 1 + drivers/virt/acrn/hsm.c | 1 + drivers/xen/events/events_base.c | 1 + drivers/xen/grant-table.c | 1 + drivers/xen/xenbus/xenbus_xs.c | 3 +++ 70 files changed, 86 insertions(+) diff --git a/arch/x86/boot/compressed/pgtable_64.c b/arch/x86/boot/compressed/pgtable_64.c index 0e89e197e112..1b2fb35704f9 100644 --- a/arch/x86/boot/compressed/pgtable_64.c +++ b/arch/x86/boot/compressed/pgtable_64.c @@ -2,6 +2,7 @@ #include "misc.h" #include #include +#include #include #include #include diff --git a/arch/x86/boot/startup/sme.c b/arch/x86/boot/startup/sme.c index b76a7c95dfe1..c07a2c381ed1 100644 --- a/arch/x86/boot/startup/sme.c +++ b/arch/x86/boot/startup/sme.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index 186915a17c50..29b6f1ed59ec 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/events/amd/core.c b/arch/x86/events/amd/core.c index 0c92ed5f464b..d66a357f219d 100644 --- a/arch/x86/events/amd/core.c +++ b/arch/x86/events/amd/core.c @@ -8,8 +8,10 @@ #include #include #include + #include #include +#include #include #include diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c index e0bd5051db2a..20c2de5c697b 100644 --- a/arch/x86/events/amd/ibs.c +++ b/arch/x86/events/amd/ibs.c @@ -15,6 +15,7 @@ #include #include +#include #include #include "../perf_event.h" diff --git a/arch/x86/events/amd/lbr.c b/arch/x86/events/amd/lbr.c index d24da377df77..5b437dc8e4ce 100644 --- a/arch/x86/events/amd/lbr.c +++ b/arch/x86/events/amd/lbr.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include + +#include #include #include diff --git a/arch/x86/events/amd/power.c b/arch/x86/events/amd/power.c index dad42790cf7d..744dffa42dee 100644 --- a/arch/x86/events/amd/power.c +++ b/arch/x86/events/amd/power.c @@ -10,8 +10,11 @@ #include #include #include + #include +#include #include + #include "../perf_event.h" /* Event code: LSB 8 bits, passed in attr->config any other bit is reserved. */ diff --git a/arch/x86/events/amd/uncore.c b/arch/x86/events/amd/uncore.c index dd956cfcadef..05cff39968ec 100644 --- a/arch/x86/events/amd/uncore.c +++ b/arch/x86/events/amd/uncore.c @@ -16,6 +16,7 @@ #include #include +#include #include #define NUM_COUNTERS_NB 4 diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index d9488ade0f8e..e7bea277b14a 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index 72f2adcda7c6..cae2e02fe6cc 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -4,6 +4,7 @@ #include #include +#include #include #include diff --git a/arch/x86/events/zhaoxin/core.c b/arch/x86/events/zhaoxin/core.c index 4bdfcf091200..6ed644fe89aa 100644 --- a/arch/x86/events/zhaoxin/core.c +++ b/arch/x86/events/zhaoxin/core.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/include/asm/acrn.h b/arch/x86/include/asm/acrn.h index fab11192c60a..db42b477c41d 100644 --- a/arch/x86/include/asm/acrn.h +++ b/arch/x86/include/asm/acrn.h @@ -2,6 +2,8 @@ #ifndef _ASM_X86_ACRN_H #define _ASM_X86_ACRN_H +#include + /* * This CPUID returns feature bitmaps in EAX. * Guest VM uses this to detect the appropriate feature bit. diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h index 3c317d155771..9cd136d4515c 100644 --- a/arch/x86/include/asm/microcode.h +++ b/arch/x86/include/asm/microcode.h @@ -3,6 +3,7 @@ #define _ASM_X86_MICROCODE_H #include +#include struct cpu_signature { unsigned int sig; diff --git a/arch/x86/include/asm/xen/hypervisor.h b/arch/x86/include/asm/xen/hypervisor.h index c2fc7869b996..7c596cebfb78 100644 --- a/arch/x86/include/asm/xen/hypervisor.h +++ b/arch/x86/include/asm/xen/hypervisor.h @@ -37,6 +37,7 @@ extern struct shared_info *HYPERVISOR_shared_info; extern struct start_info *xen_start_info; #include +#include #include #define XEN_SIGNATURE "XenVMMXenVMM" diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 639904911444..8c614750a19b 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -64,6 +64,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 2d9ae6ab1701..5bc54cabbfa1 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/kernel/cpu/centaur.c b/arch/x86/kernel/cpu/centaur.c index 81695da9c524..681d2da49341 100644 --- a/arch/x86/kernel/cpu/centaur.c +++ b/arch/x86/kernel/cpu/centaur.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/kernel/cpu/hygon.c b/arch/x86/kernel/cpu/hygon.c index 7f95a74e4c65..3e8891a9caf2 100644 --- a/arch/x86/kernel/cpu/hygon.c +++ b/arch/x86/kernel/cpu/hygon.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c index 8dd424ac5de8..f6499132cba6 100644 --- a/arch/x86/kernel/cpu/mce/core.c +++ b/arch/x86/kernel/cpu/mce/core.c @@ -49,6 +49,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/kernel/cpu/mce/inject.c b/arch/x86/kernel/cpu/mce/inject.c index d02c4f556cd0..42c82c14c48a 100644 --- a/arch/x86/kernel/cpu/mce/inject.c +++ b/arch/x86/kernel/cpu/mce/inject.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index e533881284a1..874b5b70c0d2 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -34,6 +34,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 651202e6fefb..56d791aeac4e 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -34,6 +34,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 37ac4afe0972..18d2eff7a4b7 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index b5b6a58b67b0..640e6b223c2d 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c index 7667cf7c4e94..9c01d2562b7a 100644 --- a/arch/x86/kernel/cpu/resctrl/core.c +++ b/arch/x86/kernel/cpu/resctrl/core.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include "internal.h" diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c index 9bd87bae4983..145be7abee52 100644 --- a/arch/x86/kernel/cpu/resctrl/monitor.c +++ b/arch/x86/kernel/cpu/resctrl/monitor.c @@ -21,6 +21,7 @@ #include #include +#include #include #include "internal.h" diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c index 837d6a4b0c28..937129ce6a96 100644 --- a/arch/x86/kernel/cpu/scattered.c +++ b/arch/x86/kernel/cpu/scattered.c @@ -6,6 +6,7 @@ #include #include +#include #include #include "cpu.h" diff --git a/arch/x86/kernel/cpu/sgx/driver.c b/arch/x86/kernel/cpu/sgx/driver.c index 473619741bc4..9268289cd9f9 100644 --- a/arch/x86/kernel/cpu/sgx/driver.c +++ b/arch/x86/kernel/cpu/sgx/driver.c @@ -6,7 +6,10 @@ #include #include #include + +#include #include + #include "driver.h" #include "encl.h" diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c index 38b7fd2f63be..4505f808af5e 100644 --- a/arch/x86/kernel/cpu/sgx/main.c +++ b/arch/x86/kernel/cpu/sgx/main.c @@ -15,9 +15,12 @@ #include #include #include + +#include #include #include #include + #include "driver.h" #include "encl.h" #include "encls.h" diff --git a/arch/x86/kernel/cpu/topology_amd.c b/arch/x86/kernel/cpu/topology_amd.c index 6ac097e13106..cc103c85b96d 100644 --- a/arch/x86/kernel/cpu/topology_amd.c +++ b/arch/x86/kernel/cpu/topology_amd.c @@ -2,6 +2,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/kernel/cpu/topology_common.c b/arch/x86/kernel/cpu/topology_common.c index d0d79d5b8eb9..cf7513416b70 100644 --- a/arch/x86/kernel/cpu/topology_common.c +++ b/arch/x86/kernel/cpu/topology_common.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "cpu.h" diff --git a/arch/x86/kernel/cpu/topology_ext.c b/arch/x86/kernel/cpu/topology_ext.c index 467b0326bf1a..eb915c73895f 100644 --- a/arch/x86/kernel/cpu/topology_ext.c +++ b/arch/x86/kernel/cpu/topology_ext.c @@ -2,6 +2,7 @@ #include #include +#include #include #include diff --git a/arch/x86/kernel/cpu/transmeta.c b/arch/x86/kernel/cpu/transmeta.c index 42c939827621..1fdcd69c625c 100644 --- a/arch/x86/kernel/cpu/transmeta.c +++ b/arch/x86/kernel/cpu/transmeta.c @@ -3,8 +3,11 @@ #include #include #include + #include +#include #include + #include "cpu.h" static void early_init_transmeta(struct cpuinfo_x86 *c) diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c index eee0d1a48802..34b73573b108 100644 --- a/arch/x86/kernel/cpu/vmware.c +++ b/arch/x86/kernel/cpu/vmware.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/kernel/cpu/zhaoxin.c b/arch/x86/kernel/cpu/zhaoxin.c index 031379b7d4fa..761aef5590ac 100644 --- a/arch/x86/kernel/cpu/zhaoxin.c +++ b/arch/x86/kernel/cpu/zhaoxin.c @@ -4,6 +4,7 @@ #include #include +#include #include #include "cpu.h" diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c index dae436253de4..cbd04b677fd1 100644 --- a/arch/x86/kernel/cpuid.c +++ b/arch/x86/kernel/cpuid.c @@ -37,6 +37,7 @@ #include #include +#include #include #include diff --git a/arch/x86/kernel/jailhouse.c b/arch/x86/kernel/jailhouse.c index 9e9a591a5fec..f58ce9220e0f 100644 --- a/arch/x86/kernel/jailhouse.c +++ b/arch/x86/kernel/jailhouse.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 29226d112029..06534e16cfb5 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index 792fa96b3233..44f29fc05b3d 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 24fbc9ea502a..7de96c7c58a3 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/kvm/mmu/spte.c b/arch/x86/kvm/mmu/spte.c index 85a0473809b0..4e753386c8d4 100644 --- a/arch/x86/kvm/mmu/spte.c +++ b/arch/x86/kvm/mmu/spte.c @@ -15,6 +15,7 @@ #include "x86.h" #include "spte.h" +#include #include #include #include diff --git a/arch/x86/kvm/reverse_cpuid.h b/arch/x86/kvm/reverse_cpuid.h index 657f5f743ed9..2ad25781cefb 100644 --- a/arch/x86/kvm/reverse_cpuid.h +++ b/arch/x86/kvm/reverse_cpuid.h @@ -3,8 +3,10 @@ #define ARCH_X86_KVM_REVERSE_CPUID_H #include + #include #include +#include /* * Define a KVM-only feature flag. diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index c2126b3c3072..e107f368ed2d 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index e7fdd7a9c280..ef783ca9f1fd 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 27eb76e6b6a0..74e0b01185b8 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "x86.h" #include "cpuid.h" #include "lapic.h" diff --git a/arch/x86/kvm/vmx/sgx.c b/arch/x86/kvm/vmx/sgx.c index df1d0cf76947..29a1f8e3be60 100644 --- a/arch/x86/kvm/vmx/sgx.c +++ b/arch/x86/kvm/vmx/sgx.c @@ -2,6 +2,7 @@ /* Copyright(c) 2021 Intel Corporation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index a29896a9ef14..43b4fd9df586 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c index 631f0375bd42..598f553cc871 100644 --- a/arch/x86/mm/pti.c +++ b/arch/x86/mm/pti.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index 6818515a501b..550c631bc77f 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -18,6 +18,7 @@ #include #include #include +#include #include diff --git a/arch/x86/xen/enlighten_hvm.c b/arch/x86/xen/enlighten_hvm.c index 2f9fa27e5a3c..2bf05bf3e17b 100644 --- a/arch/x86/xen/enlighten_hvm.c +++ b/arch/x86/xen/enlighten_hvm.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include diff --git a/arch/x86/xen/pmu.c b/arch/x86/xen/pmu.c index 8f89ce0b67e3..5f50a3ee08f5 100644 --- a/arch/x86/xen/pmu.c +++ b/arch/x86/xen/pmu.c @@ -2,6 +2,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 6f9f665bb7ae..d62c14334b35 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index 0d25bbdc7e6a..4d0b7d7c0aad 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "agp.h" #include "intel-agp.h" diff --git a/drivers/cpufreq/longrun.c b/drivers/cpufreq/longrun.c index 1caaec7c280b..f3aaca0496a4 100644 --- a/drivers/cpufreq/longrun.c +++ b/drivers/cpufreq/longrun.c @@ -14,6 +14,7 @@ #include #include #include +#include static struct cpufreq_driver longrun_driver; diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c index 6b7caf4ae20d..6a930d7e6a5c 100644 --- a/drivers/cpufreq/powernow-k7.c +++ b/drivers/cpufreq/powernow-k7.c @@ -29,6 +29,7 @@ #include /* Needed for recalibrate_cpu_khz() */ #include #include +#include #ifdef CONFIG_X86_POWERNOW_K7_ACPI #include diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index 4d77eef53fe0..2b791f1ec51b 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -39,6 +39,7 @@ #include #include +#include #include #include diff --git a/drivers/cpufreq/speedstep-lib.c b/drivers/cpufreq/speedstep-lib.c index f8b42e981635..973716c1c29c 100644 --- a/drivers/cpufreq/speedstep-lib.c +++ b/drivers/cpufreq/speedstep-lib.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include "speedstep-lib.h" diff --git a/drivers/firmware/efi/libstub/x86-5lvl.c b/drivers/firmware/efi/libstub/x86-5lvl.c index c00d0ae7ed5d..c3da05c0df8b 100644 --- a/drivers/firmware/efi/libstub/x86-5lvl.c +++ b/drivers/firmware/efi/libstub/x86-5lvl.c @@ -2,6 +2,7 @@ #include #include +#include #include #include diff --git a/drivers/gpu/drm/gma500/mmu.c b/drivers/gpu/drm/gma500/mmu.c index 6b6b44e426cf..4fbc22a59ac7 100644 --- a/drivers/gpu/drm/gma500/mmu.c +++ b/drivers/gpu/drm/gma500/mmu.c @@ -7,6 +7,8 @@ #include #include +#include + #include "mmu.h" #include "psb_drv.h" #include "psb_reg.h" diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c index efcbea2d070e..ad4ed4162b57 100644 --- a/drivers/hwmon/fam15h_power.c +++ b/drivers/hwmon/fam15h_power.c @@ -19,6 +19,7 @@ #include #include #include +#include #include MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor"); diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index a5d8f45b7881..de0760dc597d 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -20,7 +20,9 @@ #include #include #include + #include +#include #include MODULE_DESCRIPTION("AMD Family 10h+ CPU core temperature monitor"); diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c index 2b80ac410cd1..53241164570e 100644 --- a/drivers/hwmon/k8temp.c +++ b/drivers/hwmon/k8temp.c @@ -15,6 +15,7 @@ #include #include #include +#include #define TEMP_FROM_REG(val) (((((val) >> 16) & 0xff) - 49) * 1000) #define REG_TEMP 0xe4 diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c index 7898b5075a8b..b8d467ba6d72 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "dwmac-intel.h" #include "dwmac4.h" #include "stmmac.h" diff --git a/drivers/ras/amd/fmpm.c b/drivers/ras/amd/fmpm.c index 34ef75af31cb..4ccaaf7b70bf 100644 --- a/drivers/ras/amd/fmpm.c +++ b/drivers/ras/amd/fmpm.c @@ -52,6 +52,7 @@ #include #include +#include #include #include "../debugfs.h" diff --git a/drivers/thermal/intel/intel_hfi.c b/drivers/thermal/intel/intel_hfi.c index 8c4ae75231f8..3273b8fe3d4d 100644 --- a/drivers/thermal/intel/intel_hfi.c +++ b/drivers/thermal/intel/intel_hfi.c @@ -41,6 +41,7 @@ #include #include +#include #include #include "intel_hfi.h" diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c index 540109761f0a..d1dd2f5910e4 100644 --- a/drivers/thermal/intel/x86_pkg_temp_thermal.c +++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "thermal_interrupt.h" diff --git a/drivers/virt/acrn/hsm.c b/drivers/virt/acrn/hsm.c index 74f2086fa59f..f170ff4617fd 100644 --- a/drivers/virt/acrn/hsm.c +++ b/drivers/virt/acrn/hsm.c @@ -16,6 +16,7 @@ #include #include +#include #include #include "acrn_drv.h" diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index bc9a41662efc..6ea945508a89 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -40,6 +40,7 @@ #include #ifdef CONFIG_X86 +#include #include #include #include diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index a6abf1ccd54c..35f879dc5dfb 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -59,6 +59,7 @@ #include #include #ifdef CONFIG_X86 +#include #include #endif #include diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index 82b0a34ded70..c202e7c553a6 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -47,6 +47,9 @@ #include #include #include +#ifdef CONFIG_X86 +#include +#endif #include #include #include "xenbus.h" From ab05214025ee2af262591cd48df17883648bdb1a Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 15 May 2025 10:28:27 +0200 Subject: [PATCH 08/25] x86/fpu: Remove MATH_EMULATION and related glue code Now that support for 486 CPUs is gone upstream, remove the x86 mathemu code integration. Signed-off-by: Ingo Molnar Reviewed-by: Arnd Bergmann Acked-by: Dave Hansen Cc: Linus Torvalds Link: https://lore.kernel.org/r/20250425084216.3913608-9-mingo@kernel.org --- arch/x86/Kconfig | 27 --------------------------- arch/x86/Kconfig.cpufeatures | 1 - arch/x86/Makefile | 1 - arch/x86/include/asm/fpu/api.h | 6 ------ arch/x86/kernel/fpu/core.c | 5 ----- arch/x86/kernel/fpu/init.c | 9 +-------- arch/x86/kernel/traps.c | 14 -------------- 7 files changed, 1 insertion(+), 62 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 68654712e9fc..f67af156fc19 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1633,33 +1633,6 @@ config X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK Set whether the default state of memory_corruption_check is on or off. -config MATH_EMULATION - bool - depends on MODIFY_LDT_SYSCALL - prompt "Math emulation" if X86_32 && (M486SX || MELAN) - help - Linux can emulate a math coprocessor (used for floating point - operations) if you don't have one. 486DX and Pentium processors have - a math coprocessor built in, 486SX and 386 do not, unless you added - a 487DX or 387, respectively. (The messages during boot time can - give you some hints here ["man dmesg"].) Everyone needs either a - coprocessor or this emulation. - - If you don't have a math coprocessor, you need to say Y here; if you - say Y here even though you have a coprocessor, the coprocessor will - be used nevertheless. (This behavior can be changed with the kernel - command line option "no387", which comes handy if your coprocessor - is broken. Try "man bootparam" or see the documentation of your boot - loader (lilo or loadlin) about how to pass options to the kernel at - boot time.) This means that it is a good idea to say Y here if you - intend to use this kernel on different machines. - - More information about the internals of the Linux math coprocessor - emulation can be found in . - - If you are not sure, say Y; apart from resulting in a 66 KB bigger - kernel, it won't hurt. - config MTRR def_bool y prompt "MTRR (Memory Type Range Register) support" if EXPERT diff --git a/arch/x86/Kconfig.cpufeatures b/arch/x86/Kconfig.cpufeatures index 532cbc276b1e..89cbf8f572ae 100644 --- a/arch/x86/Kconfig.cpufeatures +++ b/arch/x86/Kconfig.cpufeatures @@ -70,7 +70,6 @@ config X86_REQUIRED_FEATURE_UP config X86_REQUIRED_FEATURE_FPU def_bool y - depends on !MATH_EMULATION config X86_REQUIRED_FEATURE_PAE def_bool y diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 46fec0b08487..96bfa137a82b 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -276,7 +276,6 @@ archprepare: $(cpufeaturemasks.hdr) libs-y += arch/x86/lib/ # drivers-y are linked after core-y -drivers-$(CONFIG_MATH_EMULATION) += arch/x86/math-emu/ drivers-$(CONFIG_PCI) += arch/x86/pci/ # suspend and hibernation support diff --git a/arch/x86/include/asm/fpu/api.h b/arch/x86/include/asm/fpu/api.h index cd6f194a912b..90c63fe19c0f 100644 --- a/arch/x86/include/asm/fpu/api.h +++ b/arch/x86/include/asm/fpu/api.h @@ -119,12 +119,6 @@ extern void fpu__init_system(void); extern void fpu__init_check_bugs(void); extern void fpu__resume_cpu(void); -#ifdef CONFIG_MATH_EMULATION -extern void fpstate_init_soft(struct swregs_state *soft); -#else -static inline void fpstate_init_soft(struct swregs_state *soft) {} -#endif - /* State tracking */ DECLARE_PER_CPU(bool, kernel_fpu_allowed); DECLARE_PER_CPU(struct fpu *, fpu_fpregs_owner_ctx); diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index 608983806fd7..584fb9913be4 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -558,11 +558,6 @@ static inline void fpstate_init_fstate(struct fpstate *fpstate) */ void fpstate_init_user(struct fpstate *fpstate) { - if (!cpu_feature_enabled(X86_FEATURE_FPU)) { - fpstate_init_soft(&fpstate->regs.soft); - return; - } - xstate_init_xcomp_bv(&fpstate->regs.xsave, fpstate->xfeatures); if (cpu_feature_enabled(X86_FEATURE_FXSR)) diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index ff988b9ea39f..0d33c217b71c 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c @@ -36,12 +36,7 @@ static void fpu__init_cpu_generic(void) write_cr0(cr0); /* Flush out any pending x87 state: */ -#ifdef CONFIG_MATH_EMULATION - if (!boot_cpu_has(X86_FEATURE_FPU)) - ; - else -#endif - asm volatile ("fninit"); + asm volatile ("fninit"); } /* @@ -86,13 +81,11 @@ static void __init fpu__init_system_early_generic(void) setup_clear_cpu_cap(X86_FEATURE_FPU); } -#ifndef CONFIG_MATH_EMULATION if (!test_cpu_cap(&boot_cpu_data, X86_FEATURE_FPU)) { pr_emerg("x86/fpu: Giving up, no FPU found and no math emulation present\n"); for (;;) asm volatile("hlt"); } -#endif } /* diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 52177bce0802..30aa8369957e 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -1543,20 +1543,6 @@ DEFINE_IDTENTRY(exc_device_not_available) if (handle_xfd_event(regs)) return; -#ifdef CONFIG_MATH_EMULATION - if (!boot_cpu_has(X86_FEATURE_FPU) && (cr0 & X86_CR0_EM)) { - struct math_emu_info info = { }; - - cond_local_irq_enable(regs); - - info.regs = regs; - math_emulate(&info); - - cond_local_irq_disable(regs); - return; - } -#endif - /* This should not happen. */ if (WARN(cr0 & X86_CR0_TS, "CR0.TS was set")) { /* Try to fix it up and carry on. */ From d8b55ce0c9958243c0b69211b12185287750d81a Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 25 Apr 2025 10:42:06 +0200 Subject: [PATCH 09/25] x86/fpu: Remove the 'no387' boot option Without math emulation there's no point to this option. Signed-off-by: Ingo Molnar Reviewed-by: Arnd Bergmann Acked-by: Dave Hansen Cc: Ahmed S. Darwish Cc: Linus Torvalds Link: https://lore.kernel.org/r/20250425084216.3913608-10-mingo@kernel.org --- .../admin-guide/kernel-parameters.txt | 4 ---- arch/x86/Kconfig | 20 +++++++++---------- arch/x86/kernel/cpu/common.c | 7 ------- 3 files changed, 9 insertions(+), 22 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 4d0f545fb3ec..d48d17578385 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -4437,10 +4437,6 @@ Kernel parameters These settings can be accessed at runtime via the nmi_watchdog and hardlockup_panic sysctls. - no387 [BUGS=X86-32] Tells the kernel to use the 387 maths - emulation library even if a 387 maths coprocessor - is present. - no4lvl [RISCV,EARLY] Disable 4-level and 5-level paging modes. Forces kernel to use 3-level paging instead. diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index f67af156fc19..34e92da22053 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -2742,18 +2742,16 @@ menuconfig APM 1) make sure that you have enough swap space and that it is enabled. 2) pass the "idle=poll" option to the kernel - 3) switch on floating point emulation in the kernel and pass - the "no387" option to the kernel - 4) pass the "floppy=nodma" option to the kernel - 5) pass the "mem=4M" option to the kernel (thereby disabling + 3) pass the "floppy=nodma" option to the kernel + 4) pass the "mem=4M" option to the kernel (thereby disabling all but the first 4 MB of RAM) - 6) make sure that the CPU is not over clocked. - 7) read the sig11 FAQ at - 8) disable the cache from your BIOS settings - 9) install a fan for the video card or exchange video RAM - 10) install a better fan for the CPU - 11) exchange RAM chips - 12) exchange the motherboard. + 5) make sure that the CPU is not over clocked. + 6) read the sig11 FAQ at + 7) disable the cache from your BIOS settings + 8) install a fan for the video card or exchange video RAM + 9) install a better fan for the CPU + 10) exchange RAM chips + 11) exchange the motherboard. To compile this driver as a module, choose M here: the module will be called apm. diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index a4268c47f2bc..897145f913bd 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1737,13 +1737,6 @@ static void __init cpu_parse_early_param(void) int arglen; #ifdef CONFIG_X86_32 - if (cmdline_find_option_bool(boot_command_line, "no387")) -#ifdef CONFIG_MATH_EMULATION - setup_clear_cpu_cap(X86_FEATURE_FPU); -#else - pr_err("Option 'no387' required CONFIG_MATH_EMULATION enabled.\n"); -#endif - if (cmdline_find_option_bool(boot_command_line, "nofxsr")) setup_clear_cpu_cap(X86_FEATURE_FXSR); #endif From 823caa17388451d1ca9238f26472509c8bbda117 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 14 Dec 2025 09:37:14 +0100 Subject: [PATCH 10/25] x86/fpu: Remove the math-emu/ FPU emulation library Now that all enabling code is gone, remove the FPU emulation library as well. Signed-off-by: Ingo Molnar Reviewed-by: Arnd Bergmann Acked-by: Dave Hansen Cc: Ahmed S. Darwish Cc: Linus Torvalds Link: https://lore.kernel.org/r/20250425084216.3913608-11-mingo@kernel.org --- arch/x86/math-emu/Makefile | 30 - arch/x86/math-emu/README | 427 -------- arch/x86/math-emu/control_w.h | 46 - arch/x86/math-emu/div_Xsig.S | 367 ------- arch/x86/math-emu/div_small.S | 48 - arch/x86/math-emu/errors.c | 686 ------------- arch/x86/math-emu/exception.h | 51 - arch/x86/math-emu/fpu_arith.c | 153 --- arch/x86/math-emu/fpu_asm.h | 32 - arch/x86/math-emu/fpu_aux.c | 267 ----- arch/x86/math-emu/fpu_emu.h | 218 ---- arch/x86/math-emu/fpu_entry.c | 718 ------------- arch/x86/math-emu/fpu_etc.c | 136 --- arch/x86/math-emu/fpu_proto.h | 157 --- arch/x86/math-emu/fpu_system.h | 130 --- arch/x86/math-emu/fpu_tags.c | 116 --- arch/x86/math-emu/fpu_trig.c | 1649 ------------------------------ arch/x86/math-emu/get_address.c | 401 -------- arch/x86/math-emu/load_store.c | 322 ------ arch/x86/math-emu/mul_Xsig.S | 179 ---- arch/x86/math-emu/poly.h | 115 --- arch/x86/math-emu/poly_2xm1.c | 146 --- arch/x86/math-emu/poly_atan.c | 209 ---- arch/x86/math-emu/poly_l2.c | 245 ----- arch/x86/math-emu/poly_sin.c | 379 ------- arch/x86/math-emu/poly_tan.c | 213 ---- arch/x86/math-emu/polynom_Xsig.S | 137 --- arch/x86/math-emu/reg_add_sub.c | 334 ------ arch/x86/math-emu/reg_compare.c | 479 --------- arch/x86/math-emu/reg_constant.c | 123 --- arch/x86/math-emu/reg_constant.h | 26 - arch/x86/math-emu/reg_convert.c | 47 - arch/x86/math-emu/reg_divide.c | 183 ---- arch/x86/math-emu/reg_ld_str.c | 1220 ---------------------- arch/x86/math-emu/reg_mul.c | 116 --- arch/x86/math-emu/reg_norm.S | 150 --- arch/x86/math-emu/reg_round.S | 711 ------------- arch/x86/math-emu/reg_u_add.S | 169 --- arch/x86/math-emu/reg_u_div.S | 474 --------- arch/x86/math-emu/reg_u_mul.S | 150 --- arch/x86/math-emu/reg_u_sub.S | 274 ----- arch/x86/math-emu/round_Xsig.S | 142 --- arch/x86/math-emu/shr_Xsig.S | 89 -- arch/x86/math-emu/status_w.h | 68 -- arch/x86/math-emu/version.h | 12 - arch/x86/math-emu/wm_shrx.S | 207 ---- arch/x86/math-emu/wm_sqrt.S | 472 --------- 47 files changed, 13023 deletions(-) delete mode 100644 arch/x86/math-emu/Makefile delete mode 100644 arch/x86/math-emu/README delete mode 100644 arch/x86/math-emu/control_w.h delete mode 100644 arch/x86/math-emu/div_Xsig.S delete mode 100644 arch/x86/math-emu/div_small.S delete mode 100644 arch/x86/math-emu/errors.c delete mode 100644 arch/x86/math-emu/exception.h delete mode 100644 arch/x86/math-emu/fpu_arith.c delete mode 100644 arch/x86/math-emu/fpu_asm.h delete mode 100644 arch/x86/math-emu/fpu_aux.c delete mode 100644 arch/x86/math-emu/fpu_emu.h delete mode 100644 arch/x86/math-emu/fpu_entry.c delete mode 100644 arch/x86/math-emu/fpu_etc.c delete mode 100644 arch/x86/math-emu/fpu_proto.h delete mode 100644 arch/x86/math-emu/fpu_system.h delete mode 100644 arch/x86/math-emu/fpu_tags.c delete mode 100644 arch/x86/math-emu/fpu_trig.c delete mode 100644 arch/x86/math-emu/get_address.c delete mode 100644 arch/x86/math-emu/load_store.c delete mode 100644 arch/x86/math-emu/mul_Xsig.S delete mode 100644 arch/x86/math-emu/poly.h delete mode 100644 arch/x86/math-emu/poly_2xm1.c delete mode 100644 arch/x86/math-emu/poly_atan.c delete mode 100644 arch/x86/math-emu/poly_l2.c delete mode 100644 arch/x86/math-emu/poly_sin.c delete mode 100644 arch/x86/math-emu/poly_tan.c delete mode 100644 arch/x86/math-emu/polynom_Xsig.S delete mode 100644 arch/x86/math-emu/reg_add_sub.c delete mode 100644 arch/x86/math-emu/reg_compare.c delete mode 100644 arch/x86/math-emu/reg_constant.c delete mode 100644 arch/x86/math-emu/reg_constant.h delete mode 100644 arch/x86/math-emu/reg_convert.c delete mode 100644 arch/x86/math-emu/reg_divide.c delete mode 100644 arch/x86/math-emu/reg_ld_str.c delete mode 100644 arch/x86/math-emu/reg_mul.c delete mode 100644 arch/x86/math-emu/reg_norm.S delete mode 100644 arch/x86/math-emu/reg_round.S delete mode 100644 arch/x86/math-emu/reg_u_add.S delete mode 100644 arch/x86/math-emu/reg_u_div.S delete mode 100644 arch/x86/math-emu/reg_u_mul.S delete mode 100644 arch/x86/math-emu/reg_u_sub.S delete mode 100644 arch/x86/math-emu/round_Xsig.S delete mode 100644 arch/x86/math-emu/shr_Xsig.S delete mode 100644 arch/x86/math-emu/status_w.h delete mode 100644 arch/x86/math-emu/version.h delete mode 100644 arch/x86/math-emu/wm_shrx.S delete mode 100644 arch/x86/math-emu/wm_sqrt.S diff --git a/arch/x86/math-emu/Makefile b/arch/x86/math-emu/Makefile deleted file mode 100644 index 02211fc6f2ec..000000000000 --- a/arch/x86/math-emu/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for wm-FPU-emu -# - -#DEBUG = -DDEBUGGING -DEBUG = -PARANOID = -DPARANOID -ccflags-y += $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION) -asflags-y += $(PARANOID) - -# From 'C' language sources: -C_OBJS =fpu_entry.o errors.o \ - fpu_arith.o fpu_aux.o fpu_etc.o fpu_tags.o fpu_trig.o \ - load_store.o get_address.o \ - poly_atan.o poly_l2.o poly_2xm1.o poly_sin.o poly_tan.o \ - reg_add_sub.o reg_compare.o reg_constant.o reg_convert.o \ - reg_ld_str.o reg_divide.o reg_mul.o - -# From 80x86 assembler sources: -A_OBJS =reg_u_add.o reg_u_div.o reg_u_mul.o reg_u_sub.o \ - div_small.o reg_norm.o reg_round.o \ - wm_shrx.o wm_sqrt.o \ - div_Xsig.o polynom_Xsig.o round_Xsig.o \ - shr_Xsig.o mul_Xsig.o - -obj-y =$(C_OBJS) $(A_OBJS) - -proto: - cproto -e -DMAKING_PROTO *.c >fpu_proto.h diff --git a/arch/x86/math-emu/README b/arch/x86/math-emu/README deleted file mode 100644 index e6235491d6eb..000000000000 --- a/arch/x86/math-emu/README +++ /dev/null @@ -1,427 +0,0 @@ - +---------------------------------------------------------------------------+ - | wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors. | - | | - | Copyright (C) 1992,1993,1994,1995,1996,1997,1999 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@melbpc.org.au | - | | - | This program is free software; you can redistribute it and/or modify | - | it under the terms of the GNU General Public License version 2 as | - | published by the Free Software Foundation. | - | | - | This program 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 General Public License for more details. | - | | - | You should have received a copy of the GNU General Public License | - | along with this program; if not, write to the Free Software | - | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | - | | - +---------------------------------------------------------------------------+ - - - -wm-FPU-emu is an FPU emulator for Linux. It is derived from wm-emu387 -which was my 80387 emulator for early versions of djgpp (gcc under -msdos); wm-emu387 was in turn based upon emu387 which was written by -DJ Delorie for djgpp. The interface to the Linux kernel is based upon -the original Linux math emulator by Linus Torvalds. - -My target FPU for wm-FPU-emu is that described in the Intel486 -Programmer's Reference Manual (1992 edition). Unfortunately, numerous -facets of the functioning of the FPU are not well covered in the -Reference Manual. The information in the manual has been supplemented -with measurements on real 80486's. Unfortunately, it is simply not -possible to be sure that all of the peculiarities of the 80486 have -been discovered, so there is always likely to be obscure differences -in the detailed behaviour of the emulator and a real 80486. - -wm-FPU-emu does not implement all of the behaviour of the 80486 FPU, -but is very close. See "Limitations" later in this file for a list of -some differences. - -Please report bugs, etc to me at: - billm@melbpc.org.au -or b.metzenthen@medoto.unimelb.edu.au - -For more information on the emulator and on floating point topics, see -my web pages, currently at http://www.suburbia.net/~billm/ - - ---Bill Metzenthen - December 1999 - - ------------------------ Internals of wm-FPU-emu ----------------------- - -Numeric algorithms: -(1) Add, subtract, and multiply. Nothing remarkable in these. -(2) Divide has been tuned to get reasonable performance. The algorithm - is not the obvious one which most people seem to use, but is designed - to take advantage of the characteristics of the 80386. I expect that - it has been invented many times before I discovered it, but I have not - seen it. It is based upon one of those ideas which one carries around - for years without ever bothering to check it out. -(3) The sqrt function has been tuned to get good performance. It is based - upon Newton's classic method. Performance was improved by capitalizing - upon the properties of Newton's method, and the code is once again - structured taking account of the 80386 characteristics. -(4) The trig, log, and exp functions are based in each case upon quasi- - "optimal" polynomial approximations. My definition of "optimal" was - based upon getting good accuracy with reasonable speed. -(5) The argument reducing code for the trig function effectively uses - a value of pi which is accurate to more than 128 bits. As a consequence, - the reduced argument is accurate to more than 64 bits for arguments up - to a few pi, and accurate to more than 64 bits for most arguments, - even for arguments approaching 2^63. This is far superior to an - 80486, which uses a value of pi which is accurate to 66 bits. - -The code of the emulator is complicated slightly by the need to -account for a limited form of re-entrancy. Normally, the emulator will -emulate each FPU instruction to completion without interruption. -However, it may happen that when the emulator is accessing the user -memory space, swapping may be needed. In this case the emulator may be -temporarily suspended while disk i/o takes place. During this time -another process may use the emulator, thereby perhaps changing static -variables. The code which accesses user memory is confined to five -files: - fpu_entry.c - reg_ld_str.c - load_store.c - get_address.c - errors.c -As from version 1.12 of the emulator, no static variables are used -(apart from those in the kernel's per-process tables). The emulator is -therefore now fully re-entrant, rather than having just the restricted -form of re-entrancy which is required by the Linux kernel. - ------------------------ Limitations of wm-FPU-emu ----------------------- - -There are a number of differences between the current wm-FPU-emu -(version 2.01) and the 80486 FPU (apart from bugs). The differences -are fewer than those which applied to the 1.xx series of the emulator. -Some of the more important differences are listed below: - -The Roundup flag does not have much meaning for the transcendental -functions and its 80486 value with these functions is likely to differ -from its emulator value. - -In a few rare cases the Underflow flag obtained with the emulator will -be different from that obtained with an 80486. This occurs when the -following conditions apply simultaneously: -(a) the operands have a higher precision than the current setting of the - precision control (PC) flags. -(b) the underflow exception is masked. -(c) the magnitude of the exact result (before rounding) is less than 2^-16382. -(d) the magnitude of the final result (after rounding) is exactly 2^-16382. -(e) the magnitude of the exact result would be exactly 2^-16382 if the - operands were rounded to the current precision before the arithmetic - operation was performed. -If all of these apply, the emulator will set the Underflow flag but a real -80486 will not. - -NOTE: Certain formats of Extended Real are UNSUPPORTED. They are -unsupported by the 80486. They are the Pseudo-NaNs, Pseudoinfinities, -and Unnormals. None of these will be generated by an 80486 or by the -emulator. Do not use them. The emulator treats them differently in -detail from the way an 80486 does. - -Self modifying code can cause the emulator to fail. An example of such -code is: - movl %esp,[%ebx] - fld1 -The FPU instruction may be (usually will be) loaded into the pre-fetch -queue of the CPU before the mov instruction is executed. If the -destination of the 'movl' overlaps the FPU instruction then the bytes -in the prefetch queue and memory will be inconsistent when the FPU -instruction is executed. The emulator will be invoked but will not be -able to find the instruction which caused the device-not-present -exception. For this case, the emulator cannot emulate the behaviour of -an 80486DX. - -Handling of the address size override prefix byte (0x67) has not been -extensively tested yet. A major problem exists because using it in -vm86 mode can cause a general protection fault. Address offsets -greater than 0xffff appear to be illegal in vm86 mode but are quite -acceptable (and work) in real mode. A small test program developed to -check the addressing, and which runs successfully in real mode, -crashes dosemu under Linux and also brings Windows down with a general -protection fault message when run under the MS-DOS prompt of Windows -3.1. (The program simply reads data from a valid address). - -The emulator supports 16-bit protected mode, with one difference from -an 80486DX. A 80486DX will allow some floating point instructions to -write a few bytes below the lowest address of the stack. The emulator -will not allow this in 16-bit protected mode: no instructions are -allowed to write outside the bounds set by the protection. - ------------------------ Performance of wm-FPU-emu ----------------------- - -Speed. ------ - -The speed of floating point computation with the emulator will depend -upon instruction mix. Relative performance is best for the instructions -which require most computation. The simple instructions are adversely -affected by the FPU instruction trap overhead. - - -Timing: Some simple timing tests have been made on the emulator functions. -The times include load/store instructions. All times are in microseconds -measured on a 33MHz 386 with 64k cache. The Turbo C tests were under -ms-dos, the next two columns are for emulators running with the djgpp -ms-dos extender. The final column is for wm-FPU-emu in Linux 0.97, -using libm4.0 (hard). - -function Turbo C djgpp 1.06 WM-emu387 wm-FPU-emu - - + 60.5 154.8 76.5 139.4 - - 61.1-65.5 157.3-160.8 76.2-79.5 142.9-144.7 - * 71.0 190.8 79.6 146.6 - / 61.2-75.0 261.4-266.9 75.3-91.6 142.2-158.1 - - sin() 310.8 4692.0 319.0 398.5 - cos() 284.4 4855.2 308.0 388.7 - tan() 495.0 8807.1 394.9 504.7 - atan() 328.9 4866.4 601.1 419.5-491.9 - - sqrt() 128.7 crashed 145.2 227.0 - log() 413.1-419.1 5103.4-5354.21 254.7-282.2 409.4-437.1 - exp() 479.1 6619.2 469.1 850.8 - - -The performance under Linux is improved by the use of look-ahead code. -The following results show the improvement which is obtained under -Linux due to the look-ahead code. Also given are the times for the -original Linux emulator with the 4.1 'soft' lib. - - [ Linus' note: I changed look-ahead to be the default under linux, as - there was no reason not to use it after I had edited it to be - disabled during tracing ] - - wm-FPU-emu w original w - look-ahead 'soft' lib - + 106.4 190.2 - - 108.6-111.6 192.4-216.2 - * 113.4 193.1 - / 108.8-124.4 700.1-706.2 - - sin() 390.5 2642.0 - cos() 381.5 2767.4 - tan() 496.5 3153.3 - atan() 367.2-435.5 2439.4-3396.8 - - sqrt() 195.1 4732.5 - log() 358.0-387.5 3359.2-3390.3 - exp() 619.3 4046.4 - - -These figures are now somewhat out-of-date. The emulator has become -progressively slower for most functions as more of the 80486 features -have been implemented. - - ------------------------ Accuracy of wm-FPU-emu ----------------------- - - -The accuracy of the emulator is in almost all cases equal to or better -than that of an Intel 80486 FPU. - -The results of the basic arithmetic functions (+,-,*,/), and fsqrt -match those of an 80486 FPU. They are the best possible; the error for -these never exceeds 1/2 an lsb. The fprem and fprem1 instructions -return exact results; they have no error. - - -The following table compares the emulator accuracy for the sqrt(), -trig and log functions against the Turbo C "emulator". For this table, -each function was tested at about 400 points. Ideal worst-case results -would be 64 bits. The reduced Turbo C accuracy of cos() and tan() for -arguments greater than pi/4 can be thought of as being related to the -precision of the argument x; e.g. an argument of pi/2-(1e-10) which is -accurate to 64 bits can result in a relative accuracy in cos() of -about 64 + log2(cos(x)) = 31 bits. - - -Function Tested x range Worst result Turbo C - (relative bits) - -sqrt(x) 1 .. 2 64.1 63.2 -atan(x) 1e-10 .. 200 64.2 62.8 -cos(x) 0 .. pi/2-(1e-10) 64.4 (x <= pi/4) 62.4 - 64.1 (x = pi/2-(1e-10)) 31.9 -sin(x) 1e-10 .. pi/2 64.0 62.8 -tan(x) 1e-10 .. pi/2-(1e-10) 64.0 (x <= pi/4) 62.1 - 64.1 (x = pi/2-(1e-10)) 31.9 -exp(x) 0 .. 1 63.1 ** 62.9 -log(x) 1+1e-6 .. 2 63.8 ** 62.1 - -** The accuracy for exp() and log() is low because the FPU (emulator) -does not compute them directly; two operations are required. - - -The emulator passes the "paranoia" tests (compiled with gcc 2.3.3 or -later) for 'float' variables (24 bit precision numbers) when precision -control is set to 24, 53 or 64 bits, and for 'double' variables (53 -bit precision numbers) when precision control is set to 53 bits (a -properly performing FPU cannot pass the 'paranoia' tests for 'double' -variables when precision control is set to 64 bits). - -The code for reducing the argument for the trig functions (fsin, fcos, -fptan and fsincos) has been improved and now effectively uses a value -for pi which is accurate to more than 128 bits precision. As a -consequence, the accuracy of these functions for large arguments has -been dramatically improved (and is now very much better than an 80486 -FPU). There is also now no degradation of accuracy for fcos and fptan -for operands close to pi/2. Measured results are (note that the -definition of accuracy has changed slightly from that used for the -above table): - -Function Tested x range Worst result - (absolute bits) - -cos(x) 0 .. 9.22e+18 62.0 -sin(x) 1e-16 .. 9.22e+18 62.1 -tan(x) 1e-16 .. 9.22e+18 61.8 - -It is possible with some effort to find very large arguments which -give much degraded precision. For example, the integer number - 8227740058411162616.0 -is within about 10e-7 of a multiple of pi. To find the tan (for -example) of this number to 64 bits precision it would be necessary to -have a value of pi which had about 150 bits precision. The FPU -emulator computes the result to about 42.6 bits precision (the correct -result is about -9.739715e-8). On the other hand, an 80486 FPU returns -0.01059, which in relative terms is hopelessly inaccurate. - -For arguments close to critical angles (which occur at multiples of -pi/2) the emulator is more accurate than an 80486 FPU. For very large -arguments, the emulator is far more accurate. - - -Prior to version 1.20 of the emulator, the accuracy of the results for -the transcendental functions (in their principal range) was not as -good as the results from an 80486 FPU. From version 1.20, the accuracy -has been considerably improved and these functions now give measured -worst-case results which are better than the worst-case results given -by an 80486 FPU. - -The following table gives the measured results for the emulator. The -number of randomly selected arguments in each case is about half a -million. The group of three columns gives the frequency of the given -accuracy in number of times per million, thus the second of these -columns shows that an accuracy of between 63.80 and 63.89 bits was -found at a rate of 133 times per one million measurements for fsin. -The results show that the fsin, fcos and fptan instructions return -results which are in error (i.e. less accurate than the best possible -result (which is 64 bits)) for about one per cent of all arguments -between -pi/2 and +pi/2. The other instructions have a lower -frequency of results which are in error. The last two columns give -the worst accuracy which was found (in bits) and the approximate value -of the argument which produced it. - - frequency (per M) - ------------------- --------------- -instr arg range # tests 63.7 63.8 63.9 worst at arg - bits bits bits bits ------ ------------ ------- ---- ---- ----- ----- -------- -fsin (0,pi/2) 547756 0 133 10673 63.89 0.451317 -fcos (0,pi/2) 547563 0 126 10532 63.85 0.700801 -fptan (0,pi/2) 536274 11 267 10059 63.74 0.784876 -fpatan 4 quadrants 517087 0 8 1855 63.88 0.435121 (4q) -fyl2x (0,20) 541861 0 0 1323 63.94 1.40923 (x) -fyl2xp1 (-.293,.414) 520256 0 0 5678 63.93 0.408542 (x) -f2xm1 (-1,1) 538847 4 481 6488 63.79 0.167709 - - -Tests performed on an 80486 FPU showed results of lower accuracy. The -following table gives the results which were obtained with an AMD -486DX2/66 (other tests indicate that an Intel 486DX produces -identical results). The tests were basically the same as those used -to measure the emulator (the values, being random, were in general not -the same). The total number of tests for each instruction are given -at the end of the table, in case each about 100k tests were performed. -Another line of figures at the end of the table shows that most of the -instructions return results which are in error for more than 10 -percent of the arguments tested. - -The numbers in the body of the table give the approx number of times a -result of the given accuracy in bits (given in the left-most column) -was obtained per one million arguments. For three of the instructions, -two columns of results are given: * The second column for f2xm1 gives -the number cases where the results of the first column were for a -positive argument, this shows that this instruction gives better -results for positive arguments than it does for negative. * In the -cases of fcos and fptan, the first column gives the results when all -cases where arguments greater than 1.5 were removed from the results -given in the second column. Unlike the emulator, an 80486 FPU returns -results of relatively poor accuracy for these instructions when the -argument approaches pi/2. The table does not show those cases when the -accuracy of the results were less than 62 bits, which occurs quite -often for fsin and fptan when the argument approaches pi/2. This poor -accuracy is discussed above in relation to the Turbo C "emulator", and -the accuracy of the value of pi. - - -bits f2xm1 f2xm1 fpatan fcos fcos fyl2x fyl2xp1 fsin fptan fptan -62.0 0 0 0 0 437 0 0 0 0 925 -62.1 0 0 10 0 894 0 0 0 0 1023 -62.2 14 0 0 0 1033 0 0 0 0 945 -62.3 57 0 0 0 1202 0 0 0 0 1023 -62.4 385 0 0 10 1292 0 23 0 0 1178 -62.5 1140 0 0 119 1649 0 39 0 0 1149 -62.6 2037 0 0 189 1620 0 16 0 0 1169 -62.7 5086 14 0 646 2315 10 101 35 39 1402 -62.8 8818 86 0 984 3050 59 287 131 224 2036 -62.9 11340 1355 0 2126 4153 79 605 357 321 1948 -63.0 15557 4750 0 3319 5376 246 1281 862 808 2688 -63.1 20016 8288 0 4620 6628 511 2569 1723 1510 3302 -63.2 24945 11127 10 6588 8098 1120 4470 2968 2990 4724 -63.3 25686 12382 69 8774 10682 1906 6775 4482 5474 7236 -63.4 29219 14722 79 11109 12311 3094 9414 7259 8912 10587 -63.5 30458 14936 393 13802 15014 5874 12666 9609 13762 15262 -63.6 32439 16448 1277 17945 19028 10226 15537 14657 19158 20346 -63.7 35031 16805 4067 23003 23947 18910 20116 21333 25001 26209 -63.8 33251 15820 7673 24781 25675 24617 25354 24440 29433 30329 -63.9 33293 16833 18529 28318 29233 31267 31470 27748 29676 30601 - -Per cent with error: - 30.9 3.2 18.5 9.8 13.1 11.6 17.4 -Total arguments tested: - 70194 70099 101784 100641 100641 101799 128853 114893 102675 102675 - - -------------------------- Contributors ------------------------------- - -A number of people have contributed to the development of the -emulator, often by just reporting bugs, sometimes with suggested -fixes, and a few kind people have provided me with access in one way -or another to an 80486 machine. Contributors include (to those people -who I may have forgotten, please forgive me): - -Linus Torvalds -Tommy.Thorn@daimi.aau.dk -Andrew.Tridgell@anu.edu.au -Nick Holloway, alfie@dcs.warwick.ac.uk -Hermano Moura, moura@dcs.gla.ac.uk -Jon Jagger, J.Jagger@scp.ac.uk -Lennart Benschop -Brian Gallew, geek+@CMU.EDU -Thomas Staniszewski, ts3v+@andrew.cmu.edu -Martin Howell, mph@plasma.apana.org.au -M Saggaf, alsaggaf@athena.mit.edu -Peter Barker, PETER@socpsy.sci.fau.edu -tom@vlsivie.tuwien.ac.at -Dan Russel, russed@rpi.edu -Daniel Carosone, danielce@ee.mu.oz.au -cae@jpmorgan.com -Hamish Coleman, t933093@minyos.xx.rmit.oz.au -Bruce Evans, bde@kralizec.zeta.org.au -Timo Korvola, Timo.Korvola@hut.fi -Rick Lyons, rick@razorback.brisnet.org.au -Rick, jrs@world.std.com - -...and numerous others who responded to my request for help with -a real 80486. - diff --git a/arch/x86/math-emu/control_w.h b/arch/x86/math-emu/control_w.h deleted file mode 100644 index 93cbc89b34e2..000000000000 --- a/arch/x86/math-emu/control_w.h +++ /dev/null @@ -1,46 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/*---------------------------------------------------------------------------+ - | control_w.h | - | | - | Copyright (C) 1992,1993 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | - | | - +---------------------------------------------------------------------------*/ - -#ifndef _CONTROLW_H_ -#define _CONTROLW_H_ - -#ifdef __ASSEMBLER__ -#define _Const_(x) $##x -#else -#define _Const_(x) x -#endif - -#define CW_RC _Const_(0x0C00) /* rounding control */ -#define CW_PC _Const_(0x0300) /* precision control */ - -#define CW_Precision Const_(0x0020) /* loss of precision mask */ -#define CW_Underflow Const_(0x0010) /* underflow mask */ -#define CW_Overflow Const_(0x0008) /* overflow mask */ -#define CW_ZeroDiv Const_(0x0004) /* divide by zero mask */ -#define CW_Denormal Const_(0x0002) /* denormalized operand mask */ -#define CW_Invalid Const_(0x0001) /* invalid operation mask */ - -#define CW_Exceptions _Const_(0x003f) /* all masks */ - -#define RC_RND _Const_(0x0000) -#define RC_DOWN _Const_(0x0400) -#define RC_UP _Const_(0x0800) -#define RC_CHOP _Const_(0x0C00) - -/* p 15-5: Precision control bits affect only the following: - ADD, SUB(R), MUL, DIV(R), and SQRT */ -#define PR_24_BITS _Const_(0x000) -#define PR_53_BITS _Const_(0x200) -#define PR_64_BITS _Const_(0x300) -#define PR_RESERVED_BITS _Const_(0x100) -/* FULL_PRECISION simulates all exceptions masked */ -#define FULL_PRECISION (PR_64_BITS | RC_RND | 0x3f) - -#endif /* _CONTROLW_H_ */ diff --git a/arch/x86/math-emu/div_Xsig.S b/arch/x86/math-emu/div_Xsig.S deleted file mode 100644 index 8c270ab415be..000000000000 --- a/arch/x86/math-emu/div_Xsig.S +++ /dev/null @@ -1,367 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - .file "div_Xsig.S" -/*---------------------------------------------------------------------------+ - | div_Xsig.S | - | | - | Division subroutine for 96 bit quantities | - | | - | Copyright (C) 1994,1995 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | - | | - | | - +---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------+ - | Divide the 96 bit quantity pointed to by a, by that pointed to by b, and | - | put the 96 bit result at the location d. | - | | - | The result may not be accurate to 96 bits. It is intended for use where | - | a result better than 64 bits is required. The result should usually be | - | good to at least 94 bits. | - | The returned result is actually divided by one half. This is done to | - | prevent overflow. | - | | - | .aaaaaaaaaaaaaa / .bbbbbbbbbbbbb -> .dddddddddddd | - | | - | void div_Xsig(Xsig *a, Xsig *b, Xsig *dest) | - | | - +---------------------------------------------------------------------------*/ - -#include "exception.h" -#include "fpu_emu.h" - - -#define XsigLL(x) (x) -#define XsigL(x) 4(x) -#define XsigH(x) 8(x) - - -#ifndef NON_REENTRANT_FPU -/* - Local storage on the stack: - Accumulator: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0 - */ -#define FPU_accum_3 -4(%ebp) -#define FPU_accum_2 -8(%ebp) -#define FPU_accum_1 -12(%ebp) -#define FPU_accum_0 -16(%ebp) -#define FPU_result_3 -20(%ebp) -#define FPU_result_2 -24(%ebp) -#define FPU_result_1 -28(%ebp) - -#else -.data -/* - Local storage in a static area: - Accumulator: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0 - */ - .align 4,0 -FPU_accum_3: - .long 0 -FPU_accum_2: - .long 0 -FPU_accum_1: - .long 0 -FPU_accum_0: - .long 0 -FPU_result_3: - .long 0 -FPU_result_2: - .long 0 -FPU_result_1: - .long 0 -#endif /* NON_REENTRANT_FPU */ - - -.text -SYM_FUNC_START(div_Xsig) - pushl %ebp - movl %esp,%ebp -#ifndef NON_REENTRANT_FPU - subl $28,%esp -#endif /* NON_REENTRANT_FPU */ - - pushl %esi - pushl %edi - pushl %ebx - - movl PARAM1,%esi /* pointer to num */ - movl PARAM2,%ebx /* pointer to denom */ - -#ifdef PARANOID - testl $0x80000000, XsigH(%ebx) /* Divisor */ - je L_bugged -#endif /* PARANOID */ - - -/*---------------------------------------------------------------------------+ - | Divide: Return arg1/arg2 to arg3. | - | | - | The maximum returned value is (ignoring exponents) | - | .ffffffff ffffffff | - | ------------------ = 1.ffffffff fffffffe | - | .80000000 00000000 | - | and the minimum is | - | .80000000 00000000 | - | ------------------ = .80000000 00000001 (rounded) | - | .ffffffff ffffffff | - | | - +---------------------------------------------------------------------------*/ - - /* Save extended dividend in local register */ - - /* Divide by 2 to prevent overflow */ - clc - movl XsigH(%esi),%eax - rcrl %eax - movl %eax,FPU_accum_3 - movl XsigL(%esi),%eax - rcrl %eax - movl %eax,FPU_accum_2 - movl XsigLL(%esi),%eax - rcrl %eax - movl %eax,FPU_accum_1 - movl $0,%eax - rcrl %eax - movl %eax,FPU_accum_0 - - movl FPU_accum_2,%eax /* Get the current num */ - movl FPU_accum_3,%edx - -/*----------------------------------------------------------------------*/ -/* Initialization done. - Do the first 32 bits. */ - - /* We will divide by a number which is too large */ - movl XsigH(%ebx),%ecx - addl $1,%ecx - jnc LFirst_div_not_1 - - /* here we need to divide by 100000000h, - i.e., no division at all.. */ - mov %edx,%eax - jmp LFirst_div_done - -LFirst_div_not_1: - divl %ecx /* Divide the numerator by the augmented - denom ms dw */ - -LFirst_div_done: - movl %eax,FPU_result_3 /* Put the result in the answer */ - - mull XsigH(%ebx) /* mul by the ms dw of the denom */ - - subl %eax,FPU_accum_2 /* Subtract from the num local reg */ - sbbl %edx,FPU_accum_3 - - movl FPU_result_3,%eax /* Get the result back */ - mull XsigL(%ebx) /* now mul the ls dw of the denom */ - - subl %eax,FPU_accum_1 /* Subtract from the num local reg */ - sbbl %edx,FPU_accum_2 - sbbl $0,FPU_accum_3 - je LDo_2nd_32_bits /* Must check for non-zero result here */ - -#ifdef PARANOID - jb L_bugged_1 -#endif /* PARANOID */ - - /* need to subtract another once of the denom */ - incl FPU_result_3 /* Correct the answer */ - - movl XsigL(%ebx),%eax - movl XsigH(%ebx),%edx - subl %eax,FPU_accum_1 /* Subtract from the num local reg */ - sbbl %edx,FPU_accum_2 - -#ifdef PARANOID - sbbl $0,FPU_accum_3 - jne L_bugged_1 /* Must check for non-zero result here */ -#endif /* PARANOID */ - -/*----------------------------------------------------------------------*/ -/* Half of the main problem is done, there is just a reduced numerator - to handle now. - Work with the second 32 bits, FPU_accum_0 not used from now on */ -LDo_2nd_32_bits: - movl FPU_accum_2,%edx /* get the reduced num */ - movl FPU_accum_1,%eax - - /* need to check for possible subsequent overflow */ - cmpl XsigH(%ebx),%edx - jb LDo_2nd_div - ja LPrevent_2nd_overflow - - cmpl XsigL(%ebx),%eax - jb LDo_2nd_div - -LPrevent_2nd_overflow: -/* The numerator is greater or equal, would cause overflow */ - /* prevent overflow */ - subl XsigL(%ebx),%eax - sbbl XsigH(%ebx),%edx - movl %edx,FPU_accum_2 - movl %eax,FPU_accum_1 - - incl FPU_result_3 /* Reflect the subtraction in the answer */ - -#ifdef PARANOID - je L_bugged_2 /* Can't bump the result to 1.0 */ -#endif /* PARANOID */ - -LDo_2nd_div: - cmpl $0,%ecx /* augmented denom msw */ - jnz LSecond_div_not_1 - - /* %ecx == 0, we are dividing by 1.0 */ - mov %edx,%eax - jmp LSecond_div_done - -LSecond_div_not_1: - divl %ecx /* Divide the numerator by the denom ms dw */ - -LSecond_div_done: - movl %eax,FPU_result_2 /* Put the result in the answer */ - - mull XsigH(%ebx) /* mul by the ms dw of the denom */ - - subl %eax,FPU_accum_1 /* Subtract from the num local reg */ - sbbl %edx,FPU_accum_2 - -#ifdef PARANOID - jc L_bugged_2 -#endif /* PARANOID */ - - movl FPU_result_2,%eax /* Get the result back */ - mull XsigL(%ebx) /* now mul the ls dw of the denom */ - - subl %eax,FPU_accum_0 /* Subtract from the num local reg */ - sbbl %edx,FPU_accum_1 /* Subtract from the num local reg */ - sbbl $0,FPU_accum_2 - -#ifdef PARANOID - jc L_bugged_2 -#endif /* PARANOID */ - - jz LDo_3rd_32_bits - -#ifdef PARANOID - cmpl $1,FPU_accum_2 - jne L_bugged_2 -#endif /* PARANOID */ - - /* need to subtract another once of the denom */ - movl XsigL(%ebx),%eax - movl XsigH(%ebx),%edx - subl %eax,FPU_accum_0 /* Subtract from the num local reg */ - sbbl %edx,FPU_accum_1 - sbbl $0,FPU_accum_2 - -#ifdef PARANOID - jc L_bugged_2 - jne L_bugged_2 -#endif /* PARANOID */ - - addl $1,FPU_result_2 /* Correct the answer */ - adcl $0,FPU_result_3 - -#ifdef PARANOID - jc L_bugged_2 /* Must check for non-zero result here */ -#endif /* PARANOID */ - -/*----------------------------------------------------------------------*/ -/* The division is essentially finished here, we just need to perform - tidying operations. - Deal with the 3rd 32 bits */ -LDo_3rd_32_bits: - /* We use an approximation for the third 32 bits. - To take account of the 3rd 32 bits of the divisor - (call them del), we subtract del * (a/b) */ - - movl FPU_result_3,%eax /* a/b */ - mull XsigLL(%ebx) /* del */ - - subl %edx,FPU_accum_1 - - /* A borrow indicates that the result is negative */ - jnb LTest_over - - movl XsigH(%ebx),%edx - addl %edx,FPU_accum_1 - - subl $1,FPU_result_2 /* Adjust the answer */ - sbbl $0,FPU_result_3 - - /* The above addition might not have been enough, check again. */ - movl FPU_accum_1,%edx /* get the reduced num */ - cmpl XsigH(%ebx),%edx /* denom */ - jb LDo_3rd_div - - movl XsigH(%ebx),%edx - addl %edx,FPU_accum_1 - - subl $1,FPU_result_2 /* Adjust the answer */ - sbbl $0,FPU_result_3 - jmp LDo_3rd_div - -LTest_over: - movl FPU_accum_1,%edx /* get the reduced num */ - - /* need to check for possible subsequent overflow */ - cmpl XsigH(%ebx),%edx /* denom */ - jb LDo_3rd_div - - /* prevent overflow */ - subl XsigH(%ebx),%edx - movl %edx,FPU_accum_1 - - addl $1,FPU_result_2 /* Reflect the subtraction in the answer */ - adcl $0,FPU_result_3 - -LDo_3rd_div: - movl FPU_accum_0,%eax - movl FPU_accum_1,%edx - divl XsigH(%ebx) - - movl %eax,FPU_result_1 /* Rough estimate of third word */ - - movl PARAM3,%esi /* pointer to answer */ - - movl FPU_result_1,%eax - movl %eax,XsigLL(%esi) - movl FPU_result_2,%eax - movl %eax,XsigL(%esi) - movl FPU_result_3,%eax - movl %eax,XsigH(%esi) - -L_exit: - popl %ebx - popl %edi - popl %esi - - leave - RET - - -#ifdef PARANOID -/* The logic is wrong if we got here */ -L_bugged: - pushl EX_INTERNAL|0x240 - call EXCEPTION - pop %ebx - jmp L_exit - -L_bugged_1: - pushl EX_INTERNAL|0x241 - call EXCEPTION - pop %ebx - jmp L_exit - -L_bugged_2: - pushl EX_INTERNAL|0x242 - call EXCEPTION - pop %ebx - jmp L_exit -#endif /* PARANOID */ -SYM_FUNC_END(div_Xsig) diff --git a/arch/x86/math-emu/div_small.S b/arch/x86/math-emu/div_small.S deleted file mode 100644 index 637439bfefa4..000000000000 --- a/arch/x86/math-emu/div_small.S +++ /dev/null @@ -1,48 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - .file "div_small.S" -/*---------------------------------------------------------------------------+ - | div_small.S | - | | - | Divide a 64 bit integer by a 32 bit integer & return remainder. | - | | - | Copyright (C) 1992,1995 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | - | | - | | - +---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------+ - | unsigned long FPU_div_small(unsigned long long *x, unsigned long y) | - +---------------------------------------------------------------------------*/ - -#include "fpu_emu.h" - -.text -SYM_FUNC_START(FPU_div_small) - pushl %ebp - movl %esp,%ebp - - pushl %esi - - movl PARAM1,%esi /* pointer to num */ - movl PARAM2,%ecx /* The denominator */ - - movl 4(%esi),%eax /* Get the current num msw */ - xorl %edx,%edx - divl %ecx - - movl %eax,4(%esi) - - movl (%esi),%eax /* Get the num lsw */ - divl %ecx - - movl %eax,(%esi) - - movl %edx,%eax /* Return the remainder in eax */ - - popl %esi - - leave - RET -SYM_FUNC_END(FPU_div_small) diff --git a/arch/x86/math-emu/errors.c b/arch/x86/math-emu/errors.c deleted file mode 100644 index ec071cbb0804..000000000000 --- a/arch/x86/math-emu/errors.c +++ /dev/null @@ -1,686 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | errors.c | - | | - | The error handling functions for wm-FPU-emu | - | | - | Copyright (C) 1992,1993,1994,1996 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@jacobi.maths.monash.edu.au | - | | - | | - +---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------+ - | Note: | - | The file contains code which accesses user memory. | - | Emulator static data may change when user memory is accessed, due to | - | other processes using the emulator while swapping is in progress. | - +---------------------------------------------------------------------------*/ - -#include - -#include - -#include "fpu_emu.h" -#include "fpu_system.h" -#include "exception.h" -#include "status_w.h" -#include "control_w.h" -#include "reg_constant.h" -#include "version.h" - -/* */ -#undef PRINT_MESSAGES -/* */ - -#if 0 -void Un_impl(void) -{ - u_char byte1, FPU_modrm; - unsigned long address = FPU_ORIG_EIP; - - RE_ENTRANT_CHECK_OFF; - /* No need to check access_ok(), we have previously fetched these bytes. */ - printk("Unimplemented FPU Opcode at eip=%p : ", (void __user *)address); - if (FPU_CS == __USER_CS) { - while (1) { - FPU_get_user(byte1, (u_char __user *) address); - if ((byte1 & 0xf8) == 0xd8) - break; - printk("[%02x]", byte1); - address++; - } - printk("%02x ", byte1); - FPU_get_user(FPU_modrm, 1 + (u_char __user *) address); - - if (FPU_modrm >= 0300) - printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, - FPU_modrm & 7); - else - printk("/%d\n", (FPU_modrm >> 3) & 7); - } else { - printk("cs selector = %04x\n", FPU_CS); - } - - RE_ENTRANT_CHECK_ON; - - EXCEPTION(EX_Invalid); - -} -#endif /* 0 */ - -/* - Called for opcodes which are illegal and which are known to result in a - SIGILL with a real 80486. - */ -void FPU_illegal(void) -{ - math_abort(FPU_info, SIGILL); -} - -void FPU_printall(void) -{ - int i; - static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "Empty", - "DeNorm", "Inf", "NaN" - }; - u_char byte1, FPU_modrm; - unsigned long address = FPU_ORIG_EIP; - - RE_ENTRANT_CHECK_OFF; - /* No need to check access_ok(), we have previously fetched these bytes. */ - printk("At %p:", (void *)address); - if (FPU_CS == __USER_CS) { -#define MAX_PRINTED_BYTES 20 - for (i = 0; i < MAX_PRINTED_BYTES; i++) { - FPU_get_user(byte1, (u_char __user *) address); - if ((byte1 & 0xf8) == 0xd8) { - printk(" %02x", byte1); - break; - } - printk(" [%02x]", byte1); - address++; - } - if (i == MAX_PRINTED_BYTES) - printk(" [more..]\n"); - else { - FPU_get_user(FPU_modrm, 1 + (u_char __user *) address); - - if (FPU_modrm >= 0300) - printk(" %02x (%02x+%d)\n", FPU_modrm, - FPU_modrm & 0xf8, FPU_modrm & 7); - else - printk(" /%d, mod=%d rm=%d\n", - (FPU_modrm >> 3) & 7, - (FPU_modrm >> 6) & 3, FPU_modrm & 7); - } - } else { - printk("%04x\n", FPU_CS); - } - - partial_status = status_word(); - -#ifdef DEBUGGING - if (partial_status & SW_Backward) - printk("SW: backward compatibility\n"); - if (partial_status & SW_C3) - printk("SW: condition bit 3\n"); - if (partial_status & SW_C2) - printk("SW: condition bit 2\n"); - if (partial_status & SW_C1) - printk("SW: condition bit 1\n"); - if (partial_status & SW_C0) - printk("SW: condition bit 0\n"); - if (partial_status & SW_Summary) - printk("SW: exception summary\n"); - if (partial_status & SW_Stack_Fault) - printk("SW: stack fault\n"); - if (partial_status & SW_Precision) - printk("SW: loss of precision\n"); - if (partial_status & SW_Underflow) - printk("SW: underflow\n"); - if (partial_status & SW_Overflow) - printk("SW: overflow\n"); - if (partial_status & SW_Zero_Div) - printk("SW: divide by zero\n"); - if (partial_status & SW_Denorm_Op) - printk("SW: denormalized operand\n"); - if (partial_status & SW_Invalid) - printk("SW: invalid operation\n"); -#endif /* DEBUGGING */ - - printk(" SW: b=%d st=%d es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n", partial_status & 0x8000 ? 1 : 0, /* busy */ - (partial_status & 0x3800) >> 11, /* stack top pointer */ - partial_status & 0x80 ? 1 : 0, /* Error summary status */ - partial_status & 0x40 ? 1 : 0, /* Stack flag */ - partial_status & SW_C3 ? 1 : 0, partial_status & SW_C2 ? 1 : 0, /* cc */ - partial_status & SW_C1 ? 1 : 0, partial_status & SW_C0 ? 1 : 0, /* cc */ - partial_status & SW_Precision ? 1 : 0, - partial_status & SW_Underflow ? 1 : 0, - partial_status & SW_Overflow ? 1 : 0, - partial_status & SW_Zero_Div ? 1 : 0, - partial_status & SW_Denorm_Op ? 1 : 0, - partial_status & SW_Invalid ? 1 : 0); - - printk(" CW: ic=%d rc=%d%d pc=%d%d iem=%d ef=%d%d%d%d%d%d\n", - control_word & 0x1000 ? 1 : 0, - (control_word & 0x800) >> 11, (control_word & 0x400) >> 10, - (control_word & 0x200) >> 9, (control_word & 0x100) >> 8, - control_word & 0x80 ? 1 : 0, - control_word & SW_Precision ? 1 : 0, - control_word & SW_Underflow ? 1 : 0, - control_word & SW_Overflow ? 1 : 0, - control_word & SW_Zero_Div ? 1 : 0, - control_word & SW_Denorm_Op ? 1 : 0, - control_word & SW_Invalid ? 1 : 0); - - for (i = 0; i < 8; i++) { - FPU_REG *r = &st(i); - u_char tagi = FPU_gettagi(i); - - switch (tagi) { - case TAG_Empty: - continue; - case TAG_Zero: - case TAG_Special: - /* Update tagi for the printk below */ - tagi = FPU_Special(r); - fallthrough; - case TAG_Valid: - printk("st(%d) %c .%04lx %04lx %04lx %04lx e%+-6d ", i, - getsign(r) ? '-' : '+', - (long)(r->sigh >> 16), - (long)(r->sigh & 0xFFFF), - (long)(r->sigl >> 16), - (long)(r->sigl & 0xFFFF), - exponent(r) - EXP_BIAS + 1); - break; - default: - printk("Whoops! Error in errors.c: tag%d is %d ", i, - tagi); - continue; - } - printk("%s\n", tag_desc[(int)(unsigned)tagi]); - } - - RE_ENTRANT_CHECK_ON; - -} - -static struct { - int type; - const char *name; -} exception_names[] = { - { - EX_StackOver, "stack overflow"}, { - EX_StackUnder, "stack underflow"}, { - EX_Precision, "loss of precision"}, { - EX_Underflow, "underflow"}, { - EX_Overflow, "overflow"}, { - EX_ZeroDiv, "divide by zero"}, { - EX_Denormal, "denormalized operand"}, { - EX_Invalid, "invalid operation"}, { - EX_INTERNAL, "INTERNAL BUG in " FPU_VERSION}, { - 0, NULL} -}; - -/* - EX_INTERNAL is always given with a code which indicates where the - error was detected. - - Internal error types: - 0x14 in fpu_etc.c - 0x1nn in a *.c file: - 0x101 in reg_add_sub.c - 0x102 in reg_mul.c - 0x104 in poly_atan.c - 0x105 in reg_mul.c - 0x107 in fpu_trig.c - 0x108 in reg_compare.c - 0x109 in reg_compare.c - 0x110 in reg_add_sub.c - 0x111 in fpe_entry.c - 0x112 in fpu_trig.c - 0x113 in errors.c - 0x115 in fpu_trig.c - 0x116 in fpu_trig.c - 0x117 in fpu_trig.c - 0x118 in fpu_trig.c - 0x119 in fpu_trig.c - 0x120 in poly_atan.c - 0x121 in reg_compare.c - 0x122 in reg_compare.c - 0x123 in reg_compare.c - 0x125 in fpu_trig.c - 0x126 in fpu_entry.c - 0x127 in poly_2xm1.c - 0x128 in fpu_entry.c - 0x129 in fpu_entry.c - 0x130 in get_address.c - 0x131 in get_address.c - 0x132 in get_address.c - 0x133 in get_address.c - 0x140 in load_store.c - 0x141 in load_store.c - 0x150 in poly_sin.c - 0x151 in poly_sin.c - 0x160 in reg_ld_str.c - 0x161 in reg_ld_str.c - 0x162 in reg_ld_str.c - 0x163 in reg_ld_str.c - 0x164 in reg_ld_str.c - 0x170 in fpu_tags.c - 0x171 in fpu_tags.c - 0x172 in fpu_tags.c - 0x180 in reg_convert.c - 0x2nn in an *.S file: - 0x201 in reg_u_add.S - 0x202 in reg_u_div.S - 0x203 in reg_u_div.S - 0x204 in reg_u_div.S - 0x205 in reg_u_mul.S - 0x206 in reg_u_sub.S - 0x207 in wm_sqrt.S - 0x208 in reg_div.S - 0x209 in reg_u_sub.S - 0x210 in reg_u_sub.S - 0x211 in reg_u_sub.S - 0x212 in reg_u_sub.S - 0x213 in wm_sqrt.S - 0x214 in wm_sqrt.S - 0x215 in wm_sqrt.S - 0x220 in reg_norm.S - 0x221 in reg_norm.S - 0x230 in reg_round.S - 0x231 in reg_round.S - 0x232 in reg_round.S - 0x233 in reg_round.S - 0x234 in reg_round.S - 0x235 in reg_round.S - 0x236 in reg_round.S - 0x240 in div_Xsig.S - 0x241 in div_Xsig.S - 0x242 in div_Xsig.S - */ - -asmlinkage __visible void FPU_exception(int n) -{ - int i, int_type; - - int_type = 0; /* Needed only to stop compiler warnings */ - if (n & EX_INTERNAL) { - int_type = n - EX_INTERNAL; - n = EX_INTERNAL; - /* Set lots of exception bits! */ - partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward); - } else { - /* Extract only the bits which we use to set the status word */ - n &= (SW_Exc_Mask); - /* Set the corresponding exception bit */ - partial_status |= n; - /* Set summary bits iff exception isn't masked */ - if (partial_status & ~control_word & CW_Exceptions) - partial_status |= (SW_Summary | SW_Backward); - if (n & (SW_Stack_Fault | EX_Precision)) { - if (!(n & SW_C1)) - /* This bit distinguishes over- from underflow for a stack fault, - and roundup from round-down for precision loss. */ - partial_status &= ~SW_C1; - } - } - - RE_ENTRANT_CHECK_OFF; - if ((~control_word & n & CW_Exceptions) || (n == EX_INTERNAL)) { - /* Get a name string for error reporting */ - for (i = 0; exception_names[i].type; i++) - if ((exception_names[i].type & n) == - exception_names[i].type) - break; - - if (exception_names[i].type) { -#ifdef PRINT_MESSAGES - printk("FP Exception: %s!\n", exception_names[i].name); -#endif /* PRINT_MESSAGES */ - } else - printk("FPU emulator: Unknown Exception: 0x%04x!\n", n); - - if (n == EX_INTERNAL) { - printk("FPU emulator: Internal error type 0x%04x\n", - int_type); - FPU_printall(); - } -#ifdef PRINT_MESSAGES - else - FPU_printall(); -#endif /* PRINT_MESSAGES */ - - /* - * The 80486 generates an interrupt on the next non-control FPU - * instruction. So we need some means of flagging it. - * We use the ES (Error Summary) bit for this. - */ - } - RE_ENTRANT_CHECK_ON; - -#ifdef __DEBUG__ - math_abort(FPU_info, SIGFPE); -#endif /* __DEBUG__ */ - -} - -/* Real operation attempted on a NaN. */ -/* Returns < 0 if the exception is unmasked */ -int real_1op_NaN(FPU_REG *a) -{ - int signalling, isNaN; - - isNaN = (exponent(a) == EXP_OVER) && (a->sigh & 0x80000000); - - /* The default result for the case of two "equal" NaNs (signs may - differ) is chosen to reproduce 80486 behaviour */ - signalling = isNaN && !(a->sigh & 0x40000000); - - if (!signalling) { - if (!isNaN) { /* pseudo-NaN, or other unsupported? */ - if (control_word & CW_Invalid) { - /* Masked response */ - reg_copy(&CONST_QNaN, a); - } - EXCEPTION(EX_Invalid); - return (!(control_word & CW_Invalid) ? FPU_Exception : - 0) | TAG_Special; - } - return TAG_Special; - } - - if (control_word & CW_Invalid) { - /* The masked response */ - if (!(a->sigh & 0x80000000)) { /* pseudo-NaN ? */ - reg_copy(&CONST_QNaN, a); - } - /* ensure a Quiet NaN */ - a->sigh |= 0x40000000; - } - - EXCEPTION(EX_Invalid); - - return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special; -} - -/* Real operation attempted on two operands, one a NaN. */ -/* Returns < 0 if the exception is unmasked */ -int real_2op_NaN(FPU_REG const *b, u_char tagb, - int deststnr, FPU_REG const *defaultNaN) -{ - FPU_REG *dest = &st(deststnr); - FPU_REG const *a = dest; - u_char taga = FPU_gettagi(deststnr); - FPU_REG const *x; - int signalling, unsupported; - - if (taga == TAG_Special) - taga = FPU_Special(a); - if (tagb == TAG_Special) - tagb = FPU_Special(b); - - /* TW_NaN is also used for unsupported data types. */ - unsupported = ((taga == TW_NaN) - && !((exponent(a) == EXP_OVER) - && (a->sigh & 0x80000000))) - || ((tagb == TW_NaN) - && !((exponent(b) == EXP_OVER) && (b->sigh & 0x80000000))); - if (unsupported) { - if (control_word & CW_Invalid) { - /* Masked response */ - FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr); - } - EXCEPTION(EX_Invalid); - return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | - TAG_Special; - } - - if (taga == TW_NaN) { - x = a; - if (tagb == TW_NaN) { - signalling = !(a->sigh & b->sigh & 0x40000000); - if (significand(b) > significand(a)) - x = b; - else if (significand(b) == significand(a)) { - /* The default result for the case of two "equal" NaNs (signs may - differ) is chosen to reproduce 80486 behaviour */ - x = defaultNaN; - } - } else { - /* return the quiet version of the NaN in a */ - signalling = !(a->sigh & 0x40000000); - } - } else -#ifdef PARANOID - if (tagb == TW_NaN) -#endif /* PARANOID */ - { - signalling = !(b->sigh & 0x40000000); - x = b; - } -#ifdef PARANOID - else { - signalling = 0; - EXCEPTION(EX_INTERNAL | 0x113); - x = &CONST_QNaN; - } -#endif /* PARANOID */ - - if ((!signalling) || (control_word & CW_Invalid)) { - if (!x) - x = b; - - if (!(x->sigh & 0x80000000)) /* pseudo-NaN ? */ - x = &CONST_QNaN; - - FPU_copy_to_regi(x, TAG_Special, deststnr); - - if (!signalling) - return TAG_Special; - - /* ensure a Quiet NaN */ - dest->sigh |= 0x40000000; - } - - EXCEPTION(EX_Invalid); - - return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special; -} - -/* Invalid arith operation on Valid registers */ -/* Returns < 0 if the exception is unmasked */ -asmlinkage __visible int arith_invalid(int deststnr) -{ - - EXCEPTION(EX_Invalid); - - if (control_word & CW_Invalid) { - /* The masked response */ - FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr); - } - - return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Valid; - -} - -/* Divide a finite number by zero */ -asmlinkage __visible int FPU_divide_by_zero(int deststnr, u_char sign) -{ - FPU_REG *dest = &st(deststnr); - int tag = TAG_Valid; - - if (control_word & CW_ZeroDiv) { - /* The masked response */ - FPU_copy_to_regi(&CONST_INF, TAG_Special, deststnr); - setsign(dest, sign); - tag = TAG_Special; - } - - EXCEPTION(EX_ZeroDiv); - - return (!(control_word & CW_ZeroDiv) ? FPU_Exception : 0) | tag; - -} - -/* This may be called often, so keep it lean */ -int set_precision_flag(int flags) -{ - if (control_word & CW_Precision) { - partial_status &= ~(SW_C1 & flags); - partial_status |= flags; /* The masked response */ - return 0; - } else { - EXCEPTION(flags); - return 1; - } -} - -/* This may be called often, so keep it lean */ -asmlinkage __visible void set_precision_flag_up(void) -{ - if (control_word & CW_Precision) - partial_status |= (SW_Precision | SW_C1); /* The masked response */ - else - EXCEPTION(EX_Precision | SW_C1); -} - -/* This may be called often, so keep it lean */ -asmlinkage __visible void set_precision_flag_down(void) -{ - if (control_word & CW_Precision) { /* The masked response */ - partial_status &= ~SW_C1; - partial_status |= SW_Precision; - } else - EXCEPTION(EX_Precision); -} - -asmlinkage __visible int denormal_operand(void) -{ - if (control_word & CW_Denormal) { /* The masked response */ - partial_status |= SW_Denorm_Op; - return TAG_Special; - } else { - EXCEPTION(EX_Denormal); - return TAG_Special | FPU_Exception; - } -} - -asmlinkage __visible int arith_overflow(FPU_REG *dest) -{ - int tag = TAG_Valid; - - if (control_word & CW_Overflow) { - /* The masked response */ -/* ###### The response here depends upon the rounding mode */ - reg_copy(&CONST_INF, dest); - tag = TAG_Special; - } else { - /* Subtract the magic number from the exponent */ - addexponent(dest, (-3 * (1 << 13))); - } - - EXCEPTION(EX_Overflow); - if (control_word & CW_Overflow) { - /* The overflow exception is masked. */ - /* By definition, precision is lost. - The roundup bit (C1) is also set because we have - "rounded" upwards to Infinity. */ - EXCEPTION(EX_Precision | SW_C1); - return tag; - } - - return tag; - -} - -asmlinkage __visible int arith_underflow(FPU_REG *dest) -{ - int tag = TAG_Valid; - - if (control_word & CW_Underflow) { - /* The masked response */ - if (exponent16(dest) <= EXP_UNDER - 63) { - reg_copy(&CONST_Z, dest); - partial_status &= ~SW_C1; /* Round down. */ - tag = TAG_Zero; - } else { - stdexp(dest); - } - } else { - /* Add the magic number to the exponent. */ - addexponent(dest, (3 * (1 << 13)) + EXTENDED_Ebias); - } - - EXCEPTION(EX_Underflow); - if (control_word & CW_Underflow) { - /* The underflow exception is masked. */ - EXCEPTION(EX_Precision); - return tag; - } - - return tag; - -} - -void FPU_stack_overflow(void) -{ - - if (control_word & CW_Invalid) { - /* The masked response */ - top--; - FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); - } - - EXCEPTION(EX_StackOver); - - return; - -} - -void FPU_stack_underflow(void) -{ - - if (control_word & CW_Invalid) { - /* The masked response */ - FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); - } - - EXCEPTION(EX_StackUnder); - - return; - -} - -void FPU_stack_underflow_i(int i) -{ - - if (control_word & CW_Invalid) { - /* The masked response */ - FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i); - } - - EXCEPTION(EX_StackUnder); - - return; - -} - -void FPU_stack_underflow_pop(int i) -{ - - if (control_word & CW_Invalid) { - /* The masked response */ - FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i); - FPU_pop(); - } - - EXCEPTION(EX_StackUnder); - - return; - -} diff --git a/arch/x86/math-emu/exception.h b/arch/x86/math-emu/exception.h deleted file mode 100644 index 59961d350bc4..000000000000 --- a/arch/x86/math-emu/exception.h +++ /dev/null @@ -1,51 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/*---------------------------------------------------------------------------+ - | exception.h | - | | - | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | - | | - +---------------------------------------------------------------------------*/ - -#ifndef _EXCEPTION_H_ -#define _EXCEPTION_H_ - -#ifdef __ASSEMBLER__ -#define Const_(x) $##x -#else -#define Const_(x) x -#endif - -#ifndef SW_C1 -#include "fpu_emu.h" -#endif /* SW_C1 */ - -#define FPU_BUSY Const_(0x8000) /* FPU busy bit (8087 compatibility) */ -#define EX_ErrorSummary Const_(0x0080) /* Error summary status */ -/* Special exceptions: */ -#define EX_INTERNAL Const_(0x8000) /* Internal error in wm-FPU-emu */ -#define EX_StackOver Const_(0x0041|SW_C1) /* stack overflow */ -#define EX_StackUnder Const_(0x0041) /* stack underflow */ -/* Exception flags: */ -#define EX_Precision Const_(0x0020) /* loss of precision */ -#define EX_Underflow Const_(0x0010) /* underflow */ -#define EX_Overflow Const_(0x0008) /* overflow */ -#define EX_ZeroDiv Const_(0x0004) /* divide by zero */ -#define EX_Denormal Const_(0x0002) /* denormalized operand */ -#define EX_Invalid Const_(0x0001) /* invalid operation */ - -#define PRECISION_LOST_UP Const_((EX_Precision | SW_C1)) -#define PRECISION_LOST_DOWN Const_(EX_Precision) - -#ifndef __ASSEMBLER__ - -#ifdef DEBUG -#define EXCEPTION(x) { printk("exception in %s at line %d\n", \ - __FILE__, __LINE__); FPU_exception(x); } -#else -#define EXCEPTION(x) FPU_exception(x) -#endif - -#endif /* __ASSEMBLER__ */ - -#endif /* _EXCEPTION_H_ */ diff --git a/arch/x86/math-emu/fpu_arith.c b/arch/x86/math-emu/fpu_arith.c deleted file mode 100644 index 09006dc474a0..000000000000 --- a/arch/x86/math-emu/fpu_arith.c +++ /dev/null @@ -1,153 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | fpu_arith.c | - | | - | Code to implement the FPU register/register arithmetic instructions | - | | - | Copyright (C) 1992,1993,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@suburbia.net | - | | - | | - +---------------------------------------------------------------------------*/ - -#include "fpu_system.h" -#include "fpu_emu.h" -#include "control_w.h" -#include "status_w.h" - -void fadd__(void) -{ - /* fadd st,st(i) */ - int i = FPU_rm; - clear_C1(); - FPU_add(&st(i), FPU_gettagi(i), 0, control_word); -} - -void fmul__(void) -{ - /* fmul st,st(i) */ - int i = FPU_rm; - clear_C1(); - FPU_mul(&st(i), FPU_gettagi(i), 0, control_word); -} - -void fsub__(void) -{ - /* fsub st,st(i) */ - clear_C1(); - FPU_sub(0, FPU_rm, control_word); -} - -void fsubr_(void) -{ - /* fsubr st,st(i) */ - clear_C1(); - FPU_sub(REV, FPU_rm, control_word); -} - -void fdiv__(void) -{ - /* fdiv st,st(i) */ - clear_C1(); - FPU_div(0, FPU_rm, control_word); -} - -void fdivr_(void) -{ - /* fdivr st,st(i) */ - clear_C1(); - FPU_div(REV, FPU_rm, control_word); -} - -void fadd_i(void) -{ - /* fadd st(i),st */ - int i = FPU_rm; - clear_C1(); - FPU_add(&st(i), FPU_gettagi(i), i, control_word); -} - -void fmul_i(void) -{ - /* fmul st(i),st */ - clear_C1(); - FPU_mul(&st(0), FPU_gettag0(), FPU_rm, control_word); -} - -void fsubri(void) -{ - /* fsubr st(i),st */ - clear_C1(); - FPU_sub(DEST_RM, FPU_rm, control_word); -} - -void fsub_i(void) -{ - /* fsub st(i),st */ - clear_C1(); - FPU_sub(REV | DEST_RM, FPU_rm, control_word); -} - -void fdivri(void) -{ - /* fdivr st(i),st */ - clear_C1(); - FPU_div(DEST_RM, FPU_rm, control_word); -} - -void fdiv_i(void) -{ - /* fdiv st(i),st */ - clear_C1(); - FPU_div(REV | DEST_RM, FPU_rm, control_word); -} - -void faddp_(void) -{ - /* faddp st(i),st */ - int i = FPU_rm; - clear_C1(); - if (FPU_add(&st(i), FPU_gettagi(i), i, control_word) >= 0) - FPU_pop(); -} - -void fmulp_(void) -{ - /* fmulp st(i),st */ - clear_C1(); - if (FPU_mul(&st(0), FPU_gettag0(), FPU_rm, control_word) >= 0) - FPU_pop(); -} - -void fsubrp(void) -{ - /* fsubrp st(i),st */ - clear_C1(); - if (FPU_sub(DEST_RM, FPU_rm, control_word) >= 0) - FPU_pop(); -} - -void fsubp_(void) -{ - /* fsubp st(i),st */ - clear_C1(); - if (FPU_sub(REV | DEST_RM, FPU_rm, control_word) >= 0) - FPU_pop(); -} - -void fdivrp(void) -{ - /* fdivrp st(i),st */ - clear_C1(); - if (FPU_div(DEST_RM, FPU_rm, control_word) >= 0) - FPU_pop(); -} - -void fdivp_(void) -{ - /* fdivp st(i),st */ - clear_C1(); - if (FPU_div(REV | DEST_RM, FPU_rm, control_word) >= 0) - FPU_pop(); -} diff --git a/arch/x86/math-emu/fpu_asm.h b/arch/x86/math-emu/fpu_asm.h deleted file mode 100644 index a83353d5271c..000000000000 --- a/arch/x86/math-emu/fpu_asm.h +++ /dev/null @@ -1,32 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/*---------------------------------------------------------------------------+ - | fpu_asm.h | - | | - | Copyright (C) 1992,1995,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@suburbia.net | - | | - +---------------------------------------------------------------------------*/ - -#ifndef _FPU_ASM_H_ -#define _FPU_ASM_H_ - -#include - -#define EXCEPTION FPU_exception - -#define PARAM1 8(%ebp) -#define PARAM2 12(%ebp) -#define PARAM3 16(%ebp) -#define PARAM4 20(%ebp) -#define PARAM5 24(%ebp) -#define PARAM6 28(%ebp) -#define PARAM7 32(%ebp) - -#define SIGL_OFFSET 0 -#define EXP(x) 8(x) -#define SIG(x) SIGL_OFFSET##(x) -#define SIGL(x) SIGL_OFFSET##(x) -#define SIGH(x) 4(x) - -#endif /* _FPU_ASM_H_ */ diff --git a/arch/x86/math-emu/fpu_aux.c b/arch/x86/math-emu/fpu_aux.c deleted file mode 100644 index 5f253ae406b6..000000000000 --- a/arch/x86/math-emu/fpu_aux.c +++ /dev/null @@ -1,267 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | fpu_aux.c | - | | - | Code to implement some of the FPU auxiliary instructions. | - | | - | Copyright (C) 1992,1993,1994,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@suburbia.net | - | | - | | - +---------------------------------------------------------------------------*/ - -#include "fpu_system.h" -#include "exception.h" -#include "fpu_emu.h" -#include "status_w.h" -#include "control_w.h" - -static void fnop(void) -{ -} - -static void fclex(void) -{ - partial_status &= - ~(SW_Backward | SW_Summary | SW_Stack_Fault | SW_Precision | - SW_Underflow | SW_Overflow | SW_Zero_Div | SW_Denorm_Op | - SW_Invalid); - no_ip_update = 1; -} - -/* Needs to be externally visible */ -void fpstate_init_soft(struct swregs_state *soft) -{ - struct address *oaddr, *iaddr; - memset(soft, 0, sizeof(*soft)); - soft->cwd = 0x037f; - soft->swd = 0; - soft->ftop = 0; /* We don't keep top in the status word internally. */ - soft->twd = 0xffff; - /* The behaviour is different from that detailed in - Section 15.1.6 of the Intel manual */ - oaddr = (struct address *)&soft->foo; - oaddr->offset = 0; - oaddr->selector = 0; - iaddr = (struct address *)&soft->fip; - iaddr->offset = 0; - iaddr->selector = 0; - iaddr->opcode = 0; - soft->no_update = 1; -} - -void finit(void) -{ - fpstate_init_soft(&x86_task_fpu(current)->fpstate->regs.soft); -} - -/* - * These are nops on the i387.. - */ -#define feni fnop -#define fdisi fnop -#define fsetpm fnop - -static FUNC const finit_table[] = { - feni, fdisi, fclex, finit, - fsetpm, FPU_illegal, FPU_illegal, FPU_illegal -}; - -void finit_(void) -{ - (finit_table[FPU_rm]) (); -} - -static void fstsw_ax(void) -{ - *(short *)&FPU_EAX = status_word(); - no_ip_update = 1; -} - -static FUNC const fstsw_table[] = { - fstsw_ax, FPU_illegal, FPU_illegal, FPU_illegal, - FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal -}; - -void fstsw_(void) -{ - (fstsw_table[FPU_rm]) (); -} - -static FUNC const fp_nop_table[] = { - fnop, FPU_illegal, FPU_illegal, FPU_illegal, - FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal -}; - -void fp_nop(void) -{ - (fp_nop_table[FPU_rm]) (); -} - -void fld_i_(void) -{ - FPU_REG *st_new_ptr; - int i; - u_char tag; - - if (STACK_OVERFLOW) { - FPU_stack_overflow(); - return; - } - - /* fld st(i) */ - i = FPU_rm; - if (NOT_EMPTY(i)) { - reg_copy(&st(i), st_new_ptr); - tag = FPU_gettagi(i); - push(); - FPU_settag0(tag); - } else { - if (control_word & CW_Invalid) { - /* The masked response */ - FPU_stack_underflow(); - } else - EXCEPTION(EX_StackUnder); - } - -} - -void fxch_i(void) -{ - /* fxch st(i) */ - FPU_REG t; - int i = FPU_rm; - FPU_REG *st0_ptr = &st(0), *sti_ptr = &st(i); - long tag_word = fpu_tag_word; - int regnr = top & 7, regnri = ((regnr + i) & 7); - u_char st0_tag = (tag_word >> (regnr * 2)) & 3; - u_char sti_tag = (tag_word >> (regnri * 2)) & 3; - - if (st0_tag == TAG_Empty) { - if (sti_tag == TAG_Empty) { - FPU_stack_underflow(); - FPU_stack_underflow_i(i); - return; - } - if (control_word & CW_Invalid) { - /* Masked response */ - FPU_copy_to_reg0(sti_ptr, sti_tag); - } - FPU_stack_underflow_i(i); - return; - } - if (sti_tag == TAG_Empty) { - if (control_word & CW_Invalid) { - /* Masked response */ - FPU_copy_to_regi(st0_ptr, st0_tag, i); - } - FPU_stack_underflow(); - return; - } - clear_C1(); - - reg_copy(st0_ptr, &t); - reg_copy(sti_ptr, st0_ptr); - reg_copy(&t, sti_ptr); - - tag_word &= ~(3 << (regnr * 2)) & ~(3 << (regnri * 2)); - tag_word |= (sti_tag << (regnr * 2)) | (st0_tag << (regnri * 2)); - fpu_tag_word = tag_word; -} - -static void fcmovCC(void) -{ - /* fcmovCC st(i) */ - int i = FPU_rm; - FPU_REG *st0_ptr = &st(0); - FPU_REG *sti_ptr = &st(i); - long tag_word = fpu_tag_word; - int regnr = top & 7; - int regnri = (top + i) & 7; - u_char sti_tag = (tag_word >> (regnri * 2)) & 3; - - if (sti_tag == TAG_Empty) { - FPU_stack_underflow(); - clear_C1(); - return; - } - reg_copy(sti_ptr, st0_ptr); - tag_word &= ~(3 << (regnr * 2)); - tag_word |= (sti_tag << (regnr * 2)); - fpu_tag_word = tag_word; -} - -void fcmovb(void) -{ - if (FPU_EFLAGS & X86_EFLAGS_CF) - fcmovCC(); -} - -void fcmove(void) -{ - if (FPU_EFLAGS & X86_EFLAGS_ZF) - fcmovCC(); -} - -void fcmovbe(void) -{ - if (FPU_EFLAGS & (X86_EFLAGS_CF|X86_EFLAGS_ZF)) - fcmovCC(); -} - -void fcmovu(void) -{ - if (FPU_EFLAGS & X86_EFLAGS_PF) - fcmovCC(); -} - -void fcmovnb(void) -{ - if (!(FPU_EFLAGS & X86_EFLAGS_CF)) - fcmovCC(); -} - -void fcmovne(void) -{ - if (!(FPU_EFLAGS & X86_EFLAGS_ZF)) - fcmovCC(); -} - -void fcmovnbe(void) -{ - if (!(FPU_EFLAGS & (X86_EFLAGS_CF|X86_EFLAGS_ZF))) - fcmovCC(); -} - -void fcmovnu(void) -{ - if (!(FPU_EFLAGS & X86_EFLAGS_PF)) - fcmovCC(); -} - -void ffree_(void) -{ - /* ffree st(i) */ - FPU_settagi(FPU_rm, TAG_Empty); -} - -void ffreep(void) -{ - /* ffree st(i) + pop - unofficial code */ - FPU_settagi(FPU_rm, TAG_Empty); - FPU_pop(); -} - -void fst_i_(void) -{ - /* fst st(i) */ - FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm); -} - -void fstp_i(void) -{ - /* fstp st(i) */ - FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm); - FPU_pop(); -} diff --git a/arch/x86/math-emu/fpu_emu.h b/arch/x86/math-emu/fpu_emu.h deleted file mode 100644 index def569c50b76..000000000000 --- a/arch/x86/math-emu/fpu_emu.h +++ /dev/null @@ -1,218 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/*---------------------------------------------------------------------------+ - | fpu_emu.h | - | | - | Copyright (C) 1992,1993,1994,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@suburbia.net | - | | - +---------------------------------------------------------------------------*/ - -#ifndef _FPU_EMU_H_ -#define _FPU_EMU_H_ - -/* - * Define PECULIAR_486 to get a closer approximation to 80486 behaviour, - * rather than behaviour which appears to be cleaner. - * This is a matter of opinion: for all I know, the 80486 may simply - * be complying with the IEEE spec. Maybe one day I'll get to see the - * spec... - */ -#define PECULIAR_486 - -#ifdef __ASSEMBLER__ -#include "fpu_asm.h" -#define Const(x) $##x -#else -#define Const(x) x -#endif - -#define EXP_BIAS Const(0) -#define EXP_OVER Const(0x4000) /* smallest invalid large exponent */ -#define EXP_UNDER Const(-0x3fff) /* largest invalid small exponent */ -#define EXP_WAY_UNDER Const(-0x6000) /* Below the smallest denormal, but - still a 16 bit nr. */ -#define EXP_Infinity EXP_OVER -#define EXP_NaN EXP_OVER - -#define EXTENDED_Ebias Const(0x3fff) -#define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */ - -#define SIGN_POS Const(0) -#define SIGN_NEG Const(0x80) - -#define SIGN_Positive Const(0) -#define SIGN_Negative Const(0x8000) - -/* Keep the order TAG_Valid, TAG_Zero, TW_Denormal */ -/* The following fold to 2 (Special) in the Tag Word */ -#define TW_Denormal Const(4) /* De-normal */ -#define TW_Infinity Const(5) /* + or - infinity */ -#define TW_NaN Const(6) /* Not a Number */ -#define TW_Unsupported Const(7) /* Not supported by an 80486 */ - -#define TAG_Valid Const(0) /* valid */ -#define TAG_Zero Const(1) /* zero */ -#define TAG_Special Const(2) /* De-normal, + or - infinity, - or Not a Number */ -#define TAG_Empty Const(3) /* empty */ -#define TAG_Error Const(0x80) /* probably need to abort */ - -#define LOADED_DATA Const(10101) /* Special st() number to identify - loaded data (not on stack). */ - -/* A few flags (must be >= 0x10). */ -#define REV 0x10 -#define DEST_RM 0x20 -#define LOADED 0x40 - -#define FPU_Exception Const(0x80000000) /* Added to tag returns. */ - -#ifndef __ASSEMBLER__ - -#include "fpu_system.h" - -#include /* for struct _fpstate */ -#include -#include - -/* -#define RE_ENTRANT_CHECKING - */ - -#ifdef RE_ENTRANT_CHECKING -extern u_char emulating; -# define RE_ENTRANT_CHECK_OFF emulating = 0 -# define RE_ENTRANT_CHECK_ON emulating = 1 -#else -# define RE_ENTRANT_CHECK_OFF -# define RE_ENTRANT_CHECK_ON -#endif /* RE_ENTRANT_CHECKING */ - -#define FWAIT_OPCODE 0x9b -#define OP_SIZE_PREFIX 0x66 -#define ADDR_SIZE_PREFIX 0x67 -#define PREFIX_CS 0x2e -#define PREFIX_DS 0x3e -#define PREFIX_ES 0x26 -#define PREFIX_SS 0x36 -#define PREFIX_FS 0x64 -#define PREFIX_GS 0x65 -#define PREFIX_REPE 0xf3 -#define PREFIX_REPNE 0xf2 -#define PREFIX_LOCK 0xf0 -#define PREFIX_CS_ 1 -#define PREFIX_DS_ 2 -#define PREFIX_ES_ 3 -#define PREFIX_FS_ 4 -#define PREFIX_GS_ 5 -#define PREFIX_SS_ 6 -#define PREFIX_DEFAULT 7 - -struct address { - unsigned int offset; - unsigned int selector:16; - unsigned int opcode:11; - unsigned int empty:5; -}; -struct fpu__reg { - unsigned sigl; - unsigned sigh; - short exp; -}; - -typedef void (*FUNC) (void); -typedef struct fpu__reg FPU_REG; -typedef void (*FUNC_ST0) (FPU_REG *st0_ptr, u_char st0_tag); -typedef struct { - u_char address_size, operand_size, segment; -} overrides; -/* This structure is 32 bits: */ -typedef struct { - overrides override; - u_char default_mode; -} fpu_addr_modes; -/* PROTECTED has a restricted meaning in the emulator; it is used - to signal that the emulator needs to do special things to ensure - that protection is respected in a segmented model. */ -#define PROTECTED 4 -#define SIXTEEN 1 /* We rely upon this being 1 (true) */ -#define VM86 SIXTEEN -#define PM16 (SIXTEEN | PROTECTED) -#define SEG32 PROTECTED -extern u_char const data_sizes_16[32]; - -#define register_base ((u_char *) registers ) -#define fpu_register(x) ( * ((FPU_REG *)( register_base + 10 * (x & 7) )) ) -#define st(x) ( * ((FPU_REG *)( register_base + 10 * ((top+x) & 7) )) ) - -#define STACK_OVERFLOW (FPU_stackoverflow(&st_new_ptr)) -#define NOT_EMPTY(i) (!FPU_empty_i(i)) - -#define NOT_EMPTY_ST0 (st0_tag ^ TAG_Empty) - -#define poppop() { FPU_pop(); FPU_pop(); } - -/* push() does not affect the tags */ -#define push() { top--; } - -#define signbyte(a) (((u_char *)(a))[9]) -#define getsign(a) (signbyte(a) & 0x80) -#define setsign(a,b) { if ((b) != 0) signbyte(a) |= 0x80; else signbyte(a) &= 0x7f; } -#define copysign(a,b) { if (getsign(a)) signbyte(b) |= 0x80; \ - else signbyte(b) &= 0x7f; } -#define changesign(a) { signbyte(a) ^= 0x80; } -#define setpositive(a) { signbyte(a) &= 0x7f; } -#define setnegative(a) { signbyte(a) |= 0x80; } -#define signpositive(a) ( (signbyte(a) & 0x80) == 0 ) -#define signnegative(a) (signbyte(a) & 0x80) - -static inline void reg_copy(FPU_REG const *x, FPU_REG *y) -{ - *(short *)&(y->exp) = *(const short *)&(x->exp); - *(long long *)&(y->sigl) = *(const long long *)&(x->sigl); -} - -#define exponent(x) (((*(short *)&((x)->exp)) & 0x7fff) - EXTENDED_Ebias) -#define setexponentpos(x,y) { (*(short *)&((x)->exp)) = \ - ((y) + EXTENDED_Ebias) & 0x7fff; } -#define exponent16(x) (*(short *)&((x)->exp)) -#define setexponent16(x,y) { (*(short *)&((x)->exp)) = (u16)(y); } -#define addexponent(x,y) { (*(short *)&((x)->exp)) += (y); } -#define stdexp(x) { (*(short *)&((x)->exp)) += EXTENDED_Ebias; } - -#define isdenormal(ptr) (exponent(ptr) == EXP_BIAS+EXP_UNDER) - -#define significand(x) ( ((unsigned long long *)&((x)->sigl))[0] ) - -/*----- Prototypes for functions written in assembler -----*/ -/* extern void reg_move(FPU_REG *a, FPU_REG *b); */ - -asmlinkage int FPU_normalize(FPU_REG *x); -asmlinkage int FPU_normalize_nuo(FPU_REG *x); -asmlinkage int FPU_u_sub(FPU_REG const *arg1, FPU_REG const *arg2, - FPU_REG * answ, unsigned int control_w, u_char sign, - int expa, int expb); -asmlinkage int FPU_u_mul(FPU_REG const *arg1, FPU_REG const *arg2, - FPU_REG * answ, unsigned int control_w, u_char sign, - int expon); -asmlinkage int FPU_u_div(FPU_REG const *arg1, FPU_REG const *arg2, - FPU_REG * answ, unsigned int control_w, u_char sign); -asmlinkage int FPU_u_add(FPU_REG const *arg1, FPU_REG const *arg2, - FPU_REG * answ, unsigned int control_w, u_char sign, - int expa, int expb); -asmlinkage int wm_sqrt(FPU_REG *n, int dummy1, int dummy2, - unsigned int control_w, u_char sign); -asmlinkage unsigned FPU_shrx(void *l, unsigned x); -asmlinkage unsigned FPU_shrxs(void *v, unsigned x); -asmlinkage unsigned long FPU_div_small(unsigned long long *x, unsigned long y); -asmlinkage int FPU_round(FPU_REG *arg, unsigned int extent, int dummy, - unsigned int control_w, u_char sign); - -#ifndef MAKING_PROTO -#include "fpu_proto.h" -#endif - -#endif /* __ASSEMBLER__ */ - -#endif /* _FPU_EMU_H_ */ diff --git a/arch/x86/math-emu/fpu_entry.c b/arch/x86/math-emu/fpu_entry.c deleted file mode 100644 index 5034df617740..000000000000 --- a/arch/x86/math-emu/fpu_entry.c +++ /dev/null @@ -1,718 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | fpu_entry.c | - | | - | The entry functions for wm-FPU-emu | - | | - | Copyright (C) 1992,1993,1994,1996,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@suburbia.net | - | | - | See the files "README" and "COPYING" for further copyright and warranty | - | information. | - | | - +---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------+ - | Note: | - | The file contains code which accesses user memory. | - | Emulator static data may change when user memory is accessed, due to | - | other processes using the emulator while swapping is in progress. | - +---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------+ - | math_emulate(), restore_i387_soft() and save_i387_soft() are the only | - | entry points for wm-FPU-emu. | - +---------------------------------------------------------------------------*/ - -#include -#include - -#include -#include -#include -#include -#include - -#include "fpu_system.h" -#include "fpu_emu.h" -#include "exception.h" -#include "control_w.h" -#include "status_w.h" - -#define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */ - -/* fcmovCC and f(u)comi(p) are enabled if CPUID(1).EDX(15) "cmov" is set */ - -/* WARNING: "u" entries are not documented by Intel in their 80486 manual - and may not work on FPU clones or later Intel FPUs. - Changes to support them provided by Linus Torvalds. */ - -static FUNC const st_instr_table[64] = { -/* Opcode: d8 d9 da db */ -/* dc dd de df */ -/* c0..7 */ fadd__, fld_i_, fcmovb, fcmovnb, -/* c0..7 */ fadd_i, ffree_, faddp_, ffreep,/*u*/ -/* c8..f */ fmul__, fxch_i, fcmove, fcmovne, -/* c8..f */ fmul_i, fxch_i,/*u*/ fmulp_, fxch_i,/*u*/ -/* d0..7 */ fcom_st, fp_nop, fcmovbe, fcmovnbe, -/* d0..7 */ fcom_st,/*u*/ fst_i_, fcompst,/*u*/ fstp_i,/*u*/ -/* d8..f */ fcompst, fstp_i,/*u*/ fcmovu, fcmovnu, -/* d8..f */ fcompst,/*u*/ fstp_i, fcompp, fstp_i,/*u*/ -/* e0..7 */ fsub__, FPU_etc, __BAD__, finit_, -/* e0..7 */ fsubri, fucom_, fsubrp, fstsw_, -/* e8..f */ fsubr_, fconst, fucompp, fucomi_, -/* e8..f */ fsub_i, fucomp, fsubp_, fucomip, -/* f0..7 */ fdiv__, FPU_triga, __BAD__, fcomi_, -/* f0..7 */ fdivri, __BAD__, fdivrp, fcomip, -/* f8..f */ fdivr_, FPU_trigb, __BAD__, __BAD__, -/* f8..f */ fdiv_i, __BAD__, fdivp_, __BAD__, -}; - -#define _NONE_ 0 /* Take no special action */ -#define _REG0_ 1 /* Need to check for not empty st(0) */ -#define _REGI_ 2 /* Need to check for not empty st(0) and st(rm) */ -#define _REGi_ 0 /* Uses st(rm) */ -#define _PUSH_ 3 /* Need to check for space to push onto stack */ -#define _null_ 4 /* Function illegal or not implemented */ -#define _REGIi 5 /* Uses st(0) and st(rm), result to st(rm) */ -#define _REGIp 6 /* Uses st(0) and st(rm), result to st(rm) then pop */ -#define _REGIc 0 /* Compare st(0) and st(rm) */ -#define _REGIn 0 /* Uses st(0) and st(rm), but handle checks later */ - -static u_char const type_table[64] = { -/* Opcode: d8 d9 da db dc dd de df */ -/* c0..7 */ _REGI_, _NONE_, _REGIn, _REGIn, _REGIi, _REGi_, _REGIp, _REGi_, -/* c8..f */ _REGI_, _REGIn, _REGIn, _REGIn, _REGIi, _REGI_, _REGIp, _REGI_, -/* d0..7 */ _REGIc, _NONE_, _REGIn, _REGIn, _REGIc, _REG0_, _REGIc, _REG0_, -/* d8..f */ _REGIc, _REG0_, _REGIn, _REGIn, _REGIc, _REG0_, _REGIc, _REG0_, -/* e0..7 */ _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_, -/* e8..f */ _REGI_, _NONE_, _REGIc, _REGIc, _REGIi, _REGIc, _REGIp, _REGIc, -/* f0..7 */ _REGI_, _NONE_, _null_, _REGIc, _REGIi, _null_, _REGIp, _REGIc, -/* f8..f */ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_, -}; - -#ifdef RE_ENTRANT_CHECKING -u_char emulating = 0; -#endif /* RE_ENTRANT_CHECKING */ - -static int valid_prefix(u_char *Byte, u_char __user ** fpu_eip, - overrides * override); - -void math_emulate(struct math_emu_info *info) -{ - u_char FPU_modrm, byte1; - unsigned short code; - fpu_addr_modes addr_modes; - int unmasked; - FPU_REG loaded_data; - FPU_REG *st0_ptr; - u_char loaded_tag, st0_tag; - void __user *data_address; - struct address data_sel_off; - struct address entry_sel_off; - unsigned long code_base = 0; - unsigned long code_limit = 0; /* Initialized to stop compiler warnings */ - struct desc_struct code_descriptor; - -#ifdef RE_ENTRANT_CHECKING - if (emulating) { - printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n"); - } - RE_ENTRANT_CHECK_ON; -#endif /* RE_ENTRANT_CHECKING */ - - FPU_info = info; - - FPU_ORIG_EIP = FPU_EIP; - - if ((FPU_EFLAGS & 0x00020000) != 0) { - /* Virtual 8086 mode */ - addr_modes.default_mode = VM86; - FPU_EIP += code_base = FPU_CS << 4; - code_limit = code_base + 0xffff; /* Assumes code_base <= 0xffff0000 */ - } else if (FPU_CS == __USER_CS && FPU_DS == __USER_DS) { - addr_modes.default_mode = 0; - } else if (FPU_CS == __KERNEL_CS) { - printk("math_emulate: %04x:%08lx\n", FPU_CS, FPU_EIP); - panic("Math emulation needed in kernel"); - } else { - - if ((FPU_CS & 4) != 4) { /* Must be in the LDT */ - /* Can only handle segmented addressing via the LDT - for now, and it must be 16 bit */ - printk("FPU emulator: Unsupported addressing mode\n"); - math_abort(FPU_info, SIGILL); - } - - code_descriptor = FPU_get_ldt_descriptor(FPU_CS); - if (code_descriptor.d) { - /* The above test may be wrong, the book is not clear */ - /* Segmented 32 bit protected mode */ - addr_modes.default_mode = SEG32; - } else { - /* 16 bit protected mode */ - addr_modes.default_mode = PM16; - } - FPU_EIP += code_base = seg_get_base(&code_descriptor); - code_limit = seg_get_limit(&code_descriptor) + 1; - code_limit *= seg_get_granularity(&code_descriptor); - code_limit += code_base - 1; - if (code_limit < code_base) - code_limit = 0xffffffff; - } - - FPU_lookahead = !(FPU_EFLAGS & X86_EFLAGS_TF); - - if (!valid_prefix(&byte1, (u_char __user **) & FPU_EIP, - &addr_modes.override)) { - RE_ENTRANT_CHECK_OFF; - printk - ("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n" - "FPU emulator: self-modifying code! (emulation impossible)\n", - byte1); - RE_ENTRANT_CHECK_ON; - EXCEPTION(EX_INTERNAL | 0x126); - math_abort(FPU_info, SIGILL); - } - - do_another_FPU_instruction: - - no_ip_update = 0; - - FPU_EIP++; /* We have fetched the prefix and first code bytes. */ - - if (addr_modes.default_mode) { - /* This checks for the minimum instruction bytes. - We also need to check any extra (address mode) code access. */ - if (FPU_EIP > code_limit) - math_abort(FPU_info, SIGSEGV); - } - - if ((byte1 & 0xf8) != 0xd8) { - if (byte1 == FWAIT_OPCODE) { - if (partial_status & SW_Summary) - goto do_the_FPU_interrupt; - else - goto FPU_fwait_done; - } -#ifdef PARANOID - EXCEPTION(EX_INTERNAL | 0x128); - math_abort(FPU_info, SIGILL); -#endif /* PARANOID */ - } - - RE_ENTRANT_CHECK_OFF; - FPU_code_access_ok(1); - FPU_get_user(FPU_modrm, (u_char __user *) FPU_EIP); - RE_ENTRANT_CHECK_ON; - FPU_EIP++; - - if (partial_status & SW_Summary) { - /* Ignore the error for now if the current instruction is a no-wait - control instruction */ - /* The 80486 manual contradicts itself on this topic, - but a real 80486 uses the following instructions: - fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex. - */ - code = (FPU_modrm << 8) | byte1; - if (!((((code & 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */ - (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv, - fnstsw */ - ((code & 0xc000) != 0xc000))))) { - /* - * We need to simulate the action of the kernel to FPU - * interrupts here. - */ - do_the_FPU_interrupt: - - FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */ - - RE_ENTRANT_CHECK_OFF; - current->thread.trap_nr = X86_TRAP_MF; - current->thread.error_code = 0; - send_sig(SIGFPE, current, 1); - return; - } - } - - entry_sel_off.offset = FPU_ORIG_EIP; - entry_sel_off.selector = FPU_CS; - entry_sel_off.opcode = (byte1 << 8) | FPU_modrm; - entry_sel_off.empty = 0; - - FPU_rm = FPU_modrm & 7; - - if (FPU_modrm < 0300) { - /* All of these instructions use the mod/rm byte to get a data address */ - - if ((addr_modes.default_mode & SIXTEEN) - ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX)) - data_address = - FPU_get_address_16(FPU_modrm, &FPU_EIP, - &data_sel_off, addr_modes); - else - data_address = - FPU_get_address(FPU_modrm, &FPU_EIP, &data_sel_off, - addr_modes); - - if (addr_modes.default_mode) { - if (FPU_EIP - 1 > code_limit) - math_abort(FPU_info, SIGSEGV); - } - - if (!(byte1 & 1)) { - unsigned short status1 = partial_status; - - st0_ptr = &st(0); - st0_tag = FPU_gettag0(); - - /* Stack underflow has priority */ - if (NOT_EMPTY_ST0) { - if (addr_modes.default_mode & PROTECTED) { - /* This table works for 16 and 32 bit protected mode */ - if (access_limit < - data_sizes_16[(byte1 >> 1) & 3]) - math_abort(FPU_info, SIGSEGV); - } - - unmasked = 0; /* Do this here to stop compiler warnings. */ - switch ((byte1 >> 1) & 3) { - case 0: - unmasked = - FPU_load_single((float __user *) - data_address, - &loaded_data); - loaded_tag = unmasked & 0xff; - unmasked &= ~0xff; - break; - case 1: - loaded_tag = - FPU_load_int32((long __user *) - data_address, - &loaded_data); - break; - case 2: - unmasked = - FPU_load_double((double __user *) - data_address, - &loaded_data); - loaded_tag = unmasked & 0xff; - unmasked &= ~0xff; - break; - case 3: - default: /* Used here to suppress gcc warnings. */ - loaded_tag = - FPU_load_int16((short __user *) - data_address, - &loaded_data); - break; - } - - /* No more access to user memory, it is safe - to use static data now */ - - /* NaN operands have the next priority. */ - /* We have to delay looking at st(0) until after - loading the data, because that data might contain an SNaN */ - if (((st0_tag == TAG_Special) && isNaN(st0_ptr)) - || ((loaded_tag == TAG_Special) - && isNaN(&loaded_data))) { - /* Restore the status word; we might have loaded a - denormal. */ - partial_status = status1; - if ((FPU_modrm & 0x30) == 0x10) { - /* fcom or fcomp */ - EXCEPTION(EX_Invalid); - setcc(SW_C3 | SW_C2 | SW_C0); - if ((FPU_modrm & 0x08) - && (control_word & - CW_Invalid)) - FPU_pop(); /* fcomp, masked, so we pop. */ - } else { - if (loaded_tag == TAG_Special) - loaded_tag = - FPU_Special - (&loaded_data); -#ifdef PECULIAR_486 - /* This is not really needed, but gives behaviour - identical to an 80486 */ - if ((FPU_modrm & 0x28) == 0x20) - /* fdiv or fsub */ - real_2op_NaN - (&loaded_data, - loaded_tag, 0, - &loaded_data); - else -#endif /* PECULIAR_486 */ - /* fadd, fdivr, fmul, or fsubr */ - real_2op_NaN - (&loaded_data, - loaded_tag, 0, - st0_ptr); - } - goto reg_mem_instr_done; - } - - if (unmasked && !((FPU_modrm & 0x30) == 0x10)) { - /* Is not a comparison instruction. */ - if ((FPU_modrm & 0x38) == 0x38) { - /* fdivr */ - if ((st0_tag == TAG_Zero) && - ((loaded_tag == TAG_Valid) - || (loaded_tag == - TAG_Special - && - isdenormal - (&loaded_data)))) { - if (FPU_divide_by_zero - (0, - getsign - (&loaded_data)) - < 0) { - /* We use the fact here that the unmasked - exception in the loaded data was for a - denormal operand */ - /* Restore the state of the denormal op bit */ - partial_status - &= - ~SW_Denorm_Op; - partial_status - |= - status1 & - SW_Denorm_Op; - } else - setsign(st0_ptr, - getsign - (&loaded_data)); - } - } - goto reg_mem_instr_done; - } - - switch ((FPU_modrm >> 3) & 7) { - case 0: /* fadd */ - clear_C1(); - FPU_add(&loaded_data, loaded_tag, 0, - control_word); - break; - case 1: /* fmul */ - clear_C1(); - FPU_mul(&loaded_data, loaded_tag, 0, - control_word); - break; - case 2: /* fcom */ - FPU_compare_st_data(&loaded_data, - loaded_tag); - break; - case 3: /* fcomp */ - if (!FPU_compare_st_data - (&loaded_data, loaded_tag) - && !unmasked) - FPU_pop(); - break; - case 4: /* fsub */ - clear_C1(); - FPU_sub(LOADED | loaded_tag, - (int)&loaded_data, - control_word); - break; - case 5: /* fsubr */ - clear_C1(); - FPU_sub(REV | LOADED | loaded_tag, - (int)&loaded_data, - control_word); - break; - case 6: /* fdiv */ - clear_C1(); - FPU_div(LOADED | loaded_tag, - (int)&loaded_data, - control_word); - break; - case 7: /* fdivr */ - clear_C1(); - if (st0_tag == TAG_Zero) - partial_status = status1; /* Undo any denorm tag, - zero-divide has priority. */ - FPU_div(REV | LOADED | loaded_tag, - (int)&loaded_data, - control_word); - break; - } - } else { - if ((FPU_modrm & 0x30) == 0x10) { - /* The instruction is fcom or fcomp */ - EXCEPTION(EX_StackUnder); - setcc(SW_C3 | SW_C2 | SW_C0); - if ((FPU_modrm & 0x08) - && (control_word & CW_Invalid)) - FPU_pop(); /* fcomp */ - } else - FPU_stack_underflow(); - } - reg_mem_instr_done: - operand_address = data_sel_off; - } else { - if (!(no_ip_update = - FPU_load_store(((FPU_modrm & 0x38) | (byte1 & 6)) - >> 1, addr_modes, data_address))) { - operand_address = data_sel_off; - } - } - - } else { - /* None of these instructions access user memory */ - u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7); - -#ifdef PECULIAR_486 - /* This is supposed to be undefined, but a real 80486 seems - to do this: */ - operand_address.offset = 0; - operand_address.selector = FPU_DS; -#endif /* PECULIAR_486 */ - - st0_ptr = &st(0); - st0_tag = FPU_gettag0(); - switch (type_table[(int)instr_index]) { - case _NONE_: /* also _REGIc: _REGIn */ - break; - case _REG0_: - if (!NOT_EMPTY_ST0) { - FPU_stack_underflow(); - goto FPU_instruction_done; - } - break; - case _REGIi: - if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) { - FPU_stack_underflow_i(FPU_rm); - goto FPU_instruction_done; - } - break; - case _REGIp: - if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) { - FPU_stack_underflow_pop(FPU_rm); - goto FPU_instruction_done; - } - break; - case _REGI_: - if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) { - FPU_stack_underflow(); - goto FPU_instruction_done; - } - break; - case _PUSH_: /* Only used by the fld st(i) instruction */ - break; - case _null_: - FPU_illegal(); - goto FPU_instruction_done; - default: - EXCEPTION(EX_INTERNAL | 0x111); - goto FPU_instruction_done; - } - (*st_instr_table[(int)instr_index]) (); - - FPU_instruction_done: - ; - } - - if (!no_ip_update) - instruction_address = entry_sel_off; - - FPU_fwait_done: - -#ifdef DEBUG - RE_ENTRANT_CHECK_OFF; - FPU_printall(); - RE_ENTRANT_CHECK_ON; -#endif /* DEBUG */ - - if (FPU_lookahead && !need_resched()) { - FPU_ORIG_EIP = FPU_EIP - code_base; - if (valid_prefix(&byte1, (u_char __user **) & FPU_EIP, - &addr_modes.override)) - goto do_another_FPU_instruction; - } - - if (addr_modes.default_mode) - FPU_EIP -= code_base; - - RE_ENTRANT_CHECK_OFF; -} - -/* Support for prefix bytes is not yet complete. To properly handle - all prefix bytes, further changes are needed in the emulator code - which accesses user address space. Access to separate segments is - important for msdos emulation. */ -static int valid_prefix(u_char *Byte, u_char __user **fpu_eip, - overrides * override) -{ - u_char byte; - u_char __user *ip = *fpu_eip; - - *override = (overrides) { - 0, 0, PREFIX_DEFAULT}; /* defaults */ - - RE_ENTRANT_CHECK_OFF; - FPU_code_access_ok(1); - FPU_get_user(byte, ip); - RE_ENTRANT_CHECK_ON; - - while (1) { - switch (byte) { - case ADDR_SIZE_PREFIX: - override->address_size = ADDR_SIZE_PREFIX; - goto do_next_byte; - - case OP_SIZE_PREFIX: - override->operand_size = OP_SIZE_PREFIX; - goto do_next_byte; - - case PREFIX_CS: - override->segment = PREFIX_CS_; - goto do_next_byte; - case PREFIX_ES: - override->segment = PREFIX_ES_; - goto do_next_byte; - case PREFIX_SS: - override->segment = PREFIX_SS_; - goto do_next_byte; - case PREFIX_FS: - override->segment = PREFIX_FS_; - goto do_next_byte; - case PREFIX_GS: - override->segment = PREFIX_GS_; - goto do_next_byte; - case PREFIX_DS: - override->segment = PREFIX_DS_; - goto do_next_byte; - -/* lock is not a valid prefix for FPU instructions, - let the cpu handle it to generate a SIGILL. */ -/* case PREFIX_LOCK: */ - - /* rep.. prefixes have no meaning for FPU instructions */ - case PREFIX_REPE: - case PREFIX_REPNE: - - do_next_byte: - ip++; - RE_ENTRANT_CHECK_OFF; - FPU_code_access_ok(1); - FPU_get_user(byte, ip); - RE_ENTRANT_CHECK_ON; - break; - case FWAIT_OPCODE: - *Byte = byte; - return 1; - default: - if ((byte & 0xf8) == 0xd8) { - *Byte = byte; - *fpu_eip = ip; - return 1; - } else { - /* Not a valid sequence of prefix bytes followed by - an FPU instruction. */ - *Byte = byte; /* Needed for error message. */ - return 0; - } - } - } -} - -void math_abort(struct math_emu_info *info, unsigned int signal) -{ - FPU_EIP = FPU_ORIG_EIP; - current->thread.trap_nr = X86_TRAP_MF; - current->thread.error_code = 0; - send_sig(signal, current, 1); - RE_ENTRANT_CHECK_OFF; - __asm__("movl %0,%%esp ; ret": :"g"(((long)info) - 4)); -#ifdef PARANOID - printk("ERROR: wm-FPU-emu math_abort failed!\n"); -#endif /* PARANOID */ -} - -#define S387 ((struct swregs_state *)s387) -#define sstatus_word() \ - ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top)) - -int fpregs_soft_set(struct task_struct *target, - const struct user_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - struct swregs_state *s387 = &x86_task_fpu(target)->fpstate->regs.soft; - void *space = s387->st_space; - int ret; - int offset, other, i, tags, regnr, tag, newtop; - - RE_ENTRANT_CHECK_OFF; - ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, s387, 0, - offsetof(struct swregs_state, st_space)); - RE_ENTRANT_CHECK_ON; - - if (ret) - return ret; - - S387->ftop = (S387->swd >> SW_Top_Shift) & 7; - offset = (S387->ftop & 7) * 10; - other = 80 - offset; - - RE_ENTRANT_CHECK_OFF; - - /* Copy all registers in stack order. */ - ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - space + offset, 0, other); - if (!ret && offset) - ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - space, 0, offset); - - RE_ENTRANT_CHECK_ON; - - /* The tags may need to be corrected now. */ - tags = S387->twd; - newtop = S387->ftop; - for (i = 0; i < 8; i++) { - regnr = (i + newtop) & 7; - if (((tags >> ((regnr & 7) * 2)) & 3) != TAG_Empty) { - /* The loaded data over-rides all other cases. */ - tag = - FPU_tagof((FPU_REG *) ((u_char *) S387->st_space + - 10 * regnr)); - tags &= ~(3 << (regnr * 2)); - tags |= (tag & 3) << (regnr * 2); - } - } - S387->twd = tags; - - return ret; -} - -int fpregs_soft_get(struct task_struct *target, - const struct user_regset *regset, - struct membuf to) -{ - struct swregs_state *s387 = &x86_task_fpu(target)->fpstate->regs.soft; - const void *space = s387->st_space; - int offset = (S387->ftop & 7) * 10, other = 80 - offset; - - RE_ENTRANT_CHECK_OFF; - -#ifdef PECULIAR_486 - S387->cwd &= ~0xe080; - /* An 80486 sets nearly all of the reserved bits to 1. */ - S387->cwd |= 0xffff0040; - S387->swd = sstatus_word() | 0xffff0000; - S387->twd |= 0xffff0000; - S387->fcs &= ~0xf8000000; - S387->fos |= 0xffff0000; -#endif /* PECULIAR_486 */ - - membuf_write(&to, s387, offsetof(struct swregs_state, st_space)); - membuf_write(&to, space + offset, other); - membuf_write(&to, space, offset); - - RE_ENTRANT_CHECK_ON; - - return 0; -} diff --git a/arch/x86/math-emu/fpu_etc.c b/arch/x86/math-emu/fpu_etc.c deleted file mode 100644 index 39423ec409e1..000000000000 --- a/arch/x86/math-emu/fpu_etc.c +++ /dev/null @@ -1,136 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | fpu_etc.c | - | | - | Implement a few FPU instructions. | - | | - | Copyright (C) 1992,1993,1994,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@suburbia.net | - | | - | | - +---------------------------------------------------------------------------*/ - -#include "fpu_system.h" -#include "exception.h" -#include "fpu_emu.h" -#include "status_w.h" -#include "reg_constant.h" - -static void fchs(FPU_REG *st0_ptr, u_char st0tag) -{ - if (st0tag ^ TAG_Empty) { - signbyte(st0_ptr) ^= SIGN_NEG; - clear_C1(); - } else - FPU_stack_underflow(); -} - -static void fabs(FPU_REG *st0_ptr, u_char st0tag) -{ - if (st0tag ^ TAG_Empty) { - setpositive(st0_ptr); - clear_C1(); - } else - FPU_stack_underflow(); -} - -static void ftst_(FPU_REG *st0_ptr, u_char st0tag) -{ - switch (st0tag) { - case TAG_Zero: - setcc(SW_C3); - break; - case TAG_Valid: - if (getsign(st0_ptr) == SIGN_POS) - setcc(0); - else - setcc(SW_C0); - break; - case TAG_Special: - switch (FPU_Special(st0_ptr)) { - case TW_Denormal: - if (getsign(st0_ptr) == SIGN_POS) - setcc(0); - else - setcc(SW_C0); - if (denormal_operand() < 0) { -#ifdef PECULIAR_486 - /* This is weird! */ - if (getsign(st0_ptr) == SIGN_POS) - setcc(SW_C3); -#endif /* PECULIAR_486 */ - return; - } - break; - case TW_NaN: - setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */ - EXCEPTION(EX_Invalid); - break; - case TW_Infinity: - if (getsign(st0_ptr) == SIGN_POS) - setcc(0); - else - setcc(SW_C0); - break; - default: - setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */ - EXCEPTION(EX_INTERNAL | 0x14); - break; - } - break; - case TAG_Empty: - setcc(SW_C0 | SW_C2 | SW_C3); - EXCEPTION(EX_StackUnder); - break; - } -} - -static void fxam(FPU_REG *st0_ptr, u_char st0tag) -{ - int c = 0; - switch (st0tag) { - case TAG_Empty: - c = SW_C3 | SW_C0; - break; - case TAG_Zero: - c = SW_C3; - break; - case TAG_Valid: - c = SW_C2; - break; - case TAG_Special: - switch (FPU_Special(st0_ptr)) { - case TW_Denormal: - c = SW_C2 | SW_C3; /* Denormal */ - break; - case TW_NaN: - /* We also use NaN for unsupported types. */ - if ((st0_ptr->sigh & 0x80000000) - && (exponent(st0_ptr) == EXP_OVER)) - c = SW_C0; - break; - case TW_Infinity: - c = SW_C2 | SW_C0; - break; - } - } - if (getsign(st0_ptr) == SIGN_NEG) - c |= SW_C1; - setcc(c); -} - -static void FPU_ST0_illegal(FPU_REG *st0_ptr, u_char st0_tag) -{ - FPU_illegal(); -} - -static FUNC_ST0 const fp_etc_table[] = { - fchs, fabs, FPU_ST0_illegal, FPU_ST0_illegal, - ftst_, fxam, FPU_ST0_illegal, FPU_ST0_illegal, -}; - -void FPU_etc(void) -{ - (fp_etc_table[FPU_rm]) (&st(0), FPU_gettag0()); -} diff --git a/arch/x86/math-emu/fpu_proto.h b/arch/x86/math-emu/fpu_proto.h deleted file mode 100644 index 94c4023092f3..000000000000 --- a/arch/x86/math-emu/fpu_proto.h +++ /dev/null @@ -1,157 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _FPU_PROTO_H -#define _FPU_PROTO_H - -/* errors.c */ -extern void FPU_illegal(void); -extern void FPU_printall(void); -asmlinkage void FPU_exception(int n); -extern int real_1op_NaN(FPU_REG *a); -extern int real_2op_NaN(FPU_REG const *b, u_char tagb, int deststnr, - FPU_REG const *defaultNaN); -asmlinkage int arith_invalid(int deststnr); -asmlinkage int FPU_divide_by_zero(int deststnr, u_char sign); -extern int set_precision_flag(int flags); -asmlinkage void set_precision_flag_up(void); -asmlinkage void set_precision_flag_down(void); -asmlinkage int denormal_operand(void); -asmlinkage int arith_overflow(FPU_REG *dest); -asmlinkage int arith_underflow(FPU_REG *dest); -extern void FPU_stack_overflow(void); -extern void FPU_stack_underflow(void); -extern void FPU_stack_underflow_i(int i); -extern void FPU_stack_underflow_pop(int i); -/* fpu_arith.c */ -extern void fadd__(void); -extern void fmul__(void); -extern void fsub__(void); -extern void fsubr_(void); -extern void fdiv__(void); -extern void fdivr_(void); -extern void fadd_i(void); -extern void fmul_i(void); -extern void fsubri(void); -extern void fsub_i(void); -extern void fdivri(void); -extern void fdiv_i(void); -extern void faddp_(void); -extern void fmulp_(void); -extern void fsubrp(void); -extern void fsubp_(void); -extern void fdivrp(void); -extern void fdivp_(void); -/* fpu_aux.c */ -extern void finit(void); -extern void finit_(void); -extern void fstsw_(void); -extern void fp_nop(void); -extern void fld_i_(void); -extern void fxch_i(void); -extern void fcmovb(void); -extern void fcmove(void); -extern void fcmovbe(void); -extern void fcmovu(void); -extern void fcmovnb(void); -extern void fcmovne(void); -extern void fcmovnbe(void); -extern void fcmovnu(void); -extern void ffree_(void); -extern void ffreep(void); -extern void fst_i_(void); -extern void fstp_i(void); -/* fpu_entry.c */ -extern void math_emulate(struct math_emu_info *info); -extern void math_abort(struct math_emu_info *info, unsigned int signal); -/* fpu_etc.c */ -extern void FPU_etc(void); -/* fpu_tags.c */ -extern int FPU_gettag0(void); -extern int FPU_gettagi(int stnr); -extern int FPU_gettag(int regnr); -extern void FPU_settag0(int tag); -extern void FPU_settagi(int stnr, int tag); -extern void FPU_settag(int regnr, int tag); -extern int FPU_Special(FPU_REG const *ptr); -extern int isNaN(FPU_REG const *ptr); -extern void FPU_pop(void); -extern int FPU_empty_i(int stnr); -extern int FPU_stackoverflow(FPU_REG ** st_new_ptr); -extern void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr); -extern void FPU_copy_to_reg1(FPU_REG const *r, u_char tag); -extern void FPU_copy_to_reg0(FPU_REG const *r, u_char tag); -/* fpu_trig.c */ -extern void FPU_triga(void); -extern void FPU_trigb(void); -/* get_address.c */ -extern void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip, - struct address *addr, - fpu_addr_modes addr_modes); -extern void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip, - struct address *addr, - fpu_addr_modes addr_modes); -/* load_store.c */ -extern int FPU_load_store(u_char type, fpu_addr_modes addr_modes, - void __user * data_address); -/* poly_2xm1.c */ -extern int poly_2xm1(u_char sign, FPU_REG * arg, FPU_REG *result); -/* poly_atan.c */ -extern void poly_atan(FPU_REG * st0_ptr, u_char st0_tag, FPU_REG *st1_ptr, - u_char st1_tag); -/* poly_l2.c */ -extern void poly_l2(FPU_REG *st0_ptr, FPU_REG *st1_ptr, u_char st1_sign); -extern int poly_l2p1(u_char s0, u_char s1, FPU_REG *r0, FPU_REG *r1, - FPU_REG * d); -/* poly_sin.c */ -extern void poly_sine(FPU_REG *st0_ptr); -extern void poly_cos(FPU_REG *st0_ptr); -/* poly_tan.c */ -extern void poly_tan(FPU_REG *st0_ptr); -/* reg_add_sub.c */ -extern int FPU_add(FPU_REG const *b, u_char tagb, int destrnr, int control_w); -extern int FPU_sub(int flags, int rm, int control_w); -/* reg_compare.c */ -extern int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag); -extern void fcom_st(void); -extern void fcompst(void); -extern void fcompp(void); -extern void fucom_(void); -extern void fucomp(void); -extern void fucompp(void); -extern void fcomi_(void); -extern void fcomip(void); -extern void fucomi_(void); -extern void fucomip(void); -/* reg_constant.c */ -extern void fconst(void); -/* reg_ld_str.c */ -extern int FPU_load_extended(long double __user *s, int stnr); -extern int FPU_load_double(double __user *dfloat, FPU_REG *loaded_data); -extern int FPU_load_single(float __user *single, FPU_REG *loaded_data); -extern int FPU_load_int64(long long __user *_s); -extern int FPU_load_int32(long __user *_s, FPU_REG *loaded_data); -extern int FPU_load_int16(short __user *_s, FPU_REG *loaded_data); -extern int FPU_load_bcd(u_char __user *s); -extern int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag, - long double __user * d); -extern int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, - double __user * dfloat); -extern int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, - float __user * single); -extern int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, - long long __user * d); -extern int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long __user *d); -extern int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short __user *d); -extern int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d); -extern int FPU_round_to_int(FPU_REG *r, u_char tag); -extern u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s); -extern void FPU_frstor(fpu_addr_modes addr_modes, u_char __user *data_address); -extern u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user *d); -extern void fsave(fpu_addr_modes addr_modes, u_char __user *data_address); -extern int FPU_tagof(FPU_REG *ptr); -/* reg_mul.c */ -extern int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w); - -extern int FPU_div(int flags, int regrm, int control_w); -/* reg_convert.c */ -extern int FPU_to_exp16(FPU_REG const *a, FPU_REG *x); -#endif /* _FPU_PROTO_H */ diff --git a/arch/x86/math-emu/fpu_system.h b/arch/x86/math-emu/fpu_system.h deleted file mode 100644 index 5e238e930fe3..000000000000 --- a/arch/x86/math-emu/fpu_system.h +++ /dev/null @@ -1,130 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/*---------------------------------------------------------------------------+ - | fpu_system.h | - | | - | Copyright (C) 1992,1994,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@suburbia.net | - | | - +---------------------------------------------------------------------------*/ - -#ifndef _FPU_SYSTEM_H -#define _FPU_SYSTEM_H - -/* system dependent definitions */ - -#include -#include -#include - -#include -#include - -static inline struct desc_struct FPU_get_ldt_descriptor(unsigned seg) -{ - static struct desc_struct zero_desc; - struct desc_struct ret = zero_desc; - -#ifdef CONFIG_MODIFY_LDT_SYSCALL - seg >>= 3; - mutex_lock(¤t->mm->context.lock); - if (current->mm->context.ldt && seg < current->mm->context.ldt->nr_entries) - ret = current->mm->context.ldt->entries[seg]; - mutex_unlock(¤t->mm->context.lock); -#endif - return ret; -} - -#define SEG_TYPE_WRITABLE (1U << 1) -#define SEG_TYPE_EXPANDS_DOWN (1U << 2) -#define SEG_TYPE_EXECUTE (1U << 3) -#define SEG_TYPE_EXPAND_MASK (SEG_TYPE_EXPANDS_DOWN | SEG_TYPE_EXECUTE) -#define SEG_TYPE_EXECUTE_MASK (SEG_TYPE_WRITABLE | SEG_TYPE_EXECUTE) - -static inline unsigned long seg_get_base(struct desc_struct *d) -{ - unsigned long base = (unsigned long)d->base2 << 24; - - return base | ((unsigned long)d->base1 << 16) | d->base0; -} - -static inline unsigned long seg_get_limit(struct desc_struct *d) -{ - return ((unsigned long)d->limit1 << 16) | d->limit0; -} - -static inline unsigned long seg_get_granularity(struct desc_struct *d) -{ - return d->g ? 4096 : 1; -} - -static inline bool seg_expands_down(struct desc_struct *d) -{ - return (d->type & SEG_TYPE_EXPAND_MASK) == SEG_TYPE_EXPANDS_DOWN; -} - -static inline bool seg_execute_only(struct desc_struct *d) -{ - return (d->type & SEG_TYPE_EXECUTE_MASK) == SEG_TYPE_EXECUTE; -} - -static inline bool seg_writable(struct desc_struct *d) -{ - return (d->type & SEG_TYPE_EXECUTE_MASK) == SEG_TYPE_WRITABLE; -} - -#define I387 (&x86_task_fpu(current)->fpstate->regs) -#define FPU_info (I387->soft.info) - -#define FPU_CS (*(unsigned short *) &(FPU_info->regs->cs)) -#define FPU_SS (*(unsigned short *) &(FPU_info->regs->ss)) -#define FPU_DS (*(unsigned short *) &(FPU_info->regs->ds)) -#define FPU_EAX (FPU_info->regs->ax) -#define FPU_EFLAGS (FPU_info->regs->flags) -#define FPU_EIP (FPU_info->regs->ip) -#define FPU_ORIG_EIP (FPU_info->___orig_eip) - -#define FPU_lookahead (I387->soft.lookahead) - -/* nz if ip_offset and cs_selector are not to be set for the current - instruction. */ -#define no_ip_update (*(u_char *)&(I387->soft.no_update)) -#define FPU_rm (*(u_char *)&(I387->soft.rm)) - -/* Number of bytes of data which can be legally accessed by the current - instruction. This only needs to hold a number <= 108, so a byte will do. */ -#define access_limit (*(u_char *)&(I387->soft.alimit)) - -#define partial_status (I387->soft.swd) -#define control_word (I387->soft.cwd) -#define fpu_tag_word (I387->soft.twd) -#define registers (I387->soft.st_space) -#define top (I387->soft.ftop) - -#define instruction_address (*(struct address *)&I387->soft.fip) -#define operand_address (*(struct address *)&I387->soft.foo) - -#define FPU_access_ok(y,z) if ( !access_ok(y,z) ) \ - math_abort(FPU_info,SIGSEGV) -#define FPU_abort math_abort(FPU_info, SIGSEGV) -#define FPU_copy_from_user(to, from, n) \ - do { if (copy_from_user(to, from, n)) FPU_abort; } while (0) - -#undef FPU_IGNORE_CODE_SEGV -#ifdef FPU_IGNORE_CODE_SEGV -/* access_ok() is very expensive, and causes the emulator to run - about 20% slower if applied to the code. Anyway, errors due to bad - code addresses should be much rarer than errors due to bad data - addresses. */ -#define FPU_code_access_ok(z) -#else -/* A simpler test than access_ok() can probably be done for - FPU_code_access_ok() because the only possible error is to step - past the upper boundary of a legal code area. */ -#define FPU_code_access_ok(z) FPU_access_ok((void __user *)FPU_EIP,z) -#endif - -#define FPU_get_user(x,y) do { if (get_user((x),(y))) FPU_abort; } while (0) -#define FPU_put_user(x,y) do { if (put_user((x),(y))) FPU_abort; } while (0) - -#endif diff --git a/arch/x86/math-emu/fpu_tags.c b/arch/x86/math-emu/fpu_tags.c deleted file mode 100644 index bff95d4e7dca..000000000000 --- a/arch/x86/math-emu/fpu_tags.c +++ /dev/null @@ -1,116 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | fpu_tags.c | - | | - | Set FPU register tags. | - | | - | Copyright (C) 1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@jacobi.maths.monash.edu.au | - | | - | | - +---------------------------------------------------------------------------*/ - -#include "fpu_emu.h" -#include "fpu_system.h" -#include "exception.h" - -void FPU_pop(void) -{ - fpu_tag_word |= 3 << ((top & 7) * 2); - top++; -} - -int FPU_gettag0(void) -{ - return (fpu_tag_word >> ((top & 7) * 2)) & 3; -} - -int FPU_gettagi(int stnr) -{ - return (fpu_tag_word >> (((top + stnr) & 7) * 2)) & 3; -} - -int FPU_gettag(int regnr) -{ - return (fpu_tag_word >> ((regnr & 7) * 2)) & 3; -} - -void FPU_settag0(int tag) -{ - int regnr = top; - regnr &= 7; - fpu_tag_word &= ~(3 << (regnr * 2)); - fpu_tag_word |= (tag & 3) << (regnr * 2); -} - -void FPU_settagi(int stnr, int tag) -{ - int regnr = stnr + top; - regnr &= 7; - fpu_tag_word &= ~(3 << (regnr * 2)); - fpu_tag_word |= (tag & 3) << (regnr * 2); -} - -void FPU_settag(int regnr, int tag) -{ - regnr &= 7; - fpu_tag_word &= ~(3 << (regnr * 2)); - fpu_tag_word |= (tag & 3) << (regnr * 2); -} - -int FPU_Special(FPU_REG const *ptr) -{ - int exp = exponent(ptr); - - if (exp == EXP_BIAS + EXP_UNDER) - return TW_Denormal; - else if (exp != EXP_BIAS + EXP_OVER) - return TW_NaN; - else if ((ptr->sigh == 0x80000000) && (ptr->sigl == 0)) - return TW_Infinity; - return TW_NaN; -} - -int isNaN(FPU_REG const *ptr) -{ - return ((exponent(ptr) == EXP_BIAS + EXP_OVER) - && !((ptr->sigh == 0x80000000) && (ptr->sigl == 0))); -} - -int FPU_empty_i(int stnr) -{ - int regnr = (top + stnr) & 7; - - return ((fpu_tag_word >> (regnr * 2)) & 3) == TAG_Empty; -} - -int FPU_stackoverflow(FPU_REG ** st_new_ptr) -{ - *st_new_ptr = &st(-1); - - return ((fpu_tag_word >> (((top - 1) & 7) * 2)) & 3) != TAG_Empty; -} - -void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr) -{ - reg_copy(r, &st(stnr)); - FPU_settagi(stnr, tag); -} - -void FPU_copy_to_reg1(FPU_REG const *r, u_char tag) -{ - reg_copy(r, &st(1)); - FPU_settagi(1, tag); -} - -void FPU_copy_to_reg0(FPU_REG const *r, u_char tag) -{ - int regnr = top; - regnr &= 7; - - reg_copy(r, &st(0)); - - fpu_tag_word &= ~(3 << (regnr * 2)); - fpu_tag_word |= (tag & 3) << (regnr * 2); -} diff --git a/arch/x86/math-emu/fpu_trig.c b/arch/x86/math-emu/fpu_trig.c deleted file mode 100644 index 85daf98c81c3..000000000000 --- a/arch/x86/math-emu/fpu_trig.c +++ /dev/null @@ -1,1649 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | fpu_trig.c | - | | - | Implementation of the FPU "transcendental" functions. | - | | - | Copyright (C) 1992,1993,1994,1997,1999 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@melbpc.org.au | - | | - | | - +---------------------------------------------------------------------------*/ - -#include "fpu_system.h" -#include "exception.h" -#include "fpu_emu.h" -#include "status_w.h" -#include "control_w.h" -#include "reg_constant.h" - -static void rem_kernel(unsigned long long st0, unsigned long long *y, - unsigned long long st1, unsigned long long q, int n); - -#define BETTER_THAN_486 - -#define FCOS 4 - -/* Used only by fptan, fsin, fcos, and fsincos. */ -/* This routine produces very accurate results, similar to - using a value of pi with more than 128 bits precision. */ -/* Limited measurements show no results worse than 64 bit precision - except for the results for arguments close to 2^63, where the - precision of the result sometimes degrades to about 63.9 bits */ -static int trig_arg(FPU_REG *st0_ptr, int even) -{ - FPU_REG tmp; - u_char tmptag; - unsigned long long q; - int old_cw = control_word, saved_status = partial_status; - int tag, st0_tag = TAG_Valid; - - if (exponent(st0_ptr) >= 63) { - partial_status |= SW_C2; /* Reduction incomplete. */ - return -1; - } - - control_word &= ~CW_RC; - control_word |= RC_CHOP; - - setpositive(st0_ptr); - tag = FPU_u_div(st0_ptr, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f, - SIGN_POS); - - FPU_round_to_int(&tmp, tag); /* Fortunately, this can't overflow - to 2^64 */ - q = significand(&tmp); - if (q) { - rem_kernel(significand(st0_ptr), - &significand(&tmp), - significand(&CONST_PI2), - q, exponent(st0_ptr) - exponent(&CONST_PI2)); - setexponent16(&tmp, exponent(&CONST_PI2)); - st0_tag = FPU_normalize(&tmp); - FPU_copy_to_reg0(&tmp, st0_tag); - } - - if ((even && !(q & 1)) || (!even && (q & 1))) { - st0_tag = - FPU_sub(REV | LOADED | TAG_Valid, (int)&CONST_PI2, - FULL_PRECISION); - -#ifdef BETTER_THAN_486 - /* So far, the results are exact but based upon a 64 bit - precision approximation to pi/2. The technique used - now is equivalent to using an approximation to pi/2 which - is accurate to about 128 bits. */ - if ((exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64) - || (q > 1)) { - /* This code gives the effect of having pi/2 to better than - 128 bits precision. */ - - significand(&tmp) = q + 1; - setexponent16(&tmp, 63); - FPU_normalize(&tmp); - tmptag = - FPU_u_mul(&CONST_PI2extra, &tmp, &tmp, - FULL_PRECISION, SIGN_POS, - exponent(&CONST_PI2extra) + - exponent(&tmp)); - setsign(&tmp, getsign(&CONST_PI2extra)); - st0_tag = FPU_add(&tmp, tmptag, 0, FULL_PRECISION); - if (signnegative(st0_ptr)) { - /* CONST_PI2extra is negative, so the result of the addition - can be negative. This means that the argument is actually - in a different quadrant. The correction is always < pi/2, - so it can't overflow into yet another quadrant. */ - setpositive(st0_ptr); - q++; - } - } -#endif /* BETTER_THAN_486 */ - } -#ifdef BETTER_THAN_486 - else { - /* So far, the results are exact but based upon a 64 bit - precision approximation to pi/2. The technique used - now is equivalent to using an approximation to pi/2 which - is accurate to about 128 bits. */ - if (((q > 0) - && (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64)) - || (q > 1)) { - /* This code gives the effect of having p/2 to better than - 128 bits precision. */ - - significand(&tmp) = q; - setexponent16(&tmp, 63); - FPU_normalize(&tmp); /* This must return TAG_Valid */ - tmptag = - FPU_u_mul(&CONST_PI2extra, &tmp, &tmp, - FULL_PRECISION, SIGN_POS, - exponent(&CONST_PI2extra) + - exponent(&tmp)); - setsign(&tmp, getsign(&CONST_PI2extra)); - st0_tag = FPU_sub(LOADED | (tmptag & 0x0f), (int)&tmp, - FULL_PRECISION); - if ((exponent(st0_ptr) == exponent(&CONST_PI2)) && - ((st0_ptr->sigh > CONST_PI2.sigh) - || ((st0_ptr->sigh == CONST_PI2.sigh) - && (st0_ptr->sigl > CONST_PI2.sigl)))) { - /* CONST_PI2extra is negative, so the result of the - subtraction can be larger than pi/2. This means - that the argument is actually in a different quadrant. - The correction is always < pi/2, so it can't overflow - into yet another quadrant. */ - st0_tag = - FPU_sub(REV | LOADED | TAG_Valid, - (int)&CONST_PI2, FULL_PRECISION); - q++; - } - } - } -#endif /* BETTER_THAN_486 */ - - FPU_settag0(st0_tag); - control_word = old_cw; - partial_status = saved_status & ~SW_C2; /* Reduction complete. */ - - return (q & 3) | even; -} - -/* Convert a long to register */ -static void convert_l2reg(long const *arg, int deststnr) -{ - int tag; - long num = *arg; - u_char sign; - FPU_REG *dest = &st(deststnr); - - if (num == 0) { - FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); - return; - } - - if (num > 0) { - sign = SIGN_POS; - } else { - num = -num; - sign = SIGN_NEG; - } - - dest->sigh = num; - dest->sigl = 0; - setexponent16(dest, 31); - tag = FPU_normalize(dest); - FPU_settagi(deststnr, tag); - setsign(dest, sign); - return; -} - -static void single_arg_error(FPU_REG *st0_ptr, u_char st0_tag) -{ - if (st0_tag == TAG_Empty) - FPU_stack_underflow(); /* Puts a QNaN in st(0) */ - else if (st0_tag == TW_NaN) - real_1op_NaN(st0_ptr); /* return with a NaN in st(0) */ -#ifdef PARANOID - else - EXCEPTION(EX_INTERNAL | 0x0112); -#endif /* PARANOID */ -} - -static void single_arg_2_error(FPU_REG *st0_ptr, u_char st0_tag) -{ - int isNaN; - - switch (st0_tag) { - case TW_NaN: - isNaN = (exponent(st0_ptr) == EXP_OVER) - && (st0_ptr->sigh & 0x80000000); - if (isNaN && !(st0_ptr->sigh & 0x40000000)) { /* Signaling ? */ - EXCEPTION(EX_Invalid); - if (control_word & CW_Invalid) { - /* The masked response */ - /* Convert to a QNaN */ - st0_ptr->sigh |= 0x40000000; - push(); - FPU_copy_to_reg0(st0_ptr, TAG_Special); - } - } else if (isNaN) { - /* A QNaN */ - push(); - FPU_copy_to_reg0(st0_ptr, TAG_Special); - } else { - /* pseudoNaN or other unsupported */ - EXCEPTION(EX_Invalid); - if (control_word & CW_Invalid) { - /* The masked response */ - FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); - push(); - FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); - } - } - break; /* return with a NaN in st(0) */ -#ifdef PARANOID - default: - EXCEPTION(EX_INTERNAL | 0x0112); -#endif /* PARANOID */ - } -} - -/*---------------------------------------------------------------------------*/ - -static void f2xm1(FPU_REG *st0_ptr, u_char tag) -{ - FPU_REG a; - - clear_C1(); - - if (tag == TAG_Valid) { - /* For an 80486 FPU, the result is undefined if the arg is >= 1.0 */ - if (exponent(st0_ptr) < 0) { - denormal_arg: - - FPU_to_exp16(st0_ptr, &a); - - /* poly_2xm1(x) requires 0 < st(0) < 1. */ - poly_2xm1(getsign(st0_ptr), &a, st0_ptr); - } - set_precision_flag_up(); /* 80486 appears to always do this */ - return; - } - - if (tag == TAG_Zero) - return; - - if (tag == TAG_Special) - tag = FPU_Special(st0_ptr); - - switch (tag) { - case TW_Denormal: - if (denormal_operand() < 0) - return; - goto denormal_arg; - case TW_Infinity: - if (signnegative(st0_ptr)) { - /* -infinity gives -1 (p16-10) */ - FPU_copy_to_reg0(&CONST_1, TAG_Valid); - setnegative(st0_ptr); - } - return; - default: - single_arg_error(st0_ptr, tag); - } -} - -static void fptan(FPU_REG *st0_ptr, u_char st0_tag) -{ - FPU_REG *st_new_ptr; - int q; - u_char arg_sign = getsign(st0_ptr); - - /* Stack underflow has higher priority */ - if (st0_tag == TAG_Empty) { - FPU_stack_underflow(); /* Puts a QNaN in st(0) */ - if (control_word & CW_Invalid) { - st_new_ptr = &st(-1); - push(); - FPU_stack_underflow(); /* Puts a QNaN in the new st(0) */ - } - return; - } - - if (STACK_OVERFLOW) { - FPU_stack_overflow(); - return; - } - - if (st0_tag == TAG_Valid) { - if (exponent(st0_ptr) > -40) { - if ((q = trig_arg(st0_ptr, 0)) == -1) { - /* Operand is out of range */ - return; - } - - poly_tan(st0_ptr); - setsign(st0_ptr, (q & 1) ^ (arg_sign != 0)); - set_precision_flag_up(); /* We do not really know if up or down */ - } else { - /* For a small arg, the result == the argument */ - /* Underflow may happen */ - - denormal_arg: - - FPU_to_exp16(st0_ptr, st0_ptr); - - st0_tag = - FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign); - FPU_settag0(st0_tag); - } - push(); - FPU_copy_to_reg0(&CONST_1, TAG_Valid); - return; - } - - if (st0_tag == TAG_Zero) { - push(); - FPU_copy_to_reg0(&CONST_1, TAG_Valid); - setcc(0); - return; - } - - if (st0_tag == TAG_Special) - st0_tag = FPU_Special(st0_ptr); - - if (st0_tag == TW_Denormal) { - if (denormal_operand() < 0) - return; - - goto denormal_arg; - } - - if (st0_tag == TW_Infinity) { - /* The 80486 treats infinity as an invalid operand */ - if (arith_invalid(0) >= 0) { - st_new_ptr = &st(-1); - push(); - arith_invalid(0); - } - return; - } - - single_arg_2_error(st0_ptr, st0_tag); -} - -static void fxtract(FPU_REG *st0_ptr, u_char st0_tag) -{ - FPU_REG *st_new_ptr; - u_char sign; - register FPU_REG *st1_ptr = st0_ptr; /* anticipate */ - - if (STACK_OVERFLOW) { - FPU_stack_overflow(); - return; - } - - clear_C1(); - - if (st0_tag == TAG_Valid) { - long e; - - push(); - sign = getsign(st1_ptr); - reg_copy(st1_ptr, st_new_ptr); - setexponent16(st_new_ptr, exponent(st_new_ptr)); - - denormal_arg: - - e = exponent16(st_new_ptr); - convert_l2reg(&e, 1); - setexponentpos(st_new_ptr, 0); - setsign(st_new_ptr, sign); - FPU_settag0(TAG_Valid); /* Needed if arg was a denormal */ - return; - } else if (st0_tag == TAG_Zero) { - sign = getsign(st0_ptr); - - if (FPU_divide_by_zero(0, SIGN_NEG) < 0) - return; - - push(); - FPU_copy_to_reg0(&CONST_Z, TAG_Zero); - setsign(st_new_ptr, sign); - return; - } - - if (st0_tag == TAG_Special) - st0_tag = FPU_Special(st0_ptr); - - if (st0_tag == TW_Denormal) { - if (denormal_operand() < 0) - return; - - push(); - sign = getsign(st1_ptr); - FPU_to_exp16(st1_ptr, st_new_ptr); - goto denormal_arg; - } else if (st0_tag == TW_Infinity) { - sign = getsign(st0_ptr); - setpositive(st0_ptr); - push(); - FPU_copy_to_reg0(&CONST_INF, TAG_Special); - setsign(st_new_ptr, sign); - return; - } else if (st0_tag == TW_NaN) { - if (real_1op_NaN(st0_ptr) < 0) - return; - - push(); - FPU_copy_to_reg0(st0_ptr, TAG_Special); - return; - } else if (st0_tag == TAG_Empty) { - /* Is this the correct behaviour? */ - if (control_word & EX_Invalid) { - FPU_stack_underflow(); - push(); - FPU_stack_underflow(); - } else - EXCEPTION(EX_StackUnder); - } -#ifdef PARANOID - else - EXCEPTION(EX_INTERNAL | 0x119); -#endif /* PARANOID */ -} - -static void fdecstp(FPU_REG *st0_ptr, u_char st0_tag) -{ - clear_C1(); - top--; -} - -static void fincstp(FPU_REG *st0_ptr, u_char st0_tag) -{ - clear_C1(); - top++; -} - -static void fsqrt_(FPU_REG *st0_ptr, u_char st0_tag) -{ - int expon; - - clear_C1(); - - if (st0_tag == TAG_Valid) { - u_char tag; - - if (signnegative(st0_ptr)) { - arith_invalid(0); /* sqrt(negative) is invalid */ - return; - } - - /* make st(0) in [1.0 .. 4.0) */ - expon = exponent(st0_ptr); - - denormal_arg: - - setexponent16(st0_ptr, (expon & 1)); - - /* Do the computation, the sign of the result will be positive. */ - tag = wm_sqrt(st0_ptr, 0, 0, control_word, SIGN_POS); - addexponent(st0_ptr, expon >> 1); - FPU_settag0(tag); - return; - } - - if (st0_tag == TAG_Zero) - return; - - if (st0_tag == TAG_Special) - st0_tag = FPU_Special(st0_ptr); - - if (st0_tag == TW_Infinity) { - if (signnegative(st0_ptr)) - arith_invalid(0); /* sqrt(-Infinity) is invalid */ - return; - } else if (st0_tag == TW_Denormal) { - if (signnegative(st0_ptr)) { - arith_invalid(0); /* sqrt(negative) is invalid */ - return; - } - - if (denormal_operand() < 0) - return; - - FPU_to_exp16(st0_ptr, st0_ptr); - - expon = exponent16(st0_ptr); - - goto denormal_arg; - } - - single_arg_error(st0_ptr, st0_tag); - -} - -static void frndint_(FPU_REG *st0_ptr, u_char st0_tag) -{ - int flags, tag; - - if (st0_tag == TAG_Valid) { - u_char sign; - - denormal_arg: - - sign = getsign(st0_ptr); - - if (exponent(st0_ptr) > 63) - return; - - if (st0_tag == TW_Denormal) { - if (denormal_operand() < 0) - return; - } - - /* Fortunately, this can't overflow to 2^64 */ - if ((flags = FPU_round_to_int(st0_ptr, st0_tag))) - set_precision_flag(flags); - - setexponent16(st0_ptr, 63); - tag = FPU_normalize(st0_ptr); - setsign(st0_ptr, sign); - FPU_settag0(tag); - return; - } - - if (st0_tag == TAG_Zero) - return; - - if (st0_tag == TAG_Special) - st0_tag = FPU_Special(st0_ptr); - - if (st0_tag == TW_Denormal) - goto denormal_arg; - else if (st0_tag == TW_Infinity) - return; - else - single_arg_error(st0_ptr, st0_tag); -} - -static int f_sin(FPU_REG *st0_ptr, u_char tag) -{ - u_char arg_sign = getsign(st0_ptr); - - if (tag == TAG_Valid) { - int q; - - if (exponent(st0_ptr) > -40) { - if ((q = trig_arg(st0_ptr, 0)) == -1) { - /* Operand is out of range */ - return 1; - } - - poly_sine(st0_ptr); - - if (q & 2) - changesign(st0_ptr); - - setsign(st0_ptr, getsign(st0_ptr) ^ arg_sign); - - /* We do not really know if up or down */ - set_precision_flag_up(); - return 0; - } else { - /* For a small arg, the result == the argument */ - set_precision_flag_up(); /* Must be up. */ - return 0; - } - } - - if (tag == TAG_Zero) { - setcc(0); - return 0; - } - - if (tag == TAG_Special) - tag = FPU_Special(st0_ptr); - - if (tag == TW_Denormal) { - if (denormal_operand() < 0) - return 1; - - /* For a small arg, the result == the argument */ - /* Underflow may happen */ - FPU_to_exp16(st0_ptr, st0_ptr); - - tag = FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign); - - FPU_settag0(tag); - - return 0; - } else if (tag == TW_Infinity) { - /* The 80486 treats infinity as an invalid operand */ - arith_invalid(0); - return 1; - } else { - single_arg_error(st0_ptr, tag); - return 1; - } -} - -static void fsin(FPU_REG *st0_ptr, u_char tag) -{ - f_sin(st0_ptr, tag); -} - -static int f_cos(FPU_REG *st0_ptr, u_char tag) -{ - u_char st0_sign; - - st0_sign = getsign(st0_ptr); - - if (tag == TAG_Valid) { - int q; - - if (exponent(st0_ptr) > -40) { - if ((exponent(st0_ptr) < 0) - || ((exponent(st0_ptr) == 0) - && (significand(st0_ptr) <= - 0xc90fdaa22168c234LL))) { - poly_cos(st0_ptr); - - /* We do not really know if up or down */ - set_precision_flag_down(); - - return 0; - } else if ((q = trig_arg(st0_ptr, FCOS)) != -1) { - poly_sine(st0_ptr); - - if ((q + 1) & 2) - changesign(st0_ptr); - - /* We do not really know if up or down */ - set_precision_flag_down(); - - return 0; - } else { - /* Operand is out of range */ - return 1; - } - } else { - denormal_arg: - - setcc(0); - FPU_copy_to_reg0(&CONST_1, TAG_Valid); -#ifdef PECULIAR_486 - set_precision_flag_down(); /* 80486 appears to do this. */ -#else - set_precision_flag_up(); /* Must be up. */ -#endif /* PECULIAR_486 */ - return 0; - } - } else if (tag == TAG_Zero) { - FPU_copy_to_reg0(&CONST_1, TAG_Valid); - setcc(0); - return 0; - } - - if (tag == TAG_Special) - tag = FPU_Special(st0_ptr); - - if (tag == TW_Denormal) { - if (denormal_operand() < 0) - return 1; - - goto denormal_arg; - } else if (tag == TW_Infinity) { - /* The 80486 treats infinity as an invalid operand */ - arith_invalid(0); - return 1; - } else { - single_arg_error(st0_ptr, tag); /* requires st0_ptr == &st(0) */ - return 1; - } -} - -static void fcos(FPU_REG *st0_ptr, u_char st0_tag) -{ - f_cos(st0_ptr, st0_tag); -} - -static void fsincos(FPU_REG *st0_ptr, u_char st0_tag) -{ - FPU_REG *st_new_ptr; - FPU_REG arg; - u_char tag; - - /* Stack underflow has higher priority */ - if (st0_tag == TAG_Empty) { - FPU_stack_underflow(); /* Puts a QNaN in st(0) */ - if (control_word & CW_Invalid) { - st_new_ptr = &st(-1); - push(); - FPU_stack_underflow(); /* Puts a QNaN in the new st(0) */ - } - return; - } - - if (STACK_OVERFLOW) { - FPU_stack_overflow(); - return; - } - - if (st0_tag == TAG_Special) - tag = FPU_Special(st0_ptr); - else - tag = st0_tag; - - if (tag == TW_NaN) { - single_arg_2_error(st0_ptr, TW_NaN); - return; - } else if (tag == TW_Infinity) { - /* The 80486 treats infinity as an invalid operand */ - if (arith_invalid(0) >= 0) { - /* Masked response */ - push(); - arith_invalid(0); - } - return; - } - - reg_copy(st0_ptr, &arg); - if (!f_sin(st0_ptr, st0_tag)) { - push(); - FPU_copy_to_reg0(&arg, st0_tag); - f_cos(&st(0), st0_tag); - } else { - /* An error, so restore st(0) */ - FPU_copy_to_reg0(&arg, st0_tag); - } -} - -/*---------------------------------------------------------------------------*/ -/* The following all require two arguments: st(0) and st(1) */ - -/* A lean, mean kernel for the fprem instructions. This relies upon - the division and rounding to an integer in do_fprem giving an - exact result. Because of this, rem_kernel() needs to deal only with - the least significant 64 bits, the more significant bits of the - result must be zero. - */ -static void rem_kernel(unsigned long long st0, unsigned long long *y, - unsigned long long st1, unsigned long long q, int n) -{ - int dummy; - unsigned long long x; - - x = st0 << n; - - /* Do the required multiplication and subtraction in the one operation */ - - /* lsw x -= lsw st1 * lsw q */ - asm volatile ("mull %4; subl %%eax,%0; sbbl %%edx,%1":"=m" - (((unsigned *)&x)[0]), "=m"(((unsigned *)&x)[1]), - "=a"(dummy) - :"2"(((unsigned *)&st1)[0]), "m"(((unsigned *)&q)[0]) - :"%dx"); - /* msw x -= msw st1 * lsw q */ - asm volatile ("mull %3; subl %%eax,%0":"=m" (((unsigned *)&x)[1]), - "=a"(dummy) - :"1"(((unsigned *)&st1)[1]), "m"(((unsigned *)&q)[0]) - :"%dx"); - /* msw x -= lsw st1 * msw q */ - asm volatile ("mull %3; subl %%eax,%0":"=m" (((unsigned *)&x)[1]), - "=a"(dummy) - :"1"(((unsigned *)&st1)[0]), "m"(((unsigned *)&q)[1]) - :"%dx"); - - *y = x; -} - -/* Remainder of st(0) / st(1) */ -/* This routine produces exact results, i.e. there is never any - rounding or truncation, etc of the result. */ -static void do_fprem(FPU_REG *st0_ptr, u_char st0_tag, int round) -{ - FPU_REG *st1_ptr = &st(1); - u_char st1_tag = FPU_gettagi(1); - - if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) { - FPU_REG tmp, st0, st1; - u_char st0_sign, st1_sign; - u_char tmptag; - int tag; - int old_cw; - int expdif; - long long q; - unsigned short saved_status; - int cc; - - fprem_valid: - /* Convert registers for internal use. */ - st0_sign = FPU_to_exp16(st0_ptr, &st0); - st1_sign = FPU_to_exp16(st1_ptr, &st1); - expdif = exponent16(&st0) - exponent16(&st1); - - old_cw = control_word; - cc = 0; - - /* We want the status following the denorm tests, but don't want - the status changed by the arithmetic operations. */ - saved_status = partial_status; - control_word &= ~CW_RC; - control_word |= RC_CHOP; - - if (expdif < 64) { - /* This should be the most common case */ - - if (expdif > -2) { - u_char sign = st0_sign ^ st1_sign; - tag = FPU_u_div(&st0, &st1, &tmp, - PR_64_BITS | RC_CHOP | 0x3f, - sign); - setsign(&tmp, sign); - - if (exponent(&tmp) >= 0) { - FPU_round_to_int(&tmp, tag); /* Fortunately, this can't - overflow to 2^64 */ - q = significand(&tmp); - - rem_kernel(significand(&st0), - &significand(&tmp), - significand(&st1), - q, expdif); - - setexponent16(&tmp, exponent16(&st1)); - } else { - reg_copy(&st0, &tmp); - q = 0; - } - - if ((round == RC_RND) - && (tmp.sigh & 0xc0000000)) { - /* We may need to subtract st(1) once more, - to get a result <= 1/2 of st(1). */ - unsigned long long x; - expdif = - exponent16(&st1) - exponent16(&tmp); - if (expdif <= 1) { - if (expdif == 0) - x = significand(&st1) - - significand(&tmp); - else /* expdif is 1 */ - x = (significand(&st1) - << 1) - - significand(&tmp); - if ((x < significand(&tmp)) || - /* or equi-distant (from 0 & st(1)) and q is odd */ - ((x == significand(&tmp)) - && (q & 1))) { - st0_sign = !st0_sign; - significand(&tmp) = x; - q++; - } - } - } - - if (q & 4) - cc |= SW_C0; - if (q & 2) - cc |= SW_C3; - if (q & 1) - cc |= SW_C1; - } else { - control_word = old_cw; - setcc(0); - return; - } - } else { - /* There is a large exponent difference ( >= 64 ) */ - /* To make much sense, the code in this section should - be done at high precision. */ - int exp_1, N; - u_char sign; - - /* prevent overflow here */ - /* N is 'a number between 32 and 63' (p26-113) */ - reg_copy(&st0, &tmp); - tmptag = st0_tag; - N = (expdif & 0x0000001f) + 32; /* This choice gives results - identical to an AMD 486 */ - setexponent16(&tmp, N); - exp_1 = exponent16(&st1); - setexponent16(&st1, 0); - expdif -= N; - - sign = getsign(&tmp) ^ st1_sign; - tag = - FPU_u_div(&tmp, &st1, &tmp, - PR_64_BITS | RC_CHOP | 0x3f, sign); - setsign(&tmp, sign); - - FPU_round_to_int(&tmp, tag); /* Fortunately, this can't - overflow to 2^64 */ - - rem_kernel(significand(&st0), - &significand(&tmp), - significand(&st1), - significand(&tmp), exponent(&tmp) - ); - setexponent16(&tmp, exp_1 + expdif); - - /* It is possible for the operation to be complete here. - What does the IEEE standard say? The Intel 80486 manual - implies that the operation will never be completed at this - point, and the behaviour of a real 80486 confirms this. - */ - if (!(tmp.sigh | tmp.sigl)) { - /* The result is zero */ - control_word = old_cw; - partial_status = saved_status; - FPU_copy_to_reg0(&CONST_Z, TAG_Zero); - setsign(&st0, st0_sign); -#ifdef PECULIAR_486 - setcc(SW_C2); -#else - setcc(0); -#endif /* PECULIAR_486 */ - return; - } - cc = SW_C2; - } - - control_word = old_cw; - partial_status = saved_status; - tag = FPU_normalize_nuo(&tmp); - reg_copy(&tmp, st0_ptr); - - /* The only condition to be looked for is underflow, - and it can occur here only if underflow is unmasked. */ - if ((exponent16(&tmp) <= EXP_UNDER) && (tag != TAG_Zero) - && !(control_word & CW_Underflow)) { - setcc(cc); - tag = arith_underflow(st0_ptr); - setsign(st0_ptr, st0_sign); - FPU_settag0(tag); - return; - } else if ((exponent16(&tmp) > EXP_UNDER) || (tag == TAG_Zero)) { - stdexp(st0_ptr); - setsign(st0_ptr, st0_sign); - } else { - tag = - FPU_round(st0_ptr, 0, 0, FULL_PRECISION, st0_sign); - } - FPU_settag0(tag); - setcc(cc); - - return; - } - - if (st0_tag == TAG_Special) - st0_tag = FPU_Special(st0_ptr); - if (st1_tag == TAG_Special) - st1_tag = FPU_Special(st1_ptr); - - if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal)) - || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid)) - || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) { - if (denormal_operand() < 0) - return; - goto fprem_valid; - } else if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) { - FPU_stack_underflow(); - return; - } else if (st0_tag == TAG_Zero) { - if (st1_tag == TAG_Valid) { - setcc(0); - return; - } else if (st1_tag == TW_Denormal) { - if (denormal_operand() < 0) - return; - setcc(0); - return; - } else if (st1_tag == TAG_Zero) { - arith_invalid(0); - return; - } /* fprem(?,0) always invalid */ - else if (st1_tag == TW_Infinity) { - setcc(0); - return; - } - } else if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) { - if (st1_tag == TAG_Zero) { - arith_invalid(0); /* fprem(Valid,Zero) is invalid */ - return; - } else if (st1_tag != TW_NaN) { - if (((st0_tag == TW_Denormal) - || (st1_tag == TW_Denormal)) - && (denormal_operand() < 0)) - return; - - if (st1_tag == TW_Infinity) { - /* fprem(Valid,Infinity) is o.k. */ - setcc(0); - return; - } - } - } else if (st0_tag == TW_Infinity) { - if (st1_tag != TW_NaN) { - arith_invalid(0); /* fprem(Infinity,?) is invalid */ - return; - } - } - - /* One of the registers must contain a NaN if we got here. */ - -#ifdef PARANOID - if ((st0_tag != TW_NaN) && (st1_tag != TW_NaN)) - EXCEPTION(EX_INTERNAL | 0x118); -#endif /* PARANOID */ - - real_2op_NaN(st1_ptr, st1_tag, 0, st1_ptr); - -} - -/* ST(1) <- ST(1) * log ST; pop ST */ -static void fyl2x(FPU_REG *st0_ptr, u_char st0_tag) -{ - FPU_REG *st1_ptr = &st(1), exponent; - u_char st1_tag = FPU_gettagi(1); - u_char sign; - int e, tag; - - clear_C1(); - - if ((st0_tag == TAG_Valid) && (st1_tag == TAG_Valid)) { - both_valid: - /* Both regs are Valid or Denormal */ - if (signpositive(st0_ptr)) { - if (st0_tag == TW_Denormal) - FPU_to_exp16(st0_ptr, st0_ptr); - else - /* Convert st(0) for internal use. */ - setexponent16(st0_ptr, exponent(st0_ptr)); - - if ((st0_ptr->sigh == 0x80000000) - && (st0_ptr->sigl == 0)) { - /* Special case. The result can be precise. */ - u_char esign; - e = exponent16(st0_ptr); - if (e >= 0) { - exponent.sigh = e; - esign = SIGN_POS; - } else { - exponent.sigh = -e; - esign = SIGN_NEG; - } - exponent.sigl = 0; - setexponent16(&exponent, 31); - tag = FPU_normalize_nuo(&exponent); - stdexp(&exponent); - setsign(&exponent, esign); - tag = - FPU_mul(&exponent, tag, 1, FULL_PRECISION); - if (tag >= 0) - FPU_settagi(1, tag); - } else { - /* The usual case */ - sign = getsign(st1_ptr); - if (st1_tag == TW_Denormal) - FPU_to_exp16(st1_ptr, st1_ptr); - else - /* Convert st(1) for internal use. */ - setexponent16(st1_ptr, - exponent(st1_ptr)); - poly_l2(st0_ptr, st1_ptr, sign); - } - } else { - /* negative */ - if (arith_invalid(1) < 0) - return; - } - - FPU_pop(); - - return; - } - - if (st0_tag == TAG_Special) - st0_tag = FPU_Special(st0_ptr); - if (st1_tag == TAG_Special) - st1_tag = FPU_Special(st1_ptr); - - if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) { - FPU_stack_underflow_pop(1); - return; - } else if ((st0_tag <= TW_Denormal) && (st1_tag <= TW_Denormal)) { - if (st0_tag == TAG_Zero) { - if (st1_tag == TAG_Zero) { - /* Both args zero is invalid */ - if (arith_invalid(1) < 0) - return; - } else { - u_char sign; - sign = getsign(st1_ptr) ^ SIGN_NEG; - if (FPU_divide_by_zero(1, sign) < 0) - return; - - setsign(st1_ptr, sign); - } - } else if (st1_tag == TAG_Zero) { - /* st(1) contains zero, st(0) valid <> 0 */ - /* Zero is the valid answer */ - sign = getsign(st1_ptr); - - if (signnegative(st0_ptr)) { - /* log(negative) */ - if (arith_invalid(1) < 0) - return; - } else if ((st0_tag == TW_Denormal) - && (denormal_operand() < 0)) - return; - else { - if (exponent(st0_ptr) < 0) - sign ^= SIGN_NEG; - - FPU_copy_to_reg1(&CONST_Z, TAG_Zero); - setsign(st1_ptr, sign); - } - } else { - /* One or both operands are denormals. */ - if (denormal_operand() < 0) - return; - goto both_valid; - } - } else if ((st0_tag == TW_NaN) || (st1_tag == TW_NaN)) { - if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0) - return; - } - /* One or both arg must be an infinity */ - else if (st0_tag == TW_Infinity) { - if ((signnegative(st0_ptr)) || (st1_tag == TAG_Zero)) { - /* log(-infinity) or 0*log(infinity) */ - if (arith_invalid(1) < 0) - return; - } else { - u_char sign = getsign(st1_ptr); - - if ((st1_tag == TW_Denormal) - && (denormal_operand() < 0)) - return; - - FPU_copy_to_reg1(&CONST_INF, TAG_Special); - setsign(st1_ptr, sign); - } - } - /* st(1) must be infinity here */ - else if (((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) - && (signpositive(st0_ptr))) { - if (exponent(st0_ptr) >= 0) { - if ((exponent(st0_ptr) == 0) && - (st0_ptr->sigh == 0x80000000) && - (st0_ptr->sigl == 0)) { - /* st(0) holds 1.0 */ - /* infinity*log(1) */ - if (arith_invalid(1) < 0) - return; - } - /* else st(0) is positive and > 1.0 */ - } else { - /* st(0) is positive and < 1.0 */ - - if ((st0_tag == TW_Denormal) - && (denormal_operand() < 0)) - return; - - changesign(st1_ptr); - } - } else { - /* st(0) must be zero or negative */ - if (st0_tag == TAG_Zero) { - /* This should be invalid, but a real 80486 is happy with it. */ - -#ifndef PECULIAR_486 - sign = getsign(st1_ptr); - if (FPU_divide_by_zero(1, sign) < 0) - return; -#endif /* PECULIAR_486 */ - - changesign(st1_ptr); - } else if (arith_invalid(1) < 0) /* log(negative) */ - return; - } - - FPU_pop(); -} - -static void fpatan(FPU_REG *st0_ptr, u_char st0_tag) -{ - FPU_REG *st1_ptr = &st(1); - u_char st1_tag = FPU_gettagi(1); - int tag; - - clear_C1(); - if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) { - valid_atan: - - poly_atan(st0_ptr, st0_tag, st1_ptr, st1_tag); - - FPU_pop(); - - return; - } - - if (st0_tag == TAG_Special) - st0_tag = FPU_Special(st0_ptr); - if (st1_tag == TAG_Special) - st1_tag = FPU_Special(st1_ptr); - - if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal)) - || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid)) - || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) { - if (denormal_operand() < 0) - return; - - goto valid_atan; - } else if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) { - FPU_stack_underflow_pop(1); - return; - } else if ((st0_tag == TW_NaN) || (st1_tag == TW_NaN)) { - if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) >= 0) - FPU_pop(); - return; - } else if ((st0_tag == TW_Infinity) || (st1_tag == TW_Infinity)) { - u_char sign = getsign(st1_ptr); - if (st0_tag == TW_Infinity) { - if (st1_tag == TW_Infinity) { - if (signpositive(st0_ptr)) { - FPU_copy_to_reg1(&CONST_PI4, TAG_Valid); - } else { - setpositive(st1_ptr); - tag = - FPU_u_add(&CONST_PI4, &CONST_PI2, - st1_ptr, FULL_PRECISION, - SIGN_POS, - exponent(&CONST_PI4), - exponent(&CONST_PI2)); - if (tag >= 0) - FPU_settagi(1, tag); - } - } else { - if ((st1_tag == TW_Denormal) - && (denormal_operand() < 0)) - return; - - if (signpositive(st0_ptr)) { - FPU_copy_to_reg1(&CONST_Z, TAG_Zero); - setsign(st1_ptr, sign); /* An 80486 preserves the sign */ - FPU_pop(); - return; - } else { - FPU_copy_to_reg1(&CONST_PI, TAG_Valid); - } - } - } else { - /* st(1) is infinity, st(0) not infinity */ - if ((st0_tag == TW_Denormal) - && (denormal_operand() < 0)) - return; - - FPU_copy_to_reg1(&CONST_PI2, TAG_Valid); - } - setsign(st1_ptr, sign); - } else if (st1_tag == TAG_Zero) { - /* st(0) must be valid or zero */ - u_char sign = getsign(st1_ptr); - - if ((st0_tag == TW_Denormal) && (denormal_operand() < 0)) - return; - - if (signpositive(st0_ptr)) { - /* An 80486 preserves the sign */ - FPU_pop(); - return; - } - - FPU_copy_to_reg1(&CONST_PI, TAG_Valid); - setsign(st1_ptr, sign); - } else if (st0_tag == TAG_Zero) { - /* st(1) must be TAG_Valid here */ - u_char sign = getsign(st1_ptr); - - if ((st1_tag == TW_Denormal) && (denormal_operand() < 0)) - return; - - FPU_copy_to_reg1(&CONST_PI2, TAG_Valid); - setsign(st1_ptr, sign); - } -#ifdef PARANOID - else - EXCEPTION(EX_INTERNAL | 0x125); -#endif /* PARANOID */ - - FPU_pop(); - set_precision_flag_up(); /* We do not really know if up or down */ -} - -static void fprem(FPU_REG *st0_ptr, u_char st0_tag) -{ - do_fprem(st0_ptr, st0_tag, RC_CHOP); -} - -static void fprem1(FPU_REG *st0_ptr, u_char st0_tag) -{ - do_fprem(st0_ptr, st0_tag, RC_RND); -} - -static void fyl2xp1(FPU_REG *st0_ptr, u_char st0_tag) -{ - u_char sign, sign1; - FPU_REG *st1_ptr = &st(1), a, b; - u_char st1_tag = FPU_gettagi(1); - - clear_C1(); - if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) { - valid_yl2xp1: - - sign = getsign(st0_ptr); - sign1 = getsign(st1_ptr); - - FPU_to_exp16(st0_ptr, &a); - FPU_to_exp16(st1_ptr, &b); - - if (poly_l2p1(sign, sign1, &a, &b, st1_ptr)) - return; - - FPU_pop(); - return; - } - - if (st0_tag == TAG_Special) - st0_tag = FPU_Special(st0_ptr); - if (st1_tag == TAG_Special) - st1_tag = FPU_Special(st1_ptr); - - if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal)) - || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid)) - || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) { - if (denormal_operand() < 0) - return; - - goto valid_yl2xp1; - } else if ((st0_tag == TAG_Empty) | (st1_tag == TAG_Empty)) { - FPU_stack_underflow_pop(1); - return; - } else if (st0_tag == TAG_Zero) { - switch (st1_tag) { - case TW_Denormal: - if (denormal_operand() < 0) - return; - fallthrough; - case TAG_Zero: - case TAG_Valid: - setsign(st0_ptr, getsign(st0_ptr) ^ getsign(st1_ptr)); - FPU_copy_to_reg1(st0_ptr, st0_tag); - break; - - case TW_Infinity: - /* Infinity*log(1) */ - if (arith_invalid(1) < 0) - return; - break; - - case TW_NaN: - if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0) - return; - break; - - default: -#ifdef PARANOID - EXCEPTION(EX_INTERNAL | 0x116); - return; -#endif /* PARANOID */ - break; - } - } else if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) { - switch (st1_tag) { - case TAG_Zero: - if (signnegative(st0_ptr)) { - if (exponent(st0_ptr) >= 0) { - /* st(0) holds <= -1.0 */ -#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */ - changesign(st1_ptr); -#else - if (arith_invalid(1) < 0) - return; -#endif /* PECULIAR_486 */ - } else if ((st0_tag == TW_Denormal) - && (denormal_operand() < 0)) - return; - else - changesign(st1_ptr); - } else if ((st0_tag == TW_Denormal) - && (denormal_operand() < 0)) - return; - break; - - case TW_Infinity: - if (signnegative(st0_ptr)) { - if ((exponent(st0_ptr) >= 0) && - !((st0_ptr->sigh == 0x80000000) && - (st0_ptr->sigl == 0))) { - /* st(0) holds < -1.0 */ -#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */ - changesign(st1_ptr); -#else - if (arith_invalid(1) < 0) - return; -#endif /* PECULIAR_486 */ - } else if ((st0_tag == TW_Denormal) - && (denormal_operand() < 0)) - return; - else - changesign(st1_ptr); - } else if ((st0_tag == TW_Denormal) - && (denormal_operand() < 0)) - return; - break; - - case TW_NaN: - if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0) - return; - } - - } else if (st0_tag == TW_NaN) { - if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0) - return; - } else if (st0_tag == TW_Infinity) { - if (st1_tag == TW_NaN) { - if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0) - return; - } else if (signnegative(st0_ptr)) { -#ifndef PECULIAR_486 - /* This should have higher priority than denormals, but... */ - if (arith_invalid(1) < 0) /* log(-infinity) */ - return; -#endif /* PECULIAR_486 */ - if ((st1_tag == TW_Denormal) - && (denormal_operand() < 0)) - return; -#ifdef PECULIAR_486 - /* Denormal operands actually get higher priority */ - if (arith_invalid(1) < 0) /* log(-infinity) */ - return; -#endif /* PECULIAR_486 */ - } else if (st1_tag == TAG_Zero) { - /* log(infinity) */ - if (arith_invalid(1) < 0) - return; - } - - /* st(1) must be valid here. */ - - else if ((st1_tag == TW_Denormal) && (denormal_operand() < 0)) - return; - - /* The Manual says that log(Infinity) is invalid, but a real - 80486 sensibly says that it is o.k. */ - else { - u_char sign = getsign(st1_ptr); - FPU_copy_to_reg1(&CONST_INF, TAG_Special); - setsign(st1_ptr, sign); - } - } -#ifdef PARANOID - else { - EXCEPTION(EX_INTERNAL | 0x117); - return; - } -#endif /* PARANOID */ - - FPU_pop(); - return; - -} - -static void fscale(FPU_REG *st0_ptr, u_char st0_tag) -{ - FPU_REG *st1_ptr = &st(1); - u_char st1_tag = FPU_gettagi(1); - int old_cw = control_word; - u_char sign = getsign(st0_ptr); - - clear_C1(); - if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) { - long scale; - FPU_REG tmp; - - /* Convert register for internal use. */ - setexponent16(st0_ptr, exponent(st0_ptr)); - - valid_scale: - - if (exponent(st1_ptr) > 30) { - /* 2^31 is far too large, would require 2^(2^30) or 2^(-2^30) */ - - if (signpositive(st1_ptr)) { - EXCEPTION(EX_Overflow); - FPU_copy_to_reg0(&CONST_INF, TAG_Special); - } else { - EXCEPTION(EX_Underflow); - FPU_copy_to_reg0(&CONST_Z, TAG_Zero); - } - setsign(st0_ptr, sign); - return; - } - - control_word &= ~CW_RC; - control_word |= RC_CHOP; - reg_copy(st1_ptr, &tmp); - FPU_round_to_int(&tmp, st1_tag); /* This can never overflow here */ - control_word = old_cw; - scale = signnegative(st1_ptr) ? -tmp.sigl : tmp.sigl; - scale += exponent16(st0_ptr); - - setexponent16(st0_ptr, scale); - - /* Use FPU_round() to properly detect under/overflow etc */ - FPU_round(st0_ptr, 0, 0, control_word, sign); - - return; - } - - if (st0_tag == TAG_Special) - st0_tag = FPU_Special(st0_ptr); - if (st1_tag == TAG_Special) - st1_tag = FPU_Special(st1_ptr); - - if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) { - switch (st1_tag) { - case TAG_Valid: - /* st(0) must be a denormal */ - if ((st0_tag == TW_Denormal) - && (denormal_operand() < 0)) - return; - - FPU_to_exp16(st0_ptr, st0_ptr); /* Will not be left on stack */ - goto valid_scale; - - case TAG_Zero: - if (st0_tag == TW_Denormal) - denormal_operand(); - return; - - case TW_Denormal: - denormal_operand(); - return; - - case TW_Infinity: - if ((st0_tag == TW_Denormal) - && (denormal_operand() < 0)) - return; - - if (signpositive(st1_ptr)) - FPU_copy_to_reg0(&CONST_INF, TAG_Special); - else - FPU_copy_to_reg0(&CONST_Z, TAG_Zero); - setsign(st0_ptr, sign); - return; - - case TW_NaN: - real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr); - return; - } - } else if (st0_tag == TAG_Zero) { - switch (st1_tag) { - case TAG_Valid: - case TAG_Zero: - return; - - case TW_Denormal: - denormal_operand(); - return; - - case TW_Infinity: - if (signpositive(st1_ptr)) - arith_invalid(0); /* Zero scaled by +Infinity */ - return; - - case TW_NaN: - real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr); - return; - } - } else if (st0_tag == TW_Infinity) { - switch (st1_tag) { - case TAG_Valid: - case TAG_Zero: - return; - - case TW_Denormal: - denormal_operand(); - return; - - case TW_Infinity: - if (signnegative(st1_ptr)) - arith_invalid(0); /* Infinity scaled by -Infinity */ - return; - - case TW_NaN: - real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr); - return; - } - } else if (st0_tag == TW_NaN) { - if (st1_tag != TAG_Empty) { - real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr); - return; - } - } -#ifdef PARANOID - if (!((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty))) { - EXCEPTION(EX_INTERNAL | 0x115); - return; - } -#endif - - /* At least one of st(0), st(1) must be empty */ - FPU_stack_underflow(); - -} - -/*---------------------------------------------------------------------------*/ - -static FUNC_ST0 const trig_table_a[] = { - f2xm1, fyl2x, fptan, fpatan, - fxtract, fprem1, fdecstp, fincstp, -}; - -void FPU_triga(void) -{ - (trig_table_a[FPU_rm]) (&st(0), FPU_gettag0()); -} - -static FUNC_ST0 const trig_table_b[] = { - fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, fsin, fcos -}; - -void FPU_trigb(void) -{ - (trig_table_b[FPU_rm]) (&st(0), FPU_gettag0()); -} diff --git a/arch/x86/math-emu/get_address.c b/arch/x86/math-emu/get_address.c deleted file mode 100644 index 4a9fd9029a53..000000000000 --- a/arch/x86/math-emu/get_address.c +++ /dev/null @@ -1,401 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | get_address.c | - | | - | Get the effective address from an FPU instruction. | - | | - | Copyright (C) 1992,1993,1994,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@suburbia.net | - | | - | | - +---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------+ - | Note: | - | The file contains code which accesses user memory. | - | Emulator static data may change when user memory is accessed, due to | - | other processes using the emulator while swapping is in progress. | - +---------------------------------------------------------------------------*/ - -#include - -#include -#include - -#include "fpu_system.h" -#include "exception.h" -#include "fpu_emu.h" - -#define FPU_WRITE_BIT 0x10 - -static int reg_offset[] = { - offsetof(struct pt_regs, ax), - offsetof(struct pt_regs, cx), - offsetof(struct pt_regs, dx), - offsetof(struct pt_regs, bx), - offsetof(struct pt_regs, sp), - offsetof(struct pt_regs, bp), - offsetof(struct pt_regs, si), - offsetof(struct pt_regs, di) -}; - -#define REG_(x) (*(long *)(reg_offset[(x)] + (u_char *)FPU_info->regs)) - -static int reg_offset_vm86[] = { - offsetof(struct pt_regs, cs), - offsetof(struct kernel_vm86_regs, ds), - offsetof(struct kernel_vm86_regs, es), - offsetof(struct kernel_vm86_regs, fs), - offsetof(struct kernel_vm86_regs, gs), - offsetof(struct pt_regs, ss), - offsetof(struct kernel_vm86_regs, ds) -}; - -#define VM86_REG_(x) (*(unsigned short *) \ - (reg_offset_vm86[((unsigned)x)] + (u_char *)FPU_info->regs)) - -static int reg_offset_pm[] = { - offsetof(struct pt_regs, cs), - offsetof(struct pt_regs, ds), - offsetof(struct pt_regs, es), - offsetof(struct pt_regs, fs), - offsetof(struct pt_regs, ds), /* dummy, not saved on stack */ - offsetof(struct pt_regs, ss), - offsetof(struct pt_regs, ds) -}; - -#define PM_REG_(x) (*(unsigned short *) \ - (reg_offset_pm[((unsigned)x)] + (u_char *)FPU_info->regs)) - -/* Decode the SIB byte. This function assumes mod != 0 */ -static int sib(int mod, unsigned long *fpu_eip) -{ - u_char ss, index, base; - long offset; - - RE_ENTRANT_CHECK_OFF; - FPU_code_access_ok(1); - FPU_get_user(base, (u_char __user *) (*fpu_eip)); /* The SIB byte */ - RE_ENTRANT_CHECK_ON; - (*fpu_eip)++; - ss = base >> 6; - index = (base >> 3) & 7; - base &= 7; - - if ((mod == 0) && (base == 5)) - offset = 0; /* No base register */ - else - offset = REG_(base); - - if (index == 4) { - /* No index register */ - /* A non-zero ss is illegal */ - if (ss) - EXCEPTION(EX_Invalid); - } else { - offset += (REG_(index)) << ss; - } - - if (mod == 1) { - /* 8 bit signed displacement */ - long displacement; - RE_ENTRANT_CHECK_OFF; - FPU_code_access_ok(1); - FPU_get_user(displacement, (signed char __user *)(*fpu_eip)); - offset += displacement; - RE_ENTRANT_CHECK_ON; - (*fpu_eip)++; - } else if (mod == 2 || base == 5) { /* The second condition also has mod==0 */ - /* 32 bit displacement */ - long displacement; - RE_ENTRANT_CHECK_OFF; - FPU_code_access_ok(4); - FPU_get_user(displacement, (long __user *)(*fpu_eip)); - offset += displacement; - RE_ENTRANT_CHECK_ON; - (*fpu_eip) += 4; - } - - return offset; -} - -static unsigned long vm86_segment(u_char segment, struct address *addr) -{ - segment--; -#ifdef PARANOID - if (segment > PREFIX_SS_) { - EXCEPTION(EX_INTERNAL | 0x130); - math_abort(FPU_info, SIGSEGV); - } -#endif /* PARANOID */ - addr->selector = VM86_REG_(segment); - return (unsigned long)VM86_REG_(segment) << 4; -} - -/* This should work for 16 and 32 bit protected mode. */ -static long pm_address(u_char FPU_modrm, u_char segment, - struct address *addr, long offset) -{ - struct desc_struct descriptor; - unsigned long base_address, limit, address, seg_top; - - segment--; - -#ifdef PARANOID - /* segment is unsigned, so this also detects if segment was 0: */ - if (segment > PREFIX_SS_) { - EXCEPTION(EX_INTERNAL | 0x132); - math_abort(FPU_info, SIGSEGV); - } -#endif /* PARANOID */ - - switch (segment) { - case PREFIX_GS_ - 1: - /* user gs handling can be lazy, use special accessors */ - savesegment(gs, addr->selector); - break; - default: - addr->selector = PM_REG_(segment); - } - - descriptor = FPU_get_ldt_descriptor(addr->selector); - base_address = seg_get_base(&descriptor); - address = base_address + offset; - limit = seg_get_limit(&descriptor) + 1; - limit *= seg_get_granularity(&descriptor); - limit += base_address - 1; - if (limit < base_address) - limit = 0xffffffff; - - if (seg_expands_down(&descriptor)) { - if (descriptor.g) { - seg_top = 0xffffffff; - } else { - seg_top = base_address + (1 << 20); - if (seg_top < base_address) - seg_top = 0xffffffff; - } - access_limit = - (address <= limit) || (address >= seg_top) ? 0 : - ((seg_top - address) >= 255 ? 255 : seg_top - address); - } else { - access_limit = - (address > limit) || (address < base_address) ? 0 : - ((limit - address) >= 254 ? 255 : limit - address + 1); - } - if (seg_execute_only(&descriptor) || - (!seg_writable(&descriptor) && (FPU_modrm & FPU_WRITE_BIT))) { - access_limit = 0; - } - return address; -} - -/* - MOD R/M byte: MOD == 3 has a special use for the FPU - SIB byte used iff R/M = 100b - - 7 6 5 4 3 2 1 0 - ..... ......... ......... - MOD OPCODE(2) R/M - - SIB byte - - 7 6 5 4 3 2 1 0 - ..... ......... ......... - SS INDEX BASE - -*/ - -void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip, - struct address *addr, fpu_addr_modes addr_modes) -{ - u_char mod; - unsigned rm = FPU_modrm & 7; - long *cpu_reg_ptr; - int address = 0; /* Initialized just to stop compiler warnings. */ - - /* Memory accessed via the cs selector is write protected - in `non-segmented' 32 bit protected mode. */ - if (!addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT) - && (addr_modes.override.segment == PREFIX_CS_)) { - math_abort(FPU_info, SIGSEGV); - } - - addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */ - - mod = (FPU_modrm >> 6) & 3; - - if (rm == 4 && mod != 3) { - address = sib(mod, fpu_eip); - } else { - cpu_reg_ptr = ®_(rm); - switch (mod) { - case 0: - if (rm == 5) { - /* Special case: disp32 */ - RE_ENTRANT_CHECK_OFF; - FPU_code_access_ok(4); - FPU_get_user(address, - (unsigned long __user - *)(*fpu_eip)); - (*fpu_eip) += 4; - RE_ENTRANT_CHECK_ON; - addr->offset = address; - return (void __user *)address; - } else { - address = *cpu_reg_ptr; /* Just return the contents - of the cpu register */ - addr->offset = address; - return (void __user *)address; - } - case 1: - /* 8 bit signed displacement */ - RE_ENTRANT_CHECK_OFF; - FPU_code_access_ok(1); - FPU_get_user(address, (signed char __user *)(*fpu_eip)); - RE_ENTRANT_CHECK_ON; - (*fpu_eip)++; - break; - case 2: - /* 32 bit displacement */ - RE_ENTRANT_CHECK_OFF; - FPU_code_access_ok(4); - FPU_get_user(address, (long __user *)(*fpu_eip)); - (*fpu_eip) += 4; - RE_ENTRANT_CHECK_ON; - break; - case 3: - /* Not legal for the FPU */ - EXCEPTION(EX_Invalid); - } - address += *cpu_reg_ptr; - } - - addr->offset = address; - - switch (addr_modes.default_mode) { - case 0: - break; - case VM86: - address += vm86_segment(addr_modes.override.segment, addr); - break; - case PM16: - case SEG32: - address = pm_address(FPU_modrm, addr_modes.override.segment, - addr, address); - break; - default: - EXCEPTION(EX_INTERNAL | 0x133); - } - - return (void __user *)address; -} - -void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip, - struct address *addr, fpu_addr_modes addr_modes) -{ - u_char mod; - unsigned rm = FPU_modrm & 7; - int address = 0; /* Default used for mod == 0 */ - - /* Memory accessed via the cs selector is write protected - in `non-segmented' 32 bit protected mode. */ - if (!addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT) - && (addr_modes.override.segment == PREFIX_CS_)) { - math_abort(FPU_info, SIGSEGV); - } - - addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */ - - mod = (FPU_modrm >> 6) & 3; - - switch (mod) { - case 0: - if (rm == 6) { - /* Special case: disp16 */ - RE_ENTRANT_CHECK_OFF; - FPU_code_access_ok(2); - FPU_get_user(address, - (unsigned short __user *)(*fpu_eip)); - (*fpu_eip) += 2; - RE_ENTRANT_CHECK_ON; - goto add_segment; - } - break; - case 1: - /* 8 bit signed displacement */ - RE_ENTRANT_CHECK_OFF; - FPU_code_access_ok(1); - FPU_get_user(address, (signed char __user *)(*fpu_eip)); - RE_ENTRANT_CHECK_ON; - (*fpu_eip)++; - break; - case 2: - /* 16 bit displacement */ - RE_ENTRANT_CHECK_OFF; - FPU_code_access_ok(2); - FPU_get_user(address, (unsigned short __user *)(*fpu_eip)); - (*fpu_eip) += 2; - RE_ENTRANT_CHECK_ON; - break; - case 3: - /* Not legal for the FPU */ - EXCEPTION(EX_Invalid); - break; - } - switch (rm) { - case 0: - address += FPU_info->regs->bx + FPU_info->regs->si; - break; - case 1: - address += FPU_info->regs->bx + FPU_info->regs->di; - break; - case 2: - address += FPU_info->regs->bp + FPU_info->regs->si; - if (addr_modes.override.segment == PREFIX_DEFAULT) - addr_modes.override.segment = PREFIX_SS_; - break; - case 3: - address += FPU_info->regs->bp + FPU_info->regs->di; - if (addr_modes.override.segment == PREFIX_DEFAULT) - addr_modes.override.segment = PREFIX_SS_; - break; - case 4: - address += FPU_info->regs->si; - break; - case 5: - address += FPU_info->regs->di; - break; - case 6: - address += FPU_info->regs->bp; - if (addr_modes.override.segment == PREFIX_DEFAULT) - addr_modes.override.segment = PREFIX_SS_; - break; - case 7: - address += FPU_info->regs->bx; - break; - } - - add_segment: - address &= 0xffff; - - addr->offset = address; - - switch (addr_modes.default_mode) { - case 0: - break; - case VM86: - address += vm86_segment(addr_modes.override.segment, addr); - break; - case PM16: - case SEG32: - address = pm_address(FPU_modrm, addr_modes.override.segment, - addr, address); - break; - default: - EXCEPTION(EX_INTERNAL | 0x131); - } - - return (void __user *)address; -} diff --git a/arch/x86/math-emu/load_store.c b/arch/x86/math-emu/load_store.c deleted file mode 100644 index 4092df79de4f..000000000000 --- a/arch/x86/math-emu/load_store.c +++ /dev/null @@ -1,322 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | load_store.c | - | | - | This file contains most of the code to interpret the FPU instructions | - | which load and store from user memory. | - | | - | Copyright (C) 1992,1993,1994,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@suburbia.net | - | | - | | - +---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------+ - | Note: | - | The file contains code which accesses user memory. | - | Emulator static data may change when user memory is accessed, due to | - | other processes using the emulator while swapping is in progress. | - +---------------------------------------------------------------------------*/ - -#include - -#include "fpu_system.h" -#include "exception.h" -#include "fpu_emu.h" -#include "status_w.h" -#include "control_w.h" - -#define _NONE_ 0 /* st0_ptr etc not needed */ -#define _REG0_ 1 /* Will be storing st(0) */ -#define _PUSH_ 3 /* Need to check for space to push onto stack */ -#define _null_ 4 /* Function illegal or not implemented */ - -#define pop_0() { FPU_settag0(TAG_Empty); top++; } - -/* index is a 5-bit value: (3-bit FPU_modrm.reg field | opcode[2,1]) */ -static u_char const type_table[32] = { - _PUSH_, _PUSH_, _PUSH_, _PUSH_, /* /0: d9:fld f32, db:fild m32, dd:fld f64, df:fild m16 */ - _null_, _REG0_, _REG0_, _REG0_, /* /1: d9:undef, db,dd,df:fisttp m32/64/16 */ - _REG0_, _REG0_, _REG0_, _REG0_, /* /2: d9:fst f32, db:fist m32, dd:fst f64, df:fist m16 */ - _REG0_, _REG0_, _REG0_, _REG0_, /* /3: d9:fstp f32, db:fistp m32, dd:fstp f64, df:fistp m16 */ - _NONE_, _null_, _NONE_, _PUSH_, - _NONE_, _PUSH_, _null_, _PUSH_, - _NONE_, _null_, _NONE_, _REG0_, - _NONE_, _REG0_, _NONE_, _REG0_ -}; - -u_char const data_sizes_16[32] = { - 4, 4, 8, 2, - 0, 4, 8, 2, /* /1: d9:undef, db,dd,df:fisttp */ - 4, 4, 8, 2, - 4, 4, 8, 2, - 14, 0, 94, 10, 2, 10, 0, 8, - 14, 0, 94, 10, 2, 10, 2, 8 -}; - -static u_char const data_sizes_32[32] = { - 4, 4, 8, 2, - 0, 4, 8, 2, /* /1: d9:undef, db,dd,df:fisttp */ - 4, 4, 8, 2, - 4, 4, 8, 2, - 28, 0, 108, 10, 2, 10, 0, 8, - 28, 0, 108, 10, 2, 10, 2, 8 -}; - -int FPU_load_store(u_char type, fpu_addr_modes addr_modes, - void __user * data_address) -{ - FPU_REG loaded_data; - FPU_REG *st0_ptr; - u_char st0_tag = TAG_Empty; /* This is just to stop a gcc warning. */ - u_char loaded_tag; - int sv_cw; - - st0_ptr = NULL; /* Initialized just to stop compiler warnings. */ - - if (addr_modes.default_mode & PROTECTED) { - if (addr_modes.default_mode == SEG32) { - if (access_limit < data_sizes_32[type]) - math_abort(FPU_info, SIGSEGV); - } else if (addr_modes.default_mode == PM16) { - if (access_limit < data_sizes_16[type]) - math_abort(FPU_info, SIGSEGV); - } -#ifdef PARANOID - else - EXCEPTION(EX_INTERNAL | 0x140); -#endif /* PARANOID */ - } - - switch (type_table[type]) { - case _NONE_: - break; - case _REG0_: - st0_ptr = &st(0); /* Some of these instructions pop after - storing */ - st0_tag = FPU_gettag0(); - break; - case _PUSH_: - { - if (FPU_gettagi(-1) != TAG_Empty) { - FPU_stack_overflow(); - return 0; - } - top--; - st0_ptr = &st(0); - } - break; - case _null_: - FPU_illegal(); - return 0; -#ifdef PARANOID - default: - EXCEPTION(EX_INTERNAL | 0x141); - return 0; -#endif /* PARANOID */ - } - - switch (type) { - /* type is a 5-bit value: (3-bit FPU_modrm.reg field | opcode[2,1]) */ - case 000: /* fld m32real (d9 /0) */ - clear_C1(); - loaded_tag = - FPU_load_single((float __user *)data_address, &loaded_data); - if ((loaded_tag == TAG_Special) - && isNaN(&loaded_data) - && (real_1op_NaN(&loaded_data) < 0)) { - top++; - break; - } - FPU_copy_to_reg0(&loaded_data, loaded_tag); - break; - case 001: /* fild m32int (db /0) */ - clear_C1(); - loaded_tag = - FPU_load_int32((long __user *)data_address, &loaded_data); - FPU_copy_to_reg0(&loaded_data, loaded_tag); - break; - case 002: /* fld m64real (dd /0) */ - clear_C1(); - loaded_tag = - FPU_load_double((double __user *)data_address, - &loaded_data); - if ((loaded_tag == TAG_Special) - && isNaN(&loaded_data) - && (real_1op_NaN(&loaded_data) < 0)) { - top++; - break; - } - FPU_copy_to_reg0(&loaded_data, loaded_tag); - break; - case 003: /* fild m16int (df /0) */ - clear_C1(); - loaded_tag = - FPU_load_int16((short __user *)data_address, &loaded_data); - FPU_copy_to_reg0(&loaded_data, loaded_tag); - break; - /* case 004: undefined (d9 /1) */ - /* fisttp are enabled if CPUID(1).ECX(0) "sse3" is set */ - case 005: /* fisttp m32int (db /1) */ - clear_C1(); - sv_cw = control_word; - control_word |= RC_CHOP; - if (FPU_store_int32 - (st0_ptr, st0_tag, (long __user *)data_address)) - pop_0(); /* pop only if the number was actually stored - (see the 80486 manual p16-28) */ - control_word = sv_cw; - break; - case 006: /* fisttp m64int (dd /1) */ - clear_C1(); - sv_cw = control_word; - control_word |= RC_CHOP; - if (FPU_store_int64 - (st0_ptr, st0_tag, (long long __user *)data_address)) - pop_0(); /* pop only if the number was actually stored - (see the 80486 manual p16-28) */ - control_word = sv_cw; - break; - case 007: /* fisttp m16int (df /1) */ - clear_C1(); - sv_cw = control_word; - control_word |= RC_CHOP; - if (FPU_store_int16 - (st0_ptr, st0_tag, (short __user *)data_address)) - pop_0(); /* pop only if the number was actually stored - (see the 80486 manual p16-28) */ - control_word = sv_cw; - break; - case 010: /* fst m32real */ - clear_C1(); - FPU_store_single(st0_ptr, st0_tag, - (float __user *)data_address); - break; - case 011: /* fist m32int */ - clear_C1(); - FPU_store_int32(st0_ptr, st0_tag, (long __user *)data_address); - break; - case 012: /* fst m64real */ - clear_C1(); - FPU_store_double(st0_ptr, st0_tag, - (double __user *)data_address); - break; - case 013: /* fist m16int */ - clear_C1(); - FPU_store_int16(st0_ptr, st0_tag, (short __user *)data_address); - break; - case 014: /* fstp m32real */ - clear_C1(); - if (FPU_store_single - (st0_ptr, st0_tag, (float __user *)data_address)) - pop_0(); /* pop only if the number was actually stored - (see the 80486 manual p16-28) */ - break; - case 015: /* fistp m32int */ - clear_C1(); - if (FPU_store_int32 - (st0_ptr, st0_tag, (long __user *)data_address)) - pop_0(); /* pop only if the number was actually stored - (see the 80486 manual p16-28) */ - break; - case 016: /* fstp m64real */ - clear_C1(); - if (FPU_store_double - (st0_ptr, st0_tag, (double __user *)data_address)) - pop_0(); /* pop only if the number was actually stored - (see the 80486 manual p16-28) */ - break; - case 017: /* fistp m16int */ - clear_C1(); - if (FPU_store_int16 - (st0_ptr, st0_tag, (short __user *)data_address)) - pop_0(); /* pop only if the number was actually stored - (see the 80486 manual p16-28) */ - break; - case 020: /* fldenv m14/28byte */ - fldenv(addr_modes, (u_char __user *) data_address); - /* Ensure that the values just loaded are not changed by - fix-up operations. */ - return 1; - case 022: /* frstor m94/108byte */ - FPU_frstor(addr_modes, (u_char __user *) data_address); - /* Ensure that the values just loaded are not changed by - fix-up operations. */ - return 1; - case 023: /* fbld m80dec */ - clear_C1(); - loaded_tag = FPU_load_bcd((u_char __user *) data_address); - FPU_settag0(loaded_tag); - break; - case 024: /* fldcw */ - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(data_address, 2); - FPU_get_user(control_word, - (unsigned short __user *)data_address); - RE_ENTRANT_CHECK_ON; - if (partial_status & ~control_word & CW_Exceptions) - partial_status |= (SW_Summary | SW_Backward); - else - partial_status &= ~(SW_Summary | SW_Backward); -#ifdef PECULIAR_486 - control_word |= 0x40; /* An 80486 appears to always set this bit */ -#endif /* PECULIAR_486 */ - return 1; - case 025: /* fld m80real */ - clear_C1(); - loaded_tag = - FPU_load_extended((long double __user *)data_address, 0); - FPU_settag0(loaded_tag); - break; - case 027: /* fild m64int */ - clear_C1(); - loaded_tag = FPU_load_int64((long long __user *)data_address); - if (loaded_tag == TAG_Error) - return 0; - FPU_settag0(loaded_tag); - break; - case 030: /* fstenv m14/28byte */ - fstenv(addr_modes, (u_char __user *) data_address); - return 1; - case 032: /* fsave */ - fsave(addr_modes, (u_char __user *) data_address); - return 1; - case 033: /* fbstp m80dec */ - clear_C1(); - if (FPU_store_bcd - (st0_ptr, st0_tag, (u_char __user *) data_address)) - pop_0(); /* pop only if the number was actually stored - (see the 80486 manual p16-28) */ - break; - case 034: /* fstcw m16int */ - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(data_address, 2); - FPU_put_user(control_word, - (unsigned short __user *)data_address); - RE_ENTRANT_CHECK_ON; - return 1; - case 035: /* fstp m80real */ - clear_C1(); - if (FPU_store_extended - (st0_ptr, st0_tag, (long double __user *)data_address)) - pop_0(); /* pop only if the number was actually stored - (see the 80486 manual p16-28) */ - break; - case 036: /* fstsw m2byte */ - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(data_address, 2); - FPU_put_user(status_word(), - (unsigned short __user *)data_address); - RE_ENTRANT_CHECK_ON; - return 1; - case 037: /* fistp m64int */ - clear_C1(); - if (FPU_store_int64 - (st0_ptr, st0_tag, (long long __user *)data_address)) - pop_0(); /* pop only if the number was actually stored - (see the 80486 manual p16-28) */ - break; - } - return 0; -} diff --git a/arch/x86/math-emu/mul_Xsig.S b/arch/x86/math-emu/mul_Xsig.S deleted file mode 100644 index 54a031b66142..000000000000 --- a/arch/x86/math-emu/mul_Xsig.S +++ /dev/null @@ -1,179 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/*---------------------------------------------------------------------------+ - | mul_Xsig.S | - | | - | Multiply a 12 byte fixed point number by another fixed point number. | - | | - | Copyright (C) 1992,1994,1995 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | - | | - | Call from C as: | - | void mul32_Xsig(Xsig *x, unsigned b) | - | | - | void mul64_Xsig(Xsig *x, unsigned long long *b) | - | | - | void mul_Xsig_Xsig(Xsig *x, unsigned *b) | - | | - | The result is neither rounded nor normalized, and the ls bit or so may | - | be wrong. | - | | - +---------------------------------------------------------------------------*/ - .file "mul_Xsig.S" - - -#include "fpu_emu.h" - -.text -SYM_FUNC_START(mul32_Xsig) - pushl %ebp - movl %esp,%ebp - subl $16,%esp - pushl %esi - - movl PARAM1,%esi - movl PARAM2,%ecx - - xor %eax,%eax - movl %eax,-4(%ebp) - movl %eax,-8(%ebp) - - movl (%esi),%eax /* lsl of Xsig */ - mull %ecx /* msl of b */ - movl %edx,-12(%ebp) - - movl 4(%esi),%eax /* midl of Xsig */ - mull %ecx /* msl of b */ - addl %eax,-12(%ebp) - adcl %edx,-8(%ebp) - adcl $0,-4(%ebp) - - movl 8(%esi),%eax /* msl of Xsig */ - mull %ecx /* msl of b */ - addl %eax,-8(%ebp) - adcl %edx,-4(%ebp) - - movl -12(%ebp),%eax - movl %eax,(%esi) - movl -8(%ebp),%eax - movl %eax,4(%esi) - movl -4(%ebp),%eax - movl %eax,8(%esi) - - popl %esi - leave - RET -SYM_FUNC_END(mul32_Xsig) - - -SYM_FUNC_START(mul64_Xsig) - pushl %ebp - movl %esp,%ebp - subl $16,%esp - pushl %esi - - movl PARAM1,%esi - movl PARAM2,%ecx - - xor %eax,%eax - movl %eax,-4(%ebp) - movl %eax,-8(%ebp) - - movl (%esi),%eax /* lsl of Xsig */ - mull 4(%ecx) /* msl of b */ - movl %edx,-12(%ebp) - - movl 4(%esi),%eax /* midl of Xsig */ - mull (%ecx) /* lsl of b */ - addl %edx,-12(%ebp) - adcl $0,-8(%ebp) - adcl $0,-4(%ebp) - - movl 4(%esi),%eax /* midl of Xsig */ - mull 4(%ecx) /* msl of b */ - addl %eax,-12(%ebp) - adcl %edx,-8(%ebp) - adcl $0,-4(%ebp) - - movl 8(%esi),%eax /* msl of Xsig */ - mull (%ecx) /* lsl of b */ - addl %eax,-12(%ebp) - adcl %edx,-8(%ebp) - adcl $0,-4(%ebp) - - movl 8(%esi),%eax /* msl of Xsig */ - mull 4(%ecx) /* msl of b */ - addl %eax,-8(%ebp) - adcl %edx,-4(%ebp) - - movl -12(%ebp),%eax - movl %eax,(%esi) - movl -8(%ebp),%eax - movl %eax,4(%esi) - movl -4(%ebp),%eax - movl %eax,8(%esi) - - popl %esi - leave - RET -SYM_FUNC_END(mul64_Xsig) - - - -SYM_FUNC_START(mul_Xsig_Xsig) - pushl %ebp - movl %esp,%ebp - subl $16,%esp - pushl %esi - - movl PARAM1,%esi - movl PARAM2,%ecx - - xor %eax,%eax - movl %eax,-4(%ebp) - movl %eax,-8(%ebp) - - movl (%esi),%eax /* lsl of Xsig */ - mull 8(%ecx) /* msl of b */ - movl %edx,-12(%ebp) - - movl 4(%esi),%eax /* midl of Xsig */ - mull 4(%ecx) /* midl of b */ - addl %edx,-12(%ebp) - adcl $0,-8(%ebp) - adcl $0,-4(%ebp) - - movl 8(%esi),%eax /* msl of Xsig */ - mull (%ecx) /* lsl of b */ - addl %edx,-12(%ebp) - adcl $0,-8(%ebp) - adcl $0,-4(%ebp) - - movl 4(%esi),%eax /* midl of Xsig */ - mull 8(%ecx) /* msl of b */ - addl %eax,-12(%ebp) - adcl %edx,-8(%ebp) - adcl $0,-4(%ebp) - - movl 8(%esi),%eax /* msl of Xsig */ - mull 4(%ecx) /* midl of b */ - addl %eax,-12(%ebp) - adcl %edx,-8(%ebp) - adcl $0,-4(%ebp) - - movl 8(%esi),%eax /* msl of Xsig */ - mull 8(%ecx) /* msl of b */ - addl %eax,-8(%ebp) - adcl %edx,-4(%ebp) - - movl -12(%ebp),%edx - movl %edx,(%esi) - movl -8(%ebp),%edx - movl %edx,4(%esi) - movl -4(%ebp),%edx - movl %edx,8(%esi) - - popl %esi - leave - RET -SYM_FUNC_END(mul_Xsig_Xsig) diff --git a/arch/x86/math-emu/poly.h b/arch/x86/math-emu/poly.h deleted file mode 100644 index 654bfe4e29a0..000000000000 --- a/arch/x86/math-emu/poly.h +++ /dev/null @@ -1,115 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/*---------------------------------------------------------------------------+ - | poly.h | - | | - | Header file for the FPU-emu poly*.c source files. | - | | - | Copyright (C) 1994,1999 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@melbpc.org.au | - | | - | Declarations and definitions for functions operating on Xsig (12-byte | - | extended-significand) quantities. | - | | - +---------------------------------------------------------------------------*/ - -#ifndef _POLY_H -#define _POLY_H - -/* This 12-byte structure is used to improve the accuracy of computation - of transcendental functions. - Intended to be used to get results better than 8-byte computation - allows. 9-byte would probably be sufficient. - */ -typedef struct { - unsigned long lsw; - unsigned long midw; - unsigned long msw; -} Xsig; - -asmlinkage void mul64(unsigned long long const *a, unsigned long long const *b, - unsigned long long *result); -asmlinkage void polynomial_Xsig(Xsig *, const unsigned long long *x, - const unsigned long long terms[], const int n); - -asmlinkage void mul32_Xsig(Xsig *, const unsigned long mult); -asmlinkage void mul64_Xsig(Xsig *, const unsigned long long *mult); -asmlinkage void mul_Xsig_Xsig(Xsig *dest, const Xsig *mult); - -asmlinkage void shr_Xsig(Xsig *, const int n); -asmlinkage int round_Xsig(Xsig *); -asmlinkage int norm_Xsig(Xsig *); -asmlinkage void div_Xsig(Xsig *x1, const Xsig *x2, Xsig *dest); - -/* Macro to extract the most significant 32 bits from a long long */ -#define LL_MSW(x) (((unsigned long *)&x)[1]) - -/* Macro to initialize an Xsig struct */ -#define MK_XSIG(a,b,c) { c, b, a } - -/* Macro to access the 8 ms bytes of an Xsig as a long long */ -#define XSIG_LL(x) (*(unsigned long long *)&x.midw) - -/* - Need to run gcc with optimizations on to get these to - actually be in-line. - */ - -/* Multiply two fixed-point 32 bit numbers, producing a 32 bit result. - The answer is the ms word of the product. */ -/* Some versions of gcc make it difficult to stop eax from being clobbered. - Merely specifying that it is used doesn't work... - */ -static inline unsigned long mul_32_32(const unsigned long arg1, - const unsigned long arg2) -{ - int retval; - asm volatile ("mull %2; movl %%edx,%%eax":"=a" (retval) - :"0"(arg1), "g"(arg2) - :"dx"); - return retval; -} - -/* Add the 12 byte Xsig x2 to Xsig dest, with no checks for overflow. */ -static inline void add_Xsig_Xsig(Xsig *dest, const Xsig *x2) -{ - asm volatile ("movl %1,%%edi; movl %2,%%esi;\n" - "movl (%%esi),%%eax; addl %%eax,(%%edi);\n" - "movl 4(%%esi),%%eax; adcl %%eax,4(%%edi);\n" - "movl 8(%%esi),%%eax; adcl %%eax,8(%%edi);\n":"=g" - (*dest):"g"(dest), "g"(x2) - :"ax", "si", "di"); -} - -/* Add the 12 byte Xsig x2 to Xsig dest, adjust exp if overflow occurs. */ -/* Note: the constraints in the asm statement didn't always work properly - with gcc 2.5.8. Changing from using edi to using ecx got around the - problem, but keep fingers crossed! */ -static inline void add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp) -{ - asm volatile ("movl %2,%%ecx; movl %3,%%esi;\n" - "movl (%%esi),%%eax; addl %%eax,(%%ecx);\n" - "movl 4(%%esi),%%eax; adcl %%eax,4(%%ecx);\n" - "movl 8(%%esi),%%eax; adcl %%eax,8(%%ecx);\n" - "jnc 0f;\n" - "rcrl 8(%%ecx); rcrl 4(%%ecx); rcrl (%%ecx)\n" - "movl %4,%%ecx; incl (%%ecx)\n" - "movl $1,%%eax; jmp 1f;\n" - "0: xorl %%eax,%%eax;\n" "1:\n":"=g" (*exp), "=g"(*dest) - :"g"(dest), "g"(x2), "g"(exp) - :"cx", "si", "ax"); -} - -/* Negate (subtract from 1.0) the 12 byte Xsig */ -/* This is faster in a loop on my 386 than using the "neg" instruction. */ -static inline void negate_Xsig(Xsig *x) -{ - asm volatile ("movl %1,%%esi;\n" - "xorl %%ecx,%%ecx;\n" - "movl %%ecx,%%eax; subl (%%esi),%%eax; movl %%eax,(%%esi);\n" - "movl %%ecx,%%eax; sbbl 4(%%esi),%%eax; movl %%eax,4(%%esi);\n" - "movl %%ecx,%%eax; sbbl 8(%%esi),%%eax; movl %%eax,8(%%esi);\n":"=g" - (*x):"g"(x):"si", "ax", "cx"); -} - -#endif /* _POLY_H */ diff --git a/arch/x86/math-emu/poly_2xm1.c b/arch/x86/math-emu/poly_2xm1.c deleted file mode 100644 index aa33006bafd5..000000000000 --- a/arch/x86/math-emu/poly_2xm1.c +++ /dev/null @@ -1,146 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | poly_2xm1.c | - | | - | Function to compute 2^x-1 by a polynomial approximation. | - | | - | Copyright (C) 1992,1993,1994,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@suburbia.net | - | | - | | - +---------------------------------------------------------------------------*/ - -#include "exception.h" -#include "reg_constant.h" -#include "fpu_emu.h" -#include "fpu_system.h" -#include "control_w.h" -#include "poly.h" - -#define HIPOWER 11 -static const unsigned long long lterms[HIPOWER] = { - 0x0000000000000000LL, /* This term done separately as 12 bytes */ - 0xf5fdeffc162c7543LL, - 0x1c6b08d704a0bfa6LL, - 0x0276556df749cc21LL, - 0x002bb0ffcf14f6b8LL, - 0x0002861225ef751cLL, - 0x00001ffcbfcd5422LL, - 0x00000162c005d5f1LL, - 0x0000000da96ccb1bLL, - 0x0000000078d1b897LL, - 0x000000000422b029LL -}; - -static const Xsig hiterm = MK_XSIG(0xb17217f7, 0xd1cf79ab, 0xc8a39194); - -/* Four slices: 0.0 : 0.25 : 0.50 : 0.75 : 1.0, - These numbers are 2^(1/4), 2^(1/2), and 2^(3/4) - */ -static const Xsig shiftterm0 = MK_XSIG(0, 0, 0); -static const Xsig shiftterm1 = MK_XSIG(0x9837f051, 0x8db8a96f, 0x46ad2318); -static const Xsig shiftterm2 = MK_XSIG(0xb504f333, 0xf9de6484, 0x597d89b3); -static const Xsig shiftterm3 = MK_XSIG(0xd744fcca, 0xd69d6af4, 0x39a68bb9); - -static const Xsig *shiftterm[] = { &shiftterm0, &shiftterm1, - &shiftterm2, &shiftterm3 -}; - -/*--- poly_2xm1() -----------------------------------------------------------+ - | Requires st(0) which is TAG_Valid and < 1. | - +---------------------------------------------------------------------------*/ -int poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result) -{ - long int exponent, shift; - unsigned long long Xll; - Xsig accumulator, Denom, argSignif; - u_char tag; - - exponent = exponent16(arg); - -#ifdef PARANOID - if (exponent >= 0) { /* Don't want a |number| >= 1.0 */ - /* Number negative, too large, or not Valid. */ - EXCEPTION(EX_INTERNAL | 0x127); - return 1; - } -#endif /* PARANOID */ - - argSignif.lsw = 0; - XSIG_LL(argSignif) = Xll = significand(arg); - - if (exponent == -1) { - shift = (argSignif.msw & 0x40000000) ? 3 : 2; - /* subtract 0.5 or 0.75 */ - exponent -= 2; - XSIG_LL(argSignif) <<= 2; - Xll <<= 2; - } else if (exponent == -2) { - shift = 1; - /* subtract 0.25 */ - exponent--; - XSIG_LL(argSignif) <<= 1; - Xll <<= 1; - } else - shift = 0; - - if (exponent < -2) { - /* Shift the argument right by the required places. */ - if (FPU_shrx(&Xll, -2 - exponent) >= 0x80000000U) - Xll++; /* round up */ - } - - accumulator.lsw = accumulator.midw = accumulator.msw = 0; - polynomial_Xsig(&accumulator, &Xll, lterms, HIPOWER - 1); - mul_Xsig_Xsig(&accumulator, &argSignif); - shr_Xsig(&accumulator, 3); - - mul_Xsig_Xsig(&argSignif, &hiterm); /* The leading term */ - add_two_Xsig(&accumulator, &argSignif, &exponent); - - if (shift) { - /* The argument is large, use the identity: - f(x+a) = f(a) * (f(x) + 1) - 1; - */ - shr_Xsig(&accumulator, -exponent); - accumulator.msw |= 0x80000000; /* add 1.0 */ - mul_Xsig_Xsig(&accumulator, shiftterm[shift]); - accumulator.msw &= 0x3fffffff; /* subtract 1.0 */ - exponent = 1; - } - - if (sign != SIGN_POS) { - /* The argument is negative, use the identity: - f(-x) = -f(x) / (1 + f(x)) - */ - Denom.lsw = accumulator.lsw; - XSIG_LL(Denom) = XSIG_LL(accumulator); - if (exponent < 0) - shr_Xsig(&Denom, -exponent); - else if (exponent > 0) { - /* exponent must be 1 here */ - XSIG_LL(Denom) <<= 1; - if (Denom.lsw & 0x80000000) - XSIG_LL(Denom) |= 1; - (Denom.lsw) <<= 1; - } - Denom.msw |= 0x80000000; /* add 1.0 */ - div_Xsig(&accumulator, &Denom, &accumulator); - } - - /* Convert to 64 bit signed-compatible */ - exponent += round_Xsig(&accumulator); - - result = &st(0); - significand(result) = XSIG_LL(accumulator); - setexponent16(result, exponent); - - tag = FPU_round(result, 1, 0, FULL_PRECISION, sign); - - setsign(result, sign); - FPU_settag0(tag); - - return 0; - -} diff --git a/arch/x86/math-emu/poly_atan.c b/arch/x86/math-emu/poly_atan.c deleted file mode 100644 index 7e7412c5a1fe..000000000000 --- a/arch/x86/math-emu/poly_atan.c +++ /dev/null @@ -1,209 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | poly_atan.c | - | | - | Compute the arctan of a FPU_REG, using a polynomial approximation. | - | | - | Copyright (C) 1992,1993,1994,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@suburbia.net | - | | - | | - +---------------------------------------------------------------------------*/ - -#include "exception.h" -#include "reg_constant.h" -#include "fpu_emu.h" -#include "fpu_system.h" -#include "status_w.h" -#include "control_w.h" -#include "poly.h" - -#define HIPOWERon 6 /* odd poly, negative terms */ -static const unsigned long long oddnegterms[HIPOWERon] = { - 0x0000000000000000LL, /* Dummy (not for - 1.0) */ - 0x015328437f756467LL, - 0x0005dda27b73dec6LL, - 0x0000226bf2bfb91aLL, - 0x000000ccc439c5f7LL, - 0x0000000355438407LL -}; - -#define HIPOWERop 6 /* odd poly, positive terms */ -static const unsigned long long oddplterms[HIPOWERop] = { -/* 0xaaaaaaaaaaaaaaabLL, transferred to fixedpterm[] */ - 0x0db55a71875c9ac2LL, - 0x0029fce2d67880b0LL, - 0x0000dfd3908b4596LL, - 0x00000550fd61dab4LL, - 0x0000001c9422b3f9LL, - 0x000000003e3301e1LL -}; - -static const unsigned long long denomterm = 0xebd9b842c5c53a0eLL; - -static const Xsig fixedpterm = MK_XSIG(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa); - -static const Xsig pi_signif = MK_XSIG(0xc90fdaa2, 0x2168c234, 0xc4c6628b); - -/*--- poly_atan() -----------------------------------------------------------+ - | | - +---------------------------------------------------------------------------*/ -void poly_atan(FPU_REG *st0_ptr, u_char st0_tag, - FPU_REG *st1_ptr, u_char st1_tag) -{ - u_char transformed, inverted, sign1, sign2; - int exponent; - long int dummy_exp; - Xsig accumulator, Numer, Denom, accumulatore, argSignif, argSq, argSqSq; - u_char tag; - - sign1 = getsign(st0_ptr); - sign2 = getsign(st1_ptr); - if (st0_tag == TAG_Valid) { - exponent = exponent(st0_ptr); - } else { - /* This gives non-compatible stack contents... */ - FPU_to_exp16(st0_ptr, st0_ptr); - exponent = exponent16(st0_ptr); - } - if (st1_tag == TAG_Valid) { - exponent -= exponent(st1_ptr); - } else { - /* This gives non-compatible stack contents... */ - FPU_to_exp16(st1_ptr, st1_ptr); - exponent -= exponent16(st1_ptr); - } - - if ((exponent < 0) || ((exponent == 0) && - ((st0_ptr->sigh < st1_ptr->sigh) || - ((st0_ptr->sigh == st1_ptr->sigh) && - (st0_ptr->sigl < st1_ptr->sigl))))) { - inverted = 1; - Numer.lsw = Denom.lsw = 0; - XSIG_LL(Numer) = significand(st0_ptr); - XSIG_LL(Denom) = significand(st1_ptr); - } else { - inverted = 0; - exponent = -exponent; - Numer.lsw = Denom.lsw = 0; - XSIG_LL(Numer) = significand(st1_ptr); - XSIG_LL(Denom) = significand(st0_ptr); - } - div_Xsig(&Numer, &Denom, &argSignif); - exponent += norm_Xsig(&argSignif); - - if ((exponent >= -1) - || ((exponent == -2) && (argSignif.msw > 0xd413ccd0))) { - /* The argument is greater than sqrt(2)-1 (=0.414213562...) */ - /* Convert the argument by an identity for atan */ - transformed = 1; - - if (exponent >= 0) { -#ifdef PARANOID - if (!((exponent == 0) && - (argSignif.lsw == 0) && (argSignif.midw == 0) && - (argSignif.msw == 0x80000000))) { - EXCEPTION(EX_INTERNAL | 0x104); /* There must be a logic error */ - return; - } -#endif /* PARANOID */ - argSignif.msw = 0; /* Make the transformed arg -> 0.0 */ - } else { - Numer.lsw = Denom.lsw = argSignif.lsw; - XSIG_LL(Numer) = XSIG_LL(Denom) = XSIG_LL(argSignif); - - if (exponent < -1) - shr_Xsig(&Numer, -1 - exponent); - negate_Xsig(&Numer); - - shr_Xsig(&Denom, -exponent); - Denom.msw |= 0x80000000; - - div_Xsig(&Numer, &Denom, &argSignif); - - exponent = -1 + norm_Xsig(&argSignif); - } - } else { - transformed = 0; - } - - argSq.lsw = argSignif.lsw; - argSq.midw = argSignif.midw; - argSq.msw = argSignif.msw; - mul_Xsig_Xsig(&argSq, &argSq); - - argSqSq.lsw = argSq.lsw; - argSqSq.midw = argSq.midw; - argSqSq.msw = argSq.msw; - mul_Xsig_Xsig(&argSqSq, &argSqSq); - - accumulatore.lsw = argSq.lsw; - XSIG_LL(accumulatore) = XSIG_LL(argSq); - - shr_Xsig(&argSq, 2 * (-1 - exponent - 1)); - shr_Xsig(&argSqSq, 4 * (-1 - exponent - 1)); - - /* Now have argSq etc with binary point at the left - .1xxxxxxxx */ - - /* Do the basic fixed point polynomial evaluation */ - accumulator.msw = accumulator.midw = accumulator.lsw = 0; - polynomial_Xsig(&accumulator, &XSIG_LL(argSqSq), - oddplterms, HIPOWERop - 1); - mul64_Xsig(&accumulator, &XSIG_LL(argSq)); - negate_Xsig(&accumulator); - polynomial_Xsig(&accumulator, &XSIG_LL(argSqSq), oddnegterms, - HIPOWERon - 1); - negate_Xsig(&accumulator); - add_two_Xsig(&accumulator, &fixedpterm, &dummy_exp); - - mul64_Xsig(&accumulatore, &denomterm); - shr_Xsig(&accumulatore, 1 + 2 * (-1 - exponent)); - accumulatore.msw |= 0x80000000; - - div_Xsig(&accumulator, &accumulatore, &accumulator); - - mul_Xsig_Xsig(&accumulator, &argSignif); - mul_Xsig_Xsig(&accumulator, &argSq); - - shr_Xsig(&accumulator, 3); - negate_Xsig(&accumulator); - add_Xsig_Xsig(&accumulator, &argSignif); - - if (transformed) { - /* compute pi/4 - accumulator */ - shr_Xsig(&accumulator, -1 - exponent); - negate_Xsig(&accumulator); - add_Xsig_Xsig(&accumulator, &pi_signif); - exponent = -1; - } - - if (inverted) { - /* compute pi/2 - accumulator */ - shr_Xsig(&accumulator, -exponent); - negate_Xsig(&accumulator); - add_Xsig_Xsig(&accumulator, &pi_signif); - exponent = 0; - } - - if (sign1) { - /* compute pi - accumulator */ - shr_Xsig(&accumulator, 1 - exponent); - negate_Xsig(&accumulator); - add_Xsig_Xsig(&accumulator, &pi_signif); - exponent = 1; - } - - exponent += round_Xsig(&accumulator); - - significand(st1_ptr) = XSIG_LL(accumulator); - setexponent16(st1_ptr, exponent); - - tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign2); - FPU_settagi(1, tag); - - set_precision_flag_up(); /* We do not really know if up or down, - use this as the default. */ - -} diff --git a/arch/x86/math-emu/poly_l2.c b/arch/x86/math-emu/poly_l2.c deleted file mode 100644 index 98b6949bb854..000000000000 --- a/arch/x86/math-emu/poly_l2.c +++ /dev/null @@ -1,245 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | poly_l2.c | - | | - | Compute the base 2 log of a FPU_REG, using a polynomial approximation. | - | | - | Copyright (C) 1992,1993,1994,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@suburbia.net | - | | - | | - +---------------------------------------------------------------------------*/ - -#include "exception.h" -#include "reg_constant.h" -#include "fpu_emu.h" -#include "fpu_system.h" -#include "control_w.h" -#include "poly.h" - -static void log2_kernel(FPU_REG const *arg, u_char argsign, - Xsig * accum_result, long int *expon); - -/*--- poly_l2() -------------------------------------------------------------+ - | Base 2 logarithm by a polynomial approximation. | - +---------------------------------------------------------------------------*/ -void poly_l2(FPU_REG *st0_ptr, FPU_REG *st1_ptr, u_char st1_sign) -{ - long int exponent, expon, expon_expon; - Xsig accumulator, expon_accum, yaccum; - u_char sign, argsign; - FPU_REG x; - int tag; - - exponent = exponent16(st0_ptr); - - /* From st0_ptr, make a number > sqrt(2)/2 and < sqrt(2) */ - if (st0_ptr->sigh > (unsigned)0xb504f334) { - /* Treat as sqrt(2)/2 < st0_ptr < 1 */ - significand(&x) = -significand(st0_ptr); - setexponent16(&x, -1); - exponent++; - argsign = SIGN_NEG; - } else { - /* Treat as 1 <= st0_ptr < sqrt(2) */ - x.sigh = st0_ptr->sigh - 0x80000000; - x.sigl = st0_ptr->sigl; - setexponent16(&x, 0); - argsign = SIGN_POS; - } - tag = FPU_normalize_nuo(&x); - - if (tag == TAG_Zero) { - expon = 0; - accumulator.msw = accumulator.midw = accumulator.lsw = 0; - } else { - log2_kernel(&x, argsign, &accumulator, &expon); - } - - if (exponent < 0) { - sign = SIGN_NEG; - exponent = -exponent; - } else - sign = SIGN_POS; - expon_accum.msw = exponent; - expon_accum.midw = expon_accum.lsw = 0; - if (exponent) { - expon_expon = 31 + norm_Xsig(&expon_accum); - shr_Xsig(&accumulator, expon_expon - expon); - - if (sign ^ argsign) - negate_Xsig(&accumulator); - add_Xsig_Xsig(&accumulator, &expon_accum); - } else { - expon_expon = expon; - sign = argsign; - } - - yaccum.lsw = 0; - XSIG_LL(yaccum) = significand(st1_ptr); - mul_Xsig_Xsig(&accumulator, &yaccum); - - expon_expon += round_Xsig(&accumulator); - - if (accumulator.msw == 0) { - FPU_copy_to_reg1(&CONST_Z, TAG_Zero); - return; - } - - significand(st1_ptr) = XSIG_LL(accumulator); - setexponent16(st1_ptr, expon_expon + exponent16(st1_ptr) + 1); - - tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign ^ st1_sign); - FPU_settagi(1, tag); - - set_precision_flag_up(); /* 80486 appears to always do this */ - - return; - -} - -/*--- poly_l2p1() -----------------------------------------------------------+ - | Base 2 logarithm by a polynomial approximation. | - | log2(x+1) | - +---------------------------------------------------------------------------*/ -int poly_l2p1(u_char sign0, u_char sign1, - FPU_REG * st0_ptr, FPU_REG * st1_ptr, FPU_REG * dest) -{ - u_char tag; - long int exponent; - Xsig accumulator, yaccum; - - if (exponent16(st0_ptr) < 0) { - log2_kernel(st0_ptr, sign0, &accumulator, &exponent); - - yaccum.lsw = 0; - XSIG_LL(yaccum) = significand(st1_ptr); - mul_Xsig_Xsig(&accumulator, &yaccum); - - exponent += round_Xsig(&accumulator); - - exponent += exponent16(st1_ptr) + 1; - if (exponent < EXP_WAY_UNDER) - exponent = EXP_WAY_UNDER; - - significand(dest) = XSIG_LL(accumulator); - setexponent16(dest, exponent); - - tag = FPU_round(dest, 1, 0, FULL_PRECISION, sign0 ^ sign1); - FPU_settagi(1, tag); - - if (tag == TAG_Valid) - set_precision_flag_up(); /* 80486 appears to always do this */ - } else { - /* The magnitude of st0_ptr is far too large. */ - - if (sign0 != SIGN_POS) { - /* Trying to get the log of a negative number. */ -#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */ - changesign(st1_ptr); -#else - if (arith_invalid(1) < 0) - return 1; -#endif /* PECULIAR_486 */ - } - - /* 80486 appears to do this */ - if (sign0 == SIGN_NEG) - set_precision_flag_down(); - else - set_precision_flag_up(); - } - - if (exponent(dest) <= EXP_UNDER) - EXCEPTION(EX_Underflow); - - return 0; - -} - -#undef HIPOWER -#define HIPOWER 10 -static const unsigned long long logterms[HIPOWER] = { - 0x2a8eca5705fc2ef0LL, - 0xf6384ee1d01febceLL, - 0x093bb62877cdf642LL, - 0x006985d8a9ec439bLL, - 0x0005212c4f55a9c8LL, - 0x00004326a16927f0LL, - 0x0000038d1d80a0e7LL, - 0x0000003141cc80c6LL, - 0x00000002b1668c9fLL, - 0x000000002c7a46aaLL -}; - -static const unsigned long leadterm = 0xb8000000; - -/*--- log2_kernel() ---------------------------------------------------------+ - | Base 2 logarithm by a polynomial approximation. | - | log2(x+1) | - +---------------------------------------------------------------------------*/ -static void log2_kernel(FPU_REG const *arg, u_char argsign, Xsig *accum_result, - long int *expon) -{ - long int exponent, adj; - unsigned long long Xsq; - Xsig accumulator, Numer, Denom, argSignif, arg_signif; - - exponent = exponent16(arg); - Numer.lsw = Denom.lsw = 0; - XSIG_LL(Numer) = XSIG_LL(Denom) = significand(arg); - if (argsign == SIGN_POS) { - shr_Xsig(&Denom, 2 - (1 + exponent)); - Denom.msw |= 0x80000000; - div_Xsig(&Numer, &Denom, &argSignif); - } else { - shr_Xsig(&Denom, 1 - (1 + exponent)); - negate_Xsig(&Denom); - if (Denom.msw & 0x80000000) { - div_Xsig(&Numer, &Denom, &argSignif); - exponent++; - } else { - /* Denom must be 1.0 */ - argSignif.lsw = Numer.lsw; - argSignif.midw = Numer.midw; - argSignif.msw = Numer.msw; - } - } - -#ifndef PECULIAR_486 - /* Should check here that |local_arg| is within the valid range */ - if (exponent >= -2) { - if ((exponent > -2) || (argSignif.msw > (unsigned)0xafb0ccc0)) { - /* The argument is too large */ - } - } -#endif /* PECULIAR_486 */ - - arg_signif.lsw = argSignif.lsw; - XSIG_LL(arg_signif) = XSIG_LL(argSignif); - adj = norm_Xsig(&argSignif); - accumulator.lsw = argSignif.lsw; - XSIG_LL(accumulator) = XSIG_LL(argSignif); - mul_Xsig_Xsig(&accumulator, &accumulator); - shr_Xsig(&accumulator, 2 * (-1 - (1 + exponent + adj))); - Xsq = XSIG_LL(accumulator); - if (accumulator.lsw & 0x80000000) - Xsq++; - - accumulator.msw = accumulator.midw = accumulator.lsw = 0; - /* Do the basic fixed point polynomial evaluation */ - polynomial_Xsig(&accumulator, &Xsq, logterms, HIPOWER - 1); - - mul_Xsig_Xsig(&accumulator, &argSignif); - shr_Xsig(&accumulator, 6 - adj); - - mul32_Xsig(&arg_signif, leadterm); - add_two_Xsig(&accumulator, &arg_signif, &exponent); - - *expon = exponent + 1; - accum_result->lsw = accumulator.lsw; - accum_result->midw = accumulator.midw; - accum_result->msw = accumulator.msw; - -} diff --git a/arch/x86/math-emu/poly_sin.c b/arch/x86/math-emu/poly_sin.c deleted file mode 100644 index c192fba51526..000000000000 --- a/arch/x86/math-emu/poly_sin.c +++ /dev/null @@ -1,379 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | poly_sin.c | - | | - | Computation of an approximation of the sin function and the cosine | - | function by a polynomial. | - | | - | Copyright (C) 1992,1993,1994,1997,1999 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@melbpc.org.au | - | | - | | - +---------------------------------------------------------------------------*/ - -#include "exception.h" -#include "reg_constant.h" -#include "fpu_emu.h" -#include "fpu_system.h" -#include "control_w.h" -#include "poly.h" - -#define N_COEFF_P 4 -#define N_COEFF_N 4 - -static const unsigned long long pos_terms_l[N_COEFF_P] = { - 0xaaaaaaaaaaaaaaabLL, - 0x00d00d00d00cf906LL, - 0x000006b99159a8bbLL, - 0x000000000d7392e6LL -}; - -static const unsigned long long neg_terms_l[N_COEFF_N] = { - 0x2222222222222167LL, - 0x0002e3bc74aab624LL, - 0x0000000b09229062LL, - 0x00000000000c7973LL -}; - -#define N_COEFF_PH 4 -#define N_COEFF_NH 4 -static const unsigned long long pos_terms_h[N_COEFF_PH] = { - 0x0000000000000000LL, - 0x05b05b05b05b0406LL, - 0x000049f93edd91a9LL, - 0x00000000c9c9ed62LL -}; - -static const unsigned long long neg_terms_h[N_COEFF_NH] = { - 0xaaaaaaaaaaaaaa98LL, - 0x001a01a01a019064LL, - 0x0000008f76c68a77LL, - 0x0000000000d58f5eLL -}; - -/*--- poly_sine() -----------------------------------------------------------+ - | | - +---------------------------------------------------------------------------*/ -void poly_sine(FPU_REG *st0_ptr) -{ - int exponent, echange; - Xsig accumulator, argSqrd, argTo4; - unsigned long fix_up, adj; - unsigned long long fixed_arg; - FPU_REG result; - - exponent = exponent(st0_ptr); - - accumulator.lsw = accumulator.midw = accumulator.msw = 0; - - /* Split into two ranges, for arguments below and above 1.0 */ - /* The boundary between upper and lower is approx 0.88309101259 */ - if ((exponent < -1) - || ((exponent == -1) && (st0_ptr->sigh <= 0xe21240aa))) { - /* The argument is <= 0.88309101259 */ - - argSqrd.msw = st0_ptr->sigh; - argSqrd.midw = st0_ptr->sigl; - argSqrd.lsw = 0; - mul64_Xsig(&argSqrd, &significand(st0_ptr)); - shr_Xsig(&argSqrd, 2 * (-1 - exponent)); - argTo4.msw = argSqrd.msw; - argTo4.midw = argSqrd.midw; - argTo4.lsw = argSqrd.lsw; - mul_Xsig_Xsig(&argTo4, &argTo4); - - polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l, - N_COEFF_N - 1); - mul_Xsig_Xsig(&accumulator, &argSqrd); - negate_Xsig(&accumulator); - - polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l, - N_COEFF_P - 1); - - shr_Xsig(&accumulator, 2); /* Divide by four */ - accumulator.msw |= 0x80000000; /* Add 1.0 */ - - mul64_Xsig(&accumulator, &significand(st0_ptr)); - mul64_Xsig(&accumulator, &significand(st0_ptr)); - mul64_Xsig(&accumulator, &significand(st0_ptr)); - - /* Divide by four, FPU_REG compatible, etc */ - exponent = 3 * exponent; - - /* The minimum exponent difference is 3 */ - shr_Xsig(&accumulator, exponent(st0_ptr) - exponent); - - negate_Xsig(&accumulator); - XSIG_LL(accumulator) += significand(st0_ptr); - - echange = round_Xsig(&accumulator); - - setexponentpos(&result, exponent(st0_ptr) + echange); - } else { - /* The argument is > 0.88309101259 */ - /* We use sin(st(0)) = cos(pi/2-st(0)) */ - - fixed_arg = significand(st0_ptr); - - if (exponent == 0) { - /* The argument is >= 1.0 */ - - /* Put the binary point at the left. */ - fixed_arg <<= 1; - } - /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */ - fixed_arg = 0x921fb54442d18469LL - fixed_arg; - /* There is a special case which arises due to rounding, to fix here. */ - if (fixed_arg == 0xffffffffffffffffLL) - fixed_arg = 0; - - XSIG_LL(argSqrd) = fixed_arg; - argSqrd.lsw = 0; - mul64_Xsig(&argSqrd, &fixed_arg); - - XSIG_LL(argTo4) = XSIG_LL(argSqrd); - argTo4.lsw = argSqrd.lsw; - mul_Xsig_Xsig(&argTo4, &argTo4); - - polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h, - N_COEFF_NH - 1); - mul_Xsig_Xsig(&accumulator, &argSqrd); - negate_Xsig(&accumulator); - - polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h, - N_COEFF_PH - 1); - negate_Xsig(&accumulator); - - mul64_Xsig(&accumulator, &fixed_arg); - mul64_Xsig(&accumulator, &fixed_arg); - - shr_Xsig(&accumulator, 3); - negate_Xsig(&accumulator); - - add_Xsig_Xsig(&accumulator, &argSqrd); - - shr_Xsig(&accumulator, 1); - - accumulator.lsw |= 1; /* A zero accumulator here would cause problems */ - negate_Xsig(&accumulator); - - /* The basic computation is complete. Now fix the answer to - compensate for the error due to the approximation used for - pi/2 - */ - - /* This has an exponent of -65 */ - fix_up = 0x898cc517; - /* The fix-up needs to be improved for larger args */ - if (argSqrd.msw & 0xffc00000) { - /* Get about 32 bit precision in these: */ - fix_up -= mul_32_32(0x898cc517, argSqrd.msw) / 6; - } - fix_up = mul_32_32(fix_up, LL_MSW(fixed_arg)); - - adj = accumulator.lsw; /* temp save */ - accumulator.lsw -= fix_up; - if (accumulator.lsw > adj) - XSIG_LL(accumulator)--; - - echange = round_Xsig(&accumulator); - - setexponentpos(&result, echange - 1); - } - - significand(&result) = XSIG_LL(accumulator); - setsign(&result, getsign(st0_ptr)); - FPU_copy_to_reg0(&result, TAG_Valid); - -#ifdef PARANOID - if ((exponent(&result) >= 0) - && (significand(&result) > 0x8000000000000000LL)) { - EXCEPTION(EX_INTERNAL | 0x150); - } -#endif /* PARANOID */ - -} - -/*--- poly_cos() ------------------------------------------------------------+ - | | - +---------------------------------------------------------------------------*/ -void poly_cos(FPU_REG *st0_ptr) -{ - FPU_REG result; - long int exponent, exp2, echange; - Xsig accumulator, argSqrd, fix_up, argTo4; - unsigned long long fixed_arg; - -#ifdef PARANOID - if ((exponent(st0_ptr) > 0) - || ((exponent(st0_ptr) == 0) - && (significand(st0_ptr) > 0xc90fdaa22168c234LL))) { - EXCEPTION(EX_Invalid); - FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); - return; - } -#endif /* PARANOID */ - - exponent = exponent(st0_ptr); - - accumulator.lsw = accumulator.midw = accumulator.msw = 0; - - if ((exponent < -1) - || ((exponent == -1) && (st0_ptr->sigh <= 0xb00d6f54))) { - /* arg is < 0.687705 */ - - argSqrd.msw = st0_ptr->sigh; - argSqrd.midw = st0_ptr->sigl; - argSqrd.lsw = 0; - mul64_Xsig(&argSqrd, &significand(st0_ptr)); - - if (exponent < -1) { - /* shift the argument right by the required places */ - shr_Xsig(&argSqrd, 2 * (-1 - exponent)); - } - - argTo4.msw = argSqrd.msw; - argTo4.midw = argSqrd.midw; - argTo4.lsw = argSqrd.lsw; - mul_Xsig_Xsig(&argTo4, &argTo4); - - polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h, - N_COEFF_NH - 1); - mul_Xsig_Xsig(&accumulator, &argSqrd); - negate_Xsig(&accumulator); - - polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h, - N_COEFF_PH - 1); - negate_Xsig(&accumulator); - - mul64_Xsig(&accumulator, &significand(st0_ptr)); - mul64_Xsig(&accumulator, &significand(st0_ptr)); - shr_Xsig(&accumulator, -2 * (1 + exponent)); - - shr_Xsig(&accumulator, 3); - negate_Xsig(&accumulator); - - add_Xsig_Xsig(&accumulator, &argSqrd); - - shr_Xsig(&accumulator, 1); - - /* It doesn't matter if accumulator is all zero here, the - following code will work ok */ - negate_Xsig(&accumulator); - - if (accumulator.lsw & 0x80000000) - XSIG_LL(accumulator)++; - if (accumulator.msw == 0) { - /* The result is 1.0 */ - FPU_copy_to_reg0(&CONST_1, TAG_Valid); - return; - } else { - significand(&result) = XSIG_LL(accumulator); - - /* will be a valid positive nr with expon = -1 */ - setexponentpos(&result, -1); - } - } else { - fixed_arg = significand(st0_ptr); - - if (exponent == 0) { - /* The argument is >= 1.0 */ - - /* Put the binary point at the left. */ - fixed_arg <<= 1; - } - /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */ - fixed_arg = 0x921fb54442d18469LL - fixed_arg; - /* There is a special case which arises due to rounding, to fix here. */ - if (fixed_arg == 0xffffffffffffffffLL) - fixed_arg = 0; - - exponent = -1; - exp2 = -1; - - /* A shift is needed here only for a narrow range of arguments, - i.e. for fixed_arg approx 2^-32, but we pick up more... */ - if (!(LL_MSW(fixed_arg) & 0xffff0000)) { - fixed_arg <<= 16; - exponent -= 16; - exp2 -= 16; - } - - XSIG_LL(argSqrd) = fixed_arg; - argSqrd.lsw = 0; - mul64_Xsig(&argSqrd, &fixed_arg); - - if (exponent < -1) { - /* shift the argument right by the required places */ - shr_Xsig(&argSqrd, 2 * (-1 - exponent)); - } - - argTo4.msw = argSqrd.msw; - argTo4.midw = argSqrd.midw; - argTo4.lsw = argSqrd.lsw; - mul_Xsig_Xsig(&argTo4, &argTo4); - - polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l, - N_COEFF_N - 1); - mul_Xsig_Xsig(&accumulator, &argSqrd); - negate_Xsig(&accumulator); - - polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l, - N_COEFF_P - 1); - - shr_Xsig(&accumulator, 2); /* Divide by four */ - accumulator.msw |= 0x80000000; /* Add 1.0 */ - - mul64_Xsig(&accumulator, &fixed_arg); - mul64_Xsig(&accumulator, &fixed_arg); - mul64_Xsig(&accumulator, &fixed_arg); - - /* Divide by four, FPU_REG compatible, etc */ - exponent = 3 * exponent; - - /* The minimum exponent difference is 3 */ - shr_Xsig(&accumulator, exp2 - exponent); - - negate_Xsig(&accumulator); - XSIG_LL(accumulator) += fixed_arg; - - /* The basic computation is complete. Now fix the answer to - compensate for the error due to the approximation used for - pi/2 - */ - - /* This has an exponent of -65 */ - XSIG_LL(fix_up) = 0x898cc51701b839a2ll; - fix_up.lsw = 0; - - /* The fix-up needs to be improved for larger args */ - if (argSqrd.msw & 0xffc00000) { - /* Get about 32 bit precision in these: */ - fix_up.msw -= mul_32_32(0x898cc517, argSqrd.msw) / 2; - fix_up.msw += mul_32_32(0x898cc517, argTo4.msw) / 24; - } - - exp2 += norm_Xsig(&accumulator); - shr_Xsig(&accumulator, 1); /* Prevent overflow */ - exp2++; - shr_Xsig(&fix_up, 65 + exp2); - - add_Xsig_Xsig(&accumulator, &fix_up); - - echange = round_Xsig(&accumulator); - - setexponentpos(&result, exp2 + echange); - significand(&result) = XSIG_LL(accumulator); - } - - FPU_copy_to_reg0(&result, TAG_Valid); - -#ifdef PARANOID - if ((exponent(&result) >= 0) - && (significand(&result) > 0x8000000000000000LL)) { - EXCEPTION(EX_INTERNAL | 0x151); - } -#endif /* PARANOID */ - -} diff --git a/arch/x86/math-emu/poly_tan.c b/arch/x86/math-emu/poly_tan.c deleted file mode 100644 index 1f5b1d712323..000000000000 --- a/arch/x86/math-emu/poly_tan.c +++ /dev/null @@ -1,213 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | poly_tan.c | - | | - | Compute the tan of a FPU_REG, using a polynomial approximation. | - | | - | Copyright (C) 1992,1993,1994,1997,1999 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@melbpc.org.au | - | | - | | - +---------------------------------------------------------------------------*/ - -#include "exception.h" -#include "reg_constant.h" -#include "fpu_emu.h" -#include "fpu_system.h" -#include "control_w.h" -#include "poly.h" - -#define HiPOWERop 3 /* odd poly, positive terms */ -static const unsigned long long oddplterm[HiPOWERop] = { - 0x0000000000000000LL, - 0x0051a1cf08fca228LL, - 0x0000000071284ff7LL -}; - -#define HiPOWERon 2 /* odd poly, negative terms */ -static const unsigned long long oddnegterm[HiPOWERon] = { - 0x1291a9a184244e80LL, - 0x0000583245819c21LL -}; - -#define HiPOWERep 2 /* even poly, positive terms */ -static const unsigned long long evenplterm[HiPOWERep] = { - 0x0e848884b539e888LL, - 0x00003c7f18b887daLL -}; - -#define HiPOWERen 2 /* even poly, negative terms */ -static const unsigned long long evennegterm[HiPOWERen] = { - 0xf1f0200fd51569ccLL, - 0x003afb46105c4432LL -}; - -static const unsigned long long twothirds = 0xaaaaaaaaaaaaaaabLL; - -/*--- poly_tan() ------------------------------------------------------------+ - | | - +---------------------------------------------------------------------------*/ -void poly_tan(FPU_REG *st0_ptr) -{ - long int exponent; - int invert; - Xsig argSq, argSqSq, accumulatoro, accumulatore, accum, - argSignif, fix_up; - unsigned long adj; - - exponent = exponent(st0_ptr); - -#ifdef PARANOID - if (signnegative(st0_ptr)) { /* Can't hack a number < 0.0 */ - arith_invalid(0); - return; - } /* Need a positive number */ -#endif /* PARANOID */ - - /* Split the problem into two domains, smaller and larger than pi/4 */ - if ((exponent == 0) - || ((exponent == -1) && (st0_ptr->sigh > 0xc90fdaa2))) { - /* The argument is greater than (approx) pi/4 */ - invert = 1; - accum.lsw = 0; - XSIG_LL(accum) = significand(st0_ptr); - - if (exponent == 0) { - /* The argument is >= 1.0 */ - /* Put the binary point at the left. */ - XSIG_LL(accum) <<= 1; - } - /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */ - XSIG_LL(accum) = 0x921fb54442d18469LL - XSIG_LL(accum); - /* This is a special case which arises due to rounding. */ - if (XSIG_LL(accum) == 0xffffffffffffffffLL) { - FPU_settag0(TAG_Valid); - significand(st0_ptr) = 0x8a51e04daabda360LL; - setexponent16(st0_ptr, - (0x41 + EXTENDED_Ebias) | SIGN_Negative); - return; - } - - argSignif.lsw = accum.lsw; - XSIG_LL(argSignif) = XSIG_LL(accum); - exponent = -1 + norm_Xsig(&argSignif); - } else { - invert = 0; - argSignif.lsw = 0; - XSIG_LL(accum) = XSIG_LL(argSignif) = significand(st0_ptr); - - if (exponent < -1) { - /* shift the argument right by the required places */ - if (FPU_shrx(&XSIG_LL(accum), -1 - exponent) >= - 0x80000000U) - XSIG_LL(accum)++; /* round up */ - } - } - - XSIG_LL(argSq) = XSIG_LL(accum); - argSq.lsw = accum.lsw; - mul_Xsig_Xsig(&argSq, &argSq); - XSIG_LL(argSqSq) = XSIG_LL(argSq); - argSqSq.lsw = argSq.lsw; - mul_Xsig_Xsig(&argSqSq, &argSqSq); - - /* Compute the negative terms for the numerator polynomial */ - accumulatoro.msw = accumulatoro.midw = accumulatoro.lsw = 0; - polynomial_Xsig(&accumulatoro, &XSIG_LL(argSqSq), oddnegterm, - HiPOWERon - 1); - mul_Xsig_Xsig(&accumulatoro, &argSq); - negate_Xsig(&accumulatoro); - /* Add the positive terms */ - polynomial_Xsig(&accumulatoro, &XSIG_LL(argSqSq), oddplterm, - HiPOWERop - 1); - - /* Compute the positive terms for the denominator polynomial */ - accumulatore.msw = accumulatore.midw = accumulatore.lsw = 0; - polynomial_Xsig(&accumulatore, &XSIG_LL(argSqSq), evenplterm, - HiPOWERep - 1); - mul_Xsig_Xsig(&accumulatore, &argSq); - negate_Xsig(&accumulatore); - /* Add the negative terms */ - polynomial_Xsig(&accumulatore, &XSIG_LL(argSqSq), evennegterm, - HiPOWERen - 1); - /* Multiply by arg^2 */ - mul64_Xsig(&accumulatore, &XSIG_LL(argSignif)); - mul64_Xsig(&accumulatore, &XSIG_LL(argSignif)); - /* de-normalize and divide by 2 */ - shr_Xsig(&accumulatore, -2 * (1 + exponent) + 1); - negate_Xsig(&accumulatore); /* This does 1 - accumulator */ - - /* Now find the ratio. */ - if (accumulatore.msw == 0) { - /* accumulatoro must contain 1.0 here, (actually, 0) but it - really doesn't matter what value we use because it will - have negligible effect in later calculations - */ - XSIG_LL(accum) = 0x8000000000000000LL; - accum.lsw = 0; - } else { - div_Xsig(&accumulatoro, &accumulatore, &accum); - } - - /* Multiply by 1/3 * arg^3 */ - mul64_Xsig(&accum, &XSIG_LL(argSignif)); - mul64_Xsig(&accum, &XSIG_LL(argSignif)); - mul64_Xsig(&accum, &XSIG_LL(argSignif)); - mul64_Xsig(&accum, &twothirds); - shr_Xsig(&accum, -2 * (exponent + 1)); - - /* tan(arg) = arg + accum */ - add_two_Xsig(&accum, &argSignif, &exponent); - - if (invert) { - /* We now have the value of tan(pi_2 - arg) where pi_2 is an - approximation for pi/2 - */ - /* The next step is to fix the answer to compensate for the - error due to the approximation used for pi/2 - */ - - /* This is (approx) delta, the error in our approx for pi/2 - (see above). It has an exponent of -65 - */ - XSIG_LL(fix_up) = 0x898cc51701b839a2LL; - fix_up.lsw = 0; - - if (exponent == 0) - adj = 0xffffffff; /* We want approx 1.0 here, but - this is close enough. */ - else if (exponent > -30) { - adj = accum.msw >> -(exponent + 1); /* tan */ - adj = mul_32_32(adj, adj); /* tan^2 */ - } else - adj = 0; - adj = mul_32_32(0x898cc517, adj); /* delta * tan^2 */ - - fix_up.msw += adj; - if (!(fix_up.msw & 0x80000000)) { /* did fix_up overflow ? */ - /* Yes, we need to add an msb */ - shr_Xsig(&fix_up, 1); - fix_up.msw |= 0x80000000; - shr_Xsig(&fix_up, 64 + exponent); - } else - shr_Xsig(&fix_up, 65 + exponent); - - add_two_Xsig(&accum, &fix_up, &exponent); - - /* accum now contains tan(pi/2 - arg). - Use tan(arg) = 1.0 / tan(pi/2 - arg) - */ - accumulatoro.lsw = accumulatoro.midw = 0; - accumulatoro.msw = 0x80000000; - div_Xsig(&accumulatoro, &accum, &accum); - exponent = -exponent - 1; - } - - /* Transfer the result */ - round_Xsig(&accum); - FPU_settag0(TAG_Valid); - significand(st0_ptr) = XSIG_LL(accum); - setexponent16(st0_ptr, exponent + EXTENDED_Ebias); /* Result is positive. */ - -} diff --git a/arch/x86/math-emu/polynom_Xsig.S b/arch/x86/math-emu/polynom_Xsig.S deleted file mode 100644 index 35fd723fc0df..000000000000 --- a/arch/x86/math-emu/polynom_Xsig.S +++ /dev/null @@ -1,137 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/*---------------------------------------------------------------------------+ - | polynomial_Xsig.S | - | | - | Fixed point arithmetic polynomial evaluation. | - | | - | Copyright (C) 1992,1993,1994,1995 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | - | | - | Call from C as: | - | void polynomial_Xsig(Xsig *accum, unsigned long long x, | - | unsigned long long terms[], int n) | - | | - | Computes: | - | terms[0] + (terms[1] + (terms[2] + ... + (terms[n-1]*x)*x)*x)*x) ... )*x | - | and adds the result to the 12 byte Xsig. | - | The terms[] are each 8 bytes, but all computation is performed to 12 byte | - | precision. | - | | - | This function must be used carefully: most overflow of intermediate | - | results is controlled, but overflow of the result is not. | - | | - +---------------------------------------------------------------------------*/ - .file "polynomial_Xsig.S" - -#include "fpu_emu.h" - - -#define TERM_SIZE $8 -#define SUM_MS -20(%ebp) /* sum ms long */ -#define SUM_MIDDLE -24(%ebp) /* sum middle long */ -#define SUM_LS -28(%ebp) /* sum ls long */ -#define ACCUM_MS -4(%ebp) /* accum ms long */ -#define ACCUM_MIDDLE -8(%ebp) /* accum middle long */ -#define ACCUM_LS -12(%ebp) /* accum ls long */ -#define OVERFLOWED -16(%ebp) /* addition overflow flag */ - -.text -SYM_FUNC_START(polynomial_Xsig) - pushl %ebp - movl %esp,%ebp - subl $32,%esp - pushl %esi - pushl %edi - pushl %ebx - - movl PARAM2,%esi /* x */ - movl PARAM3,%edi /* terms */ - - movl TERM_SIZE,%eax - mull PARAM4 /* n */ - addl %eax,%edi - - movl 4(%edi),%edx /* terms[n] */ - movl %edx,SUM_MS - movl (%edi),%edx /* terms[n] */ - movl %edx,SUM_MIDDLE - xor %eax,%eax - movl %eax,SUM_LS - movb %al,OVERFLOWED - - subl TERM_SIZE,%edi - decl PARAM4 - js L_accum_done - -L_accum_loop: - xor %eax,%eax - movl %eax,ACCUM_MS - movl %eax,ACCUM_MIDDLE - - movl SUM_MIDDLE,%eax - mull (%esi) /* x ls long */ - movl %edx,ACCUM_LS - - movl SUM_MIDDLE,%eax - mull 4(%esi) /* x ms long */ - addl %eax,ACCUM_LS - adcl %edx,ACCUM_MIDDLE - adcl $0,ACCUM_MS - - movl SUM_MS,%eax - mull (%esi) /* x ls long */ - addl %eax,ACCUM_LS - adcl %edx,ACCUM_MIDDLE - adcl $0,ACCUM_MS - - movl SUM_MS,%eax - mull 4(%esi) /* x ms long */ - addl %eax,ACCUM_MIDDLE - adcl %edx,ACCUM_MS - - testb $0xff,OVERFLOWED - jz L_no_overflow - - movl (%esi),%eax - addl %eax,ACCUM_MIDDLE - movl 4(%esi),%eax - adcl %eax,ACCUM_MS /* This could overflow too */ - -L_no_overflow: - -/* - * Now put the sum of next term and the accumulator - * into the sum register - */ - movl ACCUM_LS,%eax - addl (%edi),%eax /* term ls long */ - movl %eax,SUM_LS - movl ACCUM_MIDDLE,%eax - adcl (%edi),%eax /* term ls long */ - movl %eax,SUM_MIDDLE - movl ACCUM_MS,%eax - adcl 4(%edi),%eax /* term ms long */ - movl %eax,SUM_MS - sbbb %al,%al - movb %al,OVERFLOWED /* Used in the next iteration */ - - subl TERM_SIZE,%edi - decl PARAM4 - jns L_accum_loop - -L_accum_done: - movl PARAM1,%edi /* accum */ - movl SUM_LS,%eax - addl %eax,(%edi) - movl SUM_MIDDLE,%eax - adcl %eax,4(%edi) - movl SUM_MS,%eax - adcl %eax,8(%edi) - - popl %ebx - popl %edi - popl %esi - leave - RET -SYM_FUNC_END(polynomial_Xsig) diff --git a/arch/x86/math-emu/reg_add_sub.c b/arch/x86/math-emu/reg_add_sub.c deleted file mode 100644 index 29451dd07556..000000000000 --- a/arch/x86/math-emu/reg_add_sub.c +++ /dev/null @@ -1,334 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | reg_add_sub.c | - | | - | Functions to add or subtract two registers and put the result in a third. | - | | - | Copyright (C) 1992,1993,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@suburbia.net | - | | - | | - +---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------+ - | For each function, the destination may be any FPU_REG, including one of | - | the source FPU_REGs. | - | Each function returns 0 if the answer is o.k., otherwise a non-zero | - | value is returned, indicating either an exception condition or an | - | internal error. | - +---------------------------------------------------------------------------*/ - -#include "exception.h" -#include "reg_constant.h" -#include "fpu_emu.h" -#include "control_w.h" -#include "fpu_system.h" - -static -int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa, - FPU_REG const *b, u_char tagb, u_char signb, - FPU_REG * dest, int deststnr, int control_w); - -/* - Operates on st(0) and st(n), or on st(0) and temporary data. - The destination must be one of the source st(x). - */ -int FPU_add(FPU_REG const *b, u_char tagb, int deststnr, int control_w) -{ - FPU_REG *a = &st(0); - FPU_REG *dest = &st(deststnr); - u_char signb = getsign(b); - u_char taga = FPU_gettag0(); - u_char signa = getsign(a); - u_char saved_sign = getsign(dest); - int diff, tag, expa, expb; - - if (!(taga | tagb)) { - expa = exponent(a); - expb = exponent(b); - - valid_add: - /* Both registers are valid */ - if (!(signa ^ signb)) { - /* signs are the same */ - tag = - FPU_u_add(a, b, dest, control_w, signa, expa, expb); - } else { - /* The signs are different, so do a subtraction */ - diff = expa - expb; - if (!diff) { - diff = a->sigh - b->sigh; /* This works only if the ms bits - are identical. */ - if (!diff) { - diff = a->sigl > b->sigl; - if (!diff) - diff = -(a->sigl < b->sigl); - } - } - - if (diff > 0) { - tag = - FPU_u_sub(a, b, dest, control_w, signa, - expa, expb); - } else if (diff < 0) { - tag = - FPU_u_sub(b, a, dest, control_w, signb, - expb, expa); - } else { - FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); - /* sign depends upon rounding mode */ - setsign(dest, ((control_w & CW_RC) != RC_DOWN) - ? SIGN_POS : SIGN_NEG); - return TAG_Zero; - } - } - - if (tag < 0) { - setsign(dest, saved_sign); - return tag; - } - FPU_settagi(deststnr, tag); - return tag; - } - - if (taga == TAG_Special) - taga = FPU_Special(a); - if (tagb == TAG_Special) - tagb = FPU_Special(b); - - if (((taga == TAG_Valid) && (tagb == TW_Denormal)) - || ((taga == TW_Denormal) && (tagb == TAG_Valid)) - || ((taga == TW_Denormal) && (tagb == TW_Denormal))) { - FPU_REG x, y; - - if (denormal_operand() < 0) - return FPU_Exception; - - FPU_to_exp16(a, &x); - FPU_to_exp16(b, &y); - a = &x; - b = &y; - expa = exponent16(a); - expb = exponent16(b); - goto valid_add; - } - - if ((taga == TW_NaN) || (tagb == TW_NaN)) { - if (deststnr == 0) - return real_2op_NaN(b, tagb, deststnr, a); - else - return real_2op_NaN(a, taga, deststnr, a); - } - - return add_sub_specials(a, taga, signa, b, tagb, signb, - dest, deststnr, control_w); -} - -/* Subtract b from a. (a-b) -> dest */ -int FPU_sub(int flags, int rm, int control_w) -{ - FPU_REG const *a, *b; - FPU_REG *dest; - u_char taga, tagb, signa, signb, saved_sign, sign; - int diff, tag = 0, expa, expb, deststnr; - - a = &st(0); - taga = FPU_gettag0(); - - deststnr = 0; - if (flags & LOADED) { - b = (FPU_REG *) rm; - tagb = flags & 0x0f; - } else { - b = &st(rm); - tagb = FPU_gettagi(rm); - - if (flags & DEST_RM) - deststnr = rm; - } - - signa = getsign(a); - signb = getsign(b); - - if (flags & REV) { - signa ^= SIGN_NEG; - signb ^= SIGN_NEG; - } - - dest = &st(deststnr); - saved_sign = getsign(dest); - - if (!(taga | tagb)) { - expa = exponent(a); - expb = exponent(b); - - valid_subtract: - /* Both registers are valid */ - - diff = expa - expb; - - if (!diff) { - diff = a->sigh - b->sigh; /* Works only if ms bits are identical */ - if (!diff) { - diff = a->sigl > b->sigl; - if (!diff) - diff = -(a->sigl < b->sigl); - } - } - - switch ((((int)signa) * 2 + signb) / SIGN_NEG) { - case 0: /* P - P */ - case 3: /* N - N */ - if (diff > 0) { - /* |a| > |b| */ - tag = - FPU_u_sub(a, b, dest, control_w, signa, - expa, expb); - } else if (diff == 0) { - FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); - - /* sign depends upon rounding mode */ - setsign(dest, ((control_w & CW_RC) != RC_DOWN) - ? SIGN_POS : SIGN_NEG); - return TAG_Zero; - } else { - sign = signa ^ SIGN_NEG; - tag = - FPU_u_sub(b, a, dest, control_w, sign, expb, - expa); - } - break; - case 1: /* P - N */ - tag = - FPU_u_add(a, b, dest, control_w, SIGN_POS, expa, - expb); - break; - case 2: /* N - P */ - tag = - FPU_u_add(a, b, dest, control_w, SIGN_NEG, expa, - expb); - break; -#ifdef PARANOID - default: - EXCEPTION(EX_INTERNAL | 0x111); - return -1; -#endif - } - if (tag < 0) { - setsign(dest, saved_sign); - return tag; - } - FPU_settagi(deststnr, tag); - return tag; - } - - if (taga == TAG_Special) - taga = FPU_Special(a); - if (tagb == TAG_Special) - tagb = FPU_Special(b); - - if (((taga == TAG_Valid) && (tagb == TW_Denormal)) - || ((taga == TW_Denormal) && (tagb == TAG_Valid)) - || ((taga == TW_Denormal) && (tagb == TW_Denormal))) { - FPU_REG x, y; - - if (denormal_operand() < 0) - return FPU_Exception; - - FPU_to_exp16(a, &x); - FPU_to_exp16(b, &y); - a = &x; - b = &y; - expa = exponent16(a); - expb = exponent16(b); - - goto valid_subtract; - } - - if ((taga == TW_NaN) || (tagb == TW_NaN)) { - FPU_REG const *d1, *d2; - if (flags & REV) { - d1 = b; - d2 = a; - } else { - d1 = a; - d2 = b; - } - if (flags & LOADED) - return real_2op_NaN(b, tagb, deststnr, d1); - if (flags & DEST_RM) - return real_2op_NaN(a, taga, deststnr, d2); - else - return real_2op_NaN(b, tagb, deststnr, d2); - } - - return add_sub_specials(a, taga, signa, b, tagb, signb ^ SIGN_NEG, - dest, deststnr, control_w); -} - -static -int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa, - FPU_REG const *b, u_char tagb, u_char signb, - FPU_REG * dest, int deststnr, int control_w) -{ - if (((taga == TW_Denormal) || (tagb == TW_Denormal)) - && (denormal_operand() < 0)) - return FPU_Exception; - - if (taga == TAG_Zero) { - if (tagb == TAG_Zero) { - /* Both are zero, result will be zero. */ - u_char different_signs = signa ^ signb; - - FPU_copy_to_regi(a, TAG_Zero, deststnr); - if (different_signs) { - /* Signs are different. */ - /* Sign of answer depends upon rounding mode. */ - setsign(dest, ((control_w & CW_RC) != RC_DOWN) - ? SIGN_POS : SIGN_NEG); - } else - setsign(dest, signa); /* signa may differ from the sign of a. */ - return TAG_Zero; - } else { - reg_copy(b, dest); - if ((tagb == TW_Denormal) && (b->sigh & 0x80000000)) { - /* A pseudoDenormal, convert it. */ - addexponent(dest, 1); - tagb = TAG_Valid; - } else if (tagb > TAG_Empty) - tagb = TAG_Special; - setsign(dest, signb); /* signb may differ from the sign of b. */ - FPU_settagi(deststnr, tagb); - return tagb; - } - } else if (tagb == TAG_Zero) { - reg_copy(a, dest); - if ((taga == TW_Denormal) && (a->sigh & 0x80000000)) { - /* A pseudoDenormal */ - addexponent(dest, 1); - taga = TAG_Valid; - } else if (taga > TAG_Empty) - taga = TAG_Special; - setsign(dest, signa); /* signa may differ from the sign of a. */ - FPU_settagi(deststnr, taga); - return taga; - } else if (taga == TW_Infinity) { - if ((tagb != TW_Infinity) || (signa == signb)) { - FPU_copy_to_regi(a, TAG_Special, deststnr); - setsign(dest, signa); /* signa may differ from the sign of a. */ - return taga; - } - /* Infinity-Infinity is undefined. */ - return arith_invalid(deststnr); - } else if (tagb == TW_Infinity) { - FPU_copy_to_regi(b, TAG_Special, deststnr); - setsign(dest, signb); /* signb may differ from the sign of b. */ - return tagb; - } -#ifdef PARANOID - EXCEPTION(EX_INTERNAL | 0x101); -#endif - - return FPU_Exception; -} diff --git a/arch/x86/math-emu/reg_compare.c b/arch/x86/math-emu/reg_compare.c deleted file mode 100644 index eacb5128fc09..000000000000 --- a/arch/x86/math-emu/reg_compare.c +++ /dev/null @@ -1,479 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | reg_compare.c | - | | - | Compare two floating point registers | - | | - | Copyright (C) 1992,1993,1994,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@suburbia.net | - | | - | | - +---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------+ - | compare() is the core FPU_REG comparison function | - +---------------------------------------------------------------------------*/ - -#include "fpu_system.h" -#include "exception.h" -#include "fpu_emu.h" -#include "control_w.h" -#include "status_w.h" - -static int compare(FPU_REG const *b, int tagb) -{ - int diff, exp0, expb; - u_char st0_tag; - FPU_REG *st0_ptr; - FPU_REG x, y; - u_char st0_sign, signb = getsign(b); - - st0_ptr = &st(0); - st0_tag = FPU_gettag0(); - st0_sign = getsign(st0_ptr); - - if (tagb == TAG_Special) - tagb = FPU_Special(b); - if (st0_tag == TAG_Special) - st0_tag = FPU_Special(st0_ptr); - - if (((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal)) - || ((tagb != TAG_Valid) && (tagb != TW_Denormal))) { - if (st0_tag == TAG_Zero) { - if (tagb == TAG_Zero) - return COMP_A_eq_B; - if (tagb == TAG_Valid) - return ((signb == - SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B); - if (tagb == TW_Denormal) - return ((signb == - SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) - | COMP_Denormal; - } else if (tagb == TAG_Zero) { - if (st0_tag == TAG_Valid) - return ((st0_sign == - SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B); - if (st0_tag == TW_Denormal) - return ((st0_sign == - SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) - | COMP_Denormal; - } - - if (st0_tag == TW_Infinity) { - if ((tagb == TAG_Valid) || (tagb == TAG_Zero)) - return ((st0_sign == - SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B); - else if (tagb == TW_Denormal) - return ((st0_sign == - SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) - | COMP_Denormal; - else if (tagb == TW_Infinity) { - /* The 80486 book says that infinities can be equal! */ - return (st0_sign == signb) ? COMP_A_eq_B : - ((st0_sign == - SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B); - } - /* Fall through to the NaN code */ - } else if (tagb == TW_Infinity) { - if ((st0_tag == TAG_Valid) || (st0_tag == TAG_Zero)) - return ((signb == - SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B); - if (st0_tag == TW_Denormal) - return ((signb == - SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) - | COMP_Denormal; - /* Fall through to the NaN code */ - } - - /* The only possibility now should be that one of the arguments - is a NaN */ - if ((st0_tag == TW_NaN) || (tagb == TW_NaN)) { - int signalling = 0, unsupported = 0; - if (st0_tag == TW_NaN) { - signalling = - (st0_ptr->sigh & 0xc0000000) == 0x80000000; - unsupported = !((exponent(st0_ptr) == EXP_OVER) - && (st0_ptr-> - sigh & 0x80000000)); - } - if (tagb == TW_NaN) { - signalling |= - (b->sigh & 0xc0000000) == 0x80000000; - unsupported |= !((exponent(b) == EXP_OVER) - && (b->sigh & 0x80000000)); - } - if (signalling || unsupported) - return COMP_No_Comp | COMP_SNaN | COMP_NaN; - else - /* Neither is a signaling NaN */ - return COMP_No_Comp | COMP_NaN; - } - - EXCEPTION(EX_Invalid); - } - - if (st0_sign != signb) { - return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) - | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ? - COMP_Denormal : 0); - } - - if ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) { - FPU_to_exp16(st0_ptr, &x); - FPU_to_exp16(b, &y); - st0_ptr = &x; - b = &y; - exp0 = exponent16(st0_ptr); - expb = exponent16(b); - } else { - exp0 = exponent(st0_ptr); - expb = exponent(b); - } - -#ifdef PARANOID - if (!(st0_ptr->sigh & 0x80000000)) - EXCEPTION(EX_Invalid); - if (!(b->sigh & 0x80000000)) - EXCEPTION(EX_Invalid); -#endif /* PARANOID */ - - diff = exp0 - expb; - if (diff == 0) { - diff = st0_ptr->sigh - b->sigh; /* Works only if ms bits are - identical */ - if (diff == 0) { - diff = st0_ptr->sigl > b->sigl; - if (diff == 0) - diff = -(st0_ptr->sigl < b->sigl); - } - } - - if (diff > 0) { - return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) - | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ? - COMP_Denormal : 0); - } - if (diff < 0) { - return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) - | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ? - COMP_Denormal : 0); - } - - return COMP_A_eq_B - | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ? - COMP_Denormal : 0); - -} - -/* This function requires that st(0) is not empty */ -int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag) -{ - int f, c; - - c = compare(loaded_data, loaded_tag); - - if (c & COMP_NaN) { - EXCEPTION(EX_Invalid); - f = SW_C3 | SW_C2 | SW_C0; - } else - switch (c & 7) { - case COMP_A_lt_B: - f = SW_C0; - break; - case COMP_A_eq_B: - f = SW_C3; - break; - case COMP_A_gt_B: - f = 0; - break; - case COMP_No_Comp: - f = SW_C3 | SW_C2 | SW_C0; - break; - default: -#ifdef PARANOID - EXCEPTION(EX_INTERNAL | 0x121); -#endif /* PARANOID */ - f = SW_C3 | SW_C2 | SW_C0; - break; - } - setcc(f); - if (c & COMP_Denormal) { - return denormal_operand() < 0; - } - return 0; -} - -static int compare_st_st(int nr) -{ - int f, c; - FPU_REG *st_ptr; - - if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) { - setcc(SW_C3 | SW_C2 | SW_C0); - /* Stack fault */ - EXCEPTION(EX_StackUnder); - return !(control_word & CW_Invalid); - } - - st_ptr = &st(nr); - c = compare(st_ptr, FPU_gettagi(nr)); - if (c & COMP_NaN) { - setcc(SW_C3 | SW_C2 | SW_C0); - EXCEPTION(EX_Invalid); - return !(control_word & CW_Invalid); - } else - switch (c & 7) { - case COMP_A_lt_B: - f = SW_C0; - break; - case COMP_A_eq_B: - f = SW_C3; - break; - case COMP_A_gt_B: - f = 0; - break; - case COMP_No_Comp: - f = SW_C3 | SW_C2 | SW_C0; - break; - default: -#ifdef PARANOID - EXCEPTION(EX_INTERNAL | 0x122); -#endif /* PARANOID */ - f = SW_C3 | SW_C2 | SW_C0; - break; - } - setcc(f); - if (c & COMP_Denormal) { - return denormal_operand() < 0; - } - return 0; -} - -static int compare_i_st_st(int nr) -{ - int f, c; - FPU_REG *st_ptr; - - if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) { - FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF); - /* Stack fault */ - EXCEPTION(EX_StackUnder); - return !(control_word & CW_Invalid); - } - - partial_status &= ~SW_C0; - st_ptr = &st(nr); - c = compare(st_ptr, FPU_gettagi(nr)); - if (c & COMP_NaN) { - FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF); - EXCEPTION(EX_Invalid); - return !(control_word & CW_Invalid); - } - - switch (c & 7) { - case COMP_A_lt_B: - f = X86_EFLAGS_CF; - break; - case COMP_A_eq_B: - f = X86_EFLAGS_ZF; - break; - case COMP_A_gt_B: - f = 0; - break; - case COMP_No_Comp: - f = X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF; - break; - default: -#ifdef PARANOID - EXCEPTION(EX_INTERNAL | 0x122); -#endif /* PARANOID */ - f = 0; - break; - } - FPU_EFLAGS = (FPU_EFLAGS & ~(X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF)) | f; - if (c & COMP_Denormal) { - return denormal_operand() < 0; - } - return 0; -} - -static int compare_u_st_st(int nr) -{ - int f = 0, c; - FPU_REG *st_ptr; - - if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) { - setcc(SW_C3 | SW_C2 | SW_C0); - /* Stack fault */ - EXCEPTION(EX_StackUnder); - return !(control_word & CW_Invalid); - } - - st_ptr = &st(nr); - c = compare(st_ptr, FPU_gettagi(nr)); - if (c & COMP_NaN) { - setcc(SW_C3 | SW_C2 | SW_C0); - if (c & COMP_SNaN) { /* This is the only difference between - un-ordered and ordinary comparisons */ - EXCEPTION(EX_Invalid); - return !(control_word & CW_Invalid); - } - return 0; - } else - switch (c & 7) { - case COMP_A_lt_B: - f = SW_C0; - break; - case COMP_A_eq_B: - f = SW_C3; - break; - case COMP_A_gt_B: - f = 0; - break; - case COMP_No_Comp: - f = SW_C3 | SW_C2 | SW_C0; - break; -#ifdef PARANOID - default: - EXCEPTION(EX_INTERNAL | 0x123); - f = SW_C3 | SW_C2 | SW_C0; - break; -#endif /* PARANOID */ - } - setcc(f); - if (c & COMP_Denormal) { - return denormal_operand() < 0; - } - return 0; -} - -static int compare_ui_st_st(int nr) -{ - int f = 0, c; - FPU_REG *st_ptr; - - if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) { - FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF); - /* Stack fault */ - EXCEPTION(EX_StackUnder); - return !(control_word & CW_Invalid); - } - - partial_status &= ~SW_C0; - st_ptr = &st(nr); - c = compare(st_ptr, FPU_gettagi(nr)); - if (c & COMP_NaN) { - FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF); - if (c & COMP_SNaN) { /* This is the only difference between - un-ordered and ordinary comparisons */ - EXCEPTION(EX_Invalid); - return !(control_word & CW_Invalid); - } - return 0; - } - - switch (c & 7) { - case COMP_A_lt_B: - f = X86_EFLAGS_CF; - break; - case COMP_A_eq_B: - f = X86_EFLAGS_ZF; - break; - case COMP_A_gt_B: - f = 0; - break; - case COMP_No_Comp: - f = X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF; - break; -#ifdef PARANOID - default: - EXCEPTION(EX_INTERNAL | 0x123); - f = 0; - break; -#endif /* PARANOID */ - } - FPU_EFLAGS = (FPU_EFLAGS & ~(X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF)) | f; - if (c & COMP_Denormal) { - return denormal_operand() < 0; - } - return 0; -} - -/*---------------------------------------------------------------------------*/ - -void fcom_st(void) -{ - /* fcom st(i) */ - compare_st_st(FPU_rm); -} - -void fcompst(void) -{ - /* fcomp st(i) */ - if (!compare_st_st(FPU_rm)) - FPU_pop(); -} - -void fcompp(void) -{ - /* fcompp */ - if (FPU_rm != 1) { - FPU_illegal(); - return; - } - if (!compare_st_st(1)) - poppop(); -} - -void fucom_(void) -{ - /* fucom st(i) */ - compare_u_st_st(FPU_rm); - -} - -void fucomp(void) -{ - /* fucomp st(i) */ - if (!compare_u_st_st(FPU_rm)) - FPU_pop(); -} - -void fucompp(void) -{ - /* fucompp */ - if (FPU_rm == 1) { - if (!compare_u_st_st(1)) - poppop(); - } else - FPU_illegal(); -} - -/* P6+ compare-to-EFLAGS ops */ - -void fcomi_(void) -{ - /* fcomi st(i) */ - compare_i_st_st(FPU_rm); -} - -void fcomip(void) -{ - /* fcomip st(i) */ - if (!compare_i_st_st(FPU_rm)) - FPU_pop(); -} - -void fucomi_(void) -{ - /* fucomi st(i) */ - compare_ui_st_st(FPU_rm); -} - -void fucomip(void) -{ - /* fucomip st(i) */ - if (!compare_ui_st_st(FPU_rm)) - FPU_pop(); -} diff --git a/arch/x86/math-emu/reg_constant.c b/arch/x86/math-emu/reg_constant.c deleted file mode 100644 index 003a0b2753e6..000000000000 --- a/arch/x86/math-emu/reg_constant.c +++ /dev/null @@ -1,123 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | reg_constant.c | - | | - | All of the constant FPU_REGs | - | | - | Copyright (C) 1992,1993,1994,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@suburbia.net | - | | - | | - +---------------------------------------------------------------------------*/ - -#include "fpu_system.h" -#include "fpu_emu.h" -#include "status_w.h" -#include "reg_constant.h" -#include "control_w.h" - -#define MAKE_REG(s, e, l, h) { l, h, \ - (u16)((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) } - -FPU_REG const CONST_1 = MAKE_REG(POS, 0, 0x00000000, 0x80000000); -#if 0 -FPU_REG const CONST_2 = MAKE_REG(POS, 1, 0x00000000, 0x80000000); -FPU_REG const CONST_HALF = MAKE_REG(POS, -1, 0x00000000, 0x80000000); -#endif /* 0 */ -static FPU_REG const CONST_L2T = MAKE_REG(POS, 1, 0xcd1b8afe, 0xd49a784b); -static FPU_REG const CONST_L2E = MAKE_REG(POS, 0, 0x5c17f0bc, 0xb8aa3b29); -FPU_REG const CONST_PI = MAKE_REG(POS, 1, 0x2168c235, 0xc90fdaa2); -FPU_REG const CONST_PI2 = MAKE_REG(POS, 0, 0x2168c235, 0xc90fdaa2); -FPU_REG const CONST_PI4 = MAKE_REG(POS, -1, 0x2168c235, 0xc90fdaa2); -static FPU_REG const CONST_LG2 = MAKE_REG(POS, -2, 0xfbcff799, 0x9a209a84); -static FPU_REG const CONST_LN2 = MAKE_REG(POS, -1, 0xd1cf79ac, 0xb17217f7); - -/* Extra bits to take pi/2 to more than 128 bits precision. */ -FPU_REG const CONST_PI2extra = MAKE_REG(NEG, -66, - 0xfc8f8cbb, 0xece675d1); - -/* Only the sign (and tag) is used in internal zeroes */ -FPU_REG const CONST_Z = MAKE_REG(POS, EXP_UNDER, 0x0, 0x0); - -/* Only the sign and significand (and tag) are used in internal NaNs */ -/* The 80486 never generates one of these -FPU_REG const CONST_SNAN = MAKE_REG(POS, EXP_OVER, 0x00000001, 0x80000000); - */ -/* This is the real indefinite QNaN */ -FPU_REG const CONST_QNaN = MAKE_REG(NEG, EXP_OVER, 0x00000000, 0xC0000000); - -/* Only the sign (and tag) is used in internal infinities */ -FPU_REG const CONST_INF = MAKE_REG(POS, EXP_OVER, 0x00000000, 0x80000000); - -static void fld_const(FPU_REG const * c, int adj, u_char tag) -{ - FPU_REG *st_new_ptr; - - if (STACK_OVERFLOW) { - FPU_stack_overflow(); - return; - } - push(); - reg_copy(c, st_new_ptr); - st_new_ptr->sigl += adj; /* For all our fldxxx constants, we don't need to - borrow or carry. */ - FPU_settag0(tag); - clear_C1(); -} - -/* A fast way to find out whether x is one of RC_DOWN or RC_CHOP - (and not one of RC_RND or RC_UP). - */ -#define DOWN_OR_CHOP(x) (x & RC_DOWN) - -static void fld1(int rc) -{ - fld_const(&CONST_1, 0, TAG_Valid); -} - -static void fldl2t(int rc) -{ - fld_const(&CONST_L2T, (rc == RC_UP) ? 1 : 0, TAG_Valid); -} - -static void fldl2e(int rc) -{ - fld_const(&CONST_L2E, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid); -} - -static void fldpi(int rc) -{ - fld_const(&CONST_PI, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid); -} - -static void fldlg2(int rc) -{ - fld_const(&CONST_LG2, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid); -} - -static void fldln2(int rc) -{ - fld_const(&CONST_LN2, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid); -} - -static void fldz(int rc) -{ - fld_const(&CONST_Z, 0, TAG_Zero); -} - -typedef void (*FUNC_RC) (int); - -static void FPU_RC_illegal(int unused) -{ - FPU_illegal(); -} - -static FUNC_RC constants_table[] = { - fld1, fldl2t, fldl2e, fldpi, fldlg2, fldln2, fldz, FPU_RC_illegal -}; - -void fconst(void) -{ - (constants_table[FPU_rm]) (control_word & CW_RC); -} diff --git a/arch/x86/math-emu/reg_constant.h b/arch/x86/math-emu/reg_constant.h deleted file mode 100644 index f2fdd344dcaa..000000000000 --- a/arch/x86/math-emu/reg_constant.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/*---------------------------------------------------------------------------+ - | reg_constant.h | - | | - | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | - | | - +---------------------------------------------------------------------------*/ - -#ifndef _REG_CONSTANT_H_ -#define _REG_CONSTANT_H_ - -#include "fpu_emu.h" - -extern FPU_REG const CONST_1; -extern FPU_REG const CONST_PI; -extern FPU_REG const CONST_PI2; -extern FPU_REG const CONST_PI2extra; -extern FPU_REG const CONST_PI4; -extern FPU_REG const CONST_Z; -extern FPU_REG const CONST_PINF; -extern FPU_REG const CONST_INF; -extern FPU_REG const CONST_MINF; -extern FPU_REG const CONST_QNaN; - -#endif /* _REG_CONSTANT_H_ */ diff --git a/arch/x86/math-emu/reg_convert.c b/arch/x86/math-emu/reg_convert.c deleted file mode 100644 index 251180623ce0..000000000000 --- a/arch/x86/math-emu/reg_convert.c +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | reg_convert.c | - | | - | Convert register representation. | - | | - | Copyright (C) 1992,1993,1994,1996,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@suburbia.net | - | | - | | - +---------------------------------------------------------------------------*/ - -#include "exception.h" -#include "fpu_emu.h" - -int FPU_to_exp16(FPU_REG const *a, FPU_REG *x) -{ - int sign = getsign(a); - - *(long long *)&(x->sigl) = *(const long long *)&(a->sigl); - - /* Set up the exponent as a 16 bit quantity. */ - setexponent16(x, exponent(a)); - - if (exponent16(x) == EXP_UNDER) { - /* The number is a de-normal or pseudodenormal. */ - /* We only deal with the significand and exponent. */ - - if (x->sigh & 0x80000000) { - /* Is a pseudodenormal. */ - /* This is non-80486 behaviour because the number - loses its 'denormal' identity. */ - addexponent(x, 1); - } else { - /* Is a denormal. */ - addexponent(x, 1); - FPU_normalize_nuo(x); - } - } - - if (!(x->sigh & 0x80000000)) { - EXCEPTION(EX_INTERNAL | 0x180); - } - - return sign; -} diff --git a/arch/x86/math-emu/reg_divide.c b/arch/x86/math-emu/reg_divide.c deleted file mode 100644 index 08c2f6de0288..000000000000 --- a/arch/x86/math-emu/reg_divide.c +++ /dev/null @@ -1,183 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | reg_divide.c | - | | - | Divide one FPU_REG by another and put the result in a destination FPU_REG.| - | | - | Copyright (C) 1996 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@jacobi.maths.monash.edu.au | - | | - | Return value is the tag of the answer, or-ed with FPU_Exception if | - | one was raised, or -1 on internal error. | - | | - +---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------+ - | The destination may be any FPU_REG, including one of the source FPU_REGs. | - +---------------------------------------------------------------------------*/ - -#include "exception.h" -#include "reg_constant.h" -#include "fpu_emu.h" -#include "fpu_system.h" - -/* - Divide one register by another and put the result into a third register. - */ -int FPU_div(int flags, int rm, int control_w) -{ - FPU_REG x, y; - FPU_REG const *a, *b, *st0_ptr, *st_ptr; - FPU_REG *dest; - u_char taga, tagb, signa, signb, sign, saved_sign; - int tag, deststnr; - - if (flags & DEST_RM) - deststnr = rm; - else - deststnr = 0; - - if (flags & REV) { - b = &st(0); - st0_ptr = b; - tagb = FPU_gettag0(); - if (flags & LOADED) { - a = (FPU_REG *) rm; - taga = flags & 0x0f; - } else { - a = &st(rm); - st_ptr = a; - taga = FPU_gettagi(rm); - } - } else { - a = &st(0); - st0_ptr = a; - taga = FPU_gettag0(); - if (flags & LOADED) { - b = (FPU_REG *) rm; - tagb = flags & 0x0f; - } else { - b = &st(rm); - st_ptr = b; - tagb = FPU_gettagi(rm); - } - } - - signa = getsign(a); - signb = getsign(b); - - sign = signa ^ signb; - - dest = &st(deststnr); - saved_sign = getsign(dest); - - if (!(taga | tagb)) { - /* Both regs Valid, this should be the most common case. */ - reg_copy(a, &x); - reg_copy(b, &y); - setpositive(&x); - setpositive(&y); - tag = FPU_u_div(&x, &y, dest, control_w, sign); - - if (tag < 0) - return tag; - - FPU_settagi(deststnr, tag); - return tag; - } - - if (taga == TAG_Special) - taga = FPU_Special(a); - if (tagb == TAG_Special) - tagb = FPU_Special(b); - - if (((taga == TAG_Valid) && (tagb == TW_Denormal)) - || ((taga == TW_Denormal) && (tagb == TAG_Valid)) - || ((taga == TW_Denormal) && (tagb == TW_Denormal))) { - if (denormal_operand() < 0) - return FPU_Exception; - - FPU_to_exp16(a, &x); - FPU_to_exp16(b, &y); - tag = FPU_u_div(&x, &y, dest, control_w, sign); - if (tag < 0) - return tag; - - FPU_settagi(deststnr, tag); - return tag; - } else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) { - if (tagb != TAG_Zero) { - /* Want to find Zero/Valid */ - if (tagb == TW_Denormal) { - if (denormal_operand() < 0) - return FPU_Exception; - } - - /* The result is zero. */ - FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); - setsign(dest, sign); - return TAG_Zero; - } - /* We have an exception condition, either 0/0 or Valid/Zero. */ - if (taga == TAG_Zero) { - /* 0/0 */ - return arith_invalid(deststnr); - } - /* Valid/Zero */ - return FPU_divide_by_zero(deststnr, sign); - } - /* Must have infinities, NaNs, etc */ - else if ((taga == TW_NaN) || (tagb == TW_NaN)) { - if (flags & LOADED) - return real_2op_NaN((FPU_REG *) rm, flags & 0x0f, 0, - st0_ptr); - - if (flags & DEST_RM) { - int tag; - tag = FPU_gettag0(); - if (tag == TAG_Special) - tag = FPU_Special(st0_ptr); - return real_2op_NaN(st0_ptr, tag, rm, - (flags & REV) ? st0_ptr : &st(rm)); - } else { - int tag; - tag = FPU_gettagi(rm); - if (tag == TAG_Special) - tag = FPU_Special(&st(rm)); - return real_2op_NaN(&st(rm), tag, 0, - (flags & REV) ? st0_ptr : &st(rm)); - } - } else if (taga == TW_Infinity) { - if (tagb == TW_Infinity) { - /* infinity/infinity */ - return arith_invalid(deststnr); - } else { - /* tagb must be Valid or Zero */ - if ((tagb == TW_Denormal) && (denormal_operand() < 0)) - return FPU_Exception; - - /* Infinity divided by Zero or Valid does - not raise and exception, but returns Infinity */ - FPU_copy_to_regi(a, TAG_Special, deststnr); - setsign(dest, sign); - return taga; - } - } else if (tagb == TW_Infinity) { - if ((taga == TW_Denormal) && (denormal_operand() < 0)) - return FPU_Exception; - - /* The result is zero. */ - FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); - setsign(dest, sign); - return TAG_Zero; - } -#ifdef PARANOID - else { - EXCEPTION(EX_INTERNAL | 0x102); - return FPU_Exception; - } -#endif /* PARANOID */ - - return 0; -} diff --git a/arch/x86/math-emu/reg_ld_str.c b/arch/x86/math-emu/reg_ld_str.c deleted file mode 100644 index 7e4521fbe7da..000000000000 --- a/arch/x86/math-emu/reg_ld_str.c +++ /dev/null @@ -1,1220 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | reg_ld_str.c | - | | - | All of the functions which transfer data between user memory and FPU_REGs.| - | | - | Copyright (C) 1992,1993,1994,1996,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@suburbia.net | - | | - | | - +---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------+ - | Note: | - | The file contains code which accesses user memory. | - | Emulator static data may change when user memory is accessed, due to | - | other processes using the emulator while swapping is in progress. | - +---------------------------------------------------------------------------*/ - -#include "fpu_emu.h" - -#include - -#include "fpu_system.h" -#include "exception.h" -#include "reg_constant.h" -#include "control_w.h" -#include "status_w.h" - -#define DOUBLE_Emax 1023 /* largest valid exponent */ -#define DOUBLE_Ebias 1023 -#define DOUBLE_Emin (-1022) /* smallest valid exponent */ - -#define SINGLE_Emax 127 /* largest valid exponent */ -#define SINGLE_Ebias 127 -#define SINGLE_Emin (-126) /* smallest valid exponent */ - -static u_char normalize_no_excep(FPU_REG *r, int exp, int sign) -{ - u_char tag; - - setexponent16(r, exp); - - tag = FPU_normalize_nuo(r); - stdexp(r); - if (sign) - setnegative(r); - - return tag; -} - -int FPU_tagof(FPU_REG *ptr) -{ - int exp; - - exp = exponent16(ptr) & 0x7fff; - if (exp == 0) { - if (!(ptr->sigh | ptr->sigl)) { - return TAG_Zero; - } - /* The number is a de-normal or pseudodenormal. */ - return TAG_Special; - } - - if (exp == 0x7fff) { - /* Is an Infinity, a NaN, or an unsupported data type. */ - return TAG_Special; - } - - if (!(ptr->sigh & 0x80000000)) { - /* Unsupported data type. */ - /* Valid numbers have the ms bit set to 1. */ - /* Unnormal. */ - return TAG_Special; - } - - return TAG_Valid; -} - -/* Get a long double from user memory */ -int FPU_load_extended(long double __user *s, int stnr) -{ - FPU_REG *sti_ptr = &st(stnr); - - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(s, 10); - FPU_copy_from_user(sti_ptr, s, 10); - RE_ENTRANT_CHECK_ON; - - return FPU_tagof(sti_ptr); -} - -/* Get a double from user memory */ -int FPU_load_double(double __user *dfloat, FPU_REG *loaded_data) -{ - int exp, tag, negative; - unsigned m64, l64; - - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(dfloat, 8); - FPU_get_user(m64, 1 + (unsigned long __user *)dfloat); - FPU_get_user(l64, (unsigned long __user *)dfloat); - RE_ENTRANT_CHECK_ON; - - negative = (m64 & 0x80000000) ? SIGN_Negative : SIGN_Positive; - exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias + EXTENDED_Ebias; - m64 &= 0xfffff; - if (exp > DOUBLE_Emax + EXTENDED_Ebias) { - /* Infinity or NaN */ - if ((m64 == 0) && (l64 == 0)) { - /* +- infinity */ - loaded_data->sigh = 0x80000000; - loaded_data->sigl = 0x00000000; - exp = EXP_Infinity + EXTENDED_Ebias; - tag = TAG_Special; - } else { - /* Must be a signaling or quiet NaN */ - exp = EXP_NaN + EXTENDED_Ebias; - loaded_data->sigh = (m64 << 11) | 0x80000000; - loaded_data->sigh |= l64 >> 21; - loaded_data->sigl = l64 << 11; - tag = TAG_Special; /* The calling function must look for NaNs */ - } - } else if (exp < DOUBLE_Emin + EXTENDED_Ebias) { - /* Zero or de-normal */ - if ((m64 == 0) && (l64 == 0)) { - /* Zero */ - reg_copy(&CONST_Z, loaded_data); - exp = 0; - tag = TAG_Zero; - } else { - /* De-normal */ - loaded_data->sigh = m64 << 11; - loaded_data->sigh |= l64 >> 21; - loaded_data->sigl = l64 << 11; - - return normalize_no_excep(loaded_data, DOUBLE_Emin, - negative) - | (denormal_operand() < 0 ? FPU_Exception : 0); - } - } else { - loaded_data->sigh = (m64 << 11) | 0x80000000; - loaded_data->sigh |= l64 >> 21; - loaded_data->sigl = l64 << 11; - - tag = TAG_Valid; - } - - setexponent16(loaded_data, exp | negative); - - return tag; -} - -/* Get a float from user memory */ -int FPU_load_single(float __user *single, FPU_REG *loaded_data) -{ - unsigned m32; - int exp, tag, negative; - - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(single, 4); - FPU_get_user(m32, (unsigned long __user *)single); - RE_ENTRANT_CHECK_ON; - - negative = (m32 & 0x80000000) ? SIGN_Negative : SIGN_Positive; - - if (!(m32 & 0x7fffffff)) { - /* Zero */ - reg_copy(&CONST_Z, loaded_data); - addexponent(loaded_data, negative); - return TAG_Zero; - } - exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias + EXTENDED_Ebias; - m32 = (m32 & 0x7fffff) << 8; - if (exp < SINGLE_Emin + EXTENDED_Ebias) { - /* De-normals */ - loaded_data->sigh = m32; - loaded_data->sigl = 0; - - return normalize_no_excep(loaded_data, SINGLE_Emin, negative) - | (denormal_operand() < 0 ? FPU_Exception : 0); - } else if (exp > SINGLE_Emax + EXTENDED_Ebias) { - /* Infinity or NaN */ - if (m32 == 0) { - /* +- infinity */ - loaded_data->sigh = 0x80000000; - loaded_data->sigl = 0x00000000; - exp = EXP_Infinity + EXTENDED_Ebias; - tag = TAG_Special; - } else { - /* Must be a signaling or quiet NaN */ - exp = EXP_NaN + EXTENDED_Ebias; - loaded_data->sigh = m32 | 0x80000000; - loaded_data->sigl = 0; - tag = TAG_Special; /* The calling function must look for NaNs */ - } - } else { - loaded_data->sigh = m32 | 0x80000000; - loaded_data->sigl = 0; - tag = TAG_Valid; - } - - setexponent16(loaded_data, exp | negative); /* Set the sign. */ - - return tag; -} - -/* Get a long long from user memory */ -int FPU_load_int64(long long __user *_s) -{ - long long s; - int sign; - FPU_REG *st0_ptr = &st(0); - - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(_s, 8); - if (copy_from_user(&s, _s, 8)) - FPU_abort; - RE_ENTRANT_CHECK_ON; - - if (s == 0) { - reg_copy(&CONST_Z, st0_ptr); - return TAG_Zero; - } - - if (s > 0) - sign = SIGN_Positive; - else { - s = -s; - sign = SIGN_Negative; - } - - significand(st0_ptr) = s; - - return normalize_no_excep(st0_ptr, 63, sign); -} - -/* Get a long from user memory */ -int FPU_load_int32(long __user *_s, FPU_REG *loaded_data) -{ - long s; - int negative; - - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(_s, 4); - FPU_get_user(s, _s); - RE_ENTRANT_CHECK_ON; - - if (s == 0) { - reg_copy(&CONST_Z, loaded_data); - return TAG_Zero; - } - - if (s > 0) - negative = SIGN_Positive; - else { - s = -s; - negative = SIGN_Negative; - } - - loaded_data->sigh = s; - loaded_data->sigl = 0; - - return normalize_no_excep(loaded_data, 31, negative); -} - -/* Get a short from user memory */ -int FPU_load_int16(short __user *_s, FPU_REG *loaded_data) -{ - int s, negative; - - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(_s, 2); - /* Cast as short to get the sign extended. */ - FPU_get_user(s, _s); - RE_ENTRANT_CHECK_ON; - - if (s == 0) { - reg_copy(&CONST_Z, loaded_data); - return TAG_Zero; - } - - if (s > 0) - negative = SIGN_Positive; - else { - s = -s; - negative = SIGN_Negative; - } - - loaded_data->sigh = s << 16; - loaded_data->sigl = 0; - - return normalize_no_excep(loaded_data, 15, negative); -} - -/* Get a packed bcd array from user memory */ -int FPU_load_bcd(u_char __user *s) -{ - FPU_REG *st0_ptr = &st(0); - int pos; - u_char bcd; - long long l = 0; - int sign; - - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(s, 10); - RE_ENTRANT_CHECK_ON; - for (pos = 8; pos >= 0; pos--) { - l *= 10; - RE_ENTRANT_CHECK_OFF; - FPU_get_user(bcd, s + pos); - RE_ENTRANT_CHECK_ON; - l += bcd >> 4; - l *= 10; - l += bcd & 0x0f; - } - - RE_ENTRANT_CHECK_OFF; - FPU_get_user(sign, s + 9); - sign = sign & 0x80 ? SIGN_Negative : SIGN_Positive; - RE_ENTRANT_CHECK_ON; - - if (l == 0) { - reg_copy(&CONST_Z, st0_ptr); - addexponent(st0_ptr, sign); /* Set the sign. */ - return TAG_Zero; - } else { - significand(st0_ptr) = l; - return normalize_no_excep(st0_ptr, 63, sign); - } -} - -/*===========================================================================*/ - -/* Put a long double into user memory */ -int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag, - long double __user * d) -{ - /* - The only exception raised by an attempt to store to an - extended format is the Invalid Stack exception, i.e. - attempting to store from an empty register. - */ - - if (st0_tag != TAG_Empty) { - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(d, 10); - - FPU_put_user(st0_ptr->sigl, (unsigned long __user *)d); - FPU_put_user(st0_ptr->sigh, - (unsigned long __user *)((u_char __user *) d + 4)); - FPU_put_user(exponent16(st0_ptr), - (unsigned short __user *)((u_char __user *) d + - 8)); - RE_ENTRANT_CHECK_ON; - - return 1; - } - - /* Empty register (stack underflow) */ - EXCEPTION(EX_StackUnder); - if (control_word & CW_Invalid) { - /* The masked response */ - /* Put out the QNaN indefinite */ - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(d, 10); - FPU_put_user(0, (unsigned long __user *)d); - FPU_put_user(0xc0000000, 1 + (unsigned long __user *)d); - FPU_put_user(0xffff, 4 + (short __user *)d); - RE_ENTRANT_CHECK_ON; - return 1; - } else - return 0; - -} - -/* Put a double into user memory */ -int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double __user *dfloat) -{ - unsigned long l[2]; - unsigned long increment = 0; /* avoid gcc warnings */ - int precision_loss; - int exp; - FPU_REG tmp; - - l[0] = 0; - l[1] = 0; - if (st0_tag == TAG_Valid) { - reg_copy(st0_ptr, &tmp); - exp = exponent(&tmp); - - if (exp < DOUBLE_Emin) { /* It may be a denormal */ - addexponent(&tmp, -DOUBLE_Emin + 52); /* largest exp to be 51 */ -denormal_arg: - if ((precision_loss = FPU_round_to_int(&tmp, st0_tag))) { -#ifdef PECULIAR_486 - /* Did it round to a non-denormal ? */ - /* This behaviour might be regarded as peculiar, it appears - that the 80486 rounds to the dest precision, then - converts to decide underflow. */ - if (! - ((tmp.sigh == 0x00100000) && (tmp.sigl == 0) - && (st0_ptr->sigl & 0x000007ff))) -#endif /* PECULIAR_486 */ - { - EXCEPTION(EX_Underflow); - /* This is a special case: see sec 16.2.5.1 of - the 80486 book */ - if (!(control_word & CW_Underflow)) - return 0; - } - EXCEPTION(precision_loss); - if (!(control_word & CW_Precision)) - return 0; - } - l[0] = tmp.sigl; - l[1] = tmp.sigh; - } else { - if (tmp.sigl & 0x000007ff) { - precision_loss = 1; - switch (control_word & CW_RC) { - case RC_RND: - /* Rounding can get a little messy.. */ - increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */ - ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */ - break; - case RC_DOWN: /* towards -infinity */ - increment = - signpositive(&tmp) ? 0 : tmp. - sigl & 0x7ff; - break; - case RC_UP: /* towards +infinity */ - increment = - signpositive(&tmp) ? tmp. - sigl & 0x7ff : 0; - break; - case RC_CHOP: - increment = 0; - break; - } - - /* Truncate the mantissa */ - tmp.sigl &= 0xfffff800; - - if (increment) { - if (tmp.sigl >= 0xfffff800) { - /* the sigl part overflows */ - if (tmp.sigh == 0xffffffff) { - /* The sigh part overflows */ - tmp.sigh = 0x80000000; - exp++; - if (exp >= EXP_OVER) - goto overflow; - } else { - tmp.sigh++; - } - tmp.sigl = 0x00000000; - } else { - /* We only need to increment sigl */ - tmp.sigl += 0x00000800; - } - } - } else - precision_loss = 0; - - l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21); - l[1] = ((tmp.sigh >> 11) & 0xfffff); - - if (exp > DOUBLE_Emax) { - overflow: - EXCEPTION(EX_Overflow); - if (!(control_word & CW_Overflow)) - return 0; - set_precision_flag_up(); - if (!(control_word & CW_Precision)) - return 0; - - /* This is a special case: see sec 16.2.5.1 of the 80486 book */ - /* Overflow to infinity */ - l[1] = 0x7ff00000; /* Set to + INF */ - } else { - if (precision_loss) { - if (increment) - set_precision_flag_up(); - else - set_precision_flag_down(); - } - /* Add the exponent */ - l[1] |= (((exp + DOUBLE_Ebias) & 0x7ff) << 20); - } - } - } else if (st0_tag == TAG_Zero) { - /* Number is zero */ - } else if (st0_tag == TAG_Special) { - st0_tag = FPU_Special(st0_ptr); - if (st0_tag == TW_Denormal) { - /* A denormal will always underflow. */ -#ifndef PECULIAR_486 - /* An 80486 is supposed to be able to generate - a denormal exception here, but... */ - /* Underflow has priority. */ - if (control_word & CW_Underflow) - denormal_operand(); -#endif /* PECULIAR_486 */ - reg_copy(st0_ptr, &tmp); - goto denormal_arg; - } else if (st0_tag == TW_Infinity) { - l[1] = 0x7ff00000; - } else if (st0_tag == TW_NaN) { - /* Is it really a NaN ? */ - if ((exponent(st0_ptr) == EXP_OVER) - && (st0_ptr->sigh & 0x80000000)) { - /* See if we can get a valid NaN from the FPU_REG */ - l[0] = - (st0_ptr->sigl >> 11) | (st0_ptr-> - sigh << 21); - l[1] = ((st0_ptr->sigh >> 11) & 0xfffff); - if (!(st0_ptr->sigh & 0x40000000)) { - /* It is a signalling NaN */ - EXCEPTION(EX_Invalid); - if (!(control_word & CW_Invalid)) - return 0; - l[1] |= (0x40000000 >> 11); - } - l[1] |= 0x7ff00000; - } else { - /* It is an unsupported data type */ - EXCEPTION(EX_Invalid); - if (!(control_word & CW_Invalid)) - return 0; - l[1] = 0xfff80000; - } - } - } else if (st0_tag == TAG_Empty) { - /* Empty register (stack underflow) */ - EXCEPTION(EX_StackUnder); - if (control_word & CW_Invalid) { - /* The masked response */ - /* Put out the QNaN indefinite */ - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(dfloat, 8); - FPU_put_user(0, (unsigned long __user *)dfloat); - FPU_put_user(0xfff80000, - 1 + (unsigned long __user *)dfloat); - RE_ENTRANT_CHECK_ON; - return 1; - } else - return 0; - } - if (getsign(st0_ptr)) - l[1] |= 0x80000000; - - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(dfloat, 8); - FPU_put_user(l[0], (unsigned long __user *)dfloat); - FPU_put_user(l[1], 1 + (unsigned long __user *)dfloat); - RE_ENTRANT_CHECK_ON; - - return 1; -} - -/* Put a float into user memory */ -int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float __user *single) -{ - long templ = 0; - unsigned long increment = 0; /* avoid gcc warnings */ - int precision_loss; - int exp; - FPU_REG tmp; - - if (st0_tag == TAG_Valid) { - - reg_copy(st0_ptr, &tmp); - exp = exponent(&tmp); - - if (exp < SINGLE_Emin) { - addexponent(&tmp, -SINGLE_Emin + 23); /* largest exp to be 22 */ - - denormal_arg: - - if ((precision_loss = FPU_round_to_int(&tmp, st0_tag))) { -#ifdef PECULIAR_486 - /* Did it round to a non-denormal ? */ - /* This behaviour might be regarded as peculiar, it appears - that the 80486 rounds to the dest precision, then - converts to decide underflow. */ - if (!((tmp.sigl == 0x00800000) && - ((st0_ptr->sigh & 0x000000ff) - || st0_ptr->sigl))) -#endif /* PECULIAR_486 */ - { - EXCEPTION(EX_Underflow); - /* This is a special case: see sec 16.2.5.1 of - the 80486 book */ - if (!(control_word & CW_Underflow)) - return 0; - } - EXCEPTION(precision_loss); - if (!(control_word & CW_Precision)) - return 0; - } - templ = tmp.sigl; - } else { - if (tmp.sigl | (tmp.sigh & 0x000000ff)) { - unsigned long sigh = tmp.sigh; - unsigned long sigl = tmp.sigl; - - precision_loss = 1; - switch (control_word & CW_RC) { - case RC_RND: - increment = ((sigh & 0xff) > 0x80) /* more than half */ - ||(((sigh & 0xff) == 0x80) && sigl) /* more than half */ - ||((sigh & 0x180) == 0x180); /* round to even */ - break; - case RC_DOWN: /* towards -infinity */ - increment = signpositive(&tmp) - ? 0 : (sigl | (sigh & 0xff)); - break; - case RC_UP: /* towards +infinity */ - increment = signpositive(&tmp) - ? (sigl | (sigh & 0xff)) : 0; - break; - case RC_CHOP: - increment = 0; - break; - } - - /* Truncate part of the mantissa */ - tmp.sigl = 0; - - if (increment) { - if (sigh >= 0xffffff00) { - /* The sigh part overflows */ - tmp.sigh = 0x80000000; - exp++; - if (exp >= EXP_OVER) - goto overflow; - } else { - tmp.sigh &= 0xffffff00; - tmp.sigh += 0x100; - } - } else { - tmp.sigh &= 0xffffff00; /* Finish the truncation */ - } - } else - precision_loss = 0; - - templ = (tmp.sigh >> 8) & 0x007fffff; - - if (exp > SINGLE_Emax) { - overflow: - EXCEPTION(EX_Overflow); - if (!(control_word & CW_Overflow)) - return 0; - set_precision_flag_up(); - if (!(control_word & CW_Precision)) - return 0; - - /* This is a special case: see sec 16.2.5.1 of the 80486 book. */ - /* Masked response is overflow to infinity. */ - templ = 0x7f800000; - } else { - if (precision_loss) { - if (increment) - set_precision_flag_up(); - else - set_precision_flag_down(); - } - /* Add the exponent */ - templ |= ((exp + SINGLE_Ebias) & 0xff) << 23; - } - } - } else if (st0_tag == TAG_Zero) { - templ = 0; - } else if (st0_tag == TAG_Special) { - st0_tag = FPU_Special(st0_ptr); - if (st0_tag == TW_Denormal) { - reg_copy(st0_ptr, &tmp); - - /* A denormal will always underflow. */ -#ifndef PECULIAR_486 - /* An 80486 is supposed to be able to generate - a denormal exception here, but... */ - /* Underflow has priority. */ - if (control_word & CW_Underflow) - denormal_operand(); -#endif /* PECULIAR_486 */ - goto denormal_arg; - } else if (st0_tag == TW_Infinity) { - templ = 0x7f800000; - } else if (st0_tag == TW_NaN) { - /* Is it really a NaN ? */ - if ((exponent(st0_ptr) == EXP_OVER) - && (st0_ptr->sigh & 0x80000000)) { - /* See if we can get a valid NaN from the FPU_REG */ - templ = st0_ptr->sigh >> 8; - if (!(st0_ptr->sigh & 0x40000000)) { - /* It is a signalling NaN */ - EXCEPTION(EX_Invalid); - if (!(control_word & CW_Invalid)) - return 0; - templ |= (0x40000000 >> 8); - } - templ |= 0x7f800000; - } else { - /* It is an unsupported data type */ - EXCEPTION(EX_Invalid); - if (!(control_word & CW_Invalid)) - return 0; - templ = 0xffc00000; - } - } -#ifdef PARANOID - else { - EXCEPTION(EX_INTERNAL | 0x164); - return 0; - } -#endif - } else if (st0_tag == TAG_Empty) { - /* Empty register (stack underflow) */ - EXCEPTION(EX_StackUnder); - if (control_word & EX_Invalid) { - /* The masked response */ - /* Put out the QNaN indefinite */ - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(single, 4); - FPU_put_user(0xffc00000, - (unsigned long __user *)single); - RE_ENTRANT_CHECK_ON; - return 1; - } else - return 0; - } -#ifdef PARANOID - else { - EXCEPTION(EX_INTERNAL | 0x163); - return 0; - } -#endif - if (getsign(st0_ptr)) - templ |= 0x80000000; - - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(single, 4); - FPU_put_user(templ, (unsigned long __user *)single); - RE_ENTRANT_CHECK_ON; - - return 1; -} - -/* Put a long long into user memory */ -int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long __user *d) -{ - FPU_REG t; - long long tll; - int precision_loss; - - if (st0_tag == TAG_Empty) { - /* Empty register (stack underflow) */ - EXCEPTION(EX_StackUnder); - goto invalid_operand; - } else if (st0_tag == TAG_Special) { - st0_tag = FPU_Special(st0_ptr); - if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) { - EXCEPTION(EX_Invalid); - goto invalid_operand; - } - } - - reg_copy(st0_ptr, &t); - precision_loss = FPU_round_to_int(&t, st0_tag); - ((long *)&tll)[0] = t.sigl; - ((long *)&tll)[1] = t.sigh; - if ((precision_loss == 1) || - ((t.sigh & 0x80000000) && - !((t.sigh == 0x80000000) && (t.sigl == 0) && signnegative(&t)))) { - EXCEPTION(EX_Invalid); - /* This is a special case: see sec 16.2.5.1 of the 80486 book */ - invalid_operand: - if (control_word & EX_Invalid) { - /* Produce something like QNaN "indefinite" */ - tll = 0x8000000000000000LL; - } else - return 0; - } else { - if (precision_loss) - set_precision_flag(precision_loss); - if (signnegative(&t)) - tll = -tll; - } - - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(d, 8); - if (copy_to_user(d, &tll, 8)) - FPU_abort; - RE_ENTRANT_CHECK_ON; - - return 1; -} - -/* Put a long into user memory */ -int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long __user *d) -{ - FPU_REG t; - int precision_loss; - - if (st0_tag == TAG_Empty) { - /* Empty register (stack underflow) */ - EXCEPTION(EX_StackUnder); - goto invalid_operand; - } else if (st0_tag == TAG_Special) { - st0_tag = FPU_Special(st0_ptr); - if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) { - EXCEPTION(EX_Invalid); - goto invalid_operand; - } - } - - reg_copy(st0_ptr, &t); - precision_loss = FPU_round_to_int(&t, st0_tag); - if (t.sigh || - ((t.sigl & 0x80000000) && - !((t.sigl == 0x80000000) && signnegative(&t)))) { - EXCEPTION(EX_Invalid); - /* This is a special case: see sec 16.2.5.1 of the 80486 book */ - invalid_operand: - if (control_word & EX_Invalid) { - /* Produce something like QNaN "indefinite" */ - t.sigl = 0x80000000; - } else - return 0; - } else { - if (precision_loss) - set_precision_flag(precision_loss); - if (signnegative(&t)) - t.sigl = -(long)t.sigl; - } - - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(d, 4); - FPU_put_user(t.sigl, (unsigned long __user *)d); - RE_ENTRANT_CHECK_ON; - - return 1; -} - -/* Put a short into user memory */ -int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short __user *d) -{ - FPU_REG t; - int precision_loss; - - if (st0_tag == TAG_Empty) { - /* Empty register (stack underflow) */ - EXCEPTION(EX_StackUnder); - goto invalid_operand; - } else if (st0_tag == TAG_Special) { - st0_tag = FPU_Special(st0_ptr); - if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) { - EXCEPTION(EX_Invalid); - goto invalid_operand; - } - } - - reg_copy(st0_ptr, &t); - precision_loss = FPU_round_to_int(&t, st0_tag); - if (t.sigh || - ((t.sigl & 0xffff8000) && - !((t.sigl == 0x8000) && signnegative(&t)))) { - EXCEPTION(EX_Invalid); - /* This is a special case: see sec 16.2.5.1 of the 80486 book */ - invalid_operand: - if (control_word & EX_Invalid) { - /* Produce something like QNaN "indefinite" */ - t.sigl = 0x8000; - } else - return 0; - } else { - if (precision_loss) - set_precision_flag(precision_loss); - if (signnegative(&t)) - t.sigl = -t.sigl; - } - - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(d, 2); - FPU_put_user((short)t.sigl, d); - RE_ENTRANT_CHECK_ON; - - return 1; -} - -/* Put a packed bcd array into user memory */ -int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d) -{ - FPU_REG t; - unsigned long long ll; - u_char b; - int i, precision_loss; - u_char sign = (getsign(st0_ptr) == SIGN_NEG) ? 0x80 : 0; - - if (st0_tag == TAG_Empty) { - /* Empty register (stack underflow) */ - EXCEPTION(EX_StackUnder); - goto invalid_operand; - } else if (st0_tag == TAG_Special) { - st0_tag = FPU_Special(st0_ptr); - if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) { - EXCEPTION(EX_Invalid); - goto invalid_operand; - } - } - - reg_copy(st0_ptr, &t); - precision_loss = FPU_round_to_int(&t, st0_tag); - ll = significand(&t); - - /* Check for overflow, by comparing with 999999999999999999 decimal. */ - if ((t.sigh > 0x0de0b6b3) || - ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff))) { - EXCEPTION(EX_Invalid); - /* This is a special case: see sec 16.2.5.1 of the 80486 book */ - invalid_operand: - if (control_word & CW_Invalid) { - /* Produce the QNaN "indefinite" */ - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(d, 10); - for (i = 0; i < 7; i++) - FPU_put_user(0, d + i); /* These bytes "undefined" */ - FPU_put_user(0xc0, d + 7); /* This byte "undefined" */ - FPU_put_user(0xff, d + 8); - FPU_put_user(0xff, d + 9); - RE_ENTRANT_CHECK_ON; - return 1; - } else - return 0; - } else if (precision_loss) { - /* Precision loss doesn't stop the data transfer */ - set_precision_flag(precision_loss); - } - - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(d, 10); - RE_ENTRANT_CHECK_ON; - for (i = 0; i < 9; i++) { - b = FPU_div_small(&ll, 10); - b |= (FPU_div_small(&ll, 10)) << 4; - RE_ENTRANT_CHECK_OFF; - FPU_put_user(b, d + i); - RE_ENTRANT_CHECK_ON; - } - RE_ENTRANT_CHECK_OFF; - FPU_put_user(sign, d + 9); - RE_ENTRANT_CHECK_ON; - - return 1; -} - -/*===========================================================================*/ - -/* r gets mangled such that sig is int, sign: - it is NOT normalized */ -/* The return value (in eax) is zero if the result is exact, - if bits are changed due to rounding, truncation, etc, then - a non-zero value is returned */ -/* Overflow is signaled by a non-zero return value (in eax). - In the case of overflow, the returned significand always has the - largest possible value */ -int FPU_round_to_int(FPU_REG *r, u_char tag) -{ - u_char very_big; - unsigned eax; - - if (tag == TAG_Zero) { - /* Make sure that zero is returned */ - significand(r) = 0; - return 0; /* o.k. */ - } - - if (exponent(r) > 63) { - r->sigl = r->sigh = ~0; /* The largest representable number */ - return 1; /* overflow */ - } - - eax = FPU_shrxs(&r->sigl, 63 - exponent(r)); - very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */ -#define half_or_more (eax & 0x80000000) -#define frac_part (eax) -#define more_than_half ((eax & 0x80000001) == 0x80000001) - switch (control_word & CW_RC) { - case RC_RND: - if (more_than_half /* nearest */ - || (half_or_more && (r->sigl & 1))) { /* odd -> even */ - if (very_big) - return 1; /* overflow */ - significand(r)++; - return PRECISION_LOST_UP; - } - break; - case RC_DOWN: - if (frac_part && getsign(r)) { - if (very_big) - return 1; /* overflow */ - significand(r)++; - return PRECISION_LOST_UP; - } - break; - case RC_UP: - if (frac_part && !getsign(r)) { - if (very_big) - return 1; /* overflow */ - significand(r)++; - return PRECISION_LOST_UP; - } - break; - case RC_CHOP: - break; - } - - return eax ? PRECISION_LOST_DOWN : 0; - -} - -/*===========================================================================*/ - -u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s) -{ - unsigned short tag_word = 0; - u_char tag; - int i; - - if ((addr_modes.default_mode == VM86) || - ((addr_modes.default_mode == PM16) - ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX))) { - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(s, 0x0e); - FPU_get_user(control_word, (unsigned short __user *)s); - FPU_get_user(partial_status, (unsigned short __user *)(s + 2)); - FPU_get_user(tag_word, (unsigned short __user *)(s + 4)); - FPU_get_user(instruction_address.offset, - (unsigned short __user *)(s + 6)); - FPU_get_user(instruction_address.selector, - (unsigned short __user *)(s + 8)); - FPU_get_user(operand_address.offset, - (unsigned short __user *)(s + 0x0a)); - FPU_get_user(operand_address.selector, - (unsigned short __user *)(s + 0x0c)); - RE_ENTRANT_CHECK_ON; - s += 0x0e; - if (addr_modes.default_mode == VM86) { - instruction_address.offset - += (instruction_address.selector & 0xf000) << 4; - operand_address.offset += - (operand_address.selector & 0xf000) << 4; - } - } else { - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(s, 0x1c); - FPU_get_user(control_word, (unsigned short __user *)s); - FPU_get_user(partial_status, (unsigned short __user *)(s + 4)); - FPU_get_user(tag_word, (unsigned short __user *)(s + 8)); - FPU_get_user(instruction_address.offset, - (unsigned long __user *)(s + 0x0c)); - FPU_get_user(instruction_address.selector, - (unsigned short __user *)(s + 0x10)); - FPU_get_user(instruction_address.opcode, - (unsigned short __user *)(s + 0x12)); - FPU_get_user(operand_address.offset, - (unsigned long __user *)(s + 0x14)); - FPU_get_user(operand_address.selector, - (unsigned long __user *)(s + 0x18)); - RE_ENTRANT_CHECK_ON; - s += 0x1c; - } - -#ifdef PECULIAR_486 - control_word &= ~0xe080; -#endif /* PECULIAR_486 */ - - top = (partial_status >> SW_Top_Shift) & 7; - - if (partial_status & ~control_word & CW_Exceptions) - partial_status |= (SW_Summary | SW_Backward); - else - partial_status &= ~(SW_Summary | SW_Backward); - - for (i = 0; i < 8; i++) { - tag = tag_word & 3; - tag_word >>= 2; - - if (tag == TAG_Empty) - /* New tag is empty. Accept it */ - FPU_settag(i, TAG_Empty); - else if (FPU_gettag(i) == TAG_Empty) { - /* Old tag is empty and new tag is not empty. New tag is determined - by old reg contents */ - if (exponent(&fpu_register(i)) == -EXTENDED_Ebias) { - if (! - (fpu_register(i).sigl | fpu_register(i). - sigh)) - FPU_settag(i, TAG_Zero); - else - FPU_settag(i, TAG_Special); - } else if (exponent(&fpu_register(i)) == - 0x7fff - EXTENDED_Ebias) { - FPU_settag(i, TAG_Special); - } else if (fpu_register(i).sigh & 0x80000000) - FPU_settag(i, TAG_Valid); - else - FPU_settag(i, TAG_Special); /* An Un-normal */ - } - /* Else old tag is not empty and new tag is not empty. Old tag - remains correct */ - } - - return s; -} - -void FPU_frstor(fpu_addr_modes addr_modes, u_char __user *data_address) -{ - int i, regnr; - u_char __user *s = fldenv(addr_modes, data_address); - int offset = (top & 7) * 10, other = 80 - offset; - - /* Copy all registers in stack order. */ - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(s, 80); - FPU_copy_from_user(register_base + offset, s, other); - if (offset) - FPU_copy_from_user(register_base, s + other, offset); - RE_ENTRANT_CHECK_ON; - - for (i = 0; i < 8; i++) { - regnr = (i + top) & 7; - if (FPU_gettag(regnr) != TAG_Empty) - /* The loaded data over-rides all other cases. */ - FPU_settag(regnr, FPU_tagof(&st(i))); - } - -} - -u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user *d) -{ - if ((addr_modes.default_mode == VM86) || - ((addr_modes.default_mode == PM16) - ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX))) { - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(d, 14); -#ifdef PECULIAR_486 - FPU_put_user(control_word & ~0xe080, (unsigned long __user *)d); -#else - FPU_put_user(control_word, (unsigned short __user *)d); -#endif /* PECULIAR_486 */ - FPU_put_user(status_word(), (unsigned short __user *)(d + 2)); - FPU_put_user(fpu_tag_word, (unsigned short __user *)(d + 4)); - FPU_put_user(instruction_address.offset, - (unsigned short __user *)(d + 6)); - FPU_put_user(operand_address.offset, - (unsigned short __user *)(d + 0x0a)); - if (addr_modes.default_mode == VM86) { - FPU_put_user((instruction_address. - offset & 0xf0000) >> 4, - (unsigned short __user *)(d + 8)); - FPU_put_user((operand_address.offset & 0xf0000) >> 4, - (unsigned short __user *)(d + 0x0c)); - } else { - FPU_put_user(instruction_address.selector, - (unsigned short __user *)(d + 8)); - FPU_put_user(operand_address.selector, - (unsigned short __user *)(d + 0x0c)); - } - RE_ENTRANT_CHECK_ON; - d += 0x0e; - } else { - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(d, 7 * 4); -#ifdef PECULIAR_486 - control_word &= ~0xe080; - /* An 80486 sets nearly all of the reserved bits to 1. */ - control_word |= 0xffff0040; - partial_status = status_word() | 0xffff0000; - fpu_tag_word |= 0xffff0000; - I387->soft.fcs &= ~0xf8000000; - I387->soft.fos |= 0xffff0000; -#endif /* PECULIAR_486 */ - if (__copy_to_user(d, &control_word, 7 * 4)) - FPU_abort; - RE_ENTRANT_CHECK_ON; - d += 0x1c; - } - - control_word |= CW_Exceptions; - partial_status &= ~(SW_Summary | SW_Backward); - - return d; -} - -void fsave(fpu_addr_modes addr_modes, u_char __user *data_address) -{ - u_char __user *d; - int offset = (top & 7) * 10, other = 80 - offset; - - d = fstenv(addr_modes, data_address); - - RE_ENTRANT_CHECK_OFF; - FPU_access_ok(d, 80); - - /* Copy all registers in stack order. */ - if (__copy_to_user(d, register_base + offset, other)) - FPU_abort; - if (offset) - if (__copy_to_user(d + other, register_base, offset)) - FPU_abort; - RE_ENTRANT_CHECK_ON; - - finit(); -} - -/*===========================================================================*/ diff --git a/arch/x86/math-emu/reg_mul.c b/arch/x86/math-emu/reg_mul.c deleted file mode 100644 index d69618572f14..000000000000 --- a/arch/x86/math-emu/reg_mul.c +++ /dev/null @@ -1,116 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/*---------------------------------------------------------------------------+ - | reg_mul.c | - | | - | Multiply one FPU_REG by another, put the result in a destination FPU_REG. | - | | - | Copyright (C) 1992,1993,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@suburbia.net | - | | - | Returns the tag of the result if no exceptions or errors occurred. | - | | - +---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------+ - | The destination may be any FPU_REG, including one of the source FPU_REGs. | - +---------------------------------------------------------------------------*/ - -#include "fpu_emu.h" -#include "exception.h" -#include "reg_constant.h" -#include "fpu_system.h" - -/* - Multiply two registers to give a register result. - The sources are st(deststnr) and (b,tagb,signb). - The destination is st(deststnr). - */ -/* This routine must be called with non-empty source registers */ -int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w) -{ - FPU_REG *a = &st(deststnr); - FPU_REG *dest = a; - u_char taga = FPU_gettagi(deststnr); - u_char saved_sign = getsign(dest); - u_char sign = (getsign(a) ^ getsign(b)); - int tag; - - if (!(taga | tagb)) { - /* Both regs Valid, this should be the most common case. */ - - tag = - FPU_u_mul(a, b, dest, control_w, sign, - exponent(a) + exponent(b)); - if (tag < 0) { - setsign(dest, saved_sign); - return tag; - } - FPU_settagi(deststnr, tag); - return tag; - } - - if (taga == TAG_Special) - taga = FPU_Special(a); - if (tagb == TAG_Special) - tagb = FPU_Special(b); - - if (((taga == TAG_Valid) && (tagb == TW_Denormal)) - || ((taga == TW_Denormal) && (tagb == TAG_Valid)) - || ((taga == TW_Denormal) && (tagb == TW_Denormal))) { - FPU_REG x, y; - if (denormal_operand() < 0) - return FPU_Exception; - - FPU_to_exp16(a, &x); - FPU_to_exp16(b, &y); - tag = FPU_u_mul(&x, &y, dest, control_w, sign, - exponent16(&x) + exponent16(&y)); - if (tag < 0) { - setsign(dest, saved_sign); - return tag; - } - FPU_settagi(deststnr, tag); - return tag; - } else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) { - if (((tagb == TW_Denormal) || (taga == TW_Denormal)) - && (denormal_operand() < 0)) - return FPU_Exception; - - /* Must have either both arguments == zero, or - one valid and the other zero. - The result is therefore zero. */ - FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); - /* The 80486 book says that the answer is +0, but a real - 80486 behaves this way. - IEEE-754 apparently says it should be this way. */ - setsign(dest, sign); - return TAG_Zero; - } - /* Must have infinities, NaNs, etc */ - else if ((taga == TW_NaN) || (tagb == TW_NaN)) { - return real_2op_NaN(b, tagb, deststnr, &st(0)); - } else if (((taga == TW_Infinity) && (tagb == TAG_Zero)) - || ((tagb == TW_Infinity) && (taga == TAG_Zero))) { - return arith_invalid(deststnr); /* Zero*Infinity is invalid */ - } else if (((taga == TW_Denormal) || (tagb == TW_Denormal)) - && (denormal_operand() < 0)) { - return FPU_Exception; - } else if (taga == TW_Infinity) { - FPU_copy_to_regi(a, TAG_Special, deststnr); - setsign(dest, sign); - return TAG_Special; - } else if (tagb == TW_Infinity) { - FPU_copy_to_regi(b, TAG_Special, deststnr); - setsign(dest, sign); - return TAG_Special; - } -#ifdef PARANOID - else { - EXCEPTION(EX_INTERNAL | 0x102); - return FPU_Exception; - } -#endif /* PARANOID */ - - return 0; -} diff --git a/arch/x86/math-emu/reg_norm.S b/arch/x86/math-emu/reg_norm.S deleted file mode 100644 index 594936eeed67..000000000000 --- a/arch/x86/math-emu/reg_norm.S +++ /dev/null @@ -1,150 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/*---------------------------------------------------------------------------+ - | reg_norm.S | - | | - | Copyright (C) 1992,1993,1994,1995,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@suburbia.net | - | | - | Normalize the value in a FPU_REG. | - | | - | Call from C as: | - | int FPU_normalize(FPU_REG *n) | - | | - | int FPU_normalize_nuo(FPU_REG *n) | - | | - | Return value is the tag of the answer, or-ed with FPU_Exception if | - | one was raised, or -1 on internal error. | - | | - +---------------------------------------------------------------------------*/ - -#include "fpu_emu.h" - - -.text -SYM_FUNC_START(FPU_normalize) - pushl %ebp - movl %esp,%ebp - pushl %ebx - - movl PARAM1,%ebx - - movl SIGH(%ebx),%edx - movl SIGL(%ebx),%eax - - orl %edx,%edx /* ms bits */ - js L_done /* Already normalized */ - jnz L_shift_1 /* Shift left 1 - 31 bits */ - - orl %eax,%eax - jz L_zero /* The contents are zero */ - - movl %eax,%edx - xorl %eax,%eax - subw $32,EXP(%ebx) /* This can cause an underflow */ - -/* We need to shift left by 1 - 31 bits */ -L_shift_1: - bsrl %edx,%ecx /* get the required shift in %ecx */ - subl $31,%ecx - negl %ecx - shld %cl,%eax,%edx - shl %cl,%eax - subw %cx,EXP(%ebx) /* This can cause an underflow */ - - movl %edx,SIGH(%ebx) - movl %eax,SIGL(%ebx) - -L_done: - cmpw EXP_OVER,EXP(%ebx) - jge L_overflow - - cmpw EXP_UNDER,EXP(%ebx) - jle L_underflow - -L_exit_valid: - movl TAG_Valid,%eax - - /* Convert the exponent to 80x87 form. */ - addw EXTENDED_Ebias,EXP(%ebx) - andw $0x7fff,EXP(%ebx) - -L_exit: - popl %ebx - leave - RET - - -L_zero: - movw $0,EXP(%ebx) - movl TAG_Zero,%eax - jmp L_exit - -L_underflow: - /* Convert the exponent to 80x87 form. */ - addw EXTENDED_Ebias,EXP(%ebx) - push %ebx - call arith_underflow - pop %ebx - jmp L_exit - -L_overflow: - /* Convert the exponent to 80x87 form. */ - addw EXTENDED_Ebias,EXP(%ebx) - push %ebx - call arith_overflow - pop %ebx - jmp L_exit -SYM_FUNC_END(FPU_normalize) - - - -/* Normalise without reporting underflow or overflow */ -SYM_FUNC_START(FPU_normalize_nuo) - pushl %ebp - movl %esp,%ebp - pushl %ebx - - movl PARAM1,%ebx - - movl SIGH(%ebx),%edx - movl SIGL(%ebx),%eax - - orl %edx,%edx /* ms bits */ - js L_exit_nuo_valid /* Already normalized */ - jnz L_nuo_shift_1 /* Shift left 1 - 31 bits */ - - orl %eax,%eax - jz L_exit_nuo_zero /* The contents are zero */ - - movl %eax,%edx - xorl %eax,%eax - subw $32,EXP(%ebx) /* This can cause an underflow */ - -/* We need to shift left by 1 - 31 bits */ -L_nuo_shift_1: - bsrl %edx,%ecx /* get the required shift in %ecx */ - subl $31,%ecx - negl %ecx - shld %cl,%eax,%edx - shl %cl,%eax - subw %cx,EXP(%ebx) /* This can cause an underflow */ - - movl %edx,SIGH(%ebx) - movl %eax,SIGL(%ebx) - -L_exit_nuo_valid: - movl TAG_Valid,%eax - - popl %ebx - leave - RET - -L_exit_nuo_zero: - movl TAG_Zero,%eax - movw EXP_UNDER,EXP(%ebx) - - popl %ebx - leave - RET -SYM_FUNC_END(FPU_normalize_nuo) diff --git a/arch/x86/math-emu/reg_round.S b/arch/x86/math-emu/reg_round.S deleted file mode 100644 index 0bb2a092161a..000000000000 --- a/arch/x86/math-emu/reg_round.S +++ /dev/null @@ -1,711 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - .file "reg_round.S" -/*---------------------------------------------------------------------------+ - | reg_round.S | - | | - | Rounding/truncation/etc for FPU basic arithmetic functions. | - | | - | Copyright (C) 1993,1995,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@suburbia.net | - | | - | This code has four possible entry points. | - | The following must be entered by a jmp instruction: | - | fpu_reg_round, fpu_reg_round_sqrt, and fpu_Arith_exit. | - | | - | The FPU_round entry point is intended to be used by C code. | - | From C, call as: | - | int FPU_round(FPU_REG *arg, unsigned int extent, unsigned int control_w) | - | | - | Return value is the tag of the answer, or-ed with FPU_Exception if | - | one was raised, or -1 on internal error. | - | | - | For correct "up" and "down" rounding, the argument must have the correct | - | sign. | - | | - +---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------+ - | Four entry points. | - | | - | Needed by both the fpu_reg_round and fpu_reg_round_sqrt entry points: | - | %eax:%ebx 64 bit significand | - | %edx 32 bit extension of the significand | - | %edi pointer to an FPU_REG for the result to be stored | - | stack calling function must have set up a C stack frame and | - | pushed %esi, %edi, and %ebx | - | | - | Needed just for the fpu_reg_round_sqrt entry point: | - | %cx A control word in the same format as the FPU control word. | - | Otherwise, PARAM4 must give such a value. | - | | - | | - | The significand and its extension are assumed to be exact in the | - | following sense: | - | If the significand by itself is the exact result then the significand | - | extension (%edx) must contain 0, otherwise the significand extension | - | must be non-zero. | - | If the significand extension is non-zero then the significand is | - | smaller than the magnitude of the correct exact result by an amount | - | greater than zero and less than one ls bit of the significand. | - | The significand extension is only required to have three possible | - | non-zero values: | - | less than 0x80000000 <=> the significand is less than 1/2 an ls | - | bit smaller than the magnitude of the | - | true exact result. | - | exactly 0x80000000 <=> the significand is exactly 1/2 an ls bit | - | smaller than the magnitude of the true | - | exact result. | - | greater than 0x80000000 <=> the significand is more than 1/2 an ls | - | bit smaller than the magnitude of the | - | true exact result. | - | | - +---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------+ - | The code in this module has become quite complex, but it should handle | - | all of the FPU flags which are set at this stage of the basic arithmetic | - | computations. | - | There are a few rare cases where the results are not set identically to | - | a real FPU. These require a bit more thought because at this stage the | - | results of the code here appear to be more consistent... | - | This may be changed in a future version. | - +---------------------------------------------------------------------------*/ - - -#include "fpu_emu.h" -#include "exception.h" -#include "control_w.h" - -/* Flags for FPU_bits_lost */ -#define LOST_DOWN $1 -#define LOST_UP $2 - -/* Flags for FPU_denormal */ -#define DENORMAL $1 -#define UNMASKED_UNDERFLOW $2 - - -#ifndef NON_REENTRANT_FPU -/* Make the code re-entrant by putting - local storage on the stack: */ -#define FPU_bits_lost (%esp) -#define FPU_denormal 1(%esp) - -#else -/* Not re-entrant, so we can gain speed by putting - local storage in a static area: */ -.data - .align 4,0 -FPU_bits_lost: - .byte 0 -FPU_denormal: - .byte 0 -#endif /* NON_REENTRANT_FPU */ - - -.text -.globl fpu_reg_round -.globl fpu_Arith_exit - -/* Entry point when called from C */ -SYM_FUNC_START(FPU_round) - pushl %ebp - movl %esp,%ebp - pushl %esi - pushl %edi - pushl %ebx - - movl PARAM1,%edi - movl SIGH(%edi),%eax - movl SIGL(%edi),%ebx - movl PARAM2,%edx - -fpu_reg_round: /* Normal entry point */ - movl PARAM4,%ecx - -#ifndef NON_REENTRANT_FPU - pushl %ebx /* adjust the stack pointer */ -#endif /* NON_REENTRANT_FPU */ - -#ifdef PARANOID -/* Cannot use this here yet */ -/* orl %eax,%eax */ -/* jns L_entry_bugged */ -#endif /* PARANOID */ - - cmpw EXP_UNDER,EXP(%edi) - jle L_Make_denorm /* The number is a de-normal */ - - movb $0,FPU_denormal /* 0 -> not a de-normal */ - -Denorm_done: - movb $0,FPU_bits_lost /* No bits yet lost in rounding */ - - movl %ecx,%esi - andl CW_PC,%ecx - cmpl PR_64_BITS,%ecx - je LRound_To_64 - - cmpl PR_53_BITS,%ecx - je LRound_To_53 - - cmpl PR_24_BITS,%ecx - je LRound_To_24 - -#ifdef PECULIAR_486 -/* With the precision control bits set to 01 "(reserved)", a real 80486 - behaves as if the precision control bits were set to 11 "64 bits" */ - cmpl PR_RESERVED_BITS,%ecx - je LRound_To_64 -#ifdef PARANOID - jmp L_bugged_denorm_486 -#endif /* PARANOID */ -#else -#ifdef PARANOID - jmp L_bugged_denorm /* There is no bug, just a bad control word */ -#endif /* PARANOID */ -#endif /* PECULIAR_486 */ - - -/* Round etc to 24 bit precision */ -LRound_To_24: - movl %esi,%ecx - andl CW_RC,%ecx - cmpl RC_RND,%ecx - je LRound_nearest_24 - - cmpl RC_CHOP,%ecx - je LCheck_truncate_24 - - cmpl RC_UP,%ecx /* Towards +infinity */ - je LUp_24 - - cmpl RC_DOWN,%ecx /* Towards -infinity */ - je LDown_24 - -#ifdef PARANOID - jmp L_bugged_round24 -#endif /* PARANOID */ - -LUp_24: - cmpb SIGN_POS,PARAM5 - jne LCheck_truncate_24 /* If negative then up==truncate */ - - jmp LCheck_24_round_up - -LDown_24: - cmpb SIGN_POS,PARAM5 - je LCheck_truncate_24 /* If positive then down==truncate */ - -LCheck_24_round_up: - movl %eax,%ecx - andl $0x000000ff,%ecx - orl %ebx,%ecx - orl %edx,%ecx - jnz LDo_24_round_up - jmp L_Re_normalise - -LRound_nearest_24: - /* Do rounding of the 24th bit if needed (nearest or even) */ - movl %eax,%ecx - andl $0x000000ff,%ecx - cmpl $0x00000080,%ecx - jc LCheck_truncate_24 /* less than half, no increment needed */ - - jne LGreater_Half_24 /* greater than half, increment needed */ - - /* Possibly half, we need to check the ls bits */ - orl %ebx,%ebx - jnz LGreater_Half_24 /* greater than half, increment needed */ - - orl %edx,%edx - jnz LGreater_Half_24 /* greater than half, increment needed */ - - /* Exactly half, increment only if 24th bit is 1 (round to even) */ - testl $0x00000100,%eax - jz LDo_truncate_24 - -LGreater_Half_24: /* Rounding: increment at the 24th bit */ -LDo_24_round_up: - andl $0xffffff00,%eax /* Truncate to 24 bits */ - xorl %ebx,%ebx - movb LOST_UP,FPU_bits_lost - addl $0x00000100,%eax - jmp LCheck_Round_Overflow - -LCheck_truncate_24: - movl %eax,%ecx - andl $0x000000ff,%ecx - orl %ebx,%ecx - orl %edx,%ecx - jz L_Re_normalise /* No truncation needed */ - -LDo_truncate_24: - andl $0xffffff00,%eax /* Truncate to 24 bits */ - xorl %ebx,%ebx - movb LOST_DOWN,FPU_bits_lost - jmp L_Re_normalise - - -/* Round etc to 53 bit precision */ -LRound_To_53: - movl %esi,%ecx - andl CW_RC,%ecx - cmpl RC_RND,%ecx - je LRound_nearest_53 - - cmpl RC_CHOP,%ecx - je LCheck_truncate_53 - - cmpl RC_UP,%ecx /* Towards +infinity */ - je LUp_53 - - cmpl RC_DOWN,%ecx /* Towards -infinity */ - je LDown_53 - -#ifdef PARANOID - jmp L_bugged_round53 -#endif /* PARANOID */ - -LUp_53: - cmpb SIGN_POS,PARAM5 - jne LCheck_truncate_53 /* If negative then up==truncate */ - - jmp LCheck_53_round_up - -LDown_53: - cmpb SIGN_POS,PARAM5 - je LCheck_truncate_53 /* If positive then down==truncate */ - -LCheck_53_round_up: - movl %ebx,%ecx - andl $0x000007ff,%ecx - orl %edx,%ecx - jnz LDo_53_round_up - jmp L_Re_normalise - -LRound_nearest_53: - /* Do rounding of the 53rd bit if needed (nearest or even) */ - movl %ebx,%ecx - andl $0x000007ff,%ecx - cmpl $0x00000400,%ecx - jc LCheck_truncate_53 /* less than half, no increment needed */ - - jnz LGreater_Half_53 /* greater than half, increment needed */ - - /* Possibly half, we need to check the ls bits */ - orl %edx,%edx - jnz LGreater_Half_53 /* greater than half, increment needed */ - - /* Exactly half, increment only if 53rd bit is 1 (round to even) */ - testl $0x00000800,%ebx - jz LTruncate_53 - -LGreater_Half_53: /* Rounding: increment at the 53rd bit */ -LDo_53_round_up: - movb LOST_UP,FPU_bits_lost - andl $0xfffff800,%ebx /* Truncate to 53 bits */ - addl $0x00000800,%ebx - adcl $0,%eax - jmp LCheck_Round_Overflow - -LCheck_truncate_53: - movl %ebx,%ecx - andl $0x000007ff,%ecx - orl %edx,%ecx - jz L_Re_normalise - -LTruncate_53: - movb LOST_DOWN,FPU_bits_lost - andl $0xfffff800,%ebx /* Truncate to 53 bits */ - jmp L_Re_normalise - - -/* Round etc to 64 bit precision */ -LRound_To_64: - movl %esi,%ecx - andl CW_RC,%ecx - cmpl RC_RND,%ecx - je LRound_nearest_64 - - cmpl RC_CHOP,%ecx - je LCheck_truncate_64 - - cmpl RC_UP,%ecx /* Towards +infinity */ - je LUp_64 - - cmpl RC_DOWN,%ecx /* Towards -infinity */ - je LDown_64 - -#ifdef PARANOID - jmp L_bugged_round64 -#endif /* PARANOID */ - -LUp_64: - cmpb SIGN_POS,PARAM5 - jne LCheck_truncate_64 /* If negative then up==truncate */ - - orl %edx,%edx - jnz LDo_64_round_up - jmp L_Re_normalise - -LDown_64: - cmpb SIGN_POS,PARAM5 - je LCheck_truncate_64 /* If positive then down==truncate */ - - orl %edx,%edx - jnz LDo_64_round_up - jmp L_Re_normalise - -LRound_nearest_64: - cmpl $0x80000000,%edx - jc LCheck_truncate_64 - - jne LDo_64_round_up - - /* Now test for round-to-even */ - testb $1,%bl - jz LCheck_truncate_64 - -LDo_64_round_up: - movb LOST_UP,FPU_bits_lost - addl $1,%ebx - adcl $0,%eax - -LCheck_Round_Overflow: - jnc L_Re_normalise - - /* Overflow, adjust the result (significand to 1.0) */ - rcrl $1,%eax - rcrl $1,%ebx - incw EXP(%edi) - jmp L_Re_normalise - -LCheck_truncate_64: - orl %edx,%edx - jz L_Re_normalise - -LTruncate_64: - movb LOST_DOWN,FPU_bits_lost - -L_Re_normalise: - testb $0xff,FPU_denormal - jnz Normalise_result - -L_Normalised: - movl TAG_Valid,%edx - -L_deNormalised: - cmpb LOST_UP,FPU_bits_lost - je L_precision_lost_up - - cmpb LOST_DOWN,FPU_bits_lost - je L_precision_lost_down - -L_no_precision_loss: - /* store the result */ - -L_Store_significand: - movl %eax,SIGH(%edi) - movl %ebx,SIGL(%edi) - - cmpw EXP_OVER,EXP(%edi) - jge L_overflow - - movl %edx,%eax - - /* Convert the exponent to 80x87 form. */ - addw EXTENDED_Ebias,EXP(%edi) - andw $0x7fff,EXP(%edi) - -fpu_reg_round_signed_special_exit: - - cmpb SIGN_POS,PARAM5 - je fpu_reg_round_special_exit - - orw $0x8000,EXP(%edi) /* Negative sign for the result. */ - -fpu_reg_round_special_exit: - -#ifndef NON_REENTRANT_FPU - popl %ebx /* adjust the stack pointer */ -#endif /* NON_REENTRANT_FPU */ - -fpu_Arith_exit: - popl %ebx - popl %edi - popl %esi - leave - RET - - -/* - * Set the FPU status flags to represent precision loss due to - * round-up. - */ -L_precision_lost_up: - push %edx - push %eax - call set_precision_flag_up - popl %eax - popl %edx - jmp L_no_precision_loss - -/* - * Set the FPU status flags to represent precision loss due to - * truncation. - */ -L_precision_lost_down: - push %edx - push %eax - call set_precision_flag_down - popl %eax - popl %edx - jmp L_no_precision_loss - - -/* - * The number is a denormal (which might get rounded up to a normal) - * Shift the number right the required number of bits, which will - * have to be undone later... - */ -L_Make_denorm: - /* The action to be taken depends upon whether the underflow - exception is masked */ - testb CW_Underflow,%cl /* Underflow mask. */ - jz Unmasked_underflow /* Do not make a denormal. */ - - movb DENORMAL,FPU_denormal - - pushl %ecx /* Save */ - movw EXP_UNDER+1,%cx - subw EXP(%edi),%cx - - cmpw $64,%cx /* shrd only works for 0..31 bits */ - jnc Denorm_shift_more_than_63 - - cmpw $32,%cx /* shrd only works for 0..31 bits */ - jnc Denorm_shift_more_than_32 - -/* - * We got here without jumps by assuming that the most common requirement - * is for a small de-normalising shift. - * Shift by [1..31] bits - */ - addw %cx,EXP(%edi) - orl %edx,%edx /* extension */ - setne %ch /* Save whether %edx is non-zero */ - xorl %edx,%edx - shrd %cl,%ebx,%edx - shrd %cl,%eax,%ebx - shr %cl,%eax - orb %ch,%dl - popl %ecx - jmp Denorm_done - -/* Shift by [32..63] bits */ -Denorm_shift_more_than_32: - addw %cx,EXP(%edi) - subb $32,%cl - orl %edx,%edx - setne %ch - orb %ch,%bl - xorl %edx,%edx - shrd %cl,%ebx,%edx - shrd %cl,%eax,%ebx - shr %cl,%eax - orl %edx,%edx /* test these 32 bits */ - setne %cl - orb %ch,%bl - orb %cl,%bl - movl %ebx,%edx - movl %eax,%ebx - xorl %eax,%eax - popl %ecx - jmp Denorm_done - -/* Shift by [64..) bits */ -Denorm_shift_more_than_63: - cmpw $64,%cx - jne Denorm_shift_more_than_64 - -/* Exactly 64 bit shift */ - addw %cx,EXP(%edi) - xorl %ecx,%ecx - orl %edx,%edx - setne %cl - orl %ebx,%ebx - setne %ch - orb %ch,%cl - orb %cl,%al - movl %eax,%edx - xorl %eax,%eax - xorl %ebx,%ebx - popl %ecx - jmp Denorm_done - -Denorm_shift_more_than_64: - movw EXP_UNDER+1,EXP(%edi) -/* This is easy, %eax must be non-zero, so.. */ - movl $1,%edx - xorl %eax,%eax - xorl %ebx,%ebx - popl %ecx - jmp Denorm_done - - -Unmasked_underflow: - movb UNMASKED_UNDERFLOW,FPU_denormal - jmp Denorm_done - - -/* Undo the de-normalisation. */ -Normalise_result: - cmpb UNMASKED_UNDERFLOW,FPU_denormal - je Signal_underflow - -/* The number must be a denormal if we got here. */ -#ifdef PARANOID - /* But check it... just in case. */ - cmpw EXP_UNDER+1,EXP(%edi) - jne L_norm_bugged -#endif /* PARANOID */ - -#ifdef PECULIAR_486 - /* - * This implements a special feature of 80486 behaviour. - * Underflow will be signaled even if the number is - * not a denormal after rounding. - * This difference occurs only for masked underflow, and not - * in the unmasked case. - * Actual 80486 behaviour differs from this in some circumstances. - */ - orl %eax,%eax /* ms bits */ - js LPseudoDenormal /* Will be masked underflow */ -#else - orl %eax,%eax /* ms bits */ - js L_Normalised /* No longer a denormal */ -#endif /* PECULIAR_486 */ - - jnz LDenormal_adj_exponent - - orl %ebx,%ebx - jz L_underflow_to_zero /* The contents are zero */ - -LDenormal_adj_exponent: - decw EXP(%edi) - -LPseudoDenormal: - testb $0xff,FPU_bits_lost /* bits lost == underflow */ - movl TAG_Special,%edx - jz L_deNormalised - - /* There must be a masked underflow */ - push %eax - pushl EX_Underflow - call EXCEPTION - popl %eax - popl %eax - movl TAG_Special,%edx - jmp L_deNormalised - - -/* - * The operations resulted in a number too small to represent. - * Masked response. - */ -L_underflow_to_zero: - push %eax - call set_precision_flag_down - popl %eax - - push %eax - pushl EX_Underflow - call EXCEPTION - popl %eax - popl %eax - -/* Reduce the exponent to EXP_UNDER */ - movw EXP_UNDER,EXP(%edi) - movl TAG_Zero,%edx - jmp L_Store_significand - - -/* The operations resulted in a number too large to represent. */ -L_overflow: - addw EXTENDED_Ebias,EXP(%edi) /* Set for unmasked response. */ - push %edi - call arith_overflow - pop %edi - jmp fpu_reg_round_signed_special_exit - - -Signal_underflow: - /* The number may have been changed to a non-denormal */ - /* by the rounding operations. */ - cmpw EXP_UNDER,EXP(%edi) - jle Do_unmasked_underflow - - jmp L_Normalised - -Do_unmasked_underflow: - /* Increase the exponent by the magic number */ - addw $(3*(1<<13)),EXP(%edi) - push %eax - pushl EX_Underflow - call EXCEPTION - popl %eax - popl %eax - jmp L_Normalised - - -#ifdef PARANOID -#ifdef PECULIAR_486 -L_bugged_denorm_486: - pushl EX_INTERNAL|0x236 - call EXCEPTION - popl %ebx - jmp L_exception_exit -#else -L_bugged_denorm: - pushl EX_INTERNAL|0x230 - call EXCEPTION - popl %ebx - jmp L_exception_exit -#endif /* PECULIAR_486 */ - -L_bugged_round24: - pushl EX_INTERNAL|0x231 - call EXCEPTION - popl %ebx - jmp L_exception_exit - -L_bugged_round53: - pushl EX_INTERNAL|0x232 - call EXCEPTION - popl %ebx - jmp L_exception_exit - -L_bugged_round64: - pushl EX_INTERNAL|0x233 - call EXCEPTION - popl %ebx - jmp L_exception_exit - -L_norm_bugged: - pushl EX_INTERNAL|0x234 - call EXCEPTION - popl %ebx - jmp L_exception_exit - -L_entry_bugged: - pushl EX_INTERNAL|0x235 - call EXCEPTION - popl %ebx -L_exception_exit: - mov $-1,%eax - jmp fpu_reg_round_special_exit -#endif /* PARANOID */ - -SYM_FUNC_END(FPU_round) diff --git a/arch/x86/math-emu/reg_u_add.S b/arch/x86/math-emu/reg_u_add.S deleted file mode 100644 index 07247287a3af..000000000000 --- a/arch/x86/math-emu/reg_u_add.S +++ /dev/null @@ -1,169 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - .file "reg_u_add.S" -/*---------------------------------------------------------------------------+ - | reg_u_add.S | - | | - | Add two valid (TAG_Valid) FPU_REG numbers, of the same sign, and put the | - | result in a destination FPU_REG. | - | | - | Copyright (C) 1992,1993,1995,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@suburbia.net | - | | - | Call from C as: | - | int FPU_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, | - | int control_w) | - | Return value is the tag of the answer, or-ed with FPU_Exception if | - | one was raised, or -1 on internal error. | - | | - +---------------------------------------------------------------------------*/ - -/* - | Kernel addition routine FPU_u_add(reg *arg1, reg *arg2, reg *answ). - | Takes two valid reg f.p. numbers (TAG_Valid), which are - | treated as unsigned numbers, - | and returns their sum as a TAG_Valid or TAG_Special f.p. number. - | The returned number is normalized. - | Basic checks are performed if PARANOID is defined. - */ - -#include "exception.h" -#include "fpu_emu.h" -#include "control_w.h" - -.text -SYM_FUNC_START(FPU_u_add) - pushl %ebp - movl %esp,%ebp - pushl %esi - pushl %edi - pushl %ebx - - movl PARAM1,%esi /* source 1 */ - movl PARAM2,%edi /* source 2 */ - - movl PARAM6,%ecx - movl %ecx,%edx - subl PARAM7,%ecx /* exp1 - exp2 */ - jge L_arg1_larger - - /* num1 is smaller */ - movl SIGL(%esi),%ebx - movl SIGH(%esi),%eax - - movl %edi,%esi - movl PARAM7,%edx - negw %cx - jmp L_accum_loaded - -L_arg1_larger: - /* num1 has larger or equal exponent */ - movl SIGL(%edi),%ebx - movl SIGH(%edi),%eax - -L_accum_loaded: - movl PARAM3,%edi /* destination */ - movw %dx,EXP(%edi) /* Copy exponent to destination */ - - xorl %edx,%edx /* clear the extension */ - -#ifdef PARANOID - testl $0x80000000,%eax - je L_bugged - - testl $0x80000000,SIGH(%esi) - je L_bugged -#endif /* PARANOID */ - -/* The number to be shifted is in %eax:%ebx:%edx */ - cmpw $32,%cx /* shrd only works for 0..31 bits */ - jnc L_more_than_31 - -/* less than 32 bits */ - shrd %cl,%ebx,%edx - shrd %cl,%eax,%ebx - shr %cl,%eax - jmp L_shift_done - -L_more_than_31: - cmpw $64,%cx - jnc L_more_than_63 - - subb $32,%cl - jz L_exactly_32 - - shrd %cl,%eax,%edx - shr %cl,%eax - orl %ebx,%ebx - jz L_more_31_no_low /* none of the lowest bits is set */ - - orl $1,%edx /* record the fact in the extension */ - -L_more_31_no_low: - movl %eax,%ebx - xorl %eax,%eax - jmp L_shift_done - -L_exactly_32: - movl %ebx,%edx - movl %eax,%ebx - xorl %eax,%eax - jmp L_shift_done - -L_more_than_63: - cmpw $65,%cx - jnc L_more_than_64 - - movl %eax,%edx - orl %ebx,%ebx - jz L_more_63_no_low - - orl $1,%edx - jmp L_more_63_no_low - -L_more_than_64: - movl $1,%edx /* The shifted nr always at least one '1' */ - -L_more_63_no_low: - xorl %ebx,%ebx - xorl %eax,%eax - -L_shift_done: - /* Now do the addition */ - addl SIGL(%esi),%ebx - adcl SIGH(%esi),%eax - jnc L_round_the_result - - /* Overflow, adjust the result */ - rcrl $1,%eax - rcrl $1,%ebx - rcrl $1,%edx - jnc L_no_bit_lost - - orl $1,%edx - -L_no_bit_lost: - incw EXP(%edi) - -L_round_the_result: - jmp fpu_reg_round /* Round the result */ - - - -#ifdef PARANOID -/* If we ever get here then we have problems! */ -L_bugged: - pushl EX_INTERNAL|0x201 - call EXCEPTION - pop %ebx - movl $-1,%eax - jmp L_exit - -L_exit: - popl %ebx - popl %edi - popl %esi - leave - RET -#endif /* PARANOID */ -SYM_FUNC_END(FPU_u_add) diff --git a/arch/x86/math-emu/reg_u_div.S b/arch/x86/math-emu/reg_u_div.S deleted file mode 100644 index b5a41e2fc484..000000000000 --- a/arch/x86/math-emu/reg_u_div.S +++ /dev/null @@ -1,474 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - .file "reg_u_div.S" -/*---------------------------------------------------------------------------+ - | reg_u_div.S | - | | - | Divide one FPU_REG by another and put the result in a destination FPU_REG.| - | | - | Copyright (C) 1992,1993,1995,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@suburbia.net | - | | - | | - +---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------+ - | Call from C as: | - | int FPU_u_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest, | - | unsigned int control_word, char *sign) | - | | - | Does not compute the destination exponent, but does adjust it. | - | | - | Return value is the tag of the answer, or-ed with FPU_Exception if | - | one was raised, or -1 on internal error. | - +---------------------------------------------------------------------------*/ - -#include "exception.h" -#include "fpu_emu.h" -#include "control_w.h" - - -/* #define dSIGL(x) (x) */ -/* #define dSIGH(x) 4(x) */ - - -#ifndef NON_REENTRANT_FPU -/* - Local storage on the stack: - Result: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0 - Overflow flag: ovfl_flag - */ -#define FPU_accum_3 -4(%ebp) -#define FPU_accum_2 -8(%ebp) -#define FPU_accum_1 -12(%ebp) -#define FPU_accum_0 -16(%ebp) -#define FPU_result_1 -20(%ebp) -#define FPU_result_2 -24(%ebp) -#define FPU_ovfl_flag -28(%ebp) - -#else -.data -/* - Local storage in a static area: - Result: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0 - Overflow flag: ovfl_flag - */ - .align 4,0 -FPU_accum_3: - .long 0 -FPU_accum_2: - .long 0 -FPU_accum_1: - .long 0 -FPU_accum_0: - .long 0 -FPU_result_1: - .long 0 -FPU_result_2: - .long 0 -FPU_ovfl_flag: - .byte 0 -#endif /* NON_REENTRANT_FPU */ - -#define REGA PARAM1 -#define REGB PARAM2 -#define DEST PARAM3 - -.text -SYM_FUNC_START(FPU_u_div) - pushl %ebp - movl %esp,%ebp -#ifndef NON_REENTRANT_FPU - subl $28,%esp -#endif /* NON_REENTRANT_FPU */ - - pushl %esi - pushl %edi - pushl %ebx - - movl REGA,%esi - movl REGB,%ebx - movl DEST,%edi - - movswl EXP(%esi),%edx - movswl EXP(%ebx),%eax - subl %eax,%edx - addl EXP_BIAS,%edx - - /* A denormal and a large number can cause an exponent underflow */ - cmpl EXP_WAY_UNDER,%edx - jg xExp_not_underflow - - /* Set to a really low value allow correct handling */ - movl EXP_WAY_UNDER,%edx - -xExp_not_underflow: - - movw %dx,EXP(%edi) - -#ifdef PARANOID -/* testl $0x80000000, SIGH(%esi) // Dividend */ -/* je L_bugged */ - testl $0x80000000, SIGH(%ebx) /* Divisor */ - je L_bugged -#endif /* PARANOID */ - -/* Check if the divisor can be treated as having just 32 bits */ - cmpl $0,SIGL(%ebx) - jnz L_Full_Division /* Can't do a quick divide */ - -/* We should be able to zip through the division here */ - movl SIGH(%ebx),%ecx /* The divisor */ - movl SIGH(%esi),%edx /* Dividend */ - movl SIGL(%esi),%eax /* Dividend */ - - cmpl %ecx,%edx - setaeb FPU_ovfl_flag /* Keep a record */ - jb L_no_adjust - - subl %ecx,%edx /* Prevent the overflow */ - -L_no_adjust: - /* Divide the 64 bit number by the 32 bit denominator */ - divl %ecx - movl %eax,FPU_result_2 - - /* Work on the remainder of the first division */ - xorl %eax,%eax - divl %ecx - movl %eax,FPU_result_1 - - /* Work on the remainder of the 64 bit division */ - xorl %eax,%eax - divl %ecx - - testb $255,FPU_ovfl_flag /* was the num > denom ? */ - je L_no_overflow - - /* Do the shifting here */ - /* increase the exponent */ - incw EXP(%edi) - - /* shift the mantissa right one bit */ - stc /* To set the ms bit */ - rcrl FPU_result_2 - rcrl FPU_result_1 - rcrl %eax - -L_no_overflow: - jmp LRound_precision /* Do the rounding as required */ - - -/*---------------------------------------------------------------------------+ - | Divide: Return arg1/arg2 to arg3. | - | | - | This routine does not use the exponents of arg1 and arg2, but does | - | adjust the exponent of arg3. | - | | - | The maximum returned value is (ignoring exponents) | - | .ffffffff ffffffff | - | ------------------ = 1.ffffffff fffffffe | - | .80000000 00000000 | - | and the minimum is | - | .80000000 00000000 | - | ------------------ = .80000000 00000001 (rounded) | - | .ffffffff ffffffff | - | | - +---------------------------------------------------------------------------*/ - - -L_Full_Division: - /* Save extended dividend in local register */ - movl SIGL(%esi),%eax - movl %eax,FPU_accum_2 - movl SIGH(%esi),%eax - movl %eax,FPU_accum_3 - xorl %eax,%eax - movl %eax,FPU_accum_1 /* zero the extension */ - movl %eax,FPU_accum_0 /* zero the extension */ - - movl SIGL(%esi),%eax /* Get the current num */ - movl SIGH(%esi),%edx - -/*----------------------------------------------------------------------*/ -/* Initialization done. - Do the first 32 bits. */ - - movb $0,FPU_ovfl_flag - cmpl SIGH(%ebx),%edx /* Test for imminent overflow */ - jb LLess_than_1 - ja LGreater_than_1 - - cmpl SIGL(%ebx),%eax - jb LLess_than_1 - -LGreater_than_1: -/* The dividend is greater or equal, would cause overflow */ - setaeb FPU_ovfl_flag /* Keep a record */ - - subl SIGL(%ebx),%eax - sbbl SIGH(%ebx),%edx /* Prevent the overflow */ - movl %eax,FPU_accum_2 - movl %edx,FPU_accum_3 - -LLess_than_1: -/* At this point, we have a dividend < divisor, with a record of - adjustment in FPU_ovfl_flag */ - - /* We will divide by a number which is too large */ - movl SIGH(%ebx),%ecx - addl $1,%ecx - jnc LFirst_div_not_1 - - /* here we need to divide by 100000000h, - i.e., no division at all.. */ - mov %edx,%eax - jmp LFirst_div_done - -LFirst_div_not_1: - divl %ecx /* Divide the numerator by the augmented - denom ms dw */ - -LFirst_div_done: - movl %eax,FPU_result_2 /* Put the result in the answer */ - - mull SIGH(%ebx) /* mul by the ms dw of the denom */ - - subl %eax,FPU_accum_2 /* Subtract from the num local reg */ - sbbl %edx,FPU_accum_3 - - movl FPU_result_2,%eax /* Get the result back */ - mull SIGL(%ebx) /* now mul the ls dw of the denom */ - - subl %eax,FPU_accum_1 /* Subtract from the num local reg */ - sbbl %edx,FPU_accum_2 - sbbl $0,FPU_accum_3 - je LDo_2nd_32_bits /* Must check for non-zero result here */ - -#ifdef PARANOID - jb L_bugged_1 -#endif /* PARANOID */ - - /* need to subtract another once of the denom */ - incl FPU_result_2 /* Correct the answer */ - - movl SIGL(%ebx),%eax - movl SIGH(%ebx),%edx - subl %eax,FPU_accum_1 /* Subtract from the num local reg */ - sbbl %edx,FPU_accum_2 - -#ifdef PARANOID - sbbl $0,FPU_accum_3 - jne L_bugged_1 /* Must check for non-zero result here */ -#endif /* PARANOID */ - -/*----------------------------------------------------------------------*/ -/* Half of the main problem is done, there is just a reduced numerator - to handle now. - Work with the second 32 bits, FPU_accum_0 not used from now on */ -LDo_2nd_32_bits: - movl FPU_accum_2,%edx /* get the reduced num */ - movl FPU_accum_1,%eax - - /* need to check for possible subsequent overflow */ - cmpl SIGH(%ebx),%edx - jb LDo_2nd_div - ja LPrevent_2nd_overflow - - cmpl SIGL(%ebx),%eax - jb LDo_2nd_div - -LPrevent_2nd_overflow: -/* The numerator is greater or equal, would cause overflow */ - /* prevent overflow */ - subl SIGL(%ebx),%eax - sbbl SIGH(%ebx),%edx - movl %edx,FPU_accum_2 - movl %eax,FPU_accum_1 - - incl FPU_result_2 /* Reflect the subtraction in the answer */ - -#ifdef PARANOID - je L_bugged_2 /* Can't bump the result to 1.0 */ -#endif /* PARANOID */ - -LDo_2nd_div: - cmpl $0,%ecx /* augmented denom msw */ - jnz LSecond_div_not_1 - - /* %ecx == 0, we are dividing by 1.0 */ - mov %edx,%eax - jmp LSecond_div_done - -LSecond_div_not_1: - divl %ecx /* Divide the numerator by the denom ms dw */ - -LSecond_div_done: - movl %eax,FPU_result_1 /* Put the result in the answer */ - - mull SIGH(%ebx) /* mul by the ms dw of the denom */ - - subl %eax,FPU_accum_1 /* Subtract from the num local reg */ - sbbl %edx,FPU_accum_2 - -#ifdef PARANOID - jc L_bugged_2 -#endif /* PARANOID */ - - movl FPU_result_1,%eax /* Get the result back */ - mull SIGL(%ebx) /* now mul the ls dw of the denom */ - - subl %eax,FPU_accum_0 /* Subtract from the num local reg */ - sbbl %edx,FPU_accum_1 /* Subtract from the num local reg */ - sbbl $0,FPU_accum_2 - -#ifdef PARANOID - jc L_bugged_2 -#endif /* PARANOID */ - - jz LDo_3rd_32_bits - -#ifdef PARANOID - cmpl $1,FPU_accum_2 - jne L_bugged_2 -#endif /* PARANOID */ - - /* need to subtract another once of the denom */ - movl SIGL(%ebx),%eax - movl SIGH(%ebx),%edx - subl %eax,FPU_accum_0 /* Subtract from the num local reg */ - sbbl %edx,FPU_accum_1 - sbbl $0,FPU_accum_2 - -#ifdef PARANOID - jc L_bugged_2 - jne L_bugged_2 -#endif /* PARANOID */ - - addl $1,FPU_result_1 /* Correct the answer */ - adcl $0,FPU_result_2 - -#ifdef PARANOID - jc L_bugged_2 /* Must check for non-zero result here */ -#endif /* PARANOID */ - -/*----------------------------------------------------------------------*/ -/* The division is essentially finished here, we just need to perform - tidying operations. - Deal with the 3rd 32 bits */ -LDo_3rd_32_bits: - movl FPU_accum_1,%edx /* get the reduced num */ - movl FPU_accum_0,%eax - - /* need to check for possible subsequent overflow */ - cmpl SIGH(%ebx),%edx /* denom */ - jb LRound_prep - ja LPrevent_3rd_overflow - - cmpl SIGL(%ebx),%eax /* denom */ - jb LRound_prep - -LPrevent_3rd_overflow: - /* prevent overflow */ - subl SIGL(%ebx),%eax - sbbl SIGH(%ebx),%edx - movl %edx,FPU_accum_1 - movl %eax,FPU_accum_0 - - addl $1,FPU_result_1 /* Reflect the subtraction in the answer */ - adcl $0,FPU_result_2 - jne LRound_prep - jnc LRound_prep - - /* This is a tricky spot, there is an overflow of the answer */ - movb $255,FPU_ovfl_flag /* Overflow -> 1.000 */ - -LRound_prep: -/* - * Prepare for rounding. - * To test for rounding, we just need to compare 2*accum with the - * denom. - */ - movl FPU_accum_0,%ecx - movl FPU_accum_1,%edx - movl %ecx,%eax - orl %edx,%eax - jz LRound_ovfl /* The accumulator contains zero. */ - - /* Multiply by 2 */ - clc - rcll $1,%ecx - rcll $1,%edx - jc LRound_large /* No need to compare, denom smaller */ - - subl SIGL(%ebx),%ecx - sbbl SIGH(%ebx),%edx - jnc LRound_not_small - - movl $0x70000000,%eax /* Denom was larger */ - jmp LRound_ovfl - -LRound_not_small: - jnz LRound_large - - movl $0x80000000,%eax /* Remainder was exactly 1/2 denom */ - jmp LRound_ovfl - -LRound_large: - movl $0xff000000,%eax /* Denom was smaller */ - -LRound_ovfl: -/* We are now ready to deal with rounding, but first we must get - the bits properly aligned */ - testb $255,FPU_ovfl_flag /* was the num > denom ? */ - je LRound_precision - - incw EXP(%edi) - - /* shift the mantissa right one bit */ - stc /* Will set the ms bit */ - rcrl FPU_result_2 - rcrl FPU_result_1 - rcrl %eax - -/* Round the result as required */ -LRound_precision: - decw EXP(%edi) /* binary point between 1st & 2nd bits */ - - movl %eax,%edx - movl FPU_result_1,%ebx - movl FPU_result_2,%eax - jmp fpu_reg_round - - -#ifdef PARANOID -/* The logic is wrong if we got here */ -L_bugged: - pushl EX_INTERNAL|0x202 - call EXCEPTION - pop %ebx - jmp L_exit - -L_bugged_1: - pushl EX_INTERNAL|0x203 - call EXCEPTION - pop %ebx - jmp L_exit - -L_bugged_2: - pushl EX_INTERNAL|0x204 - call EXCEPTION - pop %ebx - jmp L_exit - -L_exit: - movl $-1,%eax - popl %ebx - popl %edi - popl %esi - - leave - RET -#endif /* PARANOID */ - -SYM_FUNC_END(FPU_u_div) diff --git a/arch/x86/math-emu/reg_u_mul.S b/arch/x86/math-emu/reg_u_mul.S deleted file mode 100644 index e2588b24b8c2..000000000000 --- a/arch/x86/math-emu/reg_u_mul.S +++ /dev/null @@ -1,150 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - .file "reg_u_mul.S" -/*---------------------------------------------------------------------------+ - | reg_u_mul.S | - | | - | Core multiplication routine | - | | - | Copyright (C) 1992,1993,1995,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@suburbia.net | - | | - | | - +---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------+ - | Basic multiplication routine. | - | Does not check the resulting exponent for overflow/underflow | - | | - | FPU_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw); | - | | - | Internal working is at approx 128 bits. | - | Result is rounded to nearest 53 or 64 bits, using "nearest or even". | - +---------------------------------------------------------------------------*/ - -#include "exception.h" -#include "fpu_emu.h" -#include "control_w.h" - - - -#ifndef NON_REENTRANT_FPU -/* Local storage on the stack: */ -#define FPU_accum_0 -4(%ebp) /* ms word */ -#define FPU_accum_1 -8(%ebp) - -#else -/* Local storage in a static area: */ -.data - .align 4,0 -FPU_accum_0: - .long 0 -FPU_accum_1: - .long 0 -#endif /* NON_REENTRANT_FPU */ - - -.text -SYM_FUNC_START(FPU_u_mul) - pushl %ebp - movl %esp,%ebp -#ifndef NON_REENTRANT_FPU - subl $8,%esp -#endif /* NON_REENTRANT_FPU */ - - pushl %esi - pushl %edi - pushl %ebx - - movl PARAM1,%esi - movl PARAM2,%edi - -#ifdef PARANOID - testl $0x80000000,SIGH(%esi) - jz L_bugged - testl $0x80000000,SIGH(%edi) - jz L_bugged -#endif /* PARANOID */ - - xorl %ecx,%ecx - xorl %ebx,%ebx - - movl SIGL(%esi),%eax - mull SIGL(%edi) - movl %eax,FPU_accum_0 - movl %edx,FPU_accum_1 - - movl SIGL(%esi),%eax - mull SIGH(%edi) - addl %eax,FPU_accum_1 - adcl %edx,%ebx -/* adcl $0,%ecx // overflow here is not possible */ - - movl SIGH(%esi),%eax - mull SIGL(%edi) - addl %eax,FPU_accum_1 - adcl %edx,%ebx - adcl $0,%ecx - - movl SIGH(%esi),%eax - mull SIGH(%edi) - addl %eax,%ebx - adcl %edx,%ecx - - /* Get the sum of the exponents. */ - movl PARAM6,%eax - subl EXP_BIAS-1,%eax - - /* Two denormals can cause an exponent underflow */ - cmpl EXP_WAY_UNDER,%eax - jg Exp_not_underflow - - /* Set to a really low value allow correct handling */ - movl EXP_WAY_UNDER,%eax - -Exp_not_underflow: - -/* Have now finished with the sources */ - movl PARAM3,%edi /* Point to the destination */ - movw %ax,EXP(%edi) - -/* Now make sure that the result is normalized */ - testl $0x80000000,%ecx - jnz LResult_Normalised - - /* Normalize by shifting left one bit */ - shll $1,FPU_accum_0 - rcll $1,FPU_accum_1 - rcll $1,%ebx - rcll $1,%ecx - decw EXP(%edi) - -LResult_Normalised: - movl FPU_accum_0,%eax - movl FPU_accum_1,%edx - orl %eax,%eax - jz L_extent_zero - - orl $1,%edx - -L_extent_zero: - movl %ecx,%eax - jmp fpu_reg_round - - -#ifdef PARANOID -L_bugged: - pushl EX_INTERNAL|0x205 - call EXCEPTION - pop %ebx - jmp L_exit - -L_exit: - popl %ebx - popl %edi - popl %esi - leave - RET -#endif /* PARANOID */ - -SYM_FUNC_END(FPU_u_mul) diff --git a/arch/x86/math-emu/reg_u_sub.S b/arch/x86/math-emu/reg_u_sub.S deleted file mode 100644 index 4c900c29e4ff..000000000000 --- a/arch/x86/math-emu/reg_u_sub.S +++ /dev/null @@ -1,274 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - .file "reg_u_sub.S" -/*---------------------------------------------------------------------------+ - | reg_u_sub.S | - | | - | Core floating point subtraction routine. | - | | - | Copyright (C) 1992,1993,1995,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@suburbia.net | - | | - | Call from C as: | - | int FPU_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, | - | int control_w) | - | Return value is the tag of the answer, or-ed with FPU_Exception if | - | one was raised, or -1 on internal error. | - | | - +---------------------------------------------------------------------------*/ - -/* - | Kernel subtraction routine FPU_u_sub(reg *arg1, reg *arg2, reg *answ). - | Takes two valid reg f.p. numbers (TAG_Valid), which are - | treated as unsigned numbers, - | and returns their difference as a TAG_Valid or TAG_Zero f.p. - | number. - | The first number (arg1) must be the larger. - | The returned number is normalized. - | Basic checks are performed if PARANOID is defined. - */ - -#include "exception.h" -#include "fpu_emu.h" -#include "control_w.h" - -.text -SYM_FUNC_START(FPU_u_sub) - pushl %ebp - movl %esp,%ebp - pushl %esi - pushl %edi - pushl %ebx - - movl PARAM1,%esi /* source 1 */ - movl PARAM2,%edi /* source 2 */ - - movl PARAM6,%ecx - subl PARAM7,%ecx /* exp1 - exp2 */ - -#ifdef PARANOID - /* source 2 is always smaller than source 1 */ - js L_bugged_1 - - testl $0x80000000,SIGH(%edi) /* The args are assumed to be be normalized */ - je L_bugged_2 - - testl $0x80000000,SIGH(%esi) - je L_bugged_2 -#endif /* PARANOID */ - -/*--------------------------------------+ - | Form a register holding the | - | smaller number | - +--------------------------------------*/ - movl SIGH(%edi),%eax /* register ms word */ - movl SIGL(%edi),%ebx /* register ls word */ - - movl PARAM3,%edi /* destination */ - movl PARAM6,%edx - movw %dx,EXP(%edi) /* Copy exponent to destination */ - - xorl %edx,%edx /* register extension */ - -/*--------------------------------------+ - | Shift the temporary register | - | right the required number of | - | places. | - +--------------------------------------*/ - - cmpw $32,%cx /* shrd only works for 0..31 bits */ - jnc L_more_than_31 - -/* less than 32 bits */ - shrd %cl,%ebx,%edx - shrd %cl,%eax,%ebx - shr %cl,%eax - jmp L_shift_done - -L_more_than_31: - cmpw $64,%cx - jnc L_more_than_63 - - subb $32,%cl - jz L_exactly_32 - - shrd %cl,%eax,%edx - shr %cl,%eax - orl %ebx,%ebx - jz L_more_31_no_low /* none of the lowest bits is set */ - - orl $1,%edx /* record the fact in the extension */ - -L_more_31_no_low: - movl %eax,%ebx - xorl %eax,%eax - jmp L_shift_done - -L_exactly_32: - movl %ebx,%edx - movl %eax,%ebx - xorl %eax,%eax - jmp L_shift_done - -L_more_than_63: - cmpw $65,%cx - jnc L_more_than_64 - - /* Shift right by 64 bits */ - movl %eax,%edx - orl %ebx,%ebx - jz L_more_63_no_low - - orl $1,%edx - jmp L_more_63_no_low - -L_more_than_64: - jne L_more_than_65 - - /* Shift right by 65 bits */ - /* Carry is clear if we get here */ - movl %eax,%edx - rcrl %edx - jnc L_shift_65_nc - - orl $1,%edx - jmp L_more_63_no_low - -L_shift_65_nc: - orl %ebx,%ebx - jz L_more_63_no_low - - orl $1,%edx - jmp L_more_63_no_low - -L_more_than_65: - movl $1,%edx /* The shifted nr always at least one '1' */ - -L_more_63_no_low: - xorl %ebx,%ebx - xorl %eax,%eax - -L_shift_done: -L_subtr: -/*------------------------------+ - | Do the subtraction | - +------------------------------*/ - xorl %ecx,%ecx - subl %edx,%ecx - movl %ecx,%edx - movl SIGL(%esi),%ecx - sbbl %ebx,%ecx - movl %ecx,%ebx - movl SIGH(%esi),%ecx - sbbl %eax,%ecx - movl %ecx,%eax - -#ifdef PARANOID - /* We can never get a borrow */ - jc L_bugged -#endif /* PARANOID */ - -/*--------------------------------------+ - | Normalize the result | - +--------------------------------------*/ - testl $0x80000000,%eax - jnz L_round /* no shifting needed */ - - orl %eax,%eax - jnz L_shift_1 /* shift left 1 - 31 bits */ - - orl %ebx,%ebx - jnz L_shift_32 /* shift left 32 - 63 bits */ - -/* - * A rare case, the only one which is non-zero if we got here - * is: 1000000 .... 0000 - * -0111111 .... 1111 1 - * -------------------- - * 0000000 .... 0000 1 - */ - - cmpl $0x80000000,%edx - jnz L_must_be_zero - - /* Shift left 64 bits */ - subw $64,EXP(%edi) - xchg %edx,%eax - jmp fpu_reg_round - -L_must_be_zero: -#ifdef PARANOID - orl %edx,%edx - jnz L_bugged_3 -#endif /* PARANOID */ - - /* The result is zero */ - movw $0,EXP(%edi) /* exponent */ - movl $0,SIGL(%edi) - movl $0,SIGH(%edi) - movl TAG_Zero,%eax - jmp L_exit - -L_shift_32: - movl %ebx,%eax - movl %edx,%ebx - movl $0,%edx - subw $32,EXP(%edi) /* Can get underflow here */ - -/* We need to shift left by 1 - 31 bits */ -L_shift_1: - bsrl %eax,%ecx /* get the required shift in %ecx */ - subl $31,%ecx - negl %ecx - shld %cl,%ebx,%eax - shld %cl,%edx,%ebx - shl %cl,%edx - subw %cx,EXP(%edi) /* Can get underflow here */ - -L_round: - jmp fpu_reg_round /* Round the result */ - - -#ifdef PARANOID -L_bugged_1: - pushl EX_INTERNAL|0x206 - call EXCEPTION - pop %ebx - jmp L_error_exit - -L_bugged_2: - pushl EX_INTERNAL|0x209 - call EXCEPTION - pop %ebx - jmp L_error_exit - -L_bugged_3: - pushl EX_INTERNAL|0x210 - call EXCEPTION - pop %ebx - jmp L_error_exit - -L_bugged_4: - pushl EX_INTERNAL|0x211 - call EXCEPTION - pop %ebx - jmp L_error_exit - -L_bugged: - pushl EX_INTERNAL|0x212 - call EXCEPTION - pop %ebx - jmp L_error_exit - -L_error_exit: - movl $-1,%eax - -#endif /* PARANOID */ - -L_exit: - popl %ebx - popl %edi - popl %esi - leave - RET -SYM_FUNC_END(FPU_u_sub) diff --git a/arch/x86/math-emu/round_Xsig.S b/arch/x86/math-emu/round_Xsig.S deleted file mode 100644 index 126c40473bad..000000000000 --- a/arch/x86/math-emu/round_Xsig.S +++ /dev/null @@ -1,142 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/*---------------------------------------------------------------------------+ - | round_Xsig.S | - | | - | Copyright (C) 1992,1993,1994,1995 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | - | | - | Normalize and round a 12 byte quantity. | - | Call from C as: | - | int round_Xsig(Xsig *n) | - | | - | Normalize a 12 byte quantity. | - | Call from C as: | - | int norm_Xsig(Xsig *n) | - | | - | Each function returns the size of the shift (nr of bits). | - | | - +---------------------------------------------------------------------------*/ - .file "round_Xsig.S" - -#include "fpu_emu.h" - - -.text -SYM_FUNC_START(round_Xsig) - pushl %ebp - movl %esp,%ebp - pushl %ebx /* Reserve some space */ - pushl %ebx - pushl %esi - - movl PARAM1,%esi - - movl 8(%esi),%edx - movl 4(%esi),%ebx - movl (%esi),%eax - - movl $0,-4(%ebp) - - orl %edx,%edx /* ms bits */ - js L_round /* Already normalized */ - jnz L_shift_1 /* Shift left 1 - 31 bits */ - - movl %ebx,%edx - movl %eax,%ebx - xorl %eax,%eax - movl $-32,-4(%ebp) - -/* We need to shift left by 1 - 31 bits */ -L_shift_1: - bsrl %edx,%ecx /* get the required shift in %ecx */ - subl $31,%ecx - negl %ecx - subl %ecx,-4(%ebp) - shld %cl,%ebx,%edx - shld %cl,%eax,%ebx - shl %cl,%eax - -L_round: - testl $0x80000000,%eax - jz L_exit - - addl $1,%ebx - adcl $0,%edx - jnz L_exit - - movl $0x80000000,%edx - incl -4(%ebp) - -L_exit: - movl %edx,8(%esi) - movl %ebx,4(%esi) - movl %eax,(%esi) - - movl -4(%ebp),%eax - - popl %esi - popl %ebx - leave - RET -SYM_FUNC_END(round_Xsig) - - - -SYM_FUNC_START(norm_Xsig) - pushl %ebp - movl %esp,%ebp - pushl %ebx /* Reserve some space */ - pushl %ebx - pushl %esi - - movl PARAM1,%esi - - movl 8(%esi),%edx - movl 4(%esi),%ebx - movl (%esi),%eax - - movl $0,-4(%ebp) - - orl %edx,%edx /* ms bits */ - js L_n_exit /* Already normalized */ - jnz L_n_shift_1 /* Shift left 1 - 31 bits */ - - movl %ebx,%edx - movl %eax,%ebx - xorl %eax,%eax - movl $-32,-4(%ebp) - - orl %edx,%edx /* ms bits */ - js L_n_exit /* Normalized now */ - jnz L_n_shift_1 /* Shift left 1 - 31 bits */ - - movl %ebx,%edx - movl %eax,%ebx - xorl %eax,%eax - addl $-32,-4(%ebp) - jmp L_n_exit /* Might not be normalized, - but shift no more. */ - -/* We need to shift left by 1 - 31 bits */ -L_n_shift_1: - bsrl %edx,%ecx /* get the required shift in %ecx */ - subl $31,%ecx - negl %ecx - subl %ecx,-4(%ebp) - shld %cl,%ebx,%edx - shld %cl,%eax,%ebx - shl %cl,%eax - -L_n_exit: - movl %edx,8(%esi) - movl %ebx,4(%esi) - movl %eax,(%esi) - - movl -4(%ebp),%eax - - popl %esi - popl %ebx - leave - RET -SYM_FUNC_END(norm_Xsig) diff --git a/arch/x86/math-emu/shr_Xsig.S b/arch/x86/math-emu/shr_Xsig.S deleted file mode 100644 index f726bf6f6396..000000000000 --- a/arch/x86/math-emu/shr_Xsig.S +++ /dev/null @@ -1,89 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - .file "shr_Xsig.S" -/*---------------------------------------------------------------------------+ - | shr_Xsig.S | - | | - | 12 byte right shift function | - | | - | Copyright (C) 1992,1994,1995 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | - | | - | Call from C as: | - | void shr_Xsig(Xsig *arg, unsigned nr) | - | | - | Extended shift right function. | - | Fastest for small shifts. | - | Shifts the 12 byte quantity pointed to by the first arg (arg) | - | right by the number of bits specified by the second arg (nr). | - | | - +---------------------------------------------------------------------------*/ - -#include "fpu_emu.h" - -.text -SYM_FUNC_START(shr_Xsig) - push %ebp - movl %esp,%ebp - pushl %esi - movl PARAM2,%ecx - movl PARAM1,%esi - cmpl $32,%ecx /* shrd only works for 0..31 bits */ - jnc L_more_than_31 - -/* less than 32 bits */ - pushl %ebx - movl (%esi),%eax /* lsl */ - movl 4(%esi),%ebx /* midl */ - movl 8(%esi),%edx /* msl */ - shrd %cl,%ebx,%eax - shrd %cl,%edx,%ebx - shr %cl,%edx - movl %eax,(%esi) - movl %ebx,4(%esi) - movl %edx,8(%esi) - popl %ebx - popl %esi - leave - RET - -L_more_than_31: - cmpl $64,%ecx - jnc L_more_than_63 - - subb $32,%cl - movl 4(%esi),%eax /* midl */ - movl 8(%esi),%edx /* msl */ - shrd %cl,%edx,%eax - shr %cl,%edx - movl %eax,(%esi) - movl %edx,4(%esi) - movl $0,8(%esi) - popl %esi - leave - RET - -L_more_than_63: - cmpl $96,%ecx - jnc L_more_than_95 - - subb $64,%cl - movl 8(%esi),%eax /* msl */ - shr %cl,%eax - xorl %edx,%edx - movl %eax,(%esi) - movl %edx,4(%esi) - movl %edx,8(%esi) - popl %esi - leave - RET - -L_more_than_95: - xorl %eax,%eax - movl %eax,(%esi) - movl %eax,4(%esi) - movl %eax,8(%esi) - popl %esi - leave - RET -SYM_FUNC_END(shr_Xsig) diff --git a/arch/x86/math-emu/status_w.h b/arch/x86/math-emu/status_w.h deleted file mode 100644 index f642957330ef..000000000000 --- a/arch/x86/math-emu/status_w.h +++ /dev/null @@ -1,68 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/*---------------------------------------------------------------------------+ - | status_w.h | - | | - | Copyright (C) 1992,1993 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | - | | - +---------------------------------------------------------------------------*/ - -#ifndef _STATUS_H_ -#define _STATUS_H_ - -#include "fpu_emu.h" /* for definition of PECULIAR_486 */ - -#ifdef __ASSEMBLER__ -#define Const__(x) $##x -#else -#define Const__(x) x -#endif - -#define SW_Backward Const__(0x8000) /* backward compatibility */ -#define SW_C3 Const__(0x4000) /* condition bit 3 */ -#define SW_Top Const__(0x3800) /* top of stack */ -#define SW_Top_Shift Const__(11) /* shift for top of stack bits */ -#define SW_C2 Const__(0x0400) /* condition bit 2 */ -#define SW_C1 Const__(0x0200) /* condition bit 1 */ -#define SW_C0 Const__(0x0100) /* condition bit 0 */ -#define SW_Summary Const__(0x0080) /* exception summary */ -#define SW_Stack_Fault Const__(0x0040) /* stack fault */ -#define SW_Precision Const__(0x0020) /* loss of precision */ -#define SW_Underflow Const__(0x0010) /* underflow */ -#define SW_Overflow Const__(0x0008) /* overflow */ -#define SW_Zero_Div Const__(0x0004) /* divide by zero */ -#define SW_Denorm_Op Const__(0x0002) /* denormalized operand */ -#define SW_Invalid Const__(0x0001) /* invalid operation */ - -#define SW_Exc_Mask Const__(0x27f) /* Status word exception bit mask */ - -#ifndef __ASSEMBLER__ - -#define COMP_A_gt_B 1 -#define COMP_A_eq_B 2 -#define COMP_A_lt_B 3 -#define COMP_No_Comp 4 -#define COMP_Denormal 0x20 -#define COMP_NaN 0x40 -#define COMP_SNaN 0x80 - -#define status_word() \ - ((partial_status & ~SW_Top & 0xffff) | ((top << SW_Top_Shift) & SW_Top)) -static inline void setcc(int cc) -{ - partial_status &= ~(SW_C0 | SW_C1 | SW_C2 | SW_C3); - partial_status |= (cc) & (SW_C0 | SW_C1 | SW_C2 | SW_C3); -} - -#ifdef PECULIAR_486 - /* Default, this conveys no information, but an 80486 does it. */ - /* Clear the SW_C1 bit, "other bits undefined". */ -# define clear_C1() { partial_status &= ~SW_C1; } -# else -# define clear_C1() -#endif /* PECULIAR_486 */ - -#endif /* __ASSEMBLER__ */ - -#endif /* _STATUS_H_ */ diff --git a/arch/x86/math-emu/version.h b/arch/x86/math-emu/version.h deleted file mode 100644 index a0d73a1d2b67..000000000000 --- a/arch/x86/math-emu/version.h +++ /dev/null @@ -1,12 +0,0 @@ -/*---------------------------------------------------------------------------+ - | version.h | - | | - | | - | Copyright (C) 1992,1993,1994,1996,1997,1999 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@melbpc.org.au | - | | - | | - +---------------------------------------------------------------------------*/ - -#define FPU_VERSION "wm-FPU-emu version 2.01" diff --git a/arch/x86/math-emu/wm_shrx.S b/arch/x86/math-emu/wm_shrx.S deleted file mode 100644 index f608a28a4c43..000000000000 --- a/arch/x86/math-emu/wm_shrx.S +++ /dev/null @@ -1,207 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - .file "wm_shrx.S" -/*---------------------------------------------------------------------------+ - | wm_shrx.S | - | | - | 64 bit right shift functions | - | | - | Copyright (C) 1992,1995 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | - | | - | Call from C as: | - | unsigned FPU_shrx(void *arg1, unsigned arg2) | - | and | - | unsigned FPU_shrxs(void *arg1, unsigned arg2) | - | | - +---------------------------------------------------------------------------*/ - -#include "fpu_emu.h" - -.text -/*---------------------------------------------------------------------------+ - | unsigned FPU_shrx(void *arg1, unsigned arg2) | - | | - | Extended shift right function. | - | Fastest for small shifts. | - | Shifts the 64 bit quantity pointed to by the first arg (arg1) | - | right by the number of bits specified by the second arg (arg2). | - | Forms a 96 bit quantity from the 64 bit arg and eax: | - | [ 64 bit arg ][ eax ] | - | shift right ---------> | - | The eax register is initialized to 0 before the shifting. | - | Results returned in the 64 bit arg and eax. | - +---------------------------------------------------------------------------*/ - -SYM_FUNC_START(FPU_shrx) - push %ebp - movl %esp,%ebp - pushl %esi - movl PARAM2,%ecx - movl PARAM1,%esi - cmpl $32,%ecx /* shrd only works for 0..31 bits */ - jnc L_more_than_31 - -/* less than 32 bits */ - pushl %ebx - movl (%esi),%ebx /* lsl */ - movl 4(%esi),%edx /* msl */ - xorl %eax,%eax /* extension */ - shrd %cl,%ebx,%eax - shrd %cl,%edx,%ebx - shr %cl,%edx - movl %ebx,(%esi) - movl %edx,4(%esi) - popl %ebx - popl %esi - leave - RET - -L_more_than_31: - cmpl $64,%ecx - jnc L_more_than_63 - - subb $32,%cl - movl (%esi),%eax /* lsl */ - movl 4(%esi),%edx /* msl */ - shrd %cl,%edx,%eax - shr %cl,%edx - movl %edx,(%esi) - movl $0,4(%esi) - popl %esi - leave - RET - -L_more_than_63: - cmpl $96,%ecx - jnc L_more_than_95 - - subb $64,%cl - movl 4(%esi),%eax /* msl */ - shr %cl,%eax - xorl %edx,%edx - movl %edx,(%esi) - movl %edx,4(%esi) - popl %esi - leave - RET - -L_more_than_95: - xorl %eax,%eax - movl %eax,(%esi) - movl %eax,4(%esi) - popl %esi - leave - RET -SYM_FUNC_END(FPU_shrx) - - -/*---------------------------------------------------------------------------+ - | unsigned FPU_shrxs(void *arg1, unsigned arg2) | - | | - | Extended shift right function (optimized for small floating point | - | integers). | - | Shifts the 64 bit quantity pointed to by the first arg (arg1) | - | right by the number of bits specified by the second arg (arg2). | - | Forms a 96 bit quantity from the 64 bit arg and eax: | - | [ 64 bit arg ][ eax ] | - | shift right ---------> | - | The eax register is initialized to 0 before the shifting. | - | The lower 8 bits of eax are lost and replaced by a flag which is | - | set (to 0x01) if any bit, apart from the first one, is set in the | - | part which has been shifted out of the arg. | - | Results returned in the 64 bit arg and eax. | - +---------------------------------------------------------------------------*/ -SYM_FUNC_START(FPU_shrxs) - push %ebp - movl %esp,%ebp - pushl %esi - pushl %ebx - movl PARAM2,%ecx - movl PARAM1,%esi - cmpl $64,%ecx /* shrd only works for 0..31 bits */ - jnc Ls_more_than_63 - - cmpl $32,%ecx /* shrd only works for 0..31 bits */ - jc Ls_less_than_32 - -/* We got here without jumps by assuming that the most common requirement - is for small integers */ -/* Shift by [32..63] bits */ - subb $32,%cl - movl (%esi),%eax /* lsl */ - movl 4(%esi),%edx /* msl */ - xorl %ebx,%ebx - shrd %cl,%eax,%ebx - shrd %cl,%edx,%eax - shr %cl,%edx - orl %ebx,%ebx /* test these 32 bits */ - setne %bl - test $0x7fffffff,%eax /* and 31 bits here */ - setne %bh - orw %bx,%bx /* Any of the 63 bit set ? */ - setne %al - movl %edx,(%esi) - movl $0,4(%esi) - popl %ebx - popl %esi - leave - RET - -/* Shift by [0..31] bits */ -Ls_less_than_32: - movl (%esi),%ebx /* lsl */ - movl 4(%esi),%edx /* msl */ - xorl %eax,%eax /* extension */ - shrd %cl,%ebx,%eax - shrd %cl,%edx,%ebx - shr %cl,%edx - test $0x7fffffff,%eax /* only need to look at eax here */ - setne %al - movl %ebx,(%esi) - movl %edx,4(%esi) - popl %ebx - popl %esi - leave - RET - -/* Shift by [64..95] bits */ -Ls_more_than_63: - cmpl $96,%ecx - jnc Ls_more_than_95 - - subb $64,%cl - movl (%esi),%ebx /* lsl */ - movl 4(%esi),%eax /* msl */ - xorl %edx,%edx /* extension */ - shrd %cl,%ebx,%edx - shrd %cl,%eax,%ebx - shr %cl,%eax - orl %ebx,%edx - setne %bl - test $0x7fffffff,%eax /* only need to look at eax here */ - setne %bh - orw %bx,%bx - setne %al - xorl %edx,%edx - movl %edx,(%esi) /* set to zero */ - movl %edx,4(%esi) /* set to zero */ - popl %ebx - popl %esi - leave - RET - -Ls_more_than_95: -/* Shift by [96..inf) bits */ - xorl %eax,%eax - movl (%esi),%ebx - orl 4(%esi),%ebx - setne %al - xorl %ebx,%ebx - movl %ebx,(%esi) - movl %ebx,4(%esi) - popl %ebx - popl %esi - leave - RET -SYM_FUNC_END(FPU_shrxs) diff --git a/arch/x86/math-emu/wm_sqrt.S b/arch/x86/math-emu/wm_sqrt.S deleted file mode 100644 index 40526dd85137..000000000000 --- a/arch/x86/math-emu/wm_sqrt.S +++ /dev/null @@ -1,472 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - .file "wm_sqrt.S" -/*---------------------------------------------------------------------------+ - | wm_sqrt.S | - | | - | Fixed point arithmetic square root evaluation. | - | | - | Copyright (C) 1992,1993,1995,1997 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@suburbia.net | - | | - | Call from C as: | - | int wm_sqrt(FPU_REG *n, unsigned int control_word) | - | | - +---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------+ - | wm_sqrt(FPU_REG *n, unsigned int control_word) | - | returns the square root of n in n. | - | | - | Use Newton's method to compute the square root of a number, which must | - | be in the range [1.0 .. 4.0), to 64 bits accuracy. | - | Does not check the sign or tag of the argument. | - | Sets the exponent, but not the sign or tag of the result. | - | | - | The guess is kept in %esi:%edi | - +---------------------------------------------------------------------------*/ - -#include "exception.h" -#include "fpu_emu.h" - - -#ifndef NON_REENTRANT_FPU -/* Local storage on the stack: */ -#define FPU_accum_3 -4(%ebp) /* ms word */ -#define FPU_accum_2 -8(%ebp) -#define FPU_accum_1 -12(%ebp) -#define FPU_accum_0 -16(%ebp) - -/* - * The de-normalised argument: - * sq_2 sq_1 sq_0 - * b b b b b b b ... b b b b b b .... b b b b 0 0 0 ... 0 - * ^ binary point here - */ -#define FPU_fsqrt_arg_2 -20(%ebp) /* ms word */ -#define FPU_fsqrt_arg_1 -24(%ebp) -#define FPU_fsqrt_arg_0 -28(%ebp) /* ls word, at most the ms bit is set */ - -#else -/* Local storage in a static area: */ -.data - .align 4,0 -FPU_accum_3: - .long 0 /* ms word */ -FPU_accum_2: - .long 0 -FPU_accum_1: - .long 0 -FPU_accum_0: - .long 0 - -/* The de-normalised argument: - sq_2 sq_1 sq_0 - b b b b b b b ... b b b b b b .... b b b b 0 0 0 ... 0 - ^ binary point here - */ -FPU_fsqrt_arg_2: - .long 0 /* ms word */ -FPU_fsqrt_arg_1: - .long 0 -FPU_fsqrt_arg_0: - .long 0 /* ls word, at most the ms bit is set */ -#endif /* NON_REENTRANT_FPU */ - - -.text -SYM_FUNC_START(wm_sqrt) - pushl %ebp - movl %esp,%ebp -#ifndef NON_REENTRANT_FPU - subl $28,%esp -#endif /* NON_REENTRANT_FPU */ - pushl %esi - pushl %edi - pushl %ebx - - movl PARAM1,%esi - - movl SIGH(%esi),%eax - movl SIGL(%esi),%ecx - xorl %edx,%edx - -/* We use a rough linear estimate for the first guess.. */ - - cmpw EXP_BIAS,EXP(%esi) - jnz sqrt_arg_ge_2 - - shrl $1,%eax /* arg is in the range [1.0 .. 2.0) */ - rcrl $1,%ecx - rcrl $1,%edx - -sqrt_arg_ge_2: -/* From here on, n is never accessed directly again until it is - replaced by the answer. */ - - movl %eax,FPU_fsqrt_arg_2 /* ms word of n */ - movl %ecx,FPU_fsqrt_arg_1 - movl %edx,FPU_fsqrt_arg_0 - -/* Make a linear first estimate */ - shrl $1,%eax - addl $0x40000000,%eax - movl $0xaaaaaaaa,%ecx - mull %ecx - shll %edx /* max result was 7fff... */ - testl $0x80000000,%edx /* but min was 3fff... */ - jnz sqrt_prelim_no_adjust - - movl $0x80000000,%edx /* round up */ - -sqrt_prelim_no_adjust: - movl %edx,%esi /* Our first guess */ - -/* We have now computed (approx) (2 + x) / 3, which forms the basis - for a few iterations of Newton's method */ - - movl FPU_fsqrt_arg_2,%ecx /* ms word */ - -/* - * From our initial estimate, three iterations are enough to get us - * to 30 bits or so. This will then allow two iterations at better - * precision to complete the process. - */ - -/* Compute (g + n/g)/2 at each iteration (g is the guess). */ - shrl %ecx /* Doing this first will prevent a divide */ - /* overflow later. */ - - movl %ecx,%edx /* msw of the arg / 2 */ - divl %esi /* current estimate */ - shrl %esi /* divide by 2 */ - addl %eax,%esi /* the new estimate */ - - movl %ecx,%edx - divl %esi - shrl %esi - addl %eax,%esi - - movl %ecx,%edx - divl %esi - shrl %esi - addl %eax,%esi - -/* - * Now that an estimate accurate to about 30 bits has been obtained (in %esi), - * we improve it to 60 bits or so. - * - * The strategy from now on is to compute new estimates from - * guess := guess + (n - guess^2) / (2 * guess) - */ - -/* First, find the square of the guess */ - movl %esi,%eax - mull %esi -/* guess^2 now in %edx:%eax */ - - movl FPU_fsqrt_arg_1,%ecx - subl %ecx,%eax - movl FPU_fsqrt_arg_2,%ecx /* ms word of normalized n */ - sbbl %ecx,%edx - jnc sqrt_stage_2_positive - -/* Subtraction gives a negative result, - negate the result before division. */ - notl %edx - notl %eax - addl $1,%eax - adcl $0,%edx - - divl %esi - movl %eax,%ecx - - movl %edx,%eax - divl %esi - jmp sqrt_stage_2_finish - -sqrt_stage_2_positive: - divl %esi - movl %eax,%ecx - - movl %edx,%eax - divl %esi - - notl %ecx - notl %eax - addl $1,%eax - adcl $0,%ecx - -sqrt_stage_2_finish: - sarl $1,%ecx /* divide by 2 */ - rcrl $1,%eax - - /* Form the new estimate in %esi:%edi */ - movl %eax,%edi - addl %ecx,%esi - - jnz sqrt_stage_2_done /* result should be [1..2) */ - -#ifdef PARANOID -/* It should be possible to get here only if the arg is ffff....ffff */ - cmpl $0xffffffff,FPU_fsqrt_arg_1 - jnz sqrt_stage_2_error -#endif /* PARANOID */ - -/* The best rounded result. */ - xorl %eax,%eax - decl %eax - movl %eax,%edi - movl %eax,%esi - movl $0x7fffffff,%eax - jmp sqrt_round_result - -#ifdef PARANOID -sqrt_stage_2_error: - pushl EX_INTERNAL|0x213 - call EXCEPTION -#endif /* PARANOID */ - -sqrt_stage_2_done: - -/* Now the square root has been computed to better than 60 bits. */ - -/* Find the square of the guess. */ - movl %edi,%eax /* ls word of guess */ - mull %edi - movl %edx,FPU_accum_1 - - movl %esi,%eax - mull %esi - movl %edx,FPU_accum_3 - movl %eax,FPU_accum_2 - - movl %edi,%eax - mull %esi - addl %eax,FPU_accum_1 - adcl %edx,FPU_accum_2 - adcl $0,FPU_accum_3 - -/* movl %esi,%eax */ -/* mull %edi */ - addl %eax,FPU_accum_1 - adcl %edx,FPU_accum_2 - adcl $0,FPU_accum_3 - -/* guess^2 now in FPU_accum_3:FPU_accum_2:FPU_accum_1 */ - - movl FPU_fsqrt_arg_0,%eax /* get normalized n */ - subl %eax,FPU_accum_1 - movl FPU_fsqrt_arg_1,%eax - sbbl %eax,FPU_accum_2 - movl FPU_fsqrt_arg_2,%eax /* ms word of normalized n */ - sbbl %eax,FPU_accum_3 - jnc sqrt_stage_3_positive - -/* Subtraction gives a negative result, - negate the result before division */ - notl FPU_accum_1 - notl FPU_accum_2 - notl FPU_accum_3 - addl $1,FPU_accum_1 - adcl $0,FPU_accum_2 - -#ifdef PARANOID - adcl $0,FPU_accum_3 /* This must be zero */ - jz sqrt_stage_3_no_error - -sqrt_stage_3_error: - pushl EX_INTERNAL|0x207 - call EXCEPTION - -sqrt_stage_3_no_error: -#endif /* PARANOID */ - - movl FPU_accum_2,%edx - movl FPU_accum_1,%eax - divl %esi - movl %eax,%ecx - - movl %edx,%eax - divl %esi - - sarl $1,%ecx /* divide by 2 */ - rcrl $1,%eax - - /* prepare to round the result */ - - addl %ecx,%edi - adcl $0,%esi - - jmp sqrt_stage_3_finished - -sqrt_stage_3_positive: - movl FPU_accum_2,%edx - movl FPU_accum_1,%eax - divl %esi - movl %eax,%ecx - - movl %edx,%eax - divl %esi - - sarl $1,%ecx /* divide by 2 */ - rcrl $1,%eax - - /* prepare to round the result */ - - notl %eax /* Negate the correction term */ - notl %ecx - addl $1,%eax - adcl $0,%ecx /* carry here ==> correction == 0 */ - adcl $0xffffffff,%esi - - addl %ecx,%edi - adcl $0,%esi - -sqrt_stage_3_finished: - -/* - * The result in %esi:%edi:%esi should be good to about 90 bits here, - * and the rounding information here does not have sufficient accuracy - * in a few rare cases. - */ - cmpl $0xffffffe0,%eax - ja sqrt_near_exact_x - - cmpl $0x00000020,%eax - jb sqrt_near_exact - - cmpl $0x7fffffe0,%eax - jb sqrt_round_result - - cmpl $0x80000020,%eax - jb sqrt_get_more_precision - -sqrt_round_result: -/* Set up for rounding operations */ - movl %eax,%edx - movl %esi,%eax - movl %edi,%ebx - movl PARAM1,%edi - movw EXP_BIAS,EXP(%edi) /* Result is in [1.0 .. 2.0) */ - jmp fpu_reg_round - - -sqrt_near_exact_x: -/* First, the estimate must be rounded up. */ - addl $1,%edi - adcl $0,%esi - -sqrt_near_exact: -/* - * This is an easy case because x^1/2 is monotonic. - * We need just find the square of our estimate, compare it - * with the argument, and deduce whether our estimate is - * above, below, or exact. We use the fact that the estimate - * is known to be accurate to about 90 bits. - */ - movl %edi,%eax /* ls word of guess */ - mull %edi - movl %edx,%ebx /* 2nd ls word of square */ - movl %eax,%ecx /* ls word of square */ - - movl %edi,%eax - mull %esi - addl %eax,%ebx - addl %eax,%ebx - -#ifdef PARANOID - cmp $0xffffffb0,%ebx - jb sqrt_near_exact_ok - - cmp $0x00000050,%ebx - ja sqrt_near_exact_ok - - pushl EX_INTERNAL|0x214 - call EXCEPTION - -sqrt_near_exact_ok: -#endif /* PARANOID */ - - or %ebx,%ebx - js sqrt_near_exact_small - - jnz sqrt_near_exact_large - - or %ebx,%edx - jnz sqrt_near_exact_large - -/* Our estimate is exactly the right answer */ - xorl %eax,%eax - jmp sqrt_round_result - -sqrt_near_exact_small: -/* Our estimate is too small */ - movl $0x000000ff,%eax - jmp sqrt_round_result - -sqrt_near_exact_large: -/* Our estimate is too large, we need to decrement it */ - subl $1,%edi - sbbl $0,%esi - movl $0xffffff00,%eax - jmp sqrt_round_result - - -sqrt_get_more_precision: -/* This case is almost the same as the above, except we start - with an extra bit of precision in the estimate. */ - stc /* The extra bit. */ - rcll $1,%edi /* Shift the estimate left one bit */ - rcll $1,%esi - - movl %edi,%eax /* ls word of guess */ - mull %edi - movl %edx,%ebx /* 2nd ls word of square */ - movl %eax,%ecx /* ls word of square */ - - movl %edi,%eax - mull %esi - addl %eax,%ebx - addl %eax,%ebx - -/* Put our estimate back to its original value */ - stc /* The ms bit. */ - rcrl $1,%esi /* Shift the estimate left one bit */ - rcrl $1,%edi - -#ifdef PARANOID - cmp $0xffffff60,%ebx - jb sqrt_more_prec_ok - - cmp $0x000000a0,%ebx - ja sqrt_more_prec_ok - - pushl EX_INTERNAL|0x215 - call EXCEPTION - -sqrt_more_prec_ok: -#endif /* PARANOID */ - - or %ebx,%ebx - js sqrt_more_prec_small - - jnz sqrt_more_prec_large - - or %ebx,%ecx - jnz sqrt_more_prec_large - -/* Our estimate is exactly the right answer */ - movl $0x80000000,%eax - jmp sqrt_round_result - -sqrt_more_prec_small: -/* Our estimate is too small */ - movl $0x800000ff,%eax - jmp sqrt_round_result - -sqrt_more_prec_large: -/* Our estimate is too large */ - movl $0x7fffff00,%eax - jmp sqrt_round_result -SYM_FUNC_END(wm_sqrt) From 435ef16e69b9d7f9cdf460a4c2edd20bb47d51fa Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 15 May 2025 10:26:39 +0200 Subject: [PATCH 11/25] x86/cpu, cpufreq: Remove AMD ELAN support Now that i486 and CONFIG_MELAN support has been removed upstream: 8b793a92d862c ("x86/cpu: Remove M486/M486SX/ELAN support") the CONFIG_ELAN_CPUFREQ and CONFIG_SC520_CPUFREQ cpufreq drivers can be removed as well, as they depend on CONFIG_MELAN. Signed-off-by: Ingo Molnar Reviewed-by: Arnd Bergmann Acked-by: Dave Hansen Cc: Linus Torvalds Cc: "Rafael J. Wysocki" Cc: Viresh Kumar Cc: linux-pm@vger.kernel.org (open list:CPU FREQUENCY SCALING FRAMEWORK) Link: https://lore.kernel.org/r/20250425084216.3913608-8-mingo@kernel.org --- arch/x86/Makefile_32.cpu | 3 - drivers/cpufreq/Kconfig.x86 | 26 ---- drivers/cpufreq/Makefile | 2 - drivers/cpufreq/elanfreq.c | 226 ----------------------------------- drivers/cpufreq/sc520_freq.c | 136 --------------------- 5 files changed, 393 deletions(-) delete mode 100644 drivers/cpufreq/elanfreq.c delete mode 100644 drivers/cpufreq/sc520_freq.c diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu index ec9f34db9a8b..c5aa169b596d 100644 --- a/arch/x86/Makefile_32.cpu +++ b/arch/x86/Makefile_32.cpu @@ -28,9 +28,6 @@ cflags-$(CONFIG_MVIAC3_2) += $(call cc-option,-march=c3-2,-march=i686) cflags-$(CONFIG_MVIAC7) += -march=i686 cflags-$(CONFIG_MATOM) += -march=atom -# AMD Elan support -cflags-$(CONFIG_MELAN) += -march=i486 - # Geode GX1 support cflags-$(CONFIG_MGEODEGX1) += -march=pentium-mmx cflags-$(CONFIG_MGEODE_LX) += $(call cc-option,-march=geode,-march=pentium-mmx) diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86 index 027e6ea2e038..c42dd39e0b2a 100644 --- a/drivers/cpufreq/Kconfig.x86 +++ b/drivers/cpufreq/Kconfig.x86 @@ -126,32 +126,6 @@ config X86_ACPI_CPUFREQ_CPB By enabling this option the acpi_cpufreq driver provides the old entry in addition to the new boost ones, for compatibility reasons. -config ELAN_CPUFREQ - tristate "AMD Elan SC400 and SC410" - depends on MELAN - help - This adds the CPUFreq driver for AMD Elan SC400 and SC410 - processors. - - You need to specify the processor maximum speed as boot - parameter: elanfreq=maxspeed (in kHz) or as module - parameter "max_freq". - - For details, take a look at . - - If in doubt, say N. - -config SC520_CPUFREQ - tristate "AMD Elan SC520" - depends on MELAN - help - This adds the CPUFreq driver for AMD Elan SC520 processor. - - For details, take a look at . - - If in doubt, say N. - - config X86_POWERNOW_K6 tristate "AMD Mobile K6-2/K6-3 PowerNow!" depends on X86_32 diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 385c9fcc65c6..6c7a39b7f8d2 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -40,8 +40,6 @@ obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o obj-$(CONFIG_X86_LONGHAUL) += longhaul.o obj-$(CONFIG_X86_E_POWERSAVER) += e_powersaver.o -obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o -obj-$(CONFIG_SC520_CPUFREQ) += sc520_freq.o obj-$(CONFIG_X86_LONGRUN) += longrun.o obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o obj-$(CONFIG_X86_SPEEDSTEP_ICH) += speedstep-ich.o diff --git a/drivers/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c deleted file mode 100644 index fc5a58088b35..000000000000 --- a/drivers/cpufreq/elanfreq.c +++ /dev/null @@ -1,226 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * elanfreq: cpufreq driver for the AMD ELAN family - * - * (c) Copyright 2002 Robert Schwebel - * - * Parts of this code are (c) Sven Geggus - * - * All Rights Reserved. - * - * 2002-02-13: - initial revision for 2.4.18-pre9 by Robert Schwebel - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include - -#include -#include - -#include -#include -#include - -#define REG_CSCIR 0x22 /* Chip Setup and Control Index Register */ -#define REG_CSCDR 0x23 /* Chip Setup and Control Data Register */ - -/* Module parameter */ -static int max_freq; - -struct s_elan_multiplier { - int clock; /* frequency in kHz */ - int val40h; /* PMU Force Mode register */ - int val80h; /* CPU Clock Speed Register */ -}; - -/* - * It is important that the frequencies - * are listed in ascending order here! - */ -static struct s_elan_multiplier elan_multiplier[] = { - {1000, 0x02, 0x18}, - {2000, 0x02, 0x10}, - {4000, 0x02, 0x08}, - {8000, 0x00, 0x00}, - {16000, 0x00, 0x02}, - {33000, 0x00, 0x04}, - {66000, 0x01, 0x04}, - {99000, 0x01, 0x05} -}; - -static struct cpufreq_frequency_table elanfreq_table[] = { - {0, 0, 1000}, - {0, 1, 2000}, - {0, 2, 4000}, - {0, 3, 8000}, - {0, 4, 16000}, - {0, 5, 33000}, - {0, 6, 66000}, - {0, 7, 99000}, - {0, 0, CPUFREQ_TABLE_END}, -}; - - -/** - * elanfreq_get_cpu_frequency: determine current cpu speed - * - * Finds out at which frequency the CPU of the Elan SOC runs - * at the moment. Frequencies from 1 to 33 MHz are generated - * the normal way, 66 and 99 MHz are called "Hyperspeed Mode" - * and have the rest of the chip running with 33 MHz. - */ - -static unsigned int elanfreq_get_cpu_frequency(unsigned int cpu) -{ - u8 clockspeed_reg; /* Clock Speed Register */ - - local_irq_disable(); - outb_p(0x80, REG_CSCIR); - clockspeed_reg = inb_p(REG_CSCDR); - local_irq_enable(); - - if ((clockspeed_reg & 0xE0) == 0xE0) - return 0; - - /* Are we in CPU clock multiplied mode (66/99 MHz)? */ - if ((clockspeed_reg & 0xE0) == 0xC0) { - if ((clockspeed_reg & 0x01) == 0) - return 66000; - else - return 99000; - } - - /* 33 MHz is not 32 MHz... */ - if ((clockspeed_reg & 0xE0) == 0xA0) - return 33000; - - return (1<<((clockspeed_reg & 0xE0) >> 5)) * 1000; -} - - -static int elanfreq_target(struct cpufreq_policy *policy, - unsigned int state) -{ - /* - * Access to the Elan's internal registers is indexed via - * 0x22: Chip Setup & Control Register Index Register (CSCI) - * 0x23: Chip Setup & Control Register Data Register (CSCD) - * - */ - - /* - * 0x40 is the Power Management Unit's Force Mode Register. - * Bit 6 enables Hyperspeed Mode (66/100 MHz core frequency) - */ - - local_irq_disable(); - outb_p(0x40, REG_CSCIR); /* Disable hyperspeed mode */ - outb_p(0x00, REG_CSCDR); - local_irq_enable(); /* wait till internal pipelines and */ - udelay(1000); /* buffers have cleaned up */ - - local_irq_disable(); - - /* now, set the CPU clock speed register (0x80) */ - outb_p(0x80, REG_CSCIR); - outb_p(elan_multiplier[state].val80h, REG_CSCDR); - - /* now, the hyperspeed bit in PMU Force Mode Register (0x40) */ - outb_p(0x40, REG_CSCIR); - outb_p(elan_multiplier[state].val40h, REG_CSCDR); - udelay(10000); - local_irq_enable(); - - return 0; -} -/* - * Module init and exit code - */ - -static int elanfreq_cpu_init(struct cpufreq_policy *policy) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - struct cpufreq_frequency_table *pos; - - /* capability check */ - if ((c->x86_vendor != X86_VENDOR_AMD) || - (c->x86 != 4) || (c->x86_model != 10)) - return -ENODEV; - - /* max freq */ - if (!max_freq) - max_freq = elanfreq_get_cpu_frequency(0); - - /* table init */ - cpufreq_for_each_entry(pos, elanfreq_table) - if (pos->frequency > max_freq) - pos->frequency = CPUFREQ_ENTRY_INVALID; - - policy->freq_table = elanfreq_table; - return 0; -} - - -#ifndef MODULE -/** - * elanfreq_setup - elanfreq command line parameter parsing - * - * elanfreq command line parameter. Use: - * elanfreq=66000 - * to set the maximum CPU frequency to 66 MHz. Note that in - * case you do not give this boot parameter, the maximum - * frequency will fall back to _current_ CPU frequency which - * might be lower. If you build this as a module, use the - * max_freq module parameter instead. - */ -static int __init elanfreq_setup(char *str) -{ - max_freq = simple_strtoul(str, &str, 0); - pr_warn("You're using the deprecated elanfreq command line option. Use elanfreq.max_freq instead, please!\n"); - return 1; -} -__setup("elanfreq=", elanfreq_setup); -#endif - - -static struct cpufreq_driver elanfreq_driver = { - .get = elanfreq_get_cpu_frequency, - .flags = CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING, - .verify = cpufreq_generic_frequency_table_verify, - .target_index = elanfreq_target, - .init = elanfreq_cpu_init, - .name = "elanfreq", -}; - -static const struct x86_cpu_id elan_id[] = { - X86_MATCH_VENDOR_FAM_MODEL(AMD, 4, 10, NULL), - {} -}; -MODULE_DEVICE_TABLE(x86cpu, elan_id); - -static int __init elanfreq_init(void) -{ - if (!x86_match_cpu(elan_id)) - return -ENODEV; - return cpufreq_register_driver(&elanfreq_driver); -} - - -static void __exit elanfreq_exit(void) -{ - cpufreq_unregister_driver(&elanfreq_driver); -} - - -module_param(max_freq, int, 0444); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Robert Schwebel , " - "Sven Geggus "); -MODULE_DESCRIPTION("cpufreq driver for AMD's Elan CPUs"); - -module_init(elanfreq_init); -module_exit(elanfreq_exit); diff --git a/drivers/cpufreq/sc520_freq.c b/drivers/cpufreq/sc520_freq.c deleted file mode 100644 index b360f03a116f..000000000000 --- a/drivers/cpufreq/sc520_freq.c +++ /dev/null @@ -1,136 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * sc520_freq.c: cpufreq driver for the AMD Elan sc520 - * - * Copyright (C) 2005 Sean Young - * - * Based on elanfreq.c - * - * 2005-03-30: - initial revision - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include - -#include -#include -#include -#include - -#include - -#define MMCR_BASE 0xfffef000 /* The default base address */ -#define OFFS_CPUCTL 0x2 /* CPU Control Register */ - -static __u8 __iomem *cpuctl; - -static struct cpufreq_frequency_table sc520_freq_table[] = { - {0, 0x01, 100000}, - {0, 0x02, 133000}, - {0, 0, CPUFREQ_TABLE_END}, -}; - -static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu) -{ - u8 clockspeed_reg = *cpuctl; - - switch (clockspeed_reg & 0x03) { - default: - pr_err("error: cpuctl register has unexpected value %02x\n", - clockspeed_reg); - fallthrough; - case 0x01: - return 100000; - case 0x02: - return 133000; - } -} - -static int sc520_freq_target(struct cpufreq_policy *policy, unsigned int state) -{ - - u8 clockspeed_reg; - - local_irq_disable(); - - clockspeed_reg = *cpuctl & ~0x03; - *cpuctl = clockspeed_reg | sc520_freq_table[state].driver_data; - - local_irq_enable(); - - return 0; -} - -/* - * Module init and exit code - */ - -static int sc520_freq_cpu_init(struct cpufreq_policy *policy) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - - /* capability check */ - if (c->x86_vendor != X86_VENDOR_AMD || - c->x86 != 4 || c->x86_model != 9) - return -ENODEV; - - /* cpuinfo and default policy values */ - policy->cpuinfo.transition_latency = 1000000; /* 1ms */ - policy->freq_table = sc520_freq_table; - - return 0; -} - - -static struct cpufreq_driver sc520_freq_driver = { - .get = sc520_freq_get_cpu_frequency, - .verify = cpufreq_generic_frequency_table_verify, - .target_index = sc520_freq_target, - .init = sc520_freq_cpu_init, - .name = "sc520_freq", -}; - -static const struct x86_cpu_id sc520_ids[] = { - X86_MATCH_VENDOR_FAM_MODEL(AMD, 4, 9, NULL), - {} -}; -MODULE_DEVICE_TABLE(x86cpu, sc520_ids); - -static int __init sc520_freq_init(void) -{ - int err; - - if (!x86_match_cpu(sc520_ids)) - return -ENODEV; - - cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1); - if (!cpuctl) { - pr_err("sc520_freq: error: failed to remap memory\n"); - return -ENOMEM; - } - - err = cpufreq_register_driver(&sc520_freq_driver); - if (err) - iounmap(cpuctl); - - return err; -} - - -static void __exit sc520_freq_exit(void) -{ - cpufreq_unregister_driver(&sc520_freq_driver); - iounmap(cpuctl); -} - - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Sean Young "); -MODULE_DESCRIPTION("cpufreq driver for AMD's Elan sc520 CPU"); - -module_init(sc520_freq_init); -module_exit(sc520_freq_exit); - From 21ff606db9c57bdd670708d5e08f5a6b98841c9a Mon Sep 17 00:00:00 2001 From: Chao Gao Date: Thu, 7 May 2026 06:47:31 -0700 Subject: [PATCH 12/25] Documentation: core-api/cpu_hotplug: Remove stale cpu0_hotplug docs Commit e59e74dc48a3 ("x86/topology: Remove CPU0 hotplug option") removed the 'cpu0_hotplug' option, but its documentation remained in cpu_hotplug.rst. Remove the stale entry. Reported-by: Dave Hansen Signed-off-by: Chao Gao Signed-off-by: Dave Hansen Link: https://patch.msgid.link/20260507134732.254617-1-chao.gao@intel.com --- Documentation/core-api/cpu_hotplug.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Documentation/core-api/cpu_hotplug.rst b/Documentation/core-api/cpu_hotplug.rst index 9b4afca9fd09..6de26d1c6a9a 100644 --- a/Documentation/core-api/cpu_hotplug.rst +++ b/Documentation/core-api/cpu_hotplug.rst @@ -45,11 +45,6 @@ Command Line Switches This option is limited to the X86 and S390 architecture. -``cpu0_hotplug`` - Allow to shutdown CPU0. - - This option is limited to the X86 architecture. - CPU maps ======== From 55cbcb6731bbea264716ad57eeedc0f98ec176c5 Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Fri, 27 Mar 2026 03:15:19 +0100 Subject: [PATCH 13/25] x86/cpu: Do not include the CPUID API header in asm/processor.h asm/processor.h includes asm/cpuid/api.h but it does not need it. Remove the include. This allows the CPUID APIs header to include at a later step without introducing a circular dependency. Note, all call sites which implicitly included the CPUID API through have been modified to explicitly include the CPUID APIs instead. Signed-off-by: Ahmed S. Darwish Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/20260327021645.555257-1-darwi@linutronix.de --- arch/x86/include/asm/processor.h | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 10b5355b323e..4f4356b13158 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -16,7 +16,6 @@ struct vm86; #include #include #include -#include #include #include #include From 5fbe09ebb4dc7e0fa54f7a26d6be72a33d7e6035 Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Fri, 27 Mar 2026 03:15:20 +0100 Subject: [PATCH 14/25] x86/cpuid: Rename cpuid_leaf()/cpuid_subleaf() APIs A new CPUID model will be added where its APIs will be designated as the official CPUID API. Free the cpuid_leaf() and cpuid_subleaf() function names for that API. Rename them accordingly to cpuid_read() and cpuid_read_subleaf(). For kernel/cpuid.c, rename its local file operations read function from cpuid_read() to cpuid_read_f() so that it does not conflict with the new API. No functional change. Signed-off-by: Ahmed S. Darwish Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/20260327021645.555257-1-darwi@linutronix.de --- arch/x86/include/asm/cpuid/api.h | 6 +++--- arch/x86/kernel/cpu/topology_amd.c | 2 +- arch/x86/kernel/cpu/topology_ext.c | 2 +- arch/x86/kernel/cpuid.c | 5 ++--- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/arch/x86/include/asm/cpuid/api.h b/arch/x86/include/asm/cpuid/api.h index 44fa82e1267c..2b9750cc8a75 100644 --- a/arch/x86/include/asm/cpuid/api.h +++ b/arch/x86/include/asm/cpuid/api.h @@ -131,12 +131,12 @@ static inline void __cpuid_read(u32 leaf, u32 subleaf, u32 *regs) __cpuid(regs + CPUID_EAX, regs + CPUID_EBX, regs + CPUID_ECX, regs + CPUID_EDX); } -#define cpuid_subleaf(leaf, subleaf, regs) { \ +#define cpuid_read_subleaf(leaf, subleaf, regs) { \ static_assert(sizeof(*(regs)) == 16); \ __cpuid_read(leaf, subleaf, (u32 *)(regs)); \ } -#define cpuid_leaf(leaf, regs) { \ +#define cpuid_read(leaf, regs) { \ static_assert(sizeof(*(regs)) == 16); \ __cpuid_read(leaf, 0, (u32 *)(regs)); \ } @@ -228,7 +228,7 @@ static inline u32 cpuid_base_hypervisor(const char *sig, u32 leaves) */ static inline void cpuid_leaf_0x2(union leaf_0x2_regs *regs) { - cpuid_leaf(0x2, regs); + cpuid_read(0x2, regs); /* * All Intel CPUs must report an iteration count of 1. In case diff --git a/arch/x86/kernel/cpu/topology_amd.c b/arch/x86/kernel/cpu/topology_amd.c index cc103c85b96d..da080d732e10 100644 --- a/arch/x86/kernel/cpu/topology_amd.c +++ b/arch/x86/kernel/cpu/topology_amd.c @@ -80,7 +80,7 @@ static bool parse_8000_001e(struct topo_scan *tscan) if (!boot_cpu_has(X86_FEATURE_TOPOEXT)) return false; - cpuid_leaf(0x8000001e, &leaf); + cpuid_read(0x8000001e, &leaf); /* * If leaf 0xb/0x26 is available, then the APIC ID and the domain diff --git a/arch/x86/kernel/cpu/topology_ext.c b/arch/x86/kernel/cpu/topology_ext.c index eb915c73895f..60dfaa02ffd0 100644 --- a/arch/x86/kernel/cpu/topology_ext.c +++ b/arch/x86/kernel/cpu/topology_ext.c @@ -71,7 +71,7 @@ static inline bool topo_subleaf(struct topo_scan *tscan, u32 leaf, u32 subleaf, default: return false; } - cpuid_subleaf(leaf, subleaf, &sl); + cpuid_read_subleaf(leaf, subleaf, &sl); if (!sl.num_processors || sl.type == INVALID_TYPE) return false; diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c index cbd04b677fd1..b55fe9c7359a 100644 --- a/arch/x86/kernel/cpuid.c +++ b/arch/x86/kernel/cpuid.c @@ -59,8 +59,7 @@ static void cpuid_smp_cpuid(void *cmd_block) complete(&cmd->done); } -static ssize_t cpuid_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) +static ssize_t cpuid_read_f(struct file *file, char __user *buf, size_t count, loff_t *ppos) { char __user *tmp = buf; struct cpuid_regs_done cmd; @@ -120,7 +119,7 @@ static int cpuid_open(struct inode *inode, struct file *file) static const struct file_operations cpuid_fops = { .owner = THIS_MODULE, .llseek = no_seek_end_llseek, - .read = cpuid_read, + .read = cpuid_read_f, .open = cpuid_open, }; From 202311a754d4208ef156bc23b7ac310feccdea3b Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Fri, 27 Mar 2026 03:15:21 +0100 Subject: [PATCH 15/25] x86/cpuid: Introduce MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To centralize all CPUID access across the x86 subsystem, introduce . It is generated by the x86-cpuid-db project¹ and provides C99 bitfield listings for all publicly known CPUID leaves. ¹ https://gitlab.com/x86-cpuid.org/x86-cpuid-db/-/blob/v3.0/CHANGELOG.rst Suggested-by: Thomas Gleixner Signed-off-by: Ahmed S. Darwish Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/20260327021645.555257-1-darwi@linutronix.de --- MAINTAINERS | 1 + arch/x86/include/asm/cpuid/leaf_types.h | 2350 +++++++++++++++++++++++ 2 files changed, 2351 insertions(+) create mode 100644 arch/x86/include/asm/cpuid/leaf_types.h diff --git a/MAINTAINERS b/MAINTAINERS index 3db882dae319..c152274a8dc9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -28859,6 +28859,7 @@ R: Ahmed S. Darwish L: x86-cpuid@lists.linux.dev S: Maintained W: https://x86-cpuid.org +F: arch/x86/include/asm/cpuid/leaf_types.h F: tools/arch/x86/kcpuid/ X86 ENTRY CODE diff --git a/arch/x86/include/asm/cpuid/leaf_types.h b/arch/x86/include/asm/cpuid/leaf_types.h new file mode 100644 index 000000000000..5b0008e455e2 --- /dev/null +++ b/arch/x86/include/asm/cpuid/leaf_types.h @@ -0,0 +1,2350 @@ +/* SPDX-License-Identifier: MIT */ +/* Generator: x86-cpuid-db v3.0 */ + +/* + * Auto-generated file. + * Please submit all updates and bugfixes to https://x86-cpuid.org + */ + +#ifndef _ASM_X86_CPUID_LEAF_TYPES +#define _ASM_X86_CPUID_LEAF_TYPES + +#include + +/* + * Leaf 0x0 + * Maximum standard leaf + CPU vendor string + */ + +struct leaf_0x0_0 { + // eax + u32 max_std_leaf : 32; // Highest standard CPUID leaf + // ebx + u32 cpu_vendorid_0 : 32; // CPU vendor ID string bytes 0 - 3 + // ecx + u32 cpu_vendorid_2 : 32; // CPU vendor ID string bytes 8 - 11 + // edx + u32 cpu_vendorid_1 : 32; // CPU vendor ID string bytes 4 - 7 +}; + +/* + * Leaf 0x1 + * CPU FMS (Family/Model/Stepping) + standard feature flags + */ + +struct leaf_0x1_0 { + // eax + u32 stepping : 4, // Stepping ID + base_model : 4, // Base CPU model ID + base_family_id : 4, // Base CPU family ID + cpu_type : 2, // CPU type + : 2, // Reserved + ext_model : 4, // Extended CPU model ID + ext_family : 8, // Extended CPU family ID + : 4; // Reserved + // ebx + u32 brand_id : 8, // Brand index + clflush_size : 8, // CLFLUSH instruction cache line size + n_logical_cpu : 8, // Logical CPU count + local_apic_id : 8; // Initial local APIC physical ID + // ecx + u32 sse3 : 1, // Streaming SIMD Extensions 3 (SSE3) + pclmulqdq : 1, // PCLMULQDQ instruction support + dtes64 : 1, // 64-bit DS save area + monitor : 1, // MONITOR/MWAIT support + dscpl : 1, // CPL Qualified Debug Store + vmx : 1, // Virtual Machine Extensions + smx : 1, // Safer Mode Extensions + est : 1, // Enhanced Intel SpeedStep + tm2 : 1, // Thermal Monitor 2 + ssse3 : 1, // Supplemental SSE3 + cntxt_id : 1, // L1 Context ID + sdbg : 1, // Silicon Debug + fma : 1, // FMA extensions using YMM state + cx16 : 1, // CMPXCHG16B instruction support + xtpr_update : 1, // xTPR Update Control + pdcm : 1, // Perfmon and Debug Capability + : 1, // Reserved + pcid : 1, // Process-context identifiers + dca : 1, // Direct Cache Access + sse4_1 : 1, // SSE4.1 + sse4_2 : 1, // SSE4.2 + x2apic : 1, // X2APIC support + movbe : 1, // MOVBE instruction support + popcnt : 1, // POPCNT instruction support + tsc_deadline_timer : 1, // APIC timer one-shot operation + aes : 1, // AES instructions + xsave : 1, // XSAVE (and related instructions) support + osxsave : 1, // XSAVE (and related instructions) are enabled by OS + avx : 1, // AVX instructions support + f16c : 1, // Half-precision floating-point conversion support + rdrand : 1, // RDRAND instruction support + guest_status : 1; // System is running as guest; (para-)virtualized system + // edx + u32 fpu : 1, // Floating-Point Unit on-chip (x87) + vme : 1, // Virtual-8086 Mode Extensions + de : 1, // Debugging Extensions + pse : 1, // Page Size Extension + tsc : 1, // Time Stamp Counter + msr : 1, // Model-Specific Registers (RDMSR and WRMSR support) + pae : 1, // Physical Address Extensions + mce : 1, // Machine Check Exception + cx8 : 1, // CMPXCHG8B instruction + apic : 1, // APIC on-chip + : 1, // Reserved + sep : 1, // SYSENTER, SYSEXIT, and associated MSRs + mtrr : 1, // Memory Type Range Registers + pge : 1, // Page Global Extensions + mca : 1, // Machine Check Architecture + cmov : 1, // Conditional Move Instruction + pat : 1, // Page Attribute Table + pse36 : 1, // Page Size Extension (36-bit) + psn : 1, // Processor Serial Number + clflush : 1, // CLFLUSH instruction + : 1, // Reserved + ds : 1, // Debug Store + acpi : 1, // Thermal monitor and clock control + mmx : 1, // MMX instructions + fxsr : 1, // FXSAVE and FXRSTOR instructions + sse : 1, // SSE instructions + sse2 : 1, // SSE2 instructions + selfsnoop : 1, // Self Snoop + htt : 1, // Hyper-threading + tm : 1, // Thermal Monitor + ia64 : 1, // Legacy IA-64 (Itanium) support bit, now reserved + pbe : 1; // Pending Break Enable +}; + +/* + * Leaf 0x2 + * Intel cache and TLB information one-byte descriptors + */ + +struct leaf_0x2_0 { + // eax + u32 iteration_count : 8, // Number of times this leaf must be queried + desc1 : 8, // Descriptor #1 + desc2 : 8, // Descriptor #2 + desc3 : 7, // Descriptor #3 + eax_invalid : 1; // Descriptors 1-3 are invalid if set + // ebx + u32 desc4 : 8, // Descriptor #4 + desc5 : 8, // Descriptor #5 + desc6 : 8, // Descriptor #6 + desc7 : 7, // Descriptor #7 + ebx_invalid : 1; // Descriptors 4-7 are invalid if set + // ecx + u32 desc8 : 8, // Descriptor #8 + desc9 : 8, // Descriptor #9 + desc10 : 8, // Descriptor #10 + desc11 : 7, // Descriptor #11 + ecx_invalid : 1; // Descriptors 8-11 are invalid if set + // edx + u32 desc12 : 8, // Descriptor #12 + desc13 : 8, // Descriptor #13 + desc14 : 8, // Descriptor #14 + desc15 : 7, // Descriptor #15 + edx_invalid : 1; // Descriptors 12-15 are invalid if set +}; + +/* + * Leaf 0x4 + * Intel deterministic cache parameters + */ + +struct leaf_0x4_n { + // eax + u32 cache_type : 5, // Cache type field + cache_level : 3, // Cache level (1-based) + cache_self_init : 1, // Self-initializing cache level + fully_associative : 1, // Fully-associative cache + : 4, // Reserved + num_threads_sharing : 12, // Number logical CPUs sharing this cache + num_cores_on_die : 6; // Number of cores in the physical package + // ebx + u32 cache_linesize : 12, // System coherency line size (0-based) + cache_npartitions : 10, // Physical line partitions (0-based) + cache_nways : 10; // Ways of associativity (0-based) + // ecx + u32 cache_nsets : 31, // Cache number of sets (0-based) + : 1; // Reserved + // edx + u32 wbinvd_rll_no_guarantee : 1, // WBINVD/INVD not guaranteed for Remote Lower-Level caches + ll_inclusive : 1, // Cache is inclusive of Lower-Level caches + complex_indexing : 1, // Not a direct-mapped cache (complex function) + : 29; // Reserved +}; + +#define LEAF_0x4_SUBLEAF_N_FIRST 0 +#define LEAF_0x4_SUBLEAF_N_LAST 31 + +/* + * Leaf 0x5 + * MONITOR/MWAIT instructions + */ + +struct leaf_0x5_0 { + // eax + u32 min_mon_size : 16, // Smallest monitor-line size, in bytes + : 16; // Reserved + // ebx + u32 max_mon_size : 16, // Largest monitor-line size, in bytes + : 16; // Reserved + // ecx + u32 mwait_ext : 1, // MONITOR/MWAIT extensions + mwait_irq_break : 1, // Interrupts as a break event for MWAIT + : 30; // Reserved + // edx + u32 n_c0_substates : 4, // Number of C0 sub C-states + n_c1_substates : 4, // Number of C1 sub C-states + n_c2_substates : 4, // Number of C2 sub C-states + n_c3_substates : 4, // Number of C3 sub C-states + n_c4_substates : 4, // Number of C4 sub C-states + n_c5_substates : 4, // Number of C5 sub C-states + n_c6_substates : 4, // Number of C6 sub C-states + n_c7_substates : 4; // Number of C7 sub C-states +}; + +/* + * Leaf 0x6 + * Thermal and power management + */ + +struct leaf_0x6_0 { + // eax + u32 digital_temp : 1, // Digital temperature sensor + turbo_boost : 1, // Intel Turbo Boost + lapic_timer_always_on : 1, // Always-Running APIC Timer (not affected by p-state) + : 1, // Reserved + power_limit_event : 1, // Power Limit Notification (PLN) event + ecmd : 1, // Clock modulation duty cycle extension + package_thermal : 1, // Package thermal management + hwp_base_regs : 1, // HWP (Hardware P-states) base registers + hwp_notify : 1, // HWP notification (IA32_HWP_INTERRUPT MSR) + hwp_activity_window : 1, // HWP activity window (IA32_HWP_REQUEST[bits 41:32]) + hwp_energy_perf_pr : 1, // HWP Energy Performance Preference + hwp_package_req : 1, // HWP Package Level Request + : 1, // Reserved + hdc_base_regs : 1, // HDC base registers + turbo_boost_3_0 : 1, // Intel Turbo Boost Max 3.0 + hwp_capabilities : 1, // HWP Highest Performance change + hwp_peci_override : 1, // HWP PECI override + hwp_flexible : 1, // Flexible HWP + hwp_fast : 1, // IA32_HWP_REQUEST MSR fast access mode + hw_feedback : 1, // HW_FEEDBACK MSRs + hwp_ignore_idle : 1, // Ignoring idle logical CPU HWP request is supported + : 1, // Reserved + hwp_ctl : 1, // IA32_HWP_CTL MSR + thread_director : 1, // Intel thread director + therm_interrupt_bit25 : 1, // IA32_THERM_INTERRUPT MSR bit 25 + : 7; // Reserved + // ebx + u32 n_therm_thresholds : 4, // Digital thermometer thresholds + : 28; // Reserved + // ecx + u32 aperf_mperf : 1, // MPERF/APERF MSRs (effective frequency interface) + : 2, // Reserved + energy_perf_bias : 1, // IA32_ENERGY_PERF_BIAS MSR + : 4, // Reserved + thrd_director_nclasses : 8, // Number of classes, Intel thread director + : 16; // Reserved + // edx + u32 perfcap_reporting : 1, // Performance capability reporting + encap_reporting : 1, // Energy efficiency capability reporting + : 6, // Reserved + feedback_sz : 4, // Feedback interface structure size, in 4K pages + : 4, // Reserved + this_lcpu_hwfdbk_idx : 16; // This logical CPU hardware feedback interface index +}; + +/* + * Leaf 0x7 + * Extended CPU features + */ + +struct leaf_0x7_0 { + // eax + u32 leaf7_n_subleaves : 32; // Number of leaf 0x7 subleaves + // ebx + u32 fsgsbase : 1, // FSBASE/GSBASE read/write + tsc_adjust : 1, // IA32_TSC_ADJUST MSR + sgx : 1, // Intel SGX (Software Guard Extensions) + bmi1 : 1, // Bit manipulation extensions group 1 + hle : 1, // Hardware Lock Elision + avx2 : 1, // AVX2 instruction set + fdp_excptn_only : 1, // FPU Data Pointer updated only on x87 exceptions + smep : 1, // Supervisor Mode Execution Protection + bmi2 : 1, // Bit manipulation extensions group 2 + erms : 1, // Enhanced REP MOVSB/STOSB + invpcid : 1, // INVPCID instruction (Invalidate Processor Context ID) + rtm : 1, // Intel restricted transactional memory + pqm : 1, // Intel RDT-CMT / AMD Platform-QoS cache monitoring + zero_fcs_fds : 1, // Deprecated FPU CS/DS (stored as zero) + mpx : 1, // Intel memory protection extensions + rdt_a : 1, // Intel RDT / AMD Platform-QoS Enforcement + avx512f : 1, // AVX-512 foundation instructions + avx512dq : 1, // AVX-512 double/quadword instructions + rdseed : 1, // RDSEED instruction + adx : 1, // ADCX/ADOX instructions + smap : 1, // Supervisor mode access prevention + avx512ifma : 1, // AVX-512 integer fused multiply add + : 1, // Reserved + clflushopt : 1, // CLFLUSHOPT instruction + clwb : 1, // CLWB instruction + intel_pt : 1, // Intel processor trace + avx512pf : 1, // AVX-512 prefetch instructions + avx512er : 1, // AVX-512 exponent/reciprocal instructions + avx512cd : 1, // AVX-512 conflict detection instructions + sha : 1, // SHA/SHA256 instructions + avx512bw : 1, // AVX-512 byte/word instructions + avx512vl : 1; // AVX-512 VL (128/256 vector length) extensions + // ecx + u32 prefetchwt1 : 1, // PREFETCHWT1 (Intel Xeon Phi only) + avx512vbmi : 1, // AVX-512 Vector byte manipulation instructions + umip : 1, // User mode instruction protection + pku : 1, // Protection keys for user-space + ospke : 1, // OS protection keys enable + waitpkg : 1, // WAITPKG instructions + avx512_vbmi2 : 1, // AVX-512 vector byte manipulation instructions group 2 + cet_ss : 1, // CET shadow stack features + gfni : 1, // Galois field new instructions + vaes : 1, // Vector AES instructions + vpclmulqdq : 1, // VPCLMULQDQ 256-bit instruction + avx512_vnni : 1, // Vector neural network instructions + avx512_bitalg : 1, // AVX-512 bitwise algorithms + tme : 1, // Intel total memory encryption + avx512_vpopcntdq : 1, // AVX-512: POPCNT for vectors of DWORD/QWORD + : 1, // Reserved + la57 : 1, // 57-bit linear addresses (five-level paging) + mawau_val_lm : 5, // BNDLDX/BNDSTX MAWAU value in 64-bit mode + rdpid : 1, // RDPID instruction + key_locker : 1, // Intel key locker + bus_lock_detect : 1, // OS bus-lock detection + cldemote : 1, // CLDEMOTE instruction + : 1, // Reserved + movdiri : 1, // MOVDIRI instruction + movdir64b : 1, // MOVDIR64B instruction + enqcmd : 1, // Enqueue stores (ENQCMD{,S}) + sgx_lc : 1, // Intel SGX launch configuration + pks : 1; // Protection keys for supervisor-mode pages + // edx + u32 : 1, // Reserved + sgx_keys : 1, // Intel SGX attestation services + avx512_4vnniw : 1, // AVX-512 neural network instructions + avx512_4fmaps : 1, // AVX-512 multiply accumulation single precision + fsrm : 1, // Fast short REP MOV + uintr : 1, // User interrupts + : 2, // Reserved + avx512_vp2intersect : 1, // VP2INTERSECT{D,Q} instructions + srdbs_ctrl : 1, // SRBDS mitigation MSR + md_clear : 1, // VERW MD_CLEAR microcode + rtm_always_abort : 1, // XBEGIN (RTM transaction) always aborts + : 1, // Reserved + tsx_force_abort : 1, // MSR TSX_FORCE_ABORT, RTM_ABORT bit + serialize : 1, // SERIALIZE instruction + hybrid_cpu : 1, // The CPU is identified as a 'hybrid part' + tsxldtrk : 1, // TSX suspend/resume load address tracking + : 1, // Reserved + pconfig : 1, // PCONFIG instruction + arch_lbr : 1, // Intel architectural LBRs + cet_ibt : 1, // CET indirect branch tracking + : 1, // Reserved + amx_bf16 : 1, // AMX-BF16: tile bfloat16 + avx512_fp16 : 1, // AVX-512 FP16 instructions + amx_tile : 1, // AMX-TILE: tile architecture + amx_int8 : 1, // AMX-INT8: tile 8-bit integer + spec_ctrl : 1, // Speculation Control (IBRS/IBPB: indirect branch restrictions) + intel_stibp : 1, // Single thread indirect branch predictors + flush_l1d : 1, // FLUSH L1D cache: IA32_FLUSH_CMD MSR + arch_capabilities : 1, // Intel IA32_ARCH_CAPABILITIES MSR + core_capabilities : 1, // IA32_CORE_CAPABILITIES MSR + spec_ctrl_ssbd : 1; // Speculative store bypass disable +}; + +struct leaf_0x7_1 { + // eax + u32 : 4, // Reserved + avx_vnni : 1, // AVX-VNNI instructions + avx512_bf16 : 1, // AVX-512 bfloat16 instructions + lass : 1, // Linear address space separation + cmpccxadd : 1, // CMPccXADD instructions + arch_perfmon_ext : 1, // ArchPerfmonExt: leaf 0x23 + : 1, // Reserved + fzrm : 1, // Fast zero-length REP MOVSB + fsrs : 1, // Fast short REP STOSB + fsrc : 1, // Fast Short REP CMPSB/SCASB + : 4, // Reserved + fred : 1, // FRED: Flexible return and event delivery transitions + lkgs : 1, // LKGS: Load 'kernel' (userspace) GS + wrmsrns : 1, // WRMSRNS instruction (WRMSR-non-serializing) + nmi_src : 1, // NMI-source reporting with FRED event data + amx_fp16 : 1, // AMX-FP16: FP16 tile operations + hreset : 1, // HRESET (Thread director history reset) + avx_ifma : 1, // Integer fused multiply add + : 2, // Reserved + lam : 1, // Linear address masking + rd_wr_msrlist : 1, // RDMSRLIST/WRMSRLIST instructions + : 4; // Reserved + // ebx + u32 intel_ppin : 1, // Protected processor inventory number (PPIN{,_CTL} MSRs) + : 31; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 : 4, // Reserved + avx_vnni_int8 : 1, // AVX-VNNI-INT8 instructions + avx_ne_convert : 1, // AVX-NE-CONVERT instructions + : 2, // Reserved + amx_complex : 1, // AMX-COMPLEX instructions (starting from Granite Rapids) + : 5, // Reserved + prefetchit_0_1 : 1, // PREFETCHIT0/1 instructions + : 3, // Reserved + cet_sss : 1, // CET supervisor shadow stacks safe to use + : 13; // Reserved +}; + +struct leaf_0x7_2 { + // eax + u32 : 32; // Reserved + // ebx + u32 : 32; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 intel_psfd : 1, // Intel predictive store forward disable + ipred_ctrl : 1, // MSR bits IA32_SPEC_CTRL.IPRED_DIS_{U,S} + rrsba_ctrl : 1, // MSR bits IA32_SPEC_CTRL.RRSBA_DIS_{U,S} + ddp_ctrl : 1, // MSR bit IA32_SPEC_CTRL.DDPD_U + bhi_ctrl : 1, // MSR bit IA32_SPEC_CTRL.BHI_DIS_S + mcdt_no : 1, // MCDT mitigation not needed + uclock_disable : 1, // UC-lock disable + : 25; // Reserved +}; + +/* + * Leaf 0x9 + * Intel DCA (Direct Cache Access) + */ + +struct leaf_0x9_0 { + // eax + u32 dca_enabled_in_bios : 1, // DCA is enabled in BIOS + : 31; // Reserved + // ebx + u32 : 32; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0xa + * Intel PMU (Performance Monitoring Unit) + */ + +struct leaf_0xa_0 { + // eax + u32 pmu_version : 8, // Performance monitoring unit version ID + num_counters_gp : 8, // Number of general-purpose PMU counters per logical CPU + bit_width_gp : 8, // Bitwidth of PMU general-purpose counters + events_mask_len : 8; // Length of CPUID(0xa).EBX bit vector + // ebx + u32 no_core_cycle : 1, // Core cycle event not available + no_instruction_retired : 1, // Instruction retired event not available + no_reference_cycles : 1, // Reference cycles event not available + no_llc_reference : 1, // LLC-reference event not available + no_llc_misses : 1, // LLC-misses event not available + no_br_insn_retired : 1, // Branch instruction retired event not available + no_br_misses_retired : 1, // Branch mispredict retired event not available + no_topdown_slots : 1, // Topdown slots event not available + no_backend_bound : 1, // Topdown backend bound not available + no_bad_speculation : 1, // Topdown bad speculation not available + no_frontend_bound : 1, // Topdown frontend bound not available + no_retiring : 1, // Topdown retiring not available + no_lbr_inserts : 1, // LBR inserts not available + : 19; // Reserved + // ecx + u32 pmu_fcounters_bitmap : 32; // Fixed-function PMU counters support bitmap + // edx + u32 num_counters_fixed : 5, // Number of fixed PMU counters + bitwidth_fixed : 8, // Bitwidth of PMU fixed counters + : 2, // Reserved + anythread_deprecation : 1, // AnyThread mode deprecation + : 16; // Reserved +}; + +/* + * Leaf 0xb + * CPU extended topology v1 + */ + +struct leaf_0xb_n { + // eax + u32 x2apic_id_shift : 5, // Bit width of this level (previous levels inclusive) + : 27; // Reserved + // ebx + u32 domain_lcpus_count : 16, // Logical CPUs count across all instances of this domain + : 16; // Reserved + // ecx + u32 domain_nr : 8, // This domain level (subleaf ID) + domain_type : 8, // This domain type + : 16; // Reserved + // edx + u32 x2apic_id : 32; // x2APIC ID of current logical CPU +}; + +#define LEAF_0xb_SUBLEAF_N_FIRST 0 +#define LEAF_0xb_SUBLEAF_N_LAST 1 + +/* + * Leaf 0xd + * CPU extended state + */ + +struct leaf_0xd_0 { + // eax + u32 xcr0_x87 : 1, // XCR0.X87 + xcr0_sse : 1, // XCR0.SSE + xcr0_avx : 1, // XCR0.AVX + xcr0_mpx_bndregs : 1, // XCR0.BNDREGS: MPX BND0-BND3 registers + xcr0_mpx_bndcsr : 1, // XCR0.BNDCSR: MPX BNDCFGU/BNDSTATUS registers + xcr0_avx512_opmask : 1, // XCR0.OPMASK: AVX-512 k0-k7 registers + xcr0_avx512_zmm_hi256 : 1, // XCR0.ZMM_Hi256: AVX-512 ZMM0->ZMM7/15 registers + xcr0_avx512_hi16_zmm : 1, // XCR0.HI16_ZMM: AVX-512 ZMM16->ZMM31 registers + : 1, // Reserved + xcr0_pkru : 1, // XCR0.PKRU: XSAVE PKRU registers + : 1, // Reserved + xcr0_cet_u : 1, // XCR0.CET_U: CET user state + xcr0_cet_s : 1, // XCR0.CET_S: CET supervisor state + : 4, // Reserved + xcr0_tileconfig : 1, // XCR0.TILECONFIG: AMX can manage TILECONFIG + xcr0_tiledata : 1, // XCR0.TILEDATA: AMX can manage TILEDATA + : 13; // Reserved + // ebx + u32 xsave_sz_xcr0 : 32; // XSAVE/XRSTOR area byte size, for XCR0 enabled features + // ecx + u32 xsave_sz_max : 32; // XSAVE/XRSTOR area max byte size, all CPU features + // edx + u32 : 30, // Reserved + xcr0_lwp : 1, // AMD XCR0.LWP: Light-weight Profiling + : 1; // Reserved +}; + +struct leaf_0xd_1 { + // eax + u32 xsaveopt : 1, // XSAVEOPT instruction + xsavec : 1, // XSAVEC instruction + xgetbv1 : 1, // XGETBV instruction with ECX = 1 + xsaves : 1, // XSAVES/XRSTORS instructions (and XSS MSR) + xfd : 1, // Extended feature disable + : 27; // Reserved + // ebx + u32 xsave_sz_xcr0_xss : 32; // XSAVES/XSAVEC area byte size, for XCR0|XSS enabled features + // ecx + u32 : 8, // Reserved + xss_pt : 1, // PT state + : 1, // Reserved + xss_pasid : 1, // PASID state + xss_cet_u : 1, // CET user state + xss_cet_p : 1, // CET supervisor state + xss_hdc : 1, // HDC state + xss_uintr : 1, // UINTR state + xss_lbr : 1, // LBR state + xss_hwp : 1, // HWP state + : 15; // Reserved + // edx + u32 : 32; // Reserved +}; + +struct leaf_0xd_n { + // eax + u32 xsave_sz : 32; // Subleaf-N feature save area size, in bytes + // ebx + u32 xsave_offset : 32; // Subleaf-N feature save area offset, in bytes + // ecx + u32 is_xss_bit : 1, // Subleaf N describes an XSS bit (otherwise XCR0) + compacted_xsave_64byte_aligned : 1, // When compacted, subleaf-N XSAVE area is 64-byte aligned + : 30; // Reserved + // edx + u32 : 32; // Reserved +}; + +#define LEAF_0xd_SUBLEAF_N_FIRST 2 +#define LEAF_0xd_SUBLEAF_N_LAST 63 + +/* + * Leaf 0xf + * Intel RDT / AMD PQoS resource monitoring + */ + +struct leaf_0xf_0 { + // eax + u32 : 32; // Reserved + // ebx + u32 core_rmid_max : 32; // RMID max within this core (0-based) + // ecx + u32 : 32; // Reserved + // edx + u32 : 1, // Reserved + llc_qos_mon : 1, // LLC QoS-monitoring + : 30; // Reserved +}; + +struct leaf_0xf_1 { + // eax + u32 l3c_qm_bitwidth : 8, // L3 QoS-monitoring counter bitwidth (24-based) + l3c_qm_overflow_bit : 1, // QM_CTR MSR bit 61 is an overflow bit + io_rdt_cmt : 1, // non-CPU agent supporting Intel RDT CMT present + io_rdt_mbm : 1, // non-CPU agent supporting Intel RDT MBM present + : 21; // Reserved + // ebx + u32 l3c_qm_conver_factor : 32; // QM_CTR MSR conversion factor to bytes + // ecx + u32 l3c_qm_rmid_max : 32; // L3 QoS-monitoring max RMID + // edx + u32 l3c_qm_occupancy : 1, // L3 QoS occupancy monitoring + l3c_qm_mbm_total : 1, // L3 QoS total bandwidth monitoring + l3c_qm_mbm_local : 1, // L3 QoS local bandwidth monitoring + : 29; // Reserved +}; + +/* + * Leaf 0x10 + * Intel RDT / AMD PQoS allocation + */ + +struct leaf_0x10_0 { + // eax + u32 : 32; // Reserved + // ebx + u32 : 1, // Reserved + cat_l3 : 1, // L3 Cache Allocation Technology + cat_l2 : 1, // L2 Cache Allocation Technology + mba : 1, // Memory Bandwidth Allocation + : 28; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +struct leaf_0x10_n { + // eax + u32 cat_cbm_len : 5, // L3/L2_CAT capacity bitmask length, minus-one notation + : 27; // Reserved + // ebx + u32 cat_units_bitmap : 32; // L3/L2_CAT allocation units bitmap + // ecx + u32 : 1, // Reserved + l3_cat_cos_infreq_updates : 1, // L3_CAT COS updates should be infrequent + cat_cdp_supported : 1, // L3/L2_CAT Code and Data Prioritization + cat_sparse_1s : 1, // L3/L2_CAT non-contiguous 1s value + : 28; // Reserved + // edx + u32 cat_cos_max : 16, // L3/L2_CAT max Class of Service + : 16; // Reserved +}; + +#define LEAF_0x10_SUBLEAF_N_FIRST 1 +#define LEAF_0x10_SUBLEAF_N_LAST 2 + +struct leaf_0x10_3 { + // eax + u32 mba_max_delay : 12, // Max MBA throttling value; minus-one notation + : 20; // Reserved + // ebx + u32 : 32; // Reserved + // ecx + u32 mba_per_thread : 1, // Per-thread MBA controls + : 1, // Reserved + mba_delay_linear : 1, // Delay values are linear + : 29; // Reserved + // edx + u32 mba_cos_max : 16, // MBA max Class of Service + : 16; // Reserved +}; + +/* + * Leaf 0x12 + * Intel SGX (Software Guard Extensions) + */ + +struct leaf_0x12_0 { + // eax + u32 sgx1 : 1, // SGX1 leaf functions + sgx2 : 1, // SGX2 leaf functions + : 3, // Reserved + enclv_leaves : 1, // ENCLV leaves + encls_leaves : 1, // ENCLS leaves + enclu_everifyreport2 : 1, // ENCLU leaf EVERIFYREPORT2 + : 2, // Reserved + encls_eupdatesvn : 1, // ENCLS leaf EUPDATESVN + enclu_edeccssa : 1, // ENCLU leaf EDECCSSA + : 20; // Reserved + // ebx + u32 miscselect_exinfo : 1, // SSA.MISC frame: Enclave #PF and #GP reporting + miscselect_cpinfo : 1, // SSA.MISC frame: Enclave #CP reporting + : 30; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 max_enclave_sz_not64 : 8, // Maximum enclave size in non-64-bit mode (log2) + max_enclave_sz_64 : 8, // Maximum enclave size in 64-bit mode (log2) + : 16; // Reserved +}; + +struct leaf_0x12_1 { + // eax + u32 secs_attr_init : 1, // Enclave initialized by EINIT + secs_attr_debug : 1, // Enclave permits debugger read/write + secs_attr_mode64bit : 1, // Enclave runs in 64-bit mode + : 1, // Reserved + secs_attr_provisionkey : 1, // Provisioning key + secs_attr_einittoken_key : 1, // EINIT token key + secs_attr_cet : 1, // CET attributes + secs_attr_kss : 1, // Key Separation and Sharing + : 2, // Reserved + secs_attr_aexnotify : 1, // Enclave threads: AEX notifications + : 21; // Reserved + // ebx + u32 : 32; // Reserved + // ecx + u32 xfrm_x87 : 1, // Enclave XFRM.X87 + xfrm_sse : 1, // Enclave XFRM.SEE + xfrm_avx : 1, // Enclave XFRM.AVX + xfrm_mpx_bndregs : 1, // Enclave XFRM.BNDREGS (MPX BND0-BND3 registers) + xfrm_mpx_bndcsr : 1, // Enclave XFRM.BNDCSR (MPX BNDCFGU/BNDSTATUS registers) + xfrm_avx512_opmask : 1, // Enclave XFRM.OPMASK (AVX-512 k0-k7 registers) + xfrm_avx512_zmm_hi256 : 1, // Enclave XFRM.ZMM_Hi256 (AVX-512 ZMM0->ZMM7/15 registers) + xfrm_avx512_hi16_zmm : 1, // Enclave XFRM.HI16_ZMM (AVX-512 ZMM16->ZMM31 registers) + : 1, // Reserved + xfrm_pkru : 1, // Enclave XFRM.PKRU (XSAVE PKRU registers) + : 7, // Reserved + xfrm_tileconfig : 1, // Enclave XFRM.TILECONFIG (AMX can manage TILECONFIG) + xfrm_tiledata : 1, // Enclave XFRM.TILEDATA (AMX can manage TILEDATA) + : 13; // Reserved + // edx + u32 : 32; // Reserved +}; + +struct leaf_0x12_n { + // eax + u32 subleaf_type : 4, // Subleaf type + : 8, // Reserved + epc_sec_base_addr_0 : 20; // EPC section base address, bits[12:31] + // ebx + u32 epc_sec_base_addr_1 : 20, // EPC section base address, bits[32:51] + : 12; // Reserved + // ecx + u32 epc_sec_type : 4, // EPC section type / property encoding + : 8, // Reserved + epc_sec_size_0 : 20; // EPC section size, bits[12:31] + // edx + u32 epc_sec_size_1 : 20, // EPC section size, bits[32:51] + : 12; // Reserved +}; + +#define LEAF_0x12_SUBLEAF_N_FIRST 2 +#define LEAF_0x12_SUBLEAF_N_LAST 31 + +/* + * Leaf 0x14 + * Intel Processor Trace + */ + +struct leaf_0x14_0 { + // eax + u32 pt_max_subleaf : 32; // Maximum leaf 0x14 subleaf + // ebx + u32 cr3_filtering : 1, // IA32_RTIT_CR3_MATCH is accessible + psb_cyc : 1, // Configurable PSB and cycle-accurate mode + ip_filtering : 1, // IP/TraceStop filtering; Warm-reset PT MSRs preservation + mtc_timing : 1, // MTC timing packet; COFI-based packets suppression + ptwrite : 1, // PTWRITE instruction + power_event_trace : 1, // Power Event Trace + psb_pmi_preserve : 1, // PSB and PMI preservation + event_trace : 1, // Event Trace packet generation + tnt_disable : 1, // TNT packet generation disable + : 23; // Reserved + // ecx + u32 topa_output : 1, // ToPA output scheme + topa_multiple_entries : 1, // ToPA tables can hold multiple entries + single_range_output : 1, // Single-range output + trance_transport_output : 1, // Trace Transport subsystem output + : 27, // Reserved + ip_payloads_lip : 1; // IP payloads have LIP values (CS base included) + // edx + u32 : 32; // Reserved +}; + +struct leaf_0x14_1 { + // eax + u32 num_address_ranges : 3, // Number of configurable Address Ranges + : 13, // Reserved + mtc_periods_bmp : 16; // MTC period encodings bitmap + // ebx + u32 cycle_thresholds_bmp : 16, // Cycle Threshold encodings bitmap + psb_periods_bmp : 16; // Configurable PSB frequency encodings bitmap + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x15 + * Intel TSC (Time Stamp Counter) + */ + +struct leaf_0x15_0 { + // eax + u32 tsc_denominator : 32; // Denominator of the TSC/'core crystal clock' ratio + // ebx + u32 tsc_numerator : 32; // Numerator of the TSC/'core crystal clock' ratio + // ecx + u32 cpu_crystal_hz : 32; // Core crystal clock nominal frequency, in Hz + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x16 + * Intel processor frequency + */ + +struct leaf_0x16_0 { + // eax + u32 cpu_base_mhz : 16, // Processor base frequency, in MHz + : 16; // Reserved + // ebx + u32 cpu_max_mhz : 16, // Processor max frequency, in MHz + : 16; // Reserved + // ecx + u32 bus_mhz : 16, // Bus reference frequency, in MHz + : 16; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x17 + * Intel SoC vendor attributes + */ + +struct leaf_0x17_0 { + // eax + u32 soc_max_subleaf : 32; // Maximum leaf 0x17 subleaf + // ebx + u32 soc_vendor_id : 16, // SoC vendor ID + is_vendor_scheme : 1, // Assigned by industry enumeration scheme (not Intel) + : 15; // Reserved + // ecx + u32 soc_proj_id : 32; // SoC project ID, assigned by vendor + // edx + u32 soc_stepping_id : 32; // Soc project stepping ID, assigned by vendor +}; + +struct leaf_0x17_n { + // eax + u32 vendor_brand_a : 32; // Vendor Brand ID string, bytes subleaf_nr * (0 -> 3) + // ebx + u32 vendor_brand_b : 32; // Vendor Brand ID string, bytes subleaf_nr * (4 -> 7) + // ecx + u32 vendor_brand_c : 32; // Vendor Brand ID string, bytes subleaf_nr * (8 -> 11) + // edx + u32 vendor_brand_d : 32; // Vendor Brand ID string, bytes subleaf_nr * (12 -> 15) +}; + +#define LEAF_0x17_SUBLEAF_N_FIRST 1 +#define LEAF_0x17_SUBLEAF_N_LAST 3 + +/* + * Leaf 0x18 + * Intel deterministic address translation (TLB) parameters + */ + +struct leaf_0x18_n { + // eax + u32 tlb_max_subleaf : 32; // Maximum leaf 0x18 subleaf + // ebx + u32 tlb_4k_page : 1, // TLB supports 4KB-page entries + tlb_2m_page : 1, // TLB supports 2MB-page entries + tlb_4m_page : 1, // TLB supports 4MB-page entries + tlb_1g_page : 1, // TLB supports 1GB-page entries + : 4, // Reserved + hard_partitioning : 3, // Partitioning between logical CPUs + : 5, // Reserved + n_way_associative : 16; // Ways of associativity + // ecx + u32 n_sets : 32; // Number of sets + // edx + u32 tlb_type : 5, // Translation cache type (TLB type) + tlb_cache_level : 3, // Translation cache level (1-based) + is_fully_associative : 1, // Fully-associative + : 5, // Reserved + tlb_max_addressible_ids : 12, // Max number of addressable IDs - 1 + : 6; // Reserved +}; + +#define LEAF_0x18_SUBLEAF_N_FIRST 0 +#define LEAF_0x18_SUBLEAF_N_LAST 31 + +/* + * Leaf 0x19 + * Intel key locker + */ + +struct leaf_0x19_0 { + // eax + u32 kl_cpl0_only : 1, // CPL0-only key Locker restriction + kl_no_encrypt : 1, // No-encrypt key locker restriction + kl_no_decrypt : 1, // No-decrypt key locker restriction + : 29; // Reserved + // ebx + u32 aes_keylocker : 1, // AES key locker instructions + : 1, // Reserved + aes_keylocker_wide : 1, // AES wide key locker instructions + : 1, // Reserved + kl_msr_iwkey : 1, // Key locker MSRs and IWKEY backups + : 27; // Reserved + // ecx + u32 loadiwkey_no_backup : 1, // LOADIWKEY NoBackup parameter + iwkey_rand : 1, // IWKEY randomization + : 30; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x1a + * Intel hybrid CPUs identification (e.g. Atom, Core) + */ + +struct leaf_0x1a_0 { + // eax + u32 core_native_model : 24, // This core's native model ID + core_type : 8; // This core's type + // ebx + u32 : 32; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x1b + * Intel PCONFIG (Platform configuration) + */ + +struct leaf_0x1b_n { + // eax + u32 pconfig_subleaf_type : 12, // CPUID 0x1b subleaf type + : 20; // Reserved + // ebx + u32 pconfig_target_id_x : 32; // A supported PCONFIG target ID + // ecx + u32 pconfig_target_id_y : 32; // A supported PCONFIG target ID + // edx + u32 pconfig_target_id_z : 32; // A supported PCONFIG target ID +}; + +#define LEAF_0x1b_SUBLEAF_N_FIRST 0 +#define LEAF_0x1b_SUBLEAF_N_LAST 31 + +/* + * Leaf 0x1c + * Intel LBR (Last Branch Record) + */ + +struct leaf_0x1c_0 { + // eax + u32 lbr_depth_mask : 8, // Max LBR stack depth bitmask + : 22, // Reserved + lbr_deep_c_reset : 1, // LBRs maybe cleared on MWAIT C-state > C1 + lbr_ip_is_lip : 1; // LBR IP contain Last IP (otherwise effective IP) + // ebx + u32 lbr_cpl : 1, // CPL filtering + lbr_branch_filter : 1, // Branch filtering + lbr_call_stack : 1, // Call-stack mode + : 29; // Reserved + // ecx + u32 lbr_mispredict : 1, // Branch misprediction bit + lbr_timed_lbr : 1, // Timed LBRs (CPU cycles since last LBR entry) + lbr_branch_type : 1, // Branch type field + : 13, // Reserved + lbr_events_gpc_bmp : 4, // PMU-events logging support + : 12; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x1d + * Intel AMX (Advanced Matrix Extensions) tile information + */ + +struct leaf_0x1d_0 { + // eax + u32 amx_max_palette : 32; // Highest palette ID / subleaf ID + // ebx + u32 : 32; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +struct leaf_0x1d_1 { + // eax + u32 amx_palette_size : 16, // AMX palette total tiles size, in bytes + amx_tile_size : 16; // AMX single tile's size, in bytes + // ebx + u32 amx_tile_row_size : 16, // AMX tile single row's size, in bytes + amx_palette_nr_tiles : 16; // AMX palette number of tiles + // ecx + u32 amx_tile_nr_rows : 16, // AMX tile max number of rows + : 16; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x1e + * Intel TMUL (Tile-matrix Multiply) + */ + +struct leaf_0x1e_0 { + // eax + u32 : 32; // Reserved + // ebx + u32 tmul_maxk : 8, // TMUL unit maximum height, K (rows or columns) + tmul_maxn : 16, // TMUL unit maximum SIMD dimension, N (column bytes) + : 8; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x1f + * Intel extended topology v2 + */ + +struct leaf_0x1f_n { + // eax + u32 x2apic_id_shift : 5, // Bit width of this level (previous levels inclusive) + : 27; // Reserved + // ebx + u32 domain_lcpus_count : 16, // Logical CPUs count across all instances of this domain + : 16; // Reserved + // ecx + u32 domain_level : 8, // This domain level (subleaf ID) + domain_type : 8, // This domain type + : 16; // Reserved + // edx + u32 x2apic_id : 32; // x2APIC ID of current logical CPU +}; + +#define LEAF_0x1f_SUBLEAF_N_FIRST 0 +#define LEAF_0x1f_SUBLEAF_N_LAST 5 + +/* + * Leaf 0x20 + * Intel HRESET (History Reset) + */ + +struct leaf_0x20_0 { + // eax + u32 hreset_nr_subleaves : 32; // CPUID 0x20 max subleaf + 1 + // ebx + u32 hreset_thread_director : 1, // Intel thread director HRESET + : 31; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x21 + * Intel TD (Trust Domain) + */ + +struct leaf_0x21_0 { + // eax + u32 : 32; // Reserved + // ebx + u32 tdx_vendorid_0 : 32; // TDX vendor ID string bytes 0 - 3 + // ecx + u32 tdx_vendorid_2 : 32; // CPU vendor ID string bytes 8 - 11 + // edx + u32 tdx_vendorid_1 : 32; // CPU vendor ID string bytes 4 - 7 +}; + +/* + * Leaf 0x23 + * Intel Architectural Performance Monitoring Extended (ArchPerfmonExt) + */ + +struct leaf_0x23_0 { + // eax + u32 subleaf_0 : 1, // Subleaf 0, this subleaf + counters_subleaf : 1, // Subleaf 1, PMU counter bitmaps + acr_subleaf : 1, // Subleaf 2, Auto Counter Reload bitmaps + events_subleaf : 1, // Subleaf 3, PMU event bitmaps + pebs_caps_subleaf : 1, // Subleaf 4, PEBS capabilities + pebs_subleaf : 1, // Subleaf 5, Arch PEBS bitmaps + : 26; // Reserved + // ebx + u32 unitmask2 : 1, // IA32_PERFEVTSELx MSRs UnitMask2 bit + eq : 1, // IA32_PERFEVTSELx MSRs EQ bit + rdpmc_user_disable : 1, // RDPMC userspace disable + : 29; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +struct leaf_0x23_1 { + // eax + u32 gp_counters : 32; // Bitmap of general-purpose PMU counters + // ebx + u32 fixed_counters : 32; // Bitmap of fixed PMU counters + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +struct leaf_0x23_2 { + // eax + u32 acr_gp_reload : 32; // Bitmap of general-purpose counters that can be reloaded + // ebx + u32 acr_fixed_reload : 32; // Bitmap of fixed counters that can be reloaded + // ecx + u32 acr_gp_trigger : 32; // Bitmap of general-purpose counters that can trigger reloads + // edx + u32 acr_fixed_trigger : 32; // Bitmap of fixed counters that can trigger reloads +}; + +struct leaf_0x23_3 { + // eax + u32 core_cycles_evt : 1, // Core cycles event + insn_retired_evt : 1, // Instructions retired event + ref_cycles_evt : 1, // Reference cycles event + llc_refs_evt : 1, // Last-level cache references event + llc_misses_evt : 1, // Last-level cache misses event + br_insn_ret_evt : 1, // Branch instruction retired event + br_mispr_evt : 1, // Branch mispredict retired event + td_slots_evt : 1, // Topdown slots event + td_backend_bound_evt : 1, // Topdown backend bound event + td_bad_spec_evt : 1, // Topdown bad speculation event + td_frontend_bound_evt : 1, // Topdown frontend bound event + td_retiring_evt : 1, // Topdown retiring event + : 20; // Reserved + // ebx + u32 : 32; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +struct leaf_0x23_4 { + // eax + u32 : 32; // Reserved + // ebx + u32 : 3, // Reserved + allow_in_record : 1, // ALLOW_IN_RECORD bit in MSRs + counters_gp : 1, // Counters group sub-group general-purpose counters + counters_fixed : 1, // Counters group sub-group fixed-function counters + counters_metrics : 1, // Counters group sub-group performance metrics + : 1, // Reserved + lbr : 2, // LBR group + : 6, // Reserved + xer : 8, // XER group + : 5, // Reserved + gpr : 1, // GPR group + aux : 1, // AUX group + : 1; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +struct leaf_0x23_5 { + // eax + u32 pebs_gp : 32; // Architectural PEBS general-purpose counters + // ebx + u32 pebs_pdist_gp : 32; // Architectural PEBS PDIST general-purpose counters + // ecx + u32 pebs_fixed : 32; // Architectural PEBS fixed counters + // edx + u32 pebs_pdist_fixed : 32; // Architectural PEBS PDIST fixed counters +}; + +/* + * Leaf 0x40000000 + * Maximum hypervisor leaf + hypervisor vendor string + */ + +struct leaf_0x40000000_0 { + // eax + u32 max_hyp_leaf : 32; // Maximum hypervisor leaf + // ebx + u32 hypervisor_id_0 : 32; // Hypervisor ID string bytes 0 - 3 + // ecx + u32 hypervisor_id_1 : 32; // Hypervisor ID string bytes 4 - 7 + // edx + u32 hypervisor_id_2 : 32; // Hypervisor ID string bytes 8 - 11 +}; + +/* + * Leaf 0x4c780001 + * Linux-defined synthetic feature flags + */ + +struct leaf_0x4c780001_0 { + // eax + u32 cxmmx : 1, // Cyrix MMX extensions + k6_mtrr : 1, // AMD K6 nonstandard MTRRs + cyrix_arr : 1, // Cyrix ARRs (= MTRRs) + centaur_mcr : 1, // Centaur MCRs (= MTRRs) + k8 : 1, // Opteron, Athlon64 + zen5 : 1, // CPU based on Zen5 micro-architecture + zen6 : 1, // CPU based on Zen6 micro-architecture + : 1, // Reserved + constant_tsc : 1, // TSC ticks at a constant rate + up : 1, // SMP kernel running on UP + art : 1, // Always running timer (ART) + arch_perfmon : 1, // Intel Architectural PerfMon + pebs : 1, // Precise-Event Based Sampling + bts : 1, // Branch Trace Store + syscall32 : 1, // SYSCALL in IA32 userspace + sysenter32 : 1, // SYSENTER in IA32 userspace + rep_good : 1, // REP microcode works well + amd_lbr_v2 : 1, // AMD Last Branch Record Extension version 2 + clear_cpu_buf : 1, // Clear CPU buffers using VERW + acc_power : 1, // AMD Accumulated Power Mechanism + nopl : 1, // The NOPL instructions + always : 1, // Always-present feature + xtopology : 1, // CPU topology enumeration extensions + tsc_reliable : 1, // TSC is known to be reliable + nonstop_tsc : 1, // TSC does not stop in C states + cpuid : 1, // CPU has the CPUID instruction + extd_apicid : 1, // Extended APIC ID (8 bits) + amd_dcm : 1, // AMD multi-node processor + aperfmperf : 1, // APERF/MPERF MSRs: P-State hardware coordination feedback + rapl : 1, // AMD/Hygon RAPL interface + nonstop_tsc_s3 : 1, // TSC does not stop in S3 state + tsc_known_freq : 1; // TSC has known frequency + // ebx + u32 ring3mwait : 1, // Ring 3 MONITOR/MWAIT instructions + cpuid_fault : 1, // Intel CPUID faulting + cpb : 1, // AMD Core Performance Boost + epb : 1, // IA32_ENERGY_PERF_BIAS support + cat_l3 : 1, // Cache Allocation Technology L3 + cat_l2 : 1, // Cache Allocation Technology L2 + cdp_l3 : 1, // Code and Data Prioritization L3 + tdx_host_platform : 1, // Platform supports being a TDX host + hw_pstate : 1, // AMD Hardware P-state control + proc_feedback : 1, // AMD Processor Feedback Interface + xcompacted : 1, // Use compacted XSTATE (XSAVES or XSAVEC) + pti : 1, // Kernel Page Table Isolation enabled + kernel_ibrs : 1, // Set/clear IBRS on kernel entry/exit + rsb_vmexit : 1, // Fill RSB on VM-Exit + intel_ppin : 1, // Intel Processor Inventory Number + cdp_l2 : 1, // Code and Data Prioritization L2 + msr_spec_ctrl : 1, // MSR SPEC_CTRL is implemented + ssbd : 1, // Speculative Store Bypass Disable + mba : 1, // Memory Bandwidth Allocation + rsb_ctxsw : 1, // Fill RSB on context switches + perfmon_v2 : 1, // AMD Performance Monitoring Version 2 + : 1, // Reserved + use_ibrs_fw : 1, // Use IBRS during runtime firmware calls + ss_bypass_disable : 1, // Disable Speculative Store Bypass + ls_cfg_ssbd : 1, // AMD SSBD implementation via LS_CFG MSR + ibrs : 1, // Indirect Branch Restricted Speculation + ibpb : 1, // Indirect Branch Prediction Barrier (without RSB flush guarantee) + stibp : 1, // Single Thread Indirect Branch Predictors + zen : 1, // Generic flag for all Zen and newer + l1tf_pteinv : 1, // L1TF workaround PTE inversion + ibrs_enhanced : 1, // Enhanced IBRS + msr_ia32_feat_ctl : 1; // MSR IA32_FEAT_CTL configured + // ecx + u32 tpr_shadow : 1, // Intel TPR Shadow + flexpriority : 1, // Intel FlexPriority + ept : 1, // Intel Extended Page Table + vpid : 1, // Intel Virtual Processor ID + coherency_sfw_no : 1, // SNP cache coherency software work around not needed + : 10, // Reserved + vmmcall : 1, // Prefer VMMCALL to VMCALL + xenpv : 1, // Xen paravirtual guest + ept_ad : 1, // Intel Extended Page Table access-dirty bit + VMCALL : 1, // Hypervisor supports the VMCALL instruction + vmw_vmmcall : 1, // VMware prefers the VMMCALL instruction + pvunlock : 1, // PV unlock function + vcpupreempt : 1, // PV vcpu_is_preempted function + tdx_guest : 1, // Intel Trust Domain Extensions Guest + : 9; // Reserved + // edx + u32 cqm_llc : 1, // LLC QoS + cqm_occup_llc : 1, // LLC occupancy monitoring + cqm_mbm_total : 1, // LLC Total MBM monitoring + cqm_mbm_local : 1, // LLC Local MBM monitoring + fence_swapgs_user : 1, // LFENCE in user entry SWAPGS path + fence_swapgs_kernel : 1, // LFENCE in kernel entry SWAPGS path + split_lock_detect : 1, // #AC for split lock + per_thread_mba : 1, // Per-thread Memory Bandwidth Allocation + sgx1 : 1, // SGX Basic + sgx2 : 1, // SGX Enclave Dynamic Memory Management (EDMM) + entry_ibpb : 1, // Issue an IBPB on kernel entry + rrsba_ctrl : 1, // RET prediction control + retpoline : 1, // Generic Retpoline mitigation for Spectre variant 2 + retpoline_lfence : 1, // Use LFENCE for Spectre variant 2 + rethunk : 1, // Use Return THUNK + unret : 1, // AMD BTB untrain return + use_ibpb_fw : 1, // Use IBPB during runtime firmware calls + rsb_vmexit_lite : 1, // Fill RSB on VM exit when EIBRS is enabled + sgx_edeccssa : 1, // SGX EDECCSSA user leaf function + call_depth : 1, // Call depth tracking for RSB stuffing + msr_tsx_ctrl : 1, // MSR IA32_TSX_CTRL (Intel) implemented + smba : 1, // Slow Memory Bandwidth Allocation + bmec : 1, // Bandwidth Monitoring Event Configuration + user_shstk : 1, // Shadow stack support for user mode applications + srso : 1, // AMD BTB untrain RETs + srso_alias : 1, // AMD BTB untrain RETs through aliasing + ibpb_on_vmexit : 1, // Issue an IBPB only on VMEXIT + apic_msrs_fence : 1, // IA32_TSC_DEADLINE and X2APIC MSRs need fencing + zen2 : 1, // CPU based on Zen2 microarchitecture + zen3 : 1, // CPU based on Zen3 microarchitecture + zen4 : 1, // CPU based on Zen4 microarchitecture + zen1 : 1; // CPU based on Zen1 microarchitecture +}; + +struct leaf_0x4c780001_1 { + // eax + u32 overflow_recov : 1, // MCA overflow recovery support + succor : 1, // Uncorrectable error containment and recovery + : 1, // Reserved + smca : 1, // Scalable MCA + : 28; // Reserved + // ebx + u32 amd_lbr_pmc_freeze : 1, // AMD LBR and PMC Freeze + clear_bhb_loop : 1, // Clear branch history at SYSCALL entry using SW loop + bhi_ctrl : 1, // BHI_DIS_S HW control available + clear_bhb_hw : 1, // BHI_DIS_S HW control enabled + clear_bhb_vmexit : 1, // Clear branch history at VMEXIT using SW loop + amd_fast_cppc : 1, // AMD fast Collaborative Processor Performance Control + amd_htr_cores : 1, // Heterogeneous Core Topology + amd_workload_class : 1, // Workload Classification + prefer_ymm : 1, // Avoid ZMM registers due to downclocking + apx : 1, // Advanced Performance Extensions + indirect_thunk_its : 1, // Use thunk for indirect branches in lower half of cache line + tsa_sq_no : 1, // AMD CPU not vulnerable to TSA-SQ + tsa_l1_no : 1, // AMD CPU not vulnerable to TSA-L1 + clear_cpu_buf_vm : 1, // Clear CPU buffers using VERW before VMRUN + ibpb_exit_to_user : 1, // Use IBPB on exit-to-userspace, see VMSCAPE bug + : 17; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x4c780002 + * Linux-defined synthetic CPU bug flags + */ + +struct leaf_0x4c780002_0 { + // eax + u32 f00f : 1, // Intel F00F + fdiv : 1, // FPU FDIV + coma : 1, // Cyrix 6x86 coma + amd_tlb_mmatch : 1, // AMD Erratum 383 + amd_apic_c1e : 1, // AMD Erratum 400 + bug_11ap : 1, // Bad local APIC aka 11AP + fxsave_leak : 1, // FXSAVE leaks FOP/FIP/FOP + clflush_monitor : 1, // AAI65, CLFLUSH required before MONITOR + sysret_ss_attrs : 1, // SYSRET does not fix up SS attributes + espfix : 1, // IRET to 16-bit SS corrupts ESP/RSP high bits (x86-32) + null_seg : 1, // Setting a selector to NULL preserves the base + swapgs_fence : 1, // SWAPGS without input dep on GS + monitor : 1, // IPI required to wake up remote CPU + amd_e400 : 1, // CPU is among the affected by Erratum 400 + cpu_meltdown : 1, // CPU affected by meltdown; needs kernel page table isolation + spectre_v1 : 1, // CPU affected by Spectre variant 1 with conditional branches + specture_v2 : 1, // CPU affected by Spectre variant 2 with indirect branches + spec_store_bypass : 1, // CPU affected by speculative store bypass attack + l1tf : 1, // CPU affected by L1 Terminal Fault + mds : 1, // CPU affected by Microarchitectural data sampling + msbds_only : 1, // Microarchitectural data sampling: CPU only affected by the MSDBS variant + swapgs : 1, // CPU affected by speculation through SWAPGS + taa : 1, // CPU is affected by TSX Async Abort (TAA) + itlb_multihit : 1, // CPU may incur MCE during certain page attribute changes + srbds : 1, // CPU may leak RNG bits if not mitigated + mmio_stale_data : 1, // CPU affected by Processor MMIO Stale Data vulnerabilities + : 1, // Reserved + retbleed : 1, // CPU affected by Retbleed + eibrs_pbrsb : 1, // EIBRS is vulnerable to Post Barrier RSB Predictions + smt_rsb : 1, // CPU vulnerable to Cross-Thread Return Address Predictions + gds : 1, // CPU affected by Gather Data Sampling + tdx_pw_mce : 1; // CPU may incur #MC if non-TD software does partial write to TDX private memory + // ebx + u32 srso : 1, // AMD SRSO bug + div0 : 1, // AMD DIV0 speculation bug + rfds : 1, // CPU vulnerable to Register File Data Sampling + bhi : 1, // CPU affected by Branch History Injection + ibpb_no_ret : 1, // IBPB omits return target predictions + spectre_v2_user : 1, // CPU affected by Spectre variant 2 between user processes + old_microcode : 1, // CPU has old microcode; it must be vulnerable to something + its : 1, // CPU affected by Indirect Target Selection + its_native_only : 1, // CPU affected by ITS; VMX is not affected + tsa : 1, // CPU affected by Transient Scheduler Attacks + vmscape : 1, // CPU affected by VMSCAPE attacks from guests + : 21; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x80000000 + * Maximum extended leaf + CPU vendor string + */ + +struct leaf_0x80000000_0 { + // eax + u32 max_ext_leaf : 32; // Maximum extended CPUID leaf + // ebx + u32 cpu_vendorid_0 : 32; // Vendor ID string bytes 0 - 3 + // ecx + u32 cpu_vendorid_2 : 32; // Vendor ID string bytes 8 - 11 + // edx + u32 cpu_vendorid_1 : 32; // Vendor ID string bytes 4 - 7 +}; + +/* + * Leaf 0x80000001 + * Extended CPU features + */ + +struct leaf_0x80000001_0 { + // eax + u32 e_stepping_id : 4, // Stepping ID + e_base_model : 4, // Base processor model + e_base_family : 4, // Base processor family + e_base_type : 2, // Base processor type (Transmeta) + : 2, // Reserved + e_ext_model : 4, // Extended processor model + e_ext_family : 8, // Extended processor family + : 4; // Reserved + // ebx + u32 brand_id : 16, // Brand ID + : 12, // Reserved + pkg_type : 4; // Package type + // ecx + u32 lahf_lm : 1, // LAHF and SAHF in 64-bit mode + cmp_legacy : 1, // Multi-processing legacy mode (No HT) + svm : 1, // Secure Virtual Machine + extapic : 1, // Extended APIC space + cr8_legacy : 1, // LOCK MOV CR0 means MOV CR8 + lzcnt_abm : 1, // LZCNT advanced bit manipulation + sse4a : 1, // SSE4A support + misaligned_sse : 1, // Misaligned SSE mode + _3dnow_prefetch : 1, // 3DNow PREFETCH/PREFETCHW support + osvw : 1, // OS visible workaround + ibs : 1, // Instruction based sampling + xop : 1, // XOP: extended operation (AVX instructions) + skinit : 1, // SKINIT/STGI support + wdt : 1, // Watchdog timer support + : 1, // Reserved + lwp : 1, // Lightweight profiling + fma4 : 1, // 4-operand FMA instruction + tce : 1, // Translation cache extension + : 1, // Reserved + nodeid_msr : 1, // NodeId MSR (0xc001100c) + : 1, // Reserved + tbm : 1, // Trailing bit manipulations + topoext : 1, // Topology Extensions (leaf 0x8000001d) + perfctr_core : 1, // Core performance counter extensions + perfctr_nb : 1, // NB/DF performance counter extensions + : 1, // Reserved + data_bp_ext : 1, // Data access breakpoint extension + perf_tsc : 1, // Performance time-stamp counter + perfctr_llc : 1, // LLC (L3) performance counter extensions + mwaitx : 1, // MWAITX/MONITORX support + addr_mask_ext : 1, // Breakpoint address mask extension (to bit 31) + : 1; // Reserved + // edx + u32 e_fpu : 1, // Floating-Point Unit on-chip (x87) + e_vme : 1, // Virtual-8086 Mode Extensions + e_de : 1, // Debugging Extensions + e_pse : 1, // Page Size Extension + e_tsc : 1, // Time Stamp Counter + e_msr : 1, // Model-Specific Registers (RDMSR and WRMSR support) + pae : 1, // Physical Address Extensions + mce : 1, // Machine Check Exception + cx8 : 1, // CMPXCHG8B instruction + apic : 1, // APIC on-chip + : 1, // Reserved + syscall : 1, // SYSCALL and SYSRET instructions + mtrr : 1, // Memory Type Range Registers + pge : 1, // Page Global Extensions + mca : 1, // Machine Check Architecture + cmov : 1, // Conditional Move Instruction + pat : 1, // Page Attribute Table + pse36 : 1, // Page Size Extension (36-bit) + : 1, // Reserved + obsolete_mp_bit : 1, // Out-of-spec AMD Multiprocessing bit + nx : 1, // No-execute page protection + : 1, // Reserved + mmxext : 1, // AMD MMX extensions + e_mmx : 1, // MMX instructions + e_fxsr : 1, // FXSAVE and FXRSTOR instructions + fxsr_opt : 1, // FXSAVE and FXRSTOR optimizations + page1gb : 1, // 1-GB large page support + rdtscp : 1, // RDTSCP instruction + : 1, // Reserved + lm : 1, // Long mode (x86-64, 64-bit support) + _3dnowext : 1, // AMD 3DNow extensions + _3dnow : 1; // 3DNow instructions +}; + +/* + * Leaf 0x80000002 + * CPU brand ID string, bytes 0 - 15 + */ + +struct leaf_0x80000002_0 { + // eax + u32 cpu_brandid_0 : 32; // CPU brand ID string, bytes 0 - 3 + // ebx + u32 cpu_brandid_1 : 32; // CPU brand ID string, bytes 4 - 7 + // ecx + u32 cpu_brandid_2 : 32; // CPU brand ID string, bytes 8 - 11 + // edx + u32 cpu_brandid_3 : 32; // CPU brand ID string, bytes 12 - 15 +}; + +/* + * Leaf 0x80000003 + * CPU brand ID string, bytes 16 - 31 + */ + +struct leaf_0x80000003_0 { + // eax + u32 cpu_brandid_4 : 32; // CPU brand ID string bytes, 16 - 19 + // ebx + u32 cpu_brandid_5 : 32; // CPU brand ID string bytes, 20 - 23 + // ecx + u32 cpu_brandid_6 : 32; // CPU brand ID string bytes, 24 - 27 + // edx + u32 cpu_brandid_7 : 32; // CPU brand ID string bytes, 28 - 31 +}; + +/* + * Leaf 0x80000004 + * CPU brand ID string, bytes 32 - 47 + */ + +struct leaf_0x80000004_0 { + // eax + u32 cpu_brandid_8 : 32; // CPU brand ID string, bytes 32 - 35 + // ebx + u32 cpu_brandid_9 : 32; // CPU brand ID string, bytes 36 - 39 + // ecx + u32 cpu_brandid_10 : 32; // CPU brand ID string, bytes 40 - 43 + // edx + u32 cpu_brandid_11 : 32; // CPU brand ID string, bytes 44 - 47 +}; + +/* + * Leaf 0x80000005 + * AMD/Transmeta L1 cache and TLB + */ + +struct leaf_0x80000005_0 { + // eax + u32 l1_itlb_2m_4m_nentries : 8, // L1 ITLB #entries, 2M and 4M pages + l1_itlb_2m_4m_assoc : 8, // L1 ITLB associativity, 2M and 4M pages + l1_dtlb_2m_4m_nentries : 8, // L1 DTLB #entries, 2M and 4M pages + l1_dtlb_2m_4m_assoc : 8; // L1 DTLB associativity, 2M and 4M pages + // ebx + u32 l1_itlb_4k_nentries : 8, // L1 ITLB #entries, 4K pages + l1_itlb_4k_assoc : 8, // L1 ITLB associativity, 4K pages + l1_dtlb_4k_nentries : 8, // L1 DTLB #entries, 4K pages + l1_dtlb_4k_assoc : 8; // L1 DTLB associativity, 4K pages + // ecx + u32 l1_dcache_line_size : 8, // L1 dcache line size, in bytes + l1_dcache_nlines : 8, // L1 dcache lines per tag + l1_dcache_assoc : 8, // L1 dcache associativity + l1_dcache_size_kb : 8; // L1 dcache size, in KB + // edx + u32 l1_icache_line_size : 8, // L1 icache line size, in bytes + l1_icache_nlines : 8, // L1 icache lines per tag + l1_icache_assoc : 8, // L1 icache associativity + l1_icache_size_kb : 8; // L1 icache size, in KB +}; + +/* + * Leaf 0x80000006 + * (Mostly AMD) L2/L3 cache and TLB + */ + +struct leaf_0x80000006_0 { + // eax + u32 l2_itlb_2m_4m_nentries : 12, // L2 iTLB #entries, 2M and 4M pages + l2_itlb_2m_4m_assoc : 4, // L2 iTLB associativity, 2M and 4M pages + l2_dtlb_2m_4m_nentries : 12, // L2 dTLB #entries, 2M and 4M pages + l2_dtlb_2m_4m_assoc : 4; // L2 dTLB associativity, 2M and 4M pages + // ebx + u32 l2_itlb_4k_nentries : 12, // L2 iTLB #entries, 4K pages + l2_itlb_4k_assoc : 4, // L2 iTLB associativity, 4K pages + l2_dtlb_4k_nentries : 12, // L2 dTLB #entries, 4K pages + l2_dtlb_4k_assoc : 4; // L2 dTLB associativity, 4K pages + // ecx + u32 l2_line_size : 8, // L2 cache line size, in bytes + l2_nlines : 4, // L2 cache number of lines per tag + l2_assoc : 4, // L2 cache associativity + l2_size_kb : 16; // L2 cache size, in KB + // edx + u32 l3_line_size : 8, // L3 cache line size, in bytes + l3_nlines : 4, // L3 cache number of lines per tag + l3_assoc : 4, // L3 cache associativity + : 2, // Reserved + l3_size_range : 14; // L3 cache size range +}; + +/* + * Leaf 0x80000007 + * CPU power management (mostly AMD) and AMD RAS + */ + +struct leaf_0x80000007_0 { + // eax + u32 : 32; // Reserved + // ebx + u32 mca_overflow_recovery : 1, // MCA overflow conditions not fatal + succor : 1, // Software containment of uncorrectable errors + hw_assert : 1, // Hardware assert MSRs + scalable_mca : 1, // Scalable MCA (MCAX MSRs) + : 28; // Reserved + // ecx + u32 cpu_pwr_sample_ratio : 32; // CPU power sample time ratio + // edx + u32 digital_temp : 1, // Digital temperature sensor + powernow_freq_id : 1, // PowerNOW! frequency scaling + powernow_volt_id : 1, // PowerNOW! voltage scaling + thermal_trip : 1, // THERMTRIP (Thermal Trip) + hw_thermal_control : 1, // Hardware thermal control + sw_thermal_control : 1, // Software thermal control + _100mhz_steps : 1, // 100 MHz multiplier control + hw_pstate : 1, // Hardware P-state control + constant_tsc : 1, // TSC ticks at constant rate across all P and C states + core_perf_boost : 1, // Core performance boost + eff_freq_ro : 1, // Read-only effective frequency interface + proc_feedback : 1, // Processor feedback interface (deprecated) + proc_power_reporting : 1, // Processor power reporting interface + connected_standby : 1, // CPU Connected Standby support + rapl_interface : 1, // Runtime Average Power Limit interface + : 17; // Reserved +}; + +/* + * Leaf 0x80000008 + * CPU capacity parameters and extended feature flags (mostly AMD) + */ + +struct leaf_0x80000008_0 { + // eax + u32 phys_addr_bits : 8, // Max physical address bits + virt_addr_bits : 8, // Max virtual address bits + guest_phys_addr_bits : 8, // Max nested-paging guest physical address bits + : 8; // Reserved + // ebx + u32 clzero : 1, // CLZERO instruction + insn_retired_perf : 1, // Instruction retired counter MSR + xsave_err_ptr : 1, // XSAVE/XRSTOR always saves/restores FPU error pointers + invlpgb : 1, // INVLPGB broadcasts a TLB invalidate + rdpru : 1, // RDPRU (Read Processor Register at User level) + : 1, // Reserved + mba : 1, // Memory Bandwidth Allocation (AMD bit) + : 1, // Reserved + mcommit : 1, // MCOMMIT instruction + wbnoinvd : 1, // WBNOINVD instruction + : 2, // Reserved + ibpb : 1, // Indirect Branch Prediction Barrier + wbinvd_int : 1, // Interruptible WBINVD/WBNOINVD + ibrs : 1, // Indirect Branch Restricted Speculation + stibp : 1, // Single Thread Indirect Branch Prediction mode + ibrs_always_on : 1, // IBRS always-on preferred + stibp_always_on : 1, // STIBP always-on preferred + ibrs_fast : 1, // IBRS is preferred over software solution + ibrs_same_mode : 1, // IBRS provides same mode protection + no_efer_lmsle : 1, // Long-Mode Segment Limit Enable unsupported + tlb_flush_nested : 1, // INVLPGB RAX[5] bit can be set + : 1, // Reserved + amd_ppin : 1, // Protected Processor Inventory Number + amd_ssbd : 1, // Speculative Store Bypass Disable + virt_ssbd : 1, // virtualized SSBD (Speculative Store Bypass Disable) + amd_ssb_no : 1, // SSBD is not needed (fixed in hardware) + cppc : 1, // Collaborative Processor Performance Control + amd_psfd : 1, // Predictive Store Forward Disable + btc_no : 1, // CPU not affected by Branch Type Confusion + ibpb_ret : 1, // IBPB clears RSB/RAS too + branch_sampling : 1; // Branch Sampling + // ecx + u32 cpu_nthreads : 8, // Number of physical threads - 1 + : 4, // Reserved + apicid_coreid_len : 4, // Number of thread core ID bits (shift) in APIC ID + perf_tsc_len : 2, // Performance time-stamp counter size + : 14; // Reserved + // edx + u32 invlpgb_max_pages : 16, // INVLPGB maximum page count + rdpru_max_reg_id : 16; // RDPRU max register ID (ECX input) +}; + +/* + * Leaf 0x8000000a + * AMD SVM (Secure Virtual Machine) + */ + +struct leaf_0x8000000a_0 { + // eax + u32 svm_version : 8, // SVM revision number + : 24; // Reserved + // ebx + u32 svm_nasid : 32; // Number of address space identifiers (ASID) + // ecx + u32 : 4, // Reserved + pml : 1, // Page Modification Logging (PML) + : 27; // Reserved + // edx + u32 nested_pt : 1, // Nested paging + lbr_virt : 1, // LBR virtualization + svm_lock : 1, // SVM lock + nrip_save : 1, // NRIP save support on #VMEXIT + tsc_rate_msr : 1, // MSR based TSC rate control + vmcb_clean : 1, // VMCB clean bits support + flush_by_asid : 1, // Flush by ASID + Extended VMCB TLB_Control + decode_assists : 1, // Decode Assists support + : 2, // Reserved + pause_filter : 1, // Pause intercept filter + : 1, // Reserved + pf_threshold : 1, // Pause filter threshold + avic : 1, // Advanced virtual interrupt controller + : 1, // Reserved + v_vmsave_vmload : 1, // Virtual VMSAVE/VMLOAD (nested virtualization) + v_gif : 1, // Virtualize the Global Interrupt Flag + gmet : 1, // Guest mode execution trap + x2avic : 1, // Virtual x2APIC + sss_check : 1, // Supervisor Shadow Stack restrictions + v_spec_ctrl : 1, // Virtual SPEC_CTRL + ro_gpt : 1, // Read-Only guest page table support + : 1, // Reserved + h_mce_override : 1, // Host MCE override + tlbsync_int : 1, // TLBSYNC intercept + INVLPGB/TLBSYNC in VMCB + nmi_virt : 1, // NMI virtualization + ibs_virt : 1, // IBS Virtualization + ext_lvt_off_chg : 1, // Extended LVT offset fault change + svme_addr_chk : 1, // Guest SVME address check + : 3; // Reserved +}; + +/* + * Leaf 0x80000019 + * AMD TLB characteristics for 1GB pages + */ + +struct leaf_0x80000019_0 { + // eax + u32 l1_itlb_1g_nentries : 12, // L1 iTLB #entries, 1G pages + l1_itlb_1g_assoc : 4, // L1 iTLB associativity, 1G pages + l1_dtlb_1g_nentries : 12, // L1 dTLB #entries, 1G pages + l1_dtlb_1g_assoc : 4; // L1 dTLB associativity, 1G pages + // ebx + u32 l2_itlb_1g_nentries : 12, // L2 iTLB #entries, 1G pages + l2_itlb_1g_assoc : 4, // L2 iTLB associativity, 1G pages + l2_dtlb_1g_nentries : 12, // L2 dTLB #entries, 1G pages + l2_dtlb_1g_assoc : 4; // L2 dTLB associativity, 1G pages + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x8000001a + * AMD instruction optimizations + */ + +struct leaf_0x8000001a_0 { + // eax + u32 fp_128 : 1, // Internal FP/SIMD exec data path is 128-bits wide + movu_preferred : 1, // SSE: MOVU* better than MOVL*/MOVH* + fp_256 : 1, // internal FP/SSE exec data path is 256-bits wide + : 29; // Reserved + // ebx + u32 : 32; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x8000001b + * AMD IBS (Instruction-Based Sampling) + */ + +struct leaf_0x8000001b_0 { + // eax + u32 ibs_flags : 1, // IBS feature flags + ibs_fetch_sampling : 1, // IBS fetch sampling + ibs_op_sampling : 1, // IBS execution sampling + ibs_rdwr_op_counter : 1, // IBS read/write of op counter + ibs_op_count : 1, // IBS OP counting mode + ibs_branch_target : 1, // IBS branch target address reporting + ibs_op_counters_ext : 1, // IBS IbsOpCurCnt/IbsOpMaxCnt extend by 7 bits + ibs_rip_invalid_chk : 1, // IBS invalid RIP indication + ibs_op_branch_fuse : 1, // IBS fused branch micro-op indication + ibs_fetch_ctl_ext : 1, // IBS Fetch Control Extended MSR + ibs_op_data_4 : 1, // IBS op data 4 MSR + ibs_l3_miss_filter : 1, // IBS L3-miss filtering (Zen4+) + : 20; // Reserved + // ebx + u32 : 32; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x8000001c + * AMD LWP (Lightweight Profiling) + */ + +struct leaf_0x8000001c_0 { + // eax + u32 os_lwp_avail : 1, // OS: LWP is available to application programs + os_lpwval : 1, // OS: LWPVAL instruction + os_lwp_ire : 1, // OS: Instructions Retired Event + os_lwp_bre : 1, // OS: Branch Retired Event + os_lwp_dme : 1, // OS: Dcache Miss Event + os_lwp_cnh : 1, // OS: CPU Clocks Not Halted event + os_lwp_rnh : 1, // OS: CPU Reference clocks Not Halted event + : 22, // Reserved + os_lwp_cont : 1, // OS: LWP sampling in continuous mode + os_lwp_ptsc : 1, // OS: Performance Time Stamp Counter in event records + os_lwp_int : 1; // OS: Interrupt on threshold overflow + // ebx + u32 lwp_lwpcb_sz : 8, // Control Block size, in quadwords + lwp_event_sz : 8, // Event record size, in bytes + lwp_max_events : 8, // Max EventID supported + lwp_event_offset : 8; // Control Block events area offset + // ecx + u32 lwp_latency_max : 5, // Cache latency counters number of bits + lwp_data_addr : 1, // Cache miss events report data cache address + lwp_latency_rnd : 3, // Cache latency rounding amount + lwp_version : 7, // LWP version + lwp_buf_min_sz : 8, // LWP event ring buffer min size, 32 event records units + : 4, // Reserved + lwp_branch_predict : 1, // Branches Retired events can be filtered + lwp_ip_filtering : 1, // IP filtering (IPI, IPF, BaseIP, and LimitIP @ LWPCP) + lwp_cache_levels : 1, // Cache-related events: filter by cache level + lwp_cache_latency : 1; // Cache-related events: filter by latency + // edx + u32 hw_lwp_avail : 1, // HW: LWP available + hw_lpwval : 1, // HW: LWPVAL available + hw_lwp_ire : 1, // HW: Instructions Retired Event + hw_lwp_bre : 1, // HW: Branch Retired Event + hw_lwp_dme : 1, // HW: Dcache Miss Event + hw_lwp_cnh : 1, // HW: Clocks Not Halted event + hw_lwp_rnh : 1, // HW: Reference clocks Not Halted event + : 22, // Reserved + hw_lwp_cont : 1, // HW: LWP sampling in continuous mode + hw_lwp_ptsc : 1, // HW: Performance Time Stamp Counter in event records + hw_lwp_int : 1; // HW: Interrupt on threshold overflow +}; + +/* + * Leaf 0x8000001d + * AMD deterministic cache parameters + */ + +struct leaf_0x8000001d_n { + // eax + u32 cache_type : 5, // Cache type field + cache_level : 3, // Cache level (1-based) + cache_self_init : 1, // Self-initializing cache level + fully_associative : 1, // Fully-associative cache + : 4, // Reserved + num_threads_sharing : 12, // Number of logical CPUs sharing cache + : 6; // Reserved + // ebx + u32 cache_linesize : 12, // System coherency line size (0-based) + cache_npartitions : 10, // Physical line partitions (0-based) + cache_nways : 10; // Ways of associativity (0-based) + // ecx + u32 cache_nsets : 31, // Cache number of sets (0-based) + : 1; // Reserved + // edx + u32 wbinvd_rll_no_guarantee : 1, // WBINVD/INVD not guaranteed for Remote Lower-Level caches + ll_inclusive : 1, // Cache is inclusive of Lower-Level caches + : 30; // Reserved +}; + +#define LEAF_0x8000001d_SUBLEAF_N_FIRST 0 +#define LEAF_0x8000001d_SUBLEAF_N_LAST 31 + +/* + * Leaf 0x8000001e + * AMD CPU topology + */ + +struct leaf_0x8000001e_0 { + // eax + u32 ext_apic_id : 32; // Extended APIC ID + // ebx + u32 core_id : 8, // Unique per-socket logical core unit ID + core_nthreads : 8, // #Threads per core (zero-based) + : 16; // Reserved + // ecx + u32 node_id : 8, // Node (die) ID of invoking logical CPU + nnodes_per_socket : 3, // #nodes in invoking logical CPU's package/socket + : 21; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x8000001f + * AMD encrypted memory capabilities (SME/SEV) + */ + +struct leaf_0x8000001f_0 { + // eax + u32 sme : 1, // Secure Memory Encryption + sev : 1, // Secure Encrypted Virtualization + vm_page_flush : 1, // VM Page Flush MSR + sev_encrypted_state : 1, // SEV Encrypted State + sev_nested_paging : 1, // SEV secure nested paging + vm_permission_levels : 1, // VMPL + rpmquery : 1, // RPMQUERY instruction + vmpl_sss : 1, // VMPL supervisor shadow stack + secure_tsc : 1, // Secure TSC + virt_tsc_aux : 1, // Hardware virtualizes TSC_AUX + sme_coherent : 1, // Cache coherency enforcement across encryption domains + req_64bit_hypervisor : 1, // SEV guest mandates 64-bit hypervisor + restricted_injection : 1, // Restricted Injection supported + alternate_injection : 1, // Alternate Injection supported + debug_swap : 1, // SEV-ES: Full debug state swap + disallow_host_ibs : 1, // SEV-ES: Disallowing IBS use by the host + virt_transparent_enc : 1, // Virtual Transparent Encryption + vmgexit_parameter : 1, // SEV_FEATURES: VmgexitParameter + virt_tom_msr : 1, // Virtual TOM MSR + virt_ibs : 1, // SEV-ES guests: IBS state virtualization + : 4, // Reserved + vmsa_reg_protection : 1, // VMSA register protection + smt_protection : 1, // SMT protection + : 2, // Reserved + svsm_page_msr : 1, // SVSM communication page MSR + nested_virt_snp_msr : 1, // VIRT_RMPUPDATE/VIRT_PSMASH MSRs + : 2; // Reserved + // ebx + u32 pte_cbit_pos : 6, // PTE bit number to enable memory encryption + phys_addr_reduction_nbits : 6, // Reduction of phys address space in bits + vmpl_count : 4, // Number of VM permission levels (VMPL) + : 16; // Reserved + // ecx + u32 enc_guests_max : 32; // Max number of simultaneous encrypted guests + // edx + u32 min_sev_asid_no_sev_es : 32; // Minimum ASID for SEV-enabled SEV-ES-disabled guest +}; + +/* + * Leaf 0x80000020 + * AMD PQoS (Platform QoS) extended features + */ + +struct leaf_0x80000020_0 { + // eax + u32 : 32; // Reserved + // ebx + u32 : 1, // Reserved + mba : 1, // Memory Bandwidth Allocation support + smba : 1, // Slow Memory Bandwidth Allocation support + bmec : 1, // Bandwidth Monitoring Event Configuration support + l3rr : 1, // L3 Range Reservation support + abmc : 1, // Assignable Bandwidth Monitoring Counters + sdciae : 1, // Smart Data Cache Injection (SDCI) Allocation Enforcement + : 25; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +struct leaf_0x80000020_1 { + // eax + u32 mba_limit_len : 32; // MBA enforcement limit size + // ebx + u32 : 32; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 mba_cos_max : 32; // MBA max Class of Service number (zero-based) +}; + +struct leaf_0x80000020_2 { + // eax + u32 smba_limit_len : 32; // SMBA enforcement limit size + // ebx + u32 : 32; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 smba_cos_max : 32; // SMBA max Class of Service number (zero-based) +}; + +struct leaf_0x80000020_3 { + // eax + u32 : 32; // Reserved + // ebx + u32 bmec_num_events : 8, // BMEC number of bandwidth events available + : 24; // Reserved + // ecx + u32 bmec_local_reads : 1, // Local NUMA reads can be tracked + bmec_remote_reads : 1, // Remote NUMA reads can be tracked + bmec_local_nontemp_wr : 1, // Local NUMA non-temporal writes can be tracked + bmec_remote_nontemp_wr : 1, // Remote NUMA non-temporal writes can be tracked + bmec_local_slow_mem_rd : 1, // Local NUMA slow-memory reads can be tracked + bmec_remote_slow_mem_rd : 1, // Remote NUMA slow-memory reads can be tracked + bmec_all_dirty_victims : 1, // Dirty QoS victims to all types of memory can be tracked + : 25; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x80000021 + * AMD extended CPU features 2 + */ + +struct leaf_0x80000021_0 { + // eax + u32 no_nested_data_bp : 1, // No nested data breakpoints + fsgs_non_serializing : 1, // WRMSR to {FS,GS,KERNEL_GS}_BASE is non-serializing + lfence_serializing : 1, // LFENCE always serializing / synchronizes RDTSC + smm_page_cfg_lock : 1, // SMM paging configuration lock + : 2, // Reserved + null_sel_clr_base : 1, // Null selector clears base + upper_addr_ignore : 1, // EFER MSR Upper Address Ignore + auto_ibrs : 1, // EFER MSR Automatic IBRS + no_smm_ctl_msr : 1, // SMM_CTL MSR not available + fsrs : 1, // Fast Short Rep STOSB + fsrc : 1, // Fast Short Rep CMPSB + : 1, // Reserved + prefetch_ctl_msr : 1, // Prefetch control MSR + : 2, // Reserved + opcode_reclaim : 1, // Reserves opcode space + user_cpuid_disable : 1, // #GP when executing CPUID at CPL > 0 + epsf : 1, // Enhanced Predictive Store Forwarding + : 3, // Reserved + wl_feedback : 1, // Workload-based heuristic feedback to OS + : 1, // Reserved + eraps : 1, // Enhanced Return Address Predictor Security + : 2, // Reserved + sbpb : 1, // Selective Branch Predictor Barrier + ibpb_brtype : 1, // Branch predictions flushed from CPU branch predictor + srso_no : 1, // No SRSO vulnerability + srso_uk_no : 1, // No SRSO at user-kernel boundary + srso_msr_fix : 1; // MSR BP_CFG[BpSpecReduce] SRSO mitigation + // ebx + u32 microcode_patch_size : 16, // Microcode patch size, in 16-byte units + rap_size : 8, // Return Address Predictor size + : 8; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x80000022 + * AMD extended performance monitoring + */ + +struct leaf_0x80000022_0 { + // eax + u32 perfmon_v2 : 1, // Performance monitoring v2 + lbr_v2 : 1, // Last Branch Record v2 extensions (LBR Stack) + lbr_pmc_freeze : 1, // Freezing core performance counters / LBR Stack + : 29; // Reserved + // ebx + u32 n_pmc_core : 4, // Number of core performance counters + lbr_v2_stack_size : 6, // Number of LBR stack entries + n_pmc_northbridge : 6, // Number of northbridge performance counters + n_pmc_umc : 6, // Number of UMC performance counters + : 10; // Reserved + // ecx + u32 active_umc_bitmask : 32; // Active UMCs bitmask + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x80000023 + * AMD multi-key encrypted memory + */ + +struct leaf_0x80000023_0 { + // eax + u32 mem_hmk_mode : 1, // MEM-HMK encryption mode + : 31; // Reserved + // ebx + u32 mem_hmk_avail_keys : 16, // Total number of available encryption keys + : 16; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x80000026 + * AMD extended CPU topology + */ + +struct leaf_0x80000026_n { + // eax + u32 x2apic_id_shift : 5, // Bit width of this level (previous levels inclusive) + : 24, // Reserved + core_has_pwreff_ranking : 1, // This core has a power efficiency ranking + domain_has_hybrid_cores : 1, // This domain level has hybrid (E, P) cores + domain_core_count_asymm : 1; // The 'Core' domain has asymmetric cores count + // ebx + u32 domain_lcpus_count : 16, // Number of logical CPUs at this domain instance + core_pwreff_ranking : 8, // This core's static power efficiency ranking + core_native_model_id : 4, // This core's native model ID + core_type : 4; // This core's type + // ecx + u32 domain_level : 8, // This domain level (subleaf ID) + domain_type : 8, // This domain type + : 16; // Reserved + // edx + u32 x2apic_id : 32; // x2APIC ID of current logical CPU +}; + +#define LEAF_0x80000026_SUBLEAF_N_FIRST 0 +#define LEAF_0x80000026_SUBLEAF_N_LAST 3 + +/* + * Leaf 0x80860000 + * Maximum Transmeta leaf + CPU vendor string + */ + +struct leaf_0x80860000_0 { + // eax + u32 max_tra_leaf : 32; // Maximum Transmeta leaf + // ebx + u32 cpu_vendorid_0 : 32; // Transmeta Vendor ID string bytes 0 - 3 + // ecx + u32 cpu_vendorid_2 : 32; // Transmeta Vendor ID string bytes 8 - 11 + // edx + u32 cpu_vendorid_1 : 32; // Transmeta Vendor ID string bytes 4 - 7 +}; + +/* + * Leaf 0x80860001 + * Transmeta extended CPU features + */ + +struct leaf_0x80860001_0 { + // eax + u32 stepping : 4, // Stepping ID + base_model : 4, // Base CPU model ID + base_family_id : 4, // Base CPU family ID + cpu_type : 2, // CPU type + : 18; // Reserved + // ebx + u32 cpu_rev_mask_minor : 8, // CPU revision ID, mask minor + cpu_rev_mask_major : 8, // CPU revision ID, mask major + cpu_rev_minor : 8, // CPU revision ID, minor + cpu_rev_major : 8; // CPU revision ID, major + // ecx + u32 cpu_base_mhz : 32; // CPU nominal frequency, in MHz + // edx + u32 recovery : 1, // Recovery CMS is active (after bad flush) + longrun : 1, // LongRun power management capabilities + : 1, // Reserved + lrti : 1, // LongRun Table Interface + : 28; // Reserved +}; + +/* + * Leaf 0x80860002 + * Transmeta CMS (Code Morphing Software) + */ + +struct leaf_0x80860002_0 { + // eax + u32 cpu_rev_id : 32; // CPU revision ID + // ebx + u32 cms_rev_mask_2 : 8, // CMS revision ID, mask component 2 + cms_rev_mask_1 : 8, // CMS revision ID, mask component 1 + cms_rev_minor : 8, // CMS revision ID, minor + cms_rev_major : 8; // CMS revision ID, major + // ecx + u32 cms_rev_mask_3 : 32; // CMS revision ID, mask component 3 + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0x80860003 + * Transmeta CPU information string, bytes 0 - 15 + */ + +struct leaf_0x80860003_0 { + // eax + u32 cpu_info_0 : 32; // CPU info string bytes 0 - 3 + // ebx + u32 cpu_info_1 : 32; // CPU info string bytes 4 - 7 + // ecx + u32 cpu_info_2 : 32; // CPU info string bytes 8 - 11 + // edx + u32 cpu_info_3 : 32; // CPU info string bytes 12 - 15 +}; + +/* + * Leaf 0x80860004 + * Transmeta CPU information string, bytes 16 - 31 + */ + +struct leaf_0x80860004_0 { + // eax + u32 cpu_info_4 : 32; // CPU info string bytes 16 - 19 + // ebx + u32 cpu_info_5 : 32; // CPU info string bytes 20 - 23 + // ecx + u32 cpu_info_6 : 32; // CPU info string bytes 24 - 27 + // edx + u32 cpu_info_7 : 32; // CPU info string bytes 28 - 31 +}; + +/* + * Leaf 0x80860005 + * Transmeta CPU information string, bytes 32 - 47 + */ + +struct leaf_0x80860005_0 { + // eax + u32 cpu_info_8 : 32; // CPU info string bytes 32 - 35 + // ebx + u32 cpu_info_9 : 32; // CPU info string bytes 36 - 39 + // ecx + u32 cpu_info_10 : 32; // CPU info string bytes 40 - 43 + // edx + u32 cpu_info_11 : 32; // CPU info string bytes 44 - 47 +}; + +/* + * Leaf 0x80860006 + * Transmeta CPU information string, bytes 48 - 63 + */ + +struct leaf_0x80860006_0 { + // eax + u32 cpu_info_12 : 32; // CPU info string bytes 48 - 51 + // ebx + u32 cpu_info_13 : 32; // CPU info string bytes 52 - 55 + // ecx + u32 cpu_info_14 : 32; // CPU info string bytes 56 - 59 + // edx + u32 cpu_info_15 : 32; // CPU info string bytes 60 - 63 +}; + +/* + * Leaf 0x80860007 + * Transmeta live CPU information + */ + +struct leaf_0x80860007_0 { + // eax + u32 cpu_cur_mhz : 32; // Current CPU frequency, in MHz + // ebx + u32 cpu_cur_voltage : 32; // Current CPU voltage, in millivolts + // ecx + u32 cpu_cur_perf_pctg : 32; // Current CPU performance percentage, 0 - 100 + // edx + u32 cpu_cur_gate_delay : 32; // Current CPU gate delay, in femtoseconds +}; + +/* + * Leaf 0xc0000000 + * Maximum Centaur/Zhaoxin leaf + */ + +struct leaf_0xc0000000_0 { + // eax + u32 max_cntr_leaf : 32; // Maximum Centaur/Zhaoxin leaf + // ebx + u32 : 32; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 : 32; // Reserved +}; + +/* + * Leaf 0xc0000001 + * Centaur/Zhaoxin extended CPU features + */ + +struct leaf_0xc0000001_0 { + // eax + u32 : 32; // Reserved + // ebx + u32 : 32; // Reserved + // ecx + u32 : 32; // Reserved + // edx + u32 ccs_sm2 : 1, // CCS SM2 instructions + ccs_sm2_en : 1, // CCS SM2 enabled + rng : 1, // Random Number Generator + rng_en : 1, // RNG enabled + ccs_sm3_sm4 : 1, // CCS SM3 and SM4 instructions + ccs_sm3_sm4_en : 1, // CCS SM3/SM4 enabled + ace : 1, // Advanced Cryptography Engine + ace_en : 1, // ACE enabled + ace2 : 1, // Advanced Cryptography Engine v2 + ace2_en : 1, // ACE v2 enabled + phe : 1, // PadLock Hash Engine + phe_en : 1, // PHE enabled + pmm : 1, // PadLock Montgomery Multiplier + pmm_en : 1, // PMM enabled + : 2, // Reserved + parallax : 1, // Parallax auto adjust processor voltage + parallax_en : 1, // Parallax enabled + : 2, // Reserved + tm3 : 1, // Thermal Monitor v3 + tm3_en : 1, // TM v3 enabled + : 3, // Reserved + phe2 : 1, // PadLock Hash Engine v2 (SHA384/SHA512) + phe2_en : 1, // PHE v2 enabled + rsa : 1, // RSA instructions (XMODEXP/MONTMUL2) + rsa_en : 1, // RSA instructions enabled + : 3; // Reserved +}; + +#endif /* _ASM_X86_CPUID_LEAF_TYPES */ From 3aa8f9fce8602d722948df641c7ca2828ee0a2f5 Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Fri, 27 Mar 2026 03:15:22 +0100 Subject: [PATCH 16/25] x86/cpu: Introduce a centralized CPUID data model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ** Context The x86-cpuid-db project generates a C header file with full C99 bitfield listings for all known CPUID leaf/subleaf query outputs. That header is now merged by parent commits at , and is of the form: struct leaf_0x0_0 { /* CPUID(0x0).0 C99 bitfields */ }; ... struct leaf_0x4_n { /* CPUID(0x4).n C99 bitfields */ }; ... struct leaf_0xd_0 { /* CPUID(0xd).0 C99 bitfields */ }; struct leaf_0xd_1 { /* CPUID(0xd).1 C99 bitfields */ }; struct leaf_0xd_n { /* CPUID(0xd).n C99 bitfields */ }; ... ** Goal Introduce a structured, size-efficient, per-CPU, CPUID data repository. Use the x86-cpuid-db auto-generated data types, and custom CPUID leaf parsers, to build that repository. Given a leaf, subleaf, and index, provide direct memory access to the parsed and cached per-CPU CPUID output. ** Long-term goal Remove the need for drivers and other areas in the kernel to invoke direct CPUID queries. Only one place in the kernel should be allowed to use the CPUID instruction: the CPUID parser code. ** Implementation Introduce CPUID_LEAF()/CPUID_LEAF_N() to build a compact CPUID storage layout in the form: struct leaf_0x0_0 leaf_0x0_0[1]; struct leaf_parse_info leaf_0x0_0_info; struct leaf_0x1_0 leaf_0x1_0[1]; struct leaf_parse_info leaf_0x0_0_info; struct leaf_0x4_n leaf_0x4_n[8]; struct leaf_parse_info leaf_0x4_n_info; ... where each CPUID query stores its output at the designated leaf/subleaf array and has an associated "CPUID query info" structure. Embed the CPUID tables inside "struct cpuinfo_x86" to ensure early-boot and per-CPU access through the CPUs capability structures. Use an array of CPUID output storage entries for each leaf/subleaf combination to accommodate leaves which produce the same output format for a large subleaf range. This is typical for CPUID leaves enumerating hierarchical objects; e.g. CPUID(0x4) cache topology enumeration, CPUID(0xd) XSAVE enumeration, and CPUID(0x12) SGX Enclave Page Cache enumeration. ** New CPUID APIs Assuming a CPU capability structure 'c', provide macros to access the parsed and cached CPUID leaf/subleaf output. These macros resolve to a compile-time tokenization that ensures type-safety: const struct leaf_0x7_0 *l7_0; l7_0 = cpuid_subleaf(c, 0x7, 0); | | └────────┐ | └─────────┐ | * * * &c.cpuid.leaf_0x7_0[0] For CPUID leaves with multiple subleaves having the same output format, provide the APIs: const struct leaf_0x4_n *l4_0, *l4_1; l4_0 = cpuid_subleaf_n(c, 0x4, 0); | | └──────────┐ | └─────────┐ | * * v &c.cpuid.leaf_0x4_n[0] l4_1 = cpuid_subleaf_n(c, 0x4, 1); | | └──────────┐ | └─────────┐ | * * v &c.cpuid.leaf_0x4_n[1] where the indices 0, 1, n above can be passed dynamically; e.g., in an enumeration for loop. Add a clear rationale on why call sites should use the these new APIs instead of directly invoking CPUID. ** Next steps For now, define cached parse entries for CPUID(0x0) and CPUID(0x1). Generic parser logic to fill the CPUID tables, along with more CPUID leaves support, will be added next. Suggested-by: Thomas Gleixner # CPUID data model Suggested-by: Andrew Cooper # x86-cpuid-db schema Suggested-by: Borislav Petkov # Early CPUID centralization drafts Suggested-by: Ingo Molnar # CPUID headers restructuring Suggested-by: Sean Christopherson # cpuid_subleaf_n() APIs Signed-off-by: Ahmed S. Darwish Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/all/20260327021645.555257-1-darwi@linutronix.de Link: https://lore.kernel.org/all/874ixernra.ffs@tglx Link: https://gitlab.com/x86-cpuid.org/x86-cpuid-db Link: https://lore.kernel.org/all/aBnSgu_JyEi8fvog@gmail.com Link: https://lore.kernel.org/all/aJ9TbaNMgaplKSbH@google.com --- arch/x86/include/asm/cpuid/api.h | 238 +++++++++++++++++++++++++++++ arch/x86/include/asm/cpuid/types.h | 98 ++++++++++++ arch/x86/include/asm/processor.h | 2 + 3 files changed, 338 insertions(+) diff --git a/arch/x86/include/asm/cpuid/api.h b/arch/x86/include/asm/cpuid/api.h index 2b9750cc8a75..b868902dbf5f 100644 --- a/arch/x86/include/asm/cpuid/api.h +++ b/arch/x86/include/asm/cpuid/api.h @@ -289,4 +289,242 @@ static inline bool cpuid_amd_hygon_has_l3_cache(void) return cpuid_edx(0x80000006); } +/* + * 'struct cpuid_leaves' accessors (without sanity checks): + * + * For internal use by the CPUID parser. + */ + +/* Return constified pointers for all call-site APIs */ +#define __const_ptr(_ptr) \ + ((const __typeof__(*(_ptr)) *)(_ptr)) + +#define __cpuid_leaves_subleaf(_leaves, _leaf, _subleaf) \ + __const_ptr(&((_leaves)->leaf_ ## _leaf ## _ ## _subleaf)[0]) + +#define __cpuid_leaves_subleaf_n(_leaves, _leaf, _index) \ + __const_ptr(&((_leaves)->leaf_ ## _leaf ## _ ## n)[_index]) + +#define __cpuid_leaves_subleaf_info(_leaves, _leaf, _subleaf) \ + __const_ptr(&((_leaves)->leaf_ ## _leaf ## _ ## _subleaf ## _ ## info)) + +/* + * 'struct cpuid_table' accessors (with sanity checks): + * + * For internal use by the CPUID parser. + */ + +#define __cpuid_table_nr_filled_subleaves(_table, _leaf, _subleaf) \ + __cpuid_leaves_subleaf_info(&((_table)->leaves), _leaf, _subleaf)->nr_entries + +#define __cpuid_table_subleaf_range_size(_table, _leaf) \ + ARRAY_SIZE((_table)->leaves.leaf_ ## _leaf ## _n) + +#define __cpuid_table_invalid_subleaf(_table, _leaf, _subleaf) \ + (((_subleaf) < (__cpuid_leaf_first_subleaf(_leaf))) || \ + ((_subleaf) > (__cpuid_leaf_first_subleaf(_leaf) + \ + __cpuid_table_subleaf_range_size(_table, _leaf) - 1))) + +/* Return NULL if the parser did not fill that leaf. Check cpuid_subleaf(). */ +#define __cpuid_table_subleaf(_table, _leaf, _subleaf) \ +({ \ + unsigned int ____f = __cpuid_table_nr_filled_subleaves(_table, _leaf, _subleaf); \ + \ + (____f != 1) ? NULL : __cpuid_leaves_subleaf(&((_table)->leaves), _leaf, _subleaf); \ +}) + +/* + * Return NULL if the CPUID parser did not fill this leaf, or if the given + * dynamic subleaf value is out of range. Check cpuid_subleaf_n(). + */ +#define __cpuid_table_subleaf_n(_table, _leaf, _subleaf) \ +({ \ + unsigned int ____i = (_subleaf) - __cpuid_leaf_first_subleaf(_leaf); \ + unsigned int ____f = __cpuid_table_nr_filled_subleaves(_table, _leaf, n); \ + \ + /* CPUID parser might not have filled the entire subleaf range */ \ + ((____i >= ____f) || __cpuid_table_invalid_subleaf(_table, _leaf, _subleaf)) ? \ + NULL : __cpuid_leaves_subleaf_n(&((_table)->leaves), _leaf, ____i); \ +}) + +/* + * Compile-time checks for leaves with a subleaf range: + */ + +#define __cpuid_assert_subleaf_range(_cpuinfo, _leaf) \ + static_assert(__cpuid_table_subleaf_range_size(&(_cpuinfo)->cpuid, _leaf) > 1) + +#define __cpuid_assert_subleaf_within_range(_cpuinfo, _leaf, _subleaf) \ + BUILD_BUG_ON(__builtin_constant_p(_subleaf) && \ + __cpuid_table_invalid_subleaf(&(_cpuinfo)->cpuid, _leaf, _subleaf)) + +/* + * CPUID Parser Call-site APIs + * + * Call sites should use below APIs instead of invoking direct CPUID queries. + * + * Benefits include: + * + * - Return CPUID output as typed C structures that are auto-generated from a + * centralized database (see data type: 'struct leaf_0xM_N', where + * 0xM is the token provided at @_leaf, and N is the token provided at + * @_subleaf; e.g. struct leaf_0x7_0. + * + * Returns NULL if the requested CPUID @_leaf/@_subleaf query output is not + * present at the parsed CPUID table inside @_cpuinfo. This can happen if: + * + * - The CPUID table inside @_cpuinfo has not yet been populated. + * - The CPUID table inside @_cpuinfo was populated, but the CPU does not + * implement the requested CPUID @_leaf/@_subleaf combination. + * - The CPUID table inside @_cpuinfo was populated, but the kernel's CPUID + * parser has predetermined that the requested CPUID @_leaf/@_subleaf + * hardware output is invalid or unsupported. + * + * Example usage:: + * + * const struct leaf_0x7_0 *l7_0 = cpuid_subleaf(c, 0x7, 0); + * if (!l7_0) { + * // Handle error + * } + * + * const struct leaf_0x7_1 *l7_1 = cpuid_subleaf(c, 0x7, 1); + * if (!l7_1) { + * // Handle error + * } + */ +#define cpuid_subleaf(_cpuinfo, _leaf, _subleaf) \ + __cpuid_table_subleaf(&(_cpuinfo)->cpuid, _leaf, _subleaf) \ + +/** + * cpuid_leaf() - Access parsed CPUID data + * @_cpuinfo: CPU capability structure reference ('struct cpuinfo_x86') + * @_leaf: CPUID leaf, in compile-time 0xN format; e.g. 0x0, 0x2, 0x80000000 + * + * Similar to cpuid_subleaf(), but with a CPUID subleaf = 0. + * + * Example usage:: + * + * const struct leaf_0x0_0 *l0 = cpuid_leaf(c, 0x0); + * if (!l0) { + * // Handle error + * } + * + * const struct leaf_0x80000000_0 *el0 = cpuid_leaf(c, 0x80000000); + * if (!el0) { + * // Handle error + * } + */ +#define cpuid_leaf(_cpuinfo, _leaf) \ + cpuid_subleaf(_cpuinfo, _leaf, 0) + +/** + * cpuid_leaf_raw() - Access parsed CPUID data in raw format + * @_cpuinfo: CPU capability structure reference ('struct cpuinfo_x86') + * @_leaf: CPUID leaf, in compile-time 0xN format + * + * Similar to cpuid_leaf(), but returns a raw 'struct cpuid_regs' pointer to + * the parsed CPUID data instead of a "typed" pointer. + */ +#define cpuid_leaf_raw(_cpuinfo, _leaf) \ + ((const struct cpuid_regs *)(cpuid_leaf(_cpuinfo, _leaf))) + +/* + * Call-site APIs for CPUID leaves with a subleaf range: + */ + +/** + * cpuid_subleaf_n() - Access parsed CPUID data for leaf with a subleaf range + * @_cpuinfo: CPU capability structure reference ('struct cpuinfo_x86') + * @_leaf: CPUID leaf, in compile-time 0xN format; e.g. 0x4, 0x8000001d + * @_subleaf: Subleaf number, which can be passed dynamically. It must be smaller + * than cpuid_subleaf_count(@_cpuinfo, @_leaf). + * + * Build-time errors will be emitted in the following cases: + * + * - @_leaf has no subleaf range. Leaves with a subleaf range have an '_n' type + * suffix and are listed at using the CPUID_LEAF_N() macro. + * + * - @_subleaf is known at compile-time but is out of range. + * + * Example usage:: + * + * const struct leaf_0x4_n *l4; + * + * for (int i = 0; i < cpuid_subleaf_count(c, 0x4); i++) { + * l4 = cpuid_subleaf_n(c, 0x4, i); + * if (!l4) { + * // Handle error + * } + * ... + * } + * + * Beside the standard error situations detailed at cpuid_subleaf(), this + * macro will also return NULL if @_subleaf is out of the leaf's subleaf range. + */ +#define cpuid_subleaf_n(_cpuinfo, _leaf, _subleaf) \ +({ \ + __cpuid_assert_subleaf_range(_cpuinfo, _leaf); \ + __cpuid_assert_subleaf_within_range(_cpuinfo, _leaf, _subleaf); \ + __cpuid_table_subleaf_n(&(_cpuinfo)->cpuid, _leaf, _subleaf); \ +}) + +/** + * cpuid_subleaf_n_raw() - Access parsed CPUID data for leaf with subleaf range + * @_cpuinfo: CPU capability structure reference ('struct cpuinfo_x86') + * @_leaf: CPUID leaf, in compile-time 0xN format; e.g. 0x4, 0x8000001d + * @_subleaf: Subleaf number, which can be passed dynamically. It must be smaller + * than cpuid_subleaf_count(@_cpuinfo, @_leaf). + * + * Similar to cpuid_subleaf_n(), but returns a raw 'struct cpuid_regs' pointer to + * the parsed CPUID data instead of a "typed" pointer. + */ +#define cpuid_subleaf_n_raw(_cpuinfo, _leaf, _subleaf) \ + ((const struct cpuid_regs *)cpuid_subleaf_n(_cpuinfo, _leaf, _subleaf)) + +/** + * cpuid_subleaf_count() - Number of filled subleaves for @_leaf + * @_cpuinfo: CPU capability structure reference ('struct cpuinfo_x86') + * @_leaf: CPUID leaf, in compile-time 0xN format; e.g. 0x4, 0x8000001d + * + * Return the number of subleaves filled by the CPUID parser for @_leaf. + * + * @_leaf must have subleaf range. Leaves with a subleaf range have an '_n' type + * suffix and are listed at using the CPUID_LEAF_N() macro. + */ +#define cpuid_subleaf_count(_cpuinfo, _leaf) \ +({ \ + __cpuid_assert_subleaf_range(_cpuinfo, _leaf); \ + __cpuid_table_nr_filled_subleaves(&(_cpuinfo)->cpuid, _leaf, n); \ +}) + #endif /* _ASM_X86_CPUID_API_H */ diff --git a/arch/x86/include/asm/cpuid/types.h b/arch/x86/include/asm/cpuid/types.h index 8a00364b79de..3d0e611c97ba 100644 --- a/arch/x86/include/asm/cpuid/types.h +++ b/arch/x86/include/asm/cpuid/types.h @@ -5,6 +5,8 @@ #include #include +#include + /* * Types for raw CPUID access: */ @@ -30,6 +32,12 @@ enum cpuid_regs_idx { #define CPUID_LEAF_FREQ 0x16 #define CPUID_LEAF_TILE 0x1d +#define CPUID_RANGE(idx) ((idx) & 0xffff0000) +#define CPUID_RANGE_MAX(idx) (CPUID_RANGE(idx) + 0xffff) + +#define CPUID_BASE_START 0x00000000 +#define CPUID_BASE_END CPUID_RANGE_MAX(CPUID_BASE_START) + /* * Types for CPUID(0x2) parsing: */ @@ -124,4 +132,94 @@ extern const struct leaf_0x2_table cpuid_0x2_table[256]; */ #define TLB_0x63_2M_4M_ENTRIES 32 +/* + * Types for centralized CPUID tables: + * + * For internal use by the CPUID parser. + */ + +/** + * struct leaf_parse_info - CPUID query parse info + * @nr_entries: Number of valid entries filled by the CPUID parser + */ +struct leaf_parse_info { + unsigned int nr_entries; +}; + +/** + * __CPUID_LEAF() - Define a CPUID output and parse info entry + * @_name: Struct type name of the CPUID leaf/subleaf (e.g. 'leaf_0x7_0'). Such + * types are defined at and follow the leaf_0xM_N + * format, where 0xM is the leaf and N is the subleaf. + * @_count: Number of storage entries to allocate for this leaf/subleaf. + * + * For a given leaf/subleaf, define an array of CPUID storage entries and an associated + * query info structure. + * + * Use an array of storage entries to accommodate CPUID leaves with multiple subleaves + * having the same output format. This is common for hierarchical enumeration; e.g., + * CPUID(0x4), CPUID(0x12), and CPUID(0x8000001d). + */ +#define __CPUID_LEAF(_name, _count) \ + struct _name _name[_count]; \ + struct leaf_parse_info _name##_info + +/** + * CPUID_LEAF() - Define a 'struct cpuid_leaves' storage entry + * @_leaf: Leaf number, in compile-time 0xN format + * @_subleaf: Subleaf number, in compile-time decimal format + * + * Convenience wrapper around __CPUID_LEAF(). + */ +#define CPUID_LEAF(_leaf, _subleaf) \ + __CPUID_LEAF(leaf_ ## _leaf ## _ ## _subleaf, 1) + +#define __cpuid_leaf_first_subleaf(_l) \ + LEAF_ ## _l ## _ ## SUBLEAF_N_FIRST +#define __cpuid_leaf_last_subleaf(_l) \ + LEAF_ ## _l ## _ ## SUBLEAF_N_LAST + +#define __cpuid_leaf_subleaf_count_min(_l) 2 +#define __cpuid_leaf_subleaf_count_max(_l) \ + (__cpuid_leaf_last_subleaf(_l) - __cpuid_leaf_first_subleaf(_l) + 1) + +/** + * CPUID_LEAF_N() - Define a 'struct cpuid_leaves' storage entry + * @_leaf: Leaf number, in compile-time 0xN format + * @_count: Number of storage entries to allocate for that leaf. It must not exceed + * the limits defined at . + * + * Convenience wrapper around __CPUID_LEAF(). + */ +#define CPUID_LEAF_N(_leaf, _count) \ + static_assert(_count >= __cpuid_leaf_subleaf_count_min(_leaf)); \ + static_assert(_count <= __cpuid_leaf_subleaf_count_max(_leaf)); \ + __CPUID_LEAF(leaf_ ## _leaf ## _ ## n, _count) + +/* + * struct cpuid_leaves - Parsed CPUID data + */ +struct cpuid_leaves { + /* Leaf Subleaf number (or max number of subleaves) */ + CPUID_LEAF ( 0x0, 0 ); + CPUID_LEAF ( 0x1, 0 ); +}; + +/* + * Types for centralized CPUID tables: + * + * For external use. + */ + +/** + * struct cpuid_table - Per-CPU CPUID data repository + * @leaves: Parsed CPUID queries output and their metadata + * + * This is to be embedded inside 'struct cpuinfo_x86' to provide parsed and + * sanitized CPUID data per CPU. + */ +struct cpuid_table { + struct cpuid_leaves leaves; +}; + #endif /* _ASM_X86_CPUID_TYPES_H */ diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 4f4356b13158..70c414eab154 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -16,6 +16,7 @@ struct vm86; #include #include #include +#include #include #include #include @@ -169,6 +170,7 @@ struct cpuinfo_x86 { char x86_vendor_id[16]; char x86_model_id[64]; struct cpuinfo_topology topo; + struct cpuid_table cpuid; /* in KB - valid for CPUS which support this call: */ unsigned int x86_cache_size; int x86_cache_alignment; /* In bytes */ From fa6dcbc69ad495eeea315870278100a554a4ca18 Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Fri, 27 Mar 2026 03:15:23 +0100 Subject: [PATCH 17/25] x86/cpuid: Introduce a centralized CPUID parser Introduce a CPUID parser for populating the system's CPUID tables. Since accessing a leaf within the CPUID table requires compile time tokenization, split the parser into two stages: (a) Compile-time macros for tokenizing the leaf/subleaf offsets within the CPUID table. (b) Generic runtime code to fill the CPUID data, using a parsing table which collects these compile-time offsets. For actual CPUID output parsing, support both generic and leaf-specific read functions. To ensure CPUID data early availability, invoke the parser during early boot, early Xen boot, and at early secondary CPUs bring up. Provide call site APIs to refresh a single leaf, or a leaf range, within the CPUID tables. This is for sites issuing MSR writes that partially change the CPU's CPUID layout. Doing full CPUID table rescans in such cases will be destructive since the CPUID tables will host all of the kernel's X86_FEATURE flags at a later stage. Suggested-by: Thomas Gleixner Signed-off-by: Ahmed S. Darwish Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/all/20260327021645.555257-1-darwi@linutronix.de --- arch/x86/include/asm/cpuid/api.h | 9 ++ arch/x86/kernel/cpu/Makefile | 1 + arch/x86/kernel/cpu/common.c | 5 +- arch/x86/kernel/cpu/cpuid_parser.c | 182 +++++++++++++++++++++++++++++ arch/x86/kernel/cpu/cpuid_parser.h | 120 +++++++++++++++++++ arch/x86/xen/enlighten.c | 3 +- arch/x86/xen/enlighten_pv.c | 1 + 7 files changed, 319 insertions(+), 2 deletions(-) create mode 100644 arch/x86/kernel/cpu/cpuid_parser.c create mode 100644 arch/x86/kernel/cpu/cpuid_parser.h diff --git a/arch/x86/include/asm/cpuid/api.h b/arch/x86/include/asm/cpuid/api.h index b868902dbf5f..82eddfa2347b 100644 --- a/arch/x86/include/asm/cpuid/api.h +++ b/arch/x86/include/asm/cpuid/api.h @@ -7,6 +7,7 @@ #include #include +#include #include /* @@ -527,4 +528,12 @@ static inline bool cpuid_amd_hygon_has_l3_cache(void) __cpuid_table_nr_filled_subleaves(&(_cpuinfo)->cpuid, _leaf, n); \ }) +/* + * CPUID parser exported APIs: + */ + +void cpuid_scan_cpu(struct cpuinfo_x86 *c); +void cpuid_refresh_leaf(struct cpuinfo_x86 *c, u32 leaf); +void cpuid_refresh_range(struct cpuinfo_x86 *c, u32 start, u32 end); + #endif /* _ASM_X86_CPUID_API_H */ diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 2f8a58ef690e..d2e8a849f180 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -19,6 +19,7 @@ KCSAN_SANITIZE_common.o := n obj-y := cacheinfo.o scattered.o obj-y += topology_common.o topology_ext.o topology_amd.o +obj-y += cpuid_parser.o obj-y += common.o obj-y += rdrand.o obj-y += match.o diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 897145f913bd..a3df21d26460 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1784,6 +1784,7 @@ static void __init cpu_parse_early_param(void) static void __init early_identify_cpu(struct cpuinfo_x86 *c) { memset(&c->x86_capability, 0, sizeof(c->x86_capability)); + memset(&c->cpuid, 0, sizeof(c->cpuid)); c->extended_cpuid_level = 0; if (!cpuid_feature()) @@ -1791,6 +1792,7 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) /* cyrix could have cpuid enabled via c_identify()*/ if (cpuid_feature()) { + cpuid_scan_cpu(c); cpu_detect(c); get_cpu_vendor(c); intel_unlock_cpuid_leafs(c); @@ -1963,8 +1965,8 @@ static void generic_identify(struct cpuinfo_x86 *c) if (!cpuid_feature()) return; + cpuid_scan_cpu(c); cpu_detect(c); - get_cpu_vendor(c); intel_unlock_cpuid_leafs(c); get_cpu_cap(c); @@ -2016,6 +2018,7 @@ static void identify_cpu(struct cpuinfo_x86 *c) #endif c->x86_cache_alignment = c->x86_clflush_size; memset(&c->x86_capability, 0, sizeof(c->x86_capability)); + memset(&c->cpuid, 0, sizeof(c->cpuid)); #ifdef CONFIG_X86_VMX_FEATURE_NAMES memset(&c->vmx_capability, 0, sizeof(c->vmx_capability)); #endif diff --git a/arch/x86/kernel/cpu/cpuid_parser.c b/arch/x86/kernel/cpu/cpuid_parser.c new file mode 100644 index 000000000000..898b0c441431 --- /dev/null +++ b/arch/x86/kernel/cpu/cpuid_parser.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * CPUID parser; for populating the system's CPUID tables. + */ + +#include + +#include +#include + +#include "cpuid_parser.h" + +/* Clear a single CPUID table entry */ +static void cpuid_clear(const struct cpuid_parse_entry *e, const struct cpuid_read_output *output) +{ + struct cpuid_regs *regs = output->regs; + + for (int i = 0; i < e->maxcnt; i++, regs++) + memset(regs, 0, sizeof(*regs)); + + memset(output->info, 0, sizeof(*output->info)); +} + +/* + * Leaf read functions: + */ + +/* + * Default CPUID read function + * Satisfies the requirements stated at 'struct cpuid_parse_entry'->read(). + */ +static void +cpuid_read_generic(const struct cpuid_parse_entry *e, const struct cpuid_read_output *output) +{ + struct cpuid_regs *regs = output->regs; + + for (int i = 0; i < e->maxcnt; i++, regs++, output->info->nr_entries++) + cpuid_read_subleaf(e->leaf, e->subleaf + i, regs); +} + +/* + * CPUID parser table: + */ + +static const struct cpuid_parse_entry cpuid_parse_entries[] = { + CPUID_PARSE_ENTRIES +}; + +/* + * Leaf-independent parser code: + */ + +static unsigned int cpuid_range_max_leaf(const struct cpuid_table *t, unsigned int range) +{ + const struct leaf_0x0_0 *l0 = __cpuid_table_subleaf(t, 0x0, 0); + + switch (range) { + case CPUID_BASE_START: return l0 ? l0->max_std_leaf : 0; + default: return 0; + } +} + +static void +__cpuid_reset_table(struct cpuid_table *t, const struct cpuid_parse_entry entries[], + unsigned int nr_entries, unsigned int start, unsigned int end, bool fill) +{ + const struct cpuid_parse_entry *entry = entries; + unsigned int range = CPUID_RANGE(start); + + for (unsigned int i = 0; i < nr_entries; i++, entry++) { + struct cpuid_read_output output = { + .regs = cpuid_table_regs_p(t, entry->regs_offs), + .info = cpuid_table_info_p(t, entry->info_offs), + }; + + if (entry->leaf < start || entry->leaf > end) + continue; + + cpuid_clear(entry, &output); + + /* + * Read the range's anchor leaf unconditionally so that the cached + * maximum valid leaf value is available for the remaining entries. + */ + if (fill && (entry->leaf == range || entry->leaf <= cpuid_range_max_leaf(t, range))) + entry->read(entry, &output); + } +} + +/* + * Zero all cached CPUID entries within [@start-@end] range. This is needed when + * certain operations like MSR writes induce changes to the CPU's CPUID layout. + */ +static void +__cpuid_zero_table(struct cpuid_table *t, const struct cpuid_parse_entry entries[], + unsigned int nr_entries, unsigned int start, unsigned int end) +{ + __cpuid_reset_table(t, entries, nr_entries, start, end, false); +} + +static void +__cpuid_fill_table(struct cpuid_table *t, const struct cpuid_parse_entry entries[], + unsigned int nr_entries, unsigned int start, unsigned int end) +{ + __cpuid_reset_table(t, entries, nr_entries, start, end, true); +} + +static void +cpuid_fill_table(struct cpuid_table *t, const struct cpuid_parse_entry entries[], unsigned int nr_entries) +{ + static const struct { + unsigned int start; + unsigned int end; + } ranges[] = { + { CPUID_BASE_START, CPUID_BASE_END }, + }; + + for (unsigned int i = 0; i < ARRAY_SIZE(ranges); i++) + __cpuid_fill_table(t, entries, nr_entries, ranges[i].start, ranges[i].end); +} + +static void __cpuid_scan_cpu_full(struct cpuinfo_x86 *c) +{ + unsigned int nr_entries = ARRAY_SIZE(cpuid_parse_entries); + struct cpuid_table *table = &c->cpuid; + + cpuid_fill_table(table, cpuid_parse_entries, nr_entries); +} + +static void +__cpuid_scan_cpu_partial(struct cpuinfo_x86 *c, unsigned int start_leaf, unsigned int end_leaf) +{ + unsigned int nr_entries = ARRAY_SIZE(cpuid_parse_entries); + struct cpuid_table *table = &c->cpuid; + + __cpuid_zero_table(table, cpuid_parse_entries, nr_entries, start_leaf, end_leaf); + __cpuid_fill_table(table, cpuid_parse_entries, nr_entries, start_leaf, end_leaf); +} + +/* + * Call-site APIs: + */ + +/** + * cpuid_scan_cpu() - Populate current CPU's CPUID table + * @c: CPU capability structure associated with the current CPU + * + * Populate the CPUID table embedded within @c with parsed CPUID data. All CPUID + * instructions are invoked locally, so this must be called on the CPU associated + * with @c. + */ +void cpuid_scan_cpu(struct cpuinfo_x86 *c) +{ + __cpuid_scan_cpu_full(c); +} + +/** + * cpuid_refresh_range() - Rescan a CPUID table's leaf range + * @c: CPU capability structure associated with the current CPU + * @start: Start of leaf range to be re-scanned + * @end: End of leaf range + */ +void cpuid_refresh_range(struct cpuinfo_x86 *c, u32 start, u32 end) +{ + if (WARN_ON_ONCE(start > end)) + return; + + if (WARN_ON_ONCE(CPUID_RANGE(start) != CPUID_RANGE(end))) + return; + + __cpuid_scan_cpu_partial(c, start, end); +} + +/** + * cpuid_refresh_leaf() - Rescan a CPUID table's leaf + * @c: CPU capability structure associated with the current CPU + * @leaf: Leaf to be re-scanned + */ +void cpuid_refresh_leaf(struct cpuinfo_x86 *c, u32 leaf) +{ + cpuid_refresh_range(c, leaf, leaf); +} diff --git a/arch/x86/kernel/cpu/cpuid_parser.h b/arch/x86/kernel/cpu/cpuid_parser.h new file mode 100644 index 000000000000..df627306cc8c --- /dev/null +++ b/arch/x86/kernel/cpu/cpuid_parser.h @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ARCH_X86_CPUID_PARSER_H +#define _ARCH_X86_CPUID_PARSER_H + +#include + +/* + * Since accessing the CPUID leaves at 'struct cpuid_leaves' require compile time + * tokenization, split the CPUID parser into two stages: compile time macros for + * tokenizing the leaf/subleaf output offsets within the table, and generic runtime + * code to write to the relevant CPUID leaves using such offsets. + * + * The output of the compile time macros is cached by a compile time "parse entry" + * table (see 'struct cpuid_parse_entry'). The runtime parser code will utilize + * such offsets by passing them to the cpuid_table_*_p() functions. + */ + +/* + * Compile time CPUID table offset calculations: + * + * @_leaf: CPUID leaf, in 0xN format + * @_subleaf: CPUID subleaf, in decimal format + */ + +#define __cpuid_leaves_regs_offset(_leaf, _subleaf) \ + offsetof(struct cpuid_leaves, leaf_ ## _leaf ## _ ## _subleaf) + +#define __cpuid_leaves_info_offset(_leaf, _subleaf) \ + offsetof(struct cpuid_leaves, leaf_ ## _leaf ## _ ## _subleaf ## _ ## info) + +#define __cpuid_leaves_regs_maxcnt(_leaf, _subleaf) \ + ARRAY_SIZE(((struct cpuid_leaves *)NULL)->leaf_ ## _leaf ## _ ## _subleaf) + +/* + * Translation of compile time offsets to generic runtime pointers: + */ + +static inline struct cpuid_regs * +cpuid_table_regs_p(const struct cpuid_table *t, unsigned long regs_offset) +{ + return (struct cpuid_regs *)((unsigned long)(&t->leaves) + regs_offset); +} + +static inline struct leaf_parse_info * +cpuid_table_info_p(const struct cpuid_table *t, unsigned long info_offset) +{ + return (struct leaf_parse_info *)((unsigned long)(&t->leaves) + info_offset); +} + +/** + * struct cpuid_read_output - Output of a CPUID read operation + * @regs: Pointer to an array of CPUID outputs, where each array element covers the + * full EAX->EDX output range. + * @info: Pointer to query info; for saving the number of filled elements at @regs. + * + * A CPUID parser read function like cpuid_read_generic() or cpuid_read_0xN() uses this + * structure to save the CPUID query outputs. Actual storage for @regs and @info is + * provided by the read function caller, and is typically within the CPU's CPUID table. + * + * See struct cpuid_parse_entry.read(). + */ +struct cpuid_read_output { + struct cpuid_regs *regs; + struct leaf_parse_info *info; +}; + +/** + * struct cpuid_parse_entry - CPUID parse table entry + * @leaf: Leaf number to be parsed + * @subleaf: Subleaf number to be parsed + * @regs_offs: Offset within 'struct cpuid_leaves' for saving the CPUID query output; to be + * passed to cpuid_table_regs_p(). + * @info_offs: Offset within 'struct cpuid_leaves' for saving the CPUID query parse info; to be + * passed to cpuid_table_info_p(). + * @maxcnt: Maximum number of output storage entries available for the CPUID query. + * @read: Read function for this entry. It must save the parsed CPUID output to the passed + * 'struct cpuid_read_output'->regs array of size >= @maxcnt. It must set + * 'struct cpuid_read_output'->info.nr_entries to the number of CPUID output entries + * parsed and filled. A generic implementation is provided at cpuid_read_generic(). + */ +struct cpuid_parse_entry { + unsigned int leaf; + unsigned int subleaf; + unsigned int regs_offs; + unsigned int info_offs; + unsigned int maxcnt; + void (*read)(const struct cpuid_parse_entry *e, const struct cpuid_read_output *o); +}; + +#define __CPUID_PARSE_ENTRY(_leaf, _subleaf, _suffix, _reader_fn) \ + { \ + .leaf = _leaf, \ + .subleaf = _subleaf, \ + .regs_offs = __cpuid_leaves_regs_offset(_leaf, _suffix), \ + .info_offs = __cpuid_leaves_info_offset(_leaf, _suffix), \ + .maxcnt = __cpuid_leaves_regs_maxcnt(_leaf, _suffix), \ + .read = cpuid_read_ ## _reader_fn, \ + } + +/* + * CPUID_PARSE_ENTRY_N() is for parsing CPUID leaves with a subleaf range. + * Check __CPUID_LEAF() vs. CPUID_LEAF_N(). + */ + +#define CPUID_PARSE_ENTRY(_leaf, _subleaf, _reader_fn) \ + __CPUID_PARSE_ENTRY(_leaf, _subleaf, _subleaf, _reader_fn) + +#define CPUID_PARSE_ENTRY_N(_leaf, _reader_fn) \ + __CPUID_PARSE_ENTRY(_leaf, __cpuid_leaf_first_subleaf(_leaf), n, _reader_fn) + +/* + * CPUID parser table: + */ + +#define CPUID_PARSE_ENTRIES \ + /* Leaf Subleaf Reader function */ \ + CPUID_PARSE_ENTRY ( 0x0, 0, generic ), \ + CPUID_PARSE_ENTRY ( 0x1, 0, generic ), \ + +#endif /* _ARCH_X86_CPUID_PARSER_H */ diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 23b91bf9b663..cf061ed45ce8 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include "xen-ops.h" @@ -76,6 +76,7 @@ unsigned long xen_released_pages; static __ref void xen_get_vendor(void) { init_cpu_devs(); + cpuid_scan_cpu(&boot_cpu_data); cpu_detect(&boot_cpu_data); get_cpu_vendor(&boot_cpu_data); } diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c index ed2d7a3756ce..223e9a2eb2d5 100644 --- a/arch/x86/xen/enlighten_pv.c +++ b/arch/x86/xen/enlighten_pv.c @@ -1429,6 +1429,7 @@ asmlinkage __visible void __init xen_start_kernel(struct start_info *si) xen_build_dynamic_phys_to_machine(); /* Work out if we support NX */ + cpuid_scan_cpu(&boot_cpu_data); get_cpu_cap(&boot_cpu_data); x86_configure_nx(); From dedcf8e104414f2e5517c2f9abad4bd31fd5d8e2 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 15 May 2026 11:02:23 -0700 Subject: [PATCH 18/25] x86/cpu: Add Intel CPU model number for rugged Panther Lake Derivative of Panther Lake with P-cores and low power E-cores intended for use in harsh environments. Signed-off-by: Tony Luck Signed-off-by: Dave Hansen Link: https://patch.msgid.link/20260515180224.13818-1-tony.luck@intel.com --- arch/x86/include/asm/intel-family.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/include/asm/intel-family.h b/arch/x86/include/asm/intel-family.h index 950bfd006905..66d964afe18a 100644 --- a/arch/x86/include/asm/intel-family.h +++ b/arch/x86/include/asm/intel-family.h @@ -29,6 +29,7 @@ * _N,_P - other mobile parts * _H - premium mobile parts * _S - other client parts + * _R - ruggedized for harsh environment * * Historical OPTDIFFs: * @@ -151,6 +152,7 @@ #define INTEL_LUNARLAKE_M IFM(6, 0xBD) /* Lion Cove / Skymont */ #define INTEL_PANTHERLAKE_L IFM(6, 0xCC) /* Cougar Cove / Darkmont */ +#define INTEL_PANTHERLAKE_R IFM(6, 0xE5) /* Cougar Cove / Darkmont */ #define INTEL_WILDCATLAKE_L IFM(6, 0xD5) From 87a451161f36a34307ca09aaa66f233d68642b5f Mon Sep 17 00:00:00 2001 From: Sohil Mehta Date: Thu, 28 May 2026 11:48:25 -0700 Subject: [PATCH 19/25] x86/cpu: Fix a F00F bug warning and clean up surrounding code On x86 SMP systems with the F00F bug present, do_clear_cpu_cap() rightfully warns that the code clears the X86_BUG_F00F flag after alternatives have been patched. X86_BUG_F00F is first cleared in intel_workarounds() and then set for the affected models. This sequence works fine on the BSP but on AP bringup, where alternatives have already been patched and clearing the flag there triggers the warning. There is no technical reason for clearing the flag before setting it. It is mainly an artifact of introducing the X86_BUG_F00F flag in e2604b49e8a8 ("x86, cpu: Convert F00F bug detection"). Remove the unnecessary clearing of the flag. While at it, remove the kernel notification and the surrounding logic to inform the user about the workaround exactly once. If needed, the presence of the F00F bug can be determined through /proc/cpuinfo. Additionally, the F00F bug was the last remaining user of clear_cpu_bug(). With no users left, get rid of this helper as well. [ bp: Massage commit message. ] Co-developed-by: Richard Weinberger Signed-off-by: Richard Weinberger Signed-off-by: Sohil Mehta Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Ahmed S. Darwish Link: https://patch.msgid.link/20260528184826.3642051-1-sohil.mehta@intel.com --- arch/x86/include/asm/cpufeature.h | 1 - arch/x86/kernel/cpu/intel.c | 15 +++------------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 3ddc1d33399b..90680f978d43 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -125,7 +125,6 @@ t_no: #define cpu_has_bug(c, bit) cpu_has(c, (bit)) #define set_cpu_bug(c, bit) set_cpu_cap(c, (bit)) -#define clear_cpu_bug(c, bit) clear_cpu_cap(c, (bit)) #define static_cpu_has_bug(bit) static_cpu_has((bit)) #define boot_cpu_has_bug(bit) cpu_has_bug(&boot_cpu_data, (bit)) diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index f28c0efb7c8f..abb3984336eb 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -388,24 +388,15 @@ __setup("forcepae", forcepae_setup); static void intel_workarounds(struct cpuinfo_x86 *c) { -#ifdef CONFIG_X86_F00F_BUG /* * All models of Pentium and Pentium with MMX technology CPUs * have the F0 0F bug, which lets nonprivileged users lock up the - * system. Announce that the fault handler will be checking for it. + * system. The fault handler always checks for it. * The Quark is also family 5, but does not have the same bug. */ - clear_cpu_bug(c, X86_BUG_F00F); - if (c->x86_vfm >= INTEL_FAM5_START && c->x86_vfm < INTEL_QUARK_X1000) { - static int f00f_workaround_enabled; - + if (IS_ENABLED(CONFIG_X86_F00F_BUG) && + (c->x86_vfm >= INTEL_FAM5_START && c->x86_vfm < INTEL_QUARK_X1000)) set_cpu_bug(c, X86_BUG_F00F); - if (!f00f_workaround_enabled) { - pr_notice("Intel Pentium with F0 0F bug - workaround enabled.\n"); - f00f_workaround_enabled = 1; - } - } -#endif /* * SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until From b04472e131016c5e4022f94db82b8d15a1e93db9 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Tue, 19 May 2026 05:45:50 +0200 Subject: [PATCH 20/25] MAINTAINERS: Drop obsolete FPU EMULATOR section Commit 823caa173884 ("x86/fpu: Remove the math-emu/ FPU emulation library") removes the directory arch/x86/math-emu/, but misses to also remove the MAINTAINERS section FPU EMULATOR. As Bill Metzenthen is already mentioned in the CREDITS for his contribution to the FPU emulator, just add the email address in the MAINTAINERS section to the CREDITS and then drop the obsolete FPU EMULATOR section. Signed-off-by: Lukas Bulwahn Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260519034550.276316-1-lukas.bulwahn@redhat.com --- CREDITS | 1 + MAINTAINERS | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/CREDITS b/CREDITS index 17962bdd6dbd..42a79083b98e 100644 --- a/CREDITS +++ b/CREDITS @@ -2804,6 +2804,7 @@ D: Some of PAS 16 mixer & PCM support, inet6-apps N: William (Bill) Metzenthen E: billm@suburbia.net +E: billm@melbpc.org.au D: Author of the FPU emulator. D: Minor kernel hacker for other lost causes (Hercules mono, etc). S: 22 Parker Street diff --git a/MAINTAINERS b/MAINTAINERS index c152274a8dc9..dcdc7bda7ace 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10101,12 +10101,6 @@ F: Documentation/fpga/ F: drivers/fpga/ F: include/linux/fpga/ -FPU EMULATOR -M: Bill Metzenthen -S: Maintained -W: https://floatingpoint.billm.au/ -F: arch/x86/math-emu/ - FRAMEBUFFER CONSOLE M: Helge Deller M: Thomas Zimmermann From 111cbb4596e336373ab93e202918f4cdbf78a4c3 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 25 Apr 2025 10:42:08 +0200 Subject: [PATCH 21/25] x86/cpu: Make CONFIG_X86_TSC unconditional I.e. it's a boot time requirement for the CPU to support it. This only removes the Kconfig glue, removal of all now dead !X86_TSC code will happen in a separate patch. Signed-off-by: Ingo Molnar Reviewed-by: Arnd Bergmann Acked-by: Dave Hansen Cc: Linus Torvalds Link: https://lore.kernel.org/r/20250425084216.3913608-12-mingo@kernel.org --- arch/x86/Kconfig | 1 - arch/x86/Kconfig.cpu | 1 - arch/x86/xen/Kconfig | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 34e92da22053..f4b8722ba106 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -683,7 +683,6 @@ config X86_INTEL_QUARK depends on X86_32 depends on X86_EXTENDED_PLATFORM depends on X86_PLATFORM_DEVICES - depends on X86_TSC depends on PCI depends on PCI_GOANY depends on X86_IO_APIC diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index 1377edd9a997..678fdc10daef 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -262,7 +262,6 @@ config X86_USE_PPRO_CHECKSUM config X86_TSC def_bool y - depends on (MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MATOM) || X86_64 config X86_HAVE_PAE def_bool y diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig index aa4040fd9215..dc38f950b1e2 100644 --- a/arch/x86/xen/Kconfig +++ b/arch/x86/xen/Kconfig @@ -11,7 +11,7 @@ config XEN select HIBERNATE_CALLBACKS depends on X86_64 || (X86_32 && X86_PAE) depends on X86_64 || (X86_GENERIC || MPENTIUM4 || MATOM) - depends on X86_LOCAL_APIC && X86_TSC + depends on X86_LOCAL_APIC help This is the Linux Xen port. Enabling this will allow the kernel to boot in a paravirtualized environment under the From bdf4d8280616308b5bb42babad1432ff4575cb8b Mon Sep 17 00:00:00 2001 From: Maciej Wieczor-Retman Date: Wed, 3 Jun 2026 17:10:49 +0000 Subject: [PATCH 22/25] tools/x86/kcpuid: Update bitfields to x86-cpuid-db v3.1 Update kcpuid's CSV file to version 3.1, as generated by x86-cpuid-db. Summary of the v3.1 changes: * Fix a few typos that were found during the kernel CPUID data model review. Also include fixes found using an LLM agent review. * Rename thrd_director_nclasses to hw_feedback_nclasses as it's the name used in Intel SDM. See https://gitlab.com/x86-cpuid.org/x86-cpuid-db/-/blob/v3.1/CHANGELOG.rst for more info. Signed-off-by: Maciej Wieczor-Retman Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/cbe9ff395b3269e112ff7ca414d726ffd7bf0787.1780506200.git.m.wieczorretman@pm.me --- tools/arch/x86/kcpuid/cpuid.csv | 52 ++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/tools/arch/x86/kcpuid/cpuid.csv b/tools/arch/x86/kcpuid/cpuid.csv index 9f5155c825ca..45a876d3519f 100644 --- a/tools/arch/x86/kcpuid/cpuid.csv +++ b/tools/arch/x86/kcpuid/cpuid.csv @@ -1,5 +1,5 @@ # SPDX-License-Identifier: CC0-1.0 -# Generator: x86-cpuid-db v3.0 +# Generator: x86-cpuid-db v3.1 # # Auto-generated file. @@ -177,7 +177,7 @@ 0x6, 0, ebx, 3:0, n_therm_thresholds , Digital thermometer thresholds 0x6, 0, ecx, 0, aperfmperf , MPERF/APERF MSRs (effective frequency interface) 0x6, 0, ecx, 3, epb , IA32_ENERGY_PERF_BIAS MSR - 0x6, 0, ecx, 15:8, thrd_director_nclasses , Number of classes, Intel thread director + 0x6, 0, ecx, 15:8, hw_feedback_nclasses , Number of Intel Thread Director classes 0x6, 0, edx, 0, perfcap_reporting , Performance capability reporting 0x6, 0, edx, 1, encap_reporting , Energy efficiency capability reporting 0x6, 0, edx, 11:8, feedback_sz , Feedback interface structure size, in 4K pages @@ -247,10 +247,10 @@ 0x7, 0, edx, 1, sgx_keys , Intel SGX attestation services 0x7, 0, edx, 2, avx512_4vnniw , AVX-512 neural network instructions 0x7, 0, edx, 3, avx512_4fmaps , AVX-512 multiply accumulation single precision - 0x7, 0, edx, 4, fsrm , Fast short REP MOV + 0x7, 0, edx, 4, fsrm , Fast short REP MOVSB 0x7, 0, edx, 5, uintr , User interrupts 0x7, 0, edx, 8, avx512_vp2intersect , VP2INTERSECT{D,Q} instructions - 0x7, 0, edx, 9, srdbs_ctrl , SRBDS mitigation MSR + 0x7, 0, edx, 9, srbds_ctrl , SRBDS mitigation MSR 0x7, 0, edx, 10, md_clear , VERW MD_CLEAR microcode 0x7, 0, edx, 11, rtm_always_abort , XBEGIN (RTM transaction) always aborts 0x7, 0, edx, 13, tsx_force_abort , MSR TSX_FORCE_ABORT, RTM_ABORT bit @@ -296,8 +296,8 @@ 0x7, 2, edx, 0, intel_psfd , Intel predictive store forward disable 0x7, 2, edx, 1, ipred_ctrl , MSR bits IA32_SPEC_CTRL.IPRED_DIS_{U,S} 0x7, 2, edx, 2, rrsba_ctrl , MSR bits IA32_SPEC_CTRL.RRSBA_DIS_{U,S} - 0x7, 2, edx, 3, ddp_ctrl , MSR bit IA32_SPEC_CTRL.DDPD_U - 0x7, 2, edx, 4, bhi_ctrl , MSR bit IA32_SPEC_CTRL.BHI_DIS_S + 0x7, 2, edx, 3, ddp_ctrl , MSR bit IA32_SPEC_CTRL.DDPD_U + 0x7, 2, edx, 4, bhi_ctrl , MSR bit IA32_SPEC_CTRL.BHI_DIS_S 0x7, 2, edx, 5, mcdt_no , MCDT mitigation not needed 0x7, 2, edx, 6, uclock_disable , UC-lock disable @@ -368,7 +368,7 @@ 0xd, 1, ecx, 8, xss_pt , PT state 0xd, 1, ecx, 10, xss_pasid , PASID state 0xd, 1, ecx, 11, xss_cet_u , CET user state - 0xd, 1, ecx, 12, xss_cet_p , CET supervisor state + 0xd, 1, ecx, 12, xss_cet_s , CET supervisor state 0xd, 1, ecx, 13, xss_hdc , HDC state 0xd, 1, ecx, 14, xss_uintr , UINTR state 0xd, 1, ecx, 15, xss_lbr , LBR state @@ -433,7 +433,7 @@ 0x12, 1, eax, 7, secs_attr_kss , Key Separation and Sharing 0x12, 1, eax, 10, secs_attr_aexnotify , Enclave threads: AEX notifications 0x12, 1, ecx, 0, xfrm_x87 , Enclave XFRM.X87 - 0x12, 1, ecx, 1, xfrm_sse , Enclave XFRM.SEE + 0x12, 1, ecx, 1, xfrm_sse , Enclave XFRM.SSE 0x12, 1, ecx, 2, xfrm_avx , Enclave XFRM.AVX 0x12, 1, ecx, 3, xfrm_mpx_bndregs , Enclave XFRM.BNDREGS (MPX BND0-BND3 registers) 0x12, 1, ecx, 4, xfrm_mpx_bndcsr , Enclave XFRM.BNDCSR (MPX BNDCFGU/BNDSTATUS registers) @@ -466,9 +466,9 @@ 0x14, 0, ecx, 0, topa_output , ToPA output scheme 0x14, 0, ecx, 1, topa_multiple_entries , ToPA tables can hold multiple entries 0x14, 0, ecx, 2, single_range_output , Single-range output - 0x14, 0, ecx, 3, trance_transport_output, Trace Transport subsystem output + 0x14, 0, ecx, 3, trace_transport_output , Trace Transport subsystem output 0x14, 0, ecx, 31, ip_payloads_lip , IP payloads have LIP values (CS base included) - 0x14, 1, eax, 2:0, num_address_ranges , Number of configurable Address Ranges + 0x14, 1, eax, 2:0, num_address_ranges , Number of configurable address ranges 0x14, 1, eax, 31:16, mtc_periods_bmp , MTC period encodings bitmap 0x14, 1, ebx, 15:0, cycle_thresholds_bmp , Cycle Threshold encodings bitmap 0x14, 1, ebx, 31:16, psb_periods_bmp , Configurable PSB frequency encodings bitmap @@ -494,7 +494,7 @@ 0x17, 0, ebx, 15:0, soc_vendor_id , SoC vendor ID 0x17, 0, ebx, 16, is_vendor_scheme , Assigned by industry enumeration scheme (not Intel) 0x17, 0, ecx, 31:0, soc_proj_id , SoC project ID, assigned by vendor - 0x17, 0, edx, 31:0, soc_stepping_id , Soc project stepping ID, assigned by vendor + 0x17, 0, edx, 31:0, soc_stepping_id , SoC project stepping ID, assigned by vendor 0x17, 3:1, eax, 31:0, vendor_brand_a , Vendor Brand ID string, bytes subleaf_nr * (0 -> 3) 0x17, 3:1, ebx, 31:0, vendor_brand_b , Vendor Brand ID string, bytes subleaf_nr * (4 -> 7) 0x17, 3:1, ecx, 31:0, vendor_brand_c , Vendor Brand ID string, bytes subleaf_nr * (8 -> 11) @@ -514,12 +514,12 @@ 0x18, 31:0, edx, 4:0, tlb_type , Translation cache type (TLB type) 0x18, 31:0, edx, 7:5, tlb_cache_level , Translation cache level (1-based) 0x18, 31:0, edx, 8, is_fully_associative , Fully-associative - 0x18, 31:0, edx, 25:14, tlb_max_addressible_ids, Max number of addressable IDs - 1 + 0x18, 31:0, edx, 25:14, tlb_max_addressable_ids, Max number of addressable IDs - 1 # Leaf 19H # Intel key locker - 0x19, 0, eax, 0, kl_cpl0_only , CPL0-only key Locker restriction + 0x19, 0, eax, 0, kl_cpl0_only , CPL0-only key locker restriction 0x19, 0, eax, 1, kl_no_encrypt , No-encrypt key locker restriction 0x19, 0, eax, 2, kl_no_decrypt , No-decrypt key locker restriction 0x19, 0, ebx, 0, aes_keylocker , AES key locker instructions @@ -546,7 +546,7 @@ # Intel LBR (Last Branch Record) 0x1c, 0, eax, 7:0, lbr_depth_mask , Max LBR stack depth bitmask - 0x1c, 0, eax, 30, lbr_deep_c_reset , LBRs maybe cleared on MWAIT C-state > C1 + 0x1c, 0, eax, 30, lbr_deep_c_reset , LBRs may be cleared on MWAIT C-state > C1 0x1c, 0, eax, 31, lbr_ip_is_lip , LBR IP contain Last IP (otherwise effective IP) 0x1c, 0, ebx, 0, lbr_cpl , CPL filtering 0x1c, 0, ebx, 1, lbr_branch_filter , Branch filtering @@ -591,8 +591,8 @@ # Intel TD (Trust Domain) 0x21, 0, ebx, 31:0, tdx_vendorid_0 , TDX vendor ID string bytes 0 - 3 - 0x21, 0, ecx, 31:0, tdx_vendorid_2 , CPU vendor ID string bytes 8 - 11 - 0x21, 0, edx, 31:0, tdx_vendorid_1 , CPU vendor ID string bytes 4 - 7 + 0x21, 0, ecx, 31:0, tdx_vendorid_2 , TDX vendor ID string bytes 8 - 11 + 0x21, 0, edx, 31:0, tdx_vendorid_1 , TDX vendor ID string bytes 4 - 7 # Leaf 23H # Intel Architectural Performance Monitoring Extended (ArchPerfmonExt) @@ -857,7 +857,7 @@ 0x8000000a, 0, edx, 1, lbrv , LBR virtualization 0x8000000a, 0, edx, 2, svm_lock , SVM lock 0x8000000a, 0, edx, 3, nrip_save , NRIP save support on #VMEXIT -0x8000000a, 0, edx, 4, tsc_scale , MSR based TSC rate control +0x8000000a, 0, edx, 4, tsc_scale , MSR-based TSC rate control 0x8000000a, 0, edx, 5, vmcb_clean , VMCB clean bits support 0x8000000a, 0, edx, 6, flushbyasid , Flush by ASID + Extended VMCB TLB_Control 0x8000000a, 0, edx, 7, decodeassists , Decode Assists support @@ -895,7 +895,7 @@ 0x8000001a, 0, eax, 0, fp_128 , Internal FP/SIMD exec data path is 128-bits wide 0x8000001a, 0, eax, 1, movu_preferred , SSE: MOVU* better than MOVL*/MOVH* -0x8000001a, 0, eax, 2, fp_256 , internal FP/SSE exec data path is 256-bits wide +0x8000001a, 0, eax, 2, fp_256 , Internal FP/SSE exec data path is 256-bits wide # Leaf 8000001BH # AMD IBS (Instruction-Based Sampling) @@ -917,7 +917,7 @@ # AMD LWP (Lightweight Profiling) 0x8000001c, 0, eax, 0, os_lwp_avail , OS: LWP is available to application programs -0x8000001c, 0, eax, 1, os_lpwval , OS: LWPVAL instruction +0x8000001c, 0, eax, 1, os_lwpval , OS: LWPVAL instruction 0x8000001c, 0, eax, 2, os_lwp_ire , OS: Instructions Retired Event 0x8000001c, 0, eax, 3, os_lwp_bre , OS: Branch Retired Event 0x8000001c, 0, eax, 4, os_lwp_dme , OS: Dcache Miss Event @@ -934,13 +934,13 @@ 0x8000001c, 0, ecx, 5, lwp_data_addr , Cache miss events report data cache address 0x8000001c, 0, ecx, 8:6, lwp_latency_rnd , Cache latency rounding amount 0x8000001c, 0, ecx, 15:9, lwp_version , LWP version -0x8000001c, 0, ecx, 23:16, lwp_buf_min_sz , LWP event ring buffer min size, 32 event records units +0x8000001c, 0, ecx, 23:16, lwp_buf_min_sz , LWP event ring buffer min size, 32 event record units 0x8000001c, 0, ecx, 28, lwp_branch_predict , Branches Retired events can be filtered 0x8000001c, 0, ecx, 29, lwp_ip_filtering , IP filtering (IPI, IPF, BaseIP, and LimitIP @ LWPCP) 0x8000001c, 0, ecx, 30, lwp_cache_levels , Cache-related events: filter by cache level 0x8000001c, 0, ecx, 31, lwp_cache_latency , Cache-related events: filter by latency 0x8000001c, 0, edx, 0, hw_lwp_avail , HW: LWP available -0x8000001c, 0, edx, 1, hw_lpwval , HW: LWPVAL available +0x8000001c, 0, edx, 1, hw_lwpval , HW: LWPVAL available 0x8000001c, 0, edx, 2, hw_lwp_ire , HW: Instructions Retired Event 0x8000001c, 0, edx, 3, hw_lwp_bre , HW: Branch Retired Event 0x8000001c, 0, edx, 4, hw_lwp_dme , HW: Dcache Miss Event @@ -1040,8 +1040,8 @@ 0x80000021, 0, eax, 7, upper_addr_ignore , EFER MSR Upper Address Ignore 0x80000021, 0, eax, 8, autoibrs , EFER MSR Automatic IBRS 0x80000021, 0, eax, 9, no_smm_ctl_msr , SMM_CTL MSR not available -0x80000021, 0, eax, 10, fsrs , Fast Short Rep STOSB -0x80000021, 0, eax, 11, fsrc , Fast Short Rep CMPSB +0x80000021, 0, eax, 10, fsrs , Fast Short REP STOSB +0x80000021, 0, eax, 11, fsrc , Fast Short REP CMPSB 0x80000021, 0, eax, 13, prefetch_ctl_msr , Prefetch control MSR 0x80000021, 0, eax, 16, opcode_reclaim , Reserves opcode space 0x80000021, 0, eax, 17, user_cpuid_disable , #GP when executing CPUID at CPL > 0 @@ -1093,9 +1093,9 @@ # Maximum Transmeta leaf + CPU vendor string 0x80860000, 0, eax, 31:0, max_tra_leaf , Maximum Transmeta leaf -0x80860000, 0, ebx, 31:0, cpu_vendorid_0 , Transmeta Vendor ID string bytes 0 - 3 -0x80860000, 0, ecx, 31:0, cpu_vendorid_2 , Transmeta Vendor ID string bytes 8 - 11 -0x80860000, 0, edx, 31:0, cpu_vendorid_1 , Transmeta Vendor ID string bytes 4 - 7 +0x80860000, 0, ebx, 31:0, cpu_vendorid_0 , Transmeta vendor ID string bytes 0 - 3 +0x80860000, 0, ecx, 31:0, cpu_vendorid_2 , Transmeta vendor ID string bytes 8 - 11 +0x80860000, 0, edx, 31:0, cpu_vendorid_1 , Transmeta vendor ID string bytes 4 - 7 # Leaf 80860001H # Transmeta extended CPU features From eabf869d795173a107ad8965e4fb1711d82544b6 Mon Sep 17 00:00:00 2001 From: Maciej Wieczor-Retman Date: Wed, 3 Jun 2026 17:10:57 +0000 Subject: [PATCH 23/25] x86/cpuid: Update bitfields to x86-cpuid-db v3.1 Update leaf_types.h to version 3.1, as generated by x86-cpuid-db. Summary of the v3.1 changes: * Fix a few typos that were found during the kernel CPUID data model review. Also include fixes found using an LLM agent review, from Ahmed. * Rename thrd_director_nclasses to hw_feedback_nclasses as it's the name used in Intel SDM. See https://gitlab.com/x86-cpuid.org/x86-cpuid-db/-/blob/v3.1/CHANGELOG.rst for more info. Signed-off-by: Maciej Wieczor-Retman Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/9653d8690ec7093c8190b12d1fa8c689c4da50fe.1780506200.git.m.wieczorretman@pm.me --- arch/x86/include/asm/cpuid/leaf_types.h | 62 ++++++++++++------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/arch/x86/include/asm/cpuid/leaf_types.h b/arch/x86/include/asm/cpuid/leaf_types.h index 5b0008e455e2..222d2d2682c8 100644 --- a/arch/x86/include/asm/cpuid/leaf_types.h +++ b/arch/x86/include/asm/cpuid/leaf_types.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: MIT */ -/* Generator: x86-cpuid-db v3.0 */ +/* Generator: x86-cpuid-db v3.1 */ /* * Auto-generated file. @@ -246,7 +246,7 @@ struct leaf_0x6_0 { : 2, // Reserved energy_perf_bias : 1, // IA32_ENERGY_PERF_BIAS MSR : 4, // Reserved - thrd_director_nclasses : 8, // Number of classes, Intel thread director + hw_feedback_nclasses : 8, // Number of Intel Thread Director classes : 16; // Reserved // edx u32 perfcap_reporting : 1, // Performance capability reporting @@ -332,11 +332,11 @@ struct leaf_0x7_0 { sgx_keys : 1, // Intel SGX attestation services avx512_4vnniw : 1, // AVX-512 neural network instructions avx512_4fmaps : 1, // AVX-512 multiply accumulation single precision - fsrm : 1, // Fast short REP MOV + fsrm : 1, // Fast short REP MOVSB uintr : 1, // User interrupts : 2, // Reserved avx512_vp2intersect : 1, // VP2INTERSECT{D,Q} instructions - srdbs_ctrl : 1, // SRBDS mitigation MSR + srbds_ctrl : 1, // SRBDS mitigation MSR md_clear : 1, // VERW MD_CLEAR microcode rtm_always_abort : 1, // XBEGIN (RTM transaction) always aborts : 1, // Reserved @@ -379,7 +379,7 @@ struct leaf_0x7_1 { wrmsrns : 1, // WRMSRNS instruction (WRMSR-non-serializing) nmi_src : 1, // NMI-source reporting with FRED event data amx_fp16 : 1, // AMX-FP16: FP16 tile operations - hreset : 1, // HRESET (Thread director history reset) + hreset : 1, // HRESET (Thread director history reset) avx_ifma : 1, // Integer fused multiply add : 2, // Reserved lam : 1, // Linear address masking @@ -414,8 +414,8 @@ struct leaf_0x7_2 { u32 intel_psfd : 1, // Intel predictive store forward disable ipred_ctrl : 1, // MSR bits IA32_SPEC_CTRL.IPRED_DIS_{U,S} rrsba_ctrl : 1, // MSR bits IA32_SPEC_CTRL.RRSBA_DIS_{U,S} - ddp_ctrl : 1, // MSR bit IA32_SPEC_CTRL.DDPD_U - bhi_ctrl : 1, // MSR bit IA32_SPEC_CTRL.BHI_DIS_S + ddp_ctrl : 1, // MSR bit IA32_SPEC_CTRL.DDPD_U + bhi_ctrl : 1, // MSR bit IA32_SPEC_CTRL.BHI_DIS_S mcdt_no : 1, // MCDT mitigation not needed uclock_disable : 1, // UC-lock disable : 25; // Reserved @@ -547,7 +547,7 @@ struct leaf_0xd_1 { : 1, // Reserved xss_pasid : 1, // PASID state xss_cet_u : 1, // CET user state - xss_cet_p : 1, // CET supervisor state + xss_cet_s : 1, // CET supervisor state xss_hdc : 1, // HDC state xss_uintr : 1, // UINTR state xss_lbr : 1, // LBR state @@ -711,7 +711,7 @@ struct leaf_0x12_1 { u32 : 32; // Reserved // ecx u32 xfrm_x87 : 1, // Enclave XFRM.X87 - xfrm_sse : 1, // Enclave XFRM.SEE + xfrm_sse : 1, // Enclave XFRM.SSE xfrm_avx : 1, // Enclave XFRM.AVX xfrm_mpx_bndregs : 1, // Enclave XFRM.BNDREGS (MPX BND0-BND3 registers) xfrm_mpx_bndcsr : 1, // Enclave XFRM.BNDCSR (MPX BNDCFGU/BNDSTATUS registers) @@ -771,7 +771,7 @@ struct leaf_0x14_0 { u32 topa_output : 1, // ToPA output scheme topa_multiple_entries : 1, // ToPA tables can hold multiple entries single_range_output : 1, // Single-range output - trance_transport_output : 1, // Trace Transport subsystem output + trace_transport_output : 1, // Trace Transport subsystem output : 27, // Reserved ip_payloads_lip : 1; // IP payloads have LIP values (CS base included) // edx @@ -780,7 +780,7 @@ struct leaf_0x14_0 { struct leaf_0x14_1 { // eax - u32 num_address_ranges : 3, // Number of configurable Address Ranges + u32 num_address_ranges : 3, // Number of configurable address ranges : 13, // Reserved mtc_periods_bmp : 16; // MTC period encodings bitmap // ebx @@ -842,7 +842,7 @@ struct leaf_0x17_0 { // ecx u32 soc_proj_id : 32; // SoC project ID, assigned by vendor // edx - u32 soc_stepping_id : 32; // Soc project stepping ID, assigned by vendor + u32 soc_stepping_id : 32; // SoC project stepping ID, assigned by vendor }; struct leaf_0x17_n { @@ -883,7 +883,7 @@ struct leaf_0x18_n { tlb_cache_level : 3, // Translation cache level (1-based) is_fully_associative : 1, // Fully-associative : 5, // Reserved - tlb_max_addressible_ids : 12, // Max number of addressable IDs - 1 + tlb_max_addressable_ids : 12, // Max number of addressable IDs - 1 : 6; // Reserved }; @@ -897,7 +897,7 @@ struct leaf_0x18_n { struct leaf_0x19_0 { // eax - u32 kl_cpl0_only : 1, // CPL0-only key Locker restriction + u32 kl_cpl0_only : 1, // CPL0-only key locker restriction kl_no_encrypt : 1, // No-encrypt key locker restriction kl_no_decrypt : 1, // No-decrypt key locker restriction : 29; // Reserved @@ -962,7 +962,7 @@ struct leaf_0x1c_0 { // eax u32 lbr_depth_mask : 8, // Max LBR stack depth bitmask : 22, // Reserved - lbr_deep_c_reset : 1, // LBRs maybe cleared on MWAIT C-state > C1 + lbr_deep_c_reset : 1, // LBRs may be cleared on MWAIT C-state > C1 lbr_ip_is_lip : 1; // LBR IP contain Last IP (otherwise effective IP) // ebx u32 lbr_cpl : 1, // CPL filtering @@ -1079,9 +1079,9 @@ struct leaf_0x21_0 { // ebx u32 tdx_vendorid_0 : 32; // TDX vendor ID string bytes 0 - 3 // ecx - u32 tdx_vendorid_2 : 32; // CPU vendor ID string bytes 8 - 11 + u32 tdx_vendorid_2 : 32; // TDX vendor ID string bytes 8 - 11 // edx - u32 tdx_vendorid_1 : 32; // CPU vendor ID string bytes 4 - 7 + u32 tdx_vendorid_1 : 32; // TDX vendor ID string bytes 4 - 7 }; /* @@ -1281,12 +1281,12 @@ struct leaf_0x4c780001_0 { flexpriority : 1, // Intel FlexPriority ept : 1, // Intel Extended Page Table vpid : 1, // Intel Virtual Processor ID - coherency_sfw_no : 1, // SNP cache coherency software work around not needed + coherency_sfw_no : 1, // SNP cache coherency software workaround not needed : 10, // Reserved vmmcall : 1, // Prefer VMMCALL to VMCALL xenpv : 1, // Xen paravirtual guest ept_ad : 1, // Intel Extended Page Table access-dirty bit - VMCALL : 1, // Hypervisor supports the VMCALL instruction + vmcall : 1, // Hypervisor supports the VMCALL instruction vmw_vmmcall : 1, // VMware prefers the VMMCALL instruction pvunlock : 1, // PV unlock function vcpupreempt : 1, // PV vcpu_is_preempted function @@ -1380,11 +1380,11 @@ struct leaf_0x4c780002_0 { amd_e400 : 1, // CPU is among the affected by Erratum 400 cpu_meltdown : 1, // CPU affected by meltdown; needs kernel page table isolation spectre_v1 : 1, // CPU affected by Spectre variant 1 with conditional branches - specture_v2 : 1, // CPU affected by Spectre variant 2 with indirect branches + spectre_v2 : 1, // CPU affected by Spectre variant 2 with indirect branches spec_store_bypass : 1, // CPU affected by speculative store bypass attack l1tf : 1, // CPU affected by L1 Terminal Fault mds : 1, // CPU affected by Microarchitectural data sampling - msbds_only : 1, // Microarchitectural data sampling: CPU only affected by the MSDBS variant + msbds_only : 1, // Microarchitectural data sampling: CPU only affected by the MSBDS variant swapgs : 1, // CPU affected by speculation through SWAPGS taa : 1, // CPU is affected by TSX Async Abort (TAA) itlb_multihit : 1, // CPU may incur MCE during certain page attribute changes @@ -1732,7 +1732,7 @@ struct leaf_0x8000000a_0 { lbr_virt : 1, // LBR virtualization svm_lock : 1, // SVM lock nrip_save : 1, // NRIP save support on #VMEXIT - tsc_rate_msr : 1, // MSR based TSC rate control + tsc_rate_msr : 1, // MSR-based TSC rate control vmcb_clean : 1, // VMCB clean bits support flush_by_asid : 1, // Flush by ASID + Extended VMCB TLB_Control decode_assists : 1, // Decode Assists support @@ -1790,7 +1790,7 @@ struct leaf_0x8000001a_0 { // eax u32 fp_128 : 1, // Internal FP/SIMD exec data path is 128-bits wide movu_preferred : 1, // SSE: MOVU* better than MOVL*/MOVH* - fp_256 : 1, // internal FP/SSE exec data path is 256-bits wide + fp_256 : 1, // Internal FP/SSE exec data path is 256-bits wide : 29; // Reserved // ebx u32 : 32; // Reserved @@ -1836,7 +1836,7 @@ struct leaf_0x8000001b_0 { struct leaf_0x8000001c_0 { // eax u32 os_lwp_avail : 1, // OS: LWP is available to application programs - os_lpwval : 1, // OS: LWPVAL instruction + os_lwpval : 1, // OS: LWPVAL instruction os_lwp_ire : 1, // OS: Instructions Retired Event os_lwp_bre : 1, // OS: Branch Retired Event os_lwp_dme : 1, // OS: Dcache Miss Event @@ -1856,7 +1856,7 @@ struct leaf_0x8000001c_0 { lwp_data_addr : 1, // Cache miss events report data cache address lwp_latency_rnd : 3, // Cache latency rounding amount lwp_version : 7, // LWP version - lwp_buf_min_sz : 8, // LWP event ring buffer min size, 32 event records units + lwp_buf_min_sz : 8, // LWP event ring buffer min size, 32 event record units : 4, // Reserved lwp_branch_predict : 1, // Branches Retired events can be filtered lwp_ip_filtering : 1, // IP filtering (IPI, IPF, BaseIP, and LimitIP @ LWPCP) @@ -1864,7 +1864,7 @@ struct leaf_0x8000001c_0 { lwp_cache_latency : 1; // Cache-related events: filter by latency // edx u32 hw_lwp_avail : 1, // HW: LWP available - hw_lpwval : 1, // HW: LWPVAL available + hw_lwpval : 1, // HW: LWPVAL available hw_lwp_ire : 1, // HW: Instructions Retired Event hw_lwp_bre : 1, // HW: Branch Retired Event hw_lwp_dme : 1, // HW: Dcache Miss Event @@ -2051,8 +2051,8 @@ struct leaf_0x80000021_0 { upper_addr_ignore : 1, // EFER MSR Upper Address Ignore auto_ibrs : 1, // EFER MSR Automatic IBRS no_smm_ctl_msr : 1, // SMM_CTL MSR not available - fsrs : 1, // Fast Short Rep STOSB - fsrc : 1, // Fast Short Rep CMPSB + fsrs : 1, // Fast Short REP STOSB + fsrc : 1, // Fast Short REP CMPSB : 1, // Reserved prefetch_ctl_msr : 1, // Prefetch control MSR : 2, // Reserved @@ -2157,11 +2157,11 @@ struct leaf_0x80860000_0 { // eax u32 max_tra_leaf : 32; // Maximum Transmeta leaf // ebx - u32 cpu_vendorid_0 : 32; // Transmeta Vendor ID string bytes 0 - 3 + u32 cpu_vendorid_0 : 32; // Transmeta vendor ID string bytes 0 - 3 // ecx - u32 cpu_vendorid_2 : 32; // Transmeta Vendor ID string bytes 8 - 11 + u32 cpu_vendorid_2 : 32; // Transmeta vendor ID string bytes 8 - 11 // edx - u32 cpu_vendorid_1 : 32; // Transmeta Vendor ID string bytes 4 - 7 + u32 cpu_vendorid_1 : 32; // Transmeta vendor ID string bytes 4 - 7 }; /* From 5c75b98aa9cd5b1725b76999d794dc72ebd7a54a Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 27 Apr 2026 08:07:02 +0200 Subject: [PATCH 24/25] x86/cpu: Remove unused !CONFIG_X86_TSC code Now that the Kconfig space always enables CONFIG_X86_TSC (on x86), remove !CONFIG_X86_TSC code from the x86 arch code. We still keep the Kconfig option to catch any eventual code still pending in maintainer or non-mainline trees, plus some drivers have raw TSC timestamping hacks that use CONFIG_X86_TSC. It's also still possible to disable TSC support runtime. Signed-off-by: Ingo Molnar Reviewed-by: Arnd Bergmann Acked-by: Dave Hansen Cc: Ahmed S . Darwish Cc: Andrew Cooper Cc: Ard Biesheuvel Cc: H . Peter Anvin Cc: John Ogness Cc: Linus Torvalds Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20250425084216.3913608-13-mingo@kernel.org --- arch/x86/include/asm/timex.h | 3 +-- arch/x86/include/asm/trace_clock.h | 8 -------- arch/x86/include/asm/tsc.h | 13 +------------ arch/x86/kernel/Makefile | 4 ++-- arch/x86/kernel/i8253.c | 2 +- arch/x86/kernel/tsc.c | 13 ------------- 6 files changed, 5 insertions(+), 38 deletions(-) diff --git a/arch/x86/include/asm/timex.h b/arch/x86/include/asm/timex.h index 956e4145311b..6e57e3c0fdd2 100644 --- a/arch/x86/include/asm/timex.h +++ b/arch/x86/include/asm/timex.h @@ -7,8 +7,7 @@ static inline unsigned long random_get_entropy(void) { - if (!IS_ENABLED(CONFIG_X86_TSC) && - !cpu_feature_enabled(X86_FEATURE_TSC)) + if (!cpu_feature_enabled(X86_FEATURE_TSC)) return random_get_entropy_fallback(); return rdtsc(); } diff --git a/arch/x86/include/asm/trace_clock.h b/arch/x86/include/asm/trace_clock.h index 7061a5650969..1efab284c32a 100644 --- a/arch/x86/include/asm/trace_clock.h +++ b/arch/x86/include/asm/trace_clock.h @@ -5,17 +5,9 @@ #include #include -#ifdef CONFIG_X86_TSC - extern u64 notrace trace_clock_x86_tsc(void); # define ARCH_TRACE_CLOCKS \ { trace_clock_x86_tsc, "x86-tsc", .in_ns = 0 }, -#else /* !CONFIG_X86_TSC */ - -#define ARCH_TRACE_CLOCKS - -#endif - #endif /* _ASM_X86_TRACE_CLOCK_H */ diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h index 4f7f09f50552..4d2d2f21ff06 100644 --- a/arch/x86/include/asm/tsc.h +++ b/arch/x86/include/asm/tsc.h @@ -76,8 +76,7 @@ extern void disable_TSC(void); static inline cycles_t get_cycles(void) { - if (!IS_ENABLED(CONFIG_X86_TSC) && - !cpu_feature_enabled(X86_FEATURE_TSC)) + if (!cpu_feature_enabled(X86_FEATURE_TSC)) return 0; return rdtsc(); } @@ -94,25 +93,15 @@ extern unsigned long native_calibrate_tsc(void); extern unsigned long long native_sched_clock_from_tsc(u64 tsc); extern int tsc_clocksource_reliable; -#ifdef CONFIG_X86_TSC extern bool tsc_async_resets; -#else -# define tsc_async_resets false -#endif /* * Boot-time check whether the TSCs are synchronized across * all CPUs/cores: */ -#ifdef CONFIG_X86_TSC extern bool tsc_store_and_check_tsc_adjust(bool bootcpu); extern void tsc_verify_tsc_adjust(bool resume); extern void check_tsc_sync_target(void); -#else -static inline bool tsc_store_and_check_tsc_adjust(bool bootcpu) { return false; } -static inline void tsc_verify_tsc_adjust(bool resume) { } -static inline void check_tsc_sync_target(void) { } -#endif extern int notsc_setup(char *); extern void tsc_save_sched_clock_state(void); diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 47a32f583930..31f46fd00527 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -108,7 +108,7 @@ apm-y := apm_32.o obj-$(CONFIG_APM) += apm.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SMP) += smpboot.o -obj-$(CONFIG_X86_TSC) += tsc_sync.o +obj-y += tsc_sync.o obj-$(CONFIG_SMP) += setup_percpu.o obj-$(CONFIG_X86_MPPARSE) += mpparse.o obj-y += apic/ @@ -117,7 +117,7 @@ obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o obj-$(CONFIG_FUNCTION_TRACER) += ftrace_$(BITS).o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o -obj-$(CONFIG_X86_TSC) += trace_clock.o +obj-y += trace_clock.o obj-$(CONFIG_TRACING) += trace.o obj-$(CONFIG_RETHOOK) += rethook.o obj-$(CONFIG_VMCORE_INFO) += vmcore_info_$(BITS).o diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c index cb9852ad6098..0b991035f127 100644 --- a/arch/x86/kernel/i8253.c +++ b/arch/x86/kernel/i8253.c @@ -31,7 +31,7 @@ struct clock_event_device *global_clock_event; */ static bool __init use_pit(void) { - if (!IS_ENABLED(CONFIG_X86_TSC) || !boot_cpu_has(X86_FEATURE_TSC)) + if (!boot_cpu_has(X86_FEATURE_TSC)) return true; /* This also returns true when APIC is disabled */ diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index c5110eb554bc..ce10ae4b298b 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -298,30 +298,17 @@ notrace u64 sched_clock(void) preempt_enable_notrace(); return now; } - int check_tsc_unstable(void) { return tsc_unstable; } EXPORT_SYMBOL_GPL(check_tsc_unstable); -#ifdef CONFIG_X86_TSC int __init notsc_setup(char *str) { mark_tsc_unstable("boot parameter notsc"); return 1; } -#else -/* - * disable flag for tsc. Takes effect by clearing the TSC cpu flag - * in cpu/common.c - */ -int __init notsc_setup(char *str) -{ - setup_clear_cpu_cap(X86_FEATURE_TSC); - return 1; -} -#endif __setup("notsc", notsc_setup); enum { From 2bebd986eddb31f9ff1e02e9245a318036280759 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 27 Apr 2026 08:11:18 +0200 Subject: [PATCH 25/25] x86/cpu: Make CONFIG_X86_CX8 unconditional I.e. from now on it's a boot time requirement for the CPU to support it. ( This was preceded by the removal of all non-CX8 platform build options, so it should have no functional effects in theory. ) Signed-off-by: Ingo Molnar Reviewed-by: Arnd Bergmann Acked-by: Dave Hansen Cc: Ahmed S . Darwish Cc: Andrew Cooper Cc: Ard Biesheuvel Cc: H . Peter Anvin Cc: John Ogness Cc: Linus Torvalds Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20250425084216.3913608-14-mingo@kernel.org --- arch/x86/Kconfig | 2 +- arch/x86/Kconfig.cpu | 1 - arch/x86/Kconfig.cpufeatures | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index f4b8722ba106..bd548dc1df5c 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -133,7 +133,7 @@ config X86 select ARCH_SUPPORTS_AUTOFDO_CLANG select ARCH_SUPPORTS_PROPELLER_CLANG if X86_64 select ARCH_USE_BUILTIN_BSWAP - select ARCH_USE_CMPXCHG_LOCKREF if X86_CX8 + select ARCH_USE_CMPXCHG_LOCKREF select ARCH_USE_MEMTEST select ARCH_USE_QUEUED_RWLOCKS select ARCH_USE_QUEUED_SPINLOCKS diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index 678fdc10daef..66111446624b 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -269,7 +269,6 @@ config X86_HAVE_PAE config X86_CX8 def_bool y - depends on X86_HAVE_PAE || M586TSC || M586MMX || MK6 || MK7 || MGEODEGX1 || MGEODE_LX # this should be set for all -march=.. options where the compiler # generates cmov. diff --git a/arch/x86/Kconfig.cpufeatures b/arch/x86/Kconfig.cpufeatures index 89cbf8f572ae..09833c88f9ff 100644 --- a/arch/x86/Kconfig.cpufeatures +++ b/arch/x86/Kconfig.cpufeatures @@ -42,7 +42,6 @@ config X86_REQUIRED_FEATURE_NOPL config X86_REQUIRED_FEATURE_CX8 def_bool y - depends on X86_CX8 # this should be set for all -march=.. options where the compiler # generates cmov.