EFI updates for v6.19:

- Parse SMBIOS tables in memory directly on Macbooks that do not
   implement the EFI SMBIOS protocol
 
 - Obtain EDID information from the primary display while running in the
   EFI stub, and expose it via bootparams on x86 (generic method is in
   the works, and will likely land during the next cycle)
 
 - Bring CPER handling for ARM systems up to data with the latest EFI
   spec changes.
 
 - Various cosmetic changes.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQQQm/3uucuRGn1Dmh0wbglWLn0tXAUCaS6z+QAKCRAwbglWLn0t
 XCs8AQCL2Ebzq/FzMB0DEzcqwp9GV6upRReqBIrZcFQuZ+8IcQD/V+N4u3h1m1nJ
 ofl4KQckZTPPV+iwDDUb7scn5fwgpA4=
 =2tk+
 -----END PGP SIGNATURE-----

Merge tag 'efi-next-for-v6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi

Pull EFI updates from Ard Biesheuvel:
 "The usual trickle of EFI contributions:

   - Parse SMBIOS tables in memory directly on Macbooks that do not
     implement the EFI SMBIOS protocol

   - Obtain EDID information from the primary display while running in
     the EFI stub, and expose it via bootparams on x86 (generic method
     is in the works, and will likely land during the next cycle)

   - Bring CPER handling for ARM systems up to data with the latest EFI
     spec changes

   - Various cosmetic changes"

* tag 'efi-next-for-v6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi:
  docs: efi: add CPER functions to driver-api
  efi/cper: align ARM CPER type with UEFI 2.9A/2.10 specs
  efi/cper: Add a new helper function to print bitmasks
  efi/cper: Adjust infopfx size to accept an extra space
  RAS: Report all ARM processor CPER information to userspace
  efi/libstub: x86: Store EDID in boot_params
  efi/libstub: gop: Add support for reading EDID
  efi/libstub: gop: Initialize screen_info in helper function
  efi/libstub: gop: Find GOP handle instead of GOP data
  efi: Fix trailing whitespace in header file
  efi/memattr: Convert efi_memattr_init() return type to void
  efi: stmm: fix kernel-doc "bad line" warnings
  efi/riscv: Remove the useless failure return message print
  efistub/x86: Add fallback for SMBIOS record lookup
This commit is contained in:
Linus Torvalds 2025-12-04 17:10:08 -08:00
commit b1dd1e2f3e
16 changed files with 436 additions and 132 deletions

View File

@ -1,11 +1,16 @@
.. SPDX-License-Identifier: GPL-2.0
============
UEFI Support
============
====================================================
Unified Extensible Firmware Interface (UEFI) Support
====================================================
UEFI stub library functions
===========================
.. kernel-doc:: drivers/firmware/efi/libstub/mem.c
:internal:
UEFI Common Platform Error Record (CPER) functions
==================================================
.. kernel-doc:: drivers/firmware/efi/cper.c

View File

