[U-Boot] [PATCH 00/15] sandbox: Add support for TPL and other improvements

This series adds TPL support to sandbox and tidies up various other things along the way:
- Fix for console being left in non-blocking mode on exit - Add debug UART (just for build coverage) - Support for serial output without DT (intended for TPL) - Enhancements to the sandbox TPM driver - Command-line flag to set the logging level
So far there is not actually a separate TPL build. I am going to leave this until I have a full Chromium OS config for U-Boot.
Simon Glass (15): log: Add helpers for common log levels sandbox: Support file truncation with os_open() sandbox: Add a way to write data to the host filesystem sandbox: spi: Drop command-line SPI option sandbox: Support booting from TPL to SPL sandbox: Add a flag to set the default log level sandbox: Remove the old memory file later sandbox: spi: Add more logging sandbox: video: Speed up video output sandbox: Add a debug UART serial: sandbox: Allow serial output without device tree sandbox: tpm: Tidy up enums and return values sandbox: tpm: Enhance to support the latest Chromium OS dm: spi: Clean up detection of sandbox SPI emulator sandbox: Restore blocking I/O on exit
arch/sandbox/cpu/os.c | 74 ++++++++++-- arch/sandbox/cpu/start.c | 19 ++- arch/sandbox/cpu/state.c | 6 +- arch/sandbox/include/asm/state.h | 2 +- common/log.c | 3 +- configs/sandbox_defconfig | 2 + drivers/mtd/spi/sandbox.c | 194 +++++++----------------------- drivers/serial/Kconfig | 11 ++ drivers/serial/sandbox.c | 24 +++- drivers/spi/sandbox_spi.c | 38 ++---- drivers/tpm/tpm_tis_sandbox.c | 115 ++++++++++++++---- drivers/video/vidconsole-uclass.c | 12 +- drivers/video/video-uclass.c | 6 +- drivers/video/video_bmp.c | 2 +- include/log.h | 15 +++ include/os.h | 24 ++-- include/tpm-v1.h | 48 ++++++++ include/tpm-v2.h | 1 + include/video.h | 4 +- test/dm/video.c | 2 +- test/log/log_test.c | 13 ++ test/py/tests/test_log.py | 6 + 22 files changed, 379 insertions(+), 242 deletions(-)

