From 1ab4d3079d29e9ebee0c85f1aec14a3b1df8f679 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 13 Mar 2024 15:08:10 +0000 Subject: [mp] Define an API for multiprocessor functions Define an API for executing very limited functions on application processors in a multiprocessor system, along with an x86-only implementation. The normal iPXE runtime environment is effectively non-existent on application processors. There is no ability to make firmware calls (e.g. to write to a console), and there may be no stack space available. Signed-off-by: Michael Brown --- src/config/defaults/pcbios.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src/config/defaults/pcbios.h') diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h index ee342d41..968bd82a 100644 --- a/src/config/defaults/pcbios.h +++ b/src/config/defaults/pcbios.h @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define TIME_RTC #define REBOOT_PCBIOS #define ACPI_RSDP +#define MPAPI_NULL #ifdef __x86_64__ #define IOMAP_PAGES -- cgit v1.2.3-55-g7522 From 1344e13a03cb6ed25372651cae6b057b863c89be Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 15 Mar 2024 17:30:21 +0000 Subject: [bios] Provide a multiprocessor API for BIOS Provide an implementation of the iPXE multiprocessor API for BIOS, based on sending broadcast INIT and SIPI interprocessor interrupts to start up all application processors. Signed-off-by: Michael Brown --- src/arch/x86/include/bits/mp.h | 2 + src/arch/x86/include/ipxe/bios_mp.h | 32 ++++++ src/arch/x86/interface/pcbios/bios_mp.c | 172 ++++++++++++++++++++++++++++++++ src/config/defaults/pcbios.h | 2 +- 4 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 src/arch/x86/include/ipxe/bios_mp.h create mode 100644 src/arch/x86/interface/pcbios/bios_mp.c (limited to 'src/config/defaults/pcbios.h') diff --git a/src/arch/x86/include/bits/mp.h b/src/arch/x86/include/bits/mp.h index fe466b09..4541aca3 100644 --- a/src/arch/x86/include/bits/mp.h +++ b/src/arch/x86/include/bits/mp.h @@ -9,4 +9,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include + #endif /* _BITS_MP_H */ diff --git a/src/arch/x86/include/ipxe/bios_mp.h b/src/arch/x86/include/ipxe/bios_mp.h new file mode 100644 index 00000000..e2e83a15 --- /dev/null +++ b/src/arch/x86/include/ipxe/bios_mp.h @@ -0,0 +1,32 @@ +#ifndef _IPXE_BIOS_MP_H +#define _IPXE_BIOS_MP_H + +/** @file + * + * BIOS multiprocessor API implementation + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +#ifdef MPAPI_PCBIOS +#define MPAPI_PREFIX_pcbios +#else +#define MPAPI_PREFIX_pcbios __pcbios_ +#endif + +/** + * Calculate address as seen by a multiprocessor function + * + * @v address Address in boot processor address space + * @ret address Address in application processor address space + */ +static inline __attribute__ (( always_inline )) mp_addr_t +MPAPI_INLINE ( pcbios, mp_address ) ( void *address ) { + + return virt_to_phys ( address ); +} + +#endif /* _IPXE_BIOS_MP_H */ diff --git a/src/arch/x86/interface/pcbios/bios_mp.c b/src/arch/x86/interface/pcbios/bios_mp.c new file mode 100644 index 00000000..914fe5c1 --- /dev/null +++ b/src/arch/x86/interface/pcbios/bios_mp.c @@ -0,0 +1,172 @@ +/* + * 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 + * + * BIOS multiprocessor API implementation + * + */ + +#include +#include +#include +#include +#include + +/** Local APIC base address MSR */ +#define MSR_APIC_BASE 0x0000001b + +/** Local APIC is in x2APIC mode */ +#define MSR_APIC_BASE_X2APIC 0x400 + +/** Local APIC base address mask */ +#define MSR_APIC_BASE_MASK ( ~0xfffULL ) + +/** Interrupt command register */ +#define APIC_ICR 0x0300 + +/** Interrupt command register (x2APIC) */ +#define MSR_X2APIC_ICR 0x830 + +/** Interrupt command register: send to all excluding self */ +#define APIC_ICR_ALL_NOT_SELF 0x000c0000 + +/** Interrupt command register: level mode */ +#define APIC_ICR_LEVEL 0x00008000 + +/** Interrupt command register: level asserted */ +#define APIC_ICR_LEVEL_ASSERT 0x00004000 + +/** Interrupt command register: INIT */ +#define APIC_ICR_INIT 0x00000500 + +/** Interrupt command register: SIPI */ +#define APIC_ICR_SIPI( vector ) ( 0x00000600 | (vector) ) + +/** Time to wait for an IPI to complete */ +#define IPI_WAIT_MS 10 + +/** + * Startup IPI vector + * + * The real-mode startup IPI code must be copied to a page boundary in + * base memory. We fairly arbitrarily choose to place this at 0x8000. + */ +#define SIPI_VECTOR 0x08 + +/** Protected-mode startup IPI handler */ +extern void __asmcall mp_jump ( mp_addr_t func, mp_addr_t opaque ); + +/** + * Execute a multiprocessor function on the boot processor + * + * @v func Multiprocessor function + * @v opaque Opaque data pointer + */ +static void bios_mp_exec_boot ( mp_func_t func, void *opaque ) { + + /* Call multiprocessor function with physical addressing */ + __asm__ __volatile__ ( PHYS_CODE ( "pushl %k2\n\t" + "pushl %k1\n\t" + "call *%k0\n\t" + "addl $8, %%esp\n\t" ) + : : "r" ( mp_address ( mp_call ) ), + "r" ( mp_address ( func ) ), + "r" ( mp_address ( opaque ) ) ); +} + +/** + * Send an interprocessor interrupt + * + * @v apic APIC base address + * @v x2apic x2APIC mode enabled + * @v icr Interrupt control register value + */ +static void bios_mp_ipi ( void *apic, int x2apic, uint32_t icr ) { + + /* Write ICR according to APIC/x2APIC mode */ + DBGC ( MSR_APIC_BASE, "BIOSMP sending IPI %#08x\n", icr ); + if ( x2apic ) { + wrmsr ( MSR_X2APIC_ICR, icr ); + } else { + writel ( icr, ( apic + APIC_ICR ) ); + } + + /* Allow plenty of time for delivery to complete */ + mdelay ( IPI_WAIT_MS ); +} + +/** + * Start a multiprocessor function on all application processors + * + * @v func Multiprocessor function + * @v opaque Opaque data pointer + */ +static void bios_mp_start_all ( mp_func_t func, void *opaque ) { + struct i386_regs regs; + uint64_t base; + uint32_t ipi; + void *apic; + int x2apic; + + /* Prepare SIPI handler */ + regs.eax = mp_address ( func ); + regs.edx = mp_address ( opaque ); + setup_sipi ( SIPI_VECTOR, virt_to_phys ( mp_jump ), ®s ); + + /* Get local APIC base address and mode */ + base = rdmsr ( MSR_APIC_BASE ); + x2apic = ( base & MSR_APIC_BASE_X2APIC ); + DBGC ( MSR_APIC_BASE, "BIOSMP local %sAPIC base %#llx\n", + ( x2apic ? "x2" : "" ), ( ( unsigned long long ) base ) ); + + /* Map local APIC */ + apic = ioremap ( ( base & MSR_APIC_BASE_MASK ), PAGE_SIZE ); + if ( ! apic ) + goto err_ioremap; + + /* Assert INIT IPI */ + ipi = ( APIC_ICR_ALL_NOT_SELF | APIC_ICR_LEVEL | + APIC_ICR_LEVEL_ASSERT | APIC_ICR_INIT ); + bios_mp_ipi ( apic, x2apic, ipi ); + + /* Clear INIT IPI */ + ipi &= ~APIC_ICR_LEVEL_ASSERT; + bios_mp_ipi ( apic, x2apic, ipi ); + + /* Send SIPI */ + ipi = ( APIC_ICR_ALL_NOT_SELF | APIC_ICR_SIPI ( SIPI_VECTOR ) ); + bios_mp_ipi ( apic, x2apic, ipi ); + + iounmap ( apic ); + err_ioremap: + /* No way to handle errors: caller must check that + * multiprocessor function executed as expected. + */ +} + +PROVIDE_MPAPI_INLINE ( pcbios, mp_address ); +PROVIDE_MPAPI ( pcbios, mp_exec_boot, bios_mp_exec_boot ); +PROVIDE_MPAPI ( pcbios, mp_start_all, bios_mp_start_all ); diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h index 968bd82a..fa12a100 100644 --- a/src/config/defaults/pcbios.h +++ b/src/config/defaults/pcbios.h @@ -24,7 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define TIME_RTC #define REBOOT_PCBIOS #define ACPI_RSDP -#define MPAPI_NULL +#define MPAPI_PCBIOS #ifdef __x86_64__ #define IOMAP_PAGES -- cgit v1.2.3-55-g7522