CONFIG_CMD_IMLS List all images found in NOR flash
CONFIG_CMD_IMLS_NAND * List all images found in NAND flash
CONFIG_CMD_IMMAP * IMMR dump support
+ CONFIG_CMD_IOTRACE * I/O tracing for debugging
CONFIG_CMD_IMPORTENV * import an environment
CONFIG_CMD_INI * import data from an ini file into the env
CONFIG_CMD_IRQ * irqinfo
Note that if the GPIO device uses I2C, then the I2C interface
must also be configured. See I2C Support, below.
+- I/O tracing:
+ When CONFIG_IO_TRACE is selected, U-Boot intercepts all I/O
+ accesses and can checksum them or write a list of them out
+ to memory. See the 'iotrace' command for details. This is
+ useful for testing device drivers since it can confirm that
+ the driver behaves the same way before and after a code
+ change. Currently this is supported on sandbox and arm. To
+ add support for your architecture, add '#include <iotrace.h>'
+ to the bottom of arch/<arch>/include/asm/io.h and test.
+
+ Example output from the 'iotrace stats' command is below.
+ Note that if the trace buffer is exhausted, the checksum will
+ still continue to operate.
+
+ iotrace is enabled
+ Start: 10000000 (buffer start address)
+ Size: 00010000 (buffer size)
+ Offset: 00000120 (current buffer offset)
+ Output: 10000120 (start + offset)
+ Count: 00000018 (number of trace records)
+ CRC32: 9526fb66 (CRC32 of all trace records)
+
- Timestamp Support:
When CONFIG_TIMESTAMP is selected, the timestamp
obj-$(CONFIG_CMD_GETTIME) += cmd_gettime.o
obj-$(CONFIG_CMD_GPIO) += cmd_gpio.o
obj-$(CONFIG_CMD_I2C) += cmd_i2c.o
+obj-$(CONFIG_CMD_IOTRACE) += cmd_iotrace.o
obj-$(CONFIG_CMD_HASH) += cmd_hash.o
obj-$(CONFIG_CMD_IDE) += cmd_ide.o
obj-$(CONFIG_CMD_IMMAP) += cmd_immap.o
obj-$(CONFIG_OF_LIBFDT) += image-fdt.o
obj-$(CONFIG_FIT) += image-fit.o
obj-$(CONFIG_FIT_SIGNATURE) += image-sig.o
+obj-$(CONFIG_IO_TRACE) += iotrace.o
obj-y += memsize.o
obj-y += stdio.o
--- /dev/null
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <iotrace.h>
+
+static void do_print_stats(void)
+{
+ ulong start, size, offset, count;
+
+ printf("iotrace is %sabled\n", iotrace_get_enabled() ? "en" : "dis");
+ iotrace_get_buffer(&start, &size, &offset, &count);
+ printf("Start: %08lx\n", start);
+ printf("Size: %08lx\n", size);
+ printf("Offset: %08lx\n", offset);
+ printf("Output: %08lx\n", start + offset);
+ printf("Count: %08lx\n", count);
+ printf("CRC32: %08lx\n", (ulong)iotrace_get_checksum());
+}
+
+static int do_set_buffer(int argc, char * const argv[])
+{
+ ulong addr = 0, size = 0;
+
+ if (argc == 2) {
+ addr = simple_strtoul(*argv++, NULL, 16);
+ size = simple_strtoul(*argv++, NULL, 16);
+ } else if (argc != 0) {
+ return CMD_RET_USAGE;
+ }
+
+ iotrace_set_buffer(addr, size);
+
+ return 0;
+}
+
+int do_iotrace(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ const char *cmd = argc < 2 ? NULL : argv[1];
+
+ if (!cmd)
+ return cmd_usage(cmdtp);
+ switch (*cmd) {
+ case 'b':
+ return do_set_buffer(argc - 2, argv + 2);
+ case 'p':
+ iotrace_set_enabled(0);
+ break;
+ case 'r':
+ iotrace_set_enabled(1);
+ break;
+ case 's':
+ do_print_stats();
+ break;
+ default:
+ return CMD_RET_USAGE;
+ }
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ iotrace, 4, 1, do_iotrace,
+ "iotrace utility commands",
+ "stats - display iotrace stats\n"
+ "iotrace buffer <address> <size> - set iotrace buffer\n"
+ "iotrace pause - pause tracing\n"
+ "iotrace resume - resume tracing"
+);
--- /dev/null
+/*
+ * Copyright (c) 2014 Google, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#define IOTRACE_IMPL
+
+#include <common.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Support up to the machine word length for now */
+typedef ulong iovalue_t;
+
+enum iotrace_flags {
+ IOT_8 = 0,
+ IOT_16,
+ IOT_32,
+
+ IOT_READ = 0 << 3,
+ IOT_WRITE = 1 << 3,
+};
+
+/**
+ * struct iotrace_record - Holds a single I/O trace record
+ *
+ * @flags: I/O access type
+ * @addr: Address of access
+ * @value: Value written or read
+ */
+struct iotrace_record {
+ enum iotrace_flags flags;
+ phys_addr_t addr;
+ iovalue_t value;
+};
+
+/**
+ * struct iotrace - current trace status and checksum
+ *
+ * @start: Start address of iotrace buffer
+ * @size: Size of iotrace buffer in bytes
+ * @offset: Current write offset into iotrace buffer
+ * @crc32: Current value of CRC chceksum of trace records
+ * @enabled: true if enabled, false if disabled
+ */
+static struct iotrace {
+ ulong start;
+ ulong size;
+ ulong offset;
+ u32 crc32;
+ bool enabled;
+} iotrace;
+
+static void add_record(int flags, const void *ptr, ulong value)
+{
+ struct iotrace_record srec, *rec = &srec;
+
+ /*
+ * We don't support iotrace before relocation. Since the trace buffer
+ * is set up by a command, it can't be enabled at present. To change
+ * this we would need to set the iotrace buffer at build-time. See
+ * lib/trace.c for how this might be done if you are interested.
+ */
+ if (!(gd->flags & GD_FLG_RELOC) || !iotrace.enabled)
+ return;
+
+ /* Store it if there is room */
+ if (iotrace.offset + sizeof(*rec) < iotrace.size) {
+ rec = (struct iotrace_record *)map_sysmem(
+ iotrace.start + iotrace.offset,
+ sizeof(value));
+ }
+
+ rec->flags = flags;
+ rec->addr = map_to_sysmem(ptr);
+ rec->value = value;
+
+ /* Update our checksum */
+ iotrace.crc32 = crc32(iotrace.crc32, (unsigned char *)rec,
+ sizeof(*rec));
+
+ iotrace.offset += sizeof(struct iotrace_record);
+}
+
+u32 iotrace_readl(const void *ptr)
+{
+ u32 v;
+
+ v = readl(ptr);
+ add_record(IOT_32 | IOT_READ, ptr, v);
+
+ return v;
+}
+
+void iotrace_writel(ulong value, const void *ptr)
+{
+ add_record(IOT_32 | IOT_WRITE, ptr, value);
+ writel(value, ptr);
+}
+
+u16 iotrace_readw(const void *ptr)
+{
+ u32 v;
+
+ v = readw(ptr);
+ add_record(IOT_16 | IOT_READ, ptr, v);
+
+ return v;
+}
+
+void iotrace_writew(ulong value, const void *ptr)
+{
+ add_record(IOT_16 | IOT_WRITE, ptr, value);
+ writew(value, ptr);
+}
+
+u8 iotrace_readb(const void *ptr)
+{
+ u32 v;
+
+ v = readb(ptr);
+ add_record(IOT_8 | IOT_READ, ptr, v);
+
+ return v;
+}
+
+void iotrace_writeb(ulong value, const void *ptr)
+{
+ add_record(IOT_8 | IOT_WRITE, ptr, value);
+ writeb(value, ptr);
+}
+
+void iotrace_reset_checksum(void)
+{
+ iotrace.crc32 = 0;
+}
+
+u32 iotrace_get_checksum(void)
+{
+ return iotrace.crc32;
+}
+
+void iotrace_set_enabled(int enable)
+{
+ iotrace.enabled = enable;
+}
+
+int iotrace_get_enabled(void)
+{
+ return iotrace.enabled;
+}
+
+void iotrace_set_buffer(ulong start, ulong size)
+{
+ iotrace.start = start;
+ iotrace.size = size;
+ iotrace.offset = 0;
+ iotrace.crc32 = 0;
+}
+
+void iotrace_get_buffer(ulong *start, ulong *size, ulong *offset, ulong *count)
+{
+ *start = iotrace.start;
+ *size = iotrace.size;
+ *offset = iotrace.offset;
+ *count = iotrace.offset / sizeof(struct iotrace_record);
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Google, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __IOTRACE_H
+#define __IOTRACE_H
+
+#include <linux/types.h>
+
+/*
+ * This file is designed to be included in arch/<arch>/include/asm/io.h.
+ * It redirects all IO access through a tracing/checksumming feature for
+ * testing purposes.
+ */
+
+#if defined(CONFIG_IO_TRACE) && !defined(IOTRACE_IMPL) && \
+ !defined(CONFIG_SPL_BUILD)
+
+#undef readl
+#define readl(addr) iotrace_readl((const void *)(addr))
+
+#undef writel
+#define writel(val, addr) iotrace_writel(val, (const void *)(addr))
+
+#undef readw
+#define readw(addr) iotrace_readw((const void *)(addr))
+
+#undef writew
+#define writew(val, addr) iotrace_writew(val, (const void *)(addr))
+
+#undef readb
+#define readb(addr) iotrace_readb((const void *)(addr))
+
+#undef writeb
+#define writeb(val, addr) iotrace_writeb(val, (const void *)(addr))
+
+#endif
+
+/* Tracing functions which mirror their io.h counterparts */
+u32 iotrace_readl(const void *ptr);
+void iotrace_writel(ulong value, const void *ptr);
+u16 iotrace_readw(const void *ptr);
+void iotrace_writew(ulong value, const void *ptr);
+u8 iotrace_readb(const void *ptr);
+void iotrace_writeb(ulong value, const void *ptr);
+
+/**
+ * iotrace_reset_checksum() - Reset the iotrace checksum
+ */
+void iotrace_reset_checksum(void);
+
+/**
+ * iotrace_get_checksum() - Get the current checksum value
+ *
+ * @return currect checksum value
+ */
+u32 iotrace_get_checksum(void);
+
+/**
+ * iotrace_set_enabled() - Set whether iotracing is enabled or not
+ *
+ * This controls whether the checksum is updated and a trace record added
+ * for each I/O access.
+ *
+ * @enable: true to enable iotracing, false to disable
+ */
+void iotrace_set_enabled(int enable);
+
+/**
+ * iotrace_get_enabled() - Get whether iotracing is enabled or not
+ *
+ * @return true if enabled, false if disabled
+ */
+int iotrace_get_enabled(void);
+
+/**
+ * iotrace_set_buffer() - Set position and size of iotrace buffer
+ *
+ * Defines where the iotrace buffer goes, and resets the output pointer to
+ * the start of the buffer.
+ *
+ * The buffer can be 0 size in which case the checksum is updated but no
+ * trace records are writen. If the buffer is exhausted, the offset will
+ * continue to increase but not new data will be written.
+ *
+ * @start: Start address of buffer
+ * @size: Size of buffer in bytes
+ */
+void iotrace_set_buffer(ulong start, ulong size);
+
+/**
+ * iotrace_get_buffer() - Get buffer information
+ *
+ * @start: Returns start address of buffer
+ * @size: Returns size of buffer in bytes
+ * @offset: Returns the byte offset where the next output trace record will
+ * @count: Returns the number of trace records recorded
+ * be written (or would be if the buffer was large enough)
+ */
+void iotrace_get_buffer(ulong *start, ulong *size, ulong *offset, ulong *count);
+
+#endif /* __IOTRACE_H */