mirror of https://github.com/torvalds/linux.git
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:
commit
b1dd1e2f3e
|
|
@ -1,11 +1,16 @@
|
||||||
.. SPDX-License-Identifier: GPL-2.0
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
============
|
====================================================
|
||||||
UEFI Support
|
Unified Extensible Firmware Interface (UEFI) Support
|
||||||
============
|
====================================================
|
||||||
|
|
||||||
UEFI stub library functions
|
UEFI stub library functions
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
.. kernel-doc:: drivers/firmware/efi/libstub/mem.c
|
.. kernel-doc:: drivers/firmware/efi/libstub/mem.c
|
||||||
:internal:
|
:internal:
|
||||||
|
|
||||||
|
UEFI Common Platform Error Record (CPER) functions
|
||||||
|
==================================================
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/firmware/efi/cper.c
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/bitfield.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/timer.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,
|
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);
|
struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata);
|
||||||
int flags = sync ? MF_ACTION_REQUIRED : 0;
|
int flags = sync ? MF_ACTION_REQUIRED : 0;
|
||||||
|
char error_type[120];
|
||||||
bool queued = false;
|
bool queued = false;
|
||||||
int sec_sev, i;
|
int sec_sev, i;
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
log_arm_hw_error(err);
|
|
||||||
|
|
||||||
sec_sev = ghes_severity(gdata->error_severity);
|
sec_sev = ghes_severity(gdata->error_severity);
|
||||||
|
log_arm_hw_error(err, sec_sev);
|
||||||
if (sev != GHES_SEV_RECOVERABLE || sec_sev != GHES_SEV_RECOVERABLE)
|
if (sev != GHES_SEV_RECOVERABLE || sec_sev != GHES_SEV_RECOVERABLE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
p = (char *)(err + 1);
|
p = (char *)(err + 1);
|
||||||
for (i = 0; i < err->err_info_num; i++) {
|
for (i = 0; i < err->err_info_num; i++) {
|
||||||
struct cper_arm_err_info *err_info = (struct cper_arm_err_info *)p;
|
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);
|
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
|
* 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err_info->type < ARRAY_SIZE(cper_proc_error_type_strs))
|
cper_bits_to_str(error_type, sizeof(error_type),
|
||||||
error_type = cper_proc_error_type_strs[err_info->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
|
pr_warn_ratelimited(FW_WARN GHES_PFX
|
||||||
"Unhandled processor error type: %s\n",
|
"Unhandled processor error type 0x%02x: %s%s\n",
|
||||||
error_type);
|
err_info->type, error_type,
|
||||||
|
(err_info->type & ~CPER_ARM_ERR_TYPE_MASK) ? " with reserved bit(s)" : "");
|
||||||
p += err_info->length;
|
p += err_info->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -895,11 +898,9 @@ static void ghes_do_proc(struct ghes *ghes,
|
||||||
|
|
||||||
arch_apei_report_mem_error(sev, mem_err);
|
arch_apei_report_mem_error(sev, mem_err);
|
||||||
queued = ghes_handle_memory_failure(gdata, sev, sync);
|
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);
|
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);
|
queued = ghes_handle_arm_hw_error(gdata, sev, sync);
|
||||||
} else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) {
|
} else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) {
|
||||||
struct cxl_cper_sec_prot_err *prot_err = acpi_hest_get_payload(gdata);
|
struct cxl_cper_sec_prot_err *prot_err = acpi_hest_get_payload(gdata);
|
||||||
|
|
|
||||||
|
|
@ -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 proc_context_corrupt, corrected, precise_pc, restartable_pc;
|
||||||
bool time_out, access_mode;
|
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
|
* Vendor type errors have error information values that are vendor
|
||||||
* specific.
|
* specific.
|
||||||
*/
|
*/
|
||||||
if (type == CPER_ARM_VENDOR_ERROR)
|
if (type & CPER_ARM_VENDOR_ERROR)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (error_info & CPER_ARM_ERR_VALID_TRANSACTION_TYPE) {
|
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) {
|
if (error_info & CPER_ARM_ERR_VALID_OPERATION_TYPE) {
|
||||||
op_type = ((error_info >> CPER_ARM_ERR_OPERATION_SHIFT)
|
op_type = ((error_info >> CPER_ARM_ERR_OPERATION_SHIFT)
|
||||||
& CPER_ARM_ERR_OPERATION_MASK);
|
& CPER_ARM_ERR_OPERATION_MASK);
|
||||||
switch (type) {
|
if (type & CPER_ARM_CACHE_ERROR) {
|
||||||
case CPER_ARM_CACHE_ERROR:
|
|
||||||
if (op_type < ARRAY_SIZE(arm_cache_err_op_strs)) {
|
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]);
|
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)) {
|
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]);
|
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)) {
|
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]);
|
arm_bus_err_op_strs[op_type]);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error_info & CPER_ARM_ERR_VALID_LEVEL) {
|
if (error_info & CPER_ARM_ERR_VALID_LEVEL) {
|
||||||
level = ((error_info >> CPER_ARM_ERR_LEVEL_SHIFT)
|
level = ((error_info >> CPER_ARM_ERR_LEVEL_SHIFT)
|
||||||
& CPER_ARM_ERR_LEVEL_MASK);
|
& CPER_ARM_ERR_LEVEL_MASK);
|
||||||
switch (type) {
|
if (type & CPER_ARM_CACHE_ERROR)
|
||||||
case CPER_ARM_CACHE_ERROR:
|
|
||||||
printk("%scache level: %d\n", pfx, level);
|
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);
|
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",
|
printk("%saffinity level at which the bus error occurred: %d\n",
|
||||||
pfx, level);
|
pfx, level);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error_info & CPER_ARM_ERR_VALID_PROC_CONTEXT_CORRUPT) {
|
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;
|
int i, len, max_ctx_type;
|
||||||
struct cper_arm_err_info *err_info;
|
struct cper_arm_err_info *err_info;
|
||||||
struct cper_arm_ctx_info *ctx_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);
|
printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
|
||||||
|
|
||||||
|
|
@ -289,9 +281,15 @@ void cper_print_proc_arm(const char *pfx,
|
||||||
newpfx);
|
newpfx);
|
||||||
}
|
}
|
||||||
|
|
||||||
printk("%serror_type: %d, %s\n", newpfx, err_info->type,
|
cper_bits_to_str(error_type, sizeof(error_type),
|
||||||
err_info->type < ARRAY_SIZE(cper_proc_error_type_strs) ?
|
FIELD_GET(CPER_ARM_ERR_TYPE_MASK, err_info->type),
|
||||||
cper_proc_error_type_strs[err_info->type] : "unknown");
|
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) {
|
if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) {
|
||||||
printk("%serror_info: 0x%016llx\n", newpfx,
|
printk("%serror_info: 0x%016llx\n", newpfx,
|
||||||
err_info->error_info);
|
err_info->error_info);
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
* Specification version 2.4.
|
* Specification version 2.4.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/bitmap.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/time.h>
|
#include <linux/time.h>
|
||||||
|
|
@ -69,7 +70,7 @@ const char *cper_severity_str(unsigned int severity)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(cper_severity_str);
|
EXPORT_SYMBOL_GPL(cper_severity_str);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* cper_print_bits - print strings for set bits
|
* cper_print_bits - print strings for set bits
|
||||||
* @pfx: prefix for each line, including log level and prefix string
|
* @pfx: prefix for each line, including log level and prefix string
|
||||||
* @bits: bit mask
|
* @bits: bit mask
|
||||||
|
|
@ -106,6 +107,65 @@ void cper_print_bits(const char *pfx, unsigned int bits,
|
||||||
printk("%s\n", buf);
|
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[] = {
|
static const char * const proc_type_strs[] = {
|
||||||
"IA32/X64",
|
"IA32/X64",
|
||||||
"IA64",
|
"IA64",
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ static struct screen_info *setup_graphics(void)
|
||||||
{
|
{
|
||||||
struct screen_info *si, tmp = {};
|
struct screen_info *si, tmp = {};
|
||||||
|
|
||||||
if (efi_setup_gop(&tmp) != EFI_SUCCESS)
|
if (efi_setup_graphics(&tmp, NULL) != EFI_SUCCESS)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
si = alloc_screen_info();
|
si = alloc_screen_info();
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,9 @@
|
||||||
#define EFI_ALLOC_LIMIT ULONG_MAX
|
#define EFI_ALLOC_LIMIT ULONG_MAX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct edid_info;
|
||||||
|
struct screen_info;
|
||||||
|
|
||||||
extern bool efi_no5lvl;
|
extern bool efi_no5lvl;
|
||||||
extern bool efi_nochunk;
|
extern bool efi_nochunk;
|
||||||
extern bool efi_nokaslr;
|
extern bool efi_nokaslr;
|
||||||
|
|
@ -578,6 +581,32 @@ union efi_graphics_output_protocol {
|
||||||
} mixed_mode;
|
} 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 {
|
typedef union {
|
||||||
struct {
|
struct {
|
||||||
u32 revision;
|
u32 revision;
|
||||||
|
|
@ -1085,7 +1114,7 @@ efi_status_t efi_parse_options(char const *cmdline);
|
||||||
|
|
||||||
void efi_parse_option_graphics(char *option);
|
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,
|
efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
|
||||||
const efi_char16_t *optstr,
|
const efi_char16_t *optstr,
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <asm/efi.h>
|
#include <asm/efi.h>
|
||||||
#include <asm/setup.h>
|
#include <asm/setup.h>
|
||||||
|
#include <video/edid.h>
|
||||||
|
|
||||||
#include "efistub.h"
|
#include "efistub.h"
|
||||||
|
|
||||||
|
|
@ -367,24 +368,31 @@ static void find_bits(u32 mask, u8 *pos, u8 *size)
|
||||||
*size = __fls(mask) - *pos + 1;
|
*size = __fls(mask) - *pos + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void setup_screen_info(struct screen_info *si, const efi_graphics_output_protocol_t *gop)
|
||||||
setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,
|
|
||||||
efi_pixel_bitmask_t pixel_info, int pixel_format)
|
|
||||||
{
|
{
|
||||||
if (pixel_format == PIXEL_BIT_MASK) {
|
const efi_graphics_output_protocol_mode_t *mode = efi_table_attr(gop, mode);
|
||||||
find_bits(pixel_info.red_mask,
|
const efi_graphics_output_mode_info_t *info = efi_table_attr(mode, info);
|
||||||
&si->red_pos, &si->red_size);
|
|
||||||
find_bits(pixel_info.green_mask,
|
si->orig_video_isVGA = VIDEO_TYPE_EFI;
|
||||||
&si->green_pos, &si->green_size);
|
|
||||||
find_bits(pixel_info.blue_mask,
|
si->lfb_width = info->horizontal_resolution;
|
||||||
&si->blue_pos, &si->blue_size);
|
si->lfb_height = info->vertical_resolution;
|
||||||
find_bits(pixel_info.reserved_mask,
|
|
||||||
&si->rsvd_pos, &si->rsvd_size);
|
efi_set_u64_split(efi_table_attr(mode, frame_buffer_base),
|
||||||
si->lfb_depth = si->red_size + si->green_size +
|
&si->lfb_base, &si->ext_lfb_base);
|
||||||
si->blue_size + si->rsvd_size;
|
if (si->ext_lfb_base)
|
||||||
si->lfb_linelength = (pixels_per_scan_line * si->lfb_depth) / 8;
|
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 {
|
} 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->red_pos = 0;
|
||||||
si->blue_pos = 16;
|
si->blue_pos = 16;
|
||||||
} else /* PIXEL_BGR_RESERVED_8BIT_PER_COLOR */ {
|
} 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->green_pos = 8;
|
||||||
si->rsvd_pos = 24;
|
si->rsvd_pos = 24;
|
||||||
si->red_size = si->green_size =
|
si->red_size = 8;
|
||||||
si->blue_size = si->rsvd_size = 8;
|
si->green_size = 8;
|
||||||
|
si->blue_size = 8;
|
||||||
|
si->rsvd_size = 8;
|
||||||
si->lfb_depth = 32;
|
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,
|
static void setup_edid_info(struct edid_info *edid, u32 gop_size_of_edid, u8 *gop_edid)
|
||||||
const efi_handle_t handles[])
|
{
|
||||||
|
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_graphics_output_protocol_t *first_gop;
|
||||||
efi_handle_t h;
|
efi_handle_t h, first_gop_handle;
|
||||||
|
|
||||||
|
first_gop_handle = NULL;
|
||||||
first_gop = NULL;
|
first_gop = NULL;
|
||||||
|
|
||||||
for_each_efi_handle(h, handles, num) {
|
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,
|
status = efi_bs_call(handle_protocol, h,
|
||||||
&EFI_CONSOLE_OUT_DEVICE_GUID, &dummy);
|
&EFI_CONSOLE_OUT_DEVICE_GUID, &dummy);
|
||||||
if (status == EFI_SUCCESS)
|
if (status == EFI_SUCCESS) {
|
||||||
return gop;
|
if (found_gop)
|
||||||
|
*found_gop = gop;
|
||||||
if (!first_gop)
|
return h;
|
||||||
|
} else if (!first_gop_handle) {
|
||||||
|
first_gop_handle = h;
|
||||||
first_gop = gop;
|
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_handle_t *handles __free(efi_pool) = NULL;
|
||||||
efi_graphics_output_protocol_mode_t *mode;
|
efi_handle_t handle;
|
||||||
efi_graphics_output_mode_info_t *info;
|
|
||||||
efi_graphics_output_protocol_t *gop;
|
efi_graphics_output_protocol_t *gop;
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
unsigned long num;
|
unsigned long num;
|
||||||
|
|
@ -467,35 +492,41 @@ efi_status_t efi_setup_gop(struct screen_info *si)
|
||||||
if (status != EFI_SUCCESS)
|
if (status != EFI_SUCCESS)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
gop = find_gop(num, handles);
|
handle = find_handle_with_primary_gop(num, handles, &gop);
|
||||||
if (!gop)
|
if (!handle)
|
||||||
return EFI_NOT_FOUND;
|
return EFI_NOT_FOUND;
|
||||||
|
|
||||||
/* Change mode if requested */
|
/* Change mode if requested */
|
||||||
set_mode(gop);
|
set_mode(gop);
|
||||||
|
|
||||||
/* EFI framebuffer */
|
/* EFI framebuffer */
|
||||||
mode = efi_table_attr(gop, mode);
|
if (si)
|
||||||
info = efi_table_attr(mode, info);
|
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;
|
status = efi_bs_call(handle_protocol, handle, &EFI_EDID_ACTIVE_PROTOCOL_GUID,
|
||||||
si->lfb_height = info->vertical_resolution;
|
(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),
|
setup_edid_info(edid, gop_size_of_edid, gop_edid);
|
||||||
&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;
|
|
||||||
|
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 bool apple_match_product_name(void)
|
||||||
{
|
{
|
||||||
static const char type1_product_matches[][15] = {
|
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 struct efi_smbios_type1_record *record;
|
||||||
const u8 *product;
|
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)
|
if (!record)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -388,8 +487,9 @@ static void setup_quirks(struct boot_params *boot_params)
|
||||||
static void setup_graphics(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 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)
|
static void __noreturn efi_exit(efi_handle_t handle, efi_status_t status)
|
||||||
|
|
|
||||||
|
|
@ -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
|
* Reserve the memory associated with the Memory Attributes configuration
|
||||||
* table, if it exists.
|
* table, if it exists.
|
||||||
*/
|
*/
|
||||||
int __init efi_memattr_init(void)
|
void __init efi_memattr_init(void)
|
||||||
{
|
{
|
||||||
efi_memory_attributes_table_t *tbl;
|
efi_memory_attributes_table_t *tbl;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
|
|
||||||
if (efi_mem_attr_table == EFI_INVALID_TABLE_ADDR)
|
if (efi_mem_attr_table == EFI_INVALID_TABLE_ADDR)
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
tbl = early_memremap(efi_mem_attr_table, sizeof(*tbl));
|
tbl = early_memremap(efi_mem_attr_table, sizeof(*tbl));
|
||||||
if (!tbl) {
|
if (!tbl) {
|
||||||
pr_err("Failed to map EFI Memory Attributes table @ 0x%lx\n",
|
pr_err("Failed to map EFI Memory Attributes table @ 0x%lx\n",
|
||||||
efi_mem_attr_table);
|
efi_mem_attr_table);
|
||||||
return -ENOMEM;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tbl->version > 2) {
|
if (tbl->version > 2) {
|
||||||
|
|
@ -61,7 +61,6 @@ int __init efi_memattr_init(void)
|
||||||
|
|
||||||
unmap:
|
unmap:
|
||||||
early_memunmap(tbl, sizeof(*tbl));
|
early_memunmap(tbl, sizeof(*tbl));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -36,20 +36,12 @@ static bool __init efi_virtmap_init(void)
|
||||||
init_new_context(NULL, &efi_mm);
|
init_new_context(NULL, &efi_mm);
|
||||||
|
|
||||||
for_each_efi_memory_desc(md) {
|
for_each_efi_memory_desc(md) {
|
||||||
phys_addr_t phys = md->phys_addr;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!(md->attribute & EFI_MEMORY_RUNTIME))
|
if (!(md->attribute & EFI_MEMORY_RUNTIME))
|
||||||
continue;
|
continue;
|
||||||
if (md->virt_addr == U64_MAX)
|
if (md->virt_addr == U64_MAX)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ret = efi_create_mapping(&efi_mm, md);
|
efi_create_mapping(&efi_mm, md);
|
||||||
if (ret) {
|
|
||||||
pr_warn(" EFI remap %pa: failed to create mapping (%d)\n",
|
|
||||||
&phys, ret);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (efi_memattr_apply_permissions(&efi_mm, efi_set_mapping_permissions))
|
if (efi_memattr_apply_permissions(&efi_mm, efi_set_mapping_permissions))
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct efi_mm_communicate_header - Header used for SMM variable communication
|
* struct efi_mm_communicate_header - Header used for SMM variable communication
|
||||||
|
*
|
||||||
* @header_guid: header use for disambiguation of content
|
* @header_guid: header use for disambiguation of content
|
||||||
* @message_len: length of the message. Does not include the size of the
|
* @message_len: length of the message. Does not include the size of the
|
||||||
* header
|
* header
|
||||||
|
|
@ -111,7 +111,7 @@ struct efi_mm_communicate_header {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct smm_variable_communicate_header - Used for SMM variable communication
|
* struct smm_variable_communicate_header - Used for SMM variable communication
|
||||||
|
*
|
||||||
* @function: function to call in Smm.
|
* @function: function to call in Smm.
|
||||||
* @ret_status: return status
|
* @ret_status: return status
|
||||||
* @data: payload
|
* @data: payload
|
||||||
|
|
@ -128,7 +128,7 @@ struct smm_variable_communicate_header {
|
||||||
/**
|
/**
|
||||||
* struct smm_variable_access - Used to communicate with StMM by
|
* struct smm_variable_access - Used to communicate with StMM by
|
||||||
* SetVariable and GetVariable.
|
* SetVariable and GetVariable.
|
||||||
|
*
|
||||||
* @guid: vendor GUID
|
* @guid: vendor GUID
|
||||||
* @data_size: size of EFI variable data
|
* @data_size: size of EFI variable data
|
||||||
* @name_size: size of EFI name
|
* @name_size: size of EFI name
|
||||||
|
|
|
||||||
|
|
@ -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);
|
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)
|
static int __init ras_init(void)
|
||||||
|
|
|
||||||
|
|
@ -297,11 +297,11 @@ enum {
|
||||||
#define CPER_ARM_INFO_FLAGS_PROPAGATED BIT(2)
|
#define CPER_ARM_INFO_FLAGS_PROPAGATED BIT(2)
|
||||||
#define CPER_ARM_INFO_FLAGS_OVERFLOW BIT(3)
|
#define CPER_ARM_INFO_FLAGS_OVERFLOW BIT(3)
|
||||||
|
|
||||||
#define CPER_ARM_CACHE_ERROR 0
|
#define CPER_ARM_ERR_TYPE_MASK GENMASK(4,1)
|
||||||
#define CPER_ARM_TLB_ERROR 1
|
#define CPER_ARM_CACHE_ERROR BIT(1)
|
||||||
#define CPER_ARM_BUS_ERROR 2
|
#define CPER_ARM_TLB_ERROR BIT(2)
|
||||||
#define CPER_ARM_VENDOR_ERROR 3
|
#define CPER_ARM_BUS_ERROR BIT(3)
|
||||||
#define CPER_ARM_MAX_TYPE CPER_ARM_VENDOR_ERROR
|
#define CPER_ARM_VENDOR_ERROR BIT(4)
|
||||||
|
|
||||||
#define CPER_ARM_ERR_VALID_TRANSACTION_TYPE BIT(0)
|
#define CPER_ARM_ERR_VALID_TRANSACTION_TYPE BIT(0)
|
||||||
#define CPER_ARM_ERR_VALID_OPERATION_TYPE BIT(1)
|
#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);
|
const char *cper_mem_err_status_str(u64 status);
|
||||||
void cper_print_bits(const char *prefix, unsigned int bits,
|
void cper_print_bits(const char *prefix, unsigned int bits,
|
||||||
const char * const strs[], unsigned int strs_size);
|
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 *,
|
void cper_mem_err_pack(const struct cper_sec_mem_err *,
|
||||||
struct cper_mem_err_compact *);
|
struct cper_mem_err_compact *);
|
||||||
const char *cper_mem_err_unpack(struct trace_seq *,
|
const char *cper_mem_err_unpack(struct trace_seq *,
|
||||||
|
|
|
||||||
|
|
@ -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);
|
unsigned long *data_size, void *data);
|
||||||
typedef efi_status_t efi_get_next_variable_t (unsigned long *name_size, efi_char16_t *name,
|
typedef efi_status_t efi_get_next_variable_t (unsigned long *name_size, efi_char16_t *name,
|
||||||
efi_guid_t *vendor);
|
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,
|
u32 attr, unsigned long data_size,
|
||||||
void *data);
|
void *data);
|
||||||
typedef efi_status_t efi_get_next_high_mono_count_t (u32 *count);
|
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_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_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_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_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_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)
|
#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);
|
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,
|
extern int efi_memattr_apply_permissions(struct mm_struct *mm,
|
||||||
efi_memattr_perm_setter fn);
|
efi_memattr_perm_setter fn);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,7 @@ int __init parse_cec_param(char *str);
|
||||||
void log_non_standard_event(const guid_t *sec_type,
|
void log_non_standard_event(const guid_t *sec_type,
|
||||||
const guid_t *fru_id, const char *fru_text,
|
const guid_t *fru_id, const char *fru_text,
|
||||||
const u8 sev, const u8 *err, const u32 len);
|
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
|
#else
|
||||||
static inline void
|
static inline void
|
||||||
log_non_standard_event(const guid_t *sec_type,
|
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)
|
const u8 sev, const u8 *err, const u32 len)
|
||||||
{ return; }
|
{ return; }
|
||||||
static inline void
|
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
|
#endif
|
||||||
|
|
||||||
struct atl_err {
|
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; }
|
amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err) { return -EINVAL; }
|
||||||
#endif /* CONFIG_AMD_ATL */
|
#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__ */
|
#endif /* __RAS_H__ */
|
||||||
|
|
|
||||||
|
|
@ -168,11 +168,25 @@ TRACE_EVENT(mc_event,
|
||||||
* This event is generated when hardware detects an ARM processor error
|
* This event is generated when hardware detects an ARM processor error
|
||||||
* has occurred. UEFI 2.6 spec section N.2.4.4.
|
* 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,
|
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(
|
TP_STRUCT__entry(
|
||||||
__field(u64, mpidr)
|
__field(u64, mpidr)
|
||||||
|
|
@ -180,6 +194,14 @@ TRACE_EVENT(arm_event,
|
||||||
__field(u32, running_state)
|
__field(u32, running_state)
|
||||||
__field(u32, psci_state)
|
__field(u32, psci_state)
|
||||||
__field(u8, affinity)
|
__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(
|
TP_fast_assign(
|
||||||
|
|
@ -199,12 +221,29 @@ TRACE_EVENT(arm_event,
|
||||||
__entry->running_state = ~0;
|
__entry->running_state = ~0;
|
||||||
__entry->psci_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; "
|
TP_printk("cpu: %d; error: %d; affinity level: %d; MPIDR: %016llx; MIDR: %016llx; "
|
||||||
"running state: %d; PSCI state: %d",
|
"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->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))
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue