[Skiboot] [PATCH v1 4/5] external/opal-prd: Add 'run' option to execute HBRT commands
Neelesh Gupta
neelegup at linux.vnet.ibm.com
Thu Aug 13 02:06:09 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 | 239 ++++++++++++++++++++++++++++----
external/opal-prd/thunk.S | 1
3 files changed, 221 insertions(+), 30 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 8f1d6cb..4624996 100644
--- a/external/opal-prd/opal-prd.c
+++ b/external/opal-prd/opal-prd.c
@@ -83,13 +83,20 @@ 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,
};
+
struct control_msg {
enum control_msg_type type;
- uint64_t response;
+ int response;
+ uint32_t argc;
+ uint32_t data_len;
+ uint8_t data[];
};
+#define MAX_CONTROL_MSG_BUF 4096
+
static struct opal_prd_ctx *ctx;
static const char *opal_prd_devnode = "/dev/opal-prd";
@@ -200,6 +207,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)
{
@@ -1021,6 +1029,7 @@ static void handle_prd_control_occ_error(struct control_msg *msg)
pr_debug("CTRL: calling process_occ_error(0)");
call_process_occ_error(0);
+ msg->data_len = 0;
msg->response = 0;
}
@@ -1033,6 +1042,7 @@ static void handle_prd_control_occ_reset(struct control_msg *msg)
pr_debug("CTRL: calling process_occ_reset(0)");
call_process_occ_reset(0);
+ msg->data_len = 0;
msg->response = 0;
}
@@ -1046,51 +1056,144 @@ static void handle_prd_control_occ_actuation(struct control_msg *msg,
pr_debug("CTRL: calling enable_occ_actuation(%s)",
enable ? "true" : "false");
+ msg->data_len = 0;
msg->response = call_enable_occ_actuation(enable);
}
+static void handle_prd_control_run_cmd(struct control_msg *send_msg,
+ struct control_msg *recv_msg)
+{
+ char *runcmd_output, *s;
+ const char **argv;
+ int i, argc;
+ size_t size;
+
+ if (!hservice_runtime->run_command) {
+ pr_log_nocall("run_command");
+ return;
+ }
+
+ argc = recv_msg->argc;
+ pr_debug("CTRL: run_command, argc:%d\n", argc);
+
+ argv = malloc(argc * sizeof(*argv));
+ if (!argv) {
+ pr_log(LOG_ERR, "CTRL: argv buffer malloc failed: %m");
+ return;
+ }
+
+ s = (char *)recv_msg->data;
+ for (i = 0; i < argc; i++) {
+ argv[i] = (char *)htobe64((uint64_t)&s[size]);
+ size += (strlen(&s[size]) + 1);
+ }
+
+ /* Call HBRT */
+ send_msg->response = call_run_command(argc, argv, &runcmd_output);
+ runcmd_output = (char *)be64toh((uint64_t)runcmd_output);
+ free(argv);
+
+ s = (char *)send_msg->data;
+ if (runcmd_output) {
+ size = strlen(runcmd_output);
+ if (size >= MAX_CONTROL_MSG_BUF) {
+ pr_log(LOG_WARNING, "CTRL: output message truncated");
+ runcmd_output[MAX_CONTROL_MSG_BUF] = '\0';
+ size = MAX_CONTROL_MSG_BUF;
+ }
+
+ strcpy(s, runcmd_output);
+ send_msg->data_len = size + 1;
+ free(runcmd_output);
+ } else {
+ strcpy(s, "Null");
+ send_msg->data_len = strlen("Null") + 1;
+ }
+}
+
static void handle_prd_control(struct opal_prd_ctx *ctx, int fd)
{
- struct control_msg msg;
+ struct control_msg msg, *recv_msg, *send_msg;
bool enabled = false;
- int rc;
+ int rc, size;
+
+ /* Default reply, in the error path */
+ send_msg = &msg;
- rc = recv(fd, &msg, sizeof(msg), MSG_TRUNC);
+ /* Peek into the socket to ascertain the size of the available data */
+ rc = recv(fd, &msg, sizeof(msg), MSG_PEEK);
if (rc != sizeof(msg)) {
pr_log(LOG_WARNING, "CTRL: failed to receive control "
"message: %m");
msg.response = -1;
+ msg.data_len = 0;
goto out_send;
}
+ size = sizeof(*recv_msg) + msg.data_len;
+
+ /* Default reply, in the error path */
+ msg.data_len = 0;
msg.response = -1;
- switch (msg.type) {
+
+ recv_msg = malloc(size);
+ if (!recv_msg) {
+ pr_log(LOG_ERR, "CTRL: message buffer malloc failed: %m");
+ goto out_send;
+ }
+
+ rc = recv(fd, recv_msg, size, MSG_TRUNC);
+ if (rc != size) {
+ pr_log(LOG_WARNING, "CTRL: failed to receive control "
+ "message: %m");
+ goto out_free_recv;
+ }
+
+ send_msg = malloc(sizeof(*send_msg) + MAX_CONTROL_MSG_BUF);
+ if (!send_msg) {
+ pr_log(LOG_ERR, "CTRL: message buffer malloc failed: %m");
+ send_msg = &msg;
+ goto out_free_recv;
+ }
+
+ send_msg->type = recv_msg->type;
+ send_msg->response = -1;
+ switch (recv_msg->type) {
case CONTROL_MSG_ENABLE_OCCS:
enabled = true;
/* fall through */
case CONTROL_MSG_DISABLE_OCCS:
- handle_prd_control_occ_actuation(&msg, enabled);
+ handle_prd_control_occ_actuation(send_msg, enabled);
break;
case CONTROL_MSG_TEMP_OCC_RESET:
- handle_prd_control_occ_reset(&msg);
+ handle_prd_control_occ_reset(send_msg);
break;
case CONTROL_MSG_TEMP_OCC_ERROR:
- handle_prd_control_occ_error(&msg);
+ handle_prd_control_occ_error(send_msg);
+ break;
+ case CONTROL_MSG_RUN_CMD:
+ handle_prd_control_run_cmd(send_msg, recv_msg);
break;
default:
pr_log(LOG_WARNING, "CTRL: Unknown control message action %d",
- msg.type);
+ recv_msg->type);
+ send_msg->data_len = 0;
break;
}
+out_free_recv:
+ free(recv_msg);
out_send:
- /* send a response */
- rc = send(fd, &msg, sizeof(msg), MSG_DONTWAIT | MSG_NOSIGNAL);
+ size = sizeof(*send_msg) + send_msg->data_len;
+ rc = send(fd, send_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 != sizeof(msg))
+ else if (rc != size)
pr_log(LOG_NOTICE, "CTRL: Failed to send control response: %m");
+
+ if (send_msg != &msg)
+ free(send_msg);
}
static int run_attn_loop(struct opal_prd_ctx *ctx)
@@ -1292,10 +1395,12 @@ out_close:
return rc;
}
-static int send_prd_control(struct control_msg *msg)
+static int send_prd_control(struct control_msg *send_msg,
+ struct control_msg **recv_msg)
{
struct sockaddr_un addr;
- int sd, rc;
+ struct control_msg *msg;
+ int sd, rc, size;
sd = socket(AF_UNIX, SOCK_STREAM, 0);
if (!sd) {
@@ -1312,20 +1417,31 @@ static int send_prd_control(struct control_msg *msg)
goto out_close;
}
- rc = send(sd, msg, sizeof(*msg), 0);
- if (rc != sizeof(*msg)) {
+ size = sizeof(*send_msg) + send_msg->data_len;
+ rc = send(sd, send_msg, size, 0);
+ if (rc != size) {
pr_log(LOG_ERR, "CTRL: Failed to send control message: %m");
rc = -1;
goto out_close;
}
/* wait for our reply */
- rc = recv(sd, msg, sizeof(*msg), 0);
+ size = sizeof(*msg) + MAX_CONTROL_MSG_BUF;
+ msg = malloc(size);
+ if (!msg) {
+ pr_log(LOG_ERR, "CTRL: msg buffer malloc failed: %m");
+ rc = -1;
+ goto out_close;
+ }
+
+ *recv_msg = msg;
+
+ rc = recv(sd, msg, size, 0);
if (rc < 0) {
pr_log(LOG_ERR, "CTRL: Failed to receive control message: %m");
goto out_close;
- } else if (rc != sizeof(*msg)) {
+ } else if (rc != (sizeof(*msg) + msg->data_len)) {
pr_log(LOG_WARNING, "CTRL: Short read from control socket");
rc = -1;
goto out_close;
@@ -1340,28 +1456,78 @@ out_close:
static int send_occ_control(struct opal_prd_ctx *ctx, const char *str)
{
- struct control_msg msg;
+ struct control_msg send_msg, *recv_msg = NULL;
int rc;
- memset(&msg, 0, sizeof(msg));
+ memset(&send_msg, 0, sizeof(send_msg));
if (!strcmp(str, "enable")) {
- msg.type = CONTROL_MSG_ENABLE_OCCS;
+ send_msg.type = CONTROL_MSG_ENABLE_OCCS;
} else if (!strcmp(str, "disable")) {
- msg.type = CONTROL_MSG_DISABLE_OCCS;
+ send_msg.type = CONTROL_MSG_DISABLE_OCCS;
} else if (!strcmp(str, "reset")) {
- msg.type = CONTROL_MSG_TEMP_OCC_RESET;
+ send_msg.type = CONTROL_MSG_TEMP_OCC_RESET;
} else if (!strcmp(str, "process-error")) {
- msg.type = CONTROL_MSG_TEMP_OCC_ERROR;
+ send_msg.type = CONTROL_MSG_TEMP_OCC_ERROR;
} else {
pr_log(LOG_ERR, "CTRL: Invalid OCC action '%s'", str);
return -1;
}
- rc = send_prd_control(&msg);
- if (msg.response || ctx->debug)
- pr_debug("CTRL: OCC action %s returned status %ld", str,
- msg.response);
+ rc = send_prd_control(&send_msg, &recv_msg);
+ if (recv_msg) {
+ if (recv_msg->response || ctx->debug)
+ pr_debug("CTRL: OCC action %s returned status %d", str,
+ recv_msg->response);
+ free(recv_msg);
+ }
+
+ return rc;
+}
+
+static int send_run_command(struct opal_prd_ctx *ctx, int argc, char *argv[])
+{
+ struct control_msg *send_msg, *recv_msg = NULL;
+ uint32_t size = 0;
+ int rc, i;
+ char *s;
+
+ if (ctx->debug) {
+ pr_debug("CTRL: run command arguments:");
+ for (i=0; i < argc; i++)
+ pr_debug("argv[%d] = %s", i, argv[i]);
+ }
+
+ for (i = 0; i < argc; i++)
+ size += (strlen(argv[i]) + 1);
+
+ send_msg = malloc(sizeof(*send_msg) + size);
+ if (!send_msg) {
+ pr_log(LOG_ERR, "CTRL: msg buffer malloc failed: %m");
+ return -1;
+ }
+
+ /* Setup message */
+ send_msg->type = CONTROL_MSG_RUN_CMD;
+ send_msg->argc = argc;
+ send_msg->data_len = size;
+ s = (char *)send_msg->data;
+ for (i = 0; i < argc; i++) {
+ strcpy(s, argv[i]);
+ s = s + strlen(argv[i]) + 1;
+ }
+
+ rc = send_prd_control(send_msg, &recv_msg);
+ free(send_msg);
+ if (recv_msg) {
+ if (!rc)
+ pr_log(LOG_INFO, "Received: %s", recv_msg->data);
+
+ if (recv_msg->response || ctx->debug)
+ pr_debug("CTRL: run command returned status %d",
+ recv_msg->response);
+ free(recv_msg);
+ }
return rc;
}
@@ -1372,6 +1538,7 @@ static void usage(const char *progname)
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"
@@ -1400,6 +1567,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)
@@ -1414,6 +1582,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;
}
@@ -1475,7 +1648,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");
@@ -1483,8 +1655,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..3828534 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, 14)
.globl call_hbrt_init
call_hbrt_init:
More information about the Skiboot
mailing list