/* * Copyright (C) 2024 Michael Brown . * * 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