At present to output a log message you need something like:
log(UCLASS_SPI, LOCL_INFO, "message1"); log(UCLASS_SPI, LOCL_INFO, "message2");
but many files use the same category throughout. Also it is helpful to shorten the length of log names, providing helpers for common logging levels. Add some macros so that it is possible to do:
(top of file, before #includes) #define LOG_CATEGORY UCLASS_SPI
(later in the file) log_info("message1"); log_debug("message2"); log_err("message3");
Signed-off-by: Simon Glass sjg@chromium.org ---
include/log.h | 14 ++++++++++++++ test/log/log_test.c | 13 +++++++++++++ test/py/tests/test_log.py | 6 ++++++ 3 files changed, 33 insertions(+)
diff --git a/include/log.h b/include/log.h index 61411b72eac..12168340d12 100644 --- a/include/log.h +++ b/include/log.h @@ -103,8 +103,22 @@ int _log(enum log_category_t cat, enum log_level_t level, const char *file, __func__, \ pr_fmt(_fmt), ##_args); \ }) +#define log_err(_fmt...) log(LOG_CATEGORY, LOGL_ERR, ##_fmt) +#define log_warning(_fmt...) log(LOG_CATEGORY, LOGL_WARNING, ##_fmt) +#define log_notice(_fmt...) log(LOG_CATEGORY, LOGL_NOTICE, ##_fmt) +#define log_info(_fmt...) log(LOG_CATEGORY, LOGL_INFO, ##_fmt) +#define log_debug(_fmt...) log(LOG_CATEGORY, LOGL_DEBUG, ##_fmt) +#define log_content(_fmt...) log(LOG_CATEGORY, LOGL_DEBUG_CONTENT, ##_fmt) +#define log_io(_fmt...) log(LOG_CATEGORY, LOGL_DEBUG_IO, ##_fmt) #else #define log(_cat, _level, _fmt, _args...) +#define log_err(_fmt...) +#define log_warning(_fmt...) +#define log_notice(_fmt...) +#define log_info(_fmt...) +#define log_debug(_fmt...) +#define log_content(_fmt...) +#define log_io(_fmt...) #endif
#ifdef DEBUG diff --git a/test/log/log_test.c b/test/log/log_test.c index de431b0823e..febc2c1252a 100644 --- a/test/log/log_test.c +++ b/test/log/log_test.c @@ -181,6 +181,19 @@ static int log_test(int testnum) return ret; break; } + case 10: { + log_err("level %d\n", LOGL_EMERG); + log_err("level %d\n", LOGL_ALERT); + log_err("level %d\n", LOGL_CRIT); + log_err("level %d\n", LOGL_ERR); + log_warning("level %d\n", LOGL_WARNING); + log_notice("level %d\n", LOGL_NOTICE); + log_info("level %d\n", LOGL_INFO); + log_debug("level %d\n", LOGL_DEBUG); + log_content("level %d\n", LOGL_DEBUG_CONTENT); + log_io("level %d\n", LOGL_DEBUG_IO); + break; + } }
return 0; diff --git a/test/py/tests/test_log.py b/test/py/tests/test_log.py index 605275b0399..cb183444c6f 100644 --- a/test/py/tests/test_log.py +++ b/test/py/tests/test_log.py @@ -85,6 +85,11 @@ def test_log(u_boot_console): lines = run_test(9) check_log_entries(lines, 3)
+ def test10(): + lines = run_test(10) + for i in range(7): + assert 'log_test() level %d' % i == lines.next() + # TODO(sjg@chromium.org): Consider structuring this as separate tests cons = u_boot_console test0() @@ -97,6 +102,7 @@ def test_log(u_boot_console): test7() test8() test9() + test10()
@pytest.mark.buildconfigspec('cmd_log') def test_log_format(u_boot_console):

At present to output a log message you need something like:
log(UCLASS_SPI, LOCL_INFO, "message1"); log(UCLASS_SPI, LOCL_INFO, "message2");
but many files use the same category throughout. Also it is helpful to shorten the length of log names, providing helpers for common logging levels. Add some macros so that it is possible to do:
(top of file, before #includes) #define LOG_CATEGORY UCLASS_SPI
(later in the file) log_info("message1"); log_debug("message2"); log_err("message3");
Signed-off-by: Simon Glass sjg@chromium.org ---
include/log.h | 14 ++++++++++++++ test/log/log_test.c | 13 +++++++++++++ test/py/tests/test_log.py | 6 ++++++ 3 files changed, 33 insertions(+)
Applied to u-boot-dm

At present files are not truncated on writing. This is a useful feature. Add support for this.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/os.c | 2 ++ include/os.h | 1 + 2 files changed, 3 insertions(+)
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index 071e2074ef4..2d20cfe1fa6 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -85,6 +85,8 @@ int os_open(const char *pathname, int os_flags)
if (os_flags & OS_O_CREAT) flags |= O_CREAT; + if (os_flags & OS_O_TRUNC) + flags |= O_TRUNC;
return open(pathname, flags, 0777); } diff --git a/include/os.h b/include/os.h index 7116f875780..9e3a561b65e 100644 --- a/include/os.h +++ b/include/os.h @@ -75,6 +75,7 @@ int os_open(const char *pathname, int flags); #define OS_O_RDWR 2 #define OS_O_MASK 3 /* Mask for read/write flags */ #define OS_O_CREAT 0100 +#define OS_O_TRUNC 01000
/** * Access to the OS close() system call

At present files are not truncated on writing. This is a useful feature. Add support for this.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/os.c | 2 ++ include/os.h | 1 + 2 files changed, 3 insertions(+)
Applied to u-boot-dm

For debugging it is sometimes useful to write out data for inspection using an external tool. Add a function which can write this data to a given file.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/os.c | 20 ++++++++++++++++++++ include/os.h | 13 +++++++++++++ 2 files changed, 33 insertions(+)
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index 2d20cfe1fa6..3a46038c5fc 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -106,6 +106,26 @@ void os_exit(int exit_code) exit(exit_code); }
+int os_write_file(const char *name, const void *buf, int size) +{ + char fname[256]; + int fd; + + fd = os_open(fname, OS_O_WRONLY | OS_O_CREAT | OS_O_TRUNC); + if (fd < 0) { + printf("Cannot open file '%s'\n", fname); + return -EIO; + } + if (os_write(fd, buf, size) != size) { + printf("Cannot write to file '%s'\n", fname); + return -EIO; + } + os_close(fd); + printf("Write '%s', size %#x (%d)\n", name, size, size); + + return 0; +} + /* Restore tty state when we exit */ static struct termios orig_term; static bool term_setup; diff --git a/include/os.h b/include/os.h index 9e3a561b65e..efa9e52d124 100644 --- a/include/os.h +++ b/include/os.h @@ -347,4 +347,17 @@ void os_abort(void); */ int os_mprotect_allow(void *start, size_t len);
+/** + * os_write_file() - Write a file to the host filesystem + * + * This can be useful when debugging for writing data out of sandbox for + * inspection by external tools. + * + * @name: File path to write to + * @buf: Data to write + * @size: Size of data to write + * @return 0 if OK, -ve on error + */ +int os_write_file(const char *name, const void *buf, int size); + #endif

For debugging it is sometimes useful to write out data for inspection using an external tool. Add a function which can write this data to a given file.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/os.c | 20 ++++++++++++++++++++ include/os.h | 13 +++++++++++++ 2 files changed, 33 insertions(+)
Applied to u-boot-dm

At present we support specifying SPI flash devices to use in the device tree and on the command line. Drop the second option, since it is a pain to support nicely with driver model, and unnecessary.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mtd/spi/sandbox.c | 122 +++----------------------------------- 1 file changed, 9 insertions(+), 113 deletions(-)
diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c index 1b6c0282513..987b05dd939 100644 --- a/drivers/mtd/spi/sandbox.c +++ b/drivers/mtd/spi/sandbox.c @@ -101,14 +101,12 @@ struct sandbox_spi_flash_plat_data { /** * This is a very strange probe function. If it has platform data (which may * have come from the device tree) then this function gets the filename and - * device type from there. Failing that it looks at the command line - * parameter. + * device type from there. */ static int sandbox_sf_probe(struct udevice *dev) { /* spec = idcode:file */ struct sandbox_spi_flash *sbsf = dev_get_priv(dev); - const char *file; size_t len, idname_len; const struct spi_flash_info *data; struct sandbox_spi_flash_plat_data *pdata = dev_get_platdata(dev); @@ -134,36 +132,15 @@ static int sandbox_sf_probe(struct udevice *dev) debug("found at cs %d\n", cs);
if (!pdata->filename) { - struct sandbox_state *state = state_get_current(); - - assert(bus->seq != -1); - if (bus->seq < CONFIG_SANDBOX_SPI_MAX_BUS) - spec = state->spi[bus->seq][cs].spec; - if (!spec) { - debug("%s: No spec found for bus %d, cs %d\n", - __func__, bus->seq, cs); - ret = -ENOENT; - goto error; - } - - file = strchr(spec, ':'); - if (!file) { - printf("%s: unable to parse file\n", __func__); - ret = -EINVAL; - goto error; - } - idname_len = file - spec; - pdata->filename = file + 1; - pdata->device_name = spec; - ++file; - } else { - spec = strchr(pdata->device_name, ','); - if (spec) - spec++; - else - spec = pdata->device_name; - idname_len = strlen(spec); + printf("Error: No filename available\n"); + return -EINVAL; } + spec = strchr(pdata->device_name, ','); + if (spec) + spec++; + else + spec = pdata->device_name; + idname_len = strlen(spec); debug("%s: device='%s'\n", __func__, spec);
for (data = spi_flash_ids; data->name; data++) { @@ -530,31 +507,6 @@ static const struct dm_spi_emul_ops sandbox_sf_emul_ops = { };
#ifdef CONFIG_SPI_FLASH -static int sandbox_cmdline_cb_spi_sf(struct sandbox_state *state, - const char *arg) -{ - unsigned long bus, cs; - const char *spec = sandbox_spi_parse_spec(arg, &bus, &cs); - - if (!spec) - return 1; - - /* - * It is safe to not make a copy of 'spec' because it comes from the - * command line. - * - * TODO(sjg@chromium.org): It would be nice if we could parse the - * spec here, but the problem is that no U-Boot init has been done - * yet. Perhaps we can figure something out. - */ - state->spi[bus][cs].spec = spec; - debug("%s: Setting up spec '%s' for bus %ld, cs %ld\n", __func__, - spec, bus, cs); - - return 0; -} -SANDBOX_CMDLINE_OPT(spi_sf, 1, "connect a SPI flash: <bus>:<cs>:<id>:<file>"); - int sandbox_sf_bind_emul(struct sandbox_state *state, int busnum, int cs, struct udevice *bus, ofnode node, const char *spec) { @@ -597,33 +549,6 @@ void sandbox_sf_unbind_emul(struct sandbox_state *state, int busnum, int cs) state->spi[busnum][cs].emul = NULL; }
-static int sandbox_sf_bind_bus_cs(struct sandbox_state *state, int busnum, - int cs, const char *spec) -{ - struct udevice *bus, *slave; - int ret; - - ret = uclass_find_device_by_seq(UCLASS_SPI, busnum, true, &bus); - if (ret) { - printf("Invalid bus %d for spec '%s' (err=%d)\n", busnum, - spec, ret); - return ret; - } - ret = spi_find_chip_select(bus, cs, &slave); - if (!ret) { - printf("Chip select %d already exists for spec '%s'\n", cs, - spec); - return -EEXIST; - } - - ret = device_bind_driver(bus, "spi_flash_std", spec, &slave); - if (ret) - return ret; - - return sandbox_sf_bind_emul(state, busnum, cs, bus, ofnode_null(), - spec); -} - int sandbox_spi_get_emul(struct sandbox_state *state, struct udevice *bus, struct udevice *slave, struct udevice **emulp) @@ -650,35 +575,6 @@ int sandbox_spi_get_emul(struct sandbox_state *state,
return 0; } - -int dm_scan_other(bool pre_reloc_only) -{ - struct sandbox_state *state = state_get_current(); - int busnum, cs; - - if (pre_reloc_only) - return 0; - for (busnum = 0; busnum < CONFIG_SANDBOX_SPI_MAX_BUS; busnum++) { - for (cs = 0; cs < CONFIG_SANDBOX_SPI_MAX_CS; cs++) { - const char *spec = state->spi[busnum][cs].spec; - int ret; - - if (spec) { - ret = sandbox_sf_bind_bus_cs(state, busnum, - cs, spec); - if (ret) { - debug("%s: Bind failed for bus %d, cs %d\n", - __func__, busnum, cs); - return ret; - } - debug("%s: Setting up spec '%s' for bus %d, cs %d\n", - __func__, spec, busnum, cs); - } - } - } - - return 0; -} #endif
static const struct udevice_id sandbox_sf_ids[] = {

At present we support specifying SPI flash devices to use in the device tree and on the command line. Drop the second option, since it is a pain to support nicely with driver model, and unnecessary.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mtd/spi/sandbox.c | 122 +++----------------------------------- 1 file changed, 9 insertions(+), 113 deletions(-)
Applied to u-boot-dm

At present we support booting from SPL to U-Boot proper. Add support for the previous stage too, so sandbox can be started with TPL.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/os.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index 3a46038c5fc..a7f17034862 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -642,15 +642,40 @@ int os_find_u_boot(char *fname, int maxlen) struct sandbox_state *state = state_get_current(); const char *progname = state->argv[0]; int len = strlen(progname); + const char *suffix; char *p; int fd;
if (len >= maxlen || len < 4) return -ENOSPC;
- /* Look for 'u-boot' in the same directory as 'u-boot-spl' */ strcpy(fname, progname); - if (!strcmp(fname + len - 4, "-spl")) { + suffix = fname + len - 4; + + /* If we are TPL, boot to SPL */ + if (!strcmp(suffix, "-tpl")) { + fname[len - 3] = 's'; + fd = os_open(fname, O_RDONLY); + if (fd >= 0) { + close(fd); + return 0; + } + + /* Look for 'u-boot-tpl' in the tpl/ directory */ + p = strstr(fname, "/tpl/"); + if (p) { + p[1] = 's'; + fd = os_open(fname, O_RDONLY); + if (fd >= 0) { + close(fd); + return 0; + } + } + return -ENOENT; + } + + /* Look for 'u-boot' in the same directory as 'u-boot-spl' */ + if (!strcmp(suffix, "-spl")) { fname[len - 4] = '\0'; fd = os_open(fname, O_RDONLY); if (fd >= 0) {

At present we support booting from SPL to U-Boot proper. Add support for the previous stage too, so sandbox can be started with TPL.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/os.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-)
Applied to u-boot-dm

It is useful to be able to set the default log level from the command line when running sandbox. Add a new -L command-line flag for this. The log level is set using the enum log_level_t in log.h. At present a number must be specified, e.g. -L7 for debug.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/start.c | 13 +++++++++++++ arch/sandbox/include/asm/state.h | 1 + common/log.c | 3 ++- 3 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c index 2251ec4c53f..ab5007c7b35 100644 --- a/arch/sandbox/cpu/start.c +++ b/arch/sandbox/cpu/start.c @@ -282,6 +282,16 @@ static int sandbox_cmdline_cb_show_of_platdata(struct sandbox_state *state, } SANDBOX_CMDLINE_OPT(show_of_platdata, 0, "Show of-platdata in SPL");
+static int sandbox_cmdline_cb_log_level(struct sandbox_state *state, + const char *arg) +{ + state->default_log_level = simple_strtol(arg, NULL, 10); + + return 0; +} +SANDBOX_CMDLINE_OPT_SHORT(log_level, 'L', 1, + "Set log level (0=panic, 7=debug)"); + int board_run_command(const char *cmdline) { printf("## Commands are disabled. Please enable CONFIG_CMDLINE.\n"); @@ -331,6 +341,9 @@ int main(int argc, char *argv[]) gd = &data; #if CONFIG_VAL(SYS_MALLOC_F_LEN) gd->malloc_base = CONFIG_MALLOC_F_ADDR; +#endif +#if CONFIG_IS_ENABLED(LOG) + gd->default_log_level = state->default_log_level; #endif setup_ram_buf(state);
diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h index 4e4c71b8062..d1baba1c3ae 100644 --- a/arch/sandbox/include/asm/state.h +++ b/arch/sandbox/include/asm/state.h @@ -90,6 +90,7 @@ struct sandbox_state { bool skip_delays; /* Ignore any time delays (for test) */ bool show_test_output; /* Don't suppress stdout in tests */ bool show_of_platdata; /* Show of-platdata in SPL */ + int default_log_level; /* Default log level for sandbox */
/* Pointer to information for each SPI bus/cs */ struct sandbox_spi_info spi[CONFIG_SANDBOX_SPI_MAX_BUS] diff --git a/common/log.c b/common/log.c index 59869cd29da..ec14644516c 100644 --- a/common/log.c +++ b/common/log.c @@ -315,7 +315,8 @@ int log_init(void) drv++; } gd->flags |= GD_FLG_LOG_READY; - gd->default_log_level = LOGL_INFO; + if (!gd->default_log_level) + gd->default_log_level = LOGL_INFO; gd->log_fmt = LOGF_DEFAULT;
return 0;

It is useful to be able to set the default log level from the command line when running sandbox. Add a new -L command-line flag for this. The log level is set using the enum log_level_t in log.h. At present a number must be specified, e.g. -L7 for debug.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/start.c | 13 +++++++++++++ arch/sandbox/include/asm/state.h | 1 + common/log.c | 3 ++- 3 files changed, 16 insertions(+), 1 deletion(-)
Applied to u-boot-dm

When debugging sandbox it is sometimes annoying that the memory file is deleted early on. If sandbox later crashes or we quit (using the debugger), it is not possible to run it again with the same state since the memory file is gone.
Remove the old memory file when sandbox exits, instead. Also add debugging showing the memory filename.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/start.c | 6 +----- arch/sandbox/cpu/state.c | 6 +++++- 2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c index ab5007c7b35..b6e3150a5e3 100644 --- a/arch/sandbox/cpu/start.c +++ b/arch/sandbox/cpu/start.c @@ -177,7 +177,7 @@ static int sandbox_cmdline_cb_memory(struct sandbox_state *state,
err = os_read_ram_buf(arg); if (err) { - printf("Failed to read RAM buffer\n"); + printf("Failed to read RAM buffer '%s': %d\n", arg, err); return err; }
@@ -333,10 +333,6 @@ int main(int argc, char *argv[]) if (ret) goto err;
- /* Remove old memory file if required */ - if (state->ram_buf_rm && state->ram_buf_fname) - os_unlink(state->ram_buf_fname); - memset(&data, '\0', sizeof(data)); gd = &data; #if CONFIG_VAL(SYS_MALLOC_F_LEN) diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c index 04a11fed559..d3b9c059859 100644 --- a/arch/sandbox/cpu/state.c +++ b/arch/sandbox/cpu/state.c @@ -393,7 +393,7 @@ int state_uninit(void)
state = &main_state;
- if (state->write_ram_buf && !state->ram_buf_rm) { + if (state->write_ram_buf) { err = os_write_ram_buf(state->ram_buf_fname); if (err) { printf("Failed to write RAM buffer\n"); @@ -408,6 +408,10 @@ int state_uninit(void) } }
+ /* Remove old memory file if required */ + if (state->ram_buf_rm && state->ram_buf_fname) + os_unlink(state->ram_buf_fname); + /* Delete this at the last moment so as not to upset gdb too much */ if (state->jumped_fname) os_unlink(state->jumped_fname);

When debugging sandbox it is sometimes annoying that the memory file is deleted early on. If sandbox later crashes or we quit (using the debugger), it is not possible to run it again with the same state since the memory file is gone.
Remove the old memory file when sandbox exits, instead. Also add debugging showing the memory filename.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/start.c | 6 +----- arch/sandbox/cpu/state.c | 6 +++++- 2 files changed, 6 insertions(+), 6 deletions(-)
Applied to u-boot-dm

Add logging to aid debugging features in these drivers. Also drop some code in sandbox_spi_xfer() which is not used.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mtd/spi/sandbox.c | 54 +++++++++++++++++++++------------------ drivers/spi/sandbox_spi.c | 38 +++++++-------------------- include/log.h | 1 + 3 files changed, 39 insertions(+), 54 deletions(-)
diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c index 987b05dd939..514484eba06 100644 --- a/drivers/mtd/spi/sandbox.c +++ b/drivers/mtd/spi/sandbox.c @@ -8,6 +8,8 @@ * Licensed under the GPL-2 or later. */
+#define LOG_CATEGORY UCLASS_SPI_FLASH + #include <common.h> #include <dm.h> #include <malloc.h> @@ -41,6 +43,7 @@ enum sandbox_sf_state { SF_WRITE_STATUS, /* write the flash's status register */ };
+#if CONFIG_IS_ENABLED(LOG) static const char *sandbox_sf_state_name(enum sandbox_sf_state state) { static const char * const states[] = { @@ -49,6 +52,7 @@ static const char *sandbox_sf_state_name(enum sandbox_sf_state state) }; return states[state]; } +#endif /* LOG */
/* Bits for the status register */ #define STAT_WIP (1 << 0) @@ -191,7 +195,7 @@ static void sandbox_sf_cs_activate(struct udevice *dev) { struct sandbox_spi_flash *sbsf = dev_get_priv(dev);
- debug("sandbox_sf: CS activated; state is fresh!\n"); + log_content("sandbox_sf: CS activated; state is fresh!\n");
/* CS is asserted, so reset state */ sbsf->off = 0; @@ -203,7 +207,7 @@ static void sandbox_sf_cs_activate(struct udevice *dev)
static void sandbox_sf_cs_deactivate(struct udevice *dev) { - debug("sandbox_sf: CS deactivated; cmd done processing!\n"); + log_content("sandbox_sf: CS deactivated; cmd done processing!\n"); }
/* @@ -279,8 +283,8 @@ static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx, }
if (oldstate != sbsf->state) - debug(" cmd: transition to %s state\n", - sandbox_sf_state_name(sbsf->state)); + log_content(" cmd: transition to %s state\n", + sandbox_sf_state_name(sbsf->state));
return 0; } @@ -311,8 +315,8 @@ static int sandbox_sf_xfer(struct udevice *dev, unsigned int bitlen, int bytes = bitlen / 8; int ret;
- debug("sandbox_sf: state:%x(%s) bytes:%u\n", sbsf->state, - sandbox_sf_state_name(sbsf->state), bytes); + log_content("sandbox_sf: state:%x(%s) bytes:%u\n", sbsf->state, + sandbox_sf_state_name(sbsf->state), bytes);
if ((flags & SPI_XFER_BEGIN)) sandbox_sf_cs_activate(dev); @@ -331,7 +335,7 @@ static int sandbox_sf_xfer(struct udevice *dev, unsigned int bitlen, case SF_ID: { u8 id;
- debug(" id: off:%u tx:", sbsf->off); + log_content(" id: off:%u tx:", sbsf->off); if (sbsf->off < IDCODE_LEN) { /* Extract correct byte from ID 0x00aabbcc */ id = ((JEDEC_MFR(sbsf->data) << 16) | @@ -340,18 +344,18 @@ static int sandbox_sf_xfer(struct udevice *dev, unsigned int bitlen, } else { id = 0; } - debug("%d %02x\n", sbsf->off, id); + log_content("%d %02x\n", sbsf->off, id); tx[pos++] = id; ++sbsf->off; break; } case SF_ADDR: - debug(" addr: bytes:%u rx:%02x ", sbsf->addr_bytes, - rx[pos]); + log_content(" addr: bytes:%u rx:%02x ", + sbsf->addr_bytes, rx[pos]);
if (sbsf->addr_bytes++ < SF_ADDR_LEN) sbsf->off = (sbsf->off << 8) | rx[pos]; - debug("addr:%06x\n", sbsf->off); + log_content("addr:%06x\n", sbsf->off);
if (tx) sandbox_spi_tristate(&tx[pos], 1); @@ -380,8 +384,8 @@ static int sandbox_sf_xfer(struct udevice *dev, unsigned int bitlen, sbsf->state = SF_ERASE; goto case_sf_erase; } - debug(" cmd: transition to %s state\n", - sandbox_sf_state_name(sbsf->state)); + log_content(" cmd: transition to %s state\n", + sandbox_sf_state_name(sbsf->state)); break; case SF_READ: /* @@ -390,7 +394,7 @@ static int sandbox_sf_xfer(struct udevice *dev, unsigned int bitlen, */
cnt = bytes - pos; - debug(" tx: read(%u)\n", cnt); + log_content(" tx: read(%u)\n", cnt); assert(tx); ret = os_read(sbsf->fd, tx + pos, cnt); if (ret < 0) { @@ -400,19 +404,19 @@ static int sandbox_sf_xfer(struct udevice *dev, unsigned int bitlen, pos += ret; break; case SF_READ_STATUS: - debug(" read status: %#x\n", sbsf->status); + log_content(" read status: %#x\n", sbsf->status); cnt = bytes - pos; memset(tx + pos, sbsf->status, cnt); pos += cnt; break; case SF_READ_STATUS1: - debug(" read status: %#x\n", sbsf->status); + log_content(" read status: %#x\n", sbsf->status); cnt = bytes - pos; memset(tx + pos, sbsf->status >> 8, cnt); pos += cnt; break; case SF_WRITE_STATUS: - debug(" write status: %#x (ignored)\n", rx[pos]); + log_content(" write status: %#x (ignored)\n", rx[pos]); pos = bytes; break; case SF_WRITE: @@ -428,7 +432,7 @@ static int sandbox_sf_xfer(struct udevice *dev, unsigned int bitlen, }
cnt = bytes - pos; - debug(" rx: write(%u)\n", cnt); + log_content(" rx: write(%u)\n", cnt); if (tx) sandbox_spi_tristate(&tx[pos], cnt); ret = os_write(sbsf->fd, rx + pos, cnt); @@ -448,15 +452,15 @@ static int sandbox_sf_xfer(struct udevice *dev, unsigned int bitlen,
/* verify address is aligned */ if (sbsf->off & (sbsf->erase_size - 1)) { - debug(" sector erase: cmd:%#x needs align:%#x, but we got %#x\n", - sbsf->cmd, sbsf->erase_size, - sbsf->off); + log_content(" sector erase: cmd:%#x needs align:%#x, but we got %#x\n", + sbsf->cmd, sbsf->erase_size, + sbsf->off); sbsf->status &= ~STAT_WEL; goto done; }
- debug(" sector erase addr: %u, size: %u\n", sbsf->off, - sbsf->erase_size); + log_content(" sector erase addr: %u, size: %u\n", + sbsf->off, sbsf->erase_size);
cnt = bytes - pos; if (tx) @@ -470,13 +474,13 @@ static int sandbox_sf_xfer(struct udevice *dev, unsigned int bitlen, ret = sandbox_erase_part(sbsf, sbsf->erase_size); sbsf->status &= ~STAT_WEL; if (ret) { - debug("sandbox_sf: Erase failed\n"); + log_content("sandbox_sf: Erase failed\n"); goto done; } goto done; } default: - debug(" ??? no idea what to do ???\n"); + log_content(" ??? no idea what to do ???\n"); goto done; } } diff --git a/drivers/spi/sandbox_spi.c b/drivers/spi/sandbox_spi.c index 75ba6a1ed7e..906401ec8ab 100644 --- a/drivers/spi/sandbox_spi.c +++ b/drivers/spi/sandbox_spi.c @@ -8,6 +8,8 @@ * Licensed under the GPL-2 or later. */
+#define LOG_CATEGORY UCLASS_SPI + #include <common.h> #include <dm.h> #include <malloc.h> @@ -56,7 +58,6 @@ static int sandbox_spi_xfer(struct udevice *slave, unsigned int bitlen, struct udevice *emul; uint bytes = bitlen / 8, i; int ret; - u8 *tx = (void *)dout, *rx = din; uint busnum, cs;
if (bitlen == 0) @@ -87,37 +88,16 @@ static int sandbox_spi_xfer(struct udevice *slave, unsigned int bitlen, if (ret) return ret;
- /* make sure rx/tx buffers are full so clients can assume */ - if (!tx) { - debug("sandbox_spi: xfer: auto-allocating tx scratch buffer\n"); - tx = malloc(bytes); - if (!tx) { - debug("sandbox_spi: Out of memory\n"); - return -ENOMEM; - } - } - if (!rx) { - debug("sandbox_spi: xfer: auto-allocating rx scratch buffer\n"); - rx = malloc(bytes); - if (!rx) { - debug("sandbox_spi: Out of memory\n"); - return -ENOMEM; - } - } - ops = spi_emul_get_ops(emul); ret = ops->xfer(emul, bitlen, dout, din, flags);
- debug("sandbox_spi: xfer: got back %i (that's %s)\n rx:", - ret, ret ? "bad" : "good"); - for (i = 0; i < bytes; ++i) - debug(" %u:%02x", i, rx[i]); - debug("\n"); - - if (tx != dout) - free(tx); - if (rx != din) - free(rx); + log_content("sandbox_spi: xfer: got back %i (that's %s)\n rx:", + ret, ret ? "bad" : "good"); + if (din) { + for (i = 0; i < bytes; ++i) + log_content(" %u:%02x", i, ((u8 *)din)[i]); + } + log_content("\n");
return ret; } diff --git a/include/log.h b/include/log.h index 12168340d12..623f0fc32f7 100644 --- a/include/log.h +++ b/include/log.h @@ -47,6 +47,7 @@ enum log_category_t { LOGC_DT, /* Device-tree */ LOGC_EFI, /* EFI implementation */ LOGC_BLOBLIST, /* Bloblist */ + LOGC_ALLOC, /* Memory allocation */
LOGC_COUNT, LOGC_END,

Add logging to aid debugging features in these drivers. Also drop some code in sandbox_spi_xfer() which is not used.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mtd/spi/sandbox.c | 54 +++++++++++++++++++++------------------ drivers/spi/sandbox_spi.c | 38 +++++++-------------------- include/log.h | 1 + 3 files changed, 39 insertions(+), 54 deletions(-)
Applied to u-boot-dm

At present there are many situations where sandbox syncs the display to the SDL frame buffer. This is a very expensive operation but is only needed every now and then. Update video_sync() so that we can specify whether this operation is really needed.
At present this flag is not used on other architectures. It could also be used for reducing writeback-cache flushes but the benefit of that would need to be investigated.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/video/vidconsole-uclass.c | 12 ++++++------ drivers/video/video-uclass.c | 6 +++--- drivers/video/video_bmp.c | 2 +- include/video.h | 4 +++- test/dm/video.c | 2 +- 5 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 7f95e9c6e56..89ac8b3cc8f 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -86,7 +86,7 @@ static int vidconsole_back(struct udevice *dev) if (priv->ycur < 0) priv->ycur = 0; } - video_sync(dev->parent); + video_sync(dev->parent, false);
return 0; } @@ -113,7 +113,7 @@ static void vidconsole_newline(struct udevice *dev) } priv->last_ch = 0;
- video_sync(dev->parent); + video_sync(dev->parent, false); }
static const struct vid_rgb colors[VID_COLOR_COUNT] = { @@ -293,7 +293,7 @@ static void vidconsole_escape_char(struct udevice *dev, char ch)
if (mode == 2) { video_clear(dev->parent); - video_sync(dev->parent); + video_sync(dev->parent, false); priv->ycur = 0; priv->xcur_frac = priv->xstart_frac; } else { @@ -449,7 +449,7 @@ static void vidconsole_putc(struct stdio_dev *sdev, const char ch) struct udevice *dev = sdev->priv;
vidconsole_put_char(dev, ch); - video_sync(dev->parent); + video_sync(dev->parent, false); }
static void vidconsole_puts(struct stdio_dev *sdev, const char *s) @@ -458,7 +458,7 @@ static void vidconsole_puts(struct stdio_dev *sdev, const char *s)
while (*s) vidconsole_put_char(dev, *s++); - video_sync(dev->parent); + video_sync(dev->parent, false); }
/* Set up the number of rows and colours (rotated drivers override this) */ @@ -547,7 +547,7 @@ static int do_video_puts(cmd_tbl_t *cmdtp, int flag, int argc, for (s = argv[1]; *s; s++) vidconsole_put_char(dev, *s);
- video_sync(dev->parent); + video_sync(dev->parent, false);
return 0; } diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index dd0873767ba..fea0886c415 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -128,7 +128,7 @@ void video_set_default_colors(struct video_priv *priv) }
/* Flush video activity to the caches */ -void video_sync(struct udevice *vid) +void video_sync(struct udevice *vid, bool force) { /* * flush_dcache_range() is declared in common.h but it seems that some @@ -147,7 +147,7 @@ void video_sync(struct udevice *vid) struct video_priv *priv = dev_get_uclass_priv(vid); static ulong last_sync;
- if (get_timer(last_sync) > 10) { + if (force || get_timer(last_sync) > 10) { sandbox_sdl_sync(priv->fb); last_sync = get_timer(0); } @@ -162,7 +162,7 @@ void video_sync_all(void) dev; uclass_find_next_device(&dev)) { if (device_active(dev)) - video_sync(dev); + video_sync(dev, true); } }
diff --git a/drivers/video/video_bmp.c b/drivers/video/video_bmp.c index aeff65648c1..1377e190817 100644 --- a/drivers/video/video_bmp.c +++ b/drivers/video/video_bmp.c @@ -345,7 +345,7 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y, break; };
- video_sync(dev); + video_sync(dev, false);
return 0; } diff --git a/include/video.h b/include/video.h index e7fc5c94e2e..cd5558f86eb 100644 --- a/include/video.h +++ b/include/video.h @@ -131,8 +131,10 @@ void video_clear(struct udevice *dev); * buffer are displayed to the user. * * @dev: Device to sync + * @force: True to force a sync even if there was one recently (this is + * very expensive on sandbox) */ -void video_sync(struct udevice *vid); +void video_sync(struct udevice *vid, bool force);
/** * video_sync_all() - Sync all devices' frame buffers with there hardware diff --git a/test/dm/video.c b/test/dm/video.c index ef74c2de721..7def338058e 100644 --- a/test/dm/video.c +++ b/test/dm/video.c @@ -169,7 +169,7 @@ static int dm_test_video_ansi(struct unit_test_state *uts)
/* reference clear: */ video_clear(con->parent); - video_sync(con->parent); + video_sync(con->parent, false); ut_asserteq(46, compress_frame_buffer(dev));
/* test clear escape sequence: [2J */

On Mon, 1 Oct 2018 11:55:14 -0600 Simon Glass sjg@chromium.org wrote:
At present there are many situations where sandbox syncs the display to the SDL frame buffer. This is a very expensive operation but is only needed every now and then. Update video_sync() so that we can specify whether this operation is really needed.
At present this flag is not used on other architectures. It could also be used for reducing writeback-cache flushes but the benefit of that would need to be investigated.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Anatolij Gustschin agust@denx.de
-- Anatolij

On Mon, 1 Oct 2018 11:55:14 -0600 Simon Glass sjg@chromium.org wrote:
At present there are many situations where sandbox syncs the display to the SDL frame buffer. This is a very expensive operation but is only needed every now and then. Update video_sync() so that we can specify whether this operation is really needed.
At present this flag is not used on other architectures. It could also be used for reducing writeback-cache flushes but the benefit of that would need to be investigated.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Anatolij Gustschin agust@denx.de
-- Anatolij
Applied to u-boot-dm

Add support for the debug UART so that sandbox provides build testing for this feature.
Signed-off-by: Simon Glass sjg@chromium.org ---
configs/sandbox_defconfig | 2 ++ drivers/serial/Kconfig | 11 +++++++++++ drivers/serial/sandbox.c | 17 +++++++++++++++++ 3 files changed, 30 insertions(+)
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 1c4a3330b4f..2ce336fc81c 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -1,5 +1,6 @@ CONFIG_SYS_TEXT_BASE=0 CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_DEBUG_UART=y CONFIG_DISTRO_DEFAULTS=y CONFIG_NR_DRAM_BANKS=1 CONFIG_ANDROID_BOOT_IMAGE=y @@ -173,6 +174,7 @@ CONFIG_REMOTEPROC_SANDBOX=y CONFIG_DM_RESET=y CONFIG_SANDBOX_RESET=y CONFIG_DM_RTC=y +CONFIG_DEBUG_UART_SANDBOX=y CONFIG_SANDBOX_SERIAL=y CONFIG_SMEM=y CONFIG_SANDBOX_SMEM=y diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 5fa27254e30..83f8c94d028 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -324,6 +324,15 @@ config DEBUG_UART_MXC will need to provide parameters to make this work. The driver will be available until the real driver model serial is running.
+config DEBUG_UART_SANDBOX + bool "sandbox" + depends on SANDBOX_SERIAL + help + Select this to enable the debug UART using the sandbox driver. This + provides basic serial output from the console without needing to + start up driver model. The driver will be available until the real + driver model serial is running. + config DEBUG_UART_STM32 bool "STMicroelectronics STM32" depends on STM32_SERIAL @@ -354,6 +363,7 @@ endchoice config DEBUG_UART_BASE hex "Base address of UART" depends on DEBUG_UART + default 0 if DEBUG_UART_SANDBOX help This is the base address of your UART for memory-mapped UARTs.
@@ -363,6 +373,7 @@ config DEBUG_UART_BASE config DEBUG_UART_CLOCK int "UART input clock" depends on DEBUG_UART + default 0 if DEBUG_UART_SANDBOX help The UART input clock determines the speed of the internal UART circuitry. The baud rate is derived from this by dividing the input diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c index 94b4fdfb171..4fbc5956b76 100644 --- a/drivers/serial/sandbox.c +++ b/drivers/serial/sandbox.c @@ -143,6 +143,23 @@ static int sandbox_serial_getc(struct udevice *dev) return result; }
+#ifdef CONFIG_DEBUG_UART_SANDBOX + +#include <debug_uart.h> + +static inline void _debug_uart_init(void) +{ +} + +static inline void _debug_uart_putc(int ch) +{ + os_putc(ch); +} + +DEBUG_UART_FUNCS + +#endif /* CONFIG_DEBUG_UART_SANDBOX */ + static int sandbox_serial_setconfig(struct udevice *dev, uint serial_config) { u8 parity = SERIAL_GET_PARITY(serial_config);

Add support for the debug UART so that sandbox provides build testing for this feature.
Signed-off-by: Simon Glass sjg@chromium.org ---
configs/sandbox_defconfig | 2 ++ drivers/serial/Kconfig | 11 +++++++++++ drivers/serial/sandbox.c | 17 +++++++++++++++++ 3 files changed, 30 insertions(+)
Applied to u-boot-dm

At present sandbox assumes that device-tree control is active, but this may not be the case in SPL or TPL. Add some conditions to handle this.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/serial/sandbox.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c index 4fbc5956b76..9e9bf3e011f 100644 --- a/drivers/serial/sandbox.c +++ b/drivers/serial/sandbox.c @@ -22,6 +22,8 @@
DECLARE_GLOBAL_DATA_PTR;
+#if CONFIG_IS_ENABLED(OF_CONTROL) + /* * * serial_buf: A buffer that holds keyboard characters for the @@ -142,6 +144,7 @@ static int sandbox_serial_getc(struct udevice *dev) serial_buf_read = increment_buffer_index(serial_buf_read); return result; } +#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
#ifdef CONFIG_DEBUG_UART_SANDBOX
@@ -173,6 +176,7 @@ static int sandbox_serial_setconfig(struct udevice *dev, uint serial_config) return 0; }
+#if CONFIG_IS_ENABLED(OF_CONTROL) static const char * const ansi_colour[] = { "black", "red", "green", "yellow", "blue", "megenta", "cyan", "white", @@ -232,3 +236,4 @@ U_BOOT_DEVICE(serial_sandbox_non_fdt) = { .name = "serial_sandbox", .platdata = &platdata_non_fdt, }; +#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */

At present sandbox assumes that device-tree control is active, but this may not be the case in SPL or TPL. Add some conditions to handle this.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/serial/sandbox.c | 5 +++++ 1 file changed, 5 insertions(+)
Applied to u-boot-dm

Use an enum for command values instead of open-coding them. This removes the need for comments. Also make sure the driver returns proper error numbers instead of -1.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/tpm/tpm_tis_sandbox.c | 20 ++++++++++---------- include/tpm-v1.h | 14 ++++++++++++++ include/tpm-v2.h | 1 + 3 files changed, 25 insertions(+), 10 deletions(-)
diff --git a/drivers/tpm/tpm_tis_sandbox.c b/drivers/tpm/tpm_tis_sandbox.c index 8816d55759f..c0b35a06c8a 100644 --- a/drivers/tpm/tpm_tis_sandbox.c +++ b/drivers/tpm/tpm_tis_sandbox.c @@ -151,10 +151,10 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, *recv_len, code); print_buffer(0, sendbuf, 1, send_size, 0); switch (code) { - case 0x65: /* get flags */ + case TPM_CMD_GET_CAPABILITY: type = get_unaligned_be32(sendbuf + 14); switch (type) { - case 4: + case TPM_CAP_FLAG: index = get_unaligned_be32(sendbuf + 18); printf("Get flags index %#02x\n", index); *recv_len = 22; @@ -173,7 +173,7 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, break; } break; - case 0x11: /* TPM_CAP_NV_INDEX */ + case TPM_CAP_NV_INDEX: index = get_unaligned_be32(sendbuf + 18); printf("Get cap nv index %#02x\n", index); put_unaligned_be32(22, recvbuf + @@ -182,26 +182,26 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, default: printf(" ** Unknown 0x65 command type %#02x\n", type); - return -1; + return -ENOSYS; } break; - case 0xcd: /* nvwrite */ + case TPM_CMD_NV_WRITE_VALUE: index = get_unaligned_be32(sendbuf + 10); length = get_unaligned_be32(sendbuf + 18); seq = index_to_seq(index); if (seq < 0) - return -1; + return -EINVAL; printf("tpm: nvwrite index=%#02x, len=%#02x\n", index, length); memcpy(&tpm->nvdata[seq], sendbuf + 22, length); *recv_len = 12; memset(recvbuf, '\0', *recv_len); break; - case 0xcf: /* nvread */ + case TPM_CMD_NV_READ_VALUE: /* nvread */ index = get_unaligned_be32(sendbuf + 10); length = get_unaligned_be32(sendbuf + 18); seq = index_to_seq(index); if (seq < 0) - return -1; + return -EINVAL; printf("tpm: nvread index=%#02x, len=%#02x\n", index, length); *recv_len = TPM_RESPONSE_HEADER_LENGTH + sizeof(uint32_t) + length; @@ -225,7 +225,7 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, sizeof(uint32_t), &tpm->nvdata[seq], length); } break; - case 0x14: /* tpm extend */ + case TPM_CMD_EXTEND: /* tpm extend */ case 0x15: /* pcr read */ case 0x5d: /* force clear */ case 0x6f: /* physical enable */ @@ -237,7 +237,7 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, break; default: printf("Unknown tpm command %02x\n", code); - return -1; + return -ENOSYS; }
return 0; diff --git a/include/tpm-v1.h b/include/tpm-v1.h index 6b4941ef9a2..29788b5390f 100644 --- a/include/tpm-v1.h +++ b/include/tpm-v1.h @@ -81,6 +81,12 @@ enum tpm_capability_areas { TPM_CAP_VERSION_VAL = 0x0000001A, };
+enum tmp_cap_flag { + TPM_CAP_FLAG_PERMANENT = 0x108, +}; + +#define TPM_TAG_PERMANENT_FLAGS 0x001f + #define TPM_NV_PER_GLOBALLOCK BIT(15) #define TPM_NV_PER_PPREAD BIT(16) #define TPM_NV_PER_PPWRITE BIT(0) @@ -93,6 +99,14 @@ enum { TPM_PUBEK_SIZE = 256, };
+enum { + TPM_CMD_EXTEND = 0x14, + TPM_CMD_GET_CAPABILITY = 0x65, + TPM_CMD_NV_DEFINE_SPACE = 0xcc, + TPM_CMD_NV_WRITE_VALUE = 0xcd, + TPM_CMD_NV_READ_VALUE = 0xcf, +}; + /** * TPM return codes as defined in the TCG Main specification * (TPM Main Part 2 Structures; Specification version 1.2) diff --git a/include/tpm-v2.h b/include/tpm-v2.h index 780e0619750..c77b416182e 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -83,6 +83,7 @@ enum tpm2_command_codes { TPM2_CC_PCR_SETAUTHPOL = 0x012C, TPM2_CC_DAM_RESET = 0x0139, TPM2_CC_DAM_PARAMETERS = 0x013A, + TPM2_CC_NV_READ = 0x014E, TPM2_CC_GET_CAPABILITY = 0x017A, TPM2_CC_PCR_READ = 0x017E, TPM2_CC_PCR_EXTEND = 0x0182,

Use an enum for command values instead of open-coding them. This removes the need for comments. Also make sure the driver returns proper error numbers instead of -1.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/tpm/tpm_tis_sandbox.c | 20 ++++++++++---------- include/tpm-v1.h | 14 ++++++++++++++ include/tpm-v2.h | 1 + 3 files changed, 25 insertions(+), 10 deletions(-)
Applied to u-boot-dm

This driver was originally written against Chromium OS circa 2012. A few new features have been added. Enhance the TPM driver to match. This mostly includes a few new messages and properly modelling whether a particular 'space' is present or not.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/tpm/tpm_tis_sandbox.c | 97 +++++++++++++++++++++++++++++------ include/tpm-v1.h | 34 ++++++++++++ 2 files changed, 116 insertions(+), 15 deletions(-)
diff --git a/drivers/tpm/tpm_tis_sandbox.c b/drivers/tpm/tpm_tis_sandbox.c index c0b35a06c8a..79517f015af 100644 --- a/drivers/tpm/tpm_tis_sandbox.c +++ b/drivers/tpm/tpm_tis_sandbox.c @@ -13,6 +13,10 @@ /* TPM NVRAM location indices. */ #define FIRMWARE_NV_INDEX 0x1007 #define KERNEL_NV_INDEX 0x1008 +#define BACKUP_NV_INDEX 0x1009 +#define FWMP_NV_INDEX 0x100a +#define REC_HASH_NV_INDEX 0x100b +#define REC_HASH_NV_SIZE VB2_SHA256_DIGEST_SIZE
#define NV_DATA_PUBLIC_PERMISSIONS_OFFSET 60
@@ -45,18 +49,28 @@ enum { NV_GLOBAL_LOCK, NV_SEQ_FIRMWARE, NV_SEQ_KERNEL, + NV_SEQ_BACKUP, + NV_SEQ_FWMP, + NV_SEQ_REC_HASH, + NV_SEQ_COUNT, };
/* Size of each non-volatile space */ #define NV_DATA_SIZE 0x20
+struct nvdata_state { + bool present; + u8 data[NV_DATA_SIZE]; +}; + /* * Information about our TPM emulation. This is preserved in the sandbox * state file if enabled. */ static struct tpm_state { - uint8_t nvdata[NV_SEQ_COUNT][NV_DATA_SIZE]; + bool valid; + struct nvdata_state nvdata[NV_SEQ_COUNT]; } g_state;
/** @@ -82,9 +96,12 @@ static int sandbox_tpm_read_state(const void *blob, int node)
sprintf(prop_name, "nvdata%d", i); prop = fdt_getprop(blob, node, prop_name, &len); - if (prop && len == NV_DATA_SIZE) - memcpy(g_state.nvdata[i], prop, NV_DATA_SIZE); + if (prop && len == NV_DATA_SIZE) { + memcpy(g_state.nvdata[i].data, prop, NV_DATA_SIZE); + g_state.nvdata[i].present = true; + } } + g_state.valid = true;
return 0; } @@ -110,9 +127,11 @@ static int sandbox_tpm_write_state(void *blob, int node) for (i = 0; i < NV_SEQ_COUNT; i++) { char prop_name[20];
- sprintf(prop_name, "nvdata%d", i); - fdt_setprop(blob, node, prop_name, g_state.nvdata[i], - NV_DATA_SIZE); + if (g_state.nvdata[i].present) { + sprintf(prop_name, "nvdata%d", i); + fdt_setprop(blob, node, prop_name, + g_state.nvdata[i].data, NV_DATA_SIZE); + } }
return 0; @@ -128,6 +147,12 @@ static int index_to_seq(uint32_t index) return NV_SEQ_FIRMWARE; case KERNEL_NV_INDEX: return NV_SEQ_KERNEL; + case BACKUP_NV_INDEX: + return NV_SEQ_BACKUP; + case FWMP_NV_INDEX: + return NV_SEQ_FWMP; + case REC_HASH_NV_INDEX: + return NV_SEQ_REC_HASH; case 0: return NV_GLOBAL_LOCK; } @@ -136,6 +161,21 @@ static int index_to_seq(uint32_t index) return -1; }
+static void handle_cap_flag_space(u8 **datap, uint index) +{ + struct tpm_nv_data_public pub; + + /* TPM_NV_PER_PPWRITE */ + memset(&pub, '\0', sizeof(pub)); + pub.nv_index = __cpu_to_be32(index); + pub.pcr_info_read.pcr_selection.size_of_select = __cpu_to_be16( + sizeof(pub.pcr_info_read.pcr_selection.pcr_select)); + pub.permission.attributes = __cpu_to_be32(1); + pub.pcr_info_write = pub.pcr_info_read; + memcpy(*datap, &pub, sizeof(pub)); + *datap += sizeof(pub); +} + static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, size_t send_size, uint8_t *recvbuf, size_t *recv_len) @@ -159,19 +199,35 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, printf("Get flags index %#02x\n", index); *recv_len = 22; memset(recvbuf, '\0', *recv_len); - put_unaligned_be32(22, recvbuf + - TPM_RESPONSE_HEADER_LENGTH); data = recvbuf + TPM_RESPONSE_HEADER_LENGTH + sizeof(uint32_t); switch (index) { case FIRMWARE_NV_INDEX: break; case KERNEL_NV_INDEX: - /* TPM_NV_PER_PPWRITE */ - put_unaligned_be32(1, data + - NV_DATA_PUBLIC_PERMISSIONS_OFFSET); + handle_cap_flag_space(&data, index); + *recv_len = data - recvbuf - + TPM_RESPONSE_HEADER_LENGTH - + sizeof(uint32_t); + break; + case TPM_CAP_FLAG_PERMANENT: { + struct tpm_permanent_flags *pflags; + + pflags = (struct tpm_permanent_flags *)data; + memset(pflags, '\0', sizeof(*pflags)); + put_unaligned_be32(TPM_TAG_PERMANENT_FLAGS, + &pflags->tag); + *recv_len = TPM_HEADER_SIZE + 4 + + sizeof(*pflags); break; } + default: + printf(" ** Unknown flags index %x\n", index); + return -ENOSYS; + } + put_unaligned_be32(*recv_len, + recvbuf + + TPM_RESPONSE_HEADER_LENGTH); break; case TPM_CAP_NV_INDEX: index = get_unaligned_be32(sendbuf + 18); @@ -192,7 +248,8 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, if (seq < 0) return -EINVAL; printf("tpm: nvwrite index=%#02x, len=%#02x\n", index, length); - memcpy(&tpm->nvdata[seq], sendbuf + 22, length); + memcpy(&tpm->nvdata[seq].data, sendbuf + 22, length); + tpm->nvdata[seq].present = true; *recv_len = 12; memset(recvbuf, '\0', *recv_len); break; @@ -202,7 +259,8 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, seq = index_to_seq(index); if (seq < 0) return -EINVAL; - printf("tpm: nvread index=%#02x, len=%#02x\n", index, length); + printf("tpm: nvread index=%#02x, len=%#02x, seq=%#02x\n", index, + length, seq); *recv_len = TPM_RESPONSE_HEADER_LENGTH + sizeof(uint32_t) + length; memset(recvbuf, '\0', *recv_len); @@ -220,17 +278,26 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, offsetof(struct rollback_space_kernel, crc8)); memcpy(data, &rsk, sizeof(rsk)); + } else if (!tpm->nvdata[seq].present) { + put_unaligned_be32(TPM_BADINDEX, recvbuf + + sizeof(uint16_t) + sizeof(uint32_t)); } else { memcpy(recvbuf + TPM_RESPONSE_HEADER_LENGTH + - sizeof(uint32_t), &tpm->nvdata[seq], length); + sizeof(uint32_t), &tpm->nvdata[seq].data, + length); } break; - case TPM_CMD_EXTEND: /* tpm extend */ + case TPM_CMD_EXTEND: + *recv_len = 30; + memset(recvbuf, '\0', *recv_len); + break; + case TPM_CMD_NV_DEFINE_SPACE: case 0x15: /* pcr read */ case 0x5d: /* force clear */ case 0x6f: /* physical enable */ case 0x72: /* physical set deactivated */ case 0x99: /* startup */ + case 0x50: /* self test full */ case 0x4000000a: /* assert physical presence */ *recv_len = 12; memset(recvbuf, '\0', *recv_len); diff --git a/include/tpm-v1.h b/include/tpm-v1.h index 29788b5390f..f9ffbb26561 100644 --- a/include/tpm-v1.h +++ b/include/tpm-v1.h @@ -245,6 +245,40 @@ struct tpm_permanent_flags { u8 disable_full_da_logic_info; } __packed;
+#define TPM_SHA1_160_HASH_LEN 0x14 + +struct __packed tpm_composite_hash { + u8 digest[TPM_SHA1_160_HASH_LEN]; +}; + +struct __packed tpm_pcr_selection { + __be16 size_of_select; + u8 pcr_select[3]; /* matches vboot's struct */ +}; + +struct __packed tpm_pcr_info_short { + struct tpm_pcr_selection pcr_selection; + u8 locality_at_release; + struct tpm_composite_hash digest_at_release; +}; + +struct __packed tpm_nv_attributes { + __be16 tag; + __be32 attributes; +}; + +struct __packed tpm_nv_data_public { + __be16 tag; + __be32 nv_index; + struct tpm_pcr_info_short pcr_info_read; + struct tpm_pcr_info_short pcr_info_write; + struct tpm_nv_attributes permission; + u8 read_st_clear; + u8 write_st_clear; + u8 write_define; + __be32 data_size; +}; + /** * Issue a TPM_Startup command. *

