Merge branch '2021-10-05-general-updates'

- Assorted OPTEE cleanups
- pinctrl, gpio improvements, assorted livetree migrations
- Assorted pytest improvements
This commit is contained in:
Tom Rini 2021-10-05 17:16:23 -04:00
commit 7240e1b8f9
31 changed files with 475 additions and 172 deletions

View File

@ -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

View File

@ -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 +

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -10,15 +10,11 @@
#include <dm.h>
#include <dm-demo.h>
#include <errno.h>
#include <fdtdec.h>
#include <log.h>
#include <malloc.h>
#include <asm/global_data.h>
#include <asm/io.h>
#include <linux/list.h>
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;

View File

@ -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;
}

View File

@ -8,6 +8,7 @@
#include <dm.h>
#include <dm/device_compat.h>
#include <dm/devres.h>
#include <dm/of_access.h>
#include <dm/pinctrl.h>
#include <linux/libfdt.h>
#include <linux/list.h>
@ -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[] = {

View File

@ -10,8 +10,6 @@
#include <exports.h>
#include <reboot-mode/reboot-mode.h>
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);

View File

@ -9,19 +9,15 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <common.h>
#include <errno.h>
#include <fdtdec.h>
#include <log.h>
#include <malloc.h>
#include <remoteproc.h>
#include <asm/global_data.h>
#include <asm/io.h>
#include <dm/device-internal.h>
#include <dm.h>
#include <dm/uclass.h>
#include <dm/uclass-internal.h>
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

View File

@ -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
*

View File

@ -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" \

View File

@ -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

View File

@ -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)

View File

@ -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/

View File

@ -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.

View File

@ -2,4 +2,4 @@
#
# (C) Copyright 2017 Linaro
obj-$(CONFIG_OPTEE) += optee.o
obj-y += optee.o

View File

@ -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)

View File

@ -0,0 +1,111 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (c) 2021 Alexandru Gagniuc <mr.nuke.me@gmail.com>
"""
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()

View File

@ -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.

View File

@ -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)

View File

@ -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'

View File

@ -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";
};
};
};