grub-devel.gnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 2/2] Add a module for retrieving SMBIOS information
@ 2016-03-09  4:37 David Michael
  2016-04-13 13:03 ` G Gregory
  2017-05-10  1:34 ` David Michael
  0 siblings, 2 replies; 5+ messages in thread
From: David Michael @ 2016-03-09  4:37 UTC (permalink / raw)
  To: grub-devel; +Cc: phcoder

The following are two use cases from Rajat Jain <rajatjain@juniper.net>:

1) We have a board that boots Linux and this board itself can be plugged into one of different chassis types. We need to pass different parameters to the kernel based on the "CHASSIS_TYPE" information that is passed by the bios in the DMI / SMBIOS tables.

2) We may have a USB stick that can go into multiple boards, and the exact kernel to be loaded depends on the machine information (PRODUCT_NAME etc) passed via the DMI.
---

Changes since v5:

* Replaced "entries" with "structures" in help to use consistent terms

To address points suggested by Andrei Borzenkov:

* Dropped explicitly initializing static struct to zero

* Test for the upper bound of the match number option

 docs/grub.texi                       |  75 ++++++++
 grub-core/Makefile.core.def          |  15 ++
 grub-core/commands/efi/smbios.c      |  59 ++++++
 grub-core/commands/i386/pc/smbios.c  |  50 +++++
 grub-core/commands/smbios.c          | 364 +++++++++++++++++++++++++++++++++++
 grub-core/efiemu/i386/pc/cfgtables.c |  15 +-
 include/grub/smbios.h                |  68 +++++++
 7 files changed, 635 insertions(+), 11 deletions(-)
 create mode 100644 grub-core/commands/efi/smbios.c
 create mode 100644 grub-core/commands/i386/pc/smbios.c
 create mode 100644 grub-core/commands/smbios.c
 create mode 100644 include/grub/smbios.h

diff --git a/docs/grub.texi b/docs/grub.texi
index 82f6fa4..c5bd812 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -3850,6 +3850,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
@@ -4972,6 +4973,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 58b4208..31c90f7 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1014,6 +1014,21 @@ module = {
 };
 
 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;
   enable = i386_ieee1275;
diff --git a/grub-core/commands/efi/smbios.c b/grub-core/commands/efi/smbios.c
new file mode 100644
index 0000000..b2440a8
--- /dev/null
+++ b/grub-core/commands/efi/smbios.c
@@ -0,0 +1,59 @@
+/* smbios.c - get smbios tables. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2016  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;
+}
diff --git a/grub-core/commands/i386/pc/smbios.c b/grub-core/commands/i386/pc/smbios.c
new file mode 100644
index 0000000..4637e93
--- /dev/null
+++ b/grub-core/commands/i386/pc/smbios.c
@@ -0,0 +1,50 @@
+/* smbios.c - get smbios tables. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2016  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;
+}
diff --git a/grub-core/commands/smbios.c b/grub-core/commands/smbios.c
new file mode 100644
index 0000000..3330439
--- /dev/null
+++ b/grub-core/commands/smbios.c
@@ -0,0 +1,364 @@
+/* smbios.c - retrieve smbios information. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2016  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;
+
+
+/*
+ * 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;
+}
+
+
+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);
+}
diff --git a/grub-core/efiemu/i386/pc/cfgtables.c b/grub-core/efiemu/i386/pc/cfgtables.c
index 492c07c..e5fffb7 100644
--- a/grub-core/efiemu/i386/pc/cfgtables.c
+++ b/grub-core/efiemu/i386/pc/cfgtables.c
@@ -22,11 +22,11 @@
 #include <grub/misc.h>
 #include <grub/mm.h>
 #include <grub/acpi.h>
+#include <grub/smbios.h>
 
 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 0000000..0e4cec8
--- /dev/null
+++ b/include/grub/smbios.h
@@ -0,0 +1,68 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2016  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 */
-- 
2.5.0



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v6 2/2] Add a module for retrieving SMBIOS information
  2016-03-09  4:37 [PATCH v6 2/2] Add a module for retrieving SMBIOS information David Michael
