diff options
Diffstat (limited to 'src/arch/i386')
-rw-r--r-- | src/arch/i386/firmware/pcbios/smbios.c | 290 | ||||
-rw-r--r-- | src/arch/i386/firmware/pcbios/smbios_settings.c | 201 | ||||
-rw-r--r-- | src/arch/i386/include/bits/errfile.h | 3 | ||||
-rw-r--r-- | src/arch/i386/include/bits/smbios.h | 12 | ||||
-rw-r--r-- | src/arch/i386/include/gpxe/bios_smbios.h | 16 | ||||
-rw-r--r-- | src/arch/i386/include/smbios.h | 60 | ||||
-rw-r--r-- | src/arch/i386/interface/pcbios/bios_smbios.c | 84 |
7 files changed, 113 insertions, 553 deletions
diff --git a/src/arch/i386/firmware/pcbios/smbios.c b/src/arch/i386/firmware/pcbios/smbios.c deleted file mode 100644 index a2cb3b88..00000000 --- a/src/arch/i386/firmware/pcbios/smbios.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright (C) 2007 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <stdint.h> -#include <string.h> -#include <errno.h> -#include <assert.h> -#include <gpxe/uaccess.h> -#include <realmode.h> -#include <pnpbios.h> -#include <smbios.h> - -/** @file - * - * System Management BIOS - * - */ - -/** 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 - * - * @v offset Offset to start of strings - * @ret offset Offset to strings terminator, or 0 if not found - */ -static size_t find_strings_terminator ( size_t offset ) { - size_t max_offset = ( smbios.len - 2 ); - uint16_t nulnul; - - for ( ; offset <= max_offset ; offset++ ) { - copy_from_user ( &nulnul, smbios.address, offset, 2 ); - if ( nulnul == 0 ) - return ( offset + 1 ); - } - return 0; -} - -/** - * Find specific structure type within SMBIOS - * - * @v type Structure type to search for - * @v structure SMBIOS structure descriptor to fill in - * @ret rc Return status code - */ -int find_smbios_structure ( unsigned int type, - struct smbios_structure *structure ) { - unsigned int count = 0; - size_t offset = 0; - size_t strings_offset; - size_t terminator_offset; - int rc; - - /* Find SMBIOS */ - if ( ( rc = find_smbios() ) != 0 ) - return rc; - - /* Scan through list of structures */ - while ( ( ( offset + sizeof ( structure->header ) ) < smbios.len ) - && ( count < smbios.count ) ) { - - /* Read next SMBIOS structure header */ - copy_from_user ( &structure->header, smbios.address, offset, - sizeof ( structure->header ) ); - - /* Determine start and extent of strings block */ - strings_offset = ( offset + structure->header.len ); - if ( strings_offset > smbios.len ) { - DBG ( "SMBIOS structure at offset %zx with length " - "%x extends beyond SMBIOS\n", offset, - structure->header.len ); - return -ENOENT; - } - terminator_offset = find_strings_terminator ( strings_offset ); - if ( ! terminator_offset ) { - DBG ( "SMBIOS structure at offset %zx has " - "unterminated strings section\n", offset ); - return -ENOENT; - } - structure->strings_len = ( terminator_offset - strings_offset); - - DBG ( "SMBIOS structure at offset %zx has type %d, length %x, " - "strings length %zx\n", offset, structure->header.type, - structure->header.len, structure->strings_len ); - - /* If this is the structure we want, return */ - if ( structure->header.type == type ) { - structure->offset = offset; - return 0; - } - - /* Move to next SMBIOS structure */ - offset = ( terminator_offset + 1 ); - count++; - } - - DBG ( "SMBIOS structure type %d not found\n", type ); - return -ENOENT; -} - -/** - * Copy SMBIOS structure - * - * @v structure SMBIOS structure descriptor - * @v data Buffer to hold SMBIOS structure - * @v len Length of buffer - * @ret rc Return status code - */ -int read_smbios_structure ( struct smbios_structure *structure, - void *data, size_t len ) { - - assert ( smbios.address != UNULL ); - - if ( len > structure->header.len ) - len = structure->header.len; - copy_from_user ( data, smbios.address, structure->offset, len ); - return 0; -} - -/** - * Find indexed string within SMBIOS structure - * - * @v structure SMBIOS structure descriptor - * @v index String index - * @v data Buffer for string - * @v len Length of string buffer - * @ret rc Length of string, or negative error - */ -int read_smbios_string ( struct smbios_structure *structure, - unsigned int index, void *data, size_t len ) { - size_t strings_start = ( structure->offset + structure->header.len ); - size_t strings_end = ( strings_start + structure->strings_len ); - size_t offset; - size_t string_len; - - assert ( smbios.address != UNULL ); - - /* String numbers start at 1 (0 is used to indicate "no string") */ - if ( ! index ) - return -ENOENT; - - for ( offset = strings_start ; offset < strings_end ; - offset += ( string_len + 1 ) ) { - /* Get string length. This is known safe, since the - * smbios_strings struct is constructed so as to - * always end on a string boundary. - */ - string_len = strlen_user ( smbios.address, offset ); - if ( --index == 0 ) { - /* Copy string, truncating as necessary. */ - if ( len > string_len ) - len = string_len; - copy_from_user ( data, smbios.address, offset, len ); - return string_len; - } - } - - DBG ( "SMBIOS string index %d not found\n", index ); - return -ENOENT; -} diff --git a/src/arch/i386/firmware/pcbios/smbios_settings.c b/src/arch/i386/firmware/pcbios/smbios_settings.c deleted file mode 100644 index 3238fb19..00000000 --- a/src/arch/i386/firmware/pcbios/smbios_settings.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2008 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <stdint.h> -#include <string.h> -#include <errno.h> -#include <gpxe/settings.h> -#include <gpxe/init.h> -#include <gpxe/uuid.h> -#include <smbios.h> - -/** SMBIOS settings tag magic number */ -#define SMBIOS_TAG_MAGIC 0x5B /* "SmBios" */ - -/** - * Construct SMBIOS empty tag - * - * @ret tag SMBIOS setting tag - */ -#define SMBIOS_EMPTY_TAG ( SMBIOS_TAG_MAGIC << 24 ) - -/** - * Construct SMBIOS raw-data tag - * - * @v _type SMBIOS structure type number - * @v _structure SMBIOS structure data type - * @v _field Field within SMBIOS structure data type - * @ret tag SMBIOS setting tag - */ -#define SMBIOS_RAW_TAG( _type, _structure, _field ) \ - ( ( SMBIOS_TAG_MAGIC << 24 ) | \ - ( (_type) << 16 ) | \ - ( offsetof ( _structure, _field ) << 8 ) | \ - ( sizeof ( ( ( _structure * ) 0 )->_field ) ) ) - -/** - * Construct SMBIOS string tag - * - * @v _type SMBIOS structure type number - * @v _structure SMBIOS structure data type - * @v _field Field within SMBIOS structure data type - * @ret tag SMBIOS setting tag - */ -#define SMBIOS_STRING_TAG( _type, _structure, _field ) \ - ( ( SMBIOS_TAG_MAGIC << 24 ) | \ - ( (_type) << 16 ) | \ - ( offsetof ( _structure, _field ) << 8 ) ) - -/** - * Store value of SMBIOS setting - * - * @v settings Settings block - * @v setting Setting to store - * @v data Setting data, or NULL to clear setting - * @v len Length of setting data - * @ret rc Return status code - */ -static int smbios_store ( struct settings *settings __unused, - struct setting *setting __unused, - const void *data __unused, size_t len __unused ) { - /* Cannot write data into SMBIOS */ - return -ENOTSUP; -} - -/** - * Fetch value of SMBIOS setting - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @v data Buffer to fill with setting data - * @v len Length of buffer - * @ret len Length of setting data, or negative error - */ -static int smbios_fetch ( struct settings *settings __unused, - struct setting *setting, - void *data, size_t len ) { - struct smbios_structure structure; - unsigned int tag_magic; - unsigned int tag_type; - unsigned int tag_offset; - unsigned int tag_len; - int rc; - - /* Split tag into type, offset and length */ - tag_magic = ( setting->tag >> 24 ); - tag_type = ( ( setting->tag >> 16 ) & 0xff ); - tag_offset = ( ( setting->tag >> 8 ) & 0xff ); - tag_len = ( setting->tag & 0xff ); - if ( tag_magic != SMBIOS_TAG_MAGIC ) - return -ENOENT; - - /* Find SMBIOS structure */ - if ( ( rc = find_smbios_structure ( tag_type, &structure ) ) != 0 ) - return rc; - - { - uint8_t buf[structure.header.len]; - - /* Read SMBIOS structure */ - if ( ( rc = read_smbios_structure ( &structure, buf, - sizeof ( buf ) ) ) != 0 ) - return rc; - - if ( tag_len == 0 ) { - /* String */ - return read_smbios_string ( &structure, - buf[tag_offset], - data, len ); - } else { - /* Raw data */ - if ( len > tag_len ) - len = tag_len; - memcpy ( data, &buf[tag_offset], len ); - return tag_len; - } - } -} - -/** SMBIOS settings operations */ -static struct settings_operations smbios_settings_operations = { - .store = smbios_store, - .fetch = smbios_fetch, -}; - -/** SMBIOS settings */ -static struct settings smbios_settings = { - .refcnt = NULL, - .name = "smbios", - .tag_magic = SMBIOS_EMPTY_TAG, - .siblings = LIST_HEAD_INIT ( smbios_settings.siblings ), - .children = LIST_HEAD_INIT ( smbios_settings.children ), - .op = &smbios_settings_operations, -}; - -/** Initialise SMBIOS settings */ -static void smbios_init ( void ) { - int rc; - - if ( ( rc = register_settings ( &smbios_settings, NULL ) ) != 0 ) { - DBG ( "SMBIOS could not register settings: %s\n", - strerror ( rc ) ); - return; - } -} - -/** SMBIOS settings initialiser */ -struct init_fn smbios_init_fn __init_fn ( INIT_NORMAL ) = { - .initialise = smbios_init, -}; - -/** UUID setting obtained via SMBIOS */ -struct setting uuid_setting __setting = { - .name = "uuid", - .description = "UUID", - .tag = SMBIOS_RAW_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION, - struct smbios_system_information, uuid ), - .type = &setting_type_uuid, -}; - -/** Other SMBIOS named settings */ -struct setting smbios_named_settings[] __setting = { - { - .name = "manufacturer", - .description = "Manufacturer", - .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION, - struct smbios_system_information, - manufacturer ), - .type = &setting_type_string, - }, - { - .name = "product", - .description = "Product name", - .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION, - struct smbios_system_information, - product ), - .type = &setting_type_string, - }, - { - .name = "serial", - .description = "Serial number", - .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION, - struct smbios_system_information, - serial ), - .type = &setting_type_string, - }, -}; diff --git a/src/arch/i386/include/bits/errfile.h b/src/arch/i386/include/bits/errfile.h index 70c78eaf..1723063b 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 00000000..647ea19e --- /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 <gpxe/bios_smbios.h> + +#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 00000000..0a6f277a --- /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 f2736dc3..00000000 --- a/src/arch/i386/include/smbios.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef _SMBIOS_H -#define _SMBIOS_H - -/** @file - * - * System Management BIOS - */ - -#include <stdint.h> - -/** 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 00000000..efaaef0d --- /dev/null +++ b/src/arch/i386/interface/pcbios/bios_smbios.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2007 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <gpxe/uaccess.h> +#include <gpxe/smbios.h> +#include <realmode.h> +#include <pnpbios.h> + +/** @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 ); |