This driver was originally written against Chromium OS circa 2012. A few new features have been added. Enhance the TPM driver to match. This mostly includes a few new messages and properly modelling whether a particular 'space' is present or not.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/tpm/tpm_tis_sandbox.c | 97 +++++++++++++++++++++++++++++------ include/tpm-v1.h | 34 ++++++++++++ 2 files changed, 116 insertions(+), 15 deletions(-)
Applied to u-boot-dm

Now that we don't have to deal with the command-line flag we can simplify the code for detecting the emulator. Remove the lookup based on the SPI specification, relying just on the device tree to locate the emulator.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/include/asm/state.h | 1 - drivers/mtd/spi/sandbox.c | 18 ++++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-)
diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h index d1baba1c3ae..1ccc8e02b9f 100644 --- a/arch/sandbox/include/asm/state.h +++ b/arch/sandbox/include/asm/state.h @@ -36,7 +36,6 @@ enum state_terminal_raw { };
struct sandbox_spi_info { - const char *spec; struct udevice *emul; };
diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c index 514484eba06..7fef754c634 100644 --- a/drivers/mtd/spi/sandbox.c +++ b/drivers/mtd/spi/sandbox.c @@ -115,24 +115,22 @@ static int sandbox_sf_probe(struct udevice *dev) const struct spi_flash_info *data; struct sandbox_spi_flash_plat_data *pdata = dev_get_platdata(dev); struct sandbox_state *state = state_get_current(); + struct dm_spi_slave_platdata *slave_plat; struct udevice *bus = dev->parent; const char *spec = NULL; + struct udevice *emul; int ret = 0; int cs = -1; - int i;
debug("%s: bus %d, looking for emul=%p: ", __func__, bus->seq, dev); - if (bus->seq >= 0 && bus->seq < CONFIG_SANDBOX_SPI_MAX_BUS) { - for (i = 0; i < CONFIG_SANDBOX_SPI_MAX_CS; i++) { - if (state->spi[bus->seq][i].emul == dev) - cs = i; - } - } - if (cs == -1) { + ret = sandbox_spi_get_emul(state, bus, dev, &emul); + if (ret) { printf("Error: Unknown chip select for device '%s'\n", - dev->name); - return -EINVAL; + dev->name); + return ret; } + slave_plat = dev_get_parent_platdata(dev); + cs = slave_plat->cs; debug("found at cs %d\n", cs);
if (!pdata->filename) {

Now that we don't have to deal with the command-line flag we can simplify the code for detecting the emulator. Remove the lookup based on the SPI specification, relying just on the device tree to locate the emulator.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/include/asm/state.h | 1 - drivers/mtd/spi/sandbox.c | 18 ++++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-)
Applied to u-boot-dm

At present sandbox sets non-blocking I/O as soon as any input is read from the terminal. However it does not restore the previous state on exit. Fix this and drop the old os_read_no_block() function.
This means that we always enable blocking I/O in sandbox (if input is a terminal) whereas previously it would only happen on the first call to tstc() or getc(). However, the difference is likely not important.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/os.c | 23 +++++++++++++++-------- drivers/serial/sandbox.c | 2 +- include/os.h | 10 ---------- 3 files changed, 16 insertions(+), 19 deletions(-)
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index a7f17034862..97d9b29407c 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -38,14 +38,6 @@ ssize_t os_read(int fd, void *buf, size_t count) return read(fd, buf, count); }
-ssize_t os_read_no_block(int fd, void *buf, size_t count) -{ - const int flags = fcntl(fd, F_GETFL, 0); - - fcntl(fd, F_SETFL, flags | O_NONBLOCK); - return os_read(fd, buf, count); -} - ssize_t os_write(int fd, const void *buf, size_t count) { return write(fd, buf, count); @@ -129,11 +121,18 @@ int os_write_file(const char *name, const void *buf, int size) /* Restore tty state when we exit */ static struct termios orig_term; static bool term_setup; +static bool term_nonblock;
void os_fd_restore(void) { if (term_setup) { + int flags; + tcsetattr(0, TCSANOW, &orig_term); + if (term_nonblock) { + flags = fcntl(0, F_GETFL, 0); + fcntl(0, F_SETFL, flags & ~O_NONBLOCK); + } term_setup = false; } } @@ -142,6 +141,7 @@ void os_fd_restore(void) void os_tty_raw(int fd, bool allow_sigs) { struct termios term; + int flags;
if (term_setup) return; @@ -158,6 +158,13 @@ void os_tty_raw(int fd, bool allow_sigs) if (tcsetattr(fd, TCSANOW, &term)) return;
+ flags = fcntl(fd, F_GETFL, 0); + if (!(flags & O_NONBLOCK)) { + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) + return; + term_nonblock = true; + } + term_setup = true; atexit(os_fd_restore); } diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c index 9e9bf3e011f..4a05ea44ce9 100644 --- a/drivers/serial/sandbox.c +++ b/drivers/serial/sandbox.c @@ -126,7 +126,7 @@ static int sandbox_serial_pending(struct udevice *dev, bool input) if (next_index == serial_buf_read) return 1; /* buffer full */
- count = os_read_no_block(0, &serial_buf[serial_buf_write], 1); + count = os_read(0, &serial_buf[serial_buf_write], 1); if (count == 1) serial_buf_write = next_index;
diff --git a/include/os.h b/include/os.h index efa9e52d124..28eb6252849 100644 --- a/include/os.h +++ b/include/os.h @@ -26,16 +26,6 @@ struct sandbox_state; */ ssize_t os_read(int fd, void *buf, size_t count);
-/** - * Access to the OS read() system call with non-blocking access - * - * \param fd File descriptor as returned by os_open() - * \param buf Buffer to place data - * \param count Number of bytes to read - * \return number of bytes read, or -1 on error - */ -ssize_t os_read_no_block(int fd, void *buf, size_t count); - /** * Access to the OS write() system call *

At present sandbox sets non-blocking I/O as soon as any input is read from the terminal. However it does not restore the previous state on exit. Fix this and drop the old os_read_no_block() function.
This means that we always enable blocking I/O in sandbox (if input is a terminal) whereas previously it would only happen on the first call to tstc() or getc(). However, the difference is likely not important.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/os.c | 23 +++++++++++++++-------- drivers/serial/sandbox.c | 2 +- include/os.h | 10 ---------- 3 files changed, 16 insertions(+), 19 deletions(-)
Applied to u-boot-dm
participants (3)
-
Anatolij Gustschin
-
Simon Glass
-
sjg@google.com