diff --git a/arch/arm/mach-imx/mx7/Kconfig b/arch/arm/mach-imx/mx7/Kconfig index 059e65879c..0cad825287 100644 --- a/arch/arm/mach-imx/mx7/Kconfig +++ b/arch/arm/mach-imx/mx7/Kconfig @@ -23,6 +23,14 @@ config SPL_TEXT_BASE depends on SPL default 0x00912000 +config OPTEE_TZDRAM_SIZE + hex "Amount of Trust-Zone RAM for the OPTEE image" + default 0x0000000 + depends on OPTEE_LIB + help + The size of pre-allocated Trust Zone DRAM to allocate for the OPTEE + runtime. + choice prompt "MX7 board select" optional diff --git a/arch/arm/mach-rockchip/sdram.c b/arch/arm/mach-rockchip/sdram.c index 28c379ef07..705ec7ba64 100644 --- a/arch/arm/mach-rockchip/sdram.c +++ b/arch/arm/mach-rockchip/sdram.c @@ -45,7 +45,7 @@ int dram_init_banksize(void) gd->bd->bi_dram[0].start = 0x200000; gd->bd->bi_dram[0].size = top - gd->bd->bi_dram[0].start; #else -#ifdef CONFIG_SPL_OPTEE +#ifdef CONFIG_SPL_OPTEE_IMAGE struct tos_parameter_t *tos_parameter; tos_parameter = (struct tos_parameter_t *)(CONFIG_SYS_SDRAM_BASE + diff --git a/arch/arm/mach-stm32mp/fdt.c b/arch/arm/mach-stm32mp/fdt.c index a19e954cf7..91330a68a4 100644 --- a/arch/arm/mach-stm32mp/fdt.c +++ b/arch/arm/mach-stm32mp/fdt.c @@ -341,7 +341,6 @@ int ft_system_setup(void *blob, struct bd_info *bd) * when FIP is not used by TF-A */ if (CONFIG_IS_ENABLED(STM32MP15x_STM32IMAGE) && - CONFIG_IS_ENABLED(OPTEE) && !tee_find_device(NULL, NULL, NULL, NULL)) stm32_fdt_disable_optee(blob); diff --git a/board/st/common/stm32mp_mtdparts.c b/board/st/common/stm32mp_mtdparts.c index 8b636d62fa..18878424c7 100644 --- a/board/st/common/stm32mp_mtdparts.c +++ b/board/st/common/stm32mp_mtdparts.c @@ -119,8 +119,7 @@ void board_mtdparts_default(const char **mtdids, const char **mtdparts) } #ifdef CONFIG_STM32MP15x_STM32IMAGE - if (!serial && CONFIG_IS_ENABLED(OPTEE) && - tee_find_device(NULL, NULL, NULL, NULL)) + if (!serial && tee_find_device(NULL, NULL, NULL, NULL)) tee = true; #endif diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 34f6fc2cfa..8a8a971a91 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -1263,11 +1263,11 @@ config SPL_AM33XX_ENABLE_RTC32K_OSC Enable access to the AM33xx RTC and select the external 32kHz clock source. -config SPL_OPTEE - bool "Support OP-TEE Trusted OS" +config SPL_OPTEE_IMAGE + bool "Support OP-TEE Trusted OS image in SPL" depends on ARM help - OP-TEE is an open source Trusted OS which is loaded by SPL. + OP-TEE is an open source Trusted OS which is loaded by SPL. More detail at: https://github.com/OP-TEE/optee_os config SPL_OPENSBI diff --git a/common/spl/Makefile b/common/spl/Makefile index cb15c8e827..db8fd36a26 100644 --- a/common/spl/Makefile +++ b/common/spl/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_$(SPL_TPL_)UBI) += spl_ubi.o obj-$(CONFIG_$(SPL_TPL_)NET) += spl_net.o obj-$(CONFIG_$(SPL_TPL_)MMC) += spl_mmc.o obj-$(CONFIG_$(SPL_TPL_)ATF) += spl_atf.o -obj-$(CONFIG_$(SPL_TPL_)OPTEE) += spl_optee.o +obj-$(CONFIG_$(SPL_TPL_)OPTEE_IMAGE) += spl_optee.o obj-$(CONFIG_$(SPL_TPL_)OPENSBI) += spl_opensbi.o obj-$(CONFIG_$(SPL_TPL_)USB_STORAGE) += spl_usb.o obj-$(CONFIG_$(SPL_TPL_)FS_FAT) += spl_fat.o diff --git a/common/spl/spl.c b/common/spl/spl.c index ed94d5146c..a9304d4148 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -776,7 +776,7 @@ void board_init_r(gd_t *dummy1, ulong dummy2) spl_invoke_atf(&spl_image); break; #endif -#if CONFIG_IS_ENABLED(OPTEE) +#if CONFIG_IS_ENABLED(OPTEE_IMAGE) case IH_OS_TEE: debug("Jumping to U-Boot via OP-TEE\n"); spl_board_prepare_for_optee(spl_image.fdt_addr); diff --git a/configs/evb-rk3229_defconfig b/configs/evb-rk3229_defconfig index 0bf91d61b4..a8b1c42ac6 100644 --- a/configs/evb-rk3229_defconfig +++ b/configs/evb-rk3229_defconfig @@ -28,7 +28,7 @@ CONFIG_DISPLAY_BOARDINFO_LATE=y # CONFIG_SPL_RAW_IMAGE_SUPPORT is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x2000 -CONFIG_SPL_OPTEE=y +CONFIG_SPL_OPTEE_IMAGE=y CONFIG_CMD_GPT=y CONFIG_CMD_MMC=y CONFIG_CMD_USB_MASS_STORAGE=y diff --git a/configs/evb-rk3288_defconfig b/configs/evb-rk3288_defconfig index efb2a3ede6..eca9f5c54d 100644 --- a/configs/evb-rk3288_defconfig +++ b/configs/evb-rk3288_defconfig @@ -25,7 +25,7 @@ CONFIG_SILENT_CONSOLE=y CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_SPL_STACK_R=y CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x10000 -CONFIG_SPL_OPTEE=y +CONFIG_SPL_OPTEE_IMAGE=y CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y diff --git a/configs/odroid-go2_defconfig b/configs/odroid-go2_defconfig index c744c3a6ea..df64307f8e 100644 --- a/configs/odroid-go2_defconfig +++ b/configs/odroid-go2_defconfig @@ -98,7 +98,7 @@ CONFIG_DEBUG_UART_SHIFT=2 CONFIG_DEBUG_UART_SKIP_INIT=y CONFIG_SOUND=y CONFIG_SYSRESET=y -CONFIG_OPTEE=y +CONFIG_OPTEE_LIB=y CONFIG_DM_THERMAL=y CONFIG_USB=y CONFIG_USB_EHCI_HCD=y diff --git a/configs/warp7_bl33_defconfig b/configs/warp7_bl33_defconfig index d127a4f8d3..246a1ec6fe 100644 --- a/configs/warp7_bl33_defconfig +++ b/configs/warp7_bl33_defconfig @@ -69,4 +69,3 @@ CONFIG_USB_ETH_CDC=y CONFIG_USBNET_HOST_ADDR="de:ad:be:af:00:00" CONFIG_OF_LIBFDT_OVERLAY=y CONFIG_OPTEE_TZDRAM_SIZE=0x02000000 -CONFIG_OPTEE_TZDRAM_BASE=0x9e000000 diff --git a/configs/warp7_defconfig b/configs/warp7_defconfig index 4b339b47ca..db8d4f625a 100644 --- a/configs/warp7_defconfig +++ b/configs/warp7_defconfig @@ -73,7 +73,5 @@ CONFIG_USB_GADGET_DOWNLOAD=y CONFIG_USB_ETHER=y CONFIG_USB_ETH_CDC=y CONFIG_USBNET_HOST_ADDR="de:ad:be:af:00:00" -CONFIG_OPTEE_LOAD_ADDR=0x84000000 CONFIG_OPTEE_TZDRAM_SIZE=0x3000000 -CONFIG_OPTEE_TZDRAM_BASE=0x9d000000 CONFIG_BOOTM_OPTEE=y diff --git a/doc/develop/py_testing.rst b/doc/develop/py_testing.rst index c4cecc0a01..4f1e1f66e7 100644 --- a/doc/develop/py_testing.rst +++ b/doc/develop/py_testing.rst @@ -103,6 +103,36 @@ will be written to `${build_dir}/test-log.html`. This is best viewed in a web browser, but may be read directly as plain text, perhaps with the aid of the `html2text` utility. +Running tests in parallel +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Note: This does not fully work yet and is documented only so you can try to +fix the problems. + +First install support for parallel tests:: + + pip3 install pytest-xdist + +Then build sandbox in a suitable build directory. It is not possible to use +the --build flag with xdist. + +Finally, run the tests in parallel using the -n flag:: + + # build sandbox first, in a suitable build directory. It is not possible + # to use the --build flag with -n + test/py/test.py -B sandbox --build-dir /tmp/b/sandbox -q -k 'not slow' -n32 + +At least the following non-slow tests are known to fail: + +- test_fit_ecdsa +- test_bind_unbind_with_uclass +- ut_dm_spi_flash +- test_gpt_rename_partition +- test_gpt_swap_partitions +- test_pinmux_status +- test_sqfs_load + + Testing under a debugger ~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/drivers/demo/demo-uclass.c b/drivers/demo/demo-uclass.c index 815f8de645..09f9a47d4d 100644 --- a/drivers/demo/demo-uclass.c +++ b/drivers/demo/demo-uclass.c @@ -10,15 +10,11 @@ #include #include #include -#include #include #include -#include #include #include -DECLARE_GLOBAL_DATA_PTR; - UCLASS_DRIVER(demo) = { .name = "demo", .id = UCLASS_DEMO, @@ -67,10 +63,9 @@ int demo_set_light(struct udevice *dev, int light) int demo_parse_dt(struct udevice *dev) { struct dm_demo_pdata *pdata = dev_get_plat(dev); - int dn = dev_of_offset(dev); - pdata->sides = fdtdec_get_int(gd->fdt_blob, dn, "sides", 0); - pdata->colour = fdt_getprop(gd->fdt_blob, dn, "colour", NULL); + pdata->sides = dev_read_s32_default(dev, "sides", 0); + pdata->colour = dev_read_string(dev, "colour"); if (!pdata->sides || !pdata->colour) { debug("%s: Invalid device tree data\n", __func__); return -EINVAL; diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index bb2f23241e..1c5e2e7976 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -141,7 +141,8 @@ int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc) if (!strncasecmp(name, uc_priv->bank_name, len)) { if (!strict_strtoul(name + len, 10, &offset)) - break; + if (offset < uc_priv->gpio_count) + break; } /* @@ -185,38 +186,50 @@ int gpio_lookup_name(const char *name, struct udevice **devp, return 0; } -int gpio_xlate_offs_flags(struct udevice *dev, struct gpio_desc *desc, - struct ofnode_phandle_args *args) +unsigned long gpio_flags_xlate(uint32_t arg) { - if (args->args_count < 1) - return -EINVAL; + unsigned long flags = 0; - desc->offset = args->args[0]; - - if (args->args_count < 2) - return 0; - - desc->flags = 0; - if (args->args[1] & GPIO_ACTIVE_LOW) - desc->flags |= GPIOD_ACTIVE_LOW; + if (arg & GPIO_ACTIVE_LOW) + flags |= GPIOD_ACTIVE_LOW; /* * need to test 2 bits for gpio output binding: * OPEN_DRAIN (0x6) = SINGLE_ENDED (0x2) | LINE_OPEN_DRAIN (0x4) * OPEN_SOURCE (0x2) = SINGLE_ENDED (0x2) | LINE_OPEN_SOURCE (0x0) */ - if (args->args[1] & GPIO_SINGLE_ENDED) { - if (args->args[1] & GPIO_LINE_OPEN_DRAIN) - desc->flags |= GPIOD_OPEN_DRAIN; + if (arg & GPIO_SINGLE_ENDED) { + if (arg & GPIO_LINE_OPEN_DRAIN) + flags |= GPIOD_OPEN_DRAIN; else - desc->flags |= GPIOD_OPEN_SOURCE; + flags |= GPIOD_OPEN_SOURCE; } - if (args->args[1] & GPIO_PULL_UP) - desc->flags |= GPIOD_PULL_UP; + if (arg & GPIO_PULL_UP) + flags |= GPIOD_PULL_UP; - if (args->args[1] & GPIO_PULL_DOWN) - desc->flags |= GPIOD_PULL_DOWN; + if (arg & GPIO_PULL_DOWN) + flags |= GPIOD_PULL_DOWN; + + return flags; +} + +int gpio_xlate_offs_flags(struct udevice *dev, struct gpio_desc *desc, + struct ofnode_phandle_args *args) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + if (args->args_count < 1) + return -EINVAL; + + desc->offset = args->args[0]; + if (desc->offset >= uc_priv->gpio_count) + return -EINVAL; + + if (args->args_count < 2) + return 0; + + desc->flags = gpio_flags_xlate(args->args[1]); return 0; } diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index cf9ad3670f..8fc07e3498 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -44,11 +45,27 @@ struct single_func { unsigned int *pins; }; +/** + * struct single_gpiofunc_range - pin ranges with same mux value of gpio fun + * @offset: offset base of pins + * @npins: number pins with the same mux value of gpio function + * @gpiofunc: mux value of gpio function + * @node: list node + */ +struct single_gpiofunc_range { + u32 offset; + u32 npins; + u32 gpiofunc; + struct list_head node; +}; + /** * struct single_priv - private data * @bits_per_pin: number of bits per pin * @npins: number of selectable pins * @pin_name: temporary buffer to store the pin name + * @functions: list pin functions + * @gpiofuncs: list gpio functions */ struct single_priv { #if (IS_ENABLED(CONFIG_SANDBOX)) @@ -58,6 +75,7 @@ struct single_priv { unsigned int npins; char pin_name[PINNAME_SIZE]; struct list_head functions; + struct list_head gpiofuncs; }; /** @@ -232,6 +250,39 @@ static int single_get_pin_muxing(struct udevice *dev, unsigned int pin, return 0; } +static int single_request(struct udevice *dev, int pin, int flags) +{ + struct single_priv *priv = dev_get_priv(dev); + struct single_pdata *pdata = dev_get_plat(dev); + struct single_gpiofunc_range *frange = NULL; + struct list_head *pos, *tmp; + phys_addr_t reg; + int mux_bytes = 0; + u32 data; + + /* If function mask is null, needn't enable it. */ + if (!pdata->mask) + return -ENOTSUPP; + + list_for_each_safe(pos, tmp, &priv->gpiofuncs) { + frange = list_entry(pos, struct single_gpiofunc_range, node); + if ((pin >= frange->offset + frange->npins) || + pin < frange->offset) + continue; + + mux_bytes = pdata->width / BITS_PER_BYTE; + reg = pdata->base + pin * mux_bytes; + + data = single_read(dev, reg); + data &= ~pdata->mask; + data |= frange->gpiofunc; + single_write(dev, data, reg); + break; + } + + return 0; +} + static struct single_func *single_allocate_function(struct udevice *dev, unsigned int group_pins) { @@ -454,6 +505,36 @@ static int single_get_pins_count(struct udevice *dev) return priv->npins; } +static int single_add_gpio_func(struct udevice *dev) +{ + struct single_priv *priv = dev_get_priv(dev); + const char *propname = "pinctrl-single,gpio-range"; + const char *cellname = "#pinctrl-single,gpio-range-cells"; + struct single_gpiofunc_range *range; + struct ofnode_phandle_args gpiospec; + int ret, i; + + for (i = 0; ; i++) { + ret = ofnode_parse_phandle_with_args(dev_ofnode(dev), propname, + cellname, 0, i, &gpiospec); + /* Do not treat it as error. Only treat it as end condition. */ + if (ret) { + ret = 0; + break; + } + range = devm_kzalloc(dev, sizeof(*range), GFP_KERNEL); + if (!range) { + ret = -ENOMEM; + break; + } + range->offset = gpiospec.args[0]; + range->npins = gpiospec.args[1]; + range->gpiofunc = gpiospec.args[2]; + list_add_tail(&range->node, &priv->gpiofuncs); + } + return ret; +} + static int single_probe(struct udevice *dev) { struct single_pdata *pdata = dev_get_plat(dev); @@ -461,6 +542,7 @@ static int single_probe(struct udevice *dev) u32 size; INIT_LIST_HEAD(&priv->functions); + INIT_LIST_HEAD(&priv->gpiofuncs); size = pdata->offset + pdata->width / BITS_PER_BYTE; #if (CONFIG_IS_ENABLED(SANDBOX)) @@ -483,6 +565,9 @@ static int single_probe(struct udevice *dev) priv->npins *= (pdata->width / priv->bits_per_pin); } + if (single_add_gpio_func(dev)) + dev_dbg(dev, "gpio functions are not added\n"); + dev_dbg(dev, "%d pins\n", priv->npins); return 0; } @@ -535,6 +620,7 @@ const struct pinctrl_ops single_pinctrl_ops = { .get_pin_name = single_get_pin_name, .set_state = single_set_state, .get_pin_muxing = single_get_pin_muxing, + .request = single_request, }; static const struct udevice_id single_pinctrl_match[] = { diff --git a/drivers/reboot-mode/reboot-mode-uclass.c b/drivers/reboot-mode/reboot-mode-uclass.c index bb7a355fbf..2b38aa26b8 100644 --- a/drivers/reboot-mode/reboot-mode-uclass.c +++ b/drivers/reboot-mode/reboot-mode-uclass.c @@ -10,8 +10,6 @@ #include #include -DECLARE_GLOBAL_DATA_PTR; - int dm_reboot_mode_update(struct udevice *dev) { struct reboot_mode_ops *ops = reboot_mode_get_ops(dev); @@ -66,25 +64,20 @@ int dm_reboot_mode_pre_probe(struct udevice *dev) return -EINVAL; #if CONFIG_IS_ENABLED(OF_CONTROL) - const int node = dev_of_offset(dev); const char *mode_prefix = "mode-"; const int mode_prefix_len = strlen(mode_prefix); - int property; + struct ofprop property; const u32 *propvalue; const char *propname; - plat_data->env_variable = fdt_getprop(gd->fdt_blob, - node, - "u-boot,env-variable", - NULL); + plat_data->env_variable = dev_read_string(dev, "u-boot,env-variable"); if (!plat_data->env_variable) plat_data->env_variable = "reboot-mode"; plat_data->count = 0; - fdt_for_each_property_offset(property, gd->fdt_blob, node) { - propvalue = fdt_getprop_by_offset(gd->fdt_blob, - property, &propname, NULL); + dev_for_each_property(property, dev) { + propvalue = dev_read_prop_by_prop(&property, &propname, NULL); if (!propvalue) { dev_err(dev, "Could not get the value for property %s\n", propname); @@ -100,9 +93,8 @@ int dm_reboot_mode_pre_probe(struct udevice *dev) struct reboot_mode_mode *next = plat_data->modes; - fdt_for_each_property_offset(property, gd->fdt_blob, node) { - propvalue = fdt_getprop_by_offset(gd->fdt_blob, - property, &propname, NULL); + dev_for_each_property(property, dev) { + propvalue = dev_read_prop_by_prop(&property, &propname, NULL); if (!propvalue) { dev_err(dev, "Could not get the value for property %s\n", propname); diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c index 64c47c1e72..87e1ec7ad7 100644 --- a/drivers/remoteproc/rproc-uclass.c +++ b/drivers/remoteproc/rproc-uclass.c @@ -9,19 +9,15 @@ #define pr_fmt(fmt) "%s: " fmt, __func__ #include #include -#include #include #include #include -#include #include #include #include #include #include -DECLARE_GLOBAL_DATA_PTR; - /** * for_each_remoteproc_device() - iterate through the list of rproc devices * @fn: check function to call per match, if this function returns fail, @@ -121,21 +117,13 @@ static int rproc_pre_probe(struct udevice *dev) if (!dev_get_plat(dev)) { #if CONFIG_IS_ENABLED(OF_CONTROL) - int node = dev_of_offset(dev); - const void *blob = gd->fdt_blob; bool tmp; - if (!blob) { - debug("'%s' no dt?\n", dev->name); - return -EINVAL; - } debug("'%s': using fdt\n", dev->name); - uc_pdata->name = fdt_getprop(blob, node, - "remoteproc-name", NULL); + uc_pdata->name = dev_read_string(dev, "remoteproc-name"); /* Default is internal memory mapped */ uc_pdata->mem_type = RPROC_INTERNAL_MEMORY_MAPPED; - tmp = fdtdec_get_bool(blob, node, - "remoteproc-internal-memory-mapped"); + tmp = dev_read_bool(dev, "remoteproc-internal-memory-mapped"); if (tmp) uc_pdata->mem_type = RPROC_INTERNAL_MEMORY_MAPPED; #else diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 6de13d925e..fa9b80722e 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -221,6 +221,14 @@ int gpio_requestf(unsigned gpio, const char *fmt, ...) struct fdtdec_phandle_args; +/** + * gpio_flags_xlate() - convert DT flags to internal flags + * + * This routine converts the GPIO_* flags from the generic DT binding to the + * GPIOD_* flags used internally. It can be called from driver xlate functions. + */ +unsigned long gpio_flags_xlate(uint32_t arg); + /** * gpio_xlate_offs_flags() - implementation for common use of dm_gpio_ops.xlate * diff --git a/include/configs/warp7.h b/include/configs/warp7.h index 0822eaf555..74fb988b76 100644 --- a/include/configs/warp7.h +++ b/include/configs/warp7.h @@ -28,10 +28,6 @@ #define BOOT_SCR_STRING "source ${bootscriptaddr}\0" #endif -#ifndef CONFIG_OPTEE_LOAD_ADDR -#define CONFIG_OPTEE_LOAD_ADDR 0 -#endif - #define CONFIG_EXTRA_ENV_SETTINGS \ CONFIG_DFU_ENV_SETTINGS \ "script=boot.scr\0" \ @@ -46,7 +42,6 @@ "fdt_file=imx7s-warp.dtb\0" \ "fdt_addr=" __stringify(CONFIG_SYS_FDT_ADDR)"\0" \ "fdtovaddr=0x83100000\0" \ - "optee_addr=" __stringify(CONFIG_OPTEE_LOAD_ADDR)"\0" \ "boot_fdt=try\0" \ "ip_dyn=yes\0" \ "mmcdev="__stringify(CONFIG_SYS_MMC_ENV_DEV)"\0" \ diff --git a/include/tee.h b/include/tee.h index 2ef29bfc8f..44e9cd4321 100644 --- a/include/tee.h +++ b/include/tee.h @@ -307,11 +307,22 @@ bool tee_shm_is_registered(struct tee_shm *shm, struct udevice *dev); * Returns a probed TEE device of the first TEE device matched by the * match() callback or NULL. */ +#if CONFIG_IS_ENABLED(TEE) struct udevice *tee_find_device(struct udevice *start, int (*match)(struct tee_version_data *vers, const void *data), const void *data, struct tee_version_data *vers); +#else +static inline struct udevice *tee_find_device(struct udevice *start, + int (*match)(struct tee_version_data *vers, + const void *data), + const void *data, + struct tee_version_data *vers) +{ + return NULL; +} +#endif /** * tee_get_version() - Query capabilities of TEE device diff --git a/include/tee/optee.h b/include/tee/optee.h index ebdfe5e98d..5412bc7386 100644 --- a/include/tee/optee.h +++ b/include/tee/optee.h @@ -43,21 +43,7 @@ optee_image_get_load_addr(const struct image_header *hdr) return optee_image_get_entry_point(hdr) - sizeof(struct optee_header); } -#if defined(CONFIG_OPTEE) -int optee_verify_image(struct optee_header *hdr, unsigned long tzdram_start, - unsigned long tzdram_len, unsigned long image_len); -#else -static inline int optee_verify_image(struct optee_header *hdr, - unsigned long tzdram_start, - unsigned long tzdram_len, - unsigned long image_len) -{ - return -EPERM; -} - -#endif - -#if defined(CONFIG_OPTEE) +#if defined(CONFIG_OPTEE_IMAGE) int optee_verify_bootm_image(unsigned long image_addr, unsigned long image_load_addr, unsigned long image_len); @@ -70,7 +56,7 @@ static inline int optee_verify_bootm_image(unsigned long image_addr, } #endif -#if defined(CONFIG_OPTEE) && defined(CONFIG_OF_LIBFDT) +#if defined(CONFIG_OPTEE_LIB) && defined(CONFIG_OF_LIBFDT) int optee_copy_fdt_nodes(void *new_blob); #else static inline int optee_copy_fdt_nodes(void *new_blob) diff --git a/lib/Makefile b/lib/Makefile index 09e380eb66..962470f496 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -16,7 +16,7 @@ obj-$(CONFIG_FIT) += libfdt/ obj-$(CONFIG_OF_LIVE) += of_live.o obj-$(CONFIG_CMD_DHRYSTONE) += dhry/ obj-$(CONFIG_ARCH_AT91) += at91/ -obj-$(CONFIG_OPTEE) += optee/ +obj-$(CONFIG_OPTEE_LIB) += optee/ obj-$(CONFIG_ASN1_DECODER) += asn1_decoder.o obj-y += crypto/ diff --git a/lib/optee/Kconfig b/lib/optee/Kconfig index 3290b6656d..517136a448 100644 --- a/lib/optee/Kconfig +++ b/lib/optee/Kconfig @@ -1,39 +1,20 @@ -config OPTEE +config OPTEE_LIB + bool "Support OPTEE library" + default y if OPTEE || OPTEE_IMAGE + help + Selecting this option will enable the shared OPTEE library code. + +config OPTEE_IMAGE bool "Support OPTEE images" help - U-Boot can be configured to boot OPTEE images. - Selecting this option will enable shared OPTEE library code and - enable an OPTEE specific bootm command that will perform additional - OPTEE specific checks before booting an OPTEE image created with - mkimage. - -config OPTEE_LOAD_ADDR - hex "OPTEE load address" - default 0x00000000 - depends on OPTEE - help - The load address of the bootable OPTEE binary. - -config OPTEE_TZDRAM_SIZE - hex "Amount of Trust-Zone RAM for the OPTEE image" - default 0x0000000 - depends on OPTEE - help - The size of pre-allocated Trust Zone DRAM to allocate for the OPTEE - runtime. - -config OPTEE_TZDRAM_BASE - hex "Base address of Trust-Zone RAM for the OPTEE image" - default 0x00000000 - depends on OPTEE - help - The base address of pre-allocated Trust Zone DRAM for - the OPTEE runtime. + Selecting this option to boot OPTEE images. + This option enable the OPTEE specific checks done before booting + an OPTEE image created with mkimage config BOOTM_OPTEE bool "Support OPTEE bootm command" select BOOTM_LINUX - depends on OPTEE + select OPTEE_IMAGE help Select this command to enable chain-loading of a Linux kernel via an OPTEE firmware. diff --git a/lib/optee/Makefile b/lib/optee/Makefile index b692311864..9befe606d8 100644 --- a/lib/optee/Makefile +++ b/lib/optee/Makefile @@ -2,4 +2,4 @@ # # (C) Copyright 2017 Linaro -obj-$(CONFIG_OPTEE) += optee.o +obj-y += optee.o diff --git a/lib/optee/optee.c b/lib/optee/optee.c index 672690dc53..766d0d9e3f 100644 --- a/lib/optee/optee.c +++ b/lib/optee/optee.c @@ -16,14 +16,13 @@ #define optee_hdr_err_msg \ "OPTEE verification error:" \ - "\n\thdr=%p image=0x%08lx magic=0x%08x tzdram 0x%08lx-0x%08lx " \ + "\n\thdr=%p image=0x%08lx magic=0x%08x" \ "\n\theader lo=0x%08x hi=0x%08x size=0x%08lx arch=0x%08x" \ "\n\tuimage params 0x%08lx-0x%08lx\n" -int optee_verify_image(struct optee_header *hdr, unsigned long tzdram_start, - unsigned long tzdram_len, unsigned long image_len) +#if defined(CONFIG_OPTEE_IMAGE) +static int optee_verify_image(struct optee_header *hdr, unsigned long image_len) { - unsigned long tzdram_end = tzdram_start + tzdram_len; uint32_t tee_file_size; tee_file_size = hdr->init_size + hdr->paged_size + @@ -31,11 +30,7 @@ int optee_verify_image(struct optee_header *hdr, unsigned long tzdram_start, if (hdr->magic != OPTEE_MAGIC || hdr->version != OPTEE_VERSION || - hdr->init_load_addr_hi > tzdram_end || - hdr->init_load_addr_lo < tzdram_start || - tee_file_size > tzdram_len || - tee_file_size != image_len || - (hdr->init_load_addr_lo + tee_file_size) > tzdram_end) { + tee_file_size != image_len) { return -EINVAL; } @@ -47,12 +42,9 @@ int optee_verify_bootm_image(unsigned long image_addr, unsigned long image_len) { struct optee_header *hdr = (struct optee_header *)image_addr; - unsigned long tzdram_start = CONFIG_OPTEE_TZDRAM_BASE; - unsigned long tzdram_len = CONFIG_OPTEE_TZDRAM_SIZE; - int ret; - ret = optee_verify_image(hdr, tzdram_start, tzdram_len, image_len); + ret = optee_verify_image(hdr, image_len); if (ret) goto error; @@ -63,13 +55,14 @@ int optee_verify_bootm_image(unsigned long image_addr, return ret; error: - printf(optee_hdr_err_msg, hdr, image_addr, hdr->magic, tzdram_start, - tzdram_start + tzdram_len, hdr->init_load_addr_lo, + printf(optee_hdr_err_msg, hdr, image_addr, hdr->magic, + hdr->init_load_addr_lo, hdr->init_load_addr_hi, image_len, hdr->arch, image_load_addr, image_load_addr + image_len); return ret; } +#endif #if defined(CONFIG_OF_LIBFDT) static int optee_copy_firmware_node(ofnode node, void *fdt_blob) diff --git a/test/py/tests/test_fit_hashes.py b/test/py/tests/test_fit_hashes.py new file mode 100644 index 0000000000..e228ea96d3 --- /dev/null +++ b/test/py/tests/test_fit_hashes.py @@ -0,0 +1,111 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2021 Alexandru Gagniuc + +""" +Check hashes produced by mkimage against known values + +This test checks the correctness of mkimage's hashes. by comparing the mkimage +output of a fixed data block with known good hashes. +This test doesn't run the sandbox. It only checks the host tool 'mkimage' +""" + +import pytest +import u_boot_utils as util + +kernel_hashes = { + "sha512" : "f18c1486a2c29f56360301576cdfce4dfd8e8e932d0ed8e239a1f314b8ae1d77b2a58cd7fe32e4075e69448e623ce53b0b6aa6ce5626d2c189a5beae29a68d93", + "sha384" : "16e28976740048485d08d793d8bf043ebc7826baf2bc15feac72825ad67530ceb3d09e0deb6932c62a5a0e9f3936baf4", + "sha256" : "2955c56bc1e5050c111ba6e089e0f5342bb47dedf77d87e3f429095feb98a7e5", + "sha1" : "652383e1a6d946953e1f65092c9435f6452c2ab7", + "md5" : "4879e5086e4c76128e525b5fe2af55f1", + "crc32" : "32eddfdf", + "crc16-ccitt" : "d4be" +} + +class ReadonlyFitImage(object): + """ Helper to manipulate a FIT image on disk """ + def __init__(self, cons, file_name): + self.fit = file_name + self.cons = cons + self.hashable_nodes = set() + + def __fdt_list(self, path): + return util.run_and_log(self.cons, f'fdtget -l {self.fit} {path}') + + def __fdt_get(self, node, prop): + val = util.run_and_log(self.cons, f'fdtget {self.fit} {node} {prop}') + return val.rstrip('\n') + + def __fdt_get_sexadecimal(self, node, prop): + numbers = util.run_and_log(self.cons, f'fdtget -tbx {self.fit} {node} {prop}') + + sexadecimal = '' + for num in numbers.rstrip('\n').split(' '): + sexadecimal += num.zfill(2) + return sexadecimal + + def find_hashable_image_nodes(self): + for node in self.__fdt_list('/images').split(): + # We only have known hashes for the kernel node + if 'kernel' not in node: + continue + self.hashable_nodes.add(f'/images/{node}') + + return self.hashable_nodes + + def verify_hashes(self): + for image in self.hashable_nodes: + algos = set() + for node in self.__fdt_list(image).split(): + if "hash-" not in node: + continue + + raw_hash = self.__fdt_get_sexadecimal(f'{image}/{node}', 'value') + algo = self.__fdt_get(f'{image}/{node}', 'algo') + algos.add(algo) + + good_hash = kernel_hashes[algo] + if good_hash != raw_hash: + raise ValueError(f'{image} Borked hash: {algo}'); + + # Did we test all the hashes we set out to test? + missing_algos = kernel_hashes.keys() - algos + if (missing_algos): + raise ValueError(f'Missing hashes from FIT: {missing_algos}') + + +@pytest.mark.buildconfigspec('hash') +@pytest.mark.requiredtool('dtc') +@pytest.mark.requiredtool('fdtget') +@pytest.mark.requiredtool('fdtput') +def test_mkimage_hashes(u_boot_console): + """ Test that hashes generated by mkimage are correct. """ + + def assemble_fit_image(dest_fit, its, destdir): + dtc_args = f'-I dts -O dtb -i {destdir}' + util.run_and_log(cons, [mkimage, '-D', dtc_args, '-f', its, dest_fit]) + + def dtc(dts): + dtb = dts.replace('.dts', '.dtb') + util.run_and_log(cons, f'dtc {datadir}/{dts} -O dtb -o {tempdir}/{dtb}') + + cons = u_boot_console + mkimage = cons.config.build_dir + '/tools/mkimage' + datadir = cons.config.source_dir + '/test/py/tests/vboot/' + tempdir = cons.config.result_dir + fit_file = f'{tempdir}/test.fit' + dtc('sandbox-kernel.dts') + + # Create a fake kernel image -- Avoid zeroes or crc16 will be zero + with open(f'{tempdir}/test-kernel.bin', 'w') as fd: + fd.write(500 * chr(0xa5)) + + assemble_fit_image(fit_file, f'{datadir}/hash-images.its', tempdir) + + fit = ReadonlyFitImage(cons, fit_file) + nodes = fit.find_hashable_image_nodes() + if len(nodes) == 0: + raise ValueError('FIT image has no "/image" nodes with "hash-..."') + + fit.verify_hashes() diff --git a/test/py/tests/test_hush_if_test.py b/test/py/tests/test_hush_if_test.py index d117921a6a..37c1608bb2 100644 --- a/test/py/tests/test_hush_if_test.py +++ b/test/py/tests/test_hush_if_test.py @@ -119,11 +119,6 @@ subtests = ( ('test ! ! aaa != aaa -o ! ! bbb = bbb', True), ('test ! ! aaa = aaa -o ! ! bbb != bbb', True), ('test ! ! aaa = aaa -o ! ! bbb = bbb', True), - - # -z operator. - - ('test -z "$ut_var_nonexistent"', True), - ('test -z "$ut_var_exists"', False), ) def exec_hush_if(u_boot_console, expr, result): @@ -141,12 +136,6 @@ def exec_hush_if(u_boot_console, expr, result): response = u_boot_console.run_command(cmd) assert response.strip() == str(result).lower() -def test_hush_if_test_setup(u_boot_console): - """Set up environment variables used during the "if" tests.""" - - u_boot_console.run_command('setenv ut_var_nonexistent') - u_boot_console.run_command('setenv ut_var_exists 1') - @pytest.mark.buildconfigspec('cmd_echo') @pytest.mark.parametrize('expr,result', subtests) def test_hush_if_test(u_boot_console, expr, result): @@ -154,9 +143,12 @@ def test_hush_if_test(u_boot_console, expr, result): exec_hush_if(u_boot_console, expr, result) -def test_hush_if_test_teardown(u_boot_console): - """Clean up environment variables used during the "if" tests.""" - +def test_hush_z(u_boot_console): + """Test the -z operator""" + u_boot_console.run_command('setenv ut_var_nonexistent') + u_boot_console.run_command('setenv ut_var_exists 1') + exec_hush_if(u_boot_console, 'test -z "$ut_var_nonexistent"', True) + exec_hush_if(u_boot_console, 'test -z "$ut_var_exists"', False) u_boot_console.run_command('setenv ut_var_exists') # We might test this on real filesystems via UMS, DFU, 'save', etc. diff --git a/test/py/tests/test_tpm2.py b/test/py/tests/test_tpm2.py index c7a9dc19bd..7c89f5f293 100644 --- a/test/py/tests/test_tpm2.py +++ b/test/py/tests/test_tpm2.py @@ -52,14 +52,17 @@ def force_init(u_boot_console, force=False): u_boot_console.run_command('tpm2 clear TPM2_RH_PLATFORM') u_boot_console.run_command('echo --- end of init ---') +def is_sandbox(cons): + # Array slice removes leading/trailing quotes. + sys_arch = cons.config.buildconfig.get('config_sys_arch', '"sandbox"')[1:-1] + return sys_arch == 'sandbox' + @pytest.mark.buildconfigspec('cmd_tpm_v2') def test_tpm2_init(u_boot_console): """Init the software stack to use TPMv2 commands.""" - skip_test = u_boot_console.config.env.get('env__tpm_device_test_skip', False) if skip_test: pytest.skip('skip TPM device test') - u_boot_console.run_command('tpm2 init') output = u_boot_console.run_command('echo $?') assert output.endswith('0') @@ -70,6 +73,19 @@ def test_tpm2_startup(u_boot_console): Initiate the TPM internal state machine. """ + u_boot_console.run_command('tpm2 startup TPM2_SU_CLEAR') + output = u_boot_console.run_command('echo $?') + assert output.endswith('0') + +def tpm2_sandbox_init(u_boot_console): + """Put sandbox back into a known state so we can run a test + + This allows all tests to run in parallel, since no test depends on another. + """ + u_boot_console.restart_uboot() + u_boot_console.run_command('tpm2 init') + output = u_boot_console.run_command('echo $?') + assert output.endswith('0') skip_test = u_boot_console.config.env.get('env__tpm_device_test_skip', False) if skip_test: @@ -78,12 +94,25 @@ def test_tpm2_startup(u_boot_console): output = u_boot_console.run_command('echo $?') assert output.endswith('0') + u_boot_console.run_command('tpm2 self_test full') + output = u_boot_console.run_command('echo $?') + assert output.endswith('0') + @pytest.mark.buildconfigspec('cmd_tpm_v2') -def test_tpm2_self_test_full(u_boot_console): +def test_tpm2_sandbox_self_test_full(u_boot_console): """Execute a TPM2_SelfTest (full) command. Ask the TPM to perform all self tests to also enable full capabilities. """ + if is_sandbox(u_boot_console): + u_boot_console.restart_uboot() + u_boot_console.run_command('tpm2 init') + output = u_boot_console.run_command('echo $?') + assert output.endswith('0') + + u_boot_console.run_command('tpm2 startup TPM2_SU_CLEAR') + output = u_boot_console.run_command('echo $?') + assert output.endswith('0') skip_test = u_boot_console.config.env.get('env__tpm_device_test_skip', False) if skip_test: @@ -103,6 +132,8 @@ def test_tpm2_continue_self_test(u_boot_console): skip_test = u_boot_console.config.env.get('env__tpm_device_test_skip', False) if skip_test: pytest.skip('skip TPM device test') + if is_sandbox(u_boot_console): + tpm2_sandbox_init(u_boot_console) u_boot_console.run_command('tpm2 self_test continue') output = u_boot_console.run_command('echo $?') assert output.endswith('0') @@ -119,6 +150,8 @@ def test_tpm2_clear(u_boot_console): not have a password set, otherwise this test will fail. ENDORSEMENT and PLATFORM hierarchies are also available. """ + if is_sandbox(u_boot_console): + tpm2_sandbox_init(u_boot_console) skip_test = u_boot_console.config.env.get('env__tpm_device_test_skip', False) if skip_test: @@ -140,7 +173,8 @@ def test_tpm2_change_auth(u_boot_console): Use the LOCKOUT hierarchy for this. ENDORSEMENT and PLATFORM hierarchies are also available. """ - + if is_sandbox(u_boot_console): + tpm2_sandbox_init(u_boot_console) force_init(u_boot_console) u_boot_console.run_command('tpm2 change_auth TPM2_RH_LOCKOUT unicorn') @@ -164,6 +198,8 @@ def test_tpm2_get_capability(u_boot_console): There is no expected default values because it would depend on the chip used. We can still save them in order to check they have changed later. """ + if is_sandbox(u_boot_console): + tpm2_sandbox_init(u_boot_console) force_init(u_boot_console) ram = u_boot_utils.find_ram_base(u_boot_console) @@ -186,7 +222,8 @@ def test_tpm2_dam_parameters(u_boot_console): the authentication, otherwise the lockout will be engaged after the first failed authentication attempt. """ - + if is_sandbox(u_boot_console): + tpm2_sandbox_init(u_boot_console) force_init(u_boot_console) ram = u_boot_utils.find_ram_base(u_boot_console) @@ -209,6 +246,8 @@ def test_tpm2_pcr_read(u_boot_console): Perform a PCR read of the 0th PCR. Must be zero. """ + if is_sandbox(u_boot_console): + tpm2_sandbox_init(u_boot_console) force_init(u_boot_console) ram = u_boot_utils.find_ram_base(u_boot_console) @@ -236,7 +275,8 @@ def test_tpm2_pcr_extend(u_boot_console): No authentication mechanism is used here, not protecting against packet replay, yet. """ - + if is_sandbox(u_boot_console): + tpm2_sandbox_init(u_boot_console) force_init(u_boot_console) ram = u_boot_utils.find_ram_base(u_boot_console) diff --git a/test/py/tests/test_vboot.py b/test/py/tests/test_vboot.py index 6dff6779d1..095e00cce3 100644 --- a/test/py/tests/test_vboot.py +++ b/test/py/tests/test_vboot.py @@ -24,6 +24,7 @@ For configuration verification: Tests run with both SHA1 and SHA256 hashing. """ +import os import shutil import struct import pytest @@ -34,16 +35,16 @@ import vboot_evil # Only run the full suite on a few combinations, since it doesn't add any more # test coverage. TESTDATA = [ - ['sha1', '', None, False, True], - ['sha1', '', '-E -p 0x10000', False, False], - ['sha1', '-pss', None, False, False], - ['sha1', '-pss', '-E -p 0x10000', False, False], - ['sha256', '', None, False, False], - ['sha256', '', '-E -p 0x10000', False, False], - ['sha256', '-pss', None, False, False], - ['sha256', '-pss', '-E -p 0x10000', False, False], - ['sha256', '-pss', None, True, False], - ['sha256', '-pss', '-E -p 0x10000', True, True], + ['sha1-basic', 'sha1', '', None, False, True], + ['sha1-pad', 'sha1', '', '-E -p 0x10000', False, False], + ['sha1-pss', 'sha1', '-pss', None, False, False], + ['sha1-pss-pad', 'sha1', '-pss', '-E -p 0x10000', False, False], + ['sha256-basic', 'sha256', '', None, False, False], + ['sha256-pad', 'sha256', '', '-E -p 0x10000', False, False], + ['sha256-pss', 'sha256', '-pss', None, False, False], + ['sha256-pss-pad', 'sha256', '-pss', '-E -p 0x10000', False, False], + ['sha256-pss-required', 'sha256', '-pss', None, True, False], + ['sha256-pss-pad-required', 'sha256', '-pss', '-E -p 0x10000', True, True], ] @pytest.mark.boardspec('sandbox') @@ -52,9 +53,9 @@ TESTDATA = [ @pytest.mark.requiredtool('fdtget') @pytest.mark.requiredtool('fdtput') @pytest.mark.requiredtool('openssl') -@pytest.mark.parametrize("sha_algo,padding,sign_options,required,full_test", +@pytest.mark.parametrize("name,sha_algo,padding,sign_options,required,full_test", TESTDATA) -def test_vboot(u_boot_console, sha_algo, padding, sign_options, required, +def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, full_test): """Test verified boot signing with mkimage and verification with 'bootm'. @@ -365,7 +366,9 @@ def test_vboot(u_boot_console, sha_algo, padding, sign_options, required, run_bootm(sha_algo, 'multi required key', '', False) cons = u_boot_console - tmpdir = cons.config.result_dir + '/' + tmpdir = os.path.join(cons.config.result_dir, name) + '/' + if not os.path.exists(tmpdir): + os.mkdir(tmpdir) datadir = cons.config.source_dir + '/test/py/tests/vboot/' fit = '%stest.fit' % tmpdir mkimage = cons.config.build_dir + '/tools/mkimage' diff --git a/test/py/tests/vboot/hash-images.its b/test/py/tests/vboot/hash-images.its new file mode 100644 index 0000000000..3ff797288c --- /dev/null +++ b/test/py/tests/vboot/hash-images.its @@ -0,0 +1,76 @@ +/dts-v1/; + +/ { + description = "Chrome OS kernel image with one or more FDT blobs"; + #address-cells = <1>; + + images { + kernel { + data = /incbin/("test-kernel.bin"); + type = "kernel_noload"; + arch = "sandbox"; + os = "linux"; + compression = "none"; + load = <0x4>; + entry = <0x8>; + kernel-version = <1>; + hash-0 { + algo = "crc16-ccitt"; + }; + hash-1 { + algo = "crc32"; + }; + hash-2 { + algo = "md5"; + }; + hash-3 { + algo = "sha1"; + }; + hash-4 { + algo = "sha256"; + }; + hash-5 { + algo = "sha384"; + }; + hash-6 { + algo = "sha512"; + }; + }; + fdt-1 { + description = "snow"; + data = /incbin/("sandbox-kernel.dtb"); + type = "flat_dt"; + arch = "sandbox"; + compression = "none"; + fdt-version = <1>; + hash-0 { + algo = "crc16-ccitt"; + }; + hash-1 { + algo = "crc32"; + }; + hash-2 { + algo = "md5"; + }; + hash-3 { + algo = "sha1"; + }; + hash-4 { + algo = "sha256"; + }; + hash-5 { + algo = "sha384"; + }; + hash-6 { + algo = "sha512"; + }; + }; + }; + configurations { + default = "conf-1"; + conf-1 { + kernel = "kernel"; + fdt = "fdt-1"; + }; + }; +};