summaryrefslogtreecommitdiffstats
path: root/common/state/state.h
diff options
context:
space:
mode:
authorMarkus Pargmann <mpa@pengutronix.de>2016-07-06 10:19:43 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2016-07-08 08:59:31 +0200
commitc999b507da9891f22cf2a60105bffa0774eea082 (patch)
treedbc1a712b3ab6919758c1cffc6f979ba8c98d59f /common/state/state.h
parent3d33f178ccd7b0602b20c8fb37d7e57beed22e89 (diff)
downloadbarebox-c999b507da9891f22cf2a60105bffa0774eea082.tar.gz
barebox-c999b507da9891f22cf2a60105bffa0774eea082.tar.xz
state: Refactor state framework
The state framework grew organically over the time. Unfortunately the architecture and abstractions disappeared during this period. This patch refactors the framework to recreate the abstractions. The main focus was the backend with its storage. The main use-case was to offer better NAND support with less erase cycles and interchangeable data formats (dtb,raw). The general architecture now has a backend which consists of a data format and storage. The storage consists of multiple storage buckets each holding exactly one copy of the state data. A data format describes a data serialization for the state framework. This can be either dtb or raw. A storage bucket is a storage location which is used to store any data. There is a (new) circular type which writes changes behind the last written data and therefore reduces the number of erases. The other type is a direct bucket which writes directly to a storage offset for all non-erase storage. Furthermore this patch splits up all classes into different files in a subdirectory. This is currently all in one patch as I can't see a good way to split the changes up without having a non-working state framework in between. The following diagram shows the new architecture roughly: .----------. | state | '----------' | | v .----------------------------. | state_backend | |----------------------------| | + state_load(*state); | | + state_save(*state); | | + state_backend_init(...); | | | | | '----------------------------' | | The format describes | | how the state data | '-------------> is serialized | .--------------------------------------------. | | state_backend_format <INTERFACE> | | |--------------------------------------------| | | + verify(*format, magic, *buf, len); | | | + pack(*format, *state, **buf, len); | | | + unpack(*format, *state, *buf, len); | | | + get_packed_len(*format, *state); | | | + free(*format); | | '--------------------------------------------' | ^ ^ | * * | * * | .--------------------. .--------------------. | | backend_format_dtb | | backend_format_raw | | '--------------------' '--------------------' | | | v .----------------------------------------------------------. | state_backend_storage | |----------------------------------------------------------| | + init(...); | | + free(*storage); | | + read(*storage, *format, magic, **buf, *len, len_hint); | | + write(*storage, *buf, len); | | + restore_consistency(*storage, *buf, len); | '----------------------------------------------------------' | The backend storage is responsible to manage multiple data copies and distribute them onto several buckets. Read data is verified against the given format to ensure that the read data is correct. | | | | | v .------------------------------------------. | state_backend_storage_bucket <INTERFACE> | |------------------------------------------| | + init(*bucket); | | + write(*bucket, *buf, len); | | + read(*bucket, **buf, len_hint); | | + free(*bucket); | '------------------------------------------' ^ ^ ^ * * * * * * A storage bucket represents*exactly one data copy at one data location. A circular b*cket writes any new data to the end of the bucket (for *educed erases on NAND). A direct bucket directly writ*s at one location. * * * * * * * * * .-----------------------. * .-------------------------. | backend_bucket_direct | * | backend_bucket_circular | '-----------------------' * '-------------------------' ^ * ^ | * | | * | | * | | .-----------------------. | '--| backend_bucket_cached |---' '-----------------------' A backend_bucket_cached is a transparent bucket that directly uses another bucket as backend device and caches all accesses. Signed-off-by: Markus Pargmann <mpa@pengutronix.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'common/state/state.h')
-rw-r--r--common/state/state.h275
1 files changed, 275 insertions, 0 deletions
diff --git a/common/state/state.h b/common/state/state.h
new file mode 100644
index 0000000000..cd54767830
--- /dev/null
+++ b/common/state/state.h
@@ -0,0 +1,275 @@
+#include <linux/types.h>
+#include <linux/list.h>
+#include <driver.h>
+
+struct state;
+struct mtd_info_user;
+
+/**
+ * state_backend_storage_bucket - This class describes a single backend storage
+ * object copy
+ *
+ * @init Optional, initiates the given bucket
+ * @write Required, writes the given data to the storage in any form. Returns 0
+ * on success
+ * @read Required, reads the last successfully written data from the backend
+ * storage. Returns 0 on success and allocates a matching memory area to buf.
+ * len_hint can be a hint of the storage format how large the data to be read
+ * is. After the operation len_hint contains the size of the allocated buffer.
+ * @free Required, Frees all internally used memory
+ * @bucket_list A list element struct to attach this bucket to a list
+ */
+struct state_backend_storage_bucket {
+ int (*init) (struct state_backend_storage_bucket * bucket);
+ int (*write) (struct state_backend_storage_bucket * bucket,
+ const uint8_t * buf, ssize_t len);
+ int (*read) (struct state_backend_storage_bucket * bucket,
+ uint8_t ** buf, ssize_t * len_hint);
+ void (*free) (struct state_backend_storage_bucket * bucket);
+
+ bool initialized;
+ struct list_head bucket_list;
+};
+
+/**
+ * state_backend_format - This class describes a data format.
+ *
+ * @verify Required, Verifies the validity of the given data. The buffer that is
+ * passed into this function may be larger than the actual data in the buffer.
+ * The magic is supplied by the state to verify that this is an expected state
+ * entity. The function should return 0 on success or a negative errno otherwise.
+ * @pack Required, Packs data from the given state into a newly created buffer.
+ * The buffer and its length are stored in the given argument pointers. Returns
+ * 0 on success, -errno otherwise.
+ * @unpack Required, Unpacks the data from the given buffer into the state. Do
+ * not free the buffer.
+ * @free Optional, Frees all allocated memory and structures.
+ * @name Name of this backend.
+ */
+struct state_backend_format {
+ int (*verify) (struct state_backend_format * format, uint32_t magic,
+ const uint8_t * buf, ssize_t len);
+ int (*pack) (struct state_backend_format * format, struct state * state,
+ uint8_t ** buf, ssize_t * len);
+ int (*unpack) (struct state_backend_format * format,
+ struct state * state, const uint8_t * buf, ssize_t len);
+ ssize_t(*get_packed_len) (struct state_backend_format * format,
+ struct state * state);
+ void (*free) (struct state_backend_format * format);
+ const char *name;
+};
+
+/**
+ * state_backend_storage - Storage backend of the state.
+ *
+ * @buckets List of storage buckets that are available
+ */
+struct state_backend_storage {
+ struct list_head buckets;
+
+ /* For outputs */
+ struct device_d *dev;
+
+ const char *name;
+
+ bool readonly;
+};
+
+/**
+ * state_backend - State Backend object
+ *
+ * @format Backend format object
+ * @storage Backend storage object
+ * @of_path Path to the DT node
+ */
+struct state_backend {
+ struct state_backend_format *format;
+ struct state_backend_storage storage;
+ const char *of_path;
+};
+
+struct state {
+ struct list_head list; /* Entry to enqueue on list of states */
+
+ struct device_d dev;
+ struct device_node *root;
+ const char *name;
+ uint32_t magic;
+
+ struct list_head variables; /* Sorted list of variables */
+ unsigned int dirty;
+
+ struct state_backend backend;
+};
+
+enum state_convert {
+ STATE_CONVERT_FROM_NODE,
+ STATE_CONVERT_FROM_NODE_CREATE,
+ STATE_CONVERT_TO_NODE,
+ STATE_CONVERT_FIXUP,
+};
+
+enum state_variable_type {
+ STATE_TYPE_INVALID = 0,
+ STATE_TYPE_ENUM,
+ STATE_TYPE_U8,
+ STATE_TYPE_U32,
+ STATE_TYPE_MAC,
+ STATE_TYPE_STRING,
+};
+
+struct state_variable;
+
+/* A variable type (uint32, enum32) */
+struct variable_type {
+ enum state_variable_type type;
+ const char *type_name;
+ struct list_head list;
+ int (*export) (struct state_variable *, struct device_node *,
+ enum state_convert);
+ int (*import) (struct state_variable *, struct device_node *);
+ struct state_variable *(*create) (struct state * state,
+ const char *name,
+ struct device_node *);
+};
+
+/* instance of a single variable */
+struct state_variable {
+ enum state_variable_type type;
+ struct list_head list;
+ const char *name;
+ unsigned int start;
+ unsigned int size;
+ void *raw;
+};
+
+/*
+ * uint32
+ */
+struct state_uint32 {
+ struct state_variable var;
+ struct param_d *param;
+ struct state *state;
+ uint32_t value;
+ uint32_t value_default;
+};
+
+/*
+ * enum32
+ */
+struct state_enum32 {
+ struct state_variable var;
+ struct param_d *param;
+ uint32_t value;
+ uint32_t value_default;
+ const char **names;
+ int num_names;
+};
+
+/*
+ * MAC address
+ */
+struct state_mac {
+ struct state_variable var;
+ struct param_d *param;
+ uint8_t value[6];
+ uint8_t value_default[6];
+};
+
+/*
+ * string
+ */
+struct state_string {
+ struct state_variable var;
+ struct param_d *param;
+ struct state *state;
+ char *value;
+ const char *value_default;
+ char raw[];
+};
+
+int state_set_dirty(struct param_d *p, void *priv);
+int state_from_node(struct state *state, struct device_node *node, bool create);
+struct device_node *state_to_node(struct state *state,
+ struct device_node *parent,
+ 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);
+int backend_format_dtb_create(struct state_backend_format **format,
+ struct device_d *dev);
+int state_storage_init(struct state_backend_storage *storage,
+ struct device_d *dev, 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,
+ struct state_backend_storage_bucket **bucket,
+ unsigned int eraseblock,
+ ssize_t writesize,
+ struct mtd_info_user *mtd_uinfo,
+ bool lazy_init);
+int state_backend_bucket_cached_create(struct device_d *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);
+struct digest *state_backend_format_raw_get_digest(struct state_backend_format
+ *format);
+int state_backend_init(struct state_backend *backend, struct device_d *dev,
+ struct device_node *node, const char *backend_format,
+ const char *storage_path, const char *state_name, const
+ char *of_path, off_t offset, size_t max_size,
+ uint32_t stridesize, const char *storagetype);
+void state_backend_set_readonly(struct state_backend *backend);
+void state_backend_free(struct state_backend *backend);
+void state_storage_free(struct state_backend_storage *storage);
+int state_backend_bucket_direct_create(struct device_d *dev, const char *path,
+ struct state_backend_storage_bucket **bucket,
+ off_t offset, ssize_t max_size);
+int state_storage_write(struct state_backend_storage *storage,
+ const uint8_t * buf, ssize_t len);
+int state_storage_restore_consistency(struct state_backend_storage
+ *storage, const uint8_t * buf,
+ ssize_t len);
+int state_storage_read(struct state_backend_storage *storage,
+ struct state_backend_format *format,
+ uint32_t magic, uint8_t **buf, ssize_t *len,
+ ssize_t len_hint);
+
+static inline struct state_uint32 *to_state_uint32(struct state_variable *s)
+{
+ return container_of(s, struct state_uint32, var);
+}
+
+static inline struct state_enum32 *to_state_enum32(struct state_variable *s)
+{
+ return container_of(s, struct state_enum32, var);
+}
+
+static inline struct state_mac *to_state_mac(struct state_variable *s)
+{
+ return container_of(s, struct state_mac, var);
+}
+
+static inline struct state_string *to_state_string(struct state_variable *s)
+{
+ return container_of(s, struct state_string, var);
+}
+
+static inline int state_string_copy_to_raw(struct state_string *string,
+ const char *src)
+{
+ size_t len;
+
+ len = strlen(src);
+ if (len > string->var.size)
+ return -EILSEQ;
+
+ /* copy string and clear remaining contents of buffer */
+ memcpy(string->raw, src, len);
+ memset(string->raw + len, 0x0, string->var.size - len);
+
+ return 0;
+}