From 29480dd7159190b91cca17298a87425a58826d32 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 4 Dec 2008 23:09:48 +0000 Subject: [PATCH] [efi] Use EFI-native mechanism for accessing SMBIOS table EFI provides a copy of the SMBIOS table accessible via the EFI system table, which we should use instead of manually scanning through the F000:0000 segment. --- src/Makefile | 2 +- src/arch/i386/include/bits/errfile.h | 3 +- src/arch/i386/include/bits/smbios.h | 12 ++ src/arch/i386/include/gpxe/bios_smbios.h | 16 ++ src/arch/i386/include/smbios.h | 60 -------- src/arch/i386/interface/pcbios/bios_smbios.c | 84 +++++++++++ src/config/defaults/efi.h | 1 + src/config/defaults/pcbios.h | 1 + src/include/gpxe/efi/Guid/SmBios.h | 34 +++++ src/include/gpxe/efi/efi_smbios.h | 16 ++ src/include/gpxe/errfile.h | 3 + src/include/gpxe/smbios.h | 140 ++++++++++++++++++ src/interface/efi/efi_smbios.c | 62 ++++++++ .../pcbios => interface/smbios}/smbios.c | 120 +-------------- .../smbios}/smbios_settings.c | 2 +- 15 files changed, 376 insertions(+), 180 deletions(-) create mode 100644 src/arch/i386/include/bits/smbios.h create mode 100644 src/arch/i386/include/gpxe/bios_smbios.h delete mode 100644 src/arch/i386/include/smbios.h create mode 100644 src/arch/i386/interface/pcbios/bios_smbios.c create mode 100644 src/include/gpxe/efi/Guid/SmBios.h create mode 100644 src/include/gpxe/efi/efi_smbios.h create mode 100644 src/include/gpxe/smbios.h create mode 100644 src/interface/efi/efi_smbios.c rename src/{arch/i386/firmware/pcbios => interface/smbios}/smbios.c (64%) rename src/{arch/i386/firmware/pcbios => interface/smbios}/smbios_settings.c (99%) diff --git a/src/Makefile b/src/Makefile index ae0545908..67e36a20f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -58,7 +58,7 @@ SRCDIRS += drivers/block SRCDIRS += drivers/nvs SRCDIRS += drivers/bitbash SRCDIRS += drivers/infiniband -SRCDIRS += interface/pxe interface/efi +SRCDIRS += interface/pxe interface/efi interface/smbios SRCDIRS += tests SRCDIRS += crypto crypto/axtls crypto/matrixssl SRCDIRS += hci hci/commands hci/tui diff --git a/src/arch/i386/include/bits/errfile.h b/src/arch/i386/include/bits/errfile.h index 70c78eaf5..1723063b4 100644 --- a/src/arch/i386/include/bits/errfile.h +++ b/src/arch/i386/include/bits/errfile.h @@ -9,10 +9,9 @@ #define ERRFILE_memtop_umalloc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00000000 ) #define ERRFILE_memmap ( ERRFILE_ARCH | ERRFILE_CORE | 0x00010000 ) #define ERRFILE_pnpbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00020000 ) -#define ERRFILE_smbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00030000 ) +#define ERRFILE_bios_smbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00030000 ) #define ERRFILE_biosint ( ERRFILE_ARCH | ERRFILE_CORE | 0x00040000 ) #define ERRFILE_int13 ( ERRFILE_ARCH | ERRFILE_CORE | 0x00050000 ) -#define ERRFILE_smbios_settings ( ERRFILE_ARCH | ERRFILE_CORE | 0x00060000 ) #define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 ) diff --git a/src/arch/i386/include/bits/smbios.h b/src/arch/i386/include/bits/smbios.h new file mode 100644 index 000000000..647ea19ef --- /dev/null +++ b/src/arch/i386/include/bits/smbios.h @@ -0,0 +1,12 @@ +#ifndef _BITS_SMBIOS_H +#define _BITS_SMBIOS_H + +/** @file + * + * i386-specific SMBIOS API implementations + * + */ + +#include + +#endif /* _BITS_SMBIOS_H */ diff --git a/src/arch/i386/include/gpxe/bios_smbios.h b/src/arch/i386/include/gpxe/bios_smbios.h new file mode 100644 index 000000000..0a6f277a6 --- /dev/null +++ b/src/arch/i386/include/gpxe/bios_smbios.h @@ -0,0 +1,16 @@ +#ifndef _GPXE_BIOS_SMBIOS_H +#define _GPXE_BIOS_SMBIOS_H + +/** @file + * + * Standard PC-BIOS SMBIOS interface + * + */ + +#ifdef SMBIOS_PCBIOS +#define SMBIOS_PREFIX_pcbios +#else +#define SMBIOS_PREFIX_pcbios __pcbios_ +#endif + +#endif /* _GPXE_BIOS_SMBIOS_H */ diff --git a/src/arch/i386/include/smbios.h b/src/arch/i386/include/smbios.h deleted file mode 100644 index f2736dc3a..000000000 --- a/src/arch/i386/include/smbios.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef _SMBIOS_H -#define _SMBIOS_H - -/** @file - * - * System Management BIOS - */ - -#include - -/** An SMBIOS structure header */ -struct smbios_header { - /** Type */ - uint8_t type; - /** Length */ - uint8_t len; - /** Handle */ - uint16_t handle; -} __attribute__ (( packed )); - -/** SMBIOS structure descriptor */ -struct smbios_structure { - /** Copy of SMBIOS structure header */ - struct smbios_header header; - /** Offset of structure within SMBIOS */ - size_t offset; - /** Length of strings section */ - size_t strings_len; -}; - -/** SMBIOS system information structure */ -struct smbios_system_information { - /** SMBIOS structure header */ - struct smbios_header header; - /** Manufacturer string */ - uint8_t manufacturer; - /** Product string */ - uint8_t product; - /** Version string */ - uint8_t version; - /** Serial number string */ - uint8_t serial; - /** UUID */ - uint8_t uuid[16]; - /** Wake-up type */ - uint8_t wakeup; -} __attribute__ (( packed )); - -/** SMBIOS system information structure type */ -#define SMBIOS_TYPE_SYSTEM_INFORMATION 1 - -extern int find_smbios_structure ( unsigned int type, - struct smbios_structure *structure ); -extern int read_smbios_structure ( struct smbios_structure *structure, - void *data, size_t len ); -extern int read_smbios_string ( struct smbios_structure *structure, - unsigned int index, - void *data, size_t len ); - -#endif /* _SMBIOS_H */ diff --git a/src/arch/i386/interface/pcbios/bios_smbios.c b/src/arch/i386/interface/pcbios/bios_smbios.c new file mode 100644 index 000000000..efaaef0d7 --- /dev/null +++ b/src/arch/i386/interface/pcbios/bios_smbios.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2007 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * System Management BIOS + * + */ + +/** + * Find SMBIOS + * + * @v smbios SMBIOS entry point descriptor structure to fill in + * @ret rc Return status code + */ +static int bios_find_smbios ( struct smbios *smbios ) { + union { + struct smbios_entry entry; + uint8_t bytes[256]; /* 256 is maximum length possible */ + } u; + static unsigned int offset = 0; + size_t len; + unsigned int i; + uint8_t sum; + + /* Try to find SMBIOS */ + for ( ; offset < 0x10000 ; offset += 0x10 ) { + + /* Read start of header and verify signature */ + copy_from_real ( &u.entry, BIOS_SEG, offset, + sizeof ( u.entry )); + if ( u.entry.signature != SMBIOS_SIGNATURE ) + continue; + + /* Read whole header and verify checksum */ + len = u.entry.len; + copy_from_real ( &u.bytes, BIOS_SEG, offset, len ); + for ( i = 0 , sum = 0 ; i < len ; i++ ) { + sum += u.bytes[i]; + } + if ( sum != 0 ) { + DBG ( "SMBIOS at %04x:%04x has bad checksum %02x\n", + BIOS_SEG, offset, sum ); + continue; + } + + /* Fill result structure */ + DBG ( "Found SMBIOS v%d.%d entry point at %04x:%04x\n", + u.entry.major, u.entry.minor, BIOS_SEG, offset ); + smbios->address = phys_to_user ( u.entry.smbios_address ); + smbios->len = u.entry.smbios_len; + smbios->count = u.entry.smbios_count; + return 0; + } + + DBG ( "No SMBIOS found\n" ); + return -ENODEV; +} + +PROVIDE_SMBIOS ( pcbios, find_smbios, bios_find_smbios ); diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index d980136a8..fe38fd03b 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -14,6 +14,7 @@ #define TIMER_EFI #define NAP_EFIX86 #define UMALLOC_EFI +#define SMBIOS_EFI #define IMAGE_EFI /* EFI image support */ diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h index e1360f533..4359e1a4c 100644 --- a/src/config/defaults/pcbios.h +++ b/src/config/defaults/pcbios.h @@ -14,6 +14,7 @@ #define CONSOLE_PCBIOS #define NAP_PCBIOS #define UMALLOC_MEMTOP +#define SMBIOS_PCBIOS #define IMAGE_ELF /* ELF image support */ #define IMAGE_MULTIBOOT /* MultiBoot image support */ diff --git a/src/include/gpxe/efi/Guid/SmBios.h b/src/include/gpxe/efi/Guid/SmBios.h new file mode 100644 index 000000000..c6c7f776e --- /dev/null +++ b/src/include/gpxe/efi/Guid/SmBios.h @@ -0,0 +1,34 @@ +/** @file + GUIDs used to locate the SMBIOS tables in the UEFI 2.0 system table. + + This GUID in the system table is the only legal way to search for and + locate the SMBIOS tables. Do not search the 0xF0000 segment to find SMBIOS + tables. + + Copyright (c) 2006, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + GUIDs defined in UEFI 2.0 spec. + +**/ + +#ifndef __SMBIOS_GUID_H__ +#define __SMBIOS_GUID_H__ + +#define EFI_SMBIOS_TABLE_GUID \ + { \ + 0xeb9d2d31, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +#define SMBIOS_TABLE_GUID EFI_SMBIOS_TABLE_GUID + +extern EFI_GUID gEfiSmbiosTableGuid; + +#endif diff --git a/src/include/gpxe/efi/efi_smbios.h b/src/include/gpxe/efi/efi_smbios.h new file mode 100644 index 000000000..df947de56 --- /dev/null +++ b/src/include/gpxe/efi/efi_smbios.h @@ -0,0 +1,16 @@ +#ifndef _GPXE_EFI_SMBIOS_H +#define _GPXE_EFI_SMBIOS_H + +/** @file + * + * gPXE SMBIOS API for EFI + * + */ + +#ifdef SMBIOS_EFI +#define SMBIOS_PREFIX_efi +#else +#define SMBIOS_PREFIX_efi __efi_ +#endif + +#endif /* _GPXE_EFI_SMBIOS_H */ diff --git a/src/include/gpxe/errfile.h b/src/include/gpxe/errfile.h index a3d6d37b8..6b7f3a4bf 100644 --- a/src/include/gpxe/errfile.h +++ b/src/include/gpxe/errfile.h @@ -164,6 +164,9 @@ #define ERRFILE_iscsiboot ( ERRFILE_OTHER | 0x000f0000 ) #define ERRFILE_efi_pci ( ERRFILE_OTHER | 0x00100000 ) #define ERRFILE_efi_snp ( ERRFILE_OTHER | 0x00110000 ) +#define ERRFILE_smbios ( ERRFILE_OTHER | 0x00120000 ) +#define ERRFILE_smbios_settings ( ERRFILE_OTHER | 0x00130000 ) +#define ERRFILE_efi_smbios ( ERRFILE_OTHER | 0x00140000 ) /** @} */ diff --git a/src/include/gpxe/smbios.h b/src/include/gpxe/smbios.h new file mode 100644 index 000000000..2b0fcbd10 --- /dev/null +++ b/src/include/gpxe/smbios.h @@ -0,0 +1,140 @@ +#ifndef _GPXE_SMBIOS_H +#define _GPXE_SMBIOS_H + +/** @file + * + * System Management BIOS + * + */ + +#include +#include +#include +#include + +/** + * Provide an SMBIOS API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_SMBIOS( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( SMBIOS_PREFIX_ ## _subsys, _api_func, _func ) + +/* Include all architecture-independent SMBIOS API headers */ +#include + +/* Include all architecture-dependent SMBIOS API headers */ +#include + +/** Signature for SMBIOS entry point */ +#define SMBIOS_SIGNATURE \ + ( ( '_' << 0 ) + ( 'S' << 8 ) + ( 'M' << 16 ) + ( '_' << 24 ) ) + +/** + * SMBIOS entry point + * + * This is the single table which describes the list of SMBIOS + * structures. It is located by scanning through the BIOS segment. + */ +struct smbios_entry { + /** Signature + * + * Must be equal to SMBIOS_SIGNATURE + */ + uint32_t signature; + /** Checksum */ + uint8_t checksum; + /** Length */ + uint8_t len; + /** Major version */ + uint8_t major; + /** Minor version */ + uint8_t minor; + /** Maximum structure size */ + uint16_t max; + /** Entry point revision */ + uint8_t revision; + /** Formatted area */ + uint8_t formatted[5]; + /** DMI Signature */ + uint8_t dmi_signature[5]; + /** DMI checksum */ + uint8_t dmi_checksum; + /** Structure table length */ + uint16_t smbios_len; + /** Structure table address */ + uint32_t smbios_address; + /** Number of SMBIOS structures */ + uint16_t smbios_count; + /** BCD revision */ + uint8_t bcd_revision; +} __attribute__ (( packed )); + +/** An SMBIOS structure header */ +struct smbios_header { + /** Type */ + uint8_t type; + /** Length */ + uint8_t len; + /** Handle */ + uint16_t handle; +} __attribute__ (( packed )); + +/** SMBIOS structure descriptor */ +struct smbios_structure { + /** Copy of SMBIOS structure header */ + struct smbios_header header; + /** Offset of structure within SMBIOS */ + size_t offset; + /** Length of strings section */ + size_t strings_len; +}; + +/** SMBIOS system information structure */ +struct smbios_system_information { + /** SMBIOS structure header */ + struct smbios_header header; + /** Manufacturer string */ + uint8_t manufacturer; + /** Product string */ + uint8_t product; + /** Version string */ + uint8_t version; + /** Serial number string */ + uint8_t serial; + /** UUID */ + uint8_t uuid[16]; + /** Wake-up type */ + uint8_t wakeup; +} __attribute__ (( packed )); + +/** SMBIOS system information structure type */ +#define SMBIOS_TYPE_SYSTEM_INFORMATION 1 + +/** + * SMBIOS entry point descriptor + * + * This contains the information from the SMBIOS entry point that we + * care about. + */ +struct smbios { + /** Start of SMBIOS structures */ + userptr_t address; + /** Length of SMBIOS structures */ + size_t len; + /** Number of SMBIOS structures */ + unsigned int count; +}; + +extern int find_smbios ( struct smbios *smbios ); +extern int find_smbios_structure ( unsigned int type, + struct smbios_structure *structure ); +extern int read_smbios_structure ( struct smbios_structure *structure, + void *data, size_t len ); +extern int read_smbios_string ( struct smbios_structure *structure, + unsigned int index, + void *data, size_t len ); + +#endif /* _GPXE_SMBIOS_H */ diff --git a/src/interface/efi/efi_smbios.c b/src/interface/efi/efi_smbios.c new file mode 100644 index 000000000..5888f2f91 --- /dev/null +++ b/src/interface/efi/efi_smbios.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +/** @file + * + * gPXE SMBIOS API for EFI + * + */ + +/** SMBIOS configuration table */ +static struct smbios_entry *smbios_entry; +EFI_USE_TABLE ( EFI_SMBIOS_TABLE, &smbios_entry, 0 ); + +/** + * Find SMBIOS + * + * @v smbios SMBIOS entry point descriptor structure to fill in + * @ret rc Return status code + */ +static int efi_find_smbios ( struct smbios *smbios ) { + + if ( ! smbios_entry ) { + DBG ( "No SMBIOS table provided\n" ); + return -ENODEV; + } + + if ( smbios_entry->signature != SMBIOS_SIGNATURE ) { + DBG ( "Invalid SMBIOS signature\n" ); + return -ENODEV; + } + + smbios->address = phys_to_user ( smbios_entry->smbios_address ); + smbios->len = smbios_entry->smbios_len; + smbios->count = smbios_entry->smbios_count; + DBG ( "Found SMBIOS v%d.%d entry point at %p (%x+%zx)\n", + smbios_entry->major, smbios_entry->minor, smbios_entry, + smbios_entry->smbios_address, smbios->len ); + + return 0; +} + +PROVIDE_SMBIOS ( efi, find_smbios, efi_find_smbios ); diff --git a/src/arch/i386/firmware/pcbios/smbios.c b/src/interface/smbios/smbios.c similarity index 64% rename from src/arch/i386/firmware/pcbios/smbios.c rename to src/interface/smbios/smbios.c index a2cb3b883..8207c1fa0 100644 --- a/src/arch/i386/firmware/pcbios/smbios.c +++ b/src/interface/smbios/smbios.c @@ -21,9 +21,7 @@ #include #include #include -#include -#include -#include +#include /** @file * @@ -31,123 +29,11 @@ * */ -/** Signature for SMBIOS entry point */ -#define SMBIOS_SIGNATURE \ - ( ( '_' << 0 ) + ( 'S' << 8 ) + ( 'M' << 16 ) + ( '_' << 24 ) ) - -/** - * SMBIOS entry point - * - * This is the single table which describes the list of SMBIOS - * structures. It is located by scanning through the BIOS segment. - */ -struct smbios_entry { - /** Signature - * - * Must be equal to SMBIOS_SIGNATURE - */ - uint32_t signature; - /** Checksum */ - uint8_t checksum; - /** Length */ - uint8_t len; - /** Major version */ - uint8_t major; - /** Minor version */ - uint8_t minor; - /** Maximum structure size */ - uint16_t max; - /** Entry point revision */ - uint8_t revision; - /** Formatted area */ - uint8_t formatted[5]; - /** DMI Signature */ - uint8_t dmi_signature[5]; - /** DMI checksum */ - uint8_t dmi_checksum; - /** Structure table length */ - uint16_t smbios_len; - /** Structure table address */ - physaddr_t smbios_address; - /** Number of SMBIOS structures */ - uint16_t smbios_count; - /** BCD revision */ - uint8_t bcd_revision; -} __attribute__ (( packed )); - -/** - * SMBIOS entry point descriptor - * - * This contains the information from the SMBIOS entry point that we - * care about. - */ -struct smbios { - /** Start of SMBIOS structures */ - userptr_t address; - /** Length of SMBIOS structures */ - size_t len; - /** Number of SMBIOS structures */ - unsigned int count; -}; - /** SMBIOS entry point descriptor */ static struct smbios smbios = { .address = UNULL, }; -/** - * Find SMBIOS - * - * @ret rc Return status code - */ -static int find_smbios ( void ) { - union { - struct smbios_entry entry; - uint8_t bytes[256]; /* 256 is maximum length possible */ - } u; - static unsigned int offset = 0; - size_t len; - unsigned int i; - uint8_t sum; - - /* Return cached result if avaiable */ - if ( smbios.address != UNULL ) - return 0; - - /* Try to find SMBIOS */ - for ( ; offset < 0x10000 ; offset += 0x10 ) { - - /* Read start of header and verify signature */ - copy_from_real ( &u.entry, BIOS_SEG, offset, - sizeof ( u.entry )); - if ( u.entry.signature != SMBIOS_SIGNATURE ) - continue; - - /* Read whole header and verify checksum */ - len = u.entry.len; - copy_from_real ( &u.bytes, BIOS_SEG, offset, len ); - for ( i = 0 , sum = 0 ; i < len ; i++ ) { - sum += u.bytes[i]; - } - if ( sum != 0 ) { - DBG ( "SMBIOS at %04x:%04x has bad checksum %02x\n", - BIOS_SEG, offset, sum ); - continue; - } - - /* Fill result structure */ - DBG ( "Found SMBIOS v%d.%d entry point at %04x:%04x\n", - u.entry.major, u.entry.minor, BIOS_SEG, offset ); - smbios.address = phys_to_user ( u.entry.smbios_address ); - smbios.len = u.entry.smbios_len; - smbios.count = u.entry.smbios_count; - return 0; - } - - DBG ( "No SMBIOS found\n" ); - return -ENODEV; -} - /** * Find SMBIOS strings terminator * @@ -182,8 +68,10 @@ int find_smbios_structure ( unsigned int type, int rc; /* Find SMBIOS */ - if ( ( rc = find_smbios() ) != 0 ) + if ( ( smbios.address == UNULL ) && + ( ( rc = find_smbios ( &smbios ) ) != 0 ) ) return rc; + assert ( smbios.address != UNULL ); /* Scan through list of structures */ while ( ( ( offset + sizeof ( structure->header ) ) < smbios.len ) diff --git a/src/arch/i386/firmware/pcbios/smbios_settings.c b/src/interface/smbios/smbios_settings.c similarity index 99% rename from src/arch/i386/firmware/pcbios/smbios_settings.c rename to src/interface/smbios/smbios_settings.c index 3238fb195..61c2d9192 100644 --- a/src/arch/i386/firmware/pcbios/smbios_settings.c +++ b/src/interface/smbios/smbios_settings.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include /** SMBIOS settings tag magic number */ #define SMBIOS_TAG_MAGIC 0x5B /* "SmBios" */