Merge pull request #21 from mjg59/smbios

Add smbios command
This commit is contained in:
mjg59 2016-01-08 15:41:17 -08:00
commit b29d1d3258
10 changed files with 673 additions and 18 deletions

View file

@ -3848,6 +3848,7 @@ you forget a command, you can run the command @command{help}
* sha256sum:: Compute or check SHA256 hash * sha256sum:: Compute or check SHA256 hash
* sha512sum:: Compute or check SHA512 hash * sha512sum:: Compute or check SHA512 hash
* sleep:: Wait for a specified number of seconds * sleep:: Wait for a specified number of seconds
* smbios:: Retrieve SMBIOS information
* source:: Read a configuration file in same context * source:: Read a configuration file in same context
* test:: Check file types and compare values * test:: Check file types and compare values
* true:: Do nothing, successfully * true:: Do nothing, successfully
@ -4967,6 +4968,74 @@ if timeout was interrupted by @key{ESC}.
@end deffn @end deffn
@node smbios
@subsection smbios
@deffn Command smbios @
[@option{--type} @var{type}] @
[@option{--handle} @var{handle}] @
[@option{--match} @var{match}] @
(@option{--get-byte} | @option{--get-word} | @option{--get-dword} | @
@option{--get-qword} | @option{--get-string} | @option{--get-uuid}) @
@var{offset} @
[@option{--set} @var{variable}]
Retrieve SMBIOS information.
The @command{smbios} command returns the value of a field in an SMBIOS
structure. The following options determine which structure to select.
@itemize @bullet
@item
Specifying @option{--type} will select structures with a matching
@var{type}. The type can be any integer from 0 to 255.
@item
Specifying @option{--handle} will select structures with a matching
@var{handle}. The handle can be any integer from 0 to 65535.
@item
Specifying @option{--match} will select structure number @var{match} in the
filtered list of structures; e.g. @code{smbios --type 4 --match 2} will select
the second Process Information (Type 4) structure. The list is always ordered
the same as the hardware's SMBIOS table. The match number must be a positive
integer. If unspecified, the first matching structure will be selected.
@end itemize
The remaining options determine which field in the selected SMBIOS structure to
return. Only one of these options may be specified at a time.
@itemize @bullet
@item
When given @option{--get-byte}, return the value of the byte
at @var{offset} bytes into the selected SMBIOS structure.
@item
When given @option{--get-word}, return the value of the word (two bytes)
at @var{offset} bytes into the selected SMBIOS structure.
@item
When given @option{--get-dword}, return the value of the dword (four bytes)
at @var{offset} bytes into the selected SMBIOS structure.
@item
When given @option{--get-qword}, return the value of the qword (eight bytes)
at @var{offset} bytes into the selected SMBIOS structure.
@item
When given @option{--get-string}, return the string with its index found
at @var{offset} bytes into the selected SMBIOS structure.
@item
When given @option{--get-uuid}, return the value of the UUID (sixteen bytes)
at @var{offset} bytes into the selected SMBIOS structure.
@end itemize
The default action is to print the value of the requested field to the console,
but a variable name can be specified with @option{--set} to store the value
instead of printing it.
For example, this will store and then display the system manufacturer's name.
@example
smbios --type 1 --get-string 4 --set system_manufacturer
echo $system_manufacturer
@end example
@end deffn
@node source @node source
@subsection source @subsection source

View file

