summaryrefslogtreecommitdiffstats
path: root/src/arch/x86/core/mpcall.S
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/x86/core/mpcall.S')
-rw-r--r--src/arch/x86/core/mpcall.S197
1 files changed, 197 insertions, 0 deletions
diff --git a/src/arch/x86/core/mpcall.S b/src/arch/x86/core/mpcall.S
new file mode 100644
index 00000000..f2a3bf90
--- /dev/null
+++ b/src/arch/x86/core/mpcall.S
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
+
+/** @file
+ *
+ * Multiprocessor functions
+ *
+ */
+
+ .section ".note.GNU-stack", "", @progbits
+ .text
+
+/* Selectively assemble code for 32-bit/64-bit builds */
+#if defined ( __x86_64__ ) && ! defined ( PLATFORM_pcbios )
+#define codemp code64
+#define DI rdi
+#define SP rsp
+#define if32 if 0
+#define if64 if 1
+#else
+#define codemp code32
+#define DI edi
+#define SP esp
+#define if32 if 1
+#define if64 if 0
+#endif
+
+/* Standard features CPUID leaf */
+#define CPUID_FEATURES 0x00000001
+
+/* x2APIC is supported */
+#define CPUID_FEATURES_ECX_X2APIC 0x00200000
+
+/* Extended topology enumeration CPUID leaf */
+#define CPUID_XT_ENUM 0x0000000b
+
+/*
+ * Call multiprocessor function from C code
+ *
+ * Parameters:
+ * 4(%esp)/%rdi Multiprocessor function
+ * 8(%esp)/%rsi Opaque data pointer
+ */
+ .section ".text.mp_call", "ax", @progbits
+ .codemp
+ .globl mp_call
+mp_call:
+.if64 /* Preserve registers, load incoming parameters into registers */
+ pushq %rax
+ pushq %rcx
+ pushq %rdx
+ pushq %rbx
+ pushq %rsp
+ pushq %rbp
+ pushq %rsi
+ pushq %rdi
+ pushq %r8
+ pushq %r9
+ pushq %r10
+ pushq %r11
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
+.else
+ pushal
+ movl 36(%esp), %eax
+ movl 40(%esp), %edx
+.endif
+ /* Call multiprocessor function */
+ call mp_jump
+
+.if64 /* Restore registers and return */
+ popq %r15
+ popq %r14
+ popq %r13
+ popq %r12
+ popq %r11
+ popq %r10
+ popq %r9
+ popq %r8
+ popq %rdi
+ popq %rsi
+ popq %rbp
+ leaq 8(%rsp), %rsp /* discard */
+ popq %rbx
+ popq %rdx
+ popq %rcx
+ popq %rax
+.else
+ popal
+.endif
+ ret
+ .size mp_call, . - mp_call
+
+/*
+ * Jump to multiprocessor function
+ *
+ * Parameters:
+ * %eax/%rdi Multiprocessor function
+ * %edx/%rsi Opaque data pointer
+ * %esp/%rsp Stack, or NULL to halt AP upon completion
+ *
+ * Obtain the CPU identifier (i.e. the APIC ID) and perform a tail
+ * call into the specified multiprocessor function.
+ *
+ * This code may run with no stack on an application processor.
+ */
+ .section ".text.mp_jump", "ax", @progbits
+ .codemp
+ .globl mp_jump
+mp_jump:
+.if32 /* Move function parameters to available registers */
+ movl %eax, %edi
+ movl %edx, %esi
+.endif
+
+ /* Get 8-bit APIC ID and x2APIC feature bit */
+ movl $CPUID_FEATURES, %eax
+ cpuid
+ shrl $24, %ebx
+ movl %ebx, %edx
+
+ /* Get 32-bit x2APIC ID if applicable */
+ testl $CPUID_FEATURES_ECX_X2APIC, %ecx
+ jz 1f
+ movl $CPUID_XT_ENUM, %eax
+ xorl %ecx, %ecx
+ cpuid
+1:
+
+.if64 /* Tail call to function */
+ movq %rdi, %rax
+ movq %rsi, %rdi
+ movl %edx, %esi
+ jmp *%rax
+.else
+ movl %esi, %eax
+ jmp *%edi
+.endif
+ .size mp_jump, . - mp_jump
+
+/*
+ * Update maximum CPU identifier
+ *
+ * Parameters:
+ * %eax/%rdi Pointer to shared maximum APIC ID
+ * %edx/%rsi CPU identifier (APIC ID)
+ * %esp/%rsp Stack, or NULL to halt AP upon completion
+ *
+ * This code may run with no stack on an application processor.
+ */
+ .section ".text.mp_update_max_cpuid", "ax", @progbits
+ .codemp
+ .globl mp_update_max_cpuid
+mp_update_max_cpuid:
+.if32 /* Move function parameters to available registers */
+ movl %eax, %edi
+ movl %edx, %esi
+.endif
+ /* Update maximum APIC ID (atomically) */
+ movl (%DI), %eax
+1: cmpl %esi, %eax
+ jae 2f
+ lock cmpxchgl %esi, (%DI)
+ jnz 1b
+2:
+ /* Return to caller (if stack exists), or halt application processor */
+ test %SP, %SP
+ jz 3f
+ ret
+3: cli
+ hlt
+ jmp 3b
+ .size mp_update_max_cpuid, . - mp_update_max_cpuid