Commit b1dd1e2f authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents b0206c4e 7a2ff00c
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
.. 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
+14 −13
Original line number Diff line number Diff line
@@ -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>
@@ -556,22 +557,21 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata,
{
	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);
+25 −27
Original line number Diff line number Diff line
@@ -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);
+61 −1
Original line number Diff line number Diff line
@@ -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",
+1 −1
Original line number Diff line number Diff line
@@ -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();
Loading