@ -1053,6 +1053,21 @@ module = {
common = commands/sleep.c; common = commands/sleep.c;
}; };
module = {
name = smbios;
common = commands/smbios.c;
efi = commands/efi/smbios.c;
i386_pc = commands/i386/pc/smbios.c;
i386_coreboot = commands/i386/pc/smbios.c;
i386_multiboot = commands/i386/pc/smbios.c;
enable = efi;
enable = i386_pc;
enable = i386_coreboot;
enable = i386_multiboot;
};
module = { module = {
name = suspend; name = suspend;
ieee1275 = commands/ieee1275/suspend.c; ieee1275 = commands/ieee1275/suspend.c;

View file

@ -30,6 +30,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
static grub_efi_guid_t acpi_guid = GRUB_EFI_ACPI_TABLE_GUID; static grub_efi_guid_t acpi_guid = GRUB_EFI_ACPI_TABLE_GUID;
static grub_efi_guid_t acpi2_guid = GRUB_EFI_ACPI_20_TABLE_GUID; static grub_efi_guid_t acpi2_guid = GRUB_EFI_ACPI_20_TABLE_GUID;
static grub_efi_guid_t smbios_guid = GRUB_EFI_SMBIOS_TABLE_GUID; static grub_efi_guid_t smbios_guid = GRUB_EFI_SMBIOS_TABLE_GUID;
static grub_efi_guid_t smbios3_guid = GRUB_EFI_SMBIOS3_TABLE_GUID;
#define EBDA_SEG_ADDR 0x40e #define EBDA_SEG_ADDR 0x40e
#define LOW_MEM_ADDR 0x413 #define LOW_MEM_ADDR 0x413
@ -93,7 +94,7 @@ static void
fake_bios_data (int use_rom) fake_bios_data (int use_rom)
{ {
unsigned i; unsigned i;
void *acpi, *smbios; void *acpi, *smbios, *smbios3;
grub_uint16_t *ebda_seg_ptr, *low_mem_ptr; grub_uint16_t *ebda_seg_ptr, *low_mem_ptr;
ebda_seg_ptr = (grub_uint16_t *) EBDA_SEG_ADDR; ebda_seg_ptr = (grub_uint16_t *) EBDA_SEG_ADDR;
@ -103,6 +104,7 @@ fake_bios_data (int use_rom)
acpi = 0; acpi = 0;
smbios = 0; smbios = 0;
smbios3 = 0;
for (i = 0; i < grub_efi_system_table->num_table_entries; i++) for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
{ {
grub_efi_packed_guid_t *guid = grub_efi_packed_guid_t *guid =
@ -127,6 +129,11 @@ fake_bios_data (int use_rom)
smbios = grub_efi_system_table->configuration_table[i].vendor_table; smbios = grub_efi_system_table->configuration_table[i].vendor_table;
grub_dprintf ("efi", "SMBIOS: %p\n", smbios); grub_dprintf ("efi", "SMBIOS: %p\n", smbios);
} }
else if (! grub_memcmp (guid, &smbios3_guid, sizeof (grub_efi_guid_t)))
{
smbios3 = grub_efi_system_table->configuration_table[i].vendor_table;
grub_dprintf ("efi", "SMBIOS3: %p\n", smbios3);
}
} }
*ebda_seg_ptr = FAKE_EBDA_SEG; *ebda_seg_ptr = FAKE_EBDA_SEG;
@ -137,8 +144,13 @@ fake_bios_data (int use_rom)
if (acpi) if (acpi)
grub_memcpy ((char *) ((FAKE_EBDA_SEG << 4) + 16), acpi, 1024 - 16); grub_memcpy ((char *) ((FAKE_EBDA_SEG << 4) + 16), acpi, 1024 - 16);
if ((use_rom) && (smbios)) if (use_rom)
grub_memcpy ((char *) SBIOS_ADDR, (char *) smbios + 16, 16); {
if (smbios)
grub_memcpy ((char *) SBIOS_ADDR, (char *) smbios, 31);
if (smbios3)
grub_memcpy ((char *) SBIOS_ADDR + 32, (char *) smbios3, 24);
}
} }
static grub_err_t static grub_err_t

View file

@ -48,6 +48,7 @@ static const struct guid_mapping guid_mappings[] =
{ GRUB_EFI_MPS_TABLE_GUID, "MPS"}, { GRUB_EFI_MPS_TABLE_GUID, "MPS"},
{ GRUB_EFI_SAL_TABLE_GUID, "SAL"}, { GRUB_EFI_SAL_TABLE_GUID, "SAL"},
{ GRUB_EFI_SMBIOS_TABLE_GUID, "SMBIOS"}, { GRUB_EFI_SMBIOS_TABLE_GUID, "SMBIOS"},
{ GRUB_EFI_SMBIOS3_TABLE_GUID, "SMBIOS3"},
{ GRUB_EFI_SYSTEM_RESOURCE_TABLE_GUID, "SYSTEM RESOURCE TABLE"}, { GRUB_EFI_SYSTEM_RESOURCE_TABLE_GUID, "SYSTEM RESOURCE TABLE"},
{ GRUB_EFI_TIANO_CUSTOM_DECOMPRESS_GUID, "TIANO CUSTOM DECOMPRESS"}, { GRUB_EFI_TIANO_CUSTOM_DECOMPRESS_GUID, "TIANO CUSTOM DECOMPRESS"},
{ GRUB_EFI_TSC_FREQUENCY_GUID, "TSC FREQUENCY"}, { GRUB_EFI_TSC_FREQUENCY_GUID, "TSC FREQUENCY"},

