From: Ross Philipson <ross.philip...@oracle.com>

Signed-off-by: Ross Philipson <ross.philip...@oracle.com>
Signed-off-by: Daniel Kiper <daniel.ki...@oracle.com>
Signed-off-by: Krystian Hebel <krystian.he...@3mdeb.com>
---
 grub-core/loader/i386/txt/acmod.c | 605 ++++++++++++++++++++++++++++++
 1 file changed, 605 insertions(+)
 create mode 100644 grub-core/loader/i386/txt/acmod.c

diff --git a/grub-core/loader/i386/txt/acmod.c 
b/grub-core/loader/i386/txt/acmod.c
new file mode 100644
index 000000000..55675a2fd
--- /dev/null
+++ b/grub-core/loader/i386/txt/acmod.c
@@ -0,0 +1,605 @@
+/*
+ * acmod.c: support functions for use of Intel(r) TXT Authenticated
+ *          Code (AC) Modules
+ *
+ * Copyright (c) 2003-2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of the Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2020  Oracle and/or its affiliates.
+ *
+ *  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/loader.h>
+#include <grub/memory.h>
+#include <grub/normal.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/types.h>
+#include <grub/safemath.h>
+#include <grub/dl.h>
+#include <grub/cpu/relocator.h>
+#include <grub/i386/cpuid.h>
+#include <grub/i386/msr.h>
+#include <grub/i386/txt.h>
+
+/*
+ * Macro that returns value of it->field if it's inside info table, 0 
otherwise.
+ * Fields at or below 'length' ('uuid', 'chipset_acm_type', 'version') don't
+ * benefit from this macro, because it requires that 'length' (and by extension
+ * fields below that) is valid.
+ */
+#define info_table_get(it, field)                                              
 \
