summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2020-03-18 17:46:53 -0700
committerCommit Bot <commit-bot@chromium.org>2020-03-31 23:24:38 +0000
commita795c626a156a92813e7992bc14c764b1ae1f994 (patch)
tree45d3a3fdb92e57eb200c0f3b1ee13838c05d5347
parent804d65e5fd86057e78c0d0b5f6139172d20b8207 (diff)
downloadchrome-ec-a795c626a156a92813e7992bc14c764b1ae1f994.tar.gz
cmsg.c, console packet mode driver
This patch adds a console driver for packet mode. The driver processes information prepared by util_precomplie.py when processing printf invocations in the source code. Each invocation is replaced by a cmsgX function, where X is the number of format arguments. cmsgX functions prepare an array of parameters of size X and invoke a common function, passing it the array and an integer value, consisting of up to 8 4 bit fields, describing the parameters. Since both console drivers need to be able to filter logical console channels, the channel_mask variable is made global. BUG=b:149964350 TEST=with the rest of patches applied and packet mode enabled, verified proper operation of both Cr50 consoles (USB and UART). Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Change-Id: I1f6ef5ea50bffbe14d3e3850fff0191c54f37033 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2113931 Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--common/build.mk1
-rw-r--r--common/cmsg.c393
-rw-r--r--common/console_output.c2
-rw-r--r--include/console.h35
4 files changed, 428 insertions, 3 deletions
diff --git a/common/build.mk b/common/build.mk
index 747b63053f..095ad401a1 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -68,6 +68,7 @@ common-$(CONFIG_DPTF)+=dptf.o
common-$(CONFIG_EC_EFS_SUPPORT)+=ec_comm.o ec_efs.o
common-$(CONFIG_EC_EC_COMM_MASTER)+=ec_ec_comm_master.o
common-$(CONFIG_EC_EC_COMM_SLAVE)+=ec_ec_comm_slave.o
+common-$(CONFIG_EXTRACT_PRINTF_STRINGS)+=cmsg.o
common-$(CONFIG_HOSTCMD_ESPI)+=espi.o
common-$(CONFIG_EXTENSION_COMMAND)+=extension.o
common-$(CONFIG_EXTPOWER_GPIO)+=extpower_gpio.o
diff --git a/common/cmsg.c b/common/cmsg.c
new file mode 100644
index 0000000000..3c65e10d42
--- /dev/null
+++ b/common/cmsg.c
@@ -0,0 +1,393 @@
+/* Copyright 2020 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Packetized console interface.
+ */
+
+#include "console.h"
+#include "crc8.h"
+#include "task.h"
+#include "timer.h"
+#include "uart.h"
+#include "usb_console.h"
+#include "util.h"
+
+#define CONSOLE_PACKET_HEADER_LEN 13
+#define CONSOLE_PACKET_MAGIC 0xc2
+#define CONSOLE_PACKET_END 0xc1
+
+/*
+ * Packet header structure was borrowed from the Acropora project and adopted
+ * for use in Cr50.
+ */
+struct console_packet {
+ /* Magic number = CONSOLE_PACKET_MAGIC */
+ uint8_t magic;
+
+ /*
+ * Packet sequence number, incremented each time sender sends a packet.
+ * So receiver can detect small numbers of corrupt/dropped packets.
+ */
+ uint8_t sequence : 4;
+
+ /* Set if the sender had to discard packets due to buffer overflow. */
+ uint8_t overflow : 1;
+ uint8_t dummy : 3;
+
+ /* Channel; values from enum console_channel */
+ uint8_t channel;
+
+ /* Bottom 48 bits of system time; enough for 8 years @ 1 us */
+ uint8_t timestamp[6];
+
+ /*
+ * Length of variable-length section in bytes, not including the
+ * packet end trailer.
+ */
+ uint8_t data_len;
+
+ uint16_t str_index; /* Index of the string in the database. */
+
+ /* Header checksum */
+ uint8_t crc;
+
+ /* Fixed length header to here. */
+
+ /*
+ * Followed by variable-length data, if data_len > 0.
+ *
+ * params: 1-8 of objects matching the format of the string indexed by
+ * 'str_index' above.
+ *
+ * CONSOLE_PACKET_END, as a sanity-check that we haven't dropped
+ * anything. A checksum or CRC would be kinda expensive for debug
+ * data. Note that it is not present if data_len == 0.
+ */
+} __packed;
+
+BUILD_ASSERT(sizeof(struct console_packet) == CONSOLE_PACKET_HEADER_LEN);
+
+/*
+ * Types of parameters recognized by util/util_precompile.py when processing
+ * format string in .E files.
+ *
+ * When invoking the cmsgX functions all parameters are typecasted to
+ * uintptr_t, and as such must fit into 4 bytes (on the 32 bit machine
+ * cortex-m is).
+ */
+enum param_types {
+ PARAM_INT = 1,
+ /* Parameter is a pointer to an 8 byte integer. */
+ PARAM_LONG = 2,
+ /* Parameter is a pointer to an ASCIIZ string. */
+ PARAM_STRING = 3,
+ PARAM_PTR = 4,
+ PARAM_HEX_BUF = 5,
+ /*
+ * Parameter is an int, the number of the function name string in the
+ * dictionary prepared by util_precompile.py. Since it is passed as a
+ * %s parameter, to allow the terminal to tell the difference this
+ * value is sent as 5 bytes, first 0xff and then the function number.
+ */
+ PARAM_FUNC_NAME = 6,
+ /*
+ * Parameter is a pointer to a 8 byte value, unless the parameter is
+ * zero, in which case current time is used.
+ */
+ PARAM_TIMESTAMP = 7,
+};
+
+/*
+ * copy_params: copy actual parameter values into the console channel.
+ *
+ * This function is processing parameters 'on the fly' and sends them into the
+ * console channel. There are two channels (uart and usb), so this fucnction
+ * is called twice. It could be called once and save the parameters in a
+ * buffer, but the buffer would have to be allocated on the stack, this
+ * remains under consideration.
+ *
+ * mask is a set of 4 bit fields (enum param_types),
+ * params[] includes as many values as there are non-zero fields in mask.
+ * cmpuc is a pointer to the function which actually sends data.
+ */
+static void copy_params(uint32_t mask, uintptr_t params[],
+ int (*cmputc)(const char *out, int len))
+{
+ enum param_types param_type;
+ uintptr_t param;
+ uint64_t t;
+
+ while ((param_type = mask & 0xf) != 0) {
+ const uint8_t ff = 0xff;
+
+ param = *params++;
+ mask >>= 4;
+
+ switch (param_type) {
+ case PARAM_FUNC_NAME:
+ cmputc(&ff, sizeof(ff));
+ /* fallthrough. */
+ case PARAM_INT:
+ case PARAM_PTR:
+ cmputc((const void *)&param, sizeof(param));
+ break;
+
+ case PARAM_LONG:
+ cmputc((const void *)param, sizeof(uint64_t));
+ break;
+
+ case PARAM_TIMESTAMP:
+ if (param == 0)
+ /*
+ * Terminal will use timestamp saved in the
+ * packet header.
+ */
+ t = 0;
+ else
+ t = get_time().val;
+ cmputc((const void *)&t, sizeof(t));
+ break;
+
+ case PARAM_HEX_BUF: {
+ const struct hex_buffer_params *hbp =
+ (const struct hex_buffer_params *)param;
+ cmputc((const void *)&hbp->size, sizeof(hbp->size));
+ cmputc((const void *)hbp->buffer, hbp->size);
+ break;
+ }
+
+ case PARAM_STRING:
+ /* Include trailing zero. */
+ cmputc((const void *)param,
+ strlen((const char *)param) + 1);
+ }
+ }
+}
+
+/* A structure describing a communication channel and its state. */
+struct packet_channel {
+ /* Function to send data on the channel. */
+ int (*cmputc)(const char *out, int len);
+ /*
+ * Function to check how much room is left in the channel buffer, the
+ * packet is not sent if it won't fit.
+ */
+ size_t (*room_check)(void);
+ /*
+ * Channel run time context - sequence number to be used on the next
+ * packet and the indicator of channel overflow when packet had to be
+ * dropped because there was no room in the channel buffer.
+ */
+ uint8_t seq_num;
+ uint8_t overflow;
+};
+
+/*
+ * ship_packet: send a console packet on a channel.
+ *
+ * cpp - pointer to a partially filled packet header.
+ * mask - a set of 4 bit parameter descriptions
+ * params - an array of parameters matching the mask fields
+ * pc - pointer to the packet channel structure used to send the packet.
+ *
+ * Returns overflow error if there is no room in the channel buffer to send
+ * the packet.
+ */
+static int ship_packet(struct console_packet *cpp, uint32_t mask,
+ uintptr_t params[], struct packet_channel *pc)
+{
+ pc->seq_num++;
+
+ /* See if there is room to send this packet. */
+ if (pc->room_check() < (sizeof(*cpp) + cpp->data_len + 1)) {
+ pc->overflow = 1;
+ return EC_ERROR_OVERFLOW;
+ }
+
+ cpp->sequence = pc->seq_num;
+ cpp->overflow = pc->overflow & 1;
+ pc->overflow = 0;
+
+ /* Now crc can be calculated. */
+ cpp->crc = crc8((void *)cpp, sizeof(*cpp) - sizeof(cpp->crc));
+ pc->cmputc((void *)cpp, sizeof(*cpp));
+ if (mask) {
+ const char pe = CONSOLE_PACKET_END;
+
+ copy_params(mask, params, pc->cmputc);
+ pc->cmputc(&pe, 1);
+ }
+ return EC_SUCCESS;
+}
+
+/*
+ * zz_msg - send console packets on both console physical channels.
+ *
+ * Calculate the size of the packet (needs to be done in advance to decide if
+ * there is enough room in the channel buffer) and then call channel specific
+ * transmit functions.
+ *
+ * chan - logical console channel, the one which can be turned and off by
+ * the cli 'channel' command.
+ * str_index - index of the original format string in the list of strings
+ * prepared by util_precompile.py
+ * fmt_mask is a set of 4 bit fields (enum param_types),
+ * params[] includes as many values as there are non-zero fields in mask.
+ *
+ * Returns overflow error if either or both channels could not fit the packet.
+ */
+static int zz_msg(enum console_channel chan, int str_index, uint32_t fmt_mask,
+ uintptr_t params[])
+{
+ uint16_t total_param_length = 0;
+ enum param_types param_type;
+ int param_count = 0;
+ uint64_t t;
+ uint32_t mask_copy;
+ int rv_uart;
+ int rv_usb;
+ static struct packet_channel pcs[] = {
+ { .cmputc = uart_put, .room_check = uart_buffer_room },
+ { .cmputc = usb_put, .room_check = usb_buffer_room }
+ };
+
+ struct console_packet cp = {
+ .magic = CONSOLE_PACKET_MAGIC,
+ };
+
+ if (!(CC_MASK(chan) & channel_mask))
+ return EC_SUCCESS;
+
+ /* Let's scan the mask to see how many parameters there are. */
+ mask_copy = fmt_mask;
+ param_type = mask_copy & 0xf;
+ while (param_type) {
+ switch (param_type) {
+ case PARAM_FUNC_NAME:
+ total_param_length += 1;
+ /* Falltrhough. */
+ case PARAM_INT:
+ case PARAM_PTR:
+ total_param_length += sizeof(uintptr_t);
+ break;
+ case PARAM_LONG:
+ case PARAM_TIMESTAMP:
+ total_param_length += sizeof(uint64_t);
+ break;
+ case PARAM_HEX_BUF: {
+ const struct hex_buffer_params *hbp =
+ (void *)params[param_count];
+
+ total_param_length += hbp->size + sizeof(hbp->size);
+ break;
+ }
+
+ case PARAM_STRING:
+ /* Include trailing zero. */
+ total_param_length +=
+ strlen((const char *)params[param_count]) + 1;
+ break;
+
+ default:
+ /* TODO(vbendeb): add panic message generation. */
+ break;
+ }
+
+ mask_copy >>= 4;
+ param_type = mask_copy & 0xf;
+ param_count++;
+ }
+
+ cp.channel = chan;
+
+ t = get_time().val;
+ memcpy(cp.timestamp, &t, sizeof(cp.timestamp));
+ cp.str_index = str_index;
+ cp.data_len = total_param_length;
+
+ if (!in_interrupt_context())
+ interrupt_disable();
+
+ rv_uart = ship_packet(&cp, fmt_mask, params, &pcs[0]);
+ rv_usb = ship_packet(&cp, fmt_mask, params, &pcs[1]);
+
+ if (!in_interrupt_context())
+ interrupt_enable();
+
+ if (rv_uart != EC_SUCCESS)
+ return rv_uart;
+
+ return rv_usb;
+}
+
+/* Packet mode console interface functions. */
+int cmsg0(enum console_channel chan, int str_index)
+{
+ return zz_msg(chan, str_index, 0, NULL);
+}
+
+int cmsg1(enum console_channel chan, int str_index, uint32_t mask, uintptr_t p1)
+{
+ uintptr_t params[] = { p1 };
+
+ return zz_msg(chan, str_index, mask, params);
+}
+
+int cmsg2(enum console_channel chan, int str_index, uint32_t mask, uintptr_t p1,
+ uintptr_t p2)
+{
+ uintptr_t params[] = { p1, p2 };
+
+ return zz_msg(chan, str_index, mask, params);
+}
+
+int cmsg3(enum console_channel chan, int str_index, uint32_t mask, uintptr_t p1,
+ uintptr_t p2, uintptr_t p3)
+{
+ uintptr_t params[] = { p1, p2, p3 };
+
+ return zz_msg(chan, str_index, mask, params);
+}
+
+int cmsg4(enum console_channel chan, int str_index, uint32_t mask, uintptr_t p1,
+ uintptr_t p2, uintptr_t p3, uintptr_t p4)
+{
+ uintptr_t params[] = { p1, p2, p3, p4 };
+
+ return zz_msg(chan, str_index, mask, params);
+}
+
+int cmsg5(enum console_channel chan, int str_index, uint32_t mask, uintptr_t p1,
+ uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5)
+{
+ uintptr_t params[] = { p1, p2, p3, p4, p5 };
+
+ return zz_msg(chan, str_index, mask, params);
+}
+
+int cmsg6(enum console_channel chan, int str_index, uint32_t mask, uintptr_t p1,
+ uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6)
+{
+ uintptr_t params[] = { p1, p2, p3, p4, p5, p6 };
+
+ return zz_msg(chan, str_index, mask, params);
+}
+
+int cmsg7(enum console_channel chan, int str_index, uint32_t mask, uintptr_t p1,
+ uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6,
+ uintptr_t p7)
+{
+ uintptr_t params[] = { p1, p2, p3, p4, p5, p6, p7 };
+
+ return zz_msg(chan, str_index, mask, params);
+}
+
+int cmsg8(enum console_channel chan, int str_index, uint32_t mask, uintptr_t p1,
+ uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6,
+ uintptr_t p7, uintptr_t p8)
+{
+ uintptr_t params[] = { p1, p2, p3, p4, p5, p6, p7, p8 };
+
+ return zz_msg(chan, str_index, mask, params);
+}
diff --git a/common/console_output.c b/common/console_output.c
index 86072d9b62..2fe1ac99a9 100644
--- a/common/console_output.c
+++ b/common/console_output.c
@@ -15,7 +15,7 @@
#ifndef CC_DEFAULT
#define CC_DEFAULT CC_ALL
#endif
-static uint32_t channel_mask = CC_DEFAULT;
+uint32_t channel_mask = CC_DEFAULT;
static uint32_t channel_mask_saved = CC_DEFAULT;
/*
diff --git a/include/console.h b/include/console.h
index 2c5e9f98fa..f0367f7ffe 100644
--- a/include/console.h
+++ b/include/console.h
@@ -225,6 +225,37 @@ void console_has_input(void);
(CONFIG_CONSOLE_COMMAND_FLAGS_DEFAULT & \
~CMD_FLAG_RESTRICTED))
-#endif /* HAS_TASK_CONSOLE */
+#endif /* HAS_TASK_CONSOLE */
-#endif /* __CROS_EC_CONSOLE_H */
+/*
+ * Packet mode console interface functions, with fixed number of parameters,
+ * replacing cprint/cprints/cputs in the source code.
+ *
+ * All converted parameters are typecast to uintptr_t. The uint32_t parameter
+ * is a mask of up to eight 4 bit fields describing each present parameter
+ * type. This allows the packet building function to properly re-cast the
+ * uintptr_t parameters.
+ */
+int cmsg0(enum console_channel chan, int str_index);
+int cmsg1(enum console_channel chan, int str_index, uint32_t mask,
+ uintptr_t p1);
+int cmsg2(enum console_channel chan, int str_index, uint32_t mask, uintptr_t p1,
+ uintptr_t p2);
+int cmsg3(enum console_channel chan, int str_index, uint32_t mask, uintptr_t p1,
+ uintptr_t p2, uintptr_t p3);
+int cmsg4(enum console_channel chan, int str_index, uint32_t mask, uintptr_t p1,
+ uintptr_t p2, uintptr_t p3, uintptr_t p4);
+int cmsg5(enum console_channel chan, int str_index, uint32_t mask, uintptr_t p1,
+ uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5);
+int cmsg6(enum console_channel chan, int str_index, uint32_t mask, uintptr_t p1,
+ uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6);
+int cmsg7(enum console_channel chan, int str_index, uint32_t mask, uintptr_t p1,
+ uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6,
+ uintptr_t p7);
+int cmsg8(enum console_channel chan, int str_index, uint32_t mask, uintptr_t p1,
+ uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6,
+ uintptr_t p7, uintptr_t p8);
+
+extern uint32_t channel_mask;
+
+#endif /* __CROS_EC_CONSOLE_H */