View file

@ -0,0 +1,59 @@
/* smbios.c - get smbios tables. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2015 Free Software Foundation, Inc.
*
* GRUB 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 3 of the License, or
* (at your option) any later version.
*
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/smbios.h>
#include <grub/misc.h>
#include <grub/efi/efi.h>
#include <grub/efi/api.h>
struct grub_smbios_eps *
grub_machine_smbios_get_eps (void)
{
unsigned i;
static grub_efi_packed_guid_t smbios_guid = GRUB_EFI_SMBIOS_TABLE_GUID;
for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
{
grub_efi_packed_guid_t *guid =
&grub_efi_system_table->configuration_table[i].vendor_guid;
if (! grub_memcmp (guid, &smbios_guid, sizeof (grub_efi_packed_guid_t)))
return (struct grub_smbios_eps *)
grub_efi_system_table->configuration_table[i].vendor_table;
}
return 0;
}
struct grub_smbios_eps3 *
grub_machine_smbios_get_eps3 (void)
{
unsigned i;
static grub_efi_packed_guid_t smbios3_guid = GRUB_EFI_SMBIOS3_TABLE_GUID;
for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
{
grub_efi_packed_guid_t *guid =
&grub_efi_system_table->configuration_table[i].vendor_guid;
if (! grub_memcmp (guid, &smbios3_guid, sizeof (grub_efi_packed_guid_t)))
return (struct grub_smbios_eps3 *)
grub_efi_system_table->configuration_table[i].vendor_table;
}
return 0;
}

View file

@ -0,0 +1,50 @@
/* smbios.c - get smbios tables. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2015 Free Software Foundation, Inc.
*
* GRUB 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 3 of the License, or
* (at your option) any later version.
*
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/acpi.h>
#include <grub/smbios.h>
#include <grub/misc.h>
struct grub_smbios_eps *
grub_machine_smbios_get_eps (void)
{
grub_uint8_t *ptr;
grub_dprintf ("smbios", "Looking for SMBIOS EPS. Scanning BIOS\n");
for (ptr = (grub_uint8_t *) 0xf0000; ptr < (grub_uint8_t *) 0x100000;
ptr += 16)
if (grub_memcmp (ptr, "_SM_", 4) == 0
&& grub_byte_checksum (ptr, sizeof (struct grub_smbios_eps)) == 0)
return (struct grub_smbios_eps *) ptr;
return 0;
}
struct grub_smbios_eps3 *
grub_machine_smbios_get_eps3 (void)
{
grub_uint8_t *ptr;
grub_dprintf ("smbios", "Looking for SMBIOS3 EPS. Scanning BIOS\n");
for (ptr = (grub_uint8_t *) 0xf0000; ptr < (grub_uint8_t *) 0x100000;
ptr += 16)
if (grub_memcmp (ptr, "_SM3_", 5) == 0
&& grub_byte_checksum (ptr, sizeof (struct grub_smbios_eps3)) == 0)
return (struct grub_smbios_eps3 *) ptr;
return 0;
}

372
grub-core/commands/smbios.c Normal file
View file

@ -0,0 +1,372 @@
/* smbios.c - retrieve smbios information. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013,2014,2015 Free Software Foundation, Inc.
*
* GRUB 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 3 of the License, or
* (at your option) any later version.
*
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/dl.h>
#include <grub/env.h>
#include <grub/extcmd.h>
#include <grub/i18n.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/smbios.h>
GRUB_MOD_LICENSE ("GPLv3+");
/* Locate the SMBIOS entry point structure depending on the hardware. */
struct grub_smbios_eps *
grub_smbios_get_eps (void)
{
static struct grub_smbios_eps *eps = NULL;
if (eps != NULL)
return eps;
eps = grub_machine_smbios_get_eps ();
return eps;
}
/* Locate the SMBIOS3 entry point structure depending on the hardware. */
struct grub_smbios_eps3 *
grub_smbios_get_eps3 (void)
{
static struct grub_smbios_eps3 *eps = NULL;
if (eps != NULL)
return eps;
eps = grub_machine_smbios_get_eps3 ();
return eps;
}
/* Abstract useful values found in either the SMBIOS3 or SMBIOS EPS. */
static struct {
grub_addr_t start;
grub_addr_t end;
grub_uint16_t structures;
} table_desc = {0, 0, 0};
/*
* These functions convert values from the various SMBIOS structure field types
* into a string formatted to be returned to the user. They expect that the
* structure and offset were already validated. The given buffer stores the
* newly formatted string if needed. When the requested data is successfully
* retrieved and formatted, the pointer to the string is returned; otherwise,
* NULL is returned on failure.
*/
static const char *
grub_smbios_format_byte (char *buffer, grub_size_t size,
const grub_uint8_t *structure, grub_uint8_t offset)
{
grub_snprintf (buffer, size, "%u", structure[offset]);
return (const char *)buffer;
}
static const char *
grub_smbios_format_word (char *buffer, grub_size_t size,
const grub_uint8_t *structure, grub_uint8_t offset)
{
grub_uint16_t value = grub_get_unaligned16 (structure + offset);
grub_snprintf (buffer, size, "%u", value);
return (const char *)buffer;
}
static const char *
grub_smbios_format_dword (char *buffer, grub_size_t size,
const grub_uint8_t *structure, grub_uint8_t offset)
{
grub_uint32_t value = grub_get_unaligned32 (structure + offset);
grub_snprintf (buffer, size, "%" PRIuGRUB_UINT32_T, value);
return (const char *)buffer;
}
static const char *
grub_smbios_format_qword (char *buffer, grub_size_t size,
const grub_uint8_t *structure, grub_uint8_t offset)
{
grub_uint64_t value = grub_get_unaligned64 (structure + offset);
grub_snprintf (buffer, size, "%" PRIuGRUB_UINT64_T, value);
return (const char *)buffer;
}
/* The matching string pointer is returned directly to avoid extra copying. */
static const char *
grub_smbios_get_string (char *buffer __attribute__ ((unused)),
grub_size_t size __attribute__ ((unused)),
const grub_uint8_t *structure, grub_uint8_t offset)
{
const grub_uint8_t *ptr = structure + structure[1];
const grub_uint8_t *table_end = (const grub_uint8_t *)table_desc.end;
const grub_uint8_t referenced_string_number = structure[offset];
grub_uint8_t i;
/* A string referenced with zero is interpreted as unset. */
if (referenced_string_number == 0)
return NULL;
/* Search the string set. */
for (i = 1; *ptr != 0 && ptr < table_end; i++)
if (i == referenced_string_number)
{
const char *str = (const char *)ptr;
while (*ptr++ != 0)
if (ptr >= table_end)
return NULL; /* The string isn't terminated. */
return str;
}
else
while (*ptr++ != 0 && ptr < table_end);
/* The string number is greater than the number of strings in the set. */
return NULL;
}
static const char *
grub_smbios_format_uuid (char *buffer, grub_size_t size,
const grub_uint8_t *structure, grub_uint8_t offset)
{
const grub_uint8_t *f = structure + offset; /* little-endian fields */
const grub_uint8_t *g = f + 8; /* byte-by-byte fields */
grub_snprintf (buffer, size,
"%02x%02x%02x%02x-%02x%02x-%02x%02x-"
"%02x%02x-%02x%02x%02x%02x%02x%02x",
f[3], f[2], f[1], f[0], f[5], f[4], f[7], f[6],
g[0], g[1], g[2], g[3], g[4], g[5], g[6], g[7]);
return (const char *)buffer;
}
/* List the field formatting functions and the number of bytes they need. */
#define MAXIMUM_FORMAT_LENGTH (sizeof ("ffffffff-ffff-ffff-ffff-ffffffffffff"))
static const struct {
const char *(*format) (char *buffer, grub_size_t size,
const grub_uint8_t *structure, grub_uint8_t offset);
grub_uint8_t field_length;
} field_extractors[] = {
{grub_smbios_format_byte, 1},
{grub_smbios_format_word, 2},
{grub_smbios_format_dword, 4},
{grub_smbios_format_qword, 8},
{grub_smbios_get_string, 1},
{grub_smbios_format_uuid, 16}
};
/* List command options, with structure field getters ordered as above. */
#define FIRST_GETTER_OPT (3)
#define SETTER_OPT (FIRST_GETTER_OPT + ARRAY_SIZE(field_extractors))
static const struct grub_arg_option options[] = {
{"type", 't', 0, N_("Match entries with the given type."),
N_("type"), ARG_TYPE_INT},
{"handle", 'h', 0, N_("Match entries with the given handle."),
N_("handle"), ARG_TYPE_INT},
{"match", 'm', 0, N_("Select a structure when several match."),
N_("match"), ARG_TYPE_INT},
{"get-byte", 'b', 0, N_("Get the byte's value at the given offset."),
N_("offset"), ARG_TYPE_INT},
{"get-word", 'w', 0, N_("Get two bytes' value at the given offset."),
N_("offset"), ARG_TYPE_INT},
{"get-dword", 'd', 0, N_("Get four bytes' value at the given offset."),
N_("offset"), ARG_TYPE_INT},
{"get-qword", 'q', 0, N_("Get eight bytes' value at the given offset."),
N_("offset"), ARG_TYPE_INT},
{"get-string", 's', 0, N_("Get the string specified at the given offset."),
N_("offset"), ARG_TYPE_INT},
{"get-uuid", 'u', 0, N_("Get the UUID's value at the given offset."),
N_("offset"), ARG_TYPE_INT},
{"set", '\0', 0, N_("Store the value in the given variable name."),
N_("variable"), ARG_TYPE_STRING},
{0, 0, 0, 0, 0, 0}
};
/*
* Return a matching SMBIOS structure.
*
* This method can use up to three criteria for selecting a structure:
* - The "type" field (use -1 to ignore)
* - The "handle" field (use -1 to ignore)
* - Which to return if several match (use 0 to ignore)
*
* The return value is a pointer to the first matching structure. If no
* structures match the given parameters, NULL is returned.
*/
static const grub_uint8_t *
grub_smbios_match_structure (const grub_int16_t type,
const grub_int32_t handle,
const grub_uint16_t match)
{
const grub_uint8_t *ptr = (const grub_uint8_t *)table_desc.start;
const grub_uint8_t *table_end = (const grub_uint8_t *)table_desc.end;
grub_uint16_t structures = table_desc.structures;
grub_uint16_t structure_count = 0;
grub_uint16_t matches = 0;
while (ptr < table_end
&& ptr[1] >= 4 /* Valid structures include the 4-byte header. */
&& (structure_count++ < structures || structures == 0))
{
grub_uint16_t structure_handle = grub_get_unaligned16 (ptr + 2);
grub_uint8_t structure_type = ptr[0];
if ((handle < 0 || handle == structure_handle)
&& (type < 0 || type == structure_type)
&& (match == 0 || match == ++matches))
return ptr;
else
{
ptr += ptr[1];
while ((*ptr++ != 0 || *ptr++ != 0) && ptr < table_end);
}
if (structure_type == GRUB_SMBIOS_TYPE_END_OF_TABLE)
break;
}
return NULL;
}
static grub_err_t
grub_cmd_smbios (grub_extcmd_context_t ctxt,
int argc __attribute__ ((unused)),
char **argv __attribute__ ((unused)))
{
struct grub_arg_list *state = ctxt->state;
grub_int16_t type = -1;
grub_int32_t handle = -1;
grub_uint16_t match = 0;
grub_uint8_t offset = 0;
const grub_uint8_t *structure;
const char *value;
char buffer[MAXIMUM_FORMAT_LENGTH];
grub_int32_t option;
grub_int8_t field_type = -1;
grub_uint8_t i;
if (table_desc.start == 0)
return grub_error (GRUB_ERR_IO,
N_("the SMBIOS entry point structure was not found"));
/* Read the given filtering options. */
if (state[0].set)
{
option = grub_strtol (state[0].arg, NULL, 0);
if (option < 0 || option > 255)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("the type must be between 0 and 255"));
type = (grub_int16_t)option;
}
if (state[1].set)
{
option = grub_strtol (state[1].arg, NULL, 0);
if (option < 0 || option > 65535)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("the handle must be between 0 and 65535"));
handle = (grub_int32_t)option;
}
if (state[2].set)
{
option = grub_strtol (state[2].arg, NULL, 0);
if (option <= 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("the match must be a positive integer"));
match = (grub_uint16_t)option;
}
/* Determine the data type of the structure field to retrieve. */
for (i = 0; i < ARRAY_SIZE(field_extractors); i++)
if (state[FIRST_GETTER_OPT + i].set)
{
if (field_type >= 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("only one --get option is usable at a time"));
field_type = i;
}
/* Require a choice of a structure field to return. */
if (field_type < 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("one of the --get options is required"));
/* Locate a matching SMBIOS structure. */
structure = grub_smbios_match_structure (type, handle, match);
if (structure == NULL)
return grub_error (GRUB_ERR_IO,
N_("no structure matched the given options"));
/* Ensure the requested byte offset is inside the structure. */
option = grub_strtol (state[FIRST_GETTER_OPT + field_type].arg, NULL, 0);
if (option < 0 || option >= structure[1])
return grub_error (GRUB_ERR_OUT_OF_RANGE,
N_("the given offset is outside the structure"));
/* Ensure the requested data type at the offset is inside the structure. */
offset = (grub_uint8_t)option;
if (offset + field_extractors[field_type].field_length > structure[1])
return grub_error (GRUB_ERR_OUT_OF_RANGE,
N_("the field ends outside the structure"));
/* Format the requested structure field into a readable string. */
value = field_extractors[field_type].format (buffer, sizeof (buffer),
structure, offset);
if (value == NULL)
return grub_error (GRUB_ERR_IO,
N_("failed to retrieve the structure field"));
/* Store or print the formatted value. */
if (state[SETTER_OPT].set)
grub_env_set (state[SETTER_OPT].arg, value);
else
grub_printf ("%s\n", value);
return GRUB_ERR_NONE;
}
static grub_extcmd_t cmd;
GRUB_MOD_INIT(smbios)
{
struct grub_smbios_eps3 *eps3;
struct grub_smbios_eps *eps;
if ((eps3 = grub_smbios_get_eps3 ()))
{
table_desc.start = (grub_addr_t)eps3->table_address;
table_desc.end = table_desc.start + eps3->maximum_table_length;
table_desc.structures = 0; /* SMBIOS3 drops the structure count. */
}
else if ((eps = grub_smbios_get_eps ()))
{
table_desc.start = (grub_addr_t)eps->intermediate.table_address;
table_desc.end = table_desc.start + eps->intermediate.table_length;
table_desc.structures = eps->intermediate.structures;
}
cmd = grub_register_extcmd ("smbios", grub_cmd_smbios, 0,
N_("[-t type] [-h handle] [-m match] "
"(-b|-w|-d|-q|-s|-u) offset "
"[--set variable]"),
N_("Retrieve SMBIOS information."), options);
}
GRUB_MOD_FINI(smbios)
{
grub_unregister_extcmd (cmd);
}