@ 2016-04-13 13:03 ` G Gregory
  2017-05-10  1:34 ` David Michael
  1 sibling, 0 replies; 5+ messages in thread
From: G Gregory @ 2016-04-13 13:03 UTC (permalink / raw)
  To: The development of GNU GRUB; +Cc: phcoder

On 9 March 2016 at 04:37, David Michael <fedora.dm0@gmail.com> wrote:
> The following are two use cases from Rajat Jain <rajatjain@juniper.net>:
>
> 1) We have a board that boots Linux and this board itself can be plugged into one of different chassis types. We need to pass different parameters to the kernel based on the "CHASSIS_TYPE" information that is passed by the bios in the DMI / SMBIOS tables.
>
> 2) We may have a USB stick that can go into multiple boards, and the exact kernel to be loaded depends on the machine information (PRODUCT_NAME etc) passed via the DMI.
> ---
>
I have usecases for this support in my little testing lab in Linaro.
Because not all the machines I use are in fully brought up state yet
it would be nice to supply custome cmdline arguments or load a
different kernel on some machines based on the machine name in SMBIOS.

Would love to see this enter grub.

Graeme

> Changes since v5:
>
> * Replaced "entries" with "structures" in help to use consistent terms
>
> To address points suggested by Andrei Borzenkov:
>
> * Dropped explicitly initializing static struct to zero
>
> * Test for the upper bound of the match number option
>
>  docs/grub.texi                       |  75 ++++++++
>  grub-core/Makefile.core.def          |  15 ++
>  grub-core/commands/efi/smbios.c      |  59 ++++++
>  grub-core/commands/i386/pc/smbios.c  |  50 +++++
>  grub-core/commands/smbios.c          | 364 +++++++++++++++++++++++++++++++++++
>  grub-core/efiemu/i386/pc/cfgtables.c |  15 +-
>  include/grub/smbios.h                |  68 +++++++
>  7 files changed, 635 insertions(+), 11 deletions(-)
>  create mode 100644 grub-core/commands/efi/smbios.c
>  create mode 100644 grub-core/commands/i386/pc/smbios.c
>  create mode 100644 grub-core/commands/smbios.c
>  create mode 100644 include/grub/smbios.h
>
> diff --git a/docs/grub.texi b/docs/grub.texi
> index 82f6fa4..c5bd812 100644
> --- a/docs/grub.texi
> +++ b/docs/grub.texi
> @@ -3850,6 +3850,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
> @@ -4972,6 +4973,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 58b4208..31c90f7 100644
> --- a/grub-core/Makefile.core.def
> +++ b/grub-core/Makefile.core.def
> @@ -1014,6 +1014,21 @@ module = {
>  };
>
>  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;
>    enable = i386_ieee1275;
> diff --git a/grub-core/commands/efi/smbios.c b/grub-core/commands/efi/smbios.c
> new file mode 100644
> index 0000000..b2440a8
> --- /dev/null
> +++ b/grub-core/commands/efi/smbios.c
> @@ -0,0 +1,59 @@
> +/* smbios.c - get smbios tables. */
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2016  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;
> +}
> diff --git a/grub-core/commands/i386/pc/smbios.c b/grub-core/commands/i386/pc/smbios.c
> new file mode 100644
> index 0000000..4637e93
> --- /dev/null
> +++ b/grub-core/commands/i386/pc/smbios.c
> @@ -0,0 +1,50 @@
> +/* smbios.c - get smbios tables. */
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2016  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;
> +}
> diff --git a/grub-core/commands/smbios.c b/grub-core/commands/smbios.c
> new file mode 100644
> index 0000000..3330439
> --- /dev/null
> +++ b/grub-core/commands/smbios.c
> @@ -0,0 +1,364 @@
> +/* smbios.c - retrieve smbios information. */
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2016  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;
> +
> +
> +/*
> + * 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;
> +}
> +
> +
> +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);
> +}
> diff --git a/grub-core/efiemu/i386/pc/cfgtables.c b/grub-core/efiemu/i386/pc/cfgtables.c
> index 492c07c..e5fffb7 100644
> --- a/grub-core/efiemu/i386/pc/cfgtables.c
> +++ b/grub-core/efiemu/i386/pc/cfgtables.c
> @@ -22,11 +22,11 @@
>  #include <grub/misc.h>
>  #include <grub/mm.h>
>  #include <grub/acpi.h>
> +#include <grub/smbios.h>
>
>  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 0000000..0e4cec8
> --- /dev/null
> +++ b/include/grub/smbios.h
> @@ -0,0 +1,68 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2016  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 */
> --
> 2.5.0
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v6 2/2] Add a module for retrieving SMBIOS information
  2016-03-09  4:37 [PATCH v6 2/2] Add a module for retrieving SMBIOS information David Michael
  2016-04-13 13:03 ` G Gregory
@ 2017-05-10  1:34 ` David Michael
  2017-05-10  4:53   ` Dennis Wassenberg
  1 sibling, 1 reply; 5+ messages in thread
From: David Michael @ 2017-05-10  1:34 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Vladimir 'φ-coder/phcoder' Serbinenko

Hi,

Bumping this thread, since it looks like new features are being
applied again, and the patch still seems to apply cleanly.  Is there
still interest in this module?  I didn't see any changes requested
with v6, but let me know if you'd like me to resend it (or the small
patch 1/2 for defining the UUID).

Thanks.

David


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v6 2/2] Add a module for retrieving SMBIOS information
  2017-05-10  1:34 ` David Michael
