[RFC PATCH 1/7] lib: Add types for platform attributes

Samuel Mendoza-Jonas sam.mj at au1.ibm.com
Mon Nov 30 14:13:14 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