@ -22,6 +22,7 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/bitfield.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
@ -552,26 +553,25 @@ static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
}
static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata,
int sev, bool sync)
int sev, bool sync)
{
struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata);
int flags = sync ? MF_ACTION_REQUIRED : 0;
char error_type[120];
bool queued = false;
int sec_sev, i;
char *p;
log_arm_hw_error(err);
sec_sev = ghes_severity(gdata->error_severity);
log_arm_hw_error(err, sec_sev);
if (sev != GHES_SEV_RECOVERABLE || sec_sev != GHES_SEV_RECOVERABLE)
return false;
p = (char *)(err + 1);
for (i = 0; i < err->err_info_num; i++) {
struct cper_arm_err_info *err_info = (struct cper_arm_err_info *)p;
bool is_cache = (err_info->type == CPER_ARM_CACHE_ERROR);
bool is_cache = err_info->type & CPER_ARM_CACHE_ERROR;
bool has_pa = (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR);
const char *error_type = "unknown error";
/*
* The field (err_info->error_info & BIT(26)) is fixed to set to
@ -585,12 +585,15 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata,
continue;
}
if (err_info->type < ARRAY_SIZE(cper_proc_error_type_strs))
error_type = cper_proc_error_type_strs[err_info->type];
cper_bits_to_str(error_type, sizeof(error_type),
FIELD_GET(CPER_ARM_ERR_TYPE_MASK, err_info->type),
cper_proc_error_type_strs,
ARRAY_SIZE(cper_proc_error_type_strs));
pr_warn_ratelimited(FW_WARN GHES_PFX
"Unhandled processor error type: %s\n",
error_type);
"Unhandled processor error type 0x%02x: %s%s\n",
err_info->type, error_type,
(err_info->type & ~CPER_ARM_ERR_TYPE_MASK) ? " with reserved bit(s)" : "");
p += err_info->length;
}
@ -895,11 +898,9 @@ static void ghes_do_proc(struct ghes *ghes,
arch_apei_report_mem_error(sev, mem_err);
queued = ghes_handle_memory_failure(gdata, sev, sync);
}
else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
} else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
ghes_handle_aer(gdata);
}
else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
} else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
queued = ghes_handle_arm_hw_error(gdata, sev, sync);
} else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) {
struct cxl_cper_sec_prot_err *prot_err = acpi_hest_get_payload(gdata);

View File

@ -93,15 +93,11 @@ static void cper_print_arm_err_info(const char *pfx, u32 type,
bool proc_context_corrupt, corrected, precise_pc, restartable_pc;
bool time_out, access_mode;
/* If the type is unknown, bail. */
if (type > CPER_ARM_MAX_TYPE)
return;
/*
* Vendor type errors have error information values that are vendor
* specific.
*/
if (type == CPER_ARM_VENDOR_ERROR)
if (type & CPER_ARM_VENDOR_ERROR)
return;
if (error_info & CPER_ARM_ERR_VALID_TRANSACTION_TYPE) {
@ -116,43 +112,38 @@ static void cper_print_arm_err_info(const char *pfx, u32 type,
if (error_info & CPER_ARM_ERR_VALID_OPERATION_TYPE) {
op_type = ((error_info >> CPER_ARM_ERR_OPERATION_SHIFT)
& CPER_ARM_ERR_OPERATION_MASK);
switch (type) {
case CPER_ARM_CACHE_ERROR:
if (type & CPER_ARM_CACHE_ERROR) {
if (op_type < ARRAY_SIZE(arm_cache_err_op_strs)) {
printk("%soperation type: %s\n", pfx,
printk("%scache error, operation type: %s\n", pfx,
arm_cache_err_op_strs[op_type]);
}
break;
case CPER_ARM_TLB_ERROR:
}
if (type & CPER_ARM_TLB_ERROR) {
if (op_type < ARRAY_SIZE(arm_tlb_err_op_strs)) {
printk("%soperation type: %s\n", pfx,
printk("%sTLB error, operation type: %s\n", pfx,
arm_tlb_err_op_strs[op_type]);
}
break;
case CPER_ARM_BUS_ERROR:
}
if (type & CPER_ARM_BUS_ERROR) {
if (op_type < ARRAY_SIZE(arm_bus_err_op_strs)) {
printk("%soperation type: %s\n", pfx,
printk("%sbus error, operation type: %s\n", pfx,
arm_bus_err_op_strs[op_type]);
}
break;
}
}
if (error_info & CPER_ARM_ERR_VALID_LEVEL) {
level = ((error_info >> CPER_ARM_ERR_LEVEL_SHIFT)
& CPER_ARM_ERR_LEVEL_MASK);
switch (type) {
case CPER_ARM_CACHE_ERROR:
if (type & CPER_ARM_CACHE_ERROR)
printk("%scache level: %d\n", pfx, level);
break;
case CPER_ARM_TLB_ERROR:
if (type & CPER_ARM_TLB_ERROR)
printk("%sTLB level: %d\n", pfx, level);
break;
case CPER_ARM_BUS_ERROR:
if (type & CPER_ARM_BUS_ERROR)
printk("%saffinity level at which the bus error occurred: %d\n",
pfx, level);
break;
}
}
if (error_info & CPER_ARM_ERR_VALID_PROC_CONTEXT_CORRUPT) {
@ -240,7 +231,8 @@ void cper_print_proc_arm(const char *pfx,
int i, len, max_ctx_type;
struct cper_arm_err_info *err_info;
struct cper_arm_ctx_info *ctx_info;
char newpfx[64], infopfx[64];
char newpfx[64], infopfx[ARRAY_SIZE(newpfx) + 1];
char error_type[120];
printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
@ -289,9 +281,15 @@ void cper_print_proc_arm(const char *pfx,
newpfx);
}
printk("%serror_type: %d, %s\n", newpfx, err_info->type,
err_info->type < ARRAY_SIZE(cper_proc_error_type_strs) ?
cper_proc_error_type_strs[err_info->type] : "unknown");
cper_bits_to_str(error_type, sizeof(error_type),
FIELD_GET(CPER_ARM_ERR_TYPE_MASK, err_info->type),
cper_proc_error_type_strs,
ARRAY_SIZE(cper_proc_error_type_strs));
printk("%serror_type: 0x%02x: %s%s\n", newpfx, err_info->type,
error_type,
(err_info->type & ~CPER_ARM_ERR_TYPE_MASK) ? " with reserved bit(s)" : "");
if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) {
printk("%serror_info: 0x%016llx\n", newpfx,
err_info->error_info);

View File

@ -12,6 +12,7 @@
* Specification version 2.4.
*/
#include <linux/bitmap.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/time.h>
@ -69,7 +70,7 @@ const char *cper_severity_str(unsigned int severity)
}
EXPORT_SYMBOL_GPL(cper_severity_str);
/*
/**
* cper_print_bits - print strings for set bits
* @pfx: prefix for each line, including log level and prefix string
* @bits: bit mask
@ -106,6 +107,65 @@ void cper_print_bits(const char *pfx, unsigned int bits,
printk("%s\n", buf);
}
/**
* cper_bits_to_str - return a string for set bits
* @buf: buffer to store the output string
* @buf_size: size of the output string buffer
* @bits: bit mask
* @strs: string array, indexed by bit position
* @strs_size: size of the string array: @strs
*
* Add to @buf the bitmask in hexadecimal. Then, for each set bit in @bits,
* add the corresponding string describing the bit in @strs to @buf.
*
* A typical example is::
*
* const char * const bits[] = {
* "bit 3 name",
* "bit 4 name",
* "bit 5 name",
* };
* char str[120];
* unsigned int bitmask = BIT(3) | BIT(5);
* #define MASK GENMASK(5,3)
*
* cper_bits_to_str(str, sizeof(str), FIELD_GET(MASK, bitmask),
* bits, ARRAY_SIZE(bits));
*
* The above code fills the string ``str`` with ``bit 3 name|bit 5 name``.
*
* Return: number of bytes stored or an error code if lower than zero.
*/
int cper_bits_to_str(char *buf, int buf_size, unsigned long bits,
const char * const strs[], unsigned int strs_size)
{
int len = buf_size;
char *str = buf;
int i, size;
*buf = '\0';
for_each_set_bit(i, &bits, strs_size) {
if (!(bits & BIT_ULL(i)))
continue;
if (*buf && len > 0) {
*str = '|';
len--;
str++;
}
size = strscpy(str, strs[i], len);
if (size < 0)
return size;
len -= size;
str += size;
}
return len - buf_size;
}
EXPORT_SYMBOL_GPL(cper_bits_to_str);
static const char * const proc_type_strs[] = {
"IA32/X64",
"IA64",

View File

@ -56,7 +56,7 @@ static struct screen_info *setup_graphics(void)
{
struct screen_info *si, tmp = {};
if (efi_setup_gop(&tmp) != EFI_SUCCESS)
if (efi_setup_graphics(&tmp, NULL) != EFI_SUCCESS)
return NULL;
si = alloc_screen_info();

View File

@ -34,6 +34,9 @@
#define EFI_ALLOC_LIMIT ULONG_MAX
#endif
struct edid_info;
struct screen_info;
extern bool efi_no5lvl;
extern bool efi_nochunk;
extern bool efi_nokaslr;
@ -578,6 +581,32 @@ union efi_graphics_output_protocol {
} mixed_mode;
};
typedef union efi_edid_discovered_protocol efi_edid_discovered_protocol_t;
union efi_edid_discovered_protocol {
struct {
u32 size_of_edid;
u8 *edid;
};
struct {
u32 size_of_edid;
u32 edid;
} mixed_mode;
};
typedef union efi_edid_active_protocol efi_edid_active_protocol_t;
union efi_edid_active_protocol {
struct {
u32 size_of_edid;
u8 *edid;
};
struct {
u32 size_of_edid;
u32 edid;
} mixed_mode;
};
typedef union {
struct {
u32 revision;
@ -1085,7 +1114,7 @@ efi_status_t efi_parse_options(char const *cmdline);
void efi_parse_option_graphics(char *option);
efi_status_t efi_setup_gop(struct screen_info *si);
efi_status_t efi_setup_graphics(struct screen_info *si, struct edid_info *edid);
efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
const efi_char16_t *optstr,

View File

@ -12,6 +12,7 @@
#include <linux/string.h>
#include <asm/efi.h>
#include <asm/setup.h>
#include <video/edid.h>
#include "efistub.h"
@ -367,24 +368,31 @@ static void find_bits(u32 mask, u8 *pos, u8 *size)
*size = __fls(mask) - *pos + 1;
}
static void
setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,
efi_pixel_bitmask_t pixel_info, int pixel_format)
static void setup_screen_info(struct screen_info *si, const efi_graphics_output_protocol_t *gop)
{
if (pixel_format == PIXEL_BIT_MASK) {
find_bits(pixel_info.red_mask,
&si->red_pos, &si->red_size);
find_bits(pixel_info.green_mask,
&si->green_pos, &si->green_size);
find_bits(pixel_info.blue_mask,
&si->blue_pos, &si->blue_size);
find_bits(pixel_info.reserved_mask,
&si->rsvd_pos, &si->rsvd_size);
si->lfb_depth = si->red_size + si->green_size +
si->blue_size + si->rsvd_size;
si->lfb_linelength = (pixels_per_scan_line * si->lfb_depth) / 8;
const efi_graphics_output_protocol_mode_t *mode = efi_table_attr(gop, mode);
const efi_graphics_output_mode_info_t *info = efi_table_attr(mode, info);
si->orig_video_isVGA = VIDEO_TYPE_EFI;
si->lfb_width = info->horizontal_resolution;
si->lfb_height = info->vertical_resolution;
efi_set_u64_split(efi_table_attr(mode, frame_buffer_base),
&si->lfb_base, &si->ext_lfb_base);
if (si->ext_lfb_base)
si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
si->pages = 1;
if (info->pixel_format == PIXEL_BIT_MASK) {
find_bits(info->pixel_information.red_mask, &si->red_pos, &si->red_size);
find_bits(info->pixel_information.green_mask, &si->green_pos, &si->green_size);
find_bits(info->pixel_information.blue_mask, &si->blue_pos, &si->blue_size);
find_bits(info->pixel_information.reserved_mask, &si->rsvd_pos, &si->rsvd_size);
si->lfb_depth = si->red_size + si->green_size + si->blue_size + si->rsvd_size;
si->lfb_linelength = (info->pixels_per_scan_line * si->lfb_depth) / 8;
} else {
if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) {
if (info->pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) {
si->red_pos = 0;
si->blue_pos = 16;
} else /* PIXEL_BGR_RESERVED_8BIT_PER_COLOR */ {
@ -394,20 +402,33 @@ setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,
si->green_pos = 8;
si->rsvd_pos = 24;
si->red_size = si->green_size =
si->blue_size = si->rsvd_size = 8;
si->red_size = 8;
si->green_size = 8;
si->blue_size = 8;
si->rsvd_size = 8;
si->lfb_depth = 32;
si->lfb_linelength = pixels_per_scan_line * 4;
si->lfb_linelength = info->pixels_per_scan_line * 4;
}
si->lfb_size = si->lfb_linelength * si->lfb_height;
si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
}
static efi_graphics_output_protocol_t *find_gop(unsigned long num,
const efi_handle_t handles[])
static void setup_edid_info(struct edid_info *edid, u32 gop_size_of_edid, u8 *gop_edid)
{
if (!gop_edid || gop_size_of_edid < 128)
memset(edid->dummy, 0, sizeof(edid->dummy));
else
memcpy(edid->dummy, gop_edid, min(gop_size_of_edid, sizeof(edid->dummy)));
}
static efi_handle_t find_handle_with_primary_gop(unsigned long num, const efi_handle_t handles[],
efi_graphics_output_protocol_t **found_gop)
{
efi_graphics_output_protocol_t *first_gop;
efi_handle_t h;
efi_handle_t h, first_gop_handle;
first_gop_handle = NULL;
first_gop = NULL;
for_each_efi_handle(h, handles, num) {
@ -442,21 +463,25 @@ static efi_graphics_output_protocol_t *find_gop(unsigned long num,
*/
status = efi_bs_call(handle_protocol, h,
&EFI_CONSOLE_OUT_DEVICE_GUID, &dummy);
if (status == EFI_SUCCESS)
return gop;
if (!first_gop)
if (status == EFI_SUCCESS) {
if (found_gop)
*found_gop = gop;
return h;
} else if (!first_gop_handle) {
first_gop_handle = h;
first_gop = gop;
}
}
return first_gop;
if (found_gop)
*found_gop = first_gop;
return first_gop_handle;
}
efi_status_t efi_setup_gop(struct screen_info *si)
efi_status_t efi_setup_graphics(struct screen_info *si, struct edid_info *edid)
{
efi_handle_t *handles __free(efi_pool) = NULL;
efi_graphics_output_protocol_mode_t *mode;
efi_graphics_output_mode_info_t *info;
efi_handle_t handle;
efi_graphics_output_protocol_t *gop;
efi_status_t status;
unsigned long num;
@ -467,35 +492,41 @@ efi_status_t efi_setup_gop(struct screen_info *si)
if (status != EFI_SUCCESS)
return status;
gop = find_gop(num, handles);
if (!gop)
handle = find_handle_with_primary_gop(num, handles, &gop);
if (!handle)
return EFI_NOT_FOUND;
/* Change mode if requested */
set_mode(gop);
/* EFI framebuffer */
mode = efi_table_attr(gop, mode);
info = efi_table_attr(mode, info);
if (si)
setup_screen_info(si, gop);
si->orig_video_isVGA = VIDEO_TYPE_EFI;
/* Display EDID for primary GOP */
if (edid) {
efi_edid_discovered_protocol_t *discovered_edid;
efi_edid_active_protocol_t *active_edid;
u32 gop_size_of_edid = 0;
u8 *gop_edid = NULL;
si->lfb_width = info->horizontal_resolution;
si->lfb_height = info->vertical_resolution;
status = efi_bs_call(handle_protocol, handle, &EFI_EDID_ACTIVE_PROTOCOL_GUID,
(void **)&active_edid);
if (status == EFI_SUCCESS) {
gop_size_of_edid = active_edid->size_of_edid;
gop_edid = active_edid->edid;
} else {
status = efi_bs_call(handle_protocol, handle,
&EFI_EDID_DISCOVERED_PROTOCOL_GUID,
(void **)&discovered_edid);
if (status == EFI_SUCCESS) {
gop_size_of_edid = discovered_edid->size_of_edid;
gop_edid = discovered_edid->edid;
}
}
efi_set_u64_split(efi_table_attr(mode, frame_buffer_base),
&si->lfb_base, &si->ext_lfb_base);
if (si->ext_lfb_base)
si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
si->pages = 1;
setup_pixel_info(si, info->pixels_per_scan_line,
info->pixel_information, info->pixel_format);
si->lfb_size = si->lfb_linelength * si->lfb_height;
si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
setup_edid_info(edid, gop_size_of_edid, gop_edid);
}
return EFI_SUCCESS;
}

View File

@ -203,6 +203,104 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)
}
}
struct smbios_entry_point {
u8 anchor[4];
u8 ep_checksum;
u8 ep_length;
u8 major_version;
u8 minor_version;
u16 max_size_entry;
u8 ep_rev;
u8 reserved[5];
struct __packed {
u8 anchor[5];
u8 checksum;
u16 st_length;
u32 st_address;
u16 number_of_entries;
u8 bcd_rev;
} intm;
};
static bool verify_ep_checksum(const void *ptr, int length)
{
u8 sum = 0;
for (int i = 0; i < length; i++)
sum += ((u8 *)ptr)[i];
return sum == 0;
}
static bool verify_ep_integrity(const struct smbios_entry_point *ep)
{
if (memcmp(ep->anchor, "_SM_", sizeof(ep->anchor)) != 0)
return false;
if (memcmp(ep->intm.anchor, "_DMI_", sizeof(ep->intm.anchor)) != 0)
return false;
if (!verify_ep_checksum(ep, ep->ep_length) ||
!verify_ep_checksum(&ep->intm, sizeof(ep->intm)))
return false;
return true;
}
static const struct efi_smbios_record *search_record(void *table, u32 length,
u8 type)
{
const u8 *p, *end;
p = (u8 *)table;
end = p + length;
while (p + sizeof(struct efi_smbios_record) < end) {
const struct efi_smbios_record *hdr =
(struct efi_smbios_record *)p;
const u8 *next;
if (hdr->type == type)
return hdr;
/* Type 127 = End-of-Table */
if (hdr->type == 0x7F)
return NULL;
/* Jumping to the unformed section */
next = p + hdr->length;
/* Unformed section ends with 0000h */
while ((next[0] != 0 || next[1] != 0) && next + 1 < end)
next++;
next += 2;
p = next;
}
return NULL;
}
static const struct efi_smbios_record *get_table_record(u8 type)
{
const struct smbios_entry_point *ep;
/*
* Locate the legacy 32-bit SMBIOS entrypoint in memory, and parse it
* directly. Needed by some Macs that do not implement the EFI protocol.
*/
ep = get_efi_config_table(SMBIOS_TABLE_GUID);
if (!ep)
return NULL;
if (!verify_ep_integrity(ep))
return NULL;
return search_record((void *)(unsigned long)ep->intm.st_address,
ep->intm.st_length, type);
}
static bool apple_match_product_name(void)
{
static const char type1_product_matches[][15] = {
@ -218,7 +316,8 @@ static bool apple_match_product_name(void)
const struct efi_smbios_type1_record *record;
const u8 *product;
record = (struct efi_smbios_type1_record *)efi_get_smbios_record(1);
record = (struct efi_smbios_type1_record *)
(efi_get_smbios_record(1) ?: get_table_record(1));
if (!record)
return false;
@ -388,8 +487,9 @@ static void setup_quirks(struct boot_params *boot_params)
static void setup_graphics(struct boot_params *boot_params)
{
struct screen_info *si = memset(&boot_params->screen_info, 0, sizeof(*si));
struct edid_info *edid = memset(&boot_params->edid_info, 0, sizeof(*edid));
efi_setup_gop(si);
efi_setup_graphics(si, edid);
}
static void __noreturn efi_exit(efi_handle_t handle, efi_status_t status)

View File

@ -19,19 +19,19 @@ unsigned long __ro_after_init efi_mem_attr_table = EFI_INVALID_TABLE_ADDR;
* Reserve the memory associated with the Memory Attributes configuration
* table, if it exists.
*/
int __init efi_memattr_init(void)
void __init efi_memattr_init(void)
{
efi_memory_attributes_table_t *tbl;
unsigned long size;
if (efi_mem_attr_table == EFI_INVALID_TABLE_ADDR)
return 0;
return;
tbl = early_memremap(efi_mem_attr_table, sizeof(*tbl));
if (!tbl) {
pr_err("Failed to map EFI Memory Attributes table @ 0x%lx\n",
efi_mem_attr_table);
return -ENOMEM;
return;
}
if (tbl->version > 2) {
@ -61,7 +61,6 @@ int __init efi_memattr_init(void)
unmap:
early_memunmap(tbl, sizeof(*tbl));
return 0;
}
/*

View File

@ -36,20 +36,12 @@ static bool __init efi_virtmap_init(void)
init_new_context(NULL, &efi_mm);
for_each_efi_memory_desc(md) {
phys_addr_t phys = md->phys_addr;
int ret;
if (!(md->attribute & EFI_MEMORY_RUNTIME))
continue;
if (md->virt_addr == U64_MAX)
return false;
ret = efi_create_mapping(&efi_mm, md);
if (ret) {
pr_warn(" EFI remap %pa: failed to create mapping (%d)\n",
&phys, ret);
return false;
}
efi_create_mapping(&efi_mm, md);
}
if (efi_memattr_apply_permissions(&efi_mm, efi_set_mapping_permissions))

View File

@ -32,7 +32,7 @@
/**
* struct efi_mm_communicate_header - Header used for SMM variable communication
*
* @header_guid: header use for disambiguation of content
* @message_len: length of the message. Does not include the size of the
* header
@ -111,7 +111,7 @@ struct efi_mm_communicate_header {
/**
* struct smm_variable_communicate_header - Used for SMM variable communication
*
* @function: function to call in Smm.
* @ret_status: return status
* @data: payload
@ -128,7 +128,7 @@ struct smm_variable_communicate_header {
/**
* struct smm_variable_access - Used to communicate with StMM by
* SetVariable and GetVariable.
*
* @guid: vendor GUID
* @data_size: size of EFI variable data
* @name_size: size of EFI name

View File

@ -53,9 +53,45 @@ void log_non_standard_event(const guid_t *sec_type, const guid_t *fru_id,
}
EXPORT_SYMBOL_GPL(log_non_standard_event);
void log_arm_hw_error(struct cper_sec_proc_arm *err)
void log_arm_hw_error(struct cper_sec_proc_arm *err, const u8 sev)
{
trace_arm_event(err);
struct cper_arm_err_info *err_info;
struct cper_arm_ctx_info *ctx_info;
u8 *ven_err_data;
u32 ctx_len = 0;
int n, sz, cpu;
s32 vsei_len;
u32 pei_len;
u8 *pei_err, *ctx_err;
pei_len = sizeof(struct cper_arm_err_info) * err->err_info_num;
pei_err = (u8 *)(err + 1);
err_info = (struct cper_arm_err_info *)(err + 1);
ctx_info = (struct cper_arm_ctx_info *)(err_info + err->err_info_num);
ctx_err = (u8 *)ctx_info;
for (n = 0; n < err->context_info_num; n++) {
sz = sizeof(struct cper_arm_ctx_info) + ctx_info->size;
ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + sz);
ctx_len += sz;
}
vsei_len = err->section_length - (sizeof(struct cper_sec_proc_arm) + pei_len + ctx_len);
if (vsei_len < 0) {
pr_warn(FW_BUG "section length: %d\n", err->section_length);
pr_warn(FW_BUG "section length is too small\n");
pr_warn(FW_BUG "firmware-generated error record is incorrect\n");
vsei_len = 0;
}
ven_err_data = (u8 *)ctx_info;
cpu = GET_LOGICAL_INDEX(err->mpidr);
if (cpu < 0)
cpu = -1;
trace_arm_event(err, pei_err, pei_len, ctx_err, ctx_len,
ven_err_data, (u32)vsei_len, sev, cpu);
}
static int __init ras_init(void)

View File

@ -297,11 +297,11 @@ enum {
#define CPER_ARM_INFO_FLAGS_PROPAGATED BIT(2)
#define CPER_ARM_INFO_FLAGS_OVERFLOW BIT(3)
#define CPER_ARM_CACHE_ERROR 0
#define CPER_ARM_TLB_ERROR 1
#define CPER_ARM_BUS_ERROR 2
#define CPER_ARM_VENDOR_ERROR 3
#define CPER_ARM_MAX_TYPE CPER_ARM_VENDOR_ERROR
#define CPER_ARM_ERR_TYPE_MASK GENMASK(4,1)
#define CPER_ARM_CACHE_ERROR BIT(1)
#define CPER_ARM_TLB_ERROR BIT(2)
#define CPER_ARM_BUS_ERROR BIT(3)
#define CPER_ARM_VENDOR_ERROR BIT(4)
#define CPER_ARM_ERR_VALID_TRANSACTION_TYPE BIT(0)
#define CPER_ARM_ERR_VALID_OPERATION_TYPE BIT(1)
@ -588,6 +588,8 @@ const char *cper_mem_err_type_str(unsigned int);
const char *cper_mem_err_status_str(u64 status);
void cper_print_bits(const char *prefix, unsigned int bits,
const char * const strs[], unsigned int strs_size);
int cper_bits_to_str(char *buf, int buf_size, unsigned long bits,
const char * const strs[], unsigned int strs_size);
void cper_mem_err_pack(const struct cper_sec_mem_err *,
struct cper_mem_err_compact *);
const char *cper_mem_err_unpack(struct trace_seq *,

View File

@ -290,7 +290,7 @@ typedef efi_status_t efi_get_variable_t (efi_char16_t *name, efi_guid_t *vendor,
unsigned long *data_size, void *data);
typedef efi_status_t efi_get_next_variable_t (unsigned long *name_size, efi_char16_t *name,
efi_guid_t *vendor);
typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor,
typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor,
u32 attr, unsigned long data_size,
void *data);
typedef efi_status_t efi_get_next_high_mono_count_t (u32 *count);
@ -373,6 +373,8 @@ void efi_native_runtime_setup(void);
#define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID EFI_GUID(0x8b843e20, 0x8132, 0x4852, 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c)
#define EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL_GUID EFI_GUID(0x05c99a21, 0xc70f, 0x4ad2, 0x8a, 0x5f, 0x35, 0xdf, 0x33, 0x43, 0xf5, 0x1e)
#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
#define EFI_EDID_DISCOVERED_PROTOCOL_GUID EFI_GUID(0x1c0c34f6, 0xd380, 0x41fa, 0xa0, 0x49, 0x8a, 0xd0, 0x6c, 0x1a, 0x66, 0xaa)
#define EFI_EDID_ACTIVE_PROTOCOL_GUID EFI_GUID(0xbd8c1056, 0x9f36, 0x44ec, 0x92, 0xa8, 0xa6, 0x33, 0x7f, 0x81, 0x79, 0x86)
#define EFI_PCI_IO_PROTOCOL_GUID EFI_GUID(0x4cf5b200, 0x68b8, 0x4ca5, 0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x02, 0x9a)
#define EFI_FILE_INFO_ID EFI_GUID(0x09576e92, 0x6d3f, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
#define EFI_SYSTEM_RESOURCE_TABLE_GUID EFI_GUID(0xb122a263, 0x3661, 0x4f68, 0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80)
@ -772,7 +774,7 @@ extern unsigned long efi_mem_attr_table;
*/
typedef int (*efi_memattr_perm_setter)(struct mm_struct *, efi_memory_desc_t *, bool);
extern int efi_memattr_init(void);
extern void efi_memattr_init(void);
extern int efi_memattr_apply_permissions(struct mm_struct *mm,
efi_memattr_perm_setter fn);

View File

@ -24,8 +24,7 @@ int __init parse_cec_param(char *str);
void log_non_standard_event(const guid_t *sec_type,
const guid_t *fru_id, const char *fru_text,
const u8 sev, const u8 *err, const u32 len);
void log_arm_hw_error(struct cper_sec_proc_arm *err);
void log_arm_hw_error(struct cper_sec_proc_arm *err, const u8 sev);
#else
static inline void
log_non_standard_event(const guid_t *sec_type,
@ -33,7 +32,7 @@ log_non_standard_event(const guid_t *sec_type,
const u8 sev, const u8 *err, const u32 len)
{ return; }
static inline void
log_arm_hw_error(struct cper_sec_proc_arm *err) { return; }
log_arm_hw_error(struct cper_sec_proc_arm *err, const u8 sev) { return; }
#endif
struct atl_err {
@ -53,4 +52,15 @@ static inline unsigned long
amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err) { return -EINVAL; }
#endif /* CONFIG_AMD_ATL */
#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
#include <asm/smp_plat.h>
/*
* Include ARM-specific SMP header which provides a function mapping mpidr to
* CPU logical index.
*/
#define GET_LOGICAL_INDEX(mpidr) get_logical_index(mpidr & MPIDR_HWID_BITMASK)
#else
#define GET_LOGICAL_INDEX(mpidr) -EINVAL
#endif /* CONFIG_ARM || CONFIG_ARM64 */
#endif /* __RAS_H__ */

View File

@ -168,11 +168,25 @@ TRACE_EVENT(mc_event,
* This event is generated when hardware detects an ARM processor error
* has occurred. UEFI 2.6 spec section N.2.4.4.
*/
#define APEIL "ARM Processor Err Info data len"
#define APEID "ARM Processor Err Info raw data"
#define APECIL "ARM Processor Err Context Info data len"
#define APECID "ARM Processor Err Context Info raw data"
#define VSEIL "Vendor Specific Err Info data len"
#define VSEID "Vendor Specific Err Info raw data"
TRACE_EVENT(arm_event,
TP_PROTO(const struct cper_sec_proc_arm *proc),
TP_PROTO(const struct cper_sec_proc_arm *proc,
const u8 *pei_err,
const u32 pei_len,
const u8 *ctx_err,
const u32 ctx_len,
const u8 *oem,
const u32 oem_len,
u8 sev,
int cpu),
TP_ARGS(proc),
TP_ARGS(proc, pei_err, pei_len, ctx_err, ctx_len, oem, oem_len, sev, cpu),
TP_STRUCT__entry(
__field(u64, mpidr)
@ -180,6 +194,14 @@ TRACE_EVENT(arm_event,
__field(u32, running_state)
__field(u32, psci_state)
__field(u8, affinity)
__field(u32, pei_len)
__dynamic_array(u8, pei_buf, pei_len)
__field(u32, ctx_len)
__dynamic_array(u8, ctx_buf, ctx_len)
__field(u32, oem_len)
__dynamic_array(u8, oem_buf, oem_len)
__field(u8, sev)
__field(int, cpu)
),
TP_fast_assign(
@ -199,12 +221,29 @@ TRACE_EVENT(arm_event,
__entry->running_state = ~0;
__entry->psci_state = ~0;
}
__entry->pei_len = pei_len;
memcpy(__get_dynamic_array(pei_buf), pei_err, pei_len);
__entry->ctx_len = ctx_len;
memcpy(__get_dynamic_array(ctx_buf), ctx_err, ctx_len);
__entry->oem_len = oem_len;
memcpy(__get_dynamic_array(oem_buf), oem, oem_len);
__entry->sev = sev;
__entry->cpu = cpu;
),
TP_printk("affinity level: %d; MPIDR: %016llx; MIDR: %016llx; "
"running state: %d; PSCI state: %d",
TP_printk("cpu: %d; error: %d; affinity level: %d; MPIDR: %016llx; MIDR: %016llx; "
"running state: %d; PSCI state: %d; "
"%s: %d; %s: %s; %s: %d; %s: %s; %s: %d; %s: %s",
__entry->cpu,
__entry->sev,
__entry->affinity, __entry->mpidr, __entry->midr,
__entry->running_state, __entry->psci_state)
__entry->running_state, __entry->psci_state,
APEIL, __entry->pei_len, APEID,
__print_hex(__get_dynamic_array(pei_buf), __entry->pei_len),
APECIL, __entry->ctx_len, APECID,
__print_hex(__get_dynamic_array(ctx_buf), __entry->ctx_len),
VSEIL, __entry->oem_len, VSEID,
__print_hex(__get_dynamic_array(oem_buf), __entry->oem_len))
);
/*