@ 2017-05-10  4:53   ` Dennis Wassenberg
  0 siblings, 0 replies; 5+ messages in thread
From: Dennis Wassenberg @ 2017-05-10  4:53 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Vladimir 'φ-coder/phcoder' Serbinenko

Hi,

from my side there is a big interest in this module.

I use it to detect specific hardware platforms. Dependant on the
hardware platforms there are several decisions in how to boot the
kernel. Thats why I would be pleased if these two patches will be
integrated into upstream grub2.

Best regards,

Dennis
On 10.05.2017 03:34, David Michael wrote:
> Hi,
> 
> Bumping this thread, since it looks like new features are being
> applied again, and the patch still seems to apply cleanly.  Is there
> still interest in this module?  I didn't see any changes requested
> with v6, but let me know if you'd like me to resend it (or the small
> patch 1/2 for defining the UUID).
> 
> Thanks.
> 
> David
> 
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
> 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v6 2/2] Add a module for retrieving SMBIOS information
       [not found] <mailman.35.1494432008.24579.grub-devel@gnu.org>
@ 2017-05-10 16:28 ` Brad Mouring
  0 siblings, 0 replies; 5+ messages in thread
From: Brad Mouring @ 2017-05-10 16:28 UTC (permalink / raw)
  To: grub-devel

> Hi,
> 
> Bumping this thread, since it looks like new features are being
> applied again, and the patch still seems to apply cleanly.  Is there
> still interest in this module?  I didn't see any changes requested
> with v6, but let me know if you'd like me to resend it (or the small
> patch 1/2 for defining the UUID).
> 
> Thanks.
> 
> David

We're currently using the patch, so

Tested-by: Brad Mouring <brad.mouring@ni.com>

Thanks David


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2017-05-10 16:28 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-03-09  4:37 [PATCH v6 2/2] Add a module for retrieving SMBIOS information David Michael
2016-04-13 13:03 ` G Gregory
2017-05-10  1:34 ` David Michael
2017-05-10  4:53   ` Dennis Wassenberg
     [not found] <mailman.35.1494432008.24579.grub-devel@gnu.org>
2017-05-10 16:28 ` Brad Mouring

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).