[Skiboot] [PATCH v1 5/5] external/opal-prd: opal-prd to support htmgt passthru and attribute override
Neelesh Gupta
neelegup at linux.vnet.ibm.com
Thu Aug 13 02:06:32 AEST 2015
This patch adds the support for htmgt passthru and attribute override
commands. The command format would like something as below:
# opal-prd occ passthru 0x10 0x11 0xac
It will pass the arguments after 'passthru' in an array as input data to
hbrt->htmgt_pass_thru(). The HBRT will return the output data to a buffer
provided by 'opal-prd' of maximum length 256 bytes.
# opal-prd override <file_name_of_binary_blob>
It will read the contents of the binary blob into a buffer and invoke
hbrt->apply_attr_override() with the buffer and size as the input to
the interface.
Signed-off-by: Neelesh Gupta <neelegup at linux.vnet.ibm.com>
---
external/opal-prd/hostboot-interface.h | 35 +++++
external/opal-prd/opal-prd.c | 215 ++++++++++++++++++++++++++++----
external/opal-prd/thunk.S | 2
3 files changed, 228 insertions(+), 24 deletions(-)
diff --git a/external/opal-prd/hostboot-interface.h b/external/opal-prd/hostboot-interface.h
index d186819..31aa6eb 100644
--- a/external/opal-prd/hostboot-interface.h
+++ b/external/opal-prd/hostboot-interface.h
@@ -422,6 +422,41 @@ struct runtime_interfaces {
int (*enable_occ_actuation)(bool i_occActivation);
/**
+ * @brief Apply a set of attribute overrides
+ *
+ * @param[in] pointer to binary override data
+ * @param[in] length of override data (bytes)
+ * @returns 0 on success, or return code if the command failed
+ *
+ * @platform OpenPower
+ */
+ int (*apply_attr_override)(uint8_t *i_data, size_t size);
+
+ /**
+ * @brief Send a pass-through command to HTMGT
+ *
+ * @details This is a blocking call that will send a command to
+ * HTMGT.
+ *
+ * @note If o_rspLength is returned with a non-zero value, the
+ * data at the o_rspData should be dumped to stdout in a
+ * hex dump format.
+ * @note The maximum response data returned will be 4096 bytes
+ *
+ * @param[in] i_cmdLength number of bytes in pass-thru command data
+ * @param[in] *i_cmdData pointer to pass-thru command data
+ * @param[out] *o_rspLength pointer to number of bytes returned in
+ * o_rspData
+ * @param[out] *o_rspData pointer to a 4096 byte buffer that will
+ * contain the response data from the command
+ *
+ * @returns 0 on success, or return code if the command failed
+ * @platform OpenPower
+ */
+ int (*htmgt_pass_thru)(uint16_t i_cmdLength, uint8_t *i_cmdData,
+ uint16_t *o_rspLength, uint8_t *o_rspData);
+
+ /**
* @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)
diff --git a/external/opal-prd/opal-prd.c b/external/opal-prd/opal-prd.c
index 4624996..83edbf6 100644
--- a/external/opal-prd/opal-prd.c
+++ b/external/opal-prd/opal-prd.c
@@ -83,7 +83,9 @@ enum control_msg_type {
CONTROL_MSG_DISABLE_OCCS = 0x01,
CONTROL_MSG_TEMP_OCC_RESET = 0x02,
CONTROL_MSG_TEMP_OCC_ERROR = 0x03,
+ CONTROL_MSG_HTMGT_PASSTHRU = 0x04,
CONTROL_MSG_RUN_CMD = 0x10,
+ CONTROL_MSG_ATTR_OVERRIDE = 0x20,
};
@@ -186,6 +188,22 @@ static void pr_log_nocall(const char *name)
pr_log(LOG_WARNING, "HBRT: Call %s not provided", name);
}
+static void pr_log_stream(const uint8_t *data, uint32_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (i % 16 == 0)
+ printf("\n");
+ else if(i % 4 == 0)
+ printf(" ");
+
+ printf("%02x", data[i]);
+ }
+
+ printf("\n");
+}
+
static void pr_log_daemon_init(void)
{
if (ctx->use_syslog) {
@@ -208,6 +226,9 @@ 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);
+extern int call_htmgt_pass_thru(uint16_t i_cmdLength, uint8_t *i_cmdData,
+ uint16_t *o_rspLength, uint8_t *o_rspData);
+extern int call_apply_attr_override(uint8_t *i_data, size_t size);
void hservice_puts(const char *str)
{
@@ -1066,7 +1087,7 @@ static void handle_prd_control_run_cmd(struct control_msg *send_msg,
char *runcmd_output, *s;
const char **argv;
int i, argc;
- size_t size;
+ size_t size = 0;
if (!hservice_runtime->run_command) {
pr_log_nocall("run_command");
@@ -1111,6 +1132,44 @@ static void handle_prd_control_run_cmd(struct control_msg *send_msg,
}
}
+static void handle_prd_control_htmgt_passthru(struct control_msg *send_msg,
+ struct control_msg *recv_msg)
+{
+ uint16_t rsp_len;
+
+
+ if (!hservice_runtime->htmgt_pass_thru) {
+ pr_log_nocall("htmgt_pass_thru");
+ return;
+ }
+
+ pr_debug("CTRL: calling htmgt_pass_thru");
+ send_msg->response = call_htmgt_pass_thru(recv_msg->data_len,
+ recv_msg->data, &rsp_len,
+ send_msg->data);
+ send_msg->data_len = be16toh(rsp_len);
+ if (send_msg->data_len > MAX_CONTROL_MSG_BUF) {
+ pr_log(LOG_ERR, "CTRL: response buffer overrun, data len: %d",
+ send_msg->data_len);
+ send_msg->data_len = MAX_CONTROL_MSG_BUF;
+ }
+
+}
+
+static void handle_prd_control_attr_override(struct control_msg *send_msg,
+ struct control_msg *recv_msg)
+{
+ if (!hservice_runtime->apply_attr_override) {
+ pr_log_nocall("apply_attr_override");
+ return;
+ }
+
+ pr_debug("CTRL: calling apply_attr_override");
+ send_msg->response = call_apply_attr_override(
+ recv_msg->data, recv_msg->data_len);
+ send_msg->data_len = 0;
+}
+
static void handle_prd_control(struct opal_prd_ctx *ctx, int fd)
{
struct control_msg msg, *recv_msg, *send_msg;
@@ -1171,9 +1230,15 @@ static void handle_prd_control(struct opal_prd_ctx *ctx, int fd)
case CONTROL_MSG_TEMP_OCC_ERROR:
handle_prd_control_occ_error(send_msg);
break;
+ case CONTROL_MSG_HTMGT_PASSTHRU:
+ handle_prd_control_htmgt_passthru(send_msg, recv_msg);
+ break;
case CONTROL_MSG_RUN_CMD:
handle_prd_control_run_cmd(send_msg, recv_msg);
break;
+ case CONTROL_MSG_ATTR_OVERRIDE:
+ handle_prd_control_attr_override(send_msg, recv_msg);
+ break;
default:
pr_log(LOG_WARNING, "CTRL: Unknown control message action %d",
recv_msg->type);
@@ -1442,7 +1507,7 @@ static int send_prd_control(struct control_msg *send_msg,
goto out_close;
} else if (rc != (sizeof(*msg) + msg->data_len)) {
- pr_log(LOG_WARNING, "CTRL: Short read from control socket");
+ pr_log(LOG_WARNING, "CTRL: Short read from control socket: %m");
rc = -1;
goto out_close;
}
@@ -1454,31 +1519,57 @@ out_close:
return rc;
}
-static int send_occ_control(struct opal_prd_ctx *ctx, const char *str)
+static int send_occ_control(struct opal_prd_ctx *ctx, int argc, char *argv[])
{
- struct control_msg send_msg, *recv_msg = NULL;
- int rc;
-
- memset(&send_msg, 0, sizeof(send_msg));
+ struct control_msg msg, *send_msg, *recv_msg = NULL;
+ int rc, i;
- if (!strcmp(str, "enable")) {
- send_msg.type = CONTROL_MSG_ENABLE_OCCS;
- } else if (!strcmp(str, "disable")) {
- send_msg.type = CONTROL_MSG_DISABLE_OCCS;
- } else if (!strcmp(str, "reset")) {
- send_msg.type = CONTROL_MSG_TEMP_OCC_RESET;
- } else if (!strcmp(str, "process-error")) {
- send_msg.type = CONTROL_MSG_TEMP_OCC_ERROR;
+ memset(&msg, 0, sizeof(msg));
+
+ if (!strcmp(argv[0], "enable"))
+ msg.type = CONTROL_MSG_ENABLE_OCCS;
+ else if (!strcmp(argv[0], "disable"))
+ msg.type = CONTROL_MSG_DISABLE_OCCS;
+ else if (!strcmp(argv[0], "reset"))
+ msg.type = CONTROL_MSG_TEMP_OCC_RESET;
+ else if (!strcmp(argv[0], "process-error"))
+ msg.type = CONTROL_MSG_TEMP_OCC_ERROR;
+ else if (!strcmp(argv[0], "passthru")) {
+ msg.type = CONTROL_MSG_HTMGT_PASSTHRU;
+ msg.data_len = argc - 1;
} else {
- pr_log(LOG_ERR, "CTRL: Invalid OCC action '%s'", str);
+ pr_log(LOG_ERR, "OCC: Invalid OCC action '%s'", argv[0]);
return -1;
}
- rc = send_prd_control(&send_msg, &recv_msg);
+ send_msg = malloc(sizeof(*send_msg) + msg.data_len);
+ if (!send_msg) {
+ pr_log(LOG_ERR, "CTRL: msg buffer malloc failed: %m");
+ return -1;
+ }
+
+ send_msg->type = msg.type;
+ send_msg->data_len = msg.data_len;
+ if (send_msg->type == CONTROL_MSG_HTMGT_PASSTHRU) {
+ for (i = 0; i < (argc - 1); i++) {
+ if (ctx->debug) {
+ pr_debug("CTRL: run command arguments:");
+ pr_debug("argv[%d] = %s", i, argv[i]);
+ }
+ sscanf(argv[i + 1], "%hhx", &send_msg->data[i]);
+ }
+ }
+
+ rc = send_prd_control(send_msg, &recv_msg);
+ free(send_msg);
if (recv_msg) {
if (recv_msg->response || ctx->debug)
- pr_debug("CTRL: OCC action %s returned status %d", str,
- recv_msg->response);
+ pr_debug("CTRL: OCC action %s returned status %d",
+ argv[0], recv_msg->response);
+ if (recv_msg->type == CONTROL_MSG_HTMGT_PASSTHRU &&
+ !recv_msg->response && recv_msg->data_len)
+ pr_log_stream(recv_msg->data, recv_msg->data_len);
+
free(recv_msg);
}
@@ -1532,13 +1623,69 @@ static int send_run_command(struct opal_prd_ctx *ctx, int argc, char *argv[])
return rc;
}
+static int send_attr_override(struct opal_prd_ctx *ctx, uint32_t argc,
+ char *argv[])
+{
+ struct control_msg *send_msg, *recv_msg = NULL;
+ struct stat statbuf;
+ size_t sz;
+ FILE *fd;
+ int rc;
+
+ rc = stat(argv[0], &statbuf);
+ if (rc) {
+ pr_log(LOG_ERR, "CTRL: stat() failed on the file: %m");
+ return -1;
+ }
+
+ send_msg = malloc(sizeof(*send_msg) + statbuf.st_size);
+ if (!send_msg) {
+ pr_log(LOG_ERR, "CTRL: msg buffer malloc failed: %m");
+ return -1;
+ }
+
+ send_msg->type = CONTROL_MSG_ATTR_OVERRIDE;
+ send_msg->data_len = statbuf.st_size;
+
+ fd = fopen(argv[0], "r");
+ if (!fd) {
+ pr_log(LOG_NOTICE, "CTRL: can't open %s: %m", argv[0]);
+ rc = -1;
+ goto out_free;
+ }
+
+ sz = fread(send_msg->data, 1, send_msg->data_len, fd);
+ fclose(fd);
+ if (sz != statbuf.st_size) {
+ pr_log(LOG_ERR, "CTRL: short read from the file");
+ rc = -1;
+ goto out_free;
+ }
+
+ rc = send_prd_control(send_msg, &recv_msg);
+ if (recv_msg) {
+ if (recv_msg->response || ctx->debug)
+ pr_debug("CTRL: attribute override returned status %d",
+ recv_msg->response);
+ free(recv_msg);
+ }
+
+out_free:
+ free(send_msg);
+ return rc;
+}
+
+/* TODO usage */
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 occ passthru [1st byte] [2nd byte]..[nth byte]\n",
+ progname);
printf("\t%s run [arg 0] [arg 1]..[arg n]\n", progname);
+ printf("\t%s override <binary_blob>\n", progname);
printf("\n");
printf("Options:\n"
"\t--debug verbose logging for debug information\n"
@@ -1568,6 +1715,7 @@ enum action {
ACTION_RUN_DAEMON,
ACTION_OCC_CONTROL,
ACTION_RUN_COMMAND,
+ ACTION_ATTR_OVERRIDE,
};
static int parse_action(const char *str, enum action *action)
@@ -1587,6 +1735,11 @@ static int parse_action(const char *str, enum action *action)
return 0;
}
+ if (!strcmp(str, "override")) {
+ *action = ACTION_ATTR_OVERRIDE;
+ return 0;
+ }
+
pr_log(LOG_ERR, "CTRL: unknown argument '%s'", str);
return -1;
}
@@ -1644,18 +1797,20 @@ int main(int argc, char *argv[])
action = ACTION_RUN_DAEMON;
}
- if (action == ACTION_RUN_DAEMON) {
+ switch (action) {
+ case ACTION_RUN_DAEMON:
rc = run_prd_daemon(ctx);
-
- } else if (action == ACTION_OCC_CONTROL) {
+ break;
+ case ACTION_OCC_CONTROL:
if (optind + 1 >= argc) {
pr_log(LOG_ERR, "CTRL: occ command requires "
"an argument");
return EXIT_FAILURE;
}
- rc = send_occ_control(ctx, argv[optind + 1]);
- } else if (action == ACTION_RUN_COMMAND) {
+ rc = send_occ_control(ctx, argc - optind - 1, &argv[optind + 1]);
+ break;
+ case ACTION_RUN_COMMAND:
if (optind + 1 >= argc) {
pr_log(LOG_ERR, "CTRL: run command requires "
"argument(s)");
@@ -1663,6 +1818,18 @@ int main(int argc, char *argv[])
}
rc = send_run_command(ctx, argc - optind - 1, &argv[optind + 1]);
+ break;
+ case ACTION_ATTR_OVERRIDE:
+ if (optind + 1 >= argc) {
+ pr_log(LOG_ERR, "CTRL: attribute override command "
+ "requires an argument");
+ return EXIT_FAILURE;
+ }
+
+ rc = send_attr_override(ctx, argc - optind - 1, &argv[optind + 1]);
+ break;
+ default:
+ break;
}
return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
diff --git a/external/opal-prd/thunk.S b/external/opal-prd/thunk.S
index 3828534..f259ba2 100644
--- a/external/opal-prd/thunk.S
+++ b/external/opal-prd/thunk.S
@@ -90,6 +90,8 @@ call_##name: ;\
CALL_THUNK(handle_attns, 9)
CALL_THUNK(process_occ_reset, 10)
CALL_THUNK(enable_occ_actuation, 11)
+ CALL_THUNK(apply_attr_override, 12)
+ CALL_THUNK(htmgt_pass_thru, 13)
CALL_THUNK(run_command, 14)
.globl call_hbrt_init
More information about the Skiboot
mailing list