diff --git a/src/arch/arm/include/bits/acpi.h b/src/arch/arm/include/bits/acpi.h new file mode 100644 index 00000000..f9f2f00e --- /dev/null +++ b/src/arch/arm/include/bits/acpi.h @@ -0,0 +1,12 @@ +#ifndef _BITS_ACPI_H +#define _BITS_ACPI_H + +/** @file + * + * ARM-specific ACPI API implementations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#endif /* _BITS_ACPI_H */ diff --git a/src/arch/x86/include/bits/acpi.h b/src/arch/x86/include/bits/acpi.h new file mode 100644 index 00000000..a6ff9080 --- /dev/null +++ b/src/arch/x86/include/bits/acpi.h @@ -0,0 +1,14 @@ +#ifndef _BITS_ACPI_H +#define _BITS_ACPI_H + +/** @file + * + * x86-specific ACPI API implementations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +#endif /* _BITS_ACPI_H */ diff --git a/src/arch/x86/include/ipxe/rsdp.h b/src/arch/x86/include/ipxe/rsdp.h new file mode 100644 index 00000000..7e32c001 --- /dev/null +++ b/src/arch/x86/include/ipxe/rsdp.h @@ -0,0 +1,18 @@ +#ifndef _IPXE_RSDP_H +#define _IPXE_RSDP_H + +/** @file + * + * Standard PC-BIOS ACPI RSDP interface + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#ifdef ACPI_RSDP +#define ACPI_PREFIX_rsdp +#else +#define ACPI_PREFIX_rsdp __rsdp_ +#endif + +#endif /* _IPXE_RSDP_H */ diff --git a/src/arch/x86/interface/pcbios/acpipwr.c b/src/arch/x86/interface/pcbios/acpipwr.c index d19f972d..dc164c7d 100644 --- a/src/arch/x86/interface/pcbios/acpipwr.c +++ b/src/arch/x86/interface/pcbios/acpipwr.c @@ -26,8 +26,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include -#include #include #include #include @@ -51,8 +49,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ int acpi_poweroff ( void ) { struct acpi_fadt fadtab; - uint16_t ebda; - userptr_t rsdt; userptr_t fadt; unsigned int pm1a_cnt_blk; unsigned int pm1b_cnt_blk; @@ -63,18 +59,8 @@ int acpi_poweroff ( void ) { int s5; int rc; - /* Locate EBDA */ - get_real ( ebda, BDA_SEG, BDA_EBDA ); - - /* Locate RSDT */ - rsdt = acpi_find_rsdt ( real_to_user ( ebda, 0 ) ); - if ( ! rsdt ) { - DBGC ( colour, "ACPI could not find RSDT (EBDA %04x)\n", ebda ); - return -ENOENT; - } - /* Locate FADT */ - fadt = acpi_find ( rsdt, FADT_SIGNATURE, 0 ); + fadt = acpi_find ( FADT_SIGNATURE, 0 ); if ( ! fadt ) { DBGC ( colour, "ACPI could not find FADT\n" ); return -ENOENT; @@ -88,7 +74,7 @@ int acpi_poweroff ( void ) { pm1b_cnt = ( pm1b_cnt_blk + ACPI_PM1_CNT ); /* Extract \_S5 from DSDT or any SSDT */ - s5 = acpi_sx ( rsdt, S5_SIGNATURE ); + s5 = acpi_sx ( S5_SIGNATURE ); if ( s5 < 0 ) { rc = s5; DBGC ( colour, "ACPI could not extract \\_S5: %s\n", diff --git a/src/arch/x86/interface/pcbios/rsdp.c b/src/arch/x86/interface/pcbios/rsdp.c new file mode 100644 index 00000000..8da0b558 --- /dev/null +++ b/src/arch/x86/interface/pcbios/rsdp.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2017 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 + * + * ACPI Root System Description Pointer + * + */ + +#include +#include +#include +#include +#include + +/** EBDA RSDP maximum segment */ +#define RSDP_EBDA_END_SEG 0xa000 + +/** Fixed BIOS area RSDP start address */ +#define RSDP_BIOS_START 0xe0000 + +/** Fixed BIOS area RSDP length */ +#define RSDP_BIOS_LEN 0x20000 + +/** Stride at which to search for RSDP */ +#define RSDP_STRIDE 16 + +/** + * Locate ACPI root system description table within a memory range + * + * @v start Start address to search + * @v len Length to search + * @ret rsdt ACPI root system description table, or UNULL + */ +static userptr_t rsdp_find_rsdt_range ( userptr_t start, size_t len ) { + static const char signature[8] = RSDP_SIGNATURE; + struct acpi_rsdp rsdp; + userptr_t rsdt; + size_t offset; + uint8_t sum; + unsigned int i; + + /* Search for RSDP */ + for ( offset = 0 ; ( ( offset + sizeof ( rsdp ) ) < len ) ; + offset += RSDP_STRIDE ) { + + /* Check signature and checksum */ + copy_from_user ( &rsdp, start, offset, sizeof ( rsdp ) ); + if ( memcmp ( rsdp.signature, signature, + sizeof ( signature ) ) != 0 ) + continue; + for ( sum = 0, i = 0 ; i < sizeof ( rsdp ) ; i++ ) + sum += *( ( ( uint8_t * ) &rsdp ) + i ); + if ( sum != 0 ) + continue; + + /* Extract RSDT */ + rsdt = phys_to_user ( le32_to_cpu ( rsdp.rsdt ) ); + DBGC ( rsdt, "RSDT %#08lx found via RSDP %#08lx\n", + user_to_phys ( rsdt, 0 ), + user_to_phys ( start, offset ) ); + return rsdt; + } + + return UNULL; +} + +/** + * Locate ACPI root system description table + * + * @ret rsdt ACPI root system description table, or UNULL + */ +static userptr_t rsdp_find_rsdt ( void ) { + static userptr_t rsdt; + uint16_t ebda_seg; + userptr_t ebda; + size_t ebda_len; + + /* Return existing RSDT if already found */ + if ( rsdt ) + return rsdt; + + /* Search EBDA */ + get_real ( ebda_seg, BDA_SEG, BDA_EBDA ); + if ( ebda_seg < RSDP_EBDA_END_SEG ) { + ebda = real_to_user ( ebda_seg, 0 ); + ebda_len = ( ( RSDP_EBDA_END_SEG - ebda_seg ) * 16 ); + rsdt = rsdp_find_rsdt_range ( ebda, ebda_len ); + if ( rsdt ) + return rsdt; + } + + /* Search fixed BIOS area */ + rsdt = rsdp_find_rsdt_range ( phys_to_user ( RSDP_BIOS_START ), + RSDP_BIOS_LEN ); + if ( rsdt ) + return rsdt; + + return UNULL; +} + +PROVIDE_ACPI ( rsdp, acpi_find_rsdt, rsdp_find_rsdt ); diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index a4f70a1d..5e1eed79 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ENTROPY_EFI #define TIME_EFI #define REBOOT_EFI +#define ACPI_NULL #define DOWNLOAD_PROTO_FILE /* Local filesystem access */ diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h index e1915054..21821c95 100644 --- a/src/config/defaults/pcbios.h +++ b/src/config/defaults/pcbios.h @@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ENTROPY_RTC #define TIME_RTC #define REBOOT_PCBIOS +#define ACPI_RSDP #ifdef __x86_64__ #define IOMAP_PAGES diff --git a/src/core/acpi.c b/src/core/acpi.c index 8ebe4b19..ff8875e1 100644 --- a/src/core/acpi.c +++ b/src/core/acpi.c @@ -57,88 +57,30 @@ void acpi_fix_checksum ( struct acpi_header *acpi ) { acpi->checksum -= sum; } -/** - * Locate ACPI root system description table within a memory range - * - * @v start Start address to search - * @v len Length to search - * @ret rsdt ACPI root system description table, or UNULL - */ -static userptr_t acpi_find_rsdt_range ( userptr_t start, size_t len ) { - static const char signature[8] = RSDP_SIGNATURE; - struct acpi_rsdp rsdp; - userptr_t rsdt; - size_t offset; - uint8_t sum; - unsigned int i; - - /* Search for RSDP */ - for ( offset = 0 ; ( ( offset + sizeof ( rsdp ) ) < len ) ; - offset += RSDP_STRIDE ) { - - /* Check signature and checksum */ - copy_from_user ( &rsdp, start, offset, sizeof ( rsdp ) ); - if ( memcmp ( rsdp.signature, signature, - sizeof ( signature ) ) != 0 ) - continue; - for ( sum = 0, i = 0 ; i < sizeof ( rsdp ) ; i++ ) - sum += *( ( ( uint8_t * ) &rsdp ) + i ); - if ( sum != 0 ) - continue; - - /* Extract RSDT */ - rsdt = phys_to_user ( le32_to_cpu ( rsdp.rsdt ) ); - DBGC ( rsdt, "RSDT %#08lx found via RSDP %#08lx\n", - user_to_phys ( rsdt, 0 ), - user_to_phys ( start, offset ) ); - return rsdt; - } - - return UNULL; -} - -/** - * Locate ACPI root system description table - * - * @v ebda Extended BIOS data area, or UNULL - * @ret rsdt ACPI root system description table, or UNULL - */ -userptr_t acpi_find_rsdt ( userptr_t ebda ) { - userptr_t rsdt; - - /* Search EBDA, if applicable */ - if ( ebda ) { - rsdt = acpi_find_rsdt_range ( ebda, RSDP_EBDA_LEN ); - if ( rsdt ) - return rsdt; - } - - /* Search fixed BIOS area */ - rsdt = acpi_find_rsdt_range ( phys_to_user ( RSDP_BIOS_START ), - RSDP_BIOS_LEN ); - if ( rsdt ) - return rsdt; - - return UNULL; -} - /** * Locate ACPI table * - * @v rsdt ACPI root system description table * @v signature Requested table signature * @v index Requested index of table with this signature * @ret table Table, or UNULL if not found */ -userptr_t acpi_find ( userptr_t rsdt, uint32_t signature, unsigned int index ) { +userptr_t acpi_find ( uint32_t signature, unsigned int index ) { struct acpi_header acpi; struct acpi_rsdt *rsdtab; typeof ( rsdtab->entry[0] ) entry; + userptr_t rsdt; userptr_t table; size_t len; unsigned int count; unsigned int i; + /* Locate RSDT */ + rsdt = acpi_find_rsdt(); + if ( ! rsdt ) { + DBG ( "RSDT not found\n" ); + return UNULL; + } + /* Read RSDT header */ copy_from_user ( &acpi, rsdt, 0, sizeof ( acpi ) ); if ( acpi.signature != cpu_to_le32 ( RSDT_SIGNATURE ) ) { @@ -278,20 +220,27 @@ static int acpi_sx_zsdt ( userptr_t zsdt, uint32_t signature ) { /** * Extract \_Sx value from DSDT/SSDT * - * @v rsdt ACPI root system description table * @v signature Signature (e.g. "_S5_") * @ret sx \_Sx value, or negative error */ -int acpi_sx ( userptr_t rsdt, uint32_t signature ) { +int acpi_sx ( uint32_t signature ) { struct acpi_fadt fadtab; + userptr_t rsdt; userptr_t fadt; userptr_t dsdt; userptr_t ssdt; unsigned int i; int sx; + /* Locate RSDT */ + rsdt = acpi_find_rsdt(); + if ( ! rsdt ) { + DBG ( "RSDT not found\n" ); + return -ENOENT; + } + /* Try DSDT first */ - fadt = acpi_find ( rsdt, FADT_SIGNATURE, 0 ); + fadt = acpi_find ( FADT_SIGNATURE, 0 ); if ( fadt ) { copy_from_user ( &fadtab, fadt, 0, sizeof ( fadtab ) ); dsdt = phys_to_user ( fadtab.dsdt ); @@ -301,7 +250,7 @@ int acpi_sx ( userptr_t rsdt, uint32_t signature ) { /* Try all SSDTs */ for ( i = 0 ; ; i++ ) { - ssdt = acpi_find ( rsdt, SSDT_SIGNATURE, i ); + ssdt = acpi_find ( SSDT_SIGNATURE, i ); if ( ! ssdt ) break; if ( ( sx = acpi_sx_zsdt ( ssdt, signature ) ) >= 0 ) diff --git a/src/core/null_acpi.c b/src/core/null_acpi.c new file mode 100644 index 00000000..90c78485 --- /dev/null +++ b/src/core/null_acpi.c @@ -0,0 +1,3 @@ +#include + +PROVIDE_ACPI_INLINE ( null, acpi_find_rsdt ); diff --git a/src/include/ipxe/acpi.h b/src/include/ipxe/acpi.h index f87b8ae9..e7ca35da 100644 --- a/src/include/ipxe/acpi.h +++ b/src/include/ipxe/acpi.h @@ -16,6 +16,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include +#include /** * An ACPI description header @@ -89,18 +91,6 @@ struct acpi_rsdp { uint32_t rsdt; } __attribute__ (( packed )); -/** EBDA RSDP length */ -#define RSDP_EBDA_LEN 0x400 - -/** Fixed BIOS area RSDP start address */ -#define RSDP_BIOS_START 0xe0000 - -/** Fixed BIOS area RSDP length */ -#define RSDP_BIOS_LEN 0x20000 - -/** Stride at which to search for RSDP */ -#define RSDP_STRIDE 16 - /** Root System Description Table (RSDT) signature */ #define RSDT_SIGNATURE ACPI_SIGNATURE ( 'R', 'S', 'D', 'T' ) @@ -194,16 +184,56 @@ struct acpi_model { /** Declare an ACPI model */ #define __acpi_model __table_entry ( ACPI_MODELS, 01 ) +/** + * Calculate static inline ACPI API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define ACPI_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( ACPI_PREFIX_ ## _subsys, _api_func ) + +/** + * Provide an ACPI API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_ACPI( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( ACPI_PREFIX_ ## _subsys, _api_func, _func ) + +/** + * Provide a static inline ACPI API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_ACPI_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( ACPI_PREFIX_ ## _subsys, _api_func ) + +/* Include all architecture-independent ACPI API headers */ +#include + +/* Include all architecture-dependent ACPI API headers */ +#include + +/** + * Locate ACPI root system description table + * + * @ret rsdt ACPI root system description table, or UNULL + */ +userptr_t acpi_find_rsdt ( void ); + extern struct acpi_descriptor * acpi_describe ( struct interface *interface ); #define acpi_describe_TYPE( object_type ) \ typeof ( struct acpi_descriptor * ( object_type ) ) extern void acpi_fix_checksum ( struct acpi_header *acpi ); -extern userptr_t acpi_find_rsdt ( userptr_t ebda ); -extern userptr_t acpi_find ( userptr_t rsdt, uint32_t signature, - unsigned int index ); -extern int acpi_sx ( userptr_t rsdt, uint32_t signature ); +extern userptr_t acpi_find ( uint32_t signature, unsigned int index ); +extern int acpi_sx ( uint32_t signature ); extern void acpi_add ( struct acpi_descriptor *desc ); extern void acpi_del ( struct acpi_descriptor *desc ); extern int acpi_install ( int ( * install ) ( struct acpi_header *acpi ) ); diff --git a/src/include/ipxe/null_acpi.h b/src/include/ipxe/null_acpi.h new file mode 100644 index 00000000..1e469e33 --- /dev/null +++ b/src/include/ipxe/null_acpi.h @@ -0,0 +1,23 @@ +#ifndef _IPXE_NULL_ACPI_H +#define _IPXE_NULL_ACPI_H + +/** @file + * + * Standard do-nothing ACPI interface + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#ifdef ACPI_NULL +#define ACPI_PREFIX_null +#else +#define ACPI_PREFIX_null __null_ +#endif + +static inline __always_inline userptr_t +ACPI_INLINE ( null, acpi_find_rsdt ) ( void ) { + return UNULL; +} + +#endif /* _IPXE_NULL_ACPI_H */