View file

@ -22,18 +22,22 @@
#include <grub/misc.h> #include <grub/misc.h>
#include <grub/mm.h> #include <grub/mm.h>
#include <grub/acpi.h> #include <grub/acpi.h>
#include <grub/smbios.h>
grub_err_t grub_err_t
grub_machine_efiemu_init_tables (void) grub_machine_efiemu_init_tables (void)
{ {
grub_uint8_t *ptr;
void *table; void *table;
grub_err_t err; grub_err_t err;
grub_efi_guid_t smbios = GRUB_EFI_SMBIOS_TABLE_GUID; grub_efi_guid_t smbios = GRUB_EFI_SMBIOS_TABLE_GUID;
grub_efi_guid_t smbios3 = GRUB_EFI_SMBIOS3_TABLE_GUID;
grub_efi_guid_t acpi20 = GRUB_EFI_ACPI_20_TABLE_GUID; grub_efi_guid_t acpi20 = GRUB_EFI_ACPI_20_TABLE_GUID;
grub_efi_guid_t acpi = GRUB_EFI_ACPI_TABLE_GUID; grub_efi_guid_t acpi = GRUB_EFI_ACPI_TABLE_GUID;
err = grub_efiemu_unregister_configuration_table (smbios); err = grub_efiemu_unregister_configuration_table (smbios);
if (err)
return err;
err = grub_efiemu_unregister_configuration_table (smbios3);
if (err) if (err)
return err; return err;
err = grub_efiemu_unregister_configuration_table (acpi); err = grub_efiemu_unregister_configuration_table (acpi);
@ -43,6 +47,20 @@ grub_machine_efiemu_init_tables (void)
if (err) if (err)
return err; return err;
table = grub_smbios_get_eps ();
if (table)
{
err = grub_efiemu_register_configuration_table (smbios, 0, 0, table);
if (err)
return err;
}
table = grub_smbios_get_eps3 ();
if (table)
{
err = grub_efiemu_register_configuration_table (smbios3, 0, 0, table);
if (err)
return err;
}
table = grub_acpi_get_rsdpv1 (); table = grub_acpi_get_rsdpv1 ();
if (table) if (table)
{ {
@ -58,19 +76,5 @@ grub_machine_efiemu_init_tables (void)
return err; return err;
} }
for (ptr = (grub_uint8_t *) 0xf0000; ptr < (grub_uint8_t *) 0x100000;
ptr += 16)
if (grub_memcmp (ptr, "_SM_", 4) == 0
&& grub_byte_checksum (ptr, *(ptr + 5)) == 0)
break;
if (ptr < (grub_uint8_t *) 0x100000)
{
grub_dprintf ("efiemu", "Registering SMBIOS\n");
err = grub_efiemu_register_configuration_table (smbios, 0, 0, ptr);
if (err)
return err;
}
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }

View file

@ -314,6 +314,11 @@
{ 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
} }
#define GRUB_EFI_SMBIOS3_TABLE_GUID \
{ 0xf2fd1544, 0x9794, 0x4a2c, \
{ 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94 } \
}
#define GRUB_EFI_SAL_TABLE_GUID \ #define GRUB_EFI_SAL_TABLE_GUID \
{ 0xeb9d2d32, 0x2d88, 0x11d3, \ { 0xeb9d2d32, 0x2d88, 0x11d3, \
{ 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \

68
include/grub/smbios.h Normal file
View file

@ -0,0 +1,68 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2015 Free Software Foundation, Inc.
*
* GRUB 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 3 of the License, or
* (at your option) any later version.
*
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_SMBIOS_HEADER
#define GRUB_SMBIOS_HEADER 1
#include <grub/types.h>
#define GRUB_SMBIOS_TYPE_END_OF_TABLE ((grub_uint8_t)127)
struct grub_smbios_ieps
{
grub_uint8_t anchor[5]; /* "_DMI_" */
grub_uint8_t checksum;
grub_uint16_t table_length;
grub_uint32_t table_address;
grub_uint16_t structures;
grub_uint8_t revision;
} GRUB_PACKED;
struct grub_smbios_eps
{
grub_uint8_t anchor[4]; /* "_SM_" */
grub_uint8_t checksum;
grub_uint8_t length; /* 0x1f */
grub_uint8_t version_major;
grub_uint8_t version_minor;
grub_uint16_t maximum_structure_size;
grub_uint8_t revision;
grub_uint8_t formatted[5];
struct grub_smbios_ieps intermediate;
} GRUB_PACKED;
struct grub_smbios_eps3
{
grub_uint8_t anchor[5]; /* "_SM3_" */
grub_uint8_t checksum;
grub_uint8_t length; /* 0x18 */
grub_uint8_t version_major;
grub_uint8_t version_minor;
grub_uint8_t docrev;
grub_uint8_t revision;
grub_uint8_t reserved;
grub_uint32_t maximum_table_length;
grub_uint64_t table_address;
} GRUB_PACKED;
struct grub_smbios_eps *grub_smbios_get_eps (void);
struct grub_smbios_eps3 *grub_smbios_get_eps3 (void);
struct grub_smbios_eps *grub_machine_smbios_get_eps (void);
struct grub_smbios_eps3 *grub_machine_smbios_get_eps3 (void);
#endif /* ! GRUB_SMBIOS_HEADER */