[Skiboot] [PATCH RFC 4/5] external/opal-prd: Add 'run' option to execute HBRT commands

Neelesh Gupta neelegup at linux.vnet.ibm.com
Wed Jul 29 02:44:04 AEST 2015


From: Vaidyanathan Srinivasan <svaidy at linux.vnet.ibm.com>

opal-prd client to accept run command and pass it as-is to hbrt.

Example:
opal-prd -d run test hbrt -t 1 -c "good cmd"
argv[0] = test
argv[1] = hbrt
argv[2] = -t
argv[3] = 1
argv[4] = -c
argv[5] = good cmd

Above argc/argv passed to hbrt->run_command() and result out string
sent to the console.

Updates from:
  Neelesh Gupta <neelegup at linux.vnet.ibm.com>

Signed-off-by: Vaidyanathan Srinivasan <svaidy at linux.vnet.ibm.com>
Signed-off-by: Neelesh Gupta <neelegup at linux.vnet.ibm.com>
---
 external/opal-prd/hostboot-interface.h |   11 ++
 external/opal-prd/opal-prd.c           |  189 +++++++++++++++++++++++++++++---
 external/opal-prd/thunk.S              |    1 
 3 files changed, 186 insertions(+), 15 deletions(-)

diff --git a/external/opal-prd/hostboot-interface.h b/external/opal-prd/hostboot-interface.h
index a518f50..d186819 100644
--- a/external/opal-prd/hostboot-interface.h
+++ b/external/opal-prd/hostboot-interface.h
@@ -421,6 +421,17 @@ struct runtime_interfaces {
 	 */
 	int (*enable_occ_actuation)(bool i_occActivation);
 
+	/**
+	 * @brief	Execute an arbitrary command inside Hostboot Runtime
+	 * @param[in]	Number of arguments (standard C args)
+	 * @param[in]	Array of argument values (standard C args)
+	 * @param[out]	Response message (NULL terminated), memory allocated
+	 *		by hbrt, if o_outString is NULL then no response will
+	 *		be sent
+	 * @return	0 on success, else error code
+	 */
+	int (*run_command)(int argc, const char **argv, char **o_outString);
+
 	/* Reserve some space for future growth. */
 	void (*reserved[32])(void);
 };
diff --git a/external/opal-prd/opal-prd.c b/external/opal-prd/opal-prd.c
index 4940da4..c477602 100644
--- a/external/opal-prd/opal-prd.c
+++ b/external/opal-prd/opal-prd.c
@@ -83,14 +83,27 @@ enum control_msg_type {
 	CONTROL_MSG_DISABLE_OCCS	= 0x01,
 	CONTROL_MSG_TEMP_OCC_RESET	= 0x02,
 	CONTROL_MSG_TEMP_OCC_ERROR	= 0x03,
+	CONTROL_MSG_RUN_CMD		= 0x10,
 	CONTROL_MSG_INVALID             = 0xf0,
 };
 
+
 struct control_msg {
-	enum control_msg_type	type;
 	uint64_t		response;
+	enum control_msg_type	type;
+	union {
+		struct {
+			uint32_t	argc;
+			uint32_t	len;
+			char		data[];
+		} run_cmd;
+	};
 };
 
+#define MAX_CONTROL_RUN_CMD_DATA	4096
+#define MAX_CONTROL_RUN_CMD	\
+		(sizeof(struct control_msg) + MAX_CONTROL_RUN_CMD_DATA)
+
 static struct opal_prd_ctx *ctx;
 
 static const char *opal_prd_devnode = "/dev/opal-prd";
@@ -201,6 +214,7 @@ extern void call_process_occ_error (uint64_t i_chipId);
 extern int call_enable_attns(void);
 extern int call_enable_occ_actuation(bool i_occActivation);
 extern void call_process_occ_reset(uint64_t i_chipId);
+extern int call_run_command(int argc, const char **argv, char **o_outString);
 
 void hservice_puts(const char *str)
 {
@@ -1077,41 +1091,121 @@ out:
 	*size = sizeof(*msg);
 }
 
