From facff75dd41fee6c7d875322c37a7bcb54f8ecc6 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Fri, 1 May 2026 15:10:19 -0400 Subject: [PATCH] kernel/x86_64: Use VZEROALL to clear XMM/YMM/etc. registers when available. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It comes with AVX, so enable it if we've enabled AVX. This also adjusts altcodepatch_replace to explicitly set NOPs for the remainder of the patch area. Change-Id: Ia07549851d86836ff5428635b580c751b4e5b2a3 Reviewed-on: https://review.haiku-os.org/c/haiku/+/10867 Reviewed-by: waddlesplash Reviewed-by: Jérôme Duval Tested-by: Commit checker robot --- headers/private/kernel/arch/x86/arch_altcodepatch.h | 1 + src/system/kernel/arch/x86/64/interrupts.S | 4 +++- src/system/kernel/arch/x86/64/stubs.S | 4 ++++ src/system/kernel/arch/x86/arch_altcodepatch.cpp | 2 ++ src/system/kernel/arch/x86/arch_cpu.cpp | 4 ++++ 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/headers/private/kernel/arch/x86/arch_altcodepatch.h b/headers/private/kernel/arch/x86/arch_altcodepatch.h index 762a083de8..3fe6334dda 100644 --- a/headers/private/kernel/arch/x86/arch_altcodepatch.h +++ b/headers/private/kernel/arch/x86/arch_altcodepatch.h @@ -24,6 +24,7 @@ #define ALTCODEPATCH_TAG_CLAC 2 #define ALTCODEPATCH_TAG_XSAVE 3 #define ALTCODEPATCH_TAG_XRSTOR 4 +#define ALTCODEPATCH_TAG_CLEAR_FPU 5 #ifdef _ASSEMBLER diff --git a/src/system/kernel/arch/x86/64/interrupts.S b/src/system/kernel/arch/x86/64/interrupts.S index d8c100a3ec..d7b666c0bc 100644 --- a/src/system/kernel/arch/x86/64/interrupts.S +++ b/src/system/kernel/arch/x86/64/interrupts.S @@ -118,6 +118,7 @@ 1: #define CLEAR_FPU_STATE() \ + CODEPATCH_START \ pxor %xmm0, %xmm0; \ pxor %xmm1, %xmm1; \ pxor %xmm2, %xmm2; \ @@ -133,7 +134,8 @@ pxor %xmm12, %xmm12; \ pxor %xmm13, %xmm13; \ pxor %xmm14, %xmm14; \ - pxor %xmm15, %xmm15 + pxor %xmm15, %xmm15; \ + CODEPATCH_END(ALTCODEPATCH_TAG_CLEAR_FPU) // The following code defines the interrupt service routines for all 256 // interrupts. It creates a block of handlers, each 16 bytes, that the IDT diff --git a/src/system/kernel/arch/x86/64/stubs.S b/src/system/kernel/arch/x86/64/stubs.S index 39e613b4ff..f8dee04a6c 100644 --- a/src/system/kernel/arch/x86/64/stubs.S +++ b/src/system/kernel/arch/x86/64/stubs.S @@ -28,3 +28,7 @@ FUNCTION_END(_xsavec) FUNCTION(_xrstor): xrstor64 (%rdi) FUNCTION_END(_xrstor) + +FUNCTION(_vzeroall): + vzeroall +FUNCTION_END(_vzeroall) diff --git a/src/system/kernel/arch/x86/arch_altcodepatch.cpp b/src/system/kernel/arch/x86/arch_altcodepatch.cpp index 958448a12b..789c56c361 100644 --- a/src/system/kernel/arch/x86/arch_altcodepatch.cpp +++ b/src/system/kernel/arch/x86/arch_altcodepatch.cpp @@ -45,7 +45,9 @@ arch_altcodepatch_replace(uint16 tag, void* newcodepatch, size_t length) void* address = (void*)(KERNEL_LOAD_BASE + patch->kernel_offset); if (patch->length < length) panic("can't copy patch: new code is too long\n"); + memcpy(address, newcodepatch, length); + memset((uint8*)address + length, 0x90 /* nop */, patch->length - length); count++; } diff --git a/src/system/kernel/arch/x86/arch_cpu.cpp b/src/system/kernel/arch/x86/arch_cpu.cpp index e2d10a5595..cf46d7d80e 100644 --- a/src/system/kernel/arch/x86/arch_cpu.cpp +++ b/src/system/kernel/arch/x86/arch_cpu.cpp @@ -88,6 +88,7 @@ extern addr_t _clac; extern addr_t _xsave; extern addr_t _xsavec; extern addr_t _xrstor; +extern addr_t _vzeroall; uint64 gXsaveMask; uint64 gFPUSaveLength = 512; bool gHasXsave = false; @@ -1944,6 +1945,9 @@ arch_cpu_init_post_vm(kernel_args* args) arch_altcodepatch_replace(ALTCODEPATCH_TAG_XRSTOR, &_xrstor, 4); + if ((gXsaveMask & IA32_XCR0_AVX) != 0) + arch_altcodepatch_replace(ALTCODEPATCH_TAG_CLEAR_FPU, &_vzeroall, 3); + dprintf("enable %s 0x%" B_PRIx64 " %" B_PRId64 "\n", gHasXsavec ? "XSAVEC" : "XSAVE", gXsaveMask, gFPUSaveLength); }