diff options
author | Tom Rini <trini@konsulko.com> | 2020-05-18 08:17:29 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2020-05-18 08:17:29 -0400 |
commit | ed9a3aa6452f57af65eb74f73bd2a54c3a2f4b03 (patch) | |
tree | 360fcb8e12955e02f8454e5f901d7891cf4168b6 | |
parent | 515f613253cf0a892c3a321770ab927fa3d925cf (diff) | |
parent | 7f44c7e281ef228d60625f5acdcbe68a847256bd (diff) | |
download | u-boot-WIP/18May2020.tar.gz |
Merge tag 'efi-2020-07-rc3' of https://gitlab.denx.de/u-boot/custodians/u-boot-efiWIP/18May2020
Pull request for UEFI sub-system for efi-2020-07-rc3
A series of patches introduces the possibility to manage UEFI variables
via an OP-TEE module. CONFIG_EFI_MM_COMM_TEE enables this. If this
option is not specified the U-Boot behavior remains unchanged. A defconfig
is provided for compile testing (lx2160ardb_tfa_stmm_defconfig).
An incorrect UEFI memory allocation for fsl-layerscape is fixed
-rw-r--r-- | MAINTAINERS | 6 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/cpu.c | 10 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/fdt.c | 5 | ||||
-rw-r--r-- | arch/arm/dts/fsl-lx2160a.dtsi | 6 | ||||
-rw-r--r-- | arch/arm/mach-meson/board-common.c | 7 | ||||
-rw-r--r-- | arch/x86/lib/e820.c | 6 | ||||
-rw-r--r-- | board/freescale/lx2160a/MAINTAINERS | 1 | ||||
-rw-r--r-- | board/raspberrypi/rpi/rpi.c | 4 | ||||
-rw-r--r-- | cmd/bootefi.c | 8 | ||||
-rw-r--r-- | cmd/efidebug.c | 58 | ||||
-rw-r--r-- | configs/lx2160ardb_tfa_stmm_defconfig | 85 | ||||
-rw-r--r-- | doc/uefi/uefi.rst | 17 | ||||
-rw-r--r-- | drivers/video/meson/meson_vpu.c | 4 | ||||
-rw-r--r-- | drivers/video/sunxi/sunxi_de2.c | 6 | ||||
-rw-r--r-- | drivers/video/sunxi/sunxi_display.c | 6 | ||||
-rw-r--r-- | include/efi_loader.h | 3 | ||||
-rw-r--r-- | include/mm_communication.h | 208 | ||||
-rw-r--r-- | lib/efi_loader/Kconfig | 9 | ||||
-rw-r--r-- | lib/efi_loader/Makefile | 4 | ||||
-rw-r--r-- | lib/efi_loader/efi_memory.c | 54 | ||||
-rw-r--r-- | lib/efi_loader/efi_runtime.c | 3 | ||||
-rw-r--r-- | lib/efi_loader/efi_variable_tee.c | 662 |
22 files changed, 1117 insertions, 55 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index d671124797..8add9d4c2a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -635,6 +635,12 @@ F: cmd/efidebug.c F: cmd/nvedit_efi.c F: tools/file2include.c +EFI VARIABLES VIA OP-TEE +M: Ilias Apalodimas <ilias.apalodimas@linaro.org> +S: Maintained +F: lib/efi_loader/efi_variable_tee.c +F: include/mm_communication.h + ENVIRONMENT M: Joe Hershberger <joe.hershberger@ni.com> R: Wolfgang Denk <wd@denx.de> diff --git a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c index b3f5c2f641..2cf3f4bb98 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c @@ -1529,9 +1529,8 @@ int dram_init_banksize(void) void efi_add_known_memory(void) { int i; - phys_addr_t ram_start, start; + phys_addr_t ram_start; phys_size_t ram_size; - u64 pages; /* Add RAM */ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { @@ -1549,11 +1548,8 @@ void efi_add_known_memory(void) gd->arch.resv_ram < ram_start + ram_size) ram_size = gd->arch.resv_ram - ram_start; #endif - start = (ram_start + EFI_PAGE_MASK) & ~EFI_PAGE_MASK; - pages = (ram_size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; - - efi_add_memory_map(start, pages, EFI_CONVENTIONAL_MEMORY, - false); + efi_add_memory_map(ram_start, ram_size, + EFI_CONVENTIONAL_MEMORY); } } #endif diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c index 3bbad827cb..0696ea6d35 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c @@ -146,9 +146,8 @@ remove_psci_node: fdt_add_mem_rsv(blob, (uintptr_t)&secondary_boot_code, *boot_code_size); #if CONFIG_IS_ENABLED(EFI_LOADER) - efi_add_memory_map((uintptr_t)&secondary_boot_code, - ALIGN(*boot_code_size, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT, - EFI_RESERVED_MEMORY_TYPE, false); + efi_add_memory_map((uintptr_t)&secondary_boot_code, *boot_code_size, + EFI_RESERVED_MEMORY_TYPE); #endif } #endif diff --git a/arch/arm/dts/fsl-lx2160a.dtsi b/arch/arm/dts/fsl-lx2160a.dtsi index 17ecdc569b..73d04db7e4 100644 --- a/arch/arm/dts/fsl-lx2160a.dtsi +++ b/arch/arm/dts/fsl-lx2160a.dtsi @@ -428,4 +428,10 @@ #size-cells = <0>; status = "disabled"; }; + firmware { + optee { + compatible = "linaro,optee-tz"; + method = "smc"; + }; + }; }; diff --git a/arch/arm/mach-meson/board-common.c b/arch/arm/mach-meson/board-common.c index bc4c92074c..747791b10e 100644 --- a/arch/arm/mach-meson/board-common.c +++ b/arch/arm/mach-meson/board-common.c @@ -69,11 +69,8 @@ void meson_board_add_reserved_memory(void *fdt, u64 start, u64 size) if (ret) printf("Could not reserve zone @ 0x%llx\n", start); - if (IS_ENABLED(CONFIG_EFI_LOADER)) { - efi_add_memory_map(start, - ALIGN(size, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT, - EFI_RESERVED_MEMORY_TYPE, false); - } + if (IS_ENABLED(CONFIG_EFI_LOADER)) + efi_add_memory_map(start, size, EFI_RESERVED_MEMORY_TYPE); } int meson_generate_serial_ethaddr(void) diff --git a/arch/x86/lib/e820.c b/arch/x86/lib/e820.c index 26da4d2f27..1f20c5c8c6 100644 --- a/arch/x86/lib/e820.c +++ b/arch/x86/lib/e820.c @@ -41,7 +41,7 @@ void efi_add_known_memory(void) { struct e820_entry e820[E820MAX]; unsigned int i, num; - u64 start, pages, ram_top; + u64 start, ram_top; int type; num = install_e820_map(ARRAY_SIZE(e820), e820); @@ -77,9 +77,7 @@ void efi_add_known_memory(void) start + e820[i].size, ram_top); } else { - pages = ALIGN(e820[i].size, EFI_PAGE_SIZE) - >> EFI_PAGE_SHIFT; - efi_add_memory_map(start, pages, type, false); + efi_add_memory_map(start, e820[i].size, type); } } } diff --git a/board/freescale/lx2160a/MAINTAINERS b/board/freescale/lx2160a/MAINTAINERS index 47ae04c91a..9fe79c0ef7 100644 --- a/board/freescale/lx2160a/MAINTAINERS +++ b/board/freescale/lx2160a/MAINTAINERS @@ -5,6 +5,7 @@ F: board/freescale/lx2160a/ F: include/configs/lx2160a_common.h F: include/configs/lx2160ardb.h F: configs/lx2160ardb_tfa_defconfig +F: configs/lx2160ardb_tfa_stmm_defconfig F: arch/arm/dts/fsl-lx2160a-rdb.dts LX2160ARDB_SECURE_BOOT BOARD diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c index 0206a093d4..45caa4d49e 100644 --- a/board/raspberrypi/rpi/rpi.c +++ b/board/raspberrypi/rpi/rpi.c @@ -489,8 +489,8 @@ int ft_board_setup(void *blob, bd_t *bd) #ifdef CONFIG_EFI_LOADER /* Reserve the spin table */ - efi_add_memory_map(0, CONFIG_RPI_EFI_NR_SPIN_PAGES, - EFI_RESERVED_MEMORY_TYPE, 0); + efi_add_memory_map(0, CONFIG_RPI_EFI_NR_SPIN_PAGES << EFI_PAGE_SHIFT, + EFI_RESERVED_MEMORY_TYPE); #endif return 0; diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 06573b14e9..9849eb4f99 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -151,14 +151,10 @@ done: static void efi_reserve_memory(u64 addr, u64 size) { - u64 pages; - /* Convert from sandbox address space. */ addr = (uintptr_t)map_sysmem(addr, 0); - pages = efi_size_in_pages(size + (addr & EFI_PAGE_MASK)); - addr &= ~EFI_PAGE_MASK; - if (efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE, - false) != EFI_SUCCESS) + if (efi_add_memory_map(addr, size, + EFI_RESERVED_MEMORY_TYPE) != EFI_SUCCESS) printf("Reserved memory mapping failed addr %llx size %llx\n", addr, size); } diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 5cc0a41af3..f020d95dbb 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -1165,6 +1165,58 @@ static int do_efi_test(cmd_tbl_t *cmdtp, int flag, return cp->cmd(cmdtp, flag, argc, argv); } +/** + * do_efi_query_info() - QueryVariableInfo EFI service + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, + * CMD_RET_USAGE or CMD_RET_FAILURE on failure + * + * Implement efidebug "test" sub-command. + */ + +static int do_efi_query_info(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + efi_status_t ret; + u32 attr = 0; + u64 max_variable_storage_size; + u64 remain_variable_storage_size; + u64 max_variable_size; + int i; + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-bs")) + attr |= EFI_VARIABLE_BOOTSERVICE_ACCESS; + else if (!strcmp(argv[i], "-rt")) + attr |= EFI_VARIABLE_RUNTIME_ACCESS; + else if (!strcmp(argv[i], "-nv")) + attr |= EFI_VARIABLE_NON_VOLATILE; + else if (!strcmp(argv[i], "-at")) + attr |= + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + } + + ret = EFI_CALL(efi_query_variable_info(attr, + &max_variable_storage_size, + &remain_variable_storage_size, + &max_variable_size)); + if (ret != EFI_SUCCESS) { + printf("Error: Cannot query UEFI variables, r = %lu\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + printf("Max storage size %llu\n", max_variable_storage_size); + printf("Remaining storage size %llu\n", remain_variable_storage_size); + printf("Max variable size %llu\n", max_variable_size); + + return CMD_RET_SUCCESS; +} + static cmd_tbl_t cmd_efidebug_sub[] = { U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""), U_BOOT_CMD_MKENT(devices, CONFIG_SYS_MAXARGS, 1, do_efi_show_devices, @@ -1181,6 +1233,8 @@ static cmd_tbl_t cmd_efidebug_sub[] = { "", ""), U_BOOT_CMD_MKENT(test, CONFIG_SYS_MAXARGS, 1, do_efi_test, "", ""), + U_BOOT_CMD_MKENT(query, CONFIG_SYS_MAXARGS, 1, do_efi_query_info, + "", ""), }; /** @@ -1252,7 +1306,9 @@ static char efidebug_help_text[] = "efidebug tables\n" " - show UEFI configuration tables\n" "efidebug test bootmgr\n" - " - run simple bootmgr for test\n"; + " - run simple bootmgr for test\n" + "efidebug query [-nv][-bs][-rt][-at]\n" + " - show size of UEFI variables store\n"; #endif U_BOOT_CMD( diff --git a/configs/lx2160ardb_tfa_stmm_defconfig b/configs/lx2160ardb_tfa_stmm_defconfig new file mode 100644 index 0000000000..5f181a3868 --- /dev/null +++ b/configs/lx2160ardb_tfa_stmm_defconfig @@ -0,0 +1,85 @@ +CONFIG_ARM=y +CONFIG_GIC_V3_ITS=y +CONFIG_TARGET_LX2160ARDB=y +CONFIG_TFABOOT=y +CONFIG_SYS_TEXT_BASE=0x82000000 +CONFIG_SYS_MALLOC_F_LEN=0x6000 +CONFIG_ENV_SIZE=0x2000 +CONFIG_ENV_OFFSET=0x500000 +CONFIG_ENV_SECT_SIZE=0x20000 +CONFIG_DM_GPIO=y +CONFIG_EMC2305=y +CONFIG_FSPI_AHB_EN_4BYTE=y +CONFIG_NR_DRAM_BANKS=3 +CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT=y +CONFIG_SEC_FIRMWARE_ARMV8_PSCI=y +CONFIG_AHCI=y +CONFIG_FIT_VERBOSE=y +CONFIG_OF_BOARD_SETUP=y +CONFIG_OF_STDOUT_VIA_ALIAS=y +CONFIG_BOOTDELAY=10 +CONFIG_USE_BOOTARGS=y +CONFIG_BOOTARGS="console=ttyAMA0,115200 root=/dev/ram0 earlycon=pl011,mmio32,0x21c0000 ramdisk_size=0x2000000 default_hugepagesz=1024m hugepagesz=1024m hugepages=2 pci=pcie_bus_perf" +# CONFIG_USE_BOOTCOMMAND is not set +CONFIG_MISC_INIT_R=y +CONFIG_CMD_GREPENV=y +CONFIG_CMD_NVEDIT_EFI=y +CONFIG_CMD_EEPROM=y +CONFIG_CMD_DM=y +CONFIG_CMD_GPT=y +CONFIG_CMD_I2C=y +CONFIG_CMD_MMC=y +CONFIG_CMD_PCI=y +CONFIG_CMD_USB=y +CONFIG_CMD_CACHE=y +CONFIG_CMD_EFIDEBUG=y +CONFIG_MP=y +CONFIG_OF_CONTROL=y +CONFIG_OF_BOARD_FIXUP=y +CONFIG_DEFAULT_DEVICE_TREE="fsl-lx2160a-rdb" +CONFIG_ENV_IS_IN_MMC=y +CONFIG_ENV_IS_IN_SPI_FLASH=y +CONFIG_ENV_ADDR=0x20500000 +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_DM=y +CONFIG_SATA_CEVA=y +CONFIG_FSL_CAAM=y +CONFIG_DM_I2C=y +CONFIG_I2C_SET_DEFAULT_BUS_NUM=y +CONFIG_I2C_DEFAULT_BUS_NUMBER=0 +CONFIG_DM_MMC=y +CONFIG_SUPPORT_EMMC_RPMB=y +CONFIG_FSL_ESDHC=y +CONFIG_MTD=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set +CONFIG_PHYLIB=y +CONFIG_PHY_AQUANTIA=y +CONFIG_PHY_ATHEROS=y +CONFIG_PHY_CORTINA=y +CONFIG_DM_ETH=y +CONFIG_DM_MDIO=y +CONFIG_E1000=y +CONFIG_FSL_LS_MDIO=y +CONFIG_PCI=y +CONFIG_DM_PCI=y +CONFIG_DM_PCI_COMPAT=y +CONFIG_PCIE_LAYERSCAPE=y +CONFIG_PCIE_LAYERSCAPE_GEN4=y +CONFIG_DM_RTC=y +CONFIG_RTC_PCF2127=y +CONFIG_DM_SCSI=y +CONFIG_DM_SERIAL=y +CONFIG_SPI=y +CONFIG_DM_SPI=y +CONFIG_NXP_FSPI=y +CONFIG_TEE=y +CONFIG_OPTEE=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_DWC3=y +CONFIG_EFI_LOADER_BOUNCE_BUFFER=y +CONFIG_EFI_MM_COMM_TEE=y diff --git a/doc/uefi/uefi.rst b/doc/uefi/uefi.rst index 4fda00d687..03d6fd0c6a 100644 --- a/doc/uefi/uefi.rst +++ b/doc/uefi/uefi.rst @@ -188,6 +188,23 @@ on the sandbox cd <U-Boot source directory> pytest.py test/py/tests/test_efi_secboot/test_signed.py --bd sandbox +Using OP-TEE for EFI variables +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Instead of implementing UEFI variable services inside U-Boot they can +also be provided in the secure world by a module for OP-TEE[1]. The +interface between U-Boot and OP-TEE for variable services is enabled by +CONFIG_EFI_MM_COMM_TEE=y. + +Tianocore EDK II's standalone management mode driver for variables can +be linked to OP-TEE for this purpose. This module uses the Replay +Protected Memory Block (RPMB) of an eMMC device for persisting +non-volatile variables. When calling the variable services via the +OP-TEE API U-Boot's OP-TEE supplicant relays calls to the RPMB driver +which has to be enabled via CONFIG_SUPPORT_EMMC_RPMB=y. + +[1] https://optee.readthedocs.io/ - OP-TEE documentation + Executing the boot manager ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/drivers/video/meson/meson_vpu.c b/drivers/video/meson/meson_vpu.c index aa8c0a962f..ed47192bf6 100644 --- a/drivers/video/meson/meson_vpu.c +++ b/drivers/video/meson/meson_vpu.c @@ -195,8 +195,8 @@ void meson_vpu_rsv_fb(void *fdt) return; #if defined(CONFIG_EFI_LOADER) - efi_add_memory_map(meson_fb.base, meson_fb.fb_size >> EFI_PAGE_SHIFT, - EFI_RESERVED_MEMORY_TYPE, false); + efi_add_memory_map(meson_fb.base, meson_fb.fb_size, + EFI_RESERVED_MEMORY_TYPE); #endif #if defined(CONFIG_VIDEO_DT_SIMPLEFB) meson_vpu_setup_simplefb(fdt); diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c index 8333ddc44c..c6e7a35338 100644 --- a/drivers/video/sunxi/sunxi_de2.c +++ b/drivers/video/sunxi/sunxi_de2.c @@ -224,9 +224,9 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase, #ifdef CONFIG_EFI_LOADER efi_add_memory_map(fbbase, - ALIGN(timing.hactive.typ * timing.vactive.typ * - (1 << l2bpp) / 8, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT, - EFI_RESERVED_MEMORY_TYPE, false); + timing.hactive.typ * timing.vactive.typ * + (1 << l2bpp) / 8, + EFI_RESERVED_MEMORY_TYPE); #endif return 0; diff --git a/drivers/video/sunxi/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c index 40ee009f62..c4c1d1b8d3 100644 --- a/drivers/video/sunxi/sunxi_display.c +++ b/drivers/video/sunxi/sunxi_display.c @@ -1196,10 +1196,8 @@ void *video_hw_init(void) sunxi_engines_init(); #ifdef CONFIG_EFI_LOADER - efi_add_memory_map(gd->fb_base, - ALIGN(sunxi_display.fb_size, EFI_PAGE_SIZE) >> - EFI_PAGE_SHIFT, - EFI_RESERVED_MEMORY_TYPE, false); + efi_add_memory_map(gd->fb_base, sunxi_display.fb_size, + EFI_RESERVED_MEMORY_TYPE); #endif fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE; diff --git a/include/efi_loader.h b/include/efi_loader.h index 0e924ad109..75c20e4679 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -545,8 +545,7 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size, efi_uintn_t *descriptor_size, uint32_t *descriptor_version); /* Adds a range into the EFI memory map */ -efi_status_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, - bool overlap_only_ram); +efi_status_t efi_add_memory_map(u64 start, u64 size, int memory_type); /* Adds a conventional range into the EFI memory map */ efi_status_t efi_add_conventional_memory_map(u64 ram_start, u64 ram_end, u64 ram_top); diff --git a/include/mm_communication.h b/include/mm_communication.h new file mode 100644 index 0000000000..193c4d1578 --- /dev/null +++ b/include/mm_communication.h @@ -0,0 +1,208 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Headers for EFI variable service via StandAloneMM, EDK2 application running + * in OP-TEE + * + * Copyright (c) 2017, Intel Corporation. All rights reserved. + * Copyright (C) 2020 Linaro Ltd. <sughosh.ganu@linaro.org> + * Copyright (C) 2020 Linaro Ltd. <ilias.apalodimas@linaro.org> + */ + +#ifndef _MM_COMMUNICATION_H_ +#define _MM_COMMUNICATION_H_ + +#include <part_efi.h> + +/* + * Interface to the pseudo Trusted Application (TA), which provides a + * communication channel with the Standalone MM (Management Mode) + * Secure Partition running at Secure-EL0 + */ + +#define PTA_STMM_CMDID_COMMUNICATE 0 + +/* OP-TEE is using big endian GUIDs while UEFI uses little endian ones */ +#define PTA_STMM_UUID { 0xed32d533, 0x99e6, 0x4209, {\ + 0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7 } } + +#define EFI_MM_VARIABLE_GUID \ + EFI_GUID(0xed32d533, 0x99e6, 0x4209, \ + 0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7) + +/* Defined in EDK2 MdePkg/Include/Protocol/MmCommunication.h */ + +/** + * struct efi_mm_communicate_header - Header used for SMM variable communication + + * @header_guid: header use for disambiguation of content + * @message_len: length of the message. Does not include the size of the + * header + * @data: payload of the message + * + * Defined in EDK2 as EFI_MM_COMMUNICATE_HEADER. + * To avoid confusion in interpreting frames, the communication buffer should + * always begin with efi_mm_communicate_header. + */ +struct efi_mm_communicate_header { + efi_guid_t header_guid; + size_t message_len; + u8 data[]; +}; + +#define MM_COMMUNICATE_HEADER_SIZE \ + (sizeof(struct efi_mm_communicate_header)) + +/* Defined in EDK2 ArmPkg/Include/IndustryStandard/ArmStdSmc.h */ + +/* MM return error codes */ +#define ARM_SMC_MM_RET_SUCCESS 0 +#define ARM_SMC_MM_RET_NOT_SUPPORTED -1 +#define ARM_SMC_MM_RET_INVALID_PARAMS -2 +#define ARM_SMC_MM_RET_DENIED -3 +#define ARM_SMC_MM_RET_NO_MEMORY -4 + +/* Defined in EDK2 MdeModulePkg/Include/Guid/SmmVariableCommon.h */ + +#define SMM_VARIABLE_FUNCTION_GET_VARIABLE 1 +/* + * The payload for this function is + * SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME. + */ +#define SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME 2 +/* + * The payload for this function is SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE. + */ +#define SMM_VARIABLE_FUNCTION_SET_VARIABLE 3 +/* + * The payload for this function is + * SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO. + */ +#define SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO 4 +/* + * It is a notify event, no extra payload for this function. + */ +#define SMM_VARIABLE_FUNCTION_READY_TO_BOOT 5 +/* + * It is a notify event, no extra payload for this function. + */ +#define SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE 6 +/* + * The payload for this function is VARIABLE_INFO_ENTRY. + * The GUID in EFI_SMM_COMMUNICATE_HEADER is gEfiSmmVariableProtocolGuid. + */ +#define SMM_VARIABLE_FUNCTION_GET_STATISTICS 7 +/* + * The payload for this function is SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE + */ +#define SMM_VARIABLE_FUNCTION_LOCK_VARIABLE 8 + +#define SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET 9 + +#define SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET 10 + +#define SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE 11 +/* + * The payload for this function is + * SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT + */ +#define SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT 12 + +#define SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE 13 +/* + * The payload for this function is + * SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO + */ +#define SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO 14 + +/** + * struct smm_variable_communicate_header - Used for SMM variable communication + + * @function: function to call in Smm. + * @ret_status: return status + * @data: payload + * + * Defined in EDK2 as SMM_VARIABLE_COMMUNICATE_HEADER. + */ +struct smm_variable_communicate_header { + efi_uintn_t function; + efi_status_t ret_status; + u8 data[]; +}; + +#define MM_VARIABLE_COMMUNICATE_SIZE \ + (sizeof(struct smm_variable_communicate_header)) + +/** + * struct smm_variable_access - Used to communicate with StMM by + * SetVariable and GetVariable. + + * @guid: vendor GUID + * @data_size: size of EFI variable data + * @name_size: size of EFI name + * @attr: attributes + * @name: variable name + * + * Defined in EDK2 as SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE. + * + */ +struct smm_variable_access { + efi_guid_t guid; + efi_uintn_t data_size; + efi_uintn_t name_size; + u32 attr; + u16 name[]; +}; + +#define MM_VARIABLE_ACCESS_HEADER_SIZE \ + (sizeof(struct smm_variable_access)) +/** + * struct smm_variable_payload_size - Used to get the max allowed + * payload used in StMM. + * + * @size: size to fill in + * + * Defined in EDK2 as SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE. + * + */ +struct smm_variable_payload_size { + efi_uintn_t size; +}; + +/** + * struct smm_variable_getnext - Used to communicate with StMM for + * GetNextVariableName. + * + * @guid: vendor GUID + * @name_size: size of the name of the variable + * @name: variable name + * + * Defined in EDK2 as SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME. + */ +struct smm_variable_getnext { + efi_guid_t guid; + efi_uintn_t name_size; + u16 name[]; +}; + +#define MM_VARIABLE_GET_NEXT_HEADER_SIZE \ + (sizeof(struct smm_variable_getnext)) + +/** + * struct smm_variable_query_info - Used to communicate with StMM for + * QueryVariableInfo. + * + * @max_variable_storage: max available storage + * @remaining_variable_storage: remaining available storage + * @max_variable_size: max variable supported size + * @attr: attributes to query storage for + * + * Defined in EDK2 as SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO. + */ +struct smm_variable_query_info { + u64 max_variable_storage; + u64 remaining_variable_storage; + u64 max_variable_size; + u32 attr; +}; + +#endif /* _MM_COMMUNICATION_H_ */ diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 1cfa24ffcf..aad37b7155 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -164,4 +164,13 @@ config EFI_SECURE_BOOT it is signed with a trusted key. To do that, you need to install, at least, PK, KEK and db. +config EFI_MM_COMM_TEE + bool "UEFI variables storage service via OP-TEE" + depends on OPTEE + default n + help + If OP-TEE is present and running StandAloneMM, dispatch all UEFI variable + related operations to that. The application will verify, authenticate and + store the variables on an RPMB. + endif diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 84d61df55b..57c7e66ea0 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -35,7 +35,11 @@ obj-y += efi_root_node.o obj-y += efi_runtime.o obj-y += efi_setup.o obj-$(CONFIG_EFI_UNICODE_COLLATION_PROTOCOL2) += efi_unicode_collation.o +ifeq ($(CONFIG_EFI_MM_COMM_TEE),y) +obj-y += efi_variable_tee.o +else obj-y += efi_variable.o +endif obj-y += efi_watchdog.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.o diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 97d90f069a..c0cf1d9126 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -229,7 +229,7 @@ static s64 efi_mem_carve_out(struct efi_mem_list *map, } /** - * efi_add_memory_map() - add memory area to the memory map + * efi_add_memory_map_pg() - add pages to the memory map * * @start: start address, must be a multiple of EFI_PAGE_SIZE * @pages: number of pages to add @@ -237,8 +237,9 @@ static s64 efi_mem_carve_out(struct efi_mem_list *map, * @overlap_only_ram: the memory area must overlap existing * Return: status code */ -efi_status_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, - bool overlap_only_ram) +static efi_status_t efi_add_memory_map_pg(u64 start, u64 pages, + int memory_type, + bool overlap_only_ram) { struct list_head *lhandle; struct efi_mem_list *newlist; @@ -344,6 +345,28 @@ efi_status_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, } /** + * efi_add_memory_map() - add memory area to the memory map + * + * @start: start address of the memory area + * @size: length in bytes of the memory area + * @memory_type: type of memory added + * + * Return: status code + * + * This function automatically aligns the start and size of the memory area + * to EFI_PAGE_SIZE. + */ +efi_status_t efi_add_memory_map(u64 start, u64 size, int memory_type) +{ + u64 pages; + + pages = efi_size_in_pages(size + (start & EFI_PAGE_MASK)); + start &= ~EFI_PAGE_MASK; + + return efi_add_memory_map_pg(start, pages, memory_type, false); +} + +/** * efi_check_allocated() - validate address to be freed * * Check that the address is within allocated memory: @@ -469,7 +492,8 @@ efi_status_t efi_allocate_pages(int type, int memory_type, } /* Reserve that map in our memory maps */ - if (efi_add_memory_map(addr, pages, memory_type, true) != EFI_SUCCESS) + ret = efi_add_memory_map_pg(addr, pages, memory_type, true); + if (ret != EFI_SUCCESS) /* Map would overlap, bail out */ return EFI_OUT_OF_RESOURCES; @@ -514,7 +538,8 @@ efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages) return EFI_INVALID_PARAMETER; } - ret = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false); + ret = efi_add_memory_map_pg(memory, pages, EFI_CONVENTIONAL_MEMORY, + false); /* Merging of adjacent free regions is missing */ if (ret != EFI_SUCCESS) @@ -680,8 +705,8 @@ efi_status_t efi_add_conventional_memory_map(u64 ram_start, u64 ram_end, pages = (ram_end - ram_start) >> EFI_PAGE_SHIFT; - efi_add_memory_map(ram_start, pages, - EFI_CONVENTIONAL_MEMORY, false); + efi_add_memory_map_pg(ram_start, pages, + EFI_CONVENTIONAL_MEMORY, false); /* * Boards may indicate to the U-Boot memory core that they @@ -691,14 +716,14 @@ efi_status_t efi_add_conventional_memory_map(u64 ram_start, u64 ram_end, */ if (ram_top < ram_start) { /* ram_top is before this region, reserve all */ - efi_add_memory_map(ram_start, pages, - EFI_BOOT_SERVICES_DATA, true); + efi_add_memory_map_pg(ram_start, pages, + EFI_BOOT_SERVICES_DATA, true); } else if ((ram_top >= ram_start) && (ram_top < ram_end)) { /* ram_top is inside this region, reserve parts */ pages = (ram_end - ram_top) >> EFI_PAGE_SHIFT; - efi_add_memory_map(ram_top, pages, - EFI_BOOT_SERVICES_DATA, true); + efi_add_memory_map_pg(ram_top, pages, + EFI_BOOT_SERVICES_DATA, true); } return EFI_SUCCESS; @@ -743,7 +768,8 @@ static void add_u_boot_and_runtime(void) uboot_stack_size) & ~EFI_PAGE_MASK; uboot_pages = ((uintptr_t)map_sysmem(gd->ram_top - 1, 0) - uboot_start + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; - efi_add_memory_map(uboot_start, uboot_pages, EFI_LOADER_DATA, false); + efi_add_memory_map_pg(uboot_start, uboot_pages, EFI_LOADER_DATA, + false); #if defined(__aarch64__) /* @@ -762,8 +788,8 @@ static void add_u_boot_and_runtime(void) runtime_end = (ulong)&__efi_runtime_stop; runtime_end = (runtime_end + runtime_mask) & ~runtime_mask; runtime_pages = (runtime_end - runtime_start) >> EFI_PAGE_SHIFT; - efi_add_memory_map(runtime_start, runtime_pages, - EFI_RUNTIME_SERVICES_CODE, false); + efi_add_memory_map_pg(runtime_start, runtime_pages, + EFI_RUNTIME_SERVICES_CODE, false); } int efi_memory_init(void) diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 6a25acbbcd..a28b291927 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -784,11 +784,10 @@ out: efi_status_t efi_add_runtime_mmio(void *mmio_ptr, u64 len) { struct efi_runtime_mmio_list *newmmio; - u64 pages = (len + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; uint64_t addr = *(uintptr_t *)mmio_ptr; efi_status_t ret; - ret = efi_add_memory_map(addr, pages, EFI_MMAP_IO, false); + ret = efi_add_memory_map(addr, len, EFI_MMAP_IO); if (ret != EFI_SUCCESS) return EFI_OUT_OF_RESOURCES; diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c new file mode 100644 index 0000000000..cacc76e23d --- /dev/null +++ b/lib/efi_loader/efi_variable_tee.c @@ -0,0 +1,662 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI variable service via OP-TEE + * + * Copyright (C) 2019 Linaro Ltd. <sughosh.ganu@linaro.org> + * Copyright (C) 2019 Linaro Ltd. <ilias.apalodimas@linaro.org> + */ + +#include <common.h> +#include <efi.h> +#include <efi_api.h> +#include <efi_loader.h> +#include <tee.h> +#include <malloc.h> +#include <mm_communication.h> + +static efi_uintn_t max_buffer_size; /* comm + var + func + data */ +static efi_uintn_t max_payload_size; /* func + data */ + +struct mm_connection { + struct udevice *tee; + u32 session; +}; + +/** + * get_connection() - Retrieve OP-TEE session for a specific UUID. + * + * @conn: session buffer to fill + * Return: status code + */ +static int get_connection(struct mm_connection *conn) +{ + static const struct tee_optee_ta_uuid uuid = PTA_STMM_UUID; + struct udevice *tee = NULL; + struct tee_open_session_arg arg; + int rc; + + tee = tee_find_device(tee, NULL, NULL, NULL); + if (!tee) + return -ENODEV; + + memset(&arg, 0, sizeof(arg)); + tee_optee_ta_uuid_to_octets(arg.uuid, &uuid); + rc = tee_open_session(tee, &arg, 0, NULL); + if (!rc) { + conn->tee = tee; + conn->session = arg.session; + } + + return rc; +} + +/** + * optee_mm_communicate() - Pass a buffer to StandaloneMM running in OP-TEE + * + * @comm_buf: locally allocted communcation buffer + * @dsize: buffer size + * Return: status code + */ +static efi_status_t optee_mm_communicate(void *comm_buf, ulong dsize) +{ + ulong buf_size; + efi_status_t ret; + struct efi_mm_communicate_header *mm_hdr; + struct mm_connection conn = { NULL, 0 }; + struct tee_invoke_arg arg; + struct tee_param param[2]; + struct tee_shm *shm = NULL; + int rc; + + if (!comm_buf) + return EFI_INVALID_PARAMETER; + + mm_hdr = (struct efi_mm_communicate_header *)comm_buf; + buf_size = mm_hdr->message_len + sizeof(efi_guid_t) + sizeof(size_t); + + if (dsize != buf_size) + return EFI_INVALID_PARAMETER; + + rc = get_connection(&conn); + if (rc) { + log_err("Unable to open OP-TEE session (err=%d)\n", rc); + return EFI_UNSUPPORTED; + } + + if (tee_shm_register(conn.tee, comm_buf, buf_size, 0, &shm)) { + log_err("Unable to register shared memory\n"); + return EFI_UNSUPPORTED; + } + + memset(&arg, 0, sizeof(arg)); + arg.func = PTA_STMM_CMDID_COMMUNICATE; + arg.session = conn.session; + + memset(param, 0, sizeof(param)); + param[0].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT; + param[0].u.memref.size = buf_size; + param[0].u.memref.shm = shm; + param[1].attr = TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT; + + rc = tee_invoke_func(conn.tee, &arg, 2, param); + if (rc) + return EFI_INVALID_PARAMETER; + tee_shm_free(shm); + tee_close_session(conn.tee, conn.session); + + switch (param[1].u.value.a) { + case ARM_SMC_MM_RET_SUCCESS: + ret = EFI_SUCCESS; + break; + + case ARM_SMC_MM_RET_INVALID_PARAMS: + ret = EFI_INVALID_PARAMETER; + break; + + case ARM_SMC_MM_RET_DENIED: + ret = EFI_ACCESS_DENIED; + break; + + case ARM_SMC_MM_RET_NO_MEMORY: + ret = EFI_OUT_OF_RESOURCES; + break; + + default: + ret = EFI_ACCESS_DENIED; + } + + return ret; +} + +/** + * mm_communicate() - Adjust the cmonnucation buffer to StandAlonneMM and send + * it to OP-TEE + * + * @comm_buf: locally allocted communcation buffer + * @dsize: buffer size + * Return: status code + */ +static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize) +{ + efi_status_t ret; + struct efi_mm_communicate_header *mm_hdr; + struct smm_variable_communicate_header *var_hdr; + + dsize += MM_COMMUNICATE_HEADER_SIZE + MM_VARIABLE_COMMUNICATE_SIZE; + mm_hdr = (struct efi_mm_communicate_header *)comm_buf; + var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data; + + ret = optee_mm_communicate(comm_buf, dsize); + if (ret != EFI_SUCCESS) { + log_err("%s failed!\n", __func__); + return ret; + } + + return var_hdr->ret_status; +} + +/** + * setup_mm_hdr() - Allocate a buffer for StandAloneMM and initialize the + * header data. + * + * @dptr: pointer address of the corresponding StandAloneMM + * function + * @payload_size: buffer size + * @func: standAloneMM function number + * @ret: EFI return code + * Return: buffer or NULL + */ +static u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size, + efi_uintn_t func, efi_status_t *ret) +{ + const efi_guid_t mm_var_guid = EFI_MM_VARIABLE_GUID; + struct efi_mm_communicate_header *mm_hdr; + struct smm_variable_communicate_header *var_hdr; + u8 *comm_buf; + + /* In the init function we initialize max_buffer_size with + * get_max_payload(). So skip the test if max_buffer_size is initialized + * StandAloneMM will perform similar checks and drop the buffer if it's + * too long + */ + if (max_buffer_size && max_buffer_size < + (MM_COMMUNICATE_HEADER_SIZE + + MM_VARIABLE_COMMUNICATE_SIZE + + payload_size)) { + *ret = EFI_INVALID_PARAMETER; + return NULL; + } + + comm_buf = calloc(1, MM_COMMUNICATE_HEADER_SIZE + + MM_VARIABLE_COMMUNICATE_SIZE + + payload_size); + if (!comm_buf) { + *ret = EFI_OUT_OF_RESOURCES; + return NULL; + } + + mm_hdr = (struct efi_mm_communicate_header *)comm_buf; + guidcpy(&mm_hdr->header_guid, &mm_var_guid); + mm_hdr->message_len = MM_VARIABLE_COMMUNICATE_SIZE + payload_size; + + var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data; + var_hdr->function = func; + if (dptr) + *dptr = var_hdr->data; + *ret = EFI_SUCCESS; + + return comm_buf; +} + +/** + * get_max_payload() - Get variable payload size from StandAloneMM. + * + * @size: size of the variable in storage + * Return: status code + */ +efi_status_t EFIAPI get_max_payload(efi_uintn_t *size) +{ + struct smm_variable_payload_size *var_payload = NULL; + efi_uintn_t payload_size; + u8 *comm_buf = NULL; + efi_status_t ret; + + if (!size) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + payload_size = sizeof(*var_payload); + comm_buf = setup_mm_hdr((void **)&var_payload, payload_size, + SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE, &ret); + if (!comm_buf) + goto out; + + ret = mm_communicate(comm_buf, payload_size); + if (ret != EFI_SUCCESS) + goto out; + + *size = var_payload->size; + +out: + free(comm_buf); + return ret; +} + +/** + * efi_get_variable() - retrieve value of a UEFI variable + * + * This function implements the GetVariable runtime service. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * @name: name of the variable + * @guid: vendor GUID + * @attr: attributes of the variable + * @data_size: size of the buffer to which the variable value is copied + * @data: buffer to which the variable value is copied + * Return: status code + */ +efi_status_t EFIAPI efi_get_variable(u16 *name, const efi_guid_t *guid, + u32 *attr, efi_uintn_t *data_size, + void *data) +{ + struct smm_variable_access *var_acc; + efi_uintn_t payload_size; + efi_uintn_t name_size; + efi_uintn_t tmp_dsize; + u8 *comm_buf = NULL; + efi_status_t ret; + + EFI_ENTRY("\"%ls\" %pUl %p %p %p", name, guid, attr, data_size, data); + + if (!name || !guid || !data_size) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + /* Check payload size */ + name_size = u16_strsize(name); + if (name_size > max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + /* Trim output buffer size */ + tmp_dsize = *data_size; + if (name_size + tmp_dsize > + max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) { + tmp_dsize = max_payload_size - + MM_VARIABLE_ACCESS_HEADER_SIZE - + name_size; + } + + /* Get communication buffer and initialize header */ + payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + tmp_dsize; + comm_buf = setup_mm_hdr((void **)&var_acc, payload_size, + SMM_VARIABLE_FUNCTION_GET_VARIABLE, &ret); + if (!comm_buf) + goto out; + + /* Fill in contents */ + guidcpy(&var_acc->guid, guid); + var_acc->data_size = tmp_dsize; + var_acc->name_size = name_size; + var_acc->attr = attr ? *attr : 0; + memcpy(var_acc->name, name, name_size); + + /* Communicate */ + ret = mm_communicate(comm_buf, payload_size); + if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) { + /* Update with reported data size for trimmed case */ + *data_size = var_acc->data_size; + } + if (ret != EFI_SUCCESS) + goto out; + + if (attr) + *attr = var_acc->attr; + if (data) + memcpy(data, (u8 *)var_acc->name + var_acc->name_size, + var_acc->data_size); + else + ret = EFI_INVALID_PARAMETER; + +out: + free(comm_buf); + return EFI_EXIT(ret); +} + +/** + * efi_get_next_variable_name() - enumerate the current variable names + * + * @variable_name_size: size of variable_name buffer in bytes + * @variable_name: name of uefi variable's name in u16 + * @guid: vendor's guid + * + * This function implements the GetNextVariableName service. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code + */ +efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size, + u16 *variable_name, + efi_guid_t *guid) +{ + struct smm_variable_getnext *var_getnext; + efi_uintn_t payload_size; + efi_uintn_t out_name_size; + efi_uintn_t in_name_size; + efi_uintn_t tmp_dsize; + efi_uintn_t name_size; + u8 *comm_buf = NULL; + efi_status_t ret; + + EFI_ENTRY("%p \"%ls\" %pUl", variable_name_size, variable_name, guid); + + if (!variable_name_size || !variable_name || !guid) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + out_name_size = *variable_name_size; + in_name_size = u16_strsize(variable_name); + + if (out_name_size < in_name_size) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + name_size = u16_strsize(variable_name); + if (name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + /* Trim output buffer size */ + tmp_dsize = *variable_name_size; + if (name_size + tmp_dsize > + max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE) { + tmp_dsize = max_payload_size - + MM_VARIABLE_GET_NEXT_HEADER_SIZE - + name_size; + } + + payload_size = MM_VARIABLE_GET_NEXT_HEADER_SIZE + out_name_size; + comm_buf = setup_mm_hdr((void **)&var_getnext, payload_size, + SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME, + &ret); + if (!comm_buf) + goto out; + + /* Fill in contents */ + guidcpy(&var_getnext->guid, guid); + var_getnext->name_size = out_name_size; + memcpy(var_getnext->name, variable_name, in_name_size); + memset((u8 *)var_getnext->name + in_name_size, 0x0, + out_name_size - in_name_size); + + /* Communicate */ + ret = mm_communicate(comm_buf, payload_size); + if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) { + /* Update with reported data size for trimmed case */ + *variable_name_size = var_getnext->name_size; + } + if (ret != EFI_SUCCESS) + goto out; + + guidcpy(guid, &var_getnext->guid); + memcpy(variable_name, (u8 *)var_getnext->name, + var_getnext->name_size); + +out: + free(comm_buf); + return EFI_EXIT(ret); +} + +/** + * efi_set_variable() - set value of a UEFI variable + * + * This function implements the SetVariable runtime service. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * @name: name of the variable + * @guid: vendor GUID + * @attr: attributes of the variable + * @data_size: size of the buffer with the variable value + * @data: buffer with the variable value + * Return: status code + */ +efi_status_t EFIAPI efi_set_variable(u16 *name, const efi_guid_t *guid, + u32 attr, efi_uintn_t data_size, + const void *data) +{ + struct smm_variable_access *var_acc; + efi_uintn_t payload_size; + efi_uintn_t name_size; + u8 *comm_buf = NULL; + efi_status_t ret; + + EFI_ENTRY("\"%ls\" %pUl %x %zu %p", name, guid, attr, data_size, data); + + if (!name || name[0] == 0 || !guid) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + if (data_size > 0 && !data) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + /* Check payload size */ + name_size = u16_strsize(name); + payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + data_size; + if (payload_size > max_payload_size) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + /* Get communication buffer and initialize header */ + comm_buf = setup_mm_hdr((void **)&var_acc, payload_size, + SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret); + if (!comm_buf) + goto out; + + /* Fill in contents */ + guidcpy(&var_acc->guid, guid); + var_acc->data_size = data_size; + var_acc->name_size = name_size; + var_acc->attr = attr; + memcpy(var_acc->name, name, name_size); + memcpy((u8 *)var_acc->name + name_size, data, data_size); + + /* Communicate */ + ret = mm_communicate(comm_buf, payload_size); + +out: + free(comm_buf); + return EFI_EXIT(ret); +} + +/** + * efi_query_variable_info() - get information about EFI variables + * + * This function implements the QueryVariableInfo() runtime service. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * @attributes: bitmask to select variables to be + * queried + * @maximum_variable_storage_size: maximum size of storage area for the + * selected variable types + * @remaining_variable_storage_size: remaining size of storage are for the + * selected variable types + * @maximum_variable_size: maximum size of a variable of the + * selected type + * Returns: status code + */ +efi_status_t EFIAPI __efi_runtime +efi_query_variable_info(u32 attributes, u64 *max_variable_storage_size, + u64 *remain_variable_storage_size, + u64 *max_variable_size) +{ + struct smm_variable_query_info *mm_query_info; + efi_uintn_t payload_size; + efi_status_t ret; + u8 *comm_buf; + + EFI_ENTRY("%x %p %p %p", attributes, max_variable_storage_size, + remain_variable_storage_size, max_variable_size); + + payload_size = sizeof(*mm_query_info); + comm_buf = setup_mm_hdr((void **)&mm_query_info, payload_size, + SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO, + &ret); + if (!comm_buf) + goto out; + + mm_query_info->attr = attributes; + ret = mm_communicate(comm_buf, payload_size); + if (ret != EFI_SUCCESS) + goto out; + *max_variable_storage_size = mm_query_info->max_variable_storage; + *remain_variable_storage_size = + mm_query_info->remaining_variable_storage; + *max_variable_size = mm_query_info->max_variable_size; + +out: + free(comm_buf); + return EFI_EXIT(ret); +} + +/** + * efi_get_variable_runtime() - runtime implementation of GetVariable() + * + * @variable_name: name of the variable + * @guid: vendor GUID + * @attributes: attributes of the variable + * @data_size: size of the buffer to which the variable value is copied + * @data: buffer to which the variable value is copied + * Return: status code + */ +static efi_status_t __efi_runtime EFIAPI +efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid, + u32 *attributes, efi_uintn_t *data_size, void *data) +{ + return EFI_UNSUPPORTED; +} + +/** + * efi_get_next_variable_name_runtime() - runtime implementation of + * GetNextVariable() + * + * @variable_name_size: size of variable_name buffer in byte + * @variable_name: name of uefi variable's name in u16 + * @guid: vendor's guid + * Return: status code + */ +static efi_status_t __efi_runtime EFIAPI +efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size, + u16 *variable_name, efi_guid_t *guid) +{ + return EFI_UNSUPPORTED; +} + +/** + * efi_query_variable_info() - get information about EFI variables + * + * This function implements the QueryVariableInfo() runtime service. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * @attributes: bitmask to select variables to be + * queried + * @maximum_variable_storage_size: maximum size of storage area for the + * selected variable types + * @remaining_variable_storage_size: remaining size of storage are for the + * selected variable types + * @maximum_variable_size: maximum size of a variable of the + * selected type + * Return: status code + */ +efi_status_t EFIAPI __efi_runtime +efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size, + u64 *remain_variable_storage_size, + u64 *max_variable_size) +{ + return EFI_UNSUPPORTED; +} + +/** + * efi_set_variable_runtime() - runtime implementation of SetVariable() + * + * @variable_name: name of the variable + * @guid: vendor GUID + * @attributes: attributes of the variable + * @data_size: size of the buffer with the variable value + * @data: buffer with the variable value + * Return: status code + */ +static efi_status_t __efi_runtime EFIAPI +efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *guid, + u32 attributes, efi_uintn_t data_size, + const void *data) +{ + return EFI_UNSUPPORTED; +} + +/** + * efi_variables_boot_exit_notify() - notify ExitBootServices() is called + */ +void efi_variables_boot_exit_notify(void) +{ + u8 *comm_buf; + efi_status_t ret; + + comm_buf = setup_mm_hdr(NULL, 0, + SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE, &ret); + if (comm_buf) + ret = mm_communicate(comm_buf, 0); + else + ret = EFI_NOT_FOUND; + + if (ret != EFI_SUCCESS) + log_err("Unable to notify StMM for ExitBootServices\n"); + free(comm_buf); + + /* Update runtime service table */ + efi_runtime_services.query_variable_info = + efi_query_variable_info_runtime; + efi_runtime_services.get_variable = efi_get_variable_runtime; + efi_runtime_services.get_next_variable_name = + efi_get_next_variable_name_runtime; + efi_runtime_services.set_variable = efi_set_variable_runtime; + efi_update_table_header_crc32(&efi_runtime_services.hdr); +} + +/** + * efi_init_variables() - initialize variable services + * + * Return: status code + */ +efi_status_t efi_init_variables(void) +{ + efi_status_t ret; + + ret = get_max_payload(&max_payload_size); + if (ret != EFI_SUCCESS) + return ret; + + max_buffer_size = MM_COMMUNICATE_HEADER_SIZE + + MM_VARIABLE_COMMUNICATE_SIZE + + max_payload_size; + + return EFI_SUCCESS; +} |