[RFC PATCH 1/7] lib: Add types for platform attributes
Samuel Mendoza-Jonas
sam.mj at au1.ibm.com
Mon Nov 30 13:59:25 AEDT 2015
Add supporting types to represent platform attribute overrides.
Attribute overrides will be received in a tree format defining logical
groups of attributes, so each firmware_option is either an attribute, or
a further group (branch) in the tree.
Signed-off-by: Samuel Mendoza-Jonas <sam.mj at au1.ibm.com>
---
lib/pb-protocol/pb-protocol.c | 358 ++++++++++++++++++++++++++++++++++++++++++
lib/pb-protocol/pb-protocol.h | 7 +
lib/types/types.h | 60 +++++++
3 files changed, 425 insertions(+)
diff --git a/lib/pb-protocol/pb-protocol.c b/lib/pb-protocol/pb-protocol.c
index 7d45f51..6d00b02 100644
--- a/lib/pb-protocol/pb-protocol.c
+++ b/lib/pb-protocol/pb-protocol.c
@@ -262,6 +262,90 @@ static int pb_protocol_interface_config_len(struct interface_config *conf)
return len;
}
+static int pb_protocol_firmware_attr_len(struct firmware_attr *attr)
+{
+ unsigned int i, len;
+
+ len = 4 + optional_strlen(attr->id) +
+ 4 + optional_strlen(attr->numeric_id);
+
+ len += 4; /* attr->is_signed */
+ len += 4; /* attr->size */
+
+ len += 4 + optional_strlen(attr->value) +
+ 4 + optional_strlen(attr->current_value) +
+ 4 + optional_strlen(attr->default_value) +
+ 4 + optional_strlen(attr->display_name) +
+ 4 + optional_strlen(attr->description);
+
+ len += 4 /* attr->limit */;
+
+ switch (attr->limit) {
+ case LIMIT_NONE:
+ break;
+ case LIMIT_RANGE:
+ len += 4 /* attr->n_range */ +
+ 4 * attr->n_range;
+ break;
+ case LIMIT_ENUM:
+ len += 4 /* attr->n_range */;
+ for (i = 0; i < attr->n_range; i++) {
+ len += 4 + optional_strlen(attr->enums[i].display_name);
+ len += 4 + optional_strlen(attr->enums[i].description);
+ len += 4 /* attr->enums[i].value */;
+ }
+ break;
+ default:
+ pb_log("Unrecognised attribute type: %d\n", attr->limit);
+ }
+
+ len += 4; /* attr->type */
+ len += 4; /* attr->pos */
+ len += 4; /* attr->unitPos */
+ len += 4; /* attr->node */
+ len += 4; /* attr->flags */
+
+ return len;
+}
+
+static int pb_protocol_firmware_len(struct firmware_option *opt)
+{
+ unsigned int i, len;
+
+ len = 4 + optional_strlen(opt->name);
+
+ len += 4 /* opt->type */;
+
+ switch (opt->type) {
+ case FIRMWARE_ATTR:
+ len += pb_protocol_firmware_attr_len(opt->attr);
+ break;
+ case FIRMWARE_GROUP:
+ len += 4 /* opt->n_opts */;
+ for (i = 0; i < opt->n_opts; i++) {
+ int tmp = pb_protocol_firmware_len(&opt->opts[i]);
+ len += tmp;
+ }
+ break;
+ default:
+ pb_log("Unrecognised firmware option type: %d\n", opt->type);
+ }
+
+ return len;
+}
+
+int pb_protocol_platform_options_len(const struct platform_options *options)
+{
+ unsigned int i, len;
+
+ len = 4; /* n_opts */
+
+ for (i = 0; i < options->n_options; i++)
+ len += pb_protocol_firmware_len(&options->options[i]);
+
+ return len;
+}
+
int pb_protocol_config_len(const struct config *config)
{
unsigned int i, len;
@@ -453,6 +537,123 @@ static int pb_protocol_serialise_config_interface(char *buf,
return pos - buf;
}
+static int pb_protocol_serialise_firmware_attr(char *buf,
+ struct firmware_attr *attr)
+{
+ char *pos = buf;
+ unsigned int i;
+
+ pos += pb_protocol_serialise_string(pos, attr->id);
+ pos += pb_protocol_serialise_string(pos, attr->numeric_id);
+
+ *(uint32_t *)pos = attr->is_signed;
+ pos += 4;
+ *(uint32_t *)pos = __cpu_to_be32(attr->size);
+ pos += 4;
+
+ pos += pb_protocol_serialise_string(pos, attr->value);
+ pos += pb_protocol_serialise_string(pos, attr->current_value);
+ pos += pb_protocol_serialise_string(pos, attr->default_value);
+ pos += pb_protocol_serialise_string(pos, attr->display_name);
+ pos += pb_protocol_serialise_string(pos, attr->description);
+
+ *(uint32_t *)pos = __cpu_to_be32(attr->limit);
+ pos += 4;
+
+ switch (attr->limit) {
+ case LIMIT_RANGE:
+ *(uint32_t *)pos = __cpu_to_be32(attr->n_range);
+ pos += 4;
+ for (i = 0; i < attr->n_range; i++) {
+ *(uint32_t *)pos = __cpu_to_be32(attr->range[i]);
+ pos += 4;
+ }
+ break;
+ case LIMIT_ENUM:
+ *(uint32_t *)pos = __cpu_to_be32(attr->n_range);
+ pos += 4;
+ for (i = 0; i < attr->n_range; i++) {
+ pos += pb_protocol_serialise_string(pos,
+ attr->enums[i].display_name);
+ pos += pb_protocol_serialise_string(pos,
+ attr->enums[i].description);
+ *(uint32_t *)pos = __cpu_to_be32(attr->enums[i].value);
+ pos += 4;
+ }
+ break;
+ default:
+ pb_log("Unrecognised attribute type: %d\n", attr->limit);
+ /* fall-through */
+ case LIMIT_NONE:
+ break;
+ }
+
+ *(uint32_t *)pos = __cpu_to_be32(attr->type);
+ pos += 4;
+ *(uint32_t *)pos = __cpu_to_be32(attr->pos);
+ pos += 4;
+ *(uint32_t *)pos = __cpu_to_be32(attr->unitPos);
+ pos += 4;
+ *(uint32_t *)pos = __cpu_to_be32(attr->node);
+ pos += 4;
+ *(uint32_t *)pos = __cpu_to_be32(attr->flags);
+ pos += 4;
+
+ return pos - buf;
+}
+
+static int pb_protocol_serialise_firmware(char *buf,
+ struct firmware_option *opt)
+{
+ unsigned int i;
+ char *pos = buf;
+
+ pos += pb_protocol_serialise_string(pos, opt->name);
+
+ *(uint32_t *)pos = __cpu_to_be32(opt->type);
+ pos += 4;
+
+ switch (opt->type) {
+ case FIRMWARE_ATTR:
+ if (!opt->attr) {
+ pb_log("NULL ATTRIBUTE!\n");
+ return -1;
+ }
+ pos += pb_protocol_serialise_firmware_attr(pos, opt->attr);
+ break;
+ case FIRMWARE_GROUP:
+ *(uint32_t *)pos = __cpu_to_be32(opt->n_opts);
+ pos += 4;
+
+ for (i = 0; i < opt->n_opts; i++)
+ pos += pb_protocol_serialise_firmware(pos, &opt->opts[i]);
+ break;
+ default:
+ pb_log("Unrecognised firmware option type: %d\n", opt->type);
+ break;
+ }
+
+ return pos - buf;
+}
+
+int pb_protocol_serialise_platform_options(const struct platform_options *options,
+ char *buf, int buf_len)
+{
+ char *pos = buf;
+ unsigned int i;
+
+ *(uint32_t *)pos = __cpu_to_be32(options->n_options);
+ pos += 4;
+
+ for (i = 0; i < options->n_options; i++)
+ pos += pb_protocol_serialise_firmware(pos, &options->options[i]);
+
+ assert(pos-buf <= buf_len);
+ (void)buf_len;
+ return 0;
+}
+
+
int pb_protocol_serialise_config(const struct config *config,
char *buf, int buf_len)
{
@@ -889,6 +1090,163 @@ static int pb_protocol_deserialise_config_interface(const char **buf,
return 0;
}
+static int pb_protocol_deserialise_firmware_attr(struct firmware_attr *attr,
+ const char **pos, unsigned int *len)
+{
+ unsigned int i, tmp;
+ int rc = -1;
+ char *tmp_str;
+
+ if (read_string(attr, pos, len, &tmp_str))
+ goto out;
+ attr->id = tmp_str;
+ if (read_string(attr, pos, len, &tmp_str))
+ goto out;
+ attr->numeric_id = tmp_str;
+
+ if (read_u32(pos, len, &tmp))
+ goto out;
+ attr->is_signed = !!tmp;
+ if (read_u32(pos, len, &attr->size))
+ goto out;
+
+ if (read_string(attr, pos, len, &tmp_str))
+ goto out;
+ attr->value = tmp_str;
+ if (read_string(attr, pos, len, &tmp_str))
+ goto out;
+ attr->current_value = tmp_str;
+ if (read_string(attr, pos, len, &tmp_str))
+ goto out;
+ attr->default_value = tmp_str;
+ if (read_string(attr, pos, len, &tmp_str))
+ goto out;
+ attr->display_name = tmp_str;
+ if (read_string(attr, pos, len, &tmp_str))
+ goto out;
+ attr->description = tmp_str;
+
+ if (read_u32(pos, len, &attr->limit))
+ goto out;
+
+ switch (attr->limit) {
+ case LIMIT_RANGE:
+ if (read_u32(pos, len, &attr->n_range))
+ goto out;
+ attr->range = talloc_array(attr, int, attr->n_range);
+ for (i = 0; i < attr->n_range; i++) {
+ if (read_u32(pos, len, (unsigned int *) &attr->range[i]))
+ goto out;
+ }
+ break;
+ case LIMIT_ENUM:
+ if (read_u32(pos, len, &attr->n_range))
+ goto out;
+ attr->enums = talloc_zero_array(attr, struct enumeration,
+ attr->n_range);
+ for (i = 0; i < attr->n_range; i++) {
+ if (read_string(attr, pos, len, &tmp_str))
+ goto out;
+ attr->enums[i].display_name = tmp_str;
+ if (read_string(attr, pos, len, &tmp_str))
+ goto out;
+ attr->enums[i].description = tmp_str;
+
+ if (read_u32(pos, len, &attr->enums[i].value))
+ goto out;
+ }
+ break;
+ case LIMIT_NONE:
+ break;
+ default:
+ pb_log("Unrecognised attribute type: %d\n", attr->limit);
+ goto out;
+ }
+
+ if (read_u32(pos, len, &attr->type))
+ goto out;
+ if (read_u32(pos, len, &attr->pos))
+ goto out;
+ if (read_u32(pos, len, &attr->unitPos))
+ goto out;
+ if (read_u32(pos, len, &attr->node))
+ goto out;
+ if (read_u32(pos, len, &attr->flags))
+ goto out;
+
+ return 0;
+out:
+ talloc_free(attr);
+ return rc;
+}
+
+static int pb_protocol_deserialise_firmware_option(void *ctx,
+ struct firmware_option *opt,
+ const char **pos, unsigned int *len)
+{
+ unsigned int i;
+ char *tmp_str;
+
+ if (read_string(ctx, pos, len, &tmp_str))
+ return -1;
+ opt->name = tmp_str;
+
+ if (read_u32(pos, len, &opt->type))
+ return -1;
+
+ switch (opt->type) {
+ case FIRMWARE_ATTR:
+ opt->attr = talloc(ctx, struct firmware_attr);
+ pb_protocol_deserialise_firmware_attr(opt->attr, pos, len);
+ break;
+ case FIRMWARE_GROUP:
+ if (read_u32(pos, len, &opt->n_opts))
+ return -1;
+ opt->opts = talloc_array(ctx, struct firmware_option,
+ opt->n_opts);
+ for (i = 0; i < opt->n_opts; i++) {
+ pb_protocol_deserialise_firmware_option(ctx, &opt->opts[i],
+ pos, len);
+ }
+ break;
+ default:
+ pb_log("Unrecognised firmware option type: %d\n", opt->type);
+ return -1;
+ }
+
+ return 0;
+}
+
+int pb_protocol_deserialise_platform_options(struct platform_options *options,
+ const struct pb_protocol_message *message)
+{
+ struct firmware_option *opts;
+ unsigned int len, i, n_opts;
+ const char *pos;
+
+ len = message->payload_len;
+ pos = message->payload;
+
+ if (read_u32(&pos, &len, &n_opts))
+ return -1;
+
+ options->n_options = n_opts;
+
+ opts = talloc_array(options, struct firmware_option, n_opts);
+ for (i = 0 ; i < n_opts; i++) {
+ if (pb_protocol_deserialise_firmware_option(options, &opts[i],
+ &pos, &len))
+ goto out;
+ }
+
+ options->options = opts;
+
+ return 0;
+out:
+ talloc_free(opts);
+ return -1;
+}
+
int pb_protocol_deserialise_config(struct config *config,
const struct pb_protocol_message *message)
{
diff --git a/lib/pb-protocol/pb-protocol.h b/lib/pb-protocol/pb-protocol.h
index f850520..d0e8ee6 100644
--- a/lib/pb-protocol/pb-protocol.h
+++ b/lib/pb-protocol/pb-protocol.h
@@ -23,6 +23,7 @@ enum pb_protocol_action {
PB_PROTOCOL_ACTION_CONFIG = 0x9,
PB_PROTOCOL_ACTION_REINIT = 0xa,
PB_PROTOCOL_ACTION_ADD_URL = 0xb,
+ PB_PROTOCOL_ACTION_FIRMWARE = 0xc,
};
struct pb_protocol_message {
@@ -40,6 +41,7 @@ int pb_protocol_boot_status_len(const struct boot_status *status);
int pb_protocol_system_info_len(const struct system_info *sysinfo);
int pb_protocol_config_len(const struct config *config);
int pb_protocol_url_len(const char *url);
+int pb_protocol_platform_options_len(const struct platform_options *options);
int pb_protocol_device_cmp(const struct device *a, const struct device *b);
int pb_protocol_boot_option_cmp(const struct boot_option *a,
@@ -62,6 +64,8 @@ int pb_protocol_serialise_system_info(const struct system_info *sysinfo,
int pb_protocol_serialise_config(const struct config *config,
char *buf, int buf_len);
int pb_protocol_serialise_url(const char *url, char *buf, int buf_len);
+int pb_protocol_serialise_platform_options(const struct platform_options *options,
+ char *buf, int buf_len);
int pb_protocol_write_message(int fd, struct pb_protocol_message *message);
@@ -87,4 +91,7 @@ int pb_protocol_deserialise_system_info(struct system_info *sysinfo,
int pb_protocol_deserialise_config(struct config *config,
const struct pb_protocol_message *message);
+
+int pb_protocol_deserialise_platform_options(struct platform_options *options,
+ const struct pb_protocol_message *message);
#endif /* _PB_PROTOCOL_H */
diff --git a/lib/types/types.h b/lib/types/types.h
index 6a2c258..8c9d552 100644
--- a/lib/types/types.h
+++ b/lib/types/types.h
@@ -136,6 +136,66 @@ struct autoboot_option {
};
};
+/* Firmware attributes define a specific attribute override */
+struct firmware_attr {
+ const char *id; /* string ID */
+ const char *numeric_id; /* hex ID */
+ unsigned int size; /* value size, given in bytes */
+ bool is_signed;
+
+ char *value; /* user defined val */
+ const char *current_value; /* current value (override) */
+ const char *default_value; /* default value (defined) */
+ const char *display_name;
+ const char *description;
+
+ /* The value of an attribute may be unbounded, limited to a certain
+ * range, or limited to certain enumerated values */
+ enum {
+ LIMIT_NONE,
+ LIMIT_RANGE,
+ LIMIT_ENUM,
+ } limit;
+
+ unsigned int n_range;
+ union {
+ int *range;
+ struct enumeration {
+ const char *display_name;
+ const char *description;
+ unsigned int value;
+ } *enums;
+ };
+
+ /* Details for updating PNOR */
+ unsigned int type;
+ unsigned int pos;
+ unsigned int unitPos;
+ unsigned int node;
+ unsigned int flags;
+};
+
+/* Firmware options define either an attribute or a group of attributes */
+struct firmware_option {
+ const char *name;
+ enum {
+ FIRMWARE_ATTR,
+ FIRMWARE_GROUP,
+ } type;
+ union {
+ struct firmware_attr *attr;
+ struct {
+ unsigned int n_opts;
+ struct firmware_option *opts;
+ } ;
+ };
+};
+
+struct platform_options {
+ unsigned int n_options;
+ struct firmware_option *options;
+};
+
struct config {
bool autoboot_enabled;
unsigned int autoboot_timeout_sec;
--
2.6.2
More information about the Petitboot
mailing list