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:
@@ -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)
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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");
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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" : "",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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)
|
||||
|
||||
#
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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: */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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) || \
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user