From patchwork Wed Aug 12 16:06:09 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Neelesh Gupta X-Patchwork-Id: 506690 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4AD1414018C for ; Thu, 13 Aug 2015 02:07:11 +1000 (AEST) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 300DF1A1E26 for ; Thu, 13 Aug 2015 02:07:11 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Received: from e28smtp04.in.ibm.com (e28smtp04.in.ibm.com [122.248.162.4]) (using TLSv1 with cipher CAMELLIA256-SHA (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id C42CE1A1E57 for ; Thu, 13 Aug 2015 02:06:19 +1000 (AEST) Received: from /spool/local by e28smtp04.in.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 12 Aug 2015 21:36:17 +0530 Received: from d28dlp01.in.ibm.com (9.184.220.126) by e28smtp04.in.ibm.com (192.168.1.134) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Wed, 12 Aug 2015 21:36:16 +0530 X-Helo: d28dlp01.in.ibm.com X-MailFrom: neelegup@linux.vnet.ibm.com X-RcptTo: skiboot@lists.ozlabs.org Received: from d28relay04.in.ibm.com (d28relay04.in.ibm.com [9.184.220.61]) by d28dlp01.in.ibm.com (Postfix) with ESMTP id 76C7FE004C for ; Wed, 12 Aug 2015 21:40:37 +0530 (IST) Received: from d28av03.in.ibm.com (d28av03.in.ibm.com [9.184.220.65]) by d28relay04.in.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id t7CG6G2266322432 for ; Wed, 12 Aug 2015 21:36:16 +0530 Received: from d28av03.in.ibm.com (localhost [127.0.0.1]) by d28av03.in.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id t7CG6ISN011981 for ; Wed, 12 Aug 2015 21:36:18 +0530 Received: from localhost.localdomain ([9.124.88.220]) by d28av03.in.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id t7CG6Cka011664; Wed, 12 Aug 2015 21:36:15 +0530 From: Neelesh Gupta To: skiboot@lists.ozlabs.org Date: Wed, 12 Aug 2015 21:36:09 +0530 Message-ID: <20150812160529.28758.34878.stgit@localhost.localdomain> In-Reply-To: <20150812155923.28758.96941.stgit@localhost.localdomain> References: <20150812155923.28758.96941.stgit@localhost.localdomain> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 15081216-0013-0000-0000-000006C4B55A Subject: [Skiboot] [PATCH v1 4/5] external/opal-prd: Add 'run' option to execute HBRT commands X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dcrowell@us.ibm.com, whs@us.ibm.com, cjcain@us.ibm.com Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" From: Vaidyanathan Srinivasan 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 Signed-off-by: Vaidyanathan Srinivasan Signed-off-by: Neelesh Gupta --- 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 ] [--pnor ]\n", progname); printf("\t%s occ \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: