Merge mainline/master into arm/fixes

This brings in the mainline tree right after armsoc contents was merged
this release cycle, so that we can re-run savedefconfig, etc.

Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
Olof Johansson
2019-12-05 13:16:58 -08:00
11169 changed files with 562144 additions and 249456 deletions
+6 -6
View File
@@ -967,29 +967,29 @@ static int sdei_get_conduit(struct platform_device *pdev)
if (np) {
if (of_property_read_string(np, "method", &method)) {
pr_warn("missing \"method\" property\n");
return CONDUIT_INVALID;
return SMCCC_CONDUIT_NONE;
}
if (!strcmp("hvc", method)) {
sdei_firmware_call = &sdei_smccc_hvc;
return CONDUIT_HVC;
return SMCCC_CONDUIT_HVC;
} else if (!strcmp("smc", method)) {
sdei_firmware_call = &sdei_smccc_smc;
return CONDUIT_SMC;
return SMCCC_CONDUIT_SMC;
}
pr_warn("invalid \"method\" property: %s\n", method);
} else if (IS_ENABLED(CONFIG_ACPI) && !acpi_disabled) {
if (acpi_psci_use_hvc()) {
sdei_firmware_call = &sdei_smccc_hvc;
return CONDUIT_HVC;
return SMCCC_CONDUIT_HVC;
} else {
sdei_firmware_call = &sdei_smccc_smc;
return CONDUIT_SMC;
return SMCCC_CONDUIT_SMC;
}
}
return CONDUIT_INVALID;
return SMCCC_CONDUIT_NONE;
}
static int sdei_probe(struct platform_device *pdev)
+8
View File
@@ -22,3 +22,11 @@ config BCM47XX_SPROM
In case of SoC devices SPROM content is stored on a flash used by
bootloader firmware CFE. This driver provides method to ssb and bcma
drivers to read SPROM on SoC.
config TEE_BNXT_FW
tristate "Broadcom BNXT firmware manager"
depends on (ARCH_BCM_IPROC && OPTEE) || (COMPILE_TEST && TEE)
default ARCH_BCM_IPROC
help
This module help to manage firmware on Broadcom BNXT device. The module
registers on tee bus and invoke calls to manage firmware on BNXT device.
+1
View File
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_BCM47XX_NVRAM) += bcm47xx_nvram.o
obj-$(CONFIG_BCM47XX_SPROM) += bcm47xx_sprom.o
obj-$(CONFIG_TEE_BNXT_FW) += tee_bnxt_fw.o
+279
View File
@@ -0,0 +1,279 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2019 Broadcom.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/tee_drv.h>
#include <linux/uuid.h>
#include <linux/firmware/broadcom/tee_bnxt_fw.h>
#define MAX_SHM_MEM_SZ SZ_4M
#define MAX_TEE_PARAM_ARRY_MEMB 4
enum ta_cmd {
/*
* TA_CMD_BNXT_FASTBOOT - boot bnxt device by copying f/w into sram
*
* param[0] unused
* param[1] unused
* param[2] unused
* param[3] unused
*
* Result:
* TEE_SUCCESS - Invoke command success
* TEE_ERROR_ITEM_NOT_FOUND - Corrupt f/w image found on memory
*/
TA_CMD_BNXT_FASTBOOT = 0,
/*
* TA_CMD_BNXT_COPY_COREDUMP - copy the core dump into shm
*
* param[0] (inout memref) - Coredump buffer memory reference
* param[1] (in value) - value.a: offset, data to be copied from
* value.b: size of data to be copied
* param[2] unused
* param[3] unused
*
* Result:
* TEE_SUCCESS - Invoke command success
* TEE_ERROR_BAD_PARAMETERS - Incorrect input param
* TEE_ERROR_ITEM_NOT_FOUND - Corrupt core dump
*/
TA_CMD_BNXT_COPY_COREDUMP = 3,
};
/**
* struct tee_bnxt_fw_private - OP-TEE bnxt private data
* @dev: OP-TEE based bnxt device.
* @ctx: OP-TEE context handler.
* @session_id: TA session identifier.
*/
struct tee_bnxt_fw_private {
struct device *dev;
struct tee_context *ctx;
u32 session_id;
struct tee_shm *fw_shm_pool;
};
static struct tee_bnxt_fw_private pvt_data;
static void prepare_args(int cmd,
struct tee_ioctl_invoke_arg *arg,
struct tee_param *param)
{
memset(arg, 0, sizeof(*arg));
memset(param, 0, MAX_TEE_PARAM_ARRY_MEMB * sizeof(*param));
arg->func = cmd;
arg->session = pvt_data.session_id;
arg->num_params = MAX_TEE_PARAM_ARRY_MEMB;
/* Fill invoke cmd params */
switch (cmd) {
case TA_CMD_BNXT_COPY_COREDUMP:
param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT;
param[0].u.memref.shm = pvt_data.fw_shm_pool;
param[0].u.memref.size = MAX_SHM_MEM_SZ;
param[0].u.memref.shm_offs = 0;
param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
break;
case TA_CMD_BNXT_FASTBOOT:
default:
/* Nothing to do */
break;
}
}
/**
* tee_bnxt_fw_load() - Load the bnxt firmware
* Uses an OP-TEE call to start a secure
* boot process.
* Returns 0 on success, negative errno otherwise.
*/
int tee_bnxt_fw_load(void)
{
int ret = 0;
struct tee_ioctl_invoke_arg arg;
struct tee_param param[MAX_TEE_PARAM_ARRY_MEMB];
if (!pvt_data.ctx)
return -ENODEV;
prepare_args(TA_CMD_BNXT_FASTBOOT, &arg, param);
ret = tee_client_invoke_func(pvt_data.ctx, &arg, param);
if (ret < 0 || arg.ret != 0) {
dev_err(pvt_data.dev,
"TA_CMD_BNXT_FASTBOOT invoke failed TEE err: %x, ret:%x\n",
arg.ret, ret);
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL(tee_bnxt_fw_load);
/**
* tee_bnxt_copy_coredump() - Copy coredump from the allocated memory
* Uses an OP-TEE call to copy coredump
* @buf: destination buffer where core dump is copied into
* @offset: offset from the base address of core dump area
* @size: size of the dump
*
* Returns 0 on success, negative errno otherwise.
*/
int tee_bnxt_copy_coredump(void *buf, u32 offset, u32 size)
{
struct tee_ioctl_invoke_arg arg;
struct tee_param param[MAX_TEE_PARAM_ARRY_MEMB];
void *core_data;
u32 rbytes = size;
u32 nbytes = 0;
int ret = 0;
if (!pvt_data.ctx)
return -ENODEV;
prepare_args(TA_CMD_BNXT_COPY_COREDUMP, &arg, param);
while (rbytes) {
nbytes = rbytes;
nbytes = min_t(u32, rbytes, param[0].u.memref.size);
/* Fill additional invoke cmd params */
param[1].u.value.a = offset;
param[1].u.value.b = nbytes;
ret = tee_client_invoke_func(pvt_data.ctx, &arg, param);
if (ret < 0 || arg.ret != 0) {
dev_err(pvt_data.dev,
"TA_CMD_BNXT_COPY_COREDUMP invoke failed TEE err: %x, ret:%x\n",
arg.ret, ret);
return -EINVAL;
}
core_data = tee_shm_get_va(pvt_data.fw_shm_pool, 0);
if (IS_ERR(core_data)) {
dev_err(pvt_data.dev, "tee_shm_get_va failed\n");
return PTR_ERR(core_data);
}
memcpy(buf, core_data, nbytes);
rbytes -= nbytes;
buf += nbytes;
offset += nbytes;
}
return 0;
}
EXPORT_SYMBOL(tee_bnxt_copy_coredump);
static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
{
return (ver->impl_id == TEE_IMPL_ID_OPTEE);
}
static int tee_bnxt_fw_probe(struct device *dev)
{
struct tee_client_device *bnxt_device = to_tee_client_device(dev);
int ret, err = -ENODEV;
struct tee_ioctl_open_session_arg sess_arg;
struct tee_shm *fw_shm_pool;
memset(&sess_arg, 0, sizeof(sess_arg));
/* Open context with TEE driver */
pvt_data.ctx = tee_client_open_context(NULL, optee_ctx_match, NULL,
NULL);
if (IS_ERR(pvt_data.ctx))
return -ENODEV;
/* Open session with Bnxt load Trusted App */
memcpy(sess_arg.uuid, bnxt_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
sess_arg.num_params = 0;
ret = tee_client_open_session(pvt_data.ctx, &sess_arg, NULL);
if (ret < 0 || sess_arg.ret != 0) {
dev_err(dev, "tee_client_open_session failed, err: %x\n",
sess_arg.ret);
err = -EINVAL;
goto out_ctx;
}
pvt_data.session_id = sess_arg.session;
pvt_data.dev = dev;
fw_shm_pool = tee_shm_alloc(pvt_data.ctx, MAX_SHM_MEM_SZ,
TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
if (IS_ERR(fw_shm_pool)) {
tee_client_close_context(pvt_data.ctx);
dev_err(pvt_data.dev, "tee_shm_alloc failed\n");
err = PTR_ERR(fw_shm_pool);
goto out_sess;
}
pvt_data.fw_shm_pool = fw_shm_pool;
return 0;
out_sess:
tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
out_ctx:
tee_client_close_context(pvt_data.ctx);
return err;
}
static int tee_bnxt_fw_remove(struct device *dev)
{
tee_shm_free(pvt_data.fw_shm_pool);
tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
tee_client_close_context(pvt_data.ctx);
pvt_data.ctx = NULL;
return 0;
}
static const struct tee_client_device_id tee_bnxt_fw_id_table[] = {
{UUID_INIT(0x6272636D, 0x2019, 0x0716,
0x42, 0x43, 0x4D, 0x5F, 0x53, 0x43, 0x48, 0x49)},
{}
};
MODULE_DEVICE_TABLE(tee, tee_bnxt_fw_id_table);
static struct tee_client_driver tee_bnxt_fw_driver = {
.id_table = tee_bnxt_fw_id_table,
.driver = {
.name = KBUILD_MODNAME,
.bus = &tee_bus_type,
.probe = tee_bnxt_fw_probe,
.remove = tee_bnxt_fw_remove,
},
};
static int __init tee_bnxt_fw_mod_init(void)
{
return driver_register(&tee_bnxt_fw_driver.driver);
}
static void __exit tee_bnxt_fw_mod_exit(void)
{
driver_unregister(&tee_bnxt_fw_driver.driver);
}
module_init(tee_bnxt_fw_mod_init);
module_exit(tee_bnxt_fw_mod_exit);
MODULE_AUTHOR("Vikas Gupta <vikas.gupta@broadcom.com>");
MODULE_DESCRIPTION("Broadcom bnxt firmware manager");
MODULE_LICENSE("GPL v2");
+41 -2
View File
@@ -35,6 +35,7 @@ static struct dmi_memdev_info {
const char *bank;
u64 size; /* bytes */
u16 handle;
u8 type; /* DDR2, DDR3, DDR4 etc */
} *dmi_memdev;
static int dmi_memdev_nr;
@@ -391,7 +392,7 @@ static void __init save_mem_devices(const struct dmi_header *dm, void *v)
u64 bytes;
u16 size;
if (dm->type != DMI_ENTRY_MEM_DEVICE || dm->length < 0x12)
if (dm->type != DMI_ENTRY_MEM_DEVICE || dm->length < 0x13)
return;
if (nr >= dmi_memdev_nr) {
pr_warn(FW_BUG "Too many DIMM entries in SMBIOS table\n");
@@ -400,6 +401,7 @@ static void __init save_mem_devices(const struct dmi_header *dm, void *v)
dmi_memdev[nr].handle = get_unaligned(&dm->handle);
dmi_memdev[nr].device = dmi_string(dm, d[0x10]);
dmi_memdev[nr].bank = dmi_string(dm, d[0x11]);
dmi_memdev[nr].type = d[0x12];
size = get_unaligned((u16 *)&d[0xC]);
if (size == 0)
@@ -408,7 +410,7 @@ static void __init save_mem_devices(const struct dmi_header *dm, void *v)
bytes = ~0ull;
else if (size & 0x8000)
bytes = (u64)(size & 0x7fff) << 10;
else if (size != 0x7fff)
else if (size != 0x7fff || dm->length < 0x20)
bytes = (u64)size << 20;
else
bytes = (u64)get_unaligned((u32 *)&d[0x1C]) << 20;
@@ -1128,3 +1130,40 @@ u64 dmi_memdev_size(u16 handle)
return ~0ull;
}
EXPORT_SYMBOL_GPL(dmi_memdev_size);
/**
* dmi_memdev_type - get the memory type
* @handle: DMI structure handle
*
* Return the DMI memory type of the module in the slot associated with the
* given DMI handle, or 0x0 if no such DMI handle exists.
*/
u8 dmi_memdev_type(u16 handle)
{
int n;
if (dmi_memdev) {
for (n = 0; n < dmi_memdev_nr; n++) {
if (handle == dmi_memdev[n].handle)
return dmi_memdev[n].type;
}
}
return 0x0; /* Not a valid value */
}
EXPORT_SYMBOL_GPL(dmi_memdev_type);
/**
* dmi_memdev_handle - get the DMI handle of a memory slot
* @slot: slot number
*
* Return the DMI handle associated with a given memory slot, or %0xFFFF
* if there is no such slot.
*/
u16 dmi_memdev_handle(int slot)
{
if (dmi_memdev && slot >= 0 && slot < dmi_memdev_nr)
return dmi_memdev[slot].handle;
return 0xffff; /* Not a valid value */
}
EXPORT_SYMBOL_GPL(dmi_memdev_handle);
+22
View File
@@ -75,6 +75,27 @@ config EFI_MAX_FAKE_MEM
Ranges can be set up to this value using comma-separated list.
The default value is 8.
config EFI_SOFT_RESERVE
bool "Reserve EFI Specific Purpose Memory"
depends on EFI && EFI_STUB && ACPI_HMAT
default ACPI_HMAT
help
On systems that have mixed performance classes of memory EFI
may indicate specific purpose memory with an attribute (See
EFI_MEMORY_SP in UEFI 2.8). A memory range tagged with this
attribute may have unique performance characteristics compared
to the system's general purpose "System RAM" pool. On the
expectation that such memory has application specific usage,
and its base EFI memory type is "conventional" answer Y to
arrange for the kernel to reserve it as a "Soft Reserved"
resource, and set aside for direct-access (device-dax) by
default. The memory range can later be optionally assigned to
the page allocator by system administrator policy via the
device-dax kmem facility. Say N to have the kernel treat this
memory as "System RAM" by default.
If unsure, say Y.
config EFI_PARAMS_FROM_FDT
bool
help
@@ -182,6 +203,7 @@ config RESET_ATTACK_MITIGATION
config EFI_RCI2_TABLE
bool "EFI Runtime Configuration Interface Table Version 2 Support"
depends on X86 || COMPILE_TEST
help
Displays the content of the Runtime Configuration Interface
Table version 2 on Dell EMC PowerEdge systems as a binary
+4 -1
View File
@@ -20,13 +20,16 @@ obj-$(CONFIG_UEFI_CPER) += cper.o
obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o
obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o
obj-$(CONFIG_EFI_STUB) += libstub/
obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_mem.o
obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_map.o
obj-$(CONFIG_EFI_BOOTLOADER_CONTROL) += efibc.o
obj-$(CONFIG_EFI_TEST) += test/
obj-$(CONFIG_EFI_DEV_PATH_PARSER) += dev-path-parser.o
obj-$(CONFIG_APPLE_PROPERTIES) += apple-properties.o
obj-$(CONFIG_EFI_RCI2_TABLE) += rci2-table.o
fake_map-y += fake_mem.o
fake_map-$(CONFIG_X86) += x86_fake_mem.o
arm-obj-$(CONFIG_EFI) := arm-init.o arm-runtime.o
obj-$(CONFIG_ARM) += $(arm-obj-y)
obj-$(CONFIG_ARM64) += $(arm-obj-y)
+8 -10
View File
@@ -53,7 +53,8 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
for (i = 0; i < dev_header->prop_count; i++) {
int remaining = dev_header->len - (ptr - (void *)dev_header);
u32 key_len, val_len;
u32 key_len, val_len, entry_len;
const u8 *entry_data;
char *key;
if (sizeof(key_len) > remaining)
@@ -85,17 +86,14 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
ucs2_as_utf8(key, ptr + sizeof(key_len),
key_len - sizeof(key_len));
entry[i].name = key;
entry[i].length = val_len - sizeof(val_len);
entry[i].is_array = !!entry[i].length;
entry[i].type = DEV_PROP_U8;
entry[i].pointer.u8_data = ptr + key_len + sizeof(val_len);
entry_data = ptr + key_len + sizeof(val_len);
entry_len = val_len - sizeof(val_len);
entry[i] = PROPERTY_ENTRY_U8_ARRAY_LEN(key, entry_data,
entry_len);
if (dump_properties) {
dev_info(dev, "property: %s\n", entry[i].name);
dev_info(dev, "property: %s\n", key);
print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET,
16, 1, entry[i].pointer.u8_data,
entry[i].length, true);
16, 1, entry_data, entry_len, true);
}
ptr += key_len + val_len;
+9
View File
@@ -163,6 +163,15 @@ static __init int is_usable_memory(efi_memory_desc_t *md)
case EFI_BOOT_SERVICES_DATA:
case EFI_CONVENTIONAL_MEMORY:
case EFI_PERSISTENT_MEMORY:
/*
* Special purpose memory is 'soft reserved', which means it
* is set aside initially, but can be hotplugged back in or
* be assigned to the dax driver after boot.
*/
if (efi_soft_reserve_enabled() &&
(md->attribute & EFI_MEMORY_SP))
return false;
/*
* According to the spec, these regions are no longer reserved
* after calling ExitBootServices(). However, we can only use
+24
View File
@@ -121,6 +121,30 @@ static int __init arm_enable_runtime_services(void)
return 0;
}
if (efi_soft_reserve_enabled()) {
efi_memory_desc_t *md;
for_each_efi_memory_desc(md) {
int md_size = md->num_pages << EFI_PAGE_SHIFT;
struct resource *res;
if (!(md->attribute & EFI_MEMORY_SP))
continue;
res = kzalloc(sizeof(*res), GFP_KERNEL);
if (WARN_ON(!res))
break;
res->start = md->phys_addr;
res->end = md->phys_addr + md_size - 1;
res->name = "Soft Reserved";
res->flags = IORESOURCE_MEM;
res->desc = IORES_DESC_SOFT_RESERVED;
insert_resource(&iomem_resource, res);
}
}
if (efi_runtime_disabled()) {
pr_info("EFI runtime services will be disabled.\n");
return 0;
+13 -4
View File
@@ -81,6 +81,11 @@ bool efi_runtime_disabled(void)
return disable_runtime;
}
bool __pure __efi_soft_reserve_enabled(void)
{
return !efi_enabled(EFI_MEM_NO_SOFT_RESERVE);
}
static int __init parse_efi_cmdline(char *str)
{
if (!str) {
@@ -94,6 +99,9 @@ static int __init parse_efi_cmdline(char *str)
if (parse_option_str(str, "noruntime"))
disable_runtime = true;
if (parse_option_str(str, "nosoftreserve"))
set_bit(EFI_MEM_NO_SOFT_RESERVE, &efi.flags);
return 0;
}
early_param("efi", parse_efi_cmdline);
@@ -296,7 +304,7 @@ static __init int efivar_ssdt_load(void)
goto free_data;
}
ret = acpi_load_table(data);
ret = acpi_load_table(data, NULL);
if (ret) {
pr_err("failed to load table: %d\n", ret);
goto free_data;
@@ -554,7 +562,7 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
sizeof(*seed) + size);
if (seed != NULL) {
pr_notice("seeding entropy pool\n");
add_device_randomness(seed->bits, seed->size);
add_bootloader_randomness(seed->bits, seed->size);
early_memunmap(seed, sizeof(*seed) + size);
} else {
pr_err("Could not map UEFI random seed!\n");
@@ -842,15 +850,16 @@ char * __init efi_md_typeattr_format(char *buf, size_t size,
if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT |
EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_RO |
EFI_MEMORY_WP | EFI_MEMORY_RP | EFI_MEMORY_XP |
EFI_MEMORY_NV |
EFI_MEMORY_NV | EFI_MEMORY_SP |
EFI_MEMORY_RUNTIME | EFI_MEMORY_MORE_RELIABLE))
snprintf(pos, size, "|attr=0x%016llx]",
(unsigned long long)attr);
else
snprintf(pos, size,
"|%3s|%2s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
"|%3s|%2s|%2s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
attr & EFI_MEMORY_RUNTIME ? "RUN" : "",
attr & EFI_MEMORY_MORE_RELIABLE ? "MR" : "",
attr & EFI_MEMORY_SP ? "SP" : "",
attr & EFI_MEMORY_NV ? "NV" : "",
attr & EFI_MEMORY_XP ? "XP" : "",
attr & EFI_MEMORY_RP ? "RP" : "",
+3
View File
@@ -246,6 +246,9 @@ void __init efi_esrt_init(void)
int rc;
phys_addr_t end;
if (!efi_enabled(EFI_MEMMAP))
return;
pr_debug("esrt-init: loading.\n");
if (!esrt_table_exists())
return;
+12 -14
View File
@@ -17,12 +17,10 @@
#include <linux/memblock.h>
#include <linux/types.h>
#include <linux/sort.h>
#include <asm/efi.h>
#include "fake_mem.h"
#define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM
static struct efi_mem_range fake_mems[EFI_MAX_FAKEMEM];
static int nr_fake_mem;
struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM];
int nr_fake_mem;
static int __init cmp_fake_mem(const void *x1, const void *x2)
{
@@ -44,13 +42,13 @@ void __init efi_fake_memmap(void)
void *new_memmap;
int i;
if (!nr_fake_mem)
if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem)
return;
/* count up the number of EFI memory descriptor */
for (i = 0; i < nr_fake_mem; i++) {
for_each_efi_memory_desc(md) {
struct range *r = &fake_mems[i].range;
struct range *r = &efi_fake_mems[i].range;
new_nr_map += efi_memmap_split_count(md, r);
}
@@ -70,7 +68,7 @@ void __init efi_fake_memmap(void)
}
for (i = 0; i < nr_fake_mem; i++)
efi_memmap_insert(&efi.memmap, new_memmap, &fake_mems[i]);
efi_memmap_insert(&efi.memmap, new_memmap, &efi_fake_mems[i]);
/* swap into new EFI memmap */
early_memunmap(new_memmap, efi.memmap.desc_size * new_nr_map);
@@ -104,22 +102,22 @@ static int __init setup_fake_mem(char *p)
if (nr_fake_mem >= EFI_MAX_FAKEMEM)
break;
fake_mems[nr_fake_mem].range.start = start;
fake_mems[nr_fake_mem].range.end = start + mem_size - 1;
fake_mems[nr_fake_mem].attribute = attribute;
efi_fake_mems[nr_fake_mem].range.start = start;
efi_fake_mems[nr_fake_mem].range.end = start + mem_size - 1;
efi_fake_mems[nr_fake_mem].attribute = attribute;
nr_fake_mem++;
if (*p == ',')
p++;
}
sort(fake_mems, nr_fake_mem, sizeof(struct efi_mem_range),
sort(efi_fake_mems, nr_fake_mem, sizeof(struct efi_mem_range),
cmp_fake_mem, NULL);
for (i = 0; i < nr_fake_mem; i++)
pr_info("efi_fake_mem: add attr=0x%016llx to [mem 0x%016llx-0x%016llx]",
fake_mems[i].attribute, fake_mems[i].range.start,
fake_mems[i].range.end);
efi_fake_mems[i].attribute, efi_fake_mems[i].range.start,
efi_fake_mems[i].range.end);
return *p == '\0' ? 0 : -EINVAL;
}
+10
View File
@@ -0,0 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __EFI_FAKE_MEM_H__
#define __EFI_FAKE_MEM_H__
#include <asm/efi.h>
#define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM
extern struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM];
extern int nr_fake_mem;
#endif /* __EFI_FAKE_MEM_H__ */
+4 -2
View File
@@ -38,7 +38,8 @@ OBJECT_FILES_NON_STANDARD := y
# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
KCOV_INSTRUMENT := n
lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o
lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \
random.o
# include the stub's generic dependencies from lib/ when building for ARM/arm64
arm-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c
@@ -47,11 +48,12 @@ arm-deps-$(CONFIG_ARM64) += sort.c
$(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
$(call if_changed_rule,cc_o_c)
lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o random.o \
lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o \
$(patsubst %.c,lib-%.o,$(arm-deps-y))
lib-$(CONFIG_ARM) += arm32-stub.o
lib-$(CONFIG_ARM64) += arm64-stub.o
CFLAGS_arm32-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
#
+2
View File
@@ -189,6 +189,8 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
goto fail_free_cmdline;
}
efi_retrieve_tpm2_eventlog(sys_table);
/* Ask the firmware to clear memory on unclean shutdown */
efi_enable_reset_attack_mitigation(sys_table);
+18 -3
View File
@@ -146,6 +146,11 @@ static efi_status_t reserve_kernel_base(efi_system_table_t *sys_table_arg,
continue;
case EFI_CONVENTIONAL_MEMORY:
/* Skip soft reserved conventional memory */
if (efi_soft_reserve_enabled() &&
(desc->attribute & EFI_MEMORY_SP))
continue;
/*
* Reserve the intersection between this entry and the
* region.
@@ -195,6 +200,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
unsigned long dram_base,
efi_loaded_image_t *image)
{
unsigned long kernel_base;
efi_status_t status;
/*
@@ -204,9 +210,18 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
* loaded. These assumptions are made by the decompressor,
* before any memory map is available.
*/
dram_base = round_up(dram_base, SZ_128M);
kernel_base = round_up(dram_base, SZ_128M);
status = reserve_kernel_base(sys_table, dram_base, reserve_addr,
/*
* Note that some platforms (notably, the Raspberry Pi 2) put
* spin-tables and other pieces of firmware at the base of RAM,
* abusing the fact that the window of TEXT_OFFSET bytes at the
* base of the kernel image is only partially used at the moment.
* (Up to 5 pages are used for the swapper page tables)
*/
kernel_base += TEXT_OFFSET - 5 * PAGE_SIZE;
status = reserve_kernel_base(sys_table, kernel_base, reserve_addr,
reserve_size);
if (status != EFI_SUCCESS) {
pr_efi_err(sys_table, "Unable to allocate memory for uncompressed kernel.\n");
@@ -220,7 +235,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
*image_size = image->image_size;
status = efi_relocate_kernel(sys_table, image_addr, *image_size,
*image_size,
dram_base + MAX_UNCOMP_KERNEL_SIZE, 0);
kernel_base + MAX_UNCOMP_KERNEL_SIZE, 0, 0);
if (status != EFI_SUCCESS) {
pr_efi_err(sys_table, "Failed to relocate kernel.\n");
efi_free(sys_table, *reserve_size, *reserve_addr);
+29 -14
View File
@@ -32,6 +32,7 @@ static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE;
static int __section(.data) __nokaslr;
static int __section(.data) __quiet;
static int __section(.data) __novamap;
static bool __section(.data) efi_nosoftreserve;
int __pure nokaslr(void)
{
@@ -45,6 +46,10 @@ int __pure novamap(void)
{
return __novamap;
}
bool __pure __efi_soft_reserve_enabled(void)
{
return !efi_nosoftreserve;
}
#define EFI_MMAP_NR_SLACK_SLOTS 8
@@ -211,6 +216,10 @@ again:
if (desc->type != EFI_CONVENTIONAL_MEMORY)
continue;
if (efi_soft_reserve_enabled() &&
(desc->attribute & EFI_MEMORY_SP))
continue;
if (desc->num_pages < nr_pages)
continue;
@@ -260,11 +269,11 @@ fail:
}
/*
* Allocate at the lowest possible address.
* Allocate at the lowest possible address that is not below 'min'.
*/
efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
unsigned long size, unsigned long align,
unsigned long *addr)
efi_status_t efi_low_alloc_above(efi_system_table_t *sys_table_arg,
unsigned long size, unsigned long align,
unsigned long *addr, unsigned long min)
{
unsigned long map_size, desc_size, buff_size;
efi_memory_desc_t *map;
@@ -305,19 +314,18 @@ efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
if (desc->type != EFI_CONVENTIONAL_MEMORY)
continue;
if (efi_soft_reserve_enabled() &&
(desc->attribute & EFI_MEMORY_SP))
continue;
if (desc->num_pages < nr_pages)
continue;
start = desc->phys_addr;
end = start + desc->num_pages * EFI_PAGE_SIZE;
/*
* Don't allocate at 0x0. It will confuse code that
* checks pointers against NULL. Skip the first 8
* bytes so we start at a nice even number.
*/
if (start == 0x0)
start += 8;
if (start < min)
start = min;
start = round_up(start, align);
if ((start + size) > end)
@@ -489,6 +497,12 @@ efi_status_t efi_parse_options(char const *cmdline)
__novamap = 1;
}
if (IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) &&
!strncmp(str, "nosoftreserve", 7)) {
str += strlen("nosoftreserve");
efi_nosoftreserve = 1;
}
/* Group words together, delimited by "," */
while (*str && *str != ' ' && *str != ',')
str++;
@@ -698,7 +712,8 @@ efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
unsigned long image_size,
unsigned long alloc_size,
unsigned long preferred_addr,
unsigned long alignment)
unsigned long alignment,
unsigned long min_addr)
{
unsigned long cur_image_addr;
unsigned long new_addr = 0;
@@ -731,8 +746,8 @@ efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
* possible.
*/
if (status != EFI_SUCCESS) {
status = efi_low_alloc(sys_table_arg, alloc_size, alignment,
&new_addr);
status = efi_low_alloc_above(sys_table_arg, alloc_size,
alignment, &new_addr, min_addr);
}
if (status != EFI_SUCCESS) {
pr_efi_err(sys_table_arg, "Failed to allocate usable memory for kernel.\n");
-2
View File
@@ -63,8 +63,6 @@ efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg,
efi_status_t check_platform_features(efi_system_table_t *sys_table_arg);
efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg);
void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid);
/* Helper macros for the usual case of using simple C variables: */
+22 -5
View File
@@ -9,6 +9,18 @@
#include "efistub.h"
typedef struct efi_rng_protocol efi_rng_protocol_t;
typedef struct {
u32 get_info;
u32 get_rng;
} efi_rng_protocol_32_t;
typedef struct {
u64 get_info;
u64 get_rng;
} efi_rng_protocol_64_t;
struct efi_rng_protocol {
efi_status_t (*get_info)(struct efi_rng_protocol *,
unsigned long *, efi_guid_t *);
@@ -28,7 +40,7 @@ efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table_arg,
if (status != EFI_SUCCESS)
return status;
return rng->get_rng(rng, NULL, size, out);
return efi_call_proto(efi_rng_protocol, get_rng, rng, NULL, size, out);
}
/*
@@ -46,6 +58,10 @@ static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
if (md->type != EFI_CONVENTIONAL_MEMORY)
return 0;
if (efi_soft_reserve_enabled() &&
(md->attribute & EFI_MEMORY_SP))
return 0;
region_end = min((u64)ULONG_MAX, md->phys_addr + md->num_pages*EFI_PAGE_SIZE - 1);
first_slot = round_up(md->phys_addr, align);
@@ -161,15 +177,16 @@ efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg)
if (status != EFI_SUCCESS)
return status;
status = rng->get_rng(rng, &rng_algo_raw, EFI_RANDOM_SEED_SIZE,
seed->bits);
status = efi_call_proto(efi_rng_protocol, get_rng, rng, &rng_algo_raw,
EFI_RANDOM_SEED_SIZE, seed->bits);
if (status == EFI_UNSUPPORTED)
/*
* Use whatever algorithm we have available if the raw algorithm
* is not implemented.
*/
status = rng->get_rng(rng, NULL, EFI_RANDOM_SEED_SIZE,
seed->bits);
status = efi_call_proto(efi_rng_protocol, get_rng, rng, NULL,
EFI_RANDOM_SEED_SIZE, seed->bits);
if (status != EFI_SUCCESS)
goto err_freepool;
+8
View File
@@ -14,6 +14,7 @@
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/efi.h>
#include <linux/security.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
@@ -717,6 +718,13 @@ static long efi_test_ioctl(struct file *file, unsigned int cmd,
static int efi_test_open(struct inode *inode, struct file *file)
{
int ret = security_locked_down(LOCKDOWN_EFI_TEST);
if (ret)
return ret;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
/*
* nothing special to do here
* We do accept multiple open files at the same time as we
+1
View File
@@ -88,6 +88,7 @@ int __init efi_tpm_eventlog_init(void)
if (tbl_size < 0) {
pr_err(FW_BUG "Failed to parse event in TPM Final Events Log\n");
ret = -EINVAL;
goto out_calc;
}
+69
View File
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2019 Intel Corporation. All rights reserved. */
#include <linux/efi.h>
#include <asm/e820/api.h>
#include "fake_mem.h"
void __init efi_fake_memmap_early(void)
{
int i;
/*
* The late efi_fake_mem() call can handle all requests if
* EFI_MEMORY_SP support is disabled.
*/
if (!efi_soft_reserve_enabled())
return;
if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem)
return;
/*
* Given that efi_fake_memmap() needs to perform memblock
* allocations it needs to run after e820__memblock_setup().
* However, if efi_fake_mem specifies EFI_MEMORY_SP for a given
* address range that potentially needs to mark the memory as
* reserved prior to e820__memblock_setup(). Update e820
* directly if EFI_MEMORY_SP is specified for an
* EFI_CONVENTIONAL_MEMORY descriptor.
*/
for (i = 0; i < nr_fake_mem; i++) {
struct efi_mem_range *mem = &efi_fake_mems[i];
efi_memory_desc_t *md;
u64 m_start, m_end;
if ((mem->attribute & EFI_MEMORY_SP) == 0)
continue;
m_start = mem->range.start;
m_end = mem->range.end;
for_each_efi_memory_desc(md) {
u64 start, end;
if (md->type != EFI_CONVENTIONAL_MEMORY)
continue;
start = md->phys_addr;
end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1;
if (m_start <= end && m_end >= start)
/* fake range overlaps descriptor */;
else
continue;
/*
* Trim the boundary of the e820 update to the
* descriptor in case the fake range overlaps
* !EFI_CONVENTIONAL_MEMORY
*/
start = max(start, m_start);
end = min(end, m_end);
if (end <= start)
continue;
e820__range_update(start, end - start + 1, E820_TYPE_RAM,
E820_TYPE_SOFT_RESERVED);
e820__update_table(e820_table);
}
}
}
+1 -1
View File
@@ -114,7 +114,7 @@ static int imx_dsp_probe(struct platform_device *pdev)
dev_info(dev, "NXP i.MX DSP IPC initialized\n");
return devm_of_platform_populate(dev);
return 0;
out:
kfree(chan_name);
for (j = 0; j < i; j++) {
+1
View File
@@ -8,6 +8,7 @@
#include <dt-bindings/firmware/imx/rsrc.h>
#include <linux/firmware/imx/ipc.h>
#include <linux/firmware/imx/sci.h>
#include <linux/mailbox_client.h>
#define IMX_SC_IRQ_FUNC_ENABLE 1
+23 -1
View File
@@ -107,6 +107,12 @@ static void imx_scu_rx_callback(struct mbox_client *c, void *msg)
struct imx_sc_rpc_msg *hdr;
u32 *data = msg;
if (!sc_ipc->msg) {
dev_warn(sc_ipc->dev, "unexpected rx idx %d 0x%08x, ignore!\n",
sc_chan->idx, *data);
return;
}
if (sc_chan->idx == 0) {
hdr = msg;
sc_ipc->rx_size = hdr->size;
@@ -156,6 +162,7 @@ static int imx_scu_ipc_write(struct imx_sc_ipc *sc_ipc, void *msg)
*/
int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp)
{
uint8_t saved_svc, saved_func;
struct imx_sc_rpc_msg *hdr;
int ret;
@@ -165,7 +172,11 @@ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp)
mutex_lock(&sc_ipc->lock);
reinit_completion(&sc_ipc->done);
sc_ipc->msg = msg;
if (have_resp) {
sc_ipc->msg = msg;
saved_svc = ((struct imx_sc_rpc_msg *)msg)->svc;
saved_func = ((struct imx_sc_rpc_msg *)msg)->func;
}
sc_ipc->count = 0;
ret = imx_scu_ipc_write(sc_ipc, msg);
if (ret < 0) {
@@ -184,9 +195,20 @@ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp)
/* response status is stored in hdr->func field */
hdr = msg;
ret = hdr->func;
/*
* Some special SCU firmware APIs do NOT have return value
* in hdr->func, but they do have response data, those special
* APIs are defined as void function in SCU firmware, so they
* should be treated as return success always.
*/
if ((saved_svc == IMX_SC_RPC_SVC_MISC) &&
(saved_func == IMX_SC_MISC_FUNC_UNIQUE_ID ||
saved_func == IMX_SC_MISC_FUNC_GET_BUTTON_STATUS))
ret = 0;
}
out:
sc_ipc->msg = NULL;
mutex_unlock(&sc_ipc->lock);
dev_dbg(sc_ipc->dev, "RPC SVC done\n");
+66 -44
View File
@@ -35,7 +35,7 @@ struct meson_sm_chip {
struct meson_sm_cmd cmd[];
};
struct meson_sm_chip gxbb_chip = {
static const struct meson_sm_chip gxbb_chip = {
.shmem_size = SZ_4K,
.cmd_shmem_in_base = 0x82000020,
.cmd_shmem_out_base = 0x82000021,
@@ -54,8 +54,6 @@ struct meson_sm_firmware {
void __iomem *sm_shmem_out_base;
};
static struct meson_sm_firmware fw;
static u32 meson_sm_get_cmd(const struct meson_sm_chip *chip,
unsigned int cmd_index)
{
@@ -90,6 +88,7 @@ static void __iomem *meson_sm_map_shmem(u32 cmd_shmem, unsigned int size)
/**
* meson_sm_call - generic SMC32 call to the secure-monitor
*
* @fw: Pointer to secure-monitor firmware
* @cmd_index: Index of the SMC32 function ID
* @ret: Returned value
* @arg0: SMC32 Argument 0
@@ -100,15 +99,15 @@ static void __iomem *meson_sm_map_shmem(u32 cmd_shmem, unsigned int size)
*
* Return: 0 on success, a negative value on error
*/
int meson_sm_call(unsigned int cmd_index, u32 *ret, u32 arg0,
u32 arg1, u32 arg2, u32 arg3, u32 arg4)
int meson_sm_call(struct meson_sm_firmware *fw, unsigned int cmd_index,
u32 *ret, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
{
u32 cmd, lret;
if (!fw.chip)
if (!fw->chip)
return -ENOENT;
cmd = meson_sm_get_cmd(fw.chip, cmd_index);
cmd = meson_sm_get_cmd(fw->chip, cmd_index);
if (!cmd)
return -EINVAL;
@@ -124,6 +123,7 @@ EXPORT_SYMBOL(meson_sm_call);
/**
* meson_sm_call_read - retrieve data from secure-monitor
*
* @fw: Pointer to secure-monitor firmware
* @buffer: Buffer to store the retrieved data
* @bsize: Size of the buffer
* @cmd_index: Index of the SMC32 function ID
@@ -137,22 +137,23 @@ EXPORT_SYMBOL(meson_sm_call);
* When 0 is returned there is no guarantee about the amount of
* data read and bsize bytes are copied in buffer.
*/
int meson_sm_call_read(void *buffer, unsigned int bsize, unsigned int cmd_index,
u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
int meson_sm_call_read(struct meson_sm_firmware *fw, void *buffer,
unsigned int bsize, unsigned int cmd_index, u32 arg0,
u32 arg1, u32 arg2, u32 arg3, u32 arg4)
{
u32 size;
int ret;
if (!fw.chip)
if (!fw->chip)
return -ENOENT;
if (!fw.chip->cmd_shmem_out_base)
if (!fw->chip->cmd_shmem_out_base)
return -EINVAL;
if (bsize > fw.chip->shmem_size)
if (bsize > fw->chip->shmem_size)
return -EINVAL;
if (meson_sm_call(cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0)
if (meson_sm_call(fw, cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0)
return -EINVAL;
if (size > bsize)
@@ -164,7 +165,7 @@ int meson_sm_call_read(void *buffer, unsigned int bsize, unsigned int cmd_index,
size = bsize;
if (buffer)
memcpy(buffer, fw.sm_shmem_out_base, size);
memcpy(buffer, fw->sm_shmem_out_base, size);
return ret;
}
@@ -173,6 +174,7 @@ EXPORT_SYMBOL(meson_sm_call_read);
/**
* meson_sm_call_write - send data to secure-monitor
*
* @fw: Pointer to secure-monitor firmware
* @buffer: Buffer containing data to send
* @size: Size of the data to send
* @cmd_index: Index of the SMC32 function ID
@@ -184,23 +186,24 @@ EXPORT_SYMBOL(meson_sm_call_read);
*
* Return: size of sent data on success, a negative value on error
*/
int meson_sm_call_write(void *buffer, unsigned int size, unsigned int cmd_index,
u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
int meson_sm_call_write(struct meson_sm_firmware *fw, void *buffer,
unsigned int size, unsigned int cmd_index, u32 arg0,
u32 arg1, u32 arg2, u32 arg3, u32 arg4)
{
u32 written;
if (!fw.chip)
if (!fw->chip)
return -ENOENT;
if (size > fw.chip->shmem_size)
if (size > fw->chip->shmem_size)
return -EINVAL;
if (!fw.chip->cmd_shmem_in_base)
if (!fw->chip->cmd_shmem_in_base)
return -EINVAL;
memcpy(fw.sm_shmem_in_base, buffer, size);
memcpy(fw->sm_shmem_in_base, buffer, size);
if (meson_sm_call(cmd_index, &written, arg0, arg1, arg2, arg3, arg4) < 0)
if (meson_sm_call(fw, cmd_index, &written, arg0, arg1, arg2, arg3, arg4) < 0)
return -EINVAL;
if (!written)
@@ -210,6 +213,24 @@ int meson_sm_call_write(void *buffer, unsigned int size, unsigned int cmd_index,
}
EXPORT_SYMBOL(meson_sm_call_write);
/**
* meson_sm_get - get pointer to meson_sm_firmware structure.
*
* @sm_node: Pointer to the secure-monitor Device Tree node.
*
* Return: NULL is the secure-monitor device is not ready.
*/
struct meson_sm_firmware *meson_sm_get(struct device_node *sm_node)
{
struct platform_device *pdev = of_find_device_by_node(sm_node);
if (!pdev)
return NULL;
return platform_get_drvdata(pdev);
}
EXPORT_SYMBOL_GPL(meson_sm_get);
#define SM_CHIP_ID_LENGTH 119
#define SM_CHIP_ID_OFFSET 4
#define SM_CHIP_ID_SIZE 12
@@ -217,33 +238,25 @@ EXPORT_SYMBOL(meson_sm_call_write);
static ssize_t serial_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
struct meson_sm_firmware *fw;
uint8_t *id_buf;
int ret;
fw = platform_get_drvdata(pdev);
id_buf = kmalloc(SM_CHIP_ID_LENGTH, GFP_KERNEL);
if (!id_buf)
return -ENOMEM;
ret = meson_sm_call_read(id_buf, SM_CHIP_ID_LENGTH, SM_GET_CHIP_ID,
ret = meson_sm_call_read(fw, id_buf, SM_CHIP_ID_LENGTH, SM_GET_CHIP_ID,
0, 0, 0, 0, 0);
if (ret < 0) {
kfree(id_buf);
return ret;
}
ret = sprintf(buf, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
id_buf[SM_CHIP_ID_OFFSET + 0],
id_buf[SM_CHIP_ID_OFFSET + 1],
id_buf[SM_CHIP_ID_OFFSET + 2],
id_buf[SM_CHIP_ID_OFFSET + 3],
id_buf[SM_CHIP_ID_OFFSET + 4],
id_buf[SM_CHIP_ID_OFFSET + 5],
id_buf[SM_CHIP_ID_OFFSET + 6],
id_buf[SM_CHIP_ID_OFFSET + 7],
id_buf[SM_CHIP_ID_OFFSET + 8],
id_buf[SM_CHIP_ID_OFFSET + 9],
id_buf[SM_CHIP_ID_OFFSET + 10],
id_buf[SM_CHIP_ID_OFFSET + 11]);
ret = sprintf(buf, "%12phN\n", &id_buf[SM_CHIP_ID_OFFSET]);
kfree(id_buf);
@@ -268,25 +281,34 @@ static const struct of_device_id meson_sm_ids[] = {
static int __init meson_sm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct meson_sm_chip *chip;
struct meson_sm_firmware *fw;
chip = of_match_device(meson_sm_ids, &pdev->dev)->data;
fw = devm_kzalloc(dev, sizeof(*fw), GFP_KERNEL);
if (!fw)
return -ENOMEM;
chip = of_match_device(meson_sm_ids, dev)->data;
if (chip->cmd_shmem_in_base) {
fw.sm_shmem_in_base = meson_sm_map_shmem(chip->cmd_shmem_in_base,
chip->shmem_size);
if (WARN_ON(!fw.sm_shmem_in_base))
fw->sm_shmem_in_base = meson_sm_map_shmem(chip->cmd_shmem_in_base,
chip->shmem_size);
if (WARN_ON(!fw->sm_shmem_in_base))
goto out;
}
if (chip->cmd_shmem_out_base) {
fw.sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base,
chip->shmem_size);
if (WARN_ON(!fw.sm_shmem_out_base))
fw->sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base,
chip->shmem_size);
if (WARN_ON(!fw->sm_shmem_out_base))
goto out_in_base;
}
fw.chip = chip;
fw->chip = chip;
platform_set_drvdata(pdev, fw);
pr_info("secure-monitor enabled\n");
if (sysfs_create_group(&pdev->dev.kobj, &meson_sm_sysfs_attr_group))
@@ -295,7 +317,7 @@ static int __init meson_sm_probe(struct platform_device *pdev)
return 0;
out_in_base:
iounmap(fw.sm_shmem_in_base);
iounmap(fw->sm_shmem_in_base);
out:
return -EINVAL;
}
+16 -8
View File
@@ -53,10 +53,18 @@ bool psci_tos_resident_on(int cpu)
}
struct psci_operations psci_ops = {
.conduit = PSCI_CONDUIT_NONE,
.conduit = SMCCC_CONDUIT_NONE,
.smccc_version = SMCCC_VERSION_1_0,
};
enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void)
{
if (psci_ops.smccc_version < SMCCC_VERSION_1_1)
return SMCCC_CONDUIT_NONE;
return psci_ops.conduit;
}
typedef unsigned long (psci_fn)(unsigned long, unsigned long,
unsigned long, unsigned long);
static psci_fn *invoke_psci_fn;
@@ -212,13 +220,13 @@ static unsigned long psci_migrate_info_up_cpu(void)
0, 0, 0);
}
static void set_conduit(enum psci_conduit conduit)
static void set_conduit(enum arm_smccc_conduit conduit)
{
switch (conduit) {
case PSCI_CONDUIT_HVC:
case SMCCC_CONDUIT_HVC:
invoke_psci_fn = __invoke_psci_fn_hvc;
break;
case PSCI_CONDUIT_SMC:
case SMCCC_CONDUIT_SMC:
invoke_psci_fn = __invoke_psci_fn_smc;
break;
default:
@@ -240,9 +248,9 @@ static int get_set_conduit_method(struct device_node *np)
}
if (!strcmp("hvc", method)) {
set_conduit(PSCI_CONDUIT_HVC);
set_conduit(SMCCC_CONDUIT_HVC);
} else if (!strcmp("smc", method)) {
set_conduit(PSCI_CONDUIT_SMC);
set_conduit(SMCCC_CONDUIT_SMC);
} else {
pr_warn("invalid \"method\" property: %s\n", method);
return -EINVAL;
@@ -583,9 +591,9 @@ int __init psci_acpi_init(void)
pr_info("probing for conduit method from ACPI.\n");
if (acpi_psci_use_hvc())
set_conduit(PSCI_CONDUIT_HVC);
set_conduit(SMCCC_CONDUIT_HVC);
else
set_conduit(PSCI_CONDUIT_SMC);
set_conduit(SMCCC_CONDUIT_SMC);
return psci_probe();
}
+5
View File
@@ -614,3 +614,8 @@ int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
return qcom_scm_call_atomic2(QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
addr, val);
}
int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool enable)
{
return -ENODEV;
}
+108 -45
View File
@@ -62,32 +62,72 @@ static DEFINE_MUTEX(qcom_scm_lock);
#define FIRST_EXT_ARG_IDX 3
#define N_REGISTER_ARGS (MAX_QCOM_SCM_ARGS - N_EXT_QCOM_SCM_ARGS + 1)
/**
* qcom_scm_call() - Invoke a syscall in the secure world
* @dev: device
* @svc_id: service identifier
* @cmd_id: command identifier
* @desc: Descriptor structure containing arguments and return values
*
* Sends a command to the SCM and waits for the command to finish processing.
* This should *only* be called in pre-emptible context.
*/
static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
const struct qcom_scm_desc *desc,
struct arm_smccc_res *res)
static void __qcom_scm_call_do(const struct qcom_scm_desc *desc,
struct arm_smccc_res *res, u32 fn_id,
u64 x5, u32 type)
{
u64 cmd;
struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 };
cmd = ARM_SMCCC_CALL_VAL(type, qcom_smccc_convention,
ARM_SMCCC_OWNER_SIP, fn_id);
quirk.state.a6 = 0;
do {
arm_smccc_smc_quirk(cmd, desc->arginfo, desc->args[0],
desc->args[1], desc->args[2], x5,
quirk.state.a6, 0, res, &quirk);
if (res->a0 == QCOM_SCM_INTERRUPTED)
cmd = res->a0;
} while (res->a0 == QCOM_SCM_INTERRUPTED);
}
static void qcom_scm_call_do(const struct qcom_scm_desc *desc,
struct arm_smccc_res *res, u32 fn_id,
u64 x5, bool atomic)
{
int retry_count = 0;
if (atomic) {
__qcom_scm_call_do(desc, res, fn_id, x5, ARM_SMCCC_FAST_CALL);
return;
}
do {
mutex_lock(&qcom_scm_lock);
__qcom_scm_call_do(desc, res, fn_id, x5,
ARM_SMCCC_STD_CALL);
mutex_unlock(&qcom_scm_lock);
if (res->a0 == QCOM_SCM_V2_EBUSY) {
if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY)
break;
msleep(QCOM_SCM_EBUSY_WAIT_MS);
}
} while (res->a0 == QCOM_SCM_V2_EBUSY);
}
static int ___qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
const struct qcom_scm_desc *desc,
struct arm_smccc_res *res, bool atomic)
{
int arglen = desc->arginfo & 0xf;
int retry_count = 0, i;
int i;
u32 fn_id = QCOM_SCM_FNID(svc_id, cmd_id);
u64 cmd, x5 = desc->args[FIRST_EXT_ARG_IDX];
u64 x5 = desc->args[FIRST_EXT_ARG_IDX];
dma_addr_t args_phys = 0;
void *args_virt = NULL;
size_t alloc_len;
struct arm_smccc_quirk quirk = {.id = ARM_SMCCC_QUIRK_QCOM_A6};
gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
if (unlikely(arglen > N_REGISTER_ARGS)) {
alloc_len = N_EXT_QCOM_SCM_ARGS * sizeof(u64);
args_virt = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL);
args_virt = kzalloc(PAGE_ALIGN(alloc_len), flag);
if (!args_virt)
return -ENOMEM;
@@ -117,45 +157,55 @@ static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
x5 = args_phys;
}
do {
mutex_lock(&qcom_scm_lock);
cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL,
qcom_smccc_convention,
ARM_SMCCC_OWNER_SIP, fn_id);
quirk.state.a6 = 0;
do {
arm_smccc_smc_quirk(cmd, desc->arginfo, desc->args[0],
desc->args[1], desc->args[2], x5,
quirk.state.a6, 0, res, &quirk);
if (res->a0 == QCOM_SCM_INTERRUPTED)
cmd = res->a0;
} while (res->a0 == QCOM_SCM_INTERRUPTED);
mutex_unlock(&qcom_scm_lock);
if (res->a0 == QCOM_SCM_V2_EBUSY) {
if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY)
break;
msleep(QCOM_SCM_EBUSY_WAIT_MS);
}
} while (res->a0 == QCOM_SCM_V2_EBUSY);
qcom_scm_call_do(desc, res, fn_id, x5, atomic);
if (args_virt) {
dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
kfree(args_virt);
}
if (res->a0 < 0)
if ((long)res->a0 < 0)
return qcom_scm_remap_error(res->a0);
return 0;
}
/**
* qcom_scm_call() - Invoke a syscall in the secure world
* @dev: device
* @svc_id: service identifier
* @cmd_id: command identifier
* @desc: Descriptor structure containing arguments and return values
*
* Sends a command to the SCM and waits for the command to finish processing.
* This should *only* be called in pre-emptible context.
*/
static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
const struct qcom_scm_desc *desc,
struct arm_smccc_res *res)
{
might_sleep();
return ___qcom_scm_call(dev, svc_id, cmd_id, desc, res, false);
}
/**
* qcom_scm_call_atomic() - atomic variation of qcom_scm_call()
* @dev: device
* @svc_id: service identifier
* @cmd_id: command identifier
* @desc: Descriptor structure containing arguments and return values
* @res: Structure containing results from SMC/HVC call
*
* Sends a command to the SCM and waits for the command to finish processing.
* This can be called in atomic context.
*/
static int qcom_scm_call_atomic(struct device *dev, u32 svc_id, u32 cmd_id,
const struct qcom_scm_desc *desc,
struct arm_smccc_res *res)
{
return ___qcom_scm_call(dev, svc_id, cmd_id, desc, res, true);
}
/**
* qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
* @entry: Entry point function for the cpus
@@ -502,3 +552,16 @@ int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
return qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
&desc, &res);
}
int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
{
struct qcom_scm_desc desc = {0};
struct arm_smccc_res res;
desc.args[0] = QCOM_SCM_CONFIG_ERRATA1_CLIENT_ALL;
desc.args[1] = en;
desc.arginfo = QCOM_SCM_ARGS(2);
return qcom_scm_call_atomic(dev, QCOM_SCM_SVC_SMMU_PROGRAM,
QCOM_SCM_CONFIG_ERRATA1, &desc, &res);
}
+6
View File
@@ -345,6 +345,12 @@ int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
}
EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init);
int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
{
return __qcom_scm_qsmmu500_wait_safe_toggle(__scm->dev, en);
}
EXPORT_SYMBOL(qcom_scm_qsmmu500_wait_safe_toggle);
int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val)
{
return __qcom_scm_io_readl(__scm->dev, addr, val);
+5
View File
@@ -91,10 +91,15 @@ extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
u32 spare);
#define QCOM_SCM_IOMMU_SECURE_PTBL_SIZE 3
#define QCOM_SCM_IOMMU_SECURE_PTBL_INIT 4
#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15
#define QCOM_SCM_CONFIG_ERRATA1 0x3
#define QCOM_SCM_CONFIG_ERRATA1_CLIENT_ALL 0x2
extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
size_t *size);
extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr,
u32 size, u32 spare);
extern int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev,
bool enable);
#define QCOM_MEM_PROT_ASSIGN_ID 0x16
extern int __qcom_scm_assign_mem(struct device *dev,
phys_addr_t mem_region, size_t mem_sz,
+18 -24
View File
@@ -20,7 +20,6 @@
#define RSU_VERSION_MASK GENMASK_ULL(63, 32)
#define RSU_ERROR_LOCATION_MASK GENMASK_ULL(31, 0)
#define RSU_ERROR_DETAIL_MASK GENMASK_ULL(63, 32)
#define RSU_FW_VERSION_MASK GENMASK_ULL(15, 0)
#define RSU_TIMEOUT (msecs_to_jiffies(SVC_RSU_REQUEST_TIMEOUT_MS))
@@ -109,9 +108,12 @@ static void rsu_command_callback(struct stratix10_svc_client *client,
{
struct stratix10_rsu_priv *priv = client->priv;
if (data->status != BIT(SVC_STATUS_RSU_OK))
dev_err(client->dev, "RSU returned status is %i\n",
data->status);
if (data->status == BIT(SVC_STATUS_RSU_NO_SUPPORT))
dev_warn(client->dev, "Secure FW doesn't support notify\n");
else if (data->status == BIT(SVC_STATUS_RSU_ERROR))
dev_err(client->dev, "Failure, returned status is %lu\n",
BIT(data->status));
complete(&priv->completion);
}
@@ -133,9 +135,11 @@ static void rsu_retry_callback(struct stratix10_svc_client *client,
if (data->status == BIT(SVC_STATUS_RSU_OK))
priv->retry_counter = *counter;
else if (data->status == BIT(SVC_STATUS_RSU_NO_SUPPORT))
dev_warn(client->dev, "Secure FW doesn't support retry\n");
else
dev_err(client->dev, "Failed to get retry counter %i\n",
data->status);
dev_err(client->dev, "Failed to get retry counter %lu\n",
BIT(data->status));
complete(&priv->completion);
}
@@ -333,15 +337,10 @@ static ssize_t notify_store(struct device *dev,
return ret;
}
/* only 19.3 or late version FW supports retry counter feature */
if (FIELD_GET(RSU_FW_VERSION_MASK, priv->status.version)) {
ret = rsu_send_msg(priv, COMMAND_RSU_RETRY,
0, rsu_retry_callback);
if (ret) {
dev_err(dev,
"Error, getting RSU retry %i\n", ret);
return ret;
}
ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, rsu_retry_callback);
if (ret) {
dev_err(dev, "Error, getting RSU retry %i\n", ret);
return ret;
}
return count;
@@ -413,15 +412,10 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
stratix10_svc_free_channel(priv->chan);
}
/* only 19.3 or late version FW supports retry counter feature */
if (FIELD_GET(RSU_FW_VERSION_MASK, priv->status.version)) {
ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0,
rsu_retry_callback);
if (ret) {
dev_err(dev,
"Error, getting RSU retry %i\n", ret);
stratix10_svc_free_channel(priv->chan);
}
ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, rsu_retry_callback);
if (ret) {
dev_err(dev, "Error, getting RSU retry %i\n", ret);
stratix10_svc_free_channel(priv->chan);
}
return ret;
+17 -1
View File
@@ -493,8 +493,24 @@ static int svc_normal_to_secure_thread(void *data)
pdata->chan->scl->receive_cb(pdata->chan->scl, cbdata);
break;
default:
pr_warn("it shouldn't happen\n");
pr_warn("Secure firmware doesn't support...\n");
/*
* be compatible with older version firmware which
* doesn't support RSU notify or retry
*/
if ((pdata->command == COMMAND_RSU_RETRY) ||
(pdata->command == COMMAND_RSU_NOTIFY)) {
cbdata->status =
BIT(SVC_STATUS_RSU_NO_SUPPORT);
cbdata->kaddr1 = NULL;
cbdata->kaddr2 = NULL;
cbdata->kaddr3 = NULL;
pdata->chan->scl->receive_cb(
pdata->chan->scl, cbdata);
}
break;
}
};
+1 -1
View File
@@ -804,7 +804,7 @@ static int __maybe_unused tegra_bpmp_resume(struct device *dev)
}
static const struct dev_pm_ops tegra_bpmp_pm_ops = {
.resume_early = tegra_bpmp_resume,
.resume_noirq = tegra_bpmp_resume,
};
#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \
+6 -2
View File
@@ -711,8 +711,11 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
int ret;
np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp");
if (!np)
return 0;
if (!np) {
np = of_find_compatible_node(NULL, NULL, "xlnx,versal");
if (!np)
return 0;
}
of_node_put(np);
ret = get_set_conduit_method(dev->of_node);
@@ -770,6 +773,7 @@ static int zynqmp_firmware_remove(struct platform_device *pdev)
static const struct of_device_id zynqmp_firmware_of_match[] = {
{.compatible = "xlnx,zynqmp-firmware"},
{.compatible = "xlnx,versal-firmware"},
{},
};
MODULE_DEVICE_TABLE(of, zynqmp_firmware_of_match);