summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/Kconfig61
-rw-r--r--common/Makefile2
-rw-r--r--common/bbu.c4
-rw-r--r--common/globalvar.c19
-rw-r--r--common/imd-barebox.c1
-rw-r--r--common/imd.c158
-rw-r--r--common/optee.c23
-rw-r--r--common/state/state.h4
-rw-r--r--common/state/state_variables.c23
9 files changed, 244 insertions, 51 deletions
diff --git a/common/Kconfig b/common/Kconfig
index f9ef9bd83b..02ef3631e0 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -69,9 +69,6 @@ config LOGBUF
config STDDEV
bool
-config BAREBOX_UPDATE
- bool
-
config MENUTREE
bool
select GLOB
@@ -643,27 +640,6 @@ config BOOTM_FORCE_SIGNED_IMAGES
are refused to boot. Effectively this means only FIT images can be booted
since they are the only supported image type that support signing.
-config BOOTM_OPTEE
- bool
- prompt "support booting OP-TEE"
- depends on BOOTM && ARM
- help
- OP-TEE is a trusted execution environment (TEE). With this option
- enabled barebox supports starting optee_os as part of the bootm command.
- Instead of the kernel bootm starts the optee_os binary which then starts
- the kernel in nonsecure mode. Pass the optee_os binary with the -t option
- or in the global.bootm.tee variable.
-
-config BOOTM_OPTEE_SIZE
- hex
- default 0x02000000
- prompt "OP-TEE Memory Size"
- depends on BOOTM_OPTEE
- help
- Size to reserve in main memory for OP-TEE.
- Can be smaller than the actual size used by OP-TEE, this is used to prevent
- barebox from allocating memory in this area.
-
config BLSPEC
depends on FLEXIBLE_BOOTARGS
depends on !SHELL_NONE
@@ -692,7 +668,11 @@ config FLEXIBLE_BOOTARGS
to replace parts of the bootargs string without reconstructing it
completely.
+config BAREBOX_UPDATE
+ bool "In-system barebox update infrastructure"
+
config IMD
+ select CRC32
bool "barebox metadata support"
config IMD_TARGET
@@ -1000,6 +980,39 @@ config MACHINE_ID
Note: if no hashable information is available no machine id will be passed
to the kernel.
+menu "OP-TEE loading"
+
+config OPTEE_SIZE
+ hex
+ default 0x02000000
+ prompt "OP-TEE Memory Size"
+ depends on BOOTM_OPTEE || PBL_OPTEE
+ help
+ Size to reserve in main memory for OP-TEE.
+ Can be smaller than the actual size used by OP-TEE, this is used to prevent
+ barebox from allocating memory in this area.
+
+config BOOTM_OPTEE
+ bool
+ prompt "support booting OP-TEE"
+ depends on BOOTM && ARM
+ help
+ OP-TEE is a trusted execution environment (TEE). With this option
+ enabled barebox supports starting optee_os as part of the bootm command.
+ Instead of the kernel bootm starts the optee_os binary which then starts
+ the kernel in nonsecure mode. Pass the optee_os binary with the -t option
+ or in the global.bootm.tee variable.
+
+config PBL_OPTEE
+ bool "Enable OP-TEE early start"
+ depends on ARM
+ depends on !THUMB2_BAREBOX
+ help
+ Allows starting OP-TEE during lowlevel initialization of the PBL.
+ Requires explicit support in the boards lowlevel file.
+
+endmenu
+
endmenu
menu "Debugging"
diff --git a/common/Makefile b/common/Makefile
index 11c91dd016..84463b4d48 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -67,6 +67,8 @@ obj-$(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) += imx-bbu-nand-fcb.o
obj-$(CONFIG_BOOT) += boot.o
obj-$(CONFIG_SERIAL_DEV_BUS) += serdev.o
obj-$(CONFIG_USBGADGET_START) += usbgadget.o
+pbl-$(CONFIG_PBL_OPTEE) += optee.o
+obj-$(CONFIG_BOOTM_OPTEE) += optee.o
ifdef CONFIG_PASSWORD
diff --git a/common/bbu.c b/common/bbu.c
index 00bec32a86..b976b99d7c 100644
--- a/common/bbu.c
+++ b/common/bbu.c
@@ -206,6 +206,10 @@ static int bbu_check_metadata(struct bbu_data *data)
if (ret)
return ret;
+ ret = imd_verify_crc32((void *)data->image, data->len);
+ if (ret == -EILSEQ && !(data->flags & BBU_FLAG_FORCE))
+ return ret;
+
return 0;
}
diff --git a/common/globalvar.c b/common/globalvar.c
index a826e1bc12..c87f2c9339 100644
--- a/common/globalvar.c
+++ b/common/globalvar.c
@@ -175,21 +175,24 @@ static int nvvar_device_dispatch(const char *name, struct device_d **dev,
return 1;
}
-static int nv_set(struct device_d *dev, struct param_d *p, const char *val)
+static int nv_set(struct device_d *dev, struct param_d *p, const char *name, const char *val)
{
int ret;
if (!val) {
- free(p->value);
+ if (p)
+ free(p->value);
return 0;
}
- ret = dev_set_param(&global_device, p->name, val);
+ ret = dev_set_param(&global_device, name, val);
if (ret)
return ret;
- free(p->value);
- p->value = xstrdup(val);
+ if (p) {
+ free(p->value);
+ p->value = xstrdup(val);
+ }
return 0;
}
@@ -203,7 +206,7 @@ static int nv_param_set(struct device_d *dev, struct param_d *p, const char *val
{
int ret;
- ret = nv_set(dev, p, val);
+ ret = nv_set(dev, p, p->name, val);
if (ret)
return ret;
@@ -234,7 +237,7 @@ static int __nvvar_add(const char *name, const char *value)
return ret;
if (value)
- return nv_set(&nv_device, p, value);
+ return nv_set(&nv_device, p, name, value);
ret = nvvar_device_dispatch(name, &dev, &pname);
if (ret > 0)
@@ -242,7 +245,7 @@ static int __nvvar_add(const char *name, const char *value)
else
value = dev_get_param(&global_device, name);
- if (value) {
+ if (value && p) {
free(p->value);
p->value = xstrdup(value);
}
diff --git a/common/imd-barebox.c b/common/imd-barebox.c
index e9cd37d83e..e5cdfd1aed 100644
--- a/common/imd-barebox.c
+++ b/common/imd-barebox.c
@@ -23,3 +23,4 @@ __BAREBOX_IMD_SECTION(.barebox_imd_end) = {
BAREBOX_IMD_TAG_STRING(imd_build_tag, IMD_TYPE_BUILD, UTS_VERSION, 1);
BAREBOX_IMD_TAG_STRING(imd_release_tag, IMD_TYPE_RELEASE, UTS_RELEASE, 1);
+BAREBOX_IMD_CRC(imd_crc32, 0x0, 1);
diff --git a/common/imd.c b/common/imd.c
index 913a01de87..9be07fef74 100644
--- a/common/imd.c
+++ b/common/imd.c
@@ -22,6 +22,7 @@
#include <getopt.h>
#include <malloc.h>
#include <fs.h>
+#include <crc.h>
#ifndef CONFIG_CMD_IMD
int imd_command_setenv(const char *variable_name, const char *value)
@@ -41,7 +42,7 @@ const struct imd_header *imd_next(const struct imd_header *imd)
length = imd_read_length(imd);
length = ALIGN(length, 4);
- length += 8;
+ length += sizeof(struct imd_header);
return (const void *)imd + length;
}
@@ -63,14 +64,14 @@ static int imd_next_validate(const void *buf, int bufsize, int start_ofs)
size = bufsize - start_ofs;
- if (size < 8) {
+ if (size < sizeof(struct imd_header)) {
debug("trunkated tag at offset %dd\n", start_ofs);
return -EINVAL;
}
length = imd_read_length(imd);
length = ALIGN(length, 4);
- length += 8;
+ length += sizeof(struct imd_header);
if (size < length) {
debug("tag at offset %d with size %d exceeds bufsize %d\n",
@@ -167,6 +168,9 @@ static struct imd_type_names imd_types[] = {
}, {
.type = IMD_TYPE_OF_COMPATIBLE,
.name = "of_compatible",
+ }, {
+ .type = IMD_TYPE_CRC32,
+ .name = "crc32",
},
};
@@ -257,6 +261,23 @@ char *imd_concat_strings(const struct imd_header *imd)
}
/**
+ * imd_uint32_flags - get uint32 flags
+ * @imd: The IMD entry
+ *
+ * This function returns the flags in @imd.
+ *
+ * Return: A pointer to the flags or NULL if the entry is not uint32.
+ */
+static uint32_t *imd_crc32_flags(const struct imd_header *imd) {
+ char *p = (char *)(imd + 1);
+
+ if (!imd_is_crc32(imd_read_type(imd)))
+ return NULL;
+
+ return (uint32_t *)(p + sizeof(uint32_t));
+}
+
+/**
* imd_get_param - get a parameter
* @imd: The IMD entry
* @name: The name of the parameter.
@@ -287,6 +308,118 @@ const char *imd_get_param(const struct imd_header *imd, const char *name)
return NULL;
}
+static int imd_calculate_crc32(void *input, const struct imd_header *imd_start,
+ struct imd_header **imd_crc, uint32_t *crc,
+ size_t size)
+{
+ const struct imd_header *imd;
+ int length;
+ int end_ofs = (char *)imd_start - (char *)input + sizeof(char) * 8;
+
+ /* search the checksum imd token */
+ imd_for_each(imd_start, imd) {
+ length = imd_read_length(imd);
+ length = ALIGN(length, 4);
+ length += sizeof(struct imd_header);
+
+ if (imd_read_type(imd) == IMD_TYPE_CRC32) {
+ *imd_crc = (struct imd_header *)imd;
+ debug("Found crc token at %d\n", end_ofs);
+ break;
+ }
+
+ end_ofs += length;
+ }
+
+ /*
+ * Calculate checksum from start of input up to the checksum.
+ * The checksum and the flags field in the imd_entry_crc32 entry are
+ * modified after the checksum is calculated. Therefore skip them here
+ * or the checksum will become invalid once it is written to the
+ * checksum tag.
+ */
+ length = sizeof(struct imd_header);
+ end_ofs += length;
+
+ *crc = crc32(*crc, input, end_ofs);
+ debug("Calculated checksum from %d to %d: 0x%08x\n", 0, end_ofs, *crc);
+
+ /* move past the checksum data and flags field */
+ end_ofs += sizeof(uint32_t) + sizeof(char);
+ input += end_ofs;
+
+ *crc = crc32(*crc, input, size - end_ofs);
+ debug("Calculated checksum from %d to %d: 0x%08x\n", end_ofs,
+ end_ofs + (size - end_ofs), *crc);
+
+ return 0;
+}
+
+static int imd_write_crc32(void *buf, const struct imd_header *imd_start,
+ const char *filename, size_t size)
+{
+ struct imd_header *imd_crc;
+ uint32_t crc = 0;
+
+ imd_calculate_crc32(buf, imd_start, &imd_crc, &crc, size);
+ debug("Calculated crc: 0x%08x\n", crc);
+
+ if (!imd_crc) {
+ debug("No tag of type 0x%08x found\n", IMD_TYPE_CRC32);
+
+ return -ENODATA;
+ } else {
+ uint32_t *p = (uint32_t *)(imd_crc + 1);
+
+ if (*p != crc) {
+ uint32_t *flags = imd_crc32_flags(imd_crc);
+ *flags |= IMD_CRC32_FLAG_TAG_VALID;
+ debug("Update crc token from 0x%08x to 0x%08x (flags 0x%08x)\n", *p, crc, *flags);
+ *p = crc;
+
+ write_file(filename, buf, size);
+ }
+ }
+
+ return 0;
+};
+
+int imd_verify_crc32(void *buf, size_t size)
+{
+ const struct imd_header *imd_start;
+ struct imd_header *imd_crc;
+ uint32_t crc = 0;
+
+ imd_start = imd_get(buf, size);
+ if (IS_ERR(imd_start))
+ return PTR_ERR(imd_start);
+
+ imd_calculate_crc32(buf, imd_start, &imd_crc, &crc, size);
+ debug("Calculated crc: 0x%08x\n", crc);
+
+ if (!imd_crc) {
+ debug("No tag of type 0x%08x found\n", IMD_TYPE_CRC32);
+
+ return -ENOENT;
+ } else {
+ uint32_t *p = (uint32_t *)(imd_crc + 1);
+ uint32_t *flags = imd_crc32_flags(imd_crc);
+
+ if (*p != crc && imd_crc32_is_valid(*flags)) {
+ eprintf("CRC: image corrupted. Found checksum 0x%08x instead of 0x%08x\n",
+ *p, crc);
+ return -EILSEQ;
+ } else if (*p != crc && !imd_crc32_is_valid(*flags)) {
+ printf("CRC: is invalid, but the checksum tag is not enabled\n");
+ return -EINVAL;
+ } else {
+ printf("CRC: valid\n");
+ }
+ }
+
+ return 0;
+};
+
int imd_command_verbose;
int imd_command(int argc, char *argv[])
@@ -299,10 +432,12 @@ int imd_command(int argc, char *argv[])
const char *filename;
const char *variable_name = NULL;
char *str;
+ uint32_t checksum = 0;
+ uint32_t verify = 0;
imd_command_verbose = 0;
- while ((opt = getopt(argc, argv, "vt:s:n:")) > 0) {
+ while ((opt = getopt(argc, argv, "vt:s:n:cV")) > 0) {
switch(opt) {
case 't':
type = imd_name_to_type(optarg);
@@ -320,6 +455,12 @@ int imd_command(int argc, char *argv[])
case 'n':
strno = simple_strtoul(optarg, NULL, 0);
break;
+ case 'c':
+ checksum = 1;
+ break;
+ case 'V':
+ verify = 1;
+ break;
default:
return -ENOSYS;
}
@@ -342,6 +483,11 @@ int imd_command(int argc, char *argv[])
goto out;
}
+ if (checksum)
+ imd_write_crc32(buf, imd_start, filename, size);
+ if (verify)
+ imd_verify_crc32(buf, size);
+
if (type == IMD_TYPE_INVALID) {
imd_for_each(imd_start, imd) {
uint32_t type = imd_read_type(imd);
@@ -350,6 +496,10 @@ int imd_command(int argc, char *argv[])
str = imd_concat_strings(imd);
printf("%s: %s\n", imd_type_to_name(type), str);
+ } else if (imd_is_crc32(type)) {
+ uint32_t *p = (uint32_t *)(imd + 1);
+
+ printf("%s: 0x%08x\n", imd_type_to_name(type), *p);
} else {
debug("Unknown tag 0x%08x\n", type);
}
diff --git a/common/optee.c b/common/optee.c
new file mode 100644
index 0000000000..d542dde118
--- /dev/null
+++ b/common/optee.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define pr_fmt(fmt) "optee: " fmt
+
+#include <tee/optee.h>
+#include <printk.h>
+#include <asm-generic/errno.h>
+
+int optee_verify_header(struct optee_header *hdr)
+{
+ if (hdr->magic != OPTEE_MAGIC) {
+ pr_err("Invalid header magic 0x%08x, expected 0x%08x\n",
+ hdr->magic, OPTEE_MAGIC);
+ return -EINVAL;
+ }
+
+ if (hdr->arch != OPTEE_ARCH_ARM32 || hdr->init_load_addr_hi) {
+ pr_err("Only 32bit supported\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/common/state/state.h b/common/state/state.h
index 912d6d4848..1881d92ea7 100644
--- a/common/state/state.h
+++ b/common/state/state.h
@@ -159,7 +159,6 @@ struct state_variable {
*/
struct state_uint32 {
struct state_variable var;
- struct param_d *param;
uint32_t value;
uint32_t value_default;
};
@@ -169,7 +168,6 @@ struct state_uint32 {
*/
struct state_enum32 {
struct state_variable var;
- struct param_d *param;
uint32_t value;
uint32_t value_default;
const char **names;
@@ -181,7 +179,6 @@ struct state_enum32 {
*/
struct state_mac {
struct state_variable var;
- struct param_d *param;
uint8_t value[6];
uint8_t value_default[6];
};
@@ -191,7 +188,6 @@ struct state_mac {
*/
struct state_string {
struct state_variable var;
- struct param_d *param;
char *value;
const char *value_default;
char raw[];
diff --git a/common/state/state_variables.c b/common/state/state_variables.c
index 6a00c82203..66c66f38bd 100644
--- a/common/state/state_variables.c
+++ b/common/state/state_variables.c
@@ -116,7 +116,6 @@ static struct state_variable *state_uint8_create(struct state *state,
return ERR_CAST(param);
}
- su32->param = param;
su32->var.type = vtype;
su32->var.size = sizeof(uint8_t);
#ifdef __LITTLE_ENDIAN
@@ -146,7 +145,6 @@ static struct state_variable *state_uint32_create(struct state *state,
return ERR_CAST(param);
}
- su32->param = param;
su32->var.type = vtype;
su32->var.size = sizeof(uint32_t);
su32->var.raw = &su32->value;
@@ -226,6 +224,7 @@ static struct state_variable *state_enum32_create(struct state *state,
const struct variable_type *vtype)
{
struct state_enum32 *enum32;
+ struct param_d *param;
int ret, i, num_names;
enum32 = xzalloc(sizeof(*enum32));
@@ -253,11 +252,11 @@ static struct state_variable *state_enum32_create(struct state *state,
enum32->names[i] = xstrdup(name);
}
- enum32->param = dev_add_param_enum(&state->dev, name, state_set_dirty,
+ param = dev_add_param_enum(&state->dev, name, state_set_dirty,
NULL, &enum32->value, enum32->names,
num_names, &enum32->var);
- if (IS_ERR(enum32->param)) {
- ret = PTR_ERR(enum32->param);
+ if (IS_ERR(param)) {
+ ret = PTR_ERR(param);
goto out;
}
@@ -310,6 +309,7 @@ static struct state_variable *state_mac_create(struct state *state,
const struct variable_type *vtype)
{
struct state_mac *mac;
+ struct param_d *param;
int ret;
mac = xzalloc(sizeof(*mac));
@@ -319,10 +319,10 @@ static struct state_variable *state_mac_create(struct state *state,
mac->var.raw = mac->value;
mac->var.state = state;
- mac->param = dev_add_param_mac(&state->dev, name, state_set_dirty,
+ param = dev_add_param_mac(&state->dev, name, state_set_dirty,
NULL, mac->value, &mac->var);
- if (IS_ERR(mac->param)) {
- ret = PTR_ERR(mac->param);
+ if (IS_ERR(param)) {
+ ret = PTR_ERR(param);
goto out;
}
@@ -413,6 +413,7 @@ static struct state_variable *state_string_create(struct state *state,
{
struct state_string *string;
uint32_t start_size[2];
+ struct param_d *param;
int ret;
ret = of_property_read_u32_array(node, "reg", start_size,
@@ -432,11 +433,11 @@ static struct state_variable *state_string_create(struct state *state,
string->var.raw = &string->raw;
string->var.state = state;
- string->param = dev_add_param_string(&state->dev, name,
+ param = dev_add_param_string(&state->dev, name,
state_string_set, state_string_get,
&string->value, &string->var);
- if (IS_ERR(string->param)) {
- ret = PTR_ERR(string->param);
+ if (IS_ERR(param)) {
+ ret = PTR_ERR(param);
goto out;
}