+static void handle_prd_control_run_cmd(struct control_msg *msg, int *size)
+{
+	char *runcmd_output;
+	const char **argv;
+	size_t len;
+	int i;
+
+	if (*size != (sizeof(*msg) + msg->run_cmd.len)) {
+		pr_log(LOG_WARNING, "CTRL: run_command, failed to receive "
+				"control message: %m");
+		goto out;
+	}
+
+	if (!hservice_runtime->run_command) {
+		pr_log_nocall("run_command");
+		goto out;
+	}
+
+	pr_debug("CTRL: run_command, argc:%d, data len:%d\n", msg->run_cmd.argc,
+			msg->run_cmd.len);
+
+	argv = malloc(msg->run_cmd.argc * sizeof(*argv));
+	if (!argv) {
+		pr_log(LOG_ERR, "CTRL: argv buffer malloc failed: %m");
+		goto out;
+	}
+
+	len = 0;
+	for (i = 0; i < msg->run_cmd.argc; i++) {
+		argv[i] = (char *)htobe64((uint64_t)&(msg->run_cmd.data[len]));
+		len += (strlen(&msg->run_cmd.data[len]) + 1);
+	}
+
+	/* Call HBRT */
+	msg->response = call_run_command(msg->run_cmd.argc, argv,
+					 &runcmd_output);
+	runcmd_output = (char *)be64toh((uint64_t)runcmd_output);
+	free(argv);
+
+	if (runcmd_output) {
+		len = strlen(runcmd_output) + 1;
+		if (len > MAX_CONTROL_RUN_CMD)
+			len = MAX_CONTROL_RUN_CMD;
+
+		strncpy(msg->run_cmd.data, runcmd_output, len);
+		*size = sizeof(*msg) + len;
+		free(runcmd_output);
+	} else {
+		strncpy(msg->run_cmd.data, "Null", sizeof("Null"));
+		*size = sizeof(*msg) + strlen("Null") + 1;
+	}
+
+	return;
+
+out:
+	*size = sizeof(*msg);
+}
+
 static void handle_prd_control(struct opal_prd_ctx *ctx, int fd)
 {
-	struct control_msg msg;
+	struct control_msg *msg, invalid_msg;
 	bool enabled = false;
 	int rc, size;
 
-	size = recv(fd, &msg, sizeof(msg), MSG_TRUNC);
-	msg.response = -1;
-	switch (msg.type) {
+	msg = malloc(MAX_CONTROL_RUN_CMD);
+	if (!msg) {
+		pr_log(LOG_ERR, "CTRL: msg buffer malloc failed: %m");
+		msg = &invalid_msg;
+		size = sizeof(*msg);
+		msg->type = CONTROL_MSG_INVALID;
+		goto out_send;
+	}
+
+	size = recv(fd, msg, MAX_CONTROL_RUN_CMD, MSG_TRUNC);
+	if (size < sizeof(*msg)) {
+		pr_log(LOG_WARNING, "CTRL: failed to receive control "
+				"message: %m");
+		msg->type = CONTROL_MSG_INVALID;
+	}
+
+	msg->response = -1;
+	switch (msg->type) {
 	case CONTROL_MSG_ENABLE_OCCS:
 		enabled = true;
 		/* fall through */
 	case CONTROL_MSG_DISABLE_OCCS:
-		handle_prd_control_occ_actuation(&msg, &size, enabled);
+		handle_prd_control_occ_actuation(msg, &size, enabled);
 		break;
 	case CONTROL_MSG_TEMP_OCC_RESET:
-		handle_prd_control_occ_reset(&msg, &size);
+		handle_prd_control_occ_reset(msg, &size);
 		break;
 	case CONTROL_MSG_TEMP_OCC_ERROR:
-		handle_prd_control_occ_error(&msg, &size);
+		handle_prd_control_occ_error(msg, &size);
+		break;
+	case CONTROL_MSG_RUN_CMD:
+		handle_prd_control_run_cmd(msg, &size);
 		break;
 	default:
 		pr_log(LOG_WARNING, "CTRL: Unknown control message action %d",
-				msg.type);
-		msg.type = CONTROL_MSG_INVALID;
-		size = sizeof(msg);
+				msg->type);
+		msg->type = CONTROL_MSG_INVALID;
+		size = sizeof(*msg);
 		break;
 	}
 
-	rc = send(fd, &msg, size, MSG_DONTWAIT | MSG_NOSIGNAL);
+out_send:
+	rc = send(fd, msg, size, MSG_DONTWAIT | MSG_NOSIGNAL);
 	if (rc && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EPIPE))
 		pr_debug("CTRL: control send() returned %d, ignoring failure",
 				rc);
 	else if (rc != size)
 		pr_log(LOG_NOTICE, "CTRL: Failed to send control response: %m");
+
+	if (msg != &invalid_msg)
+		free(msg);
 }
 
 static int run_attn_loop(struct opal_prd_ctx *ctx)
