diff --git a/docs/grub.texi b/docs/grub.texi
index 11a0e9ad8..3d50b16ba 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -3944,6 +3944,7 @@ you forget a command, you can run the command @command{help}
* sha256sum:: Compute or check SHA256 hash
* sha512sum:: Compute or check SHA512 hash
* sleep:: Wait for a specified number of seconds
+* smbios:: Retrieve SMBIOS information
* source:: Read a configuration file in same context
* test:: Check file types and compare values
* true:: Do nothing, successfully
@@ -5085,6 +5086,80 @@ if timeout was interrupted by @key{ESC}.
@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.
+It will be formatted as an unsigned decimal integer.
+@item
+When given @option{--get-word}, return the value of the word (two bytes)
+at @var{offset} bytes into the selected SMBIOS structure.
+It will be formatted as an unsigned decimal integer.
+@item
+When given @option{--get-dword}, return the value of the dword (four bytes)
+at @var{offset} bytes into the selected SMBIOS structure.
+It will be formatted as an unsigned decimal integer.
+@item
+When given @option{--get-qword}, return the value of the qword (eight bytes)
+at @var{offset} bytes into the selected SMBIOS structure.
+It will be formatted as an unsigned decimal integer.
+@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.
+It will be formatted as lower-case hyphenated hexadecimal digits, with the
+first three fields as little-endian, and the rest printed byte-by-byte.
+@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
@subsection source
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 474a63e68..269370417 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1097,6 +1097,21 @@ module = {
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 = {
name = suspend;
ieee1275 = commands/ieee1275/suspend.c;
diff --git a/grub-core/commands/efi/smbios.c b/grub-core/commands/efi/smbios.c
new file mode 100644
index 000000000..75202d5aa
--- /dev/null
+++ b/grub-core/commands/efi/smbios.c
@@ -0,0 +1,61 @@
+/* smbios.c - get smbios tables. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2019 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 .
+ */
+
+#include
+#include
+#include
+#include
+
+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;
+}
diff --git a/grub-core/commands/i386/pc/smbios.c b/grub-core/commands/i386/pc/smbios.c
new file mode 100644
index 000000000..069d66367
--- /dev/null
+++ b/grub-core/commands/i386/pc/smbios.c
@@ -0,0 +1,52 @@
+/* smbios.c - get smbios tables. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2019 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 .
+ */
+
+#include
+#include
+#include
+
+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;
+}
diff --git a/grub-core/commands/smbios.c b/grub-core/commands/smbios.c
new file mode 100644
index 000000000..7a6a391fc
--- /dev/null
+++ b/grub-core/commands/smbios.c
@@ -0,0 +1,374 @@
+/* smbios.c - retrieve smbios information. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2019 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 .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* 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;
+
+static grub_extcmd_t cmd;
+
+/* 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. */
+static 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;
+}
+
+/*
+ * 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. When the requested data is
+ * successfully retrieved and formatted, the pointer to the string is returned;
+ * otherwise, NULL is returned on failure. Don't free the result.
+ */
+
+static const char *
+grub_smbios_format_byte (const grub_uint8_t *structure, grub_uint8_t offset)
+{
+ static char buffer[sizeof ("255")];
+
+ grub_snprintf (buffer, sizeof (buffer), "%u", structure[offset]);
+
+ return (const char *)buffer;
+}
+
+static const char *
+grub_smbios_format_word (const grub_uint8_t *structure, grub_uint8_t offset)
+{
+ static char buffer[sizeof ("65535")];
+
+ grub_uint16_t value = grub_get_unaligned16 (structure + offset);
+ grub_snprintf (buffer, sizeof (buffer), "%u", value);
+
+ return (const char *)buffer;
+}
+
+static const char *
+grub_smbios_format_dword (const grub_uint8_t *structure, grub_uint8_t offset)
+{
+ static char buffer[sizeof ("4294967295")];
+
+ grub_uint32_t value = grub_get_unaligned32 (structure + offset);
+ grub_snprintf (buffer, sizeof (buffer), "%" PRIuGRUB_UINT32_T, value);
+
+ return (const char *)buffer;
+}
+
+static const char *
+grub_smbios_format_qword (const grub_uint8_t *structure, grub_uint8_t offset)
+{
+ static char buffer[sizeof ("18446744073709551615")];
+
+ grub_uint64_t value = grub_get_unaligned64 (structure + offset);
+ grub_snprintf (buffer, sizeof (buffer), "%" PRIuGRUB_UINT64_T, value);
+
+ return (const char *)buffer;
+}
+
+static const char *
+grub_smbios_get_string (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 (const grub_uint8_t *structure, grub_uint8_t offset)
+{
+ static char buffer[sizeof ("ffffffff-ffff-ffff-ffff-ffffffffffff")];
+ const grub_uint8_t *f = structure + offset; /* little-endian fields */
+ const grub_uint8_t *g = f + 8; /* byte-by-byte fields */
+
+ grub_snprintf (buffer, sizeof (buffer),
+ "%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. */
+static const struct {
+ const char *(*format) (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 structures with the given type."),
+ N_("type"), ARG_TYPE_INT},
+ {"handle", 'h', 0, N_("Match structures 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;
+ 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 || option > 65535)
+ 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 (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;
+}
+
+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);
+}
diff --git a/grub-core/efiemu/i386/pc/cfgtables.c b/grub-core/efiemu/i386/pc/cfgtables.c
index 492c07c46..e5fffb7d4 100644
--- a/grub-core/efiemu/i386/pc/cfgtables.c
+++ b/grub-core/efiemu/i386/pc/cfgtables.c
@@ -22,11 +22,11 @@
#include
#include
#include
+#include
grub_err_t
grub_machine_efiemu_init_tables (void)
{
- grub_uint8_t *ptr;
void *table;
grub_err_t err;
grub_efi_guid_t smbios = GRUB_EFI_SMBIOS_TABLE_GUID;
@@ -57,17 +57,10 @@ grub_machine_efiemu_init_tables (void)
if (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)
+ table = grub_smbios_get_eps ();
+ if (table)
{
- grub_dprintf ("efiemu", "Registering SMBIOS\n");
- err = grub_efiemu_register_configuration_table (smbios, 0, 0, ptr);
+ err = grub_efiemu_register_configuration_table (smbios, 0, 0, table);
if (err)
return err;
}
diff --git a/include/grub/smbios.h b/include/grub/smbios.h
new file mode 100644
index 000000000..15ec260b3
--- /dev/null
+++ b/include/grub/smbios.h
@@ -0,0 +1,69 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2019 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 .
+ */
+
+#ifndef GRUB_SMBIOS_HEADER
+#define GRUB_SMBIOS_HEADER 1
+
+#include
+#include
+
+#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;
+
+extern struct grub_smbios_eps *grub_machine_smbios_get_eps (void);
+extern struct grub_smbios_eps3 *grub_machine_smbios_get_eps3 (void);
+
+extern struct grub_smbios_eps *EXPORT_FUNC (grub_smbios_get_eps) (void);
+
+#endif /* ! GRUB_SMBIOS_HEADER */