summaryrefslogtreecommitdiffstats
path: root/common/state
diff options
context:
space:
mode:
Diffstat (limited to 'common/state')
-rw-r--r--common/state/Makefile2
-rw-r--r--common/state/backend_bucket_circular.c4
-rw-r--r--common/state/backend_bucket_direct.c28
-rw-r--r--common/state/backend_format_dtb.c6
-rw-r--r--common/state/backend_format_raw.c17
-rw-r--r--common/state/backend_storage.c28
-rw-r--r--common/state/state.c96
-rw-r--r--common/state/state.h32
-rw-r--r--common/state/state_variables.c13
9 files changed, 159 insertions, 67 deletions
diff --git a/common/state/Makefile b/common/state/Makefile
index fcf9add52c..93215dd069 100644
--- a/common/state/Makefile
+++ b/common/state/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
obj-y += state.o
obj-y += state_variables.o
obj-y += backend_format_dtb.o
diff --git a/common/state/backend_bucket_circular.c b/common/state/backend_bucket_circular.c
index 735510e0d3..2ac5bf6a82 100644
--- a/common/state/backend_bucket_circular.c
+++ b/common/state/backend_bucket_circular.c
@@ -62,7 +62,7 @@ struct state_backend_storage_bucket_circular {
#endif
/* For outputs */
- struct device_d *dev;
+ struct device *dev;
};
/*
@@ -456,7 +456,7 @@ static int bucket_circular_is_block_bad(struct state_backend_storage_bucket_circ
}
#endif
-int state_backend_bucket_circular_create(struct device_d *dev, const char *path,
+int state_backend_bucket_circular_create(struct device *dev, const char *path,
struct state_backend_storage_bucket **bucket,
unsigned int eraseblock,
ssize_t writesize,
diff --git a/common/state/backend_bucket_direct.c b/common/state/backend_bucket_direct.c
index 4522f0170f..03c752d6fe 100644
--- a/common/state/backend_bucket_direct.c
+++ b/common/state/backend_bucket_direct.c
@@ -17,7 +17,7 @@
#include <libfile.h>
#include <linux/kernel.h>
#include <malloc.h>
-#include <printk.h>
+#include <linux/printk.h>
#include "state.h"
@@ -29,7 +29,7 @@ struct state_backend_storage_bucket_direct {
int fd;
- struct device_d *dev;
+ struct device *dev;
};
struct __attribute__((__packed__)) state_backend_storage_bucket_direct_meta {
@@ -52,7 +52,7 @@ static int state_backend_bucket_direct_read(struct state_backend_storage_bucket
struct state_backend_storage_bucket_direct *direct =
get_bucket_direct(bucket);
struct state_backend_storage_bucket_direct_meta meta;
- uint32_t read_len;
+ uint32_t read_len, header_len = 0;
void *buf;
int ret;
@@ -72,13 +72,15 @@ static int state_backend_bucket_direct_read(struct state_backend_storage_bucket
return -EINVAL;
}
+
+ header_len = sizeof(meta);
} else {
if (meta.magic != ~0 && !!meta.magic)
bucket->wrong_magic = 1;
if (!IS_ENABLED(CONFIG_STATE_BACKWARD_COMPATIBLE)) {
- dev_err(direct->dev, "No meta data header found\n");
dev_dbg(direct->dev, "Enable backward compatibility or increase stride size\n");
- return -EINVAL;
+ return dev_err_state_init(direct->dev, meta.magic ? -EINVAL : -ENOMEDIUM,
+ "No meta data header found\n");
}
read_len = direct->max_size;
if (lseek(direct->fd, direct->offset, SEEK_SET) !=
@@ -87,12 +89,16 @@ static int state_backend_bucket_direct_read(struct state_backend_storage_bucket
-errno);
return -errno;
}
+
}
buf = xmalloc(read_len);
if (!buf)
return -ENOMEM;
+ dev_dbg(direct->dev, "Read state from %lld length %d\n", (long long) direct->offset,
+ header_len + read_len);
+
ret = read_full(direct->fd, buf, read_len);
if (ret < 0) {
dev_err(direct->dev, "Failed to read from file, %d\n", ret);
@@ -112,6 +118,7 @@ static int state_backend_bucket_direct_write(struct state_backend_storage_bucket
{
struct state_backend_storage_bucket_direct *direct =
get_bucket_direct(bucket);
+ size_t header_len = 0;
int ret;
struct state_backend_storage_bucket_direct_meta meta;
@@ -129,6 +136,8 @@ static int state_backend_bucket_direct_write(struct state_backend_storage_bucket
dev_err(direct->dev, "Failed to write metadata to file, %d\n", ret);
return ret;
}
+
+ header_len = sizeof(meta);
} else {
if (!IS_ENABLED(CONFIG_STATE_BACKWARD_COMPATIBLE)) {
dev_dbg(direct->dev, "Too small stride size: must skip metadata! Increase stride size\n");
@@ -148,6 +157,9 @@ static int state_backend_bucket_direct_write(struct state_backend_storage_bucket
return ret;
}
+ dev_dbg(direct->dev, "Written state to offset %lld length %zu data length %zu\n",
+ (long long)direct->offset, len + header_len, len);
+
return 0;
}
@@ -162,14 +174,14 @@ static void state_backend_bucket_direct_free(struct
free(direct);
}
-int state_backend_bucket_direct_create(struct device_d *dev, const char *path,
+int state_backend_bucket_direct_create(struct device *dev, const char *path,
struct state_backend_storage_bucket **bucket,
- off_t offset, ssize_t max_size)
+ off_t offset, ssize_t max_size, bool readonly)
{
int fd;
struct state_backend_storage_bucket_direct *direct;
- fd = open(path, O_RDWR);
+ fd = open(path, readonly ? O_RDONLY : O_RDWR);
if (fd < 0) {
dev_err(dev, "Failed to open file '%s', %d\n", path, -errno);
return -errno;
diff --git a/common/state/backend_format_dtb.c b/common/state/backend_format_dtb.c
index 48f30db1f5..b41b896aac 100644
--- a/common/state/backend_format_dtb.c
+++ b/common/state/backend_format_dtb.c
@@ -28,7 +28,7 @@ struct state_backend_format_dtb {
struct device_node *root;
/* For outputs */
- struct device_d *dev;
+ struct device *dev;
};
static inline struct state_backend_format_dtb *get_format_dtb(struct
@@ -59,7 +59,7 @@ static int state_backend_format_dtb_verify(struct state_backend_format *format,
fdtb->root = NULL;
}
- root = of_unflatten_dtb(buf);
+ root = of_unflatten_dtb(buf, dtb_len);
if (IS_ERR(root)) {
dev_err(fdtb->dev, "Failed to unflatten dtb from buffer with length %zd, %ld\n",
len, PTR_ERR(root));
@@ -131,7 +131,7 @@ static void state_backend_format_dtb_free(struct state_backend_format *format)
}
int backend_format_dtb_create(struct state_backend_format **format,
- struct device_d *dev)
+ struct device *dev)
{
struct state_backend_format_dtb *dtb;
diff --git a/common/state/backend_format_raw.c b/common/state/backend_format_raw.c
index 5a71149d34..105f7dd444 100644
--- a/common/state/backend_format_raw.c
+++ b/common/state/backend_format_raw.c
@@ -16,14 +16,12 @@
*/
#include <common.h>
-#include <common.h>
#include <crypto/keystore.h>
#include <digest.h>
#include <linux/kernel.h>
#include <malloc.h>
#include <crc.h>
#include <of.h>
-#include <crc.h>
#include "state.h"
@@ -34,7 +32,7 @@ struct state_backend_format_raw {
unsigned int digest_length;
/* For outputs */
- struct device_d *dev;
+ struct device *dev;
char *secret_name;
int needs_secret;
@@ -115,11 +113,10 @@ static int backend_format_raw_verify(struct state_backend_format *format,
header = (struct backend_raw_header *)buf;
crc = crc32(0, header, sizeof(*header) - sizeof(uint32_t));
- if (crc != header->header_crc) {
- dev_err(backend_raw->dev, "Error, invalid header crc in raw format, calculated 0x%08x, found 0x%08x\n",
+ if (crc != header->header_crc)
+ return dev_err_state_init(backend_raw->dev, header->header_crc ? -EINVAL : -ENOMEDIUM,
+ "header crc in raw format, calculated 0x%08x, found 0x%08x\n",
crc, header->header_crc);
- return -EINVAL;
- }
if (magic && magic != header->magic) {
dev_err(backend_raw->dev, "Error, invalid magic in raw format 0x%08x, should be 0x%08x\n",
@@ -183,6 +180,7 @@ static int backend_format_raw_unpack(struct state_backend_format *format,
const struct backend_raw_header *header;
const void *data;
struct state_backend_format_raw *backend_raw = get_format_raw(format);
+ int ret = 0;
header = (const struct backend_raw_header *)buf;
data = buf + sizeof(*header);
@@ -191,12 +189,13 @@ static int backend_format_raw_unpack(struct state_backend_format *format,
if (sv->start + sv->size > header->data_len) {
dev_err(backend_raw->dev, "State variable ends behind valid data, %s\n",
sv->name);
+ ret = -ENOSPC;
continue;
}
memcpy(sv->raw, data + sv->start, sv->size);
}
- return 0;
+ return ret;
}
static int backend_format_raw_pack(struct state_backend_format *format,
@@ -300,7 +299,7 @@ static int backend_format_raw_init_digest(struct state_backend_format_raw *raw,
int backend_format_raw_create(struct state_backend_format **format,
struct device_node *node, const char *secret_name,
- struct device_d *dev)
+ struct device *dev)
{
struct state_backend_format_raw *raw;
int ret;
diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c
index fe7e89e8fb..df81902bf7 100644
--- a/common/state/backend_storage.c
+++ b/common/state/backend_storage.c
@@ -21,7 +21,7 @@
#include <linux/mtd/mtd-abi.h>
#include <sys/stat.h>
#include <malloc.h>
-#include <printk.h>
+#include <linux/printk.h>
#include "state.h"
@@ -144,6 +144,7 @@ int state_storage_read(struct state_backend_storage *storage,
enum state_flags flags)
{
struct state_backend_storage_bucket *bucket, *bucket_used = NULL;
+ int zerobuckets = 0, totalbuckets = 0;
int ret;
dev_dbg(storage->dev, "Checking redundant buckets...\n");
@@ -152,30 +153,35 @@ int state_storage_read(struct state_backend_storage *storage,
* one we want to use.
*/
list_for_each_entry(bucket, &storage->buckets, bucket_list) {
+ totalbuckets++;
+
ret = bucket->read(bucket, &bucket->buf, &bucket->len);
- if (ret == -EUCLEAN)
+ if (ret == -EUCLEAN) {
bucket->needs_refresh = 1;
- else if (ret)
+ } else if (ret) {
+ if (ret == -ENOMEDIUM)
+ zerobuckets++;
continue;
+ }
/*
* Verify the buffer crcs. The buffer length is passed in the len argument,
* .verify overwrites it with the length actually used.
*/
ret = format->verify(format, magic, bucket->buf, &bucket->len, flags);
- if (!ret && !bucket_used)
+ if (ret == -ENOMEDIUM)
+ zerobuckets++;
+ else if (!ret && !bucket_used)
bucket_used = bucket;
- if (ret)
+ else if (ret)
dev_info(storage->dev, "Ignoring broken bucket %d@0x%08llx...\n", bucket->num, (long long) bucket->offset);
}
dev_dbg(storage->dev, "Checking redundant buckets finished.\n");
- if (!bucket_used) {
- dev_err(storage->dev, "Failed to find any valid state copy in any bucket\n");
-
- return -ENOENT;
- }
+ if (!bucket_used)
+ return dev_err_state_init(storage->dev, zerobuckets == totalbuckets ? -ENOMEDIUM : -ENOENT,
+ "no valid state copy in any bucket\n");
dev_info(storage->dev, "Using bucket %d@0x%08llx\n", bucket_used->num, (long long) bucket_used->offset);
@@ -326,7 +332,7 @@ static int state_storage_file_buckets_init(struct state_backend_storage *storage
offset = storage->offset + n * stridesize;
ret = state_backend_bucket_direct_create(storage->dev, storage->path,
&bucket, offset,
- stridesize);
+ stridesize, storage->readonly);
if (ret) {
dev_warn(storage->dev, "Failed to create direct bucket at '%s' offset %lld\n",
storage->path, (long long) offset);
diff --git a/common/state/state.c b/common/state/state.c
index d42920985d..219309d715 100644
--- a/common/state/state.c
+++ b/common/state/state.c
@@ -21,8 +21,10 @@
#include <fs.h>
#include <crc.h>
#include <init.h>
+#include <block.h>
#include <linux/err.h>
#include <linux/list.h>
+#include <linux/uuid.h>
#include <linux/mtd/mtd-abi.h>
#include <malloc.h>
@@ -101,8 +103,8 @@ static int state_do_load(struct state *state, enum state_flags flags)
ret = state_storage_read(&state->storage, state->format,
state->magic, &buf, &len, flags);
if (ret) {
- dev_err(&state->dev, "Failed to read state with format %s, %d\n",
- state->format->name, ret);
+ dev_err_state_init(&state->dev, ret, "format %s read failed\n",
+ state->format->name);
goto out;
}
@@ -271,9 +273,8 @@ static int state_convert_node_variable(struct state *state,
if (conv == STATE_CONVERT_FROM_NODE_CREATE) {
sv = vtype->create(state, name, node, vtype);
if (IS_ERR(sv)) {
+ dev_err(&state->dev, "failed to create %s: %pe\n", name, sv);
ret = PTR_ERR(sv);
- dev_err(&state->dev, "failed to create %s: %s\n", name,
- strerror(-ret));
goto out_free;
}
@@ -334,8 +335,10 @@ static int state_convert_node_variable(struct state *state,
goto out;
return 0;
- out_free:free(name);
- out: return ret;
+out_free:
+ free(name);
+out:
+ return ret;
}
struct device_node *state_to_node(struct state *state,
@@ -362,7 +365,8 @@ struct device_node *state_to_node(struct state *state,
}
return root;
- out: of_delete_node(root);
+out:
+ of_delete_node(root);
return ERR_PTR(ret);
}
@@ -557,12 +561,12 @@ static int of_state_fixup(struct device_node *root, void *ctx)
goto out;
/* delete existing node */
- if (node)
- of_delete_node(node);
+ of_delete_node(node);
return 0;
- out: of_delete_node(new_node);
+out:
+ of_delete_node(new_node);
return ret;
}
@@ -579,6 +583,22 @@ void state_release(struct state *state)
free(state);
}
+#ifdef __BAREBOX__
+static char *cdev_to_devpath(struct cdev *cdev, off_t *offset, size_t *size)
+{
+ /*
+ * We only accept partitions exactly mapping the barebox-state,
+ * but dt-utils may need to set non-zero values here
+ */
+ *offset = 0;
+ *size = 0;
+
+ return basprintf("/dev/%s", cdev->name);
+}
+#endif
+
+static guid_t barebox_state_partition_guid = BAREBOX_STATE_PARTITION_GUID;
+
/*
* state_new_from_node - create a new state instance from a device_node
*
@@ -595,12 +615,13 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
const char *alias;
uint32_t stridesize;
struct device_node *partition_node;
- off_t offset = 0;
- size_t size = 0;
+ struct cdev *cdev;
+ off_t offset;
+ size_t size;
alias = of_alias_get(node);
if (!alias) {
- pr_err("State node %s does not have an alias in the /aliases/ node\n", node->full_name);
+ pr_err("State node %pOF does not have an alias in the /aliases/ node\n", node);
return ERR_PTR(-EINVAL);
}
@@ -615,11 +636,8 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
goto out_release_state;
}
-#ifdef __BAREBOX__
- ret = of_find_path_by_node(partition_node, &state->backend_path, 0);
-#else
- ret = of_get_devicepath(partition_node, &state->backend_path, &offset, &size);
-#endif
+ cdev = of_cdev_find(partition_node);
+ ret = PTR_ERR_OR_ZERO(cdev);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(&state->dev, "state failed to parse path to backend: %s\n",
@@ -627,6 +645,22 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
goto out_release_state;
}
+ /* Is the backend referencing an on-disk partitionable block device? */
+ if (cdev_is_block_disk(cdev)) {
+ cdev = cdev_find_child_by_gpt_typeuuid(cdev, &barebox_state_partition_guid);
+ if (IS_ERR(cdev)) {
+ ret = -EINVAL;
+ goto out_release_state;
+ }
+
+ pr_debug("%pOF: backend GPT partition looked up via PartitionTypeGUID\n",
+ node);
+ }
+
+ state->backend_path = cdev_to_devpath(cdev, &offset, &size);
+
+ pr_debug("%pOF: backend resolved to %s\n", node, state->backend_path);
+
state->backend_reproducible_name = of_get_reproducible_name(partition_node);
ret = of_property_read_string(node, "backend-type", &backend_type);
@@ -650,14 +684,14 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
if (ret)
goto out_release_state;
+ if (readonly)
+ state_backend_set_readonly(state);
+
ret = state_storage_init(state, state->backend_path, offset,
size, stridesize, storage_type);
if (ret)
goto out_release_state;
- if (readonly)
- state_backend_set_readonly(state);
-
ret = state_from_node(state, node, 1);
if (ret) {
goto out_release_state;
@@ -701,10 +735,12 @@ struct state *state_by_name(const char *name)
*
* @node The of node of the state instance
*/
-struct state *state_by_node(const struct device_node *node)
+struct state *state_by_node(struct device_node *node)
{
struct state *state;
+ of_device_ensure_probed(node);
+
list_for_each_entry(state, &state_list, list) {
if (!strcmp(state->of_path, node->full_name))
return state;
@@ -713,6 +749,22 @@ struct state *state_by_node(const struct device_node *node)
return NULL;
}
+/*
+ * state_by_alias - find a state instance by alias
+ *
+ * @name The DT alias of the state instance
+ */
+struct state *state_by_alias(const char *alias)
+{
+ struct device_node *node;
+
+ node = of_find_node_by_alias(NULL, alias);
+ if (!node)
+ return NULL;
+
+ return state_by_node(node);
+}
+
int state_read_mac(struct state *state, const char *name, u8 *buf)
{
struct state_variable *svar;
diff --git a/common/state/state.h b/common/state/state.h
index 1881d92ea7..f0c5b1de41 100644
--- a/common/state/state.h
+++ b/common/state/state.h
@@ -1,5 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <linux/types.h>
#include <linux/list.h>
+#include <linux/err.h>
#include <driver.h>
struct state;
@@ -87,7 +90,7 @@ struct state_backend_storage {
struct list_head buckets;
/* For outputs */
- struct device_d *dev;
+ struct device *dev;
const char *name;
@@ -102,7 +105,7 @@ struct state_backend_storage {
struct state {
struct list_head list; /* Entry to enqueue on list of states */
- struct device_d dev;
+ struct device dev;
char *of_path;
const char *name;
uint32_t magic;
@@ -199,21 +202,21 @@ struct device_node *state_to_node(struct state *state,
enum state_convert conv);
int backend_format_raw_create(struct state_backend_format **format,
struct device_node *node, const char *secret_name,
- struct device_d *dev);
+ struct device *dev);
int backend_format_dtb_create(struct state_backend_format **format,
- struct device_d *dev);
+ struct device *dev);
int state_storage_init(struct state *state, const char *path,
off_t offset, size_t max_size, uint32_t stridesize,
const char *storagetype);
void state_storage_set_readonly(struct state_backend_storage *storage);
void state_add_var(struct state *state, struct state_variable *var);
struct variable_type *state_find_type_by_name(const char *name);
-int state_backend_bucket_circular_create(struct device_d *dev, const char *path,
+int state_backend_bucket_circular_create(struct device *dev, const char *path,
struct state_backend_storage_bucket **bucket,
unsigned int eraseblock,
ssize_t writesize,
struct mtd_info_user *mtd_uinfo);
-int state_backend_bucket_cached_create(struct device_d *dev,
+int state_backend_bucket_cached_create(struct device *dev,
struct state_backend_storage_bucket *raw,
struct state_backend_storage_bucket **out);
struct state_variable *state_find_var(struct state *state, const char *name);
@@ -221,9 +224,9 @@ struct digest *state_backend_format_raw_get_digest(struct state_backend_format
*format);
void state_backend_set_readonly(struct state *state);
void state_storage_free(struct state_backend_storage *storage);
-int state_backend_bucket_direct_create(struct device_d *dev, const char *path,
+int state_backend_bucket_direct_create(struct device *dev, const char *path,
struct state_backend_storage_bucket **bucket,
- off_t offset, ssize_t max_size);
+ off_t offset, ssize_t max_size, bool readonly);
int state_storage_write(struct state_backend_storage *storage,
const void * buf, ssize_t len);
int state_storage_read(struct state_backend_storage *storage,
@@ -266,3 +269,16 @@ static inline int state_string_copy_to_raw(struct state_string *string,
return 0;
}
+
+#ifdef DEBUG
+#define MSG_STATE_ZERO_INIT MSG_INFO
+#else
+#define MSG_STATE_ZERO_INIT MSG_DEBUG
+#endif
+
+#define dev_err_state_init(dev, ret, fmt, ...) ({ \
+ int __ret = (ret); \
+ __dev_printf(__ret == -ENOMEDIUM ? MSG_STATE_ZERO_INIT : MSG_ERR, \
+ (dev), "init error: %pe: " fmt, ERR_PTR(__ret), ##__VA_ARGS__); \
+ __ret; \
+})
diff --git a/common/state/state_variables.c b/common/state/state_variables.c
index 66c66f38bd..77946206cd 100644
--- a/common/state/state_variables.c
+++ b/common/state/state_variables.c
@@ -21,7 +21,7 @@
#include <linux/types.h>
#include <malloc.h>
#include <net.h>
-#include <printk.h>
+#include <linux/printk.h>
#include <of.h>
#include <stdio.h>
@@ -180,6 +180,8 @@ static int state_enum32_export(struct state_variable *var,
str += sprintf(str, "%s", enum32->names[i]) + 1;
ret = of_set_property(node, "names", prop, len, 1);
+ if (ret)
+ return ret;
free(prop);
@@ -261,7 +263,8 @@ static struct state_variable *state_enum32_create(struct state *state,
}
return &enum32->var;
- out: for (i--; i >= 0; i--)
+out:
+ for (i--; i >= 0; i--)
free((char *)enum32->names[i]);
free(enum32->names);
free(enum32);
@@ -327,7 +330,8 @@ static struct state_variable *state_mac_create(struct state *state,
}
return &mac->var;
- out: free(mac);
+out:
+ free(mac);
return ERR_PTR(ret);
}
@@ -442,7 +446,8 @@ static struct state_variable *state_string_create(struct state *state,
}
return &string->var;
- out: free(string);
+out:
+ free(string);
return ERR_PTR(ret);
}