Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/arch/x86/boot/compressed/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 6 kB image not shown  

Quelle  efi.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * Helpers for early access to EFI configuration table.
 *
 * Originally derived from arch/x86/boot/compressed/acpi.c
 */


#include "misc.h"

#include <asm/bootparam.h>

/**
 * efi_get_type - Given a pointer to boot_params, determine the type of EFI environment.
 *
 * @bp:         pointer to boot_params
 *
 * Return: EFI_TYPE_{32,64} for valid EFI environments, EFI_TYPE_NONE otherwise.
 */

enum efi_type efi_get_type(struct boot_params *bp)
{
 struct efi_info *ei;
 enum efi_type et;
 const char *sig;

 ei = &bp->efi_info;
 sig = (char *)&ei->efi_loader_signature;

 if (!strncmp(sig, EFI64_LOADER_SIGNATURE, 4)) {
  et = EFI_TYPE_64;
 } else if (!strncmp(sig, EFI32_LOADER_SIGNATURE, 4)) {
  et = EFI_TYPE_32;
 } else {
  debug_putstr("No EFI environment detected.\n");
  et = EFI_TYPE_NONE;
 }

#ifndef CONFIG_X86_64
 /*
 * Existing callers like acpi.c treat this case as an indicator to
 * fall-through to non-EFI, rather than an error, so maintain that
 * functionality here as well.
 */

 if (ei->efi_systab_hi || ei->efi_memmap_hi) {
  debug_putstr("EFI system table is located above 4GB and cannot be accessed.\n");
  et = EFI_TYPE_NONE;
 }
#endif

 return et;
}

/**
 * efi_get_system_table - Given a pointer to boot_params, retrieve the physical address
 *                        of the EFI system table.
 *
 * @bp:         pointer to boot_params
 *
 * Return: EFI system table address on success. On error, return 0.
 */

unsigned long efi_get_system_table(struct boot_params *bp)
{
 unsigned long sys_tbl_pa;
 struct efi_info *ei;
 enum efi_type et;

 /* Get systab from boot params. */
 ei = &bp->efi_info;
#ifdef CONFIG_X86_64
 sys_tbl_pa = ei->efi_systab | ((__u64)ei->efi_systab_hi << 32);
#else
 sys_tbl_pa = ei->efi_systab;
#endif
 if (!sys_tbl_pa) {
  debug_putstr("EFI system table not found.");
  return 0;
 }

 return sys_tbl_pa;
}

/*
 * EFI config table address changes to virtual address after boot, which may
 * not be accessible for the kexec'd kernel. To address this, kexec provides
 * the initial physical address via a struct setup_data entry, which is
 * checked for here, along with some sanity checks.
 */

static struct efi_setup_data *get_kexec_setup_data(struct boot_params *bp,
         enum efi_type et)
{
#ifdef CONFIG_X86_64
 struct efi_setup_data *esd = NULL;
 struct setup_data *data;
 u64 pa_data;

 pa_data = bp->hdr.setup_data;
 while (pa_data) {
  data = (struct setup_data *)pa_data;
  if (data->type == SETUP_EFI) {
   esd = (struct efi_setup_data *)(pa_data + sizeof(struct setup_data));
   break;
  }

  pa_data = data->next;
 }

 /*
 * Original ACPI code falls back to attempting normal EFI boot in these
 * cases, so maintain existing behavior by indicating non-kexec
 * environment to the caller, but print them for debugging.
 */

 if (esd && !esd->tables) {
  debug_putstr("kexec EFI environment missing valid configuration table.\n");
  return NULL;
 }

 return esd;
#endif
 return NULL;
}

/**
 * efi_get_conf_table - Given a pointer to boot_params, locate and return the physical
 *                      address of EFI configuration table.
 *
 * @bp:                 pointer to boot_params
 * @cfg_tbl_pa:         location to store physical address of config table
 * @cfg_tbl_len:        location to store number of config table entries
 *
 * Return: 0 on success. On error, return params are left unchanged.
 */

int efi_get_conf_table(struct boot_params *bp, unsigned long *cfg_tbl_pa,
         unsigned int *cfg_tbl_len)
{
 unsigned long sys_tbl_pa;
 enum efi_type et;
 int ret;

 if (!cfg_tbl_pa || !cfg_tbl_len)
  return -EINVAL;

 sys_tbl_pa = efi_get_system_table(bp);
 if (!sys_tbl_pa)
  return -EINVAL;

 /* Handle EFI bitness properly */
 et = efi_get_type(bp);
 if (et == EFI_TYPE_64) {
  efi_system_table_64_t *stbl = (efi_system_table_64_t *)sys_tbl_pa;
  struct efi_setup_data *esd;

  /* kexec provides an alternative EFI conf table, check for it. */
  esd = get_kexec_setup_data(bp, et);

  *cfg_tbl_pa = esd ? esd->tables : stbl->tables;
  *cfg_tbl_len = stbl->nr_tables;
 } else if (et == EFI_TYPE_32) {
  efi_system_table_32_t *stbl = (efi_system_table_32_t *)sys_tbl_pa;

  *cfg_tbl_pa = stbl->tables;
  *cfg_tbl_len = stbl->nr_tables;
 } else {
  return -EINVAL;
 }

 return 0;
}

/* Get vendor table address/guid from EFI config table at the given index */
static int get_vendor_table(void *cfg_tbl, unsigned int idx,
       unsigned long *vendor_tbl_pa,
       efi_guid_t *vendor_tbl_guid,
       enum efi_type et)
{
 if (et == EFI_TYPE_64) {
  efi_config_table_64_t *tbl_entry = (efi_config_table_64_t *)cfg_tbl + idx;

  if (!IS_ENABLED(CONFIG_X86_64) && tbl_entry->table >> 32) {
   debug_putstr("Error: EFI config table entry located above 4GB.\n");
   return -EINVAL;
  }

  *vendor_tbl_pa = tbl_entry->table;
  *vendor_tbl_guid = tbl_entry->guid;

 } else if (et == EFI_TYPE_32) {
  efi_config_table_32_t *tbl_entry = (efi_config_table_32_t *)cfg_tbl + idx;

  *vendor_tbl_pa = tbl_entry->table;
  *vendor_tbl_guid = tbl_entry->guid;
 } else {
  return -EINVAL;
 }

 return 0;
}

/**
 * efi_find_vendor_table - Given EFI config table, search it for the physical
 *                         address of the vendor table associated with GUID.
 *
 * @bp:                pointer to boot_params
 * @cfg_tbl_pa:        pointer to EFI configuration table
 * @cfg_tbl_len:       number of entries in EFI configuration table
 * @guid:              GUID of vendor table
 *
 * Return: vendor table address on success. On error, return 0.
 */

unsigned long efi_find_vendor_table(struct boot_params *bp,
        unsigned long cfg_tbl_pa,
        unsigned int cfg_tbl_len,
        efi_guid_t guid)
{
 enum efi_type et;
 unsigned int i;

 et = efi_get_type(bp);
 if (et == EFI_TYPE_NONE)
  return 0;

 for (i = 0; i < cfg_tbl_len; i++) {
  unsigned long vendor_tbl_pa;
  efi_guid_t vendor_tbl_guid;
  int ret;

  ret = get_vendor_table((void *)cfg_tbl_pa, i,
           &vendor_tbl_pa,
           &vendor_tbl_guid, et);
  if (ret)
   return 0;

  if (!efi_guidcmp(guid, vendor_tbl_guid))
   return vendor_tbl_pa;
 }

 return 0;
}

Messung V0.5
C=95 H=94 G=94

¤ Dauer der Verarbeitung: 0.22 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.