[Skiboot] [PATCH RFC 08/12] opal-prd: Add support for variable-sized messages

Jeremy Kerr jk at ozlabs.org
Thu May 25 17:05:51 AEST 2017


With the introductuion of the opaque firmware channel, we want to
support variable-sized messages. Rather than expecting to read an
entire 'struct opal_prd_msg' in one read() call, we can split this
over mutiple reads, potentially expanding our message buffer.

Signed-off-by: Jeremy Kerr <jk at ozlabs.org>
---
 external/opal-prd/opal-prd.c | 67 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 55 insertions(+), 12 deletions(-)

diff --git a/external/opal-prd/opal-prd.c b/external/opal-prd/opal-prd.c
index c7cdc61..ebd6c0f 100644
--- a/external/opal-prd/opal-prd.c
+++ b/external/opal-prd/opal-prd.c
@@ -80,6 +80,8 @@ struct opal_prd_ctx {
 	char			*hbrt_file_name;
 	bool			use_syslog;
 	bool			expert_mode;
+	struct opal_prd_msg	*msg;
+	size_t			msg_alloc_len;
 	void			(*vlog)(int, const char *, va_list);
 };
 
@@ -1225,41 +1227,76 @@ static int handle_msg_occ_reset(struct opal_prd_ctx *ctx,
 
 static int handle_prd_msg(struct opal_prd_ctx *ctx)
 {
-	struct opal_prd_msg msg;
+	struct opal_prd_msg *msg;
 	int size;
 	int rc;
 
-	rc = read(ctx->fd, &msg, sizeof(msg));
+	msg = ctx->msg;
+
+	rc = read(ctx->fd, msg, ctx->msg_alloc_len);
 	if (rc < 0 && errno == EAGAIN)
 		return -1;
 
-	if (rc != sizeof(msg)) {
-		pr_log(LOG_WARNING, "FW: Error reading events from OPAL: %m");
+	/* we need at least enough for the message header... */
+	if (rc < 0) {
+		pr_log(LOG_WARNING, "FW: error reading from firmware: %m");
+		return -1;
+	}
+
+	if (rc < sizeof(msg->hdr)) {
+		pr_log(LOG_WARNING, "FW: short message read from firmware");
 		return -1;
 	}
 
-	size = htobe16(msg.hdr.size);
-	if (size < sizeof(msg)) {
+	/* ... and for the reported message size to be sane */
+	size = htobe16(msg->hdr.size);
+	if (size < sizeof(msg->hdr)) {
 		pr_log(LOG_ERR, "FW: Mismatched message size "
 				"between opal-prd and firmware "
 				"(%d from FW, %zd expected)",
-				size, sizeof(msg));
+				size, sizeof(msg->hdr));
 		return -1;
 	}
 
-	switch (msg.hdr.type) {
+	/* expand our message buffer if necessary... */
+	if (size > ctx->msg_alloc_len) {
+		ctx->msg = msg = realloc(ctx->msg, size);
+		ctx->msg_alloc_len = size;
+	}
+
+	/* ... and complete the read */
+	if (size > rc) {
+		size_t pos;
+
+		for (pos = rc; pos < size;) {
+			rc = read(ctx->fd, msg + pos, size - pos);
+
+			if (rc < 0 && errno == EAGAIN)
+				continue;
+
+			if (rc <= 0) {
+				pr_log(LOG_WARNING,
+					"FW: error reading from firmware: %m");
+				return -1;
+			}
+
+			pos += rc;
+		}
+	}
+
+	switch (msg->hdr.type) {
 	case OPAL_PRD_MSG_TYPE_ATTN:
-		rc = handle_msg_attn(ctx, &msg);
+		rc = handle_msg_attn(ctx, msg);
 		break;
 	case OPAL_PRD_MSG_TYPE_OCC_RESET:
-		rc = handle_msg_occ_reset(ctx, &msg);
+		rc = handle_msg_occ_reset(ctx, msg);
 		break;
 	case OPAL_PRD_MSG_TYPE_OCC_ERROR:
-		rc = handle_msg_occ_error(ctx, &msg);
+		rc = handle_msg_occ_error(ctx, msg);
 		break;
 	default:
 		pr_log(LOG_WARNING, "Invalid incoming message type 0x%x",
-				msg.hdr.type);
+				msg->hdr.type);
 		return -1;
 	}
 
@@ -1621,6 +1658,10 @@ static int run_prd_daemon(struct opal_prd_ctx *ctx)
 	ctx->fd = -1;
 	ctx->socket = -1;
 
+	/* set up our message buffer */
+	ctx->msg_alloc_len = sizeof(*ctx->msg);
+	ctx->msg = malloc(ctx->msg_alloc_len);
+
 	i2c_init();
 
 #ifdef DEBUG_I2C
@@ -1708,6 +1749,8 @@ out_close:
 		close(ctx->fd);
 	if (ctx->socket != -1)
 		close(ctx->socket);
+	if (ctx->msg)
+		free(ctx->msg);
 	return rc;
 }
 
-- 
2.7.4



More information about the Skiboot mailing list