@@ -1355,13 +1449,15 @@ static int send_prd_control(struct control_msg *msg, size_t send_sz,
 	case CONTROL_MSG_DISABLE_OCCS:
 	case CONTROL_MSG_TEMP_OCC_RESET:
 	case CONTROL_MSG_TEMP_OCC_ERROR:
-		if (rc != recv_sz) {
+		if (rc != sizeof(*msg)) {
 			pr_log(LOG_WARNING, "CTRL: Short read from control "
 					"socket");
 			rc = -1;
 			goto out_close;
 		}
 		break;
+	case CONTROL_MSG_RUN_CMD:
+		break;
 	case CONTROL_MSG_INVALID:
 		pr_log(LOG_WARNING, "CTRL: Invalid message type received");
 		break;
@@ -1407,12 +1503,63 @@ static int send_occ_control(struct opal_prd_ctx *ctx, const char *str)
 	return rc;
 }
 
+static int send_run_command(struct opal_prd_ctx *ctx, int argc, char *argv[])
+{
+	struct control_msg *msg;
+	int rc, i, size;
+	uint16_t len;
+
+	msg = malloc(MAX_CONTROL_RUN_CMD);
+	if (!msg) {
+		pr_log(LOG_ERR, "CTRL: msg buffer malloc failed: %m");
+		return -1;
+	}
+
+	memset(msg, 0, MAX_CONTROL_RUN_CMD);
+
+	if (ctx->debug) {
+		for (i=0; i < argc; i++) {
+			pr_debug("CTRL: run command arguments:");
+			pr_debug("argv[%d] = %s", i, argv[i]);
+		}
+	}
+
+	/* Setup message */
+	msg->type = CONTROL_MSG_RUN_CMD;
+	msg->run_cmd.argc = argc;
+	size = 0;
+	for (i = 0; i < argc; i++) {
+		len = strlen(argv[i]) + 1;
+		if ((len + size) > MAX_CONTROL_RUN_CMD_DATA) {
+			pr_log(LOG_ERR, "CTRL: command is too big");
+			rc = -1;
+			goto out_free;
+		}
+
+		strcpy(&msg->run_cmd.data[size], argv[i]);
+		size += len;
+	}
+
+	msg->run_cmd.len = size;
+
+	rc = send_prd_control(msg, sizeof(*msg) + size, MAX_CONTROL_RUN_CMD);
+	if (rc)
+		goto out_free;
+
+	pr_log(LOG_INFO, "Received: %s", msg->run_cmd.data);
+
+out_free:
+	free(msg);
+	return rc;
+}
+
 static void usage(const char *progname)
 {
 	printf("Usage:\n");
 	printf("\t%s [--debug] [--file <hbrt-image>] [--pnor <device>]\n",
 			progname);
 	printf("\t%s occ <enable|disable>\n", progname);
+	printf("\t%s run [arg 0] [arg 1]..[arg n]\n", progname);
 	printf("\n");
 	printf("Options:\n"
 "\t--debug            verbose logging for debug information\n"
@@ -1441,6 +1588,7 @@ static struct option opal_diag_options[] = {
 enum action {
 	ACTION_RUN_DAEMON,
 	ACTION_OCC_CONTROL,
+	ACTION_RUN_COMMAND,
 };
 
 static int parse_action(const char *str, enum action *action)
@@ -1455,6 +1603,11 @@ static int parse_action(const char *str, enum action *action)
 		return 0;
 	}
 
+	if (!strcmp(str, "run")) {
+		*action = ACTION_RUN_COMMAND;
+		return 0;
+	}
+
 	pr_log(LOG_ERR, "CTRL: unknown argument '%s'", str);
 	return -1;
 }
@@ -1516,7 +1669,6 @@ int main(int argc, char *argv[])
 		rc = run_prd_daemon(ctx);
 
 	} else if (action == ACTION_OCC_CONTROL) {
-
 		if (optind + 1 >= argc) {
 			pr_log(LOG_ERR, "CTRL: occ command requires "
 					"an argument");
@@ -1524,8 +1676,15 @@ int main(int argc, char *argv[])
 		}
 
 		rc = send_occ_control(ctx, argv[optind + 1]);
+	} else if (action == ACTION_RUN_COMMAND) {
+		if (optind + 1 >= argc) {
+			pr_log(LOG_ERR, "CTRL: run command requires "
+					"argument(s)");
+			return EXIT_FAILURE;
+		}
+
+		rc = send_run_command(ctx, argc - optind - 1, &argv[optind + 1]);
 	}
 
 	return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }
-
diff --git a/external/opal-prd/thunk.S b/external/opal-prd/thunk.S
index ab1e737..f2dcebd 100644
--- a/external/opal-prd/thunk.S
+++ b/external/opal-prd/thunk.S
@@ -90,6 +90,7 @@ call_##name:					;\
 	CALL_THUNK(handle_attns, 9)
 	CALL_THUNK(process_occ_reset, 10)
 	CALL_THUNK(enable_occ_actuation, 11)
+	CALL_THUNK(run_command, 12)
 
 	.globl call_hbrt_init
 call_hbrt_init:



More information about the Skiboot mailing list