+  (__builtin_offsetof(struct grub_txt_acm_info_table, field) + 
sizeof(it->field)\
+   <= it->length ? it->field : 0)
+
+/*
+ * Returns hdr + offset if [offset, offset + count * size) is within the bounds
+ * of the ACM, NULL otherwise.
+ */
+static void *
+n_fit_in_acm (struct grub_txt_acm_header *hdr, grub_uint32_t offset,
+              grub_uint32_t size, grub_uint32_t count)
+{
+  grub_uint32_t total_size, elem_end;
+  /* ACM size overflow was checked in is_acmod() */
+  grub_uint32_t acm_len = hdr->size * 4;
+
+  /*
+   * `offset` will often come from `info_table_get`, and this is the most
+   * convenient place to check for the macro returning zero. This is fine, 
since
+   * there is no legitimate reason to access the zero offset in this manner.
+   */
+  if (offset == 0)
+    return NULL;
+
+  if (grub_mul (size, count, &total_size))
+    return NULL;
+
+  if (grub_add (offset, total_size, &elem_end))
+    return NULL;
+
+  if (elem_end > acm_len)
+    return NULL;
+
+  /*
+   * Not checking if (hdr + elem_end) overflows. We know that (hdr + acm_len)
+   * doesn't, and that elem_end <= acm_len. For the same reason we don't have
+   * to check if (hdr + offset) overflows.
+   */
+
+  return (void *) ((unsigned long) hdr + offset);
+}
+
+static void *
+fits_in_acm (struct grub_txt_acm_header *hdr, grub_uint32_t offset,
+             grub_uint32_t size)
+{
+  return n_fit_in_acm(hdr, offset, size, 1);
+}
+
+/*
+ * Returns pointer to ACM information table. If the table is located outside of
+ * ACM or its reported size is too small to cover at least 'length' field,
+ * NULL is returned instead.
+ */
+static struct grub_txt_acm_info_table*
+get_acmod_info_table (struct grub_txt_acm_header* hdr)
+{
+  grub_uint32_t user_area_off, info_table_size;
+  struct grub_txt_acm_info_table *ptr = NULL;
+  /* Minimum size required to read full size of table */
+  info_table_size = __builtin_offsetof (struct grub_txt_acm_info_table, length)
+                    + sizeof(ptr->length);
+
+  /* Overflow? */
+  if (grub_add (hdr->header_len, hdr->scratch_size, &user_area_off))
+    {
+      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM header length plus scratch 
size overflows"));
+      return NULL;
+    }
+
+  if (grub_mul (user_area_off, 4, &user_area_off))
+    {
+      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM header length and scratch 
size in bytes overflows"));
+      return NULL;
+    }
+
+  ptr = fits_in_acm(hdr, user_area_off, info_table_size);
+
+  if (ptr != NULL)
+    {
+      if (info_table_get (ptr, length) < info_table_size)
+        return NULL;
+
+      info_table_size = info_table_get (ptr, length);
+      ptr = fits_in_acm(hdr, user_area_off, info_table_size);
+    }
+
+  return ptr;
+}
+
+/*
+ * Function returns pointer to chipset ID list, after checking that
+ * grub_txt_acm_chipset_id_list and all grub_txt_acm_chipset_id structures are
+ * within ACM. Otherwise, NULL is returned.
+ */
+static struct grub_txt_acm_chipset_id_list*
+get_acmod_chipset_list (struct grub_txt_acm_header *hdr)
+{
+  struct grub_txt_acm_info_table *info_table;
+  grub_uint32_t id_entries_off;
+  struct grub_txt_acm_chipset_id_list *chipset_id_list;
+
+  /* This fn assumes that the ACM has already passed the is_acmod() checks */
+
+  info_table = get_acmod_info_table (hdr);
+  if (info_table == NULL)
+    {
+      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM info table out of bounds"));
+      return NULL;
+    }
+
+  chipset_id_list = fits_in_acm(hdr, info_table_get (info_table, 
chipset_id_list),
+                                sizeof(struct grub_txt_acm_chipset_id_list));
+  if (chipset_id_list == NULL)
+    {
+      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM chipset ID list out of 
bounds"));
+      return NULL;
+    }
+
+  /* Overflows were checked by fits_in_acm() */
+  id_entries_off = info_table->chipset_id_list + sizeof(*chipset_id_list);
+
+  if (n_fit_in_acm (hdr, id_entries_off, sizeof(struct 
grub_txt_acm_chipset_id),
+                    chipset_id_list->count) == NULL)
+    {
+      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM chipset ID entries out of 
bounds"));
+      return NULL;
+    }
+
+  return chipset_id_list;
+}
+
+/*
+ * Function returns pointer to processor ID list, after checking that
+ * grub_txt_acm_processor_id_list and all grub_txt_acm_processor_id structures
+ * are within ACM. Otherwise, NULL is returned.
+ */
+static struct grub_txt_acm_processor_id_list *
+get_acmod_processor_list (struct grub_txt_acm_header* hdr)
+{
+  struct grub_txt_acm_info_table *info_table;
+  grub_uint32_t id_entries_off;
+  struct grub_txt_acm_processor_id_list *proc_id_list;
+
+  /* This fn assumes that the ACM has already passed the is_acmod() checks */
+
+  info_table = get_acmod_info_table (hdr);
+  if (info_table == NULL)
+    {
+      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM info table out of bounds"));
+      return NULL;
+    }
+
+  proc_id_list = fits_in_acm (hdr, info_table_get (info_table, 
processor_id_list),
+                              sizeof(*proc_id_list));
+  if (proc_id_list == NULL)
+    {
+      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM processor ID list out of 
bounds"));
+      return NULL;
+    }
+
+  /* Overflows were checked by fits_in_acm() */
+  id_entries_off = info_table->processor_id_list + sizeof(*proc_id_list);
+
+  if (n_fit_in_acm (hdr, id_entries_off, sizeof(*proc_id_list),
+                    proc_id_list->count) == NULL)
+    {
+      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM processor ID entries out of 
bounds"));
+      return NULL;
+    }
+
+  return proc_id_list;
+}
+
+static int
+is_acmod (const void *acmod_base, grub_uint32_t acmod_size,
+         grub_uint8_t *type_out)
+{
+  struct grub_txt_acm_header *acm_hdr = (struct grub_txt_acm_header 
*)acmod_base;
+  struct grub_txt_acm_info_table *info_table;
+  grub_uint32_t size_from_hdr;
+
+  /* First check size */
+  if (acmod_size < sizeof (*acm_hdr))
+    return 0;
+
+  /* Then check overflow */
+  if (grub_mul (acm_hdr->size, 4, &size_from_hdr))
+    return 0;
+
+  /* Then check size equivalency */
+  if (acmod_size != size_from_hdr)
+    return 0;
+
+  /* Then check type, sub-type and vendor */
+  if ((acm_hdr->module_type != GRUB_TXT_ACM_MODULE_TYPE) ||
+      (acm_hdr->module_sub_type != GRUB_TXT_ACM_MODULE_SUB_TYPE_TXT_ACM) ||
+      (acm_hdr->module_vendor != GRUB_TXT_ACM_MODULE_VENDOR_INTEL))
+    return 0;
+
+  info_table = get_acmod_info_table (acm_hdr);
+  if (info_table == NULL)
+    return 0;
+
+  /* Check if ACM UUID is present */
+  if (grub_memcmp (&(info_table->uuid), GRUB_TXT_ACM_UUID, 16))
+    return 0;
+
+  /*
+   * TXT specification doesn't give clear mapping of info table size to 
version,
+   * so just warn if the size is different than expected but try to use it
+   * anyway. info_table_get() macro does enough testing to not read outside
+   * of info table.
+   */
+  if (info_table->length < sizeof(*info_table))
+    grub_dprintf ("slaunch", "Info table size (%x) smaller than expected (%"
+                  PRIxGRUB_SIZE ")\n",
+                  info_table->length, sizeof(*info_table));
+
+  if (type_out)
+    *type_out = info_table_get (info_table, chipset_acm_type);
+
+  return 1;
+}
+
+static struct grub_txt_acm_header *
+get_bios_sinit (void *sinit_region_base)
+{
+  grub_uint8_t *txt_heap = grub_txt_get_heap ();
+  struct grub_txt_bios_data *bios_data = grub_txt_bios_data_start (txt_heap);
+  struct grub_txt_acm_header *bios_sinit;
+  grub_uint32_t tmp;
+
+  if (sinit_region_base == NULL)
+    return NULL;
+
+  if (bios_data->bios_sinit_size == 0)
+    return NULL;
+
+  /* Check if ACM crosses 4G */
+  if (grub_add ((unsigned long)sinit_region_base, bios_data->bios_sinit_size,
+                &tmp))
+    return NULL;
+
+  /* BIOS has loaded an SINIT module, so verify that it is valid */
+  grub_dprintf ("slaunch", "BIOS has already loaded an SINIT module\n");
+
+  bios_sinit = (struct grub_txt_acm_header *) sinit_region_base;
+
+  /* Is it a valid SINIT module? */
+  if (!grub_txt_is_sinit_acmod (sinit_region_base, bios_data->bios_sinit_size) 
||
+      !grub_txt_acmod_match_platform (bios_sinit))
+    {
+      grub_dprintf("slaunch", "BIOS SINIT module did not pass reasonableness 
checks");
+      return NULL;
+    }
+
+  return bios_sinit;
+}
+
+grub_uint32_t
+grub_txt_supported_os_sinit_data_ver (struct grub_txt_acm_header *hdr)
+{
+  static struct grub_txt_acm_info_table *info_table;
+
+  /* Assumes that it passed grub_txt_is_sinit_acmod() */
+  info_table = get_acmod_info_table (hdr);
+
+  if (info_table == NULL)
+    return 0;
+
+  return info_table_get (info_table, os_sinit_data_ver);
+}
+
+grub_uint32_t
+grub_txt_get_sinit_capabilities (struct grub_txt_acm_header *hdr)
+{
+  static struct grub_txt_acm_info_table *info_table;
+
+  /* Assumes that it passed grub_txt_is_sinit_acmod() */
+  info_table = get_acmod_info_table (hdr);
+
+  if (info_table == NULL || info_table->version < 3)
+    return 0;
+
+  return info_table_get (info_table, capabilities);
+}
+
+int
+grub_txt_is_sinit_acmod (const void *acmod_base, grub_uint32_t acmod_size)
+{
+  grub_uint8_t type;
+
+  if (!is_acmod (acmod_base, acmod_size, &type))
+    return 0;
+
+  if (type != GRUB_TXT_ACM_CHIPSET_TYPE_SINIT)
+    return 0;
+
+  return 1;
+}
+
+static int
+didvid_matches(union grub_txt_didvid didvid,
+               struct grub_txt_acm_chipset_id *chipset_id)
+{
+  if (didvid.vid != chipset_id->vendor_id)
+    return 0;
+
+  if (didvid.did != chipset_id->device_id)
+    return 0;
+
+  /*
+   * If RevisionIdMask is 0, the RevisionId field must exactly match the
+   * TXT.DIDVID.RID field.
+   */
+  if ((chipset_id->flags & GRUB_TXT_ACM_REVISION_ID_MASK) == 0 &&
+      (didvid.rid == chipset_id->revision_id))
+    return 1;
+
+  /*
+   * If RevisionIdMask is 1, the RevisionId field is a bitwise mask that can be
+   * used to test for any bits set in the TXT.DIDVID.RID field. If any bits are
+   * set, the RevisionId is a match.
+   */
+  if ((chipset_id->flags & GRUB_TXT_ACM_REVISION_ID_MASK) != 0 &&
+      (didvid.rid & chipset_id->revision_id) != 0)
+    return 1;
+
+  return 0;
+}
+
+int
+grub_txt_acmod_match_platform (struct grub_txt_acm_header *hdr)
+{
+  union grub_txt_didvid didvid;
+  grub_uint32_t fms, ign, i, ver;
+  grub_uint64_t platform_id;
+  struct grub_txt_acm_chipset_id_list *chipset_id_list;
+  struct grub_txt_acm_chipset_id *chipset_id;
+  struct grub_txt_acm_processor_id_list *proc_id_list;
+  struct grub_txt_acm_processor_id *proc_id;
+  struct grub_txt_acm_info_table *info_table;
+
+  /* This fn assumes that the ACM has already passed the is_acmod() checks */
+  info_table = get_acmod_info_table (hdr);
+  if (info_table == NULL)
+    return 0;
+
+  /* Get chipset fusing, device, and vendor id info */
+  didvid.value = grub_txt_reg_pub_read64 (GRUB_TXT_DIDVID);
+
+  ver = grub_txt_reg_pub_read32 (GRUB_TXT_VER_QPIIF);
+  if (ver == 0xffffffff || ver == 0x00) /* Old CPU, need to use VER.FSBIF */
+    ver = grub_txt_reg_pub_read32 (GRUB_TXT_VER_FSBIF);
+
+  grub_dprintf ("slaunch", "chipset production fused: %s, "
+                "chipset vendor: 0x%x, device: 0x%x, revision: 0x%x\n",
+                (ver & GRUB_TXT_VERSION_PROD_FUSED) ? "yes" : "no" , 
didvid.vid,
+                didvid.did, didvid.rid);
+
+  grub_cpuid (1, fms, ign, ign, ign);
+  platform_id = grub_rdmsr (GRUB_MSR_X86_PLATFORM_ID);
+
+  grub_dprintf ("slaunch", "processor family/model/stepping: 0x%x, "
+                "platform id: 0x%" PRIxGRUB_UINT64_T "\n", fms, platform_id);
+
+  /*
+   * Check if chipset fusing is same. Note the DEBUG.FUSE bit in the version
+   * is 0 when debug fused so the logic below checking a mismatch is valid.
+   */
+  if (!!(ver & GRUB_TXT_VERSION_PROD_FUSED) ==
+      !!(hdr->flags & GRUB_TXT_ACM_FLAG_DEBUG_SIGNED))
+    {
+      grub_error (GRUB_ERR_BAD_DEVICE, N_("production/debug mismatch between 
chipset and ACM"));
+      return 0;
+    }
+
+  /* Check if chipset vendor/device/revision IDs match */
+  chipset_id_list = get_acmod_chipset_list (hdr);
+  if (chipset_id_list == NULL)
+    return 0;
+
+  grub_dprintf ("slaunch", "%d SINIT ACM chipset id entries:\n", 
chipset_id_list->count);
+
+  chipset_id = (struct grub_txt_acm_chipset_id *) ((grub_addr_t) 
chipset_id_list + sizeof (chipset_id_list->count));
+  for (i = 0; i < chipset_id_list->count; i++, chipset_id++)
+    {
+      grub_dprintf ("slaunch", "  vendor: 0x%x, device: 0x%x, flags: 0x%x, "
+                    "revision: 0x%x, extended: 0x%x\n", chipset_id->vendor_id,
+                    chipset_id->device_id, chipset_id->flags,
+                    chipset_id->revision_id, chipset_id->extended_id);
+
+      if (didvid_matches (didvid, chipset_id))
+        break;
+    }
+
+  if (i >= chipset_id_list->count)
+    {
+      /*
+       * Version 9 introduces flexible ACM information table format, not yet
+       * supported by this code.
+       *
+       * TXT spec says that 9 will be the final version and further changes 
will
+       * be reflected elsewhere, but check for higher values too in case they
+       * change their mind.
+       */
+      if (info_table->version >= 9)
+        grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+                    N_("chipset id mismatch, flexible ACM info list may 
contain"
+                       " matching entry but it isn't yet supported by code"));
+      else
+        grub_error (GRUB_ERR_BAD_DEVICE, N_("chipset id mismatch"));
+
+      return 0;
+    }
+
+  /*
+   * Unfortunately the spec isn't too clear on what the changes to the info
+   * table were, across the different versions, but an old version of the 
entire
+   * spec document shows that the processor table field didn't exist when the
+   * latest version of the info table was 3.
+   */
+  if (info_table->version < 4)
+    return 1;
+
+  /* Check if processor family/model/stepping and platform IDs match */
+  proc_id_list = get_acmod_processor_list(hdr);
+  if (proc_id_list == NULL)
+    return 0;
+
+  grub_dprintf ("slaunch", "%d SINIT ACM processor id entries:\n", 
proc_id_list->count);
+
+  proc_id = (struct grub_txt_acm_processor_id *) ((grub_addr_t) proc_id_list + 
sizeof (proc_id_list->count));
+  for (i = 0; i < proc_id_list->count; i++, proc_id++)
+    {
+      grub_dprintf ("slaunch", "  fms: 0x%x, fms_mask: 0x%x, platform_id: 0x%" 
PRIxGRUB_UINT64_T
+                    ", platform_mask: 0x%" PRIxGRUB_UINT64_T "\n", 
proc_id->fms, proc_id->fms_mask,
+                    proc_id->platform_id, proc_id->platform_mask);
+
+      if ((proc_id->fms == (fms & proc_id->fms_mask)) &&
+          (proc_id->platform_id == (platform_id & proc_id->platform_mask)))
+        break;
+    }
+
+  if (i >= proc_id_list->count)
+    {
+      grub_error (GRUB_ERR_BAD_DEVICE, N_("processor id mismatch"));
+      return 0;
+    }
+
+  return 1;
+}
+
+/*
+ * Choose between the BIOS-provided and user-provided SINIT ACMs, and copy the
+ * chosen module to the SINIT memory.
+ */
+struct grub_txt_acm_header *
+grub_txt_sinit_select (struct grub_txt_acm_header *sinit)
+{
+  struct grub_txt_acm_header *bios_sinit;
+  void *sinit_region_base;
+  grub_uint32_t sinit_size, sinit_region_size;
+
+  sinit_region_base = (void *)(grub_addr_t) grub_txt_reg_pub_read32 
(GRUB_TXT_SINIT_BASE);
+  sinit_region_size = (grub_uint32_t) grub_txt_reg_pub_read32 
(GRUB_TXT_SINIT_SIZE);
+
+  grub_dprintf ("slaunch", "TXT.SINIT.BASE: %p\nTXT.SINIT.SIZE: 0x%"
+                PRIxGRUB_UINT32_T "\n", sinit_region_base, sinit_region_size);
+
+  if (sinit_region_base == NULL)
+    {
+      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("no SINIT ACM final resting 
place"));
+      return NULL;
+    }
+
+  if (((grub_addr_t) sinit_region_base & ((1 << GRUB_PAGE_SHIFT) - 1)) != 0)
+    {
+      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("SINIT ACM base not properly 
aligned"));
+      return NULL;
+    }
+
+  if (sinit != NULL)
+    grub_dprintf ("slaunch", "SINIT ACM date: %" PRIxGRUB_UINT32_T "\n", 
sinit->date);
+
+  bios_sinit = get_bios_sinit (sinit_region_base);
+
+  /* Does BIOS provide SINIT ACM? */
+  if (bios_sinit != NULL)
+    {
+      grub_dprintf ("slaunch", "BIOS SINIT ACM date: %" PRIxGRUB_UINT32_T "\n",
+                    bios_sinit->date);
+
+      if (sinit == NULL)
+        {
+          grub_dprintf ("slaunch", "no SINIT ACM provided. Using BIOS SINIT 
ACM\n");
+          return bios_sinit;
+        }
+
+      if (bios_sinit->date >= sinit->date)
+        {
+          grub_dprintf ("slaunch", "BIOS provides newer or same SINIT ACM, so, 
using BIOS one\n");
+          return bios_sinit;
+        }
+
+      grub_dprintf ("slaunch", "BIOS provides older SINIT ACM, so, ignoring 
BIOS one\n");
+    }
+
+  /* Fail if there is no SINIT ACM. */
+  if (sinit == NULL)
+    return NULL;
+
+  /* Our SINIT ACM is newer than BIOS one or BIOS does not have one. */
+
+  if (grub_mul (sinit->size, 4, &sinit_size))
+    {
+      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("SINIT ACM size in bytes 
overflows"));
+      return NULL;
+    }
+
+  if (sinit_size > sinit_region_size)
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                  N_("SINIT ACM does not fit into final resting place: 0x%"
+                  PRIxGRUB_UINT32_T "\n"), sinit_size);
+      return NULL;
+    }
+
+  grub_memcpy (sinit_region_base, sinit, sinit_size);
+
+  return sinit_region_base;
+}
-- 
2.46.0


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to