diff --git a/.gitlab-ci.d/opentitan/qemu-ot.yml b/.gitlab-ci.d/opentitan/qemu-ot.yml index 7fa79370899b..41bab7554e82 100644 --- a/.gitlab-ci.d/opentitan/qemu-ot.yml +++ b/.gitlab-ci.d/opentitan/qemu-ot.yml @@ -1,5 +1,5 @@ variables: - BAREMETAL_REF: "240606-1" + BAREMETAL_REF: "240703-1" QEMU_BUILD_OPTS: "" include: diff --git a/docs/opentitan/darjeeling.md b/docs/opentitan/darjeeling.md index 800a9cfbbbc4..7bbfe7ad1371 100644 --- a/docs/opentitan/darjeeling.md +++ b/docs/opentitan/darjeeling.md @@ -135,7 +135,8 @@ See [`tools.md`](tools.md) is set to 10 MHz. This option is very useful/mandatory to run many OpenTitan tests that rely on time or CPU cycle to validate features. Using `-icount` option slows down execution speed though, so it is not recommended to use it when the main goal is to develop SW to run on the virtual - machine. + machine. An alternative is to use `-icount shift=auto`, which offers fatest emulation execution, + while preserving an accurate ratio between the vCPU clock and the virtual devices. * `no_epmp_cfg=true` can be appended to the machine option switch, _i.e._ `-M ot-darjeeeling,no_epmp_cfg=true` to disable the initial ePMP configuration, which can be very @@ -162,6 +163,10 @@ See [`tools.md`](tools.md) * `-cpu lowrisc-ibex,x-zbr=false` can be used to force disable the Zbr experimental-and-deprecated RISC-V bitmap extension for CRC32 extension. +* `-global ot-rstmgr.fatal_reset=N`, where `N` is an unsigned integer. Force QEMU VM to exit the + N^th^ time the reset manager received a reset request, rather than rebooting the whole machine as + the default behavior. + ### AES * `-global ot-aes.fast-mode=false` can be used to better emulate AES HW IP, as some OT tests expect diff --git a/docs/opentitan/dtm.md b/docs/opentitan/dtm.md index 9a8a1c6df876..09a01682e495 100644 --- a/docs/opentitan/dtm.md +++ b/docs/opentitan/dtm.md @@ -1,14 +1,14 @@ # `dtm.py` -`dtm.py` checks that the JTAG/DTM/DM stack is up and running and demonstrates how to use the -Debug Module to access the Ibex core. +`dtm.py` checks that the JTAG/DTM/DM stack is up and running and demonstrates how to use the Debug +Module to access the Ibex core. ## Usage ````text -usage: dtm.py [-h] [-H HOST] [-P PORT] [-Q] [-l IR_LENGTH] [-b BASE] [-I] [-c] - [-C MISA_CHECK] [-x] [-X] [-a ADDRESS] [-m {read,write}] - [-s SIZE] [-f FILE] [-e ELF] [-v] [-d] +usage: dtm.py [-h] [-H HOST] [-P PORT] [-Q] [-t] [-l IR_LENGTH] [-b BASE] [-I] + [-c CSR] [-C CSR_CHECK] [-x] [-X] [-a ADDRESS] [-m {read,write}] + [-s SIZE] [-f FILE] [-e ELF] [-F] [-v] [-d] Debug Transport Module tiny demo @@ -18,12 +18,12 @@ options: Virtual machine: -H HOST, --host HOST JTAG host (default: localhost) -P PORT, --port PORT JTAG port, default: 3335 - -Q, --no-quit do not ask the QEMU to quit on exit + -t, --terminate terminate QEMU when done DMI: -l IR_LENGTH, --ir-length IR_LENGTH - bit length of the IR register - -b BASE, --base BASE define DMI base address + bit length of the IR register (default: 5) + -b BASE, --base BASE define DMI base address (default: 0x0) Info: -I, --info report JTAG ID code and DTM configuration @@ -85,13 +85,13 @@ Extras: * `-P` specify the TCP port of the JTAG server in the QEMU VM, should follow the TCP setting of the `-chardev socket,id=taprbb,...` option for invoking QEMU. -* `-Q` do not send QEMU a request for termination when this script exits. - * `-s` specify the number of bytes to read from or write to memory. Useful with the `--mem` option. See also the `--address` option. This option may be omitted for the `write` memory operation, in which case the size of the specified file is used. Note that only sizes multiple of 4-byte are supported for now. +* `-t` send QEMU a request for termination when this script exits. + * `-v` can be repeated to increase verbosity of the script, mostly for debug purpose. * `-X` do not attempt to resume normal execution of the hart once DTM operation have been completed. diff --git a/docs/opentitan/pyot.md b/docs/opentitan/pyot.md index cbffa6e8df39..a801ed2a4fdd 100644 --- a/docs/opentitan/pyot.md +++ b/docs/opentitan/pyot.md @@ -5,12 +5,13 @@ ## Usage ````text -usage: pyot.py [-h] [-D DELAY] [-i ICOUNT] [-L LOG_FILE] [-M LOG] [-m MACHINE] - [-Q OPTS] [-q QEMU] [-p DEVICE] [-t TRACE] [-S FIRST_SOC] [-s] - [-U] [-b file] [-c JSON] [-e] [-f RAW] [-K] [-l file] [-O RAW] - [-o VMEM] [-r ELF] [-w CSV] [-x file] [-X] [-F TEST] - [-k SECONDS] [-z] [-R] [-T FACTOR] [-Z] [-v] [-d] [--log-time] - [--debug LOGGER] [--info LOGGER] [--warn LOGGER] +usage: pyot.py [-h] [-D DELAY] [-i ICOUNT] [-L LOG_FILE] [-M VARIANT] [-N LOG] + [-m MACHINE] [-Q OPTS] [-q QEMU] [-P VCP] [-p DEVICE] + [-t TRACE] [-S FIRST_SOC] [-s] [-U] [-b file] [-c JSON] [-e] + [-f RAW] [-K] [-l file] [-O RAW] [-o VMEM] [-r ELF] [-w CSV] + [-x file] [-X] [-F TEST] [-k SECONDS] [-z] [-R] [-T FACTOR] + [-Z] [-v] [-V] [-d] [--log-time] [--debug LOGGER] + [--info LOGGER] [--warn LOGGER] OpenTitan QEMU unit test sequencer. @@ -25,14 +26,18 @@ Virtual machine: per inst. or 'auto' -L LOG_FILE, --log_file LOG_FILE log file for trace and log messages - -M LOG, --log LOG log message types + -M VARIANT, --variant VARIANT + machine variant (machine specific) + -N LOG, --log LOG log message types -m MACHINE, --machine MACHINE virtual machine (default to ot-earlgrey) -Q OPTS, --opts OPTS QEMU verbatim option (can be repeated) -q QEMU, --qemu QEMU path to qemu application (default: build/qemu-system- riscv32) + -P VCP, --vcp VCP serial port devices (default: use serial0) -p DEVICE, --device DEVICE - serial port device name (default to localhost:8000) + serial port device name / template name (default to + localhost:8000) -t TRACE, --trace TRACE trace event definition file -S FIRST_SOC, --first-soc FIRST_SOC @@ -73,6 +78,7 @@ Execution: Extras: -v, --verbose increase verbosity + -V, --vcp-verbose increase verbosity of QEMU virtual comm ports -d enable debug mode --log-time show local time in log messages --debug LOGGER assign debug level to logger(s) @@ -95,12 +101,16 @@ This tool may be used in two ways, which can be combined: Use 'auto' to enable QEMU adaptive icount counter. Note that this option slows down the execution of guest applications. * `-L` / `--log_file` specify the log file for trace and log messages from QEMU. -* `-M` / `--log` specify which log message types should be logged; most useful types are: - * `in_asm` for guest instruction disassembly, - * `unimp` for uimplemented guest features, - * `int` for guest interrupts and exceptions, - * `guest_errors` for unexpected guest behavior, - * `exec` for guest execution stream (caution: highly verbose). +* `-N` / `--log` specify which log message types should be logged; most useful types are: + * `in_asm`/`A` for guest instruction disassembly, + * `unimp`/`U` for uimplemented guest features, + * `int`/`I` for guest interrupts and exceptions, + * `guest_errors`/`G` for unexpected guest behavior, + * `exec`/`E` for guest execution stream (caution: highly verbose). + These definitions may be abbreviated using their upper case, single char variants, _e.g._ + `-N GIU` would enable _guest_errors_, _interruptions_ and _unimplemented features_ logs. +* `-M` / `--variant` specify a variant of the selected machine. The accepted values depend on the + machine, see `-m` option. * `-m` / `--machine` specify the kind of virtual machine to run. * `-q` / `--qemu` specify an alternative path to the QEMU application. * `-Q` / `--opts` add a single QEMU option forwarded verbatim to QEMU (no check is performed) @@ -165,6 +175,7 @@ This tool may be used in two ways, which can be combined: ### Extras +* `-V` / `--vcp-verbose` can be repeated to increase verbosity of the QEMU virtual comm ports * `-v` / `--verbose` can be repeated to increase verbosity of the script, mostly for debug purpose. * `-d` only useful to debug the script, reports any Python traceback to the standard error stream. * `--log-time` show local time before each logged message diff --git a/docs/opentitan/spi_device.md b/docs/opentitan/spi_device.md index 12dd09f14822..2fcdfb9f34c9 100644 --- a/docs/opentitan/spi_device.md +++ b/docs/opentitan/spi_device.md @@ -37,7 +37,6 @@ instanciated this way from the command line: ```` -chardev socket,id=spidev,host=localhost,port=8004,server=on,wait=off --global ot-spi_device.chardev=spidev ```` Note that `opentitantool` and association library do support this protocol when the `qemu` backend @@ -57,6 +56,9 @@ Commands: --qemu-spidev-port [default: 8004] ```` +IT is also possible to use [`spidevflash.py`](spidevflash.md) tool to upload a binary using the same +protocol. + ### SPI device CharDev protocol SPI clock is not emulated, but each byte exchanged over the communication channel represent 8-bit diff --git a/docs/opentitan/spidevflash.md b/docs/opentitan/spidevflash.md new file mode 100644 index 000000000000..b7b596c9965b --- /dev/null +++ b/docs/opentitan/spidevflash.md @@ -0,0 +1,47 @@ +# `spidevflash.py` + +`spidevflash.py` is a tiny script to upload bootstrap image using the SPI device virtual device. + +## Usage + +````text +usage: spidevflash.py [-h] -f FILE [-a ADDRESS] [-r HOST] [-p PORT] [-v] [-d] + +SPI device flasher tool. + +options: + -h, --help show this help message and exit + -f FILE, --file FILE Binary file to flash + -a ADDRESS, --address ADDRESS + Address in the SPI flash (default to 0) + -r HOST, --host HOST remote host name (default: localhost) + -p PORT, --port PORT remote host TCP port (defaults to 8004) + -v, --verbose increase verbosity + -d, --debug enable debug mode +```` + +### Arguments + +* `-a` specify an alernative start address + +* `-d` only useful to debug the script, reports any Python traceback to the standard error stream. + +* `-f` specify the binary file to upload + +* `-p` specify an alternative port for the TCP connection on the QEMU instance + +* `-r` specify the name or address of the remote host running the QEMU instance + +* `-v` can be repeated to increase verbosity of the script, mostly for debug purpose. + +### Examples + +With the following examples: + +`-chardev socket,id=spidev,host=localhost,port=8004,server=on,wait=off -global ot-spi_device.chardev=spidev` has been +added to the QEMU command line to create a TCP chardev and connect it the SPI Device backend. See the [SPI Device](spi_device.md) documentation for details. + +* Upload a bootstrap binary + ````sh + ./scripts/opentitan/spidevflash.py -f test_bootstrap_virtual_sim_dv+manifest.bin + ```` diff --git a/docs/opentitan/tools.md b/docs/opentitan/tools.md index 82c85bac38df..e2ac9eb63669 100644 --- a/docs/opentitan/tools.md +++ b/docs/opentitan/tools.md @@ -44,6 +44,7 @@ directory to help with these tasks. * `ot-tidy.sh` is a simple shell wrapper to run clang-tidy (C linter) on OpenTitan files * `present.py` implements the Present 128-bit scrambler/descrambler used in OTP image files for HW digest verification. +* [spidevice.py](spidevice.md) is a tiny script to upload a binary using the SPI device. * `treillis/` directory contains the test application to test the [GPIO](gpio.md) device. * [`uartmux.py`](uartmux.md) is a tiny stream wrapper to help dealing with multiple QEMU output streams, typically multiple virtual UARTs. diff --git a/hw/opentitan/ot_csrng.c b/hw/opentitan/ot_csrng.c index bbf417de3d2e..6e7d644ed6f6 100644 --- a/hw/opentitan/ot_csrng.c +++ b/hw/opentitan/ot_csrng.c @@ -1029,8 +1029,7 @@ ot_csrng_handle_instantiate(OtCSRNGState *s, unsigned slot) uint32_t command = ot_fifo32_peek(&inst->cmd_fifo); uint32_t clen = FIELD_EX32(command, OT_CSNRG_CMD, CLEN); bool flag0 = - ot_csrng_check_multibitboot(s, FIELD_EX32(command, OT_CSNRG_CMD, FLAG0), - ALERT_STATUS_BIT(FLAG0)); + FIELD_EX32(command, OT_CSNRG_CMD, FLAG0) == OT_MULTIBITBOOL4_TRUE; uint32_t num; const uint32_t *buffer = @@ -1124,8 +1123,7 @@ static OtCSRNDCmdResult ot_csrng_handle_reseed(OtCSRNGState *s, unsigned slot) uint32_t command = ot_fifo32_peek(&inst->cmd_fifo); bool flag0 = - ot_csrng_check_multibitboot(s, FIELD_EX32(command, OT_CSNRG_CMD, FLAG0), - ALERT_STATUS_BIT(FLAG0)); + FIELD_EX32(command, OT_CSNRG_CMD, FLAG0) == OT_MULTIBITBOOL4_TRUE; xtrace_ot_csrng_info("reseed", flag0); diff --git a/hw/opentitan/ot_dev_proxy.c b/hw/opentitan/ot_dev_proxy.c index 9bd9e9b91fb3..767249a800c5 100644 --- a/hw/opentitan/ot_dev_proxy.c +++ b/hw/opentitan/ot_dev_proxy.c @@ -74,6 +74,8 @@ REG32(MBX_DOE_READ_DATA, 0x014u) /* Mailbox proxy */ /* ------------------------------------------------------------------------ */ +#define DEV_PROXY_DESC_LEN 16u + typedef struct _DevProxyHeader { uint16_t command; uint16_t length; @@ -94,6 +96,7 @@ typedef struct { OtDevProxyCaps caps; /* object capabilities */ const char *prefix; /* prefix name for idenfifying the device */ GHashTable *iirq_ht; /* intercepted IRQs, may be NULL */ + char desc[DEV_PROXY_DESC_LEN]; /* user friendly name, for debug purposes */ } OtDevProxyItem; typedef struct { @@ -101,6 +104,7 @@ typedef struct { unsigned dev_num; /* device number (in device array) */ uint16_t irq_num; /* IRQ number (in proxied device) */ uint8_t grp_num; /* IRQ group (in proxied device) */ + bool assigned; /* Proxy IRQ slot in use */ } OtDevProxyIrq; typedef struct { @@ -308,7 +312,7 @@ static void ot_dev_proxy_enumerate_devices(OtDevProxyState *s) uint32_t header; uint32_t base; uint32_t count; - char desc[16u]; + char desc[DEV_PROXY_DESC_LEN]; }; g_assert(sizeof(struct entry) == 7u * sizeof(uint32_t)); @@ -317,7 +321,7 @@ static void ot_dev_proxy_enumerate_devices(OtDevProxyState *s) unsigned mrcount = 0; char desc[32u]; for (unsigned ix = 0; ix < s->dev_count; ix++) { - const OtDevProxyItem *item = &s->items[ix]; + OtDevProxyItem *item = &s->items[ix]; const OtDevProxyCaps *caps = &item->caps; struct entry *entry = &entries[count]; memset(entry, 0, sizeof(*entry)); @@ -372,6 +376,8 @@ static void ot_dev_proxy_enumerate_devices(OtDevProxyState *s) object_get_typename(item->obj), desc); } memcpy(entry->desc, desc, sizeof(entry->desc)); + strncpy(item->desc, desc, sizeof(entry->desc)); + item->desc[sizeof(entry->desc) - 1] = '\0'; entry->header = ix << 16u; entry->base = (uint32_t)caps->mr->addr; entry->count = caps->reg_count; @@ -408,7 +414,7 @@ static void ot_dev_proxy_enumerate_memory_spaces(OtDevProxyState *s) struct entry *entry = &entries[count]; entry->header = ix << 24u; entry->address = subsys->mr->addr; - uint64_t size = int128_getlo(subsys->mr->size); + uint64_t size = memory_region_size(subsys->mr); entry->size = (uint32_t)MIN(size, UINT32_MAX); const char *name = memory_region_name(subsys->mr); size_t namelen = strlen(name); @@ -529,7 +535,7 @@ static void ot_dev_proxy_read_reg(OtDevProxyState *s) return; } - trace_ot_dev_proxy_read_reg(item->prefix, devix, reg); + trace_ot_dev_proxy_read_reg(item->desc, reg); const MemoryRegionOps *ops = mr->ops; if (role != PROXY_DISABLED_ROLE ? !ops->read_with_attrs : !ops->read) { @@ -588,7 +594,7 @@ static void ot_dev_proxy_write_reg(OtDevProxyState *s) return; } - trace_ot_dev_proxy_write_reg(item->prefix, devix, reg, value); + trace_ot_dev_proxy_write_reg(item->desc, reg, value); const MemoryRegionOps *ops = mr->ops; if (role != PROXY_DISABLED_ROLE ? !ops->write_with_attrs : !ops->write) { @@ -672,7 +678,7 @@ static void ot_dev_proxy_read_buffer(OtDevProxyState *s, bool mbx_mode) return; } - trace_ot_dev_proxy_read_buffer(item->prefix, devix, mbx_mode, reg, count); + trace_ot_dev_proxy_read_buffer(item->desc, mbx_mode, reg, count); const MemoryRegionOps *ops = mr->ops; if (role != PROXY_DISABLED_ROLE ? !ops->read_with_attrs : !ops->read) { @@ -786,7 +792,7 @@ static void ot_dev_proxy_write_buffer(OtDevProxyState *s, bool mbx_mode) return; } - trace_ot_dev_proxy_write_buffer(item->prefix, devix, mbx_mode, reg, count); + trace_ot_dev_proxy_write_buffer(item->desc, mbx_mode, reg, count); const MemoryRegionOps *ops = mr->ops; if (role != PROXY_DISABLED_ROLE ? !ops->write_with_attrs : !ops->write) { @@ -900,7 +906,7 @@ static void ot_dev_proxy_read_memory(OtDevProxyState *s) } } - trace_ot_dev_proxy_read_memory(item->prefix, devix, offset, count); + trace_ot_dev_proxy_read_memory(item->desc, offset, count); uint32_t *buf = g_new0(uint32_t, count); if (count) { @@ -956,7 +962,7 @@ static void ot_dev_proxy_write_memory(OtDevProxyState *s) } } - trace_ot_dev_proxy_write_memory(item->prefix, devix, offset, count); + trace_ot_dev_proxy_write_memory(item->desc, offset, count); if (object_dynamic_cast(obj, TYPE_OT_SRAM_CTRL)) { MemoryRegion *mr = caps->mr; @@ -1000,7 +1006,7 @@ ot_dev_proxy_route_interrupt(OtDevProxyState *s, OtDevProxyItem *item, unsigned six; for (six = 0; six < PROXY_IRQ_INTERCEPT_COUNT; six++) { - if (!s->proxy_irq_map[six].irq_orig) { + if (!s->proxy_irq_map[six].assigned) { proxy_irq = &s->proxy_irq_map[six]; break; } @@ -1013,6 +1019,7 @@ ot_dev_proxy_route_interrupt(OtDevProxyState *s, OtDevProxyItem *item, qemu_irq icpt_irq; icpt_irq = qdev_get_gpio_in_named(DEVICE(s), PROXY_IRQ_INTERCEPT_NAME, (int)six); + proxy_irq->assigned = true; proxy_irq->irq_orig = qdev_intercept_gpio_out(dev, icpt_irq, group, (int)irq_n); proxy_irq->dev_num = (unsigned)(uintptr_t)(item - s->items); @@ -1137,7 +1144,7 @@ static void ot_dev_proxy_intercept_interrupts(OtDevProxyState *s, bool enable) */ unsigned free_slot = 0; for (unsigned ix = 0; ix < PROXY_IRQ_INTERCEPT_COUNT; ix++) { - if (!s->proxy_irq_map[ix].irq_orig) { + if (!s->proxy_irq_map[ix].assigned) { free_slot += 1; } } @@ -1256,7 +1263,7 @@ static void ot_dev_proxy_intercept_mmio(OtDevProxyState *s) MemoryRegion *mr = s->subsys[mspc].mr; g_assert(mr->addr == 0); - uint64_t lmrsize = (uint64_t)int128_getlo(mr->size); + uint64_t lmrsize = memory_region_size(mr); uint64_t mrsize = MAX(lmrsize, UINT32_MAX); uint32_t address = s->rx_buffer[1]; @@ -1388,8 +1395,8 @@ static void ot_dev_proxy_intercepted_irq(void *opaque, int irq, int level) g_assert(irq < PROXY_IRQ_INTERCEPT_COUNT); OtDevProxyIrq *proxy_irq = &s->proxy_irq_map[irq]; - if (!proxy_irq->irq_orig) { - warn_report("%d non-assigned intercepted IRQ signaled", irq); + if (!proxy_irq->assigned) { + trace_ot_dev_proxy_unassigned_irq(irq); return; } g_assert(proxy_irq->dev_num < s->dev_count); @@ -1629,7 +1636,7 @@ static void ot_dev_proxy_reg_mr(GArray *array, Object *obj) item->obj = obj; item->caps.mr = mr; g_assert(item->caps.mr); - item->caps.reg_count = int128_getlo(mr->size) / sizeof(uint32_t); + item->caps.reg_count = memory_region_size(mr) / sizeof(uint32_t); item->prefix = "M/"; g_array_append_val(array, item); } @@ -1686,7 +1693,7 @@ static void ot_dev_proxy_reg_sram_ctrl(GArray *array, Object *obj) item->obj = obj; item->caps.mr = sysdev->mmio[0].memory; item->caps.reg_count = - int128_getlo(item->caps.mr->size) / sizeof(uint32_t); + memory_region_size(item->caps.mr) / sizeof(uint32_t); item->prefix = "SRC/"; /* SRAM control */ g_array_append_val(array, item); item = g_new0(OtDevProxyItem, 1); @@ -1694,7 +1701,7 @@ static void ot_dev_proxy_reg_sram_ctrl(GArray *array, Object *obj) item->obj = obj; item->caps.mr = sysdev->mmio[1].memory; item->caps.reg_count = - int128_getlo(item->caps.mr->size) / sizeof(uint32_t); + memory_region_size(item->caps.mr) / sizeof(uint32_t); item->prefix = "SRM/"; /* SRAM memory */ g_array_append_val(array, item); } @@ -1715,7 +1722,7 @@ static int ot_dev_proxy_discover_memory_root(Object *child, void *opaque) /* not a root memory region */ return 0; } - if (int128_getlo(mr->size) == 0) { + if (memory_region_size(mr) == 0) { /* empty region, useless */ return 0; } diff --git a/hw/opentitan/ot_dma.c b/hw/opentitan/ot_dma.c index 57f5f0551f44..7469e8806101 100644 --- a/hw/opentitan/ot_dma.c +++ b/hw/opentitan/ot_dma.c @@ -582,7 +582,7 @@ ot_dma_check_device(OtDMAState *s, bool d_or_s, OtDMAAddrSpace *asix, MemoryRegionSection mrs = { 0 }; mrs = memory_region_find(as->root, start, size); - if (!mrs.mr || !mrs.size) { + if (!mrs.mr || !int128_getlo(mrs.size)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: Invalid %s address as:%s " "addr: 0x%" HWADDR_PRIx " size: 0x%" HWADDR_PRIx "\n", @@ -592,7 +592,7 @@ ot_dma_check_device(OtDMAState *s, bool d_or_s, OtDMAAddrSpace *asix, return NULL; } - if (mrs.offset_within_region + mrs.size < size) { + if (mrs.offset_within_region + int128_getlo(mrs.size) < size) { qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: Invalid size\n", __func__, s->ot_id); ot_dma_set_xerror(s, ERR_SIZE); diff --git a/hw/opentitan/ot_otp_dj.c b/hw/opentitan/ot_otp_dj.c index 477093b861ce..103bc6a9749e 100644 --- a/hw/opentitan/ot_otp_dj.c +++ b/hw/opentitan/ot_otp_dj.c @@ -112,6 +112,7 @@ REG32(STATUS, 0x10u) FIELD(STATUS, BUS_INTEG_ERROR, 28u, 1u) FIELD(STATUS, DAI_IDLE, 29u, 1u) FIELD(STATUS, CHECK_PENDING, 30u, 1u) + FIELD(STATUS, RESET_ALLOWED, 31u, 1u) REG32(ERR_CODE_0, 0x14u) REG32(ERR_CODE_1, 0x18u) REG32(ERR_CODE_2, 0x1cu) @@ -213,127 +214,139 @@ REG32(SECRET2_DIGEST_1, 0x170u) REG32(SECRET3_DIGEST_0, 0x174u) REG32(SECRET3_DIGEST_1, 0x178u) /* Software Config Window registers (at offset SW_CFG_WINDOW = +0x4000) */ -REG32(SCRATCH, 0u) +REG32(VENDOR_TEST_SCRATCH, 0u) REG32(VENDOR_TEST_DIGEST, 56u) -REG32(CREATOR_SW_CFG_AST_CFG, 64u) -REG32(CREATOR_SW_CFG_AST_INIT_EN, 188u) -REG32(CREATOR_SW_CFG_OVERRIDES, 192u) -REG32(CREATOR_SW_CFG_ROM_EXT_SKU, 224u) -REG32(CREATOR_SW_CFG_SIGVERIFY_RSA_MOD_EXP_IBEX_EN, 228u) -REG32(CREATOR_SW_CFG_SIGVERIFY_RSA_KEY_EN, 232u) -REG32(CREATOR_SW_CFG_SIGVERIFY_SPX_EN, 240u) -REG32(CREATOR_SW_CFG_SIGVERIFY_SPX_KEY_EN, 244u) -REG32(CREATOR_SW_CFG_FLASH_DATA_DEFAULT_CFG, 252u) -REG32(CREATOR_SW_CFG_FLASH_INFO_BOOT_DATA_CFG, 256u) -REG32(CREATOR_SW_CFG_FLASH_HW_INFO_CFG_OVERRIDE, 260u) -REG32(CREATOR_SW_CFG_RNG_EN, 264u) -REG32(CREATOR_SW_CFG_JITTER_EN, 268u) -REG32(CREATOR_SW_CFG_RET_RAM_RESET_MASK, 272u) -REG32(CREATOR_SW_CFG_MANUF_STATE, 276u) -REG32(CREATOR_SW_CFG_ROM_EXEC_EN, 280u) -REG32(CREATOR_SW_CFG_CPUCTRL, 284u) -REG32(CREATOR_SW_CFG_MIN_SEC_VER_ROM_EXT, 288u) -REG32(CREATOR_SW_CFG_MIN_SEC_VER_BL0, 292u) -REG32(CREATOR_SW_CFG_DEFAULT_BOOT_DATA_IN_PROD_EN, 296u) -REG32(CREATOR_SW_CFG_RMA_SPIN_EN, 300u) -REG32(CREATOR_SW_CFG_RMA_SPIN_CYCLES, 304u) -REG32(CREATOR_SW_CFG_RNG_REPCNT_THRESHOLDS, 308u) -REG32(CREATOR_SW_CFG_RNG_REPCNTS_THRESHOLDS, 312u) -REG32(CREATOR_SW_CFG_RNG_ADAPTP_HI_THRESHOLDS, 316u) -REG32(CREATOR_SW_CFG_RNG_ADAPTP_LO_THRESHOLDS, 320u) -REG32(CREATOR_SW_CFG_RNG_BUCKET_THRESHOLDS, 324u) -REG32(CREATOR_SW_CFG_RNG_MARKOV_HI_THRESHOLDS, 328u) -REG32(CREATOR_SW_CFG_RNG_MARKOV_LO_THRESHOLDS, 332u) -REG32(CREATOR_SW_CFG_RNG_EXTHT_HI_THRESHOLDS, 336u) -REG32(CREATOR_SW_CFG_RNG_EXTHT_LO_THRESHOLDS, 340u) -REG32(CREATOR_SW_CFG_RNG_ALERT_THRESHOLD, 344u) -REG32(CREATOR_SW_CFG_RNG_HEALTH_CONFIG_DIGEST, 348u) -REG32(CREATOR_SW_CFG_SRAM_KEY_RENEW_EN, 352u) +REG32(CREATOR_SW_CFG_DIO_ATTR, 64u) +REG32(CREATOR_SW_CFG_AST_CFG, 140u) +REG32(CREATOR_SW_CFG_AST_SPARES, 160u) +REG32(CREATOR_SW_CFG_AST_AVGSFUSECTL, 176u) +REG32(CREATOR_SW_CFG_AST_AVGSHDRCFG, 180u) +REG32(CREATOR_SW_CFG_AST_RINGOSC_TRIM_CTL, 184u) +REG32(CREATOR_SW_CFG_AST_RINGOSC_FREQ_COUNT_CTL, 188u) +REG32(CREATOR_SW_CFG_AST_RINGOSC_FREQ_TH_SLOW, 192u) +REG32(CREATOR_SW_CFG_AST_RINGOSC_FREQ_TH_FAST, 196u) +REG32(CREATOR_SW_CFG_AST_INIT_EN, 200u) +REG32(CREATOR_SW_CFG_OVERRIDES, 204u) +REG32(CREATOR_SW_CFG_ROM_EXT_SKU, 236u) +REG32(CREATOR_SW_CFG_SIGVERIFY_RSA_MOD_EXP_IBEX_EN, 240u) +REG32(CREATOR_SW_CFG_SIGVERIFY_RSA_KEY_EN, 244u) +REG32(CREATOR_SW_CFG_SIGVERIFY_SPX_EN, 252u) +REG32(CREATOR_SW_CFG_SIGVERIFY_SPX_KEY_EN, 256u) +REG32(CREATOR_SW_CFG_FLASH_DATA_DEFAULT_CFG, 264u) +REG32(CREATOR_SW_CFG_FLASH_INFO_BOOT_DATA_CFG, 268u) +REG32(CREATOR_SW_CFG_FLASH_HW_INFO_CFG_OVERRIDE, 272u) +REG32(CREATOR_SW_CFG_RNG_EN, 276u) +REG32(CREATOR_SW_CFG_JITTER_EN, 280u) +REG32(CREATOR_SW_CFG_RET_RAM_RESET_MASK, 284u) +REG32(CREATOR_SW_CFG_MANUF_STATE, 288u) +REG32(CREATOR_SW_CFG_ROM_EXEC_EN, 292u) +REG32(CREATOR_SW_CFG_CPUCTRL, 296u) +REG32(CREATOR_SW_CFG_MIN_SEC_VER_ROM_EXT, 300u) +REG32(CREATOR_SW_CFG_MIN_SEC_VER_BL0, 304u) +REG32(CREATOR_SW_CFG_DEFAULT_BOOT_DATA_IN_PROD_EN, 308u) +REG32(CREATOR_SW_CFG_RMA_SPIN_EN, 312u) +REG32(CREATOR_SW_CFG_RMA_SPIN_CYCLES, 316u) +REG32(CREATOR_SW_CFG_RNG_REPCNT_THRESHOLDS, 320u) +REG32(CREATOR_SW_CFG_RNG_REPCNTS_THRESHOLDS, 324u) +REG32(CREATOR_SW_CFG_RNG_ADAPTP_HI_THRESHOLDS, 328u) +REG32(CREATOR_SW_CFG_RNG_ADAPTP_LO_THRESHOLDS, 332u) +REG32(CREATOR_SW_CFG_RNG_BUCKET_THRESHOLDS, 336u) +REG32(CREATOR_SW_CFG_RNG_MARKOV_HI_THRESHOLDS, 340u) +REG32(CREATOR_SW_CFG_RNG_MARKOV_LO_THRESHOLDS, 344u) +REG32(CREATOR_SW_CFG_RNG_EXTHT_HI_THRESHOLDS, 348u) +REG32(CREATOR_SW_CFG_RNG_EXTHT_LO_THRESHOLDS, 352u) +REG32(CREATOR_SW_CFG_RNG_ALERT_THRESHOLD, 356u) +REG32(CREATOR_SW_CFG_RNG_HEALTH_CONFIG_DIGEST, 360u) +REG32(CREATOR_SW_CFG_SRAM_KEY_RENEW_EN, 364u) REG32(CREATOR_SW_CFG_DIGEST, 376u) REG32(OWNER_SW_CFG_ROM_ERROR_REPORTING, 384u) REG32(OWNER_SW_CFG_ROM_BOOTSTRAP_DIS, 388u) REG32(OWNER_SW_CFG_ROM_ALERT_CLASS_EN, 392u) REG32(OWNER_SW_CFG_ROM_ALERT_ESCALATION, 396u) REG32(OWNER_SW_CFG_ROM_ALERT_CLASSIFICATION, 400u) -REG32(OWNER_SW_CFG_ROM_LOCAL_ALERT_CLASSIFICATION, 796u) -REG32(OWNER_SW_CFG_ROM_ALERT_ACCUM_THRESH, 860u) -REG32(OWNER_SW_CFG_ROM_ALERT_TIMEOUT_CYCLES, 876u) -REG32(OWNER_SW_CFG_ROM_ALERT_PHASE_CYCLES, 892u) -REG32(OWNER_SW_CFG_ROM_ALERT_DIGEST_PROD, 956u) -REG32(OWNER_SW_CFG_ROM_ALERT_DIGEST_PROD_END, 960u) -REG32(OWNER_SW_CFG_ROM_ALERT_DIGEST_DEV, 964u) -REG32(OWNER_SW_CFG_ROM_ALERT_DIGEST_RMA, 968u) -REG32(OWNER_SW_CFG_ROM_WATCHDOG_BITE_THRESHOLD_CYCLES, 972u) -REG32(OWNER_SW_CFG_ROM_KEYMGR_ROM_EXT_MEAS_EN, 976u) -REG32(OWNER_SW_CFG_MANUF_STATE, 980u) -REG32(OWNER_SW_CFG_ROM_RSTMGR_INFO_EN, 984u) +REG32(OWNER_SW_CFG_ROM_LOCAL_ALERT_CLASSIFICATION, 800u) +REG32(OWNER_SW_CFG_ROM_ALERT_ACCUM_THRESH, 864u) +REG32(OWNER_SW_CFG_ROM_ALERT_TIMEOUT_CYCLES, 880u) +REG32(OWNER_SW_CFG_ROM_ALERT_PHASE_CYCLES, 896u) +REG32(OWNER_SW_CFG_ROM_ALERT_DIGEST_PROD, 960u) +REG32(OWNER_SW_CFG_ROM_ALERT_DIGEST_PROD_END, 964u) +REG32(OWNER_SW_CFG_ROM_ALERT_DIGEST_DEV, 968u) +REG32(OWNER_SW_CFG_ROM_ALERT_DIGEST_RMA, 972u) +REG32(OWNER_SW_CFG_ROM_WATCHDOG_BITE_THRESHOLD_CYCLES, 976u) +REG32(OWNER_SW_CFG_ROM_KEYMGR_ROM_EXT_MEAS_EN, 980u) +REG32(OWNER_SW_CFG_MANUF_STATE, 984u) +REG32(OWNER_SW_CFG_ROM_RSTMGR_INFO_EN, 988u) REG32(OWNER_SW_CFG_DIGEST, 1008u) REG32(OWNERSHIP_SLOT_STATE_ROT_OWNER_AUTH, 1016u) REG32(OWNERSHIP_SLOT_STATE_PLAT_INTEG_AUTH, 1032u) REG32(OWNERSHIP_SLOT_STATE_PLAT_OWNER_AUTH, 1048u) REG32(ROT_CREATOR_AUTH_NON_RAW_MFW_CODESIGN_KEY, 1064u) -REG32(ROT_CREATOR_AUTH_OWNERSHIP_STATE, 1224u) -REG32(ROT_CREATOR_AUTH_ROM2_PATCH_SIGVERIFY_KEY, 1228u) -REG32(ROT_CREATOR_AUTH_KEYMANIFEST_KEY, 1388u) -REG32(ROT_CREATOR_AUTH_UNLOCK4XFER_KEY, 1548u) -REG32(ROT_CREATOR_AUTH_IDENTITY_CERT, 1708u) +REG32(ROT_CREATOR_AUTH_ROM2_PATCH_SIGVERIFY_KEY, 1240u) +REG32(ROT_CREATOR_AUTH_KEYMANIFEST_KEY, 1416u) +REG32(ROT_CREATOR_AUTH_IDENTITY_CERT, 1592u) +REG32(ROT_CREATOR_AUTH_IDENTITY_CERT_CMAC, 2360u) REG32(ROT_CREATOR_AUTH_DIGEST, 2480u) REG32(ROT_OWNER_AUTH_SLOT0_KEYMANIFEST_KEY, 2488u) -REG32(ROT_OWNER_AUTH_SLOT0_UNLOCK4XFER_KEY, 2648u) +REG32(ROT_OWNER_AUTH_SLOT0_UNLOCK4XFER_KEY, 2552u) REG32(ROT_OWNER_AUTH_SLOT0_DIGEST, 2808u) REG32(ROT_OWNER_AUTH_SLOT1_KEYMANIFEST_KEY, 2816u) -REG32(ROT_OWNER_AUTH_SLOT1_UNLOCK4XFER_KEY, 2976u) +REG32(ROT_OWNER_AUTH_SLOT1_UNLOCK4XFER_KEY, 2880u) REG32(ROT_OWNER_AUTH_SLOT1_DIGEST, 3136u) REG32(PLAT_INTEG_AUTH_SLOT0_KEYMANIFEST_KEY, 3144u) -REG32(PLAT_INTEG_AUTH_SLOT0_UNLOCK4XFER_KEY, 3304u) +REG32(PLAT_INTEG_AUTH_SLOT0_UNLOCK4XFER_KEY, 3208u) REG32(PLAT_INTEG_AUTH_SLOT0_DIGEST, 3464u) REG32(PLAT_INTEG_AUTH_SLOT1_KEYMANIFEST_KEY, 3472u) -REG32(PLAT_INTEG_AUTH_SLOT1_UNLOCK4XFER_KEY, 3632u) +REG32(PLAT_INTEG_AUTH_SLOT1_UNLOCK4XFER_KEY, 3536u) REG32(PLAT_INTEG_AUTH_SLOT1_DIGEST, 3792u) REG32(PLAT_OWNER_AUTH_SLOT0_KEYMANIFEST_KEY, 3800u) -REG32(PLAT_OWNER_AUTH_SLOT0_UNLOCK4XFER_KEY, 3960u) +REG32(PLAT_OWNER_AUTH_SLOT0_UNLOCK4XFER_KEY, 3864u) REG32(PLAT_OWNER_AUTH_SLOT0_DIGEST, 4120u) REG32(PLAT_OWNER_AUTH_SLOT1_KEYMANIFEST_KEY, 4128u) -REG32(PLAT_OWNER_AUTH_SLOT1_UNLOCK4XFER_KEY, 4288u) +REG32(PLAT_OWNER_AUTH_SLOT1_UNLOCK4XFER_KEY, 4192u) REG32(PLAT_OWNER_AUTH_SLOT1_DIGEST, 4448u) REG32(PLAT_OWNER_AUTH_SLOT2_KEYMANIFEST_KEY, 4456u) -REG32(PLAT_OWNER_AUTH_SLOT2_UNLOCK4XFER_KEY, 4616u) +REG32(PLAT_OWNER_AUTH_SLOT2_UNLOCK4XFER_KEY, 4520u) REG32(PLAT_OWNER_AUTH_SLOT2_DIGEST, 4776u) REG32(PLAT_OWNER_AUTH_SLOT3_KEYMANIFEST_KEY, 4784u) -REG32(PLAT_OWNER_AUTH_SLOT3_UNLOCK4XFER_KEY, 4944u) +REG32(PLAT_OWNER_AUTH_SLOT3_UNLOCK4XFER_KEY, 4848u) REG32(PLAT_OWNER_AUTH_SLOT3_DIGEST, 5104u) REG32(EXT_NVM_ANTIREPLAY_FRESHNESS_CNT, 5112u) REG32(ROM_PATCH_DATA, 6136u) REG32(ROM_PATCH_DIGEST, 15912u) -REG32(DEVICE_ID, 15920u) -REG32(MANUF_STATE, 15952u) +REG32(HW_CFG0_DEVICE_ID, 15920u) +REG32(HW_CFG0_MANUF_STATE, 15952u) REG32(HW_CFG0_DIGEST, 15984u) -REG32(SOC_DBG_STATE, 15992u) -REG32(EN_SRAM_IFETCH, 15996u) +REG32(HW_CFG1_SOC_DBG_STATE, 15992u) +REG32(HW_CFG1_EN_SRAM_IFETCH, 15996u) REG32(HW_CFG1_DIGEST, 16000u) -REG32(TEST_UNLOCK_TOKEN, 16008u) -REG32(TEST_EXIT_TOKEN, 16024u) +REG32(SECRET0_TEST_UNLOCK_TOKEN, 16008u) +REG32(SECRET0_TEST_EXIT_TOKEN, 16024u) REG32(SECRET0_DIGEST, 16040u) -REG32(FLASH_ADDR_KEY_SEED, 16048u) -REG32(FLASH_DATA_KEY_SEED, 16080u) -REG32(SRAM_DATA_KEY_SEED, 16112u) +REG32(SECRET1_FLASH_ADDR_KEY_SEED, 16048u) +REG32(SECRET1_FLASH_DATA_KEY_SEED, 16080u) +REG32(SECRET1_SRAM_DATA_KEY_SEED, 16112u) REG32(SECRET1_DIGEST, 16128u) -REG32(RMA_TOKEN, 16136u) -REG32(CREATOR_ROOT_KEY_SHARE0, 16152u) -REG32(CREATOR_ROOT_KEY_SHARE1, 16184u) -REG32(CREATOR_SEED, 16216u) +REG32(SECRET2_RMA_TOKEN, 16136u) +REG32(SECRET2_CREATOR_ROOT_KEY_SHARE0, 16152u) +REG32(SECRET2_CREATOR_ROOT_KEY_SHARE1, 16184u) +REG32(SECRET2_CREATOR_SEED, 16216u) REG32(SECRET2_DIGEST, 16248u) -REG32(OWNER_SEED, 16256u) +REG32(SECRET3_OWNER_SEED, 16256u) REG32(SECRET3_DIGEST, 16288u) REG32(LC_TRANSITION_CNT, 16296u) REG32(LC_STATE, 16344u) /* clang-format on */ -#define VENDOR_TEST_SIZE 64u -#define SCRATCH_SIZE 56u -#define VENDOR_TEST_DIGEST_SIZE 8u -#define CREATOR_SW_CFG_SIZE 320u -#define CREATOR_SW_CFG_AST_CFG_SIZE 124u +#define VENDOR_TEST_SCRATCH_SIZE 56u +#define CREATOR_SW_CFG_DIO_ATTR_SIZE 76u +#define CREATOR_SW_CFG_AST_CFG_SIZE 20u +#define CREATOR_SW_CFG_AST_SPARES_SIZE 14u +#define CREATOR_SW_CFG_AST_AVGSFUSECTL_SIZE 4u +#define CREATOR_SW_CFG_AST_AVGSHDRCFG_SIZE 3u +#define CREATOR_SW_CFG_AST_RINGOSC_TRIM_CTL_SIZE 1u +#define CREATOR_SW_CFG_AST_RINGOSC_FREQ_COUNT_CTL_SIZE 2u +#define CREATOR_SW_CFG_AST_RINGOSC_FREQ_TH_SLOW_SIZE 2u +#define CREATOR_SW_CFG_AST_RINGOSC_FREQ_TH_FAST_SIZE 2u #define CREATOR_SW_CFG_AST_INIT_EN_SIZE 4u #define CREATOR_SW_CFG_OVERRIDES_SIZE 32u #define CREATOR_SW_CFG_ROM_EXT_SKU_SIZE 4u @@ -365,104 +378,60 @@ REG32(LC_STATE, 16344u) #define CREATOR_SW_CFG_RNG_EXTHT_HI_THRESHOLDS_SIZE 4u #define CREATOR_SW_CFG_RNG_EXTHT_LO_THRESHOLDS_SIZE 4u #define CREATOR_SW_CFG_RNG_ALERT_THRESHOLD_SIZE 4u -#define CREATOR_SW_CFG_RNG_HEALTH_CONFIG_DIGEST_SIZE 4u #define CREATOR_SW_CFG_SRAM_KEY_RENEW_EN_SIZE 4u -#define CREATOR_SW_CFG_DIGEST_SIZE 8u -#define OWNER_SW_CFG_SIZE 632u #define OWNER_SW_CFG_ROM_ERROR_REPORTING_SIZE 4u #define OWNER_SW_CFG_ROM_BOOTSTRAP_DIS_SIZE 4u #define OWNER_SW_CFG_ROM_ALERT_CLASS_EN_SIZE 4u #define OWNER_SW_CFG_ROM_ALERT_ESCALATION_SIZE 4u -#define OWNER_SW_CFG_ROM_ALERT_CLASSIFICATION_SIZE 396u +#define OWNER_SW_CFG_ROM_ALERT_CLASSIFICATION_SIZE 400u #define OWNER_SW_CFG_ROM_LOCAL_ALERT_CLASSIFICATION_SIZE 64u #define OWNER_SW_CFG_ROM_ALERT_ACCUM_THRESH_SIZE 16u #define OWNER_SW_CFG_ROM_ALERT_TIMEOUT_CYCLES_SIZE 16u #define OWNER_SW_CFG_ROM_ALERT_PHASE_CYCLES_SIZE 64u -#define OWNER_SW_CFG_ROM_ALERT_DIGEST_PROD_SIZE 4u -#define OWNER_SW_CFG_ROM_ALERT_DIGEST_PROD_END_SIZE 4u -#define OWNER_SW_CFG_ROM_ALERT_DIGEST_DEV_SIZE 4u -#define OWNER_SW_CFG_ROM_ALERT_DIGEST_RMA_SIZE 4u #define OWNER_SW_CFG_ROM_WATCHDOG_BITE_THRESHOLD_CYCLES_SIZE 4u #define OWNER_SW_CFG_ROM_KEYMGR_ROM_EXT_MEAS_EN_SIZE 4u #define OWNER_SW_CFG_MANUF_STATE_SIZE 4u #define OWNER_SW_CFG_ROM_RSTMGR_INFO_EN_SIZE 4u -#define OWNER_SW_CFG_DIGEST_SIZE 8u -#define OWNERSHIP_SLOT_STATE_SIZE 48u #define OWNERSHIP_SLOT_STATE_ROT_OWNER_AUTH_SIZE 16u #define OWNERSHIP_SLOT_STATE_PLAT_INTEG_AUTH_SIZE 16u #define OWNERSHIP_SLOT_STATE_PLAT_OWNER_AUTH_SIZE 16u -#define ROT_CREATOR_AUTH_SIZE 1424u -#define ROT_CREATOR_AUTH_NON_RAW_MFW_CODESIGN_KEY_SIZE 160u -#define ROT_CREATOR_AUTH_OWNERSHIP_STATE_SIZE 4u -#define ROT_CREATOR_AUTH_ROM2_PATCH_SIGVERIFY_KEY_SIZE 160u -#define ROT_CREATOR_AUTH_KEYMANIFEST_KEY_SIZE 160u -#define ROT_CREATOR_AUTH_UNLOCK4XFER_KEY_SIZE 160u +#define ROT_CREATOR_AUTH_NON_RAW_MFW_CODESIGN_KEY_SIZE 176u +#define ROT_CREATOR_AUTH_ROM2_PATCH_SIGVERIFY_KEY_SIZE 176u +#define ROT_CREATOR_AUTH_KEYMANIFEST_KEY_SIZE 176u #define ROT_CREATOR_AUTH_IDENTITY_CERT_SIZE 768u -#define ROT_CREATOR_AUTH_DIGEST_SIZE 8u -#define ROT_OWNER_AUTH_SLOT0_SIZE 328u -#define ROT_OWNER_AUTH_SLOT0_KEYMANIFEST_KEY_SIZE 160u -#define ROT_OWNER_AUTH_SLOT0_UNLOCK4XFER_KEY_SIZE 160u -#define ROT_OWNER_AUTH_SLOT0_DIGEST_SIZE 8u -#define ROT_OWNER_AUTH_SLOT1_SIZE 328u -#define ROT_OWNER_AUTH_SLOT1_KEYMANIFEST_KEY_SIZE 160u -#define ROT_OWNER_AUTH_SLOT1_UNLOCK4XFER_KEY_SIZE 160u -#define ROT_OWNER_AUTH_SLOT1_DIGEST_SIZE 8u -#define PLAT_INTEG_AUTH_SLOT0_SIZE 328u -#define PLAT_INTEG_AUTH_SLOT0_KEYMANIFEST_KEY_SIZE 160u -#define PLAT_INTEG_AUTH_SLOT0_UNLOCK4XFER_KEY_SIZE 160u -#define PLAT_INTEG_AUTH_SLOT0_DIGEST_SIZE 8u -#define PLAT_INTEG_AUTH_SLOT1_SIZE 328u -#define PLAT_INTEG_AUTH_SLOT1_KEYMANIFEST_KEY_SIZE 160u -#define PLAT_INTEG_AUTH_SLOT1_UNLOCK4XFER_KEY_SIZE 160u -#define PLAT_INTEG_AUTH_SLOT1_DIGEST_SIZE 8u -#define PLAT_OWNER_AUTH_SLOT0_SIZE 328u -#define PLAT_OWNER_AUTH_SLOT0_KEYMANIFEST_KEY_SIZE 160u -#define PLAT_OWNER_AUTH_SLOT0_UNLOCK4XFER_KEY_SIZE 160u -#define PLAT_OWNER_AUTH_SLOT0_DIGEST_SIZE 8u -#define PLAT_OWNER_AUTH_SLOT1_SIZE 328u -#define PLAT_OWNER_AUTH_SLOT1_KEYMANIFEST_KEY_SIZE 160u -#define PLAT_OWNER_AUTH_SLOT1_UNLOCK4XFER_KEY_SIZE 160u -#define PLAT_OWNER_AUTH_SLOT1_DIGEST_SIZE 8u -#define PLAT_OWNER_AUTH_SLOT2_SIZE 328u -#define PLAT_OWNER_AUTH_SLOT2_KEYMANIFEST_KEY_SIZE 160u -#define PLAT_OWNER_AUTH_SLOT2_UNLOCK4XFER_KEY_SIZE 160u -#define PLAT_OWNER_AUTH_SLOT2_DIGEST_SIZE 8u -#define PLAT_OWNER_AUTH_SLOT3_SIZE 328u -#define PLAT_OWNER_AUTH_SLOT3_KEYMANIFEST_KEY_SIZE 160u -#define PLAT_OWNER_AUTH_SLOT3_UNLOCK4XFER_KEY_SIZE 160u -#define PLAT_OWNER_AUTH_SLOT3_DIGEST_SIZE 8u -#define EXT_NVM_SIZE 1024u +#define ROT_CREATOR_AUTH_IDENTITY_CERT_CMAC_SIZE 16u +#define ROT_OWNER_AUTH_SLOT0_KEYMANIFEST_KEY_SIZE 64u +#define ROT_OWNER_AUTH_SLOT0_UNLOCK4XFER_KEY_SIZE 64u +#define ROT_OWNER_AUTH_SLOT1_KEYMANIFEST_KEY_SIZE 64u +#define ROT_OWNER_AUTH_SLOT1_UNLOCK4XFER_KEY_SIZE 64u +#define PLAT_INTEG_AUTH_SLOT0_KEYMANIFEST_KEY_SIZE 64u +#define PLAT_INTEG_AUTH_SLOT0_UNLOCK4XFER_KEY_SIZE 64u +#define PLAT_INTEG_AUTH_SLOT1_KEYMANIFEST_KEY_SIZE 64u +#define PLAT_INTEG_AUTH_SLOT1_UNLOCK4XFER_KEY_SIZE 64u +#define PLAT_OWNER_AUTH_SLOT0_KEYMANIFEST_KEY_SIZE 64u +#define PLAT_OWNER_AUTH_SLOT0_UNLOCK4XFER_KEY_SIZE 64u +#define PLAT_OWNER_AUTH_SLOT1_KEYMANIFEST_KEY_SIZE 64u +#define PLAT_OWNER_AUTH_SLOT1_UNLOCK4XFER_KEY_SIZE 64u +#define PLAT_OWNER_AUTH_SLOT2_KEYMANIFEST_KEY_SIZE 64u +#define PLAT_OWNER_AUTH_SLOT2_UNLOCK4XFER_KEY_SIZE 64u +#define PLAT_OWNER_AUTH_SLOT3_KEYMANIFEST_KEY_SIZE 64u +#define PLAT_OWNER_AUTH_SLOT3_UNLOCK4XFER_KEY_SIZE 64u #define EXT_NVM_ANTIREPLAY_FRESHNESS_CNT_SIZE 1024u -#define ROM_PATCH_SIZE 9784u #define ROM_PATCH_DATA_SIZE 9192u -#define ROM_PATCH_DIGEST_SIZE 8u -#define HW_CFG0_SIZE 72u -#define DEVICE_ID_SIZE 32u -#define MANUF_STATE_SIZE 32u -#define HW_CFG0_DIGEST_SIZE 8u -#define HW_CFG1_SIZE 16u -#define SOC_DBG_STATE_SIZE 4u -#define EN_SRAM_IFETCH_SIZE 1u -#define HW_CFG1_DIGEST_SIZE 8u -#define SECRET0_SIZE 40u -#define TEST_UNLOCK_TOKEN_SIZE 16u -#define TEST_EXIT_TOKEN_SIZE 16u -#define SECRET0_DIGEST_SIZE 8u -#define SECRET1_SIZE 88u -#define FLASH_ADDR_KEY_SEED_SIZE 32u -#define FLASH_DATA_KEY_SEED_SIZE 32u -#define SRAM_DATA_KEY_SEED_SIZE 16u -#define SECRET1_DIGEST_SIZE 8u -#define SECRET2_SIZE 120u -#define RMA_TOKEN_SIZE 16u -#define CREATOR_ROOT_KEY_SHARE0_SIZE 32u -#define CREATOR_ROOT_KEY_SHARE1_SIZE 32u -#define CREATOR_SEED_SIZE 32u -#define SECRET2_DIGEST_SIZE 8u -#define SECRET3_SIZE 40u -#define OWNER_SEED_SIZE 32u -#define SECRET3_DIGEST_SIZE 8u -#define LIFE_CYCLE_SIZE 88u +#define HW_CFG0_DEVICE_ID_SIZE 32u +#define HW_CFG0_MANUF_STATE_SIZE 32u +#define HW_CFG1_SOC_DBG_STATE_SIZE 4u +#define HW_CFG1_EN_SRAM_IFETCH_SIZE 1u +#define SECRET0_TEST_UNLOCK_TOKEN_SIZE 16u +#define SECRET0_TEST_EXIT_TOKEN_SIZE 16u +#define SECRET1_FLASH_ADDR_KEY_SEED_SIZE 32u +#define SECRET1_FLASH_DATA_KEY_SEED_SIZE 32u +#define SECRET1_SRAM_DATA_KEY_SEED_SIZE 16u +#define SECRET2_RMA_TOKEN_SIZE 16u +#define SECRET2_CREATOR_ROOT_KEY_SHARE0_SIZE 32u +#define SECRET2_CREATOR_ROOT_KEY_SHARE1_SIZE 32u +#define SECRET2_CREATOR_SEED_SIZE 32u +#define SECRET3_OWNER_SEED_SIZE 32u #define LC_TRANSITION_CNT_SIZE 48u #define LC_STATE_SIZE 40u @@ -565,51 +534,6 @@ REG32(CSR7, 0x1cu) #define OTP_ENTROPY_BUF_COUNT \ (OTP_ENTROPY_PRESENT_WORDS + OTP_ENTROPY_NONCE_WORDS) -#define OTP_PART_VENDOR_TEST_OFFSET 0u -#define OTP_PART_VENDOR_TEST_SIZE 64u -#define OTP_PART_CREATOR_SW_CFG_OFFSET 64u -#define OTP_PART_CREATOR_SW_CFG_SIZE 320u -#define OTP_PART_OWNER_SW_CFG_OFFSET 384u -#define OTP_PART_OWNER_SW_CFG_SIZE 632u -#define OTP_PART_OWNERSHIP_SLOT_STATE_OFFSET 1016u -#define OTP_PART_OWNERSHIP_SLOT_STATE_SIZE 48u -#define OTP_PART_ROT_CREATOR_AUTH_OFFSET 1064u -#define OTP_PART_ROT_CREATOR_AUTH_SIZE 1424u -#define OTP_PART_ROT_OWNER_AUTH_SLOT0_OFFSET 2488u -#define OTP_PART_ROT_OWNER_AUTH_SLOT0_SIZE 328u -#define OTP_PART_ROT_OWNER_AUTH_SLOT1_OFFSET 2816u -#define OTP_PART_ROT_OWNER_AUTH_SLOT1_SIZE 328u -#define OTP_PART_PLAT_INTEG_AUTH_SLOT0_OFFSET 3144u -#define OTP_PART_PLAT_INTEG_AUTH_SLOT0_SIZE 328u -#define OTP_PART_PLAT_INTEG_AUTH_SLOT1_OFFSET 3472u -#define OTP_PART_PLAT_INTEG_AUTH_SLOT1_SIZE 328u -#define OTP_PART_PLAT_OWNER_AUTH_SLOT0_OFFSET 3800u -#define OTP_PART_PLAT_OWNER_AUTH_SLOT0_SIZE 328u -#define OTP_PART_PLAT_OWNER_AUTH_SLOT1_OFFSET 4128u -#define OTP_PART_PLAT_OWNER_AUTH_SLOT1_SIZE 328u -#define OTP_PART_PLAT_OWNER_AUTH_SLOT2_OFFSET 4456u -#define OTP_PART_PLAT_OWNER_AUTH_SLOT2_SIZE 328u -#define OTP_PART_PLAT_OWNER_AUTH_SLOT3_OFFSET 4784u -#define OTP_PART_PLAT_OWNER_AUTH_SLOT3_SIZE 328u -#define OTP_PART_EXT_NVM_OFFSET 5112u -#define OTP_PART_EXT_NVM_SIZE 1024u -#define OTP_PART_ROM_PATCH_OFFSET 6136u -#define OTP_PART_ROM_PATCH_SIZE 9784u -#define OTP_PART_HW_CFG0_OFFSET 15920u -#define OTP_PART_HW_CFG0_SIZE 72u -#define OTP_PART_HW_CFG1_OFFSET 15992u -#define OTP_PART_HW_CFG1_SIZE 16u -#define OTP_PART_SECRET0_OFFSET 16008u -#define OTP_PART_SECRET0_SIZE 40u -#define OTP_PART_SECRET1_OFFSET 16048u -#define OTP_PART_SECRET1_SIZE 88u -#define OTP_PART_SECRET2_OFFSET 16136u -#define OTP_PART_SECRET2_SIZE 120u -#define OTP_PART_SECRET3_OFFSET 16256u -#define OTP_PART_SECRET3_SIZE 40u -#define OTP_PART_LIFE_CYCLE_OFFSET 16296u -#define OTP_PART_LIFE_CYCLE_SIZE 88u - typedef enum { OTP_PART_VENDOR_TEST, OTP_PART_CREATOR_SW_CFG, @@ -733,6 +657,8 @@ typedef struct { #define OT_OTP_DJ_PARTS +#define OTP_PART_LIFE_CYCLE_SIZE 88u + /* NOLINTNEXTLINE */ #include "ot_otp_dj_parts.c" /* NOLINTNEXTLINE */ @@ -1106,6 +1032,8 @@ ot_otp_dj_lci_change_state_line(OtOTPDjState *s, OtOTPLCIState state, int line); #define LCI_CHANGE_STATE(_s_, _st_) \ ot_otp_dj_lci_change_state_line(_s_, _st_, __LINE__) +#define OT_OTP_PART_DATA_OFFSET(_pix_) \ + ((unsigned)(OtOTPPartDescs[(_pix_)].offset)) #define OT_OTP_PART_DATA_BYTE_SIZE(_pix_) \ ((unsigned)(OtOTPPartDescs[(_pix_)].size - \ sizeof(uint32_t) * NUM_DIGEST_WORDS)) @@ -1197,9 +1125,13 @@ static void ot_otp_dj_set_error(OtOTPDjState *s, unsigned part, OtOTPError err) { /* This is it NUM_ERROR_ENTRIES */ g_assert(part < NUM_ERROR_ENTRIES); - s->regs[R_ERR_CODE_0 + part] = ((uint32_t)err) & 0x7u; - trace_ot_otp_set_error(part, ERR_CODE_NAME(err), err); + uint32_t errval = ((uint32_t)err) & 0x7; + if (errval || errval != s->regs[R_ERR_CODE_0 + part]) { + trace_ot_otp_set_error(part, ERR_CODE_NAME(err), err); + } + s->regs[R_ERR_CODE_0 + part] = errval; + switch (err) { case OTP_MACRO_ERROR: @@ -1245,6 +1177,7 @@ static uint32_t ot_otp_dj_get_status(const OtOTPDjState *s) status = FIELD_DP32(s->regs[R_STATUS], STATUS, DAI_IDLE, !ot_otp_dj_dai_is_busy(s)); + status = FIELD_DP32(status, STATUS, RESET_ALLOWED, 1u); return status; } @@ -1330,22 +1263,10 @@ static bool ot_otp_dj_is_part_digest_offset(int part, hwaddr addr) static bool ot_otp_dj_is_readable(OtOTPDjState *s, int partition) { if (OtOTPPartDescs[partition].secret) { - /* secret partition cannot be read (except their digest) */ - return false; - } - - if (!OtOTPPartDescs[partition].read_lock) { - /* read lock is not supported for this partition */ - return true; - } - - if (!OtOTPPartDescs[partition].read_lock_csr && - !s->partctrls[partition].read_lock) { - /* hw read lock, not unlocked */ - return false; + /* secret partitions are only readable if digest is not yet set. */ + return ot_otp_dj_get_buffered_part_digest(s, partition) == 0u; } - bool rdaccess; uint32_t reg; switch (partition) { @@ -1413,20 +1334,21 @@ static bool ot_otp_dj_is_readable(OtOTPDjState *s, int partition) error_setg(&error_fatal, "CSR register not defined"); g_assert_not_reached(); } - rdaccess = (bool)SHARED_FIELD_EX32(s->regs[reg], READ_LOCK); - } else { - if (reg != UINT32_MAX) { - error_setg(&error_fatal, "Unexpected CSR register"); - g_assert_not_reached(); - } - /* - * hwdigest-protected partition are only readable if digest is not yet - * set. - */ - rdaccess = ot_otp_dj_get_buffered_part_digest(s, partition) == 0u; + return (bool)SHARED_FIELD_EX32(s->regs[reg], READ_LOCK); + } + + if (reg != UINT32_MAX) { + error_setg(&error_fatal, "Unexpected CSR register"); + g_assert_not_reached(); + } + + if (!OtOTPPartDescs[partition].read_lock) { + /* read lock is not supported for this partition */ + return true; } - return rdaccess; + /* hw read lock, not locked */ + return !s->partctrls[partition].read_lock; } static void @@ -1623,6 +1545,10 @@ static void ot_otp_dj_check_partition_integrity(OtOTPDjState *s, unsigned ix) if (digest != pctrl->buffer.digest) { trace_ot_otp_mismatch_digest(PART_NAME(ix), ix, digest, pctrl->buffer.digest); + + TRACE_OTP("%s: compute digest %016llx from %s\n", __func__, digest, + ot_otp_hexdump(pctrl->buffer.data, part_size)); + pctrl->failed = true; /* this is a fatal error */ ot_otp_dj_set_error(s, ix, OTP_CHECK_FAIL_ERROR); @@ -1655,6 +1581,20 @@ static bool ot_otp_dj_is_backend_writable(OtOTPDjState *s) return (s->blk != NULL) && blk_is_writable(s->blk); } +static inline int ot_otp_dj_write_backend(OtOTPDjState *s, void *buffer, + unsigned offset, size_t size) +{ + /* + * the blk_pwrite API is awful, isolate it so that linter exceptions are + * are not repeated over and over + */ + // NOLINTBEGIN(clang-analyzer-optin.core.EnumCastOutOfRange) + return blk_pwrite(s->blk, (int64_t)(intptr_t)offset, (int64_t)size, buffer, + /* a bitfield of enum is not an enum item */ + (BdrvRequestFlags)0); + // NOLINTEND(clang-analyzer-optin.core.EnumCastOutOfRange) +} + static void ot_otp_dj_dai_init(OtOTPDjState *s) { DAI_CHANGE_STATE(s, OTP_DAI_IDLE); @@ -1814,9 +1754,10 @@ static void ot_otp_dj_dai_write(OtOTPDjState *s) } unsigned waddr = address >> 2u; - + unsigned size; if (is_wide || is_digest) { waddr &= ~0b1u; + size = sizeof(uint64_t); uint32_t dst_lo = s->otp->data[waddr]; uint32_t dst_hi = s->otp->data[waddr + 1u]; @@ -1827,29 +1768,38 @@ static void ot_otp_dj_dai_write(OtOTPDjState *s) if ((dst_lo & ~lo) || (dst_hi & ~hi)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Cannot clear OTP bits\n", __func__); - ot_otp_dj_dai_set_error(s, OTP_MACRO_WRITE_BLANK_ERROR); - return; + ot_otp_dj_set_error(s, OTP_ENTRY_DAI, OTP_MACRO_WRITE_BLANK_ERROR); } s->otp->data[waddr] = lo; s->otp->data[waddr + 1u] = hi; } else { + size = sizeof(uint32_t); + uint32_t dst = s->otp->data[waddr]; uint32_t data = s->regs[R_DIRECT_ACCESS_WDATA_0]; if (dst & ~data) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Cannot clear OTP bits\n", __func__); - ot_otp_dj_dai_set_error(s, OTP_MACRO_WRITE_BLANK_ERROR); - return; + ot_otp_dj_set_error(s, OTP_ENTRY_DAI, OTP_MACRO_WRITE_BLANK_ERROR); } s->otp->data[waddr] = data; } - /* fake slow access to OTP cell */ + uintptr_t offset = (uintptr_t)s->otp->data - (uintptr_t)s->otp->storage; + if (ot_otp_dj_write_backend(s, &s->otp->data[waddr], + (unsigned)(offset + waddr * sizeof(uint32_t)), + size)) { + error_report("%s: cannot update OTP backend", __func__); + ot_otp_dj_dai_set_error(s, OTP_MACRO_ERROR); + return; + } + DAI_CHANGE_STATE(s, OTP_DAI_WRITE_WAIT); + /* fake slow access to OTP cell */ timer_mod(s->dai->delay, qemu_clock_get_ns(OT_VIRTUAL_CLOCK) + DAI_WRITE_DELAY_NS); } @@ -1919,7 +1869,14 @@ static void ot_otp_dj_dai_digest(OtOTPDjState *s) DAI_CHANGE_STATE(s, OTP_DAI_DIG_READ); - const uint8_t *data = (const uint8_t *)pctrl->buffer.data; + const uint8_t *data; + + if (OtOTPPartDescs[partition].buffered) { + data = ((const uint8_t *)s->otp->data) + + OT_OTP_PART_DATA_OFFSET(partition); + } else { + data = (const uint8_t *)pctrl->buffer.data; + } unsigned part_size = OT_OTP_PART_DATA_BYTE_SIZE(partition); DAI_CHANGE_STATE(s, OTP_DAI_DIG); @@ -1928,6 +1885,9 @@ static void ot_otp_dj_dai_digest(OtOTPDjState *s) ot_otp_dj_compute_partition_digest(s, data, part_size); s->dai->partition = partition; + TRACE_OTP("%s: next digest %016llx from %s\n", __func__, + pctrl->buffer.next_digest, ot_otp_hexdump(data, part_size)); + DAI_CHANGE_STATE(s, OTP_DAI_DIG_WAIT); /* fake slow access to OTP cell */ @@ -1945,29 +1905,31 @@ static void ot_otp_dj_dai_write_digest(void *opaque) OtOTPPartController *pctrl = &s->partctrls[s->dai->partition]; unsigned address = OtOTPPartDescs[s->dai->partition].digest_offset; - address >>= 3u; - uint64_t *dst = &((uint64_t *)s->otp->data)[address]; + unsigned dwaddr = address / sizeof(uint64_t); + uint64_t *dst = &((uint64_t *)s->otp->data)[dwaddr]; uint64_t data = pctrl->buffer.next_digest; pctrl->buffer.next_digest = 0; - OtOTPError error; + if (*dst & ~data) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Cannot clear OTP bits\n", __func__); - error = OTP_MACRO_WRITE_BLANK_ERROR; + ot_otp_dj_set_error(s, OTP_ENTRY_DAI, OTP_MACRO_WRITE_BLANK_ERROR); } else { *dst |= data; - error = OTP_NO_ERROR; } - if (error == OTP_NO_ERROR) { - /* fake slow access to OTP cell */ - DAI_CHANGE_STATE(s, OTP_DAI_WRITE_WAIT); - - timer_mod(s->dai->delay, - qemu_clock_get_ns(OT_VIRTUAL_CLOCK) + DAI_WRITE_DELAY_NS); - } else { - /* TODO: no idea on how to report the error since partition is undef */ - ot_otp_dj_dai_set_error(s, error); + uintptr_t offset = (uintptr_t)s->otp->data - (uintptr_t)s->otp->storage; + if (ot_otp_dj_write_backend(s, dst, (unsigned)(offset + address), + sizeof(uint64_t))) { + error_report("%s: cannot update OTP backend", __func__); + ot_otp_dj_dai_set_error(s, OTP_MACRO_ERROR); + return; } + + DAI_CHANGE_STATE(s, OTP_DAI_WRITE_WAIT); + + /* fake slow access to OTP cell */ + timer_mod(s->dai->delay, + qemu_clock_get_ns(OT_VIRTUAL_CLOCK) + DAI_WRITE_DELAY_NS); } static void ot_otp_dj_dai_complete(void *opaque) @@ -2004,7 +1966,7 @@ static void ot_otp_dj_lci_init(OtOTPDjState *s) LCI_CHANGE_STATE(s, OTP_LCI_IDLE); } -static uint64_t ot_otp_dj_regs_read(void *opaque, hwaddr addr, unsigned size) +static uint64_t ot_otp_dj_reg_read(void *opaque, hwaddr addr, unsigned size) { OtOTPDjState *s = OT_OTP_DJ(opaque); (void)size; @@ -2276,13 +2238,13 @@ static uint64_t ot_otp_dj_regs_read(void *opaque, hwaddr addr, unsigned size) } uint32_t pc = ibex_get_current_pc(); - trace_ot_otp_io_read_out((uint32_t)addr, REG_NAME(reg), val32, pc); + trace_ot_otp_io_reg_read_out((uint32_t)addr, REG_NAME(reg), val32, pc); return (uint64_t)val32; } -static void ot_otp_dj_regs_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) +static void ot_otp_dj_reg_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) { OtOTPDjState *s = OT_OTP_DJ(opaque); (void)size; @@ -2292,7 +2254,7 @@ static void ot_otp_dj_regs_write(void *opaque, hwaddr addr, uint64_t value, uint32_t pc = ibex_get_current_pc(); - trace_ot_otp_io_write((uint32_t)addr, REG_NAME(reg), val32, pc); + trace_ot_otp_io_reg_write((uint32_t)addr, REG_NAME(reg), val32, pc); switch (reg) { case R_DIRECT_ACCESS_CMD: @@ -2493,14 +2455,26 @@ static const char *ot_otp_dj_swcfg_reg_name(unsigned swreg) case R_##_reg_: \ return stringify(_reg_) #define CASE_RANGE(_reg_) \ - case R_##_reg_...(R_##_reg_ + ((_reg_##_SIZE) / 4u) - 1u): \ + case R_##_reg_...(R_##_reg_ + (((_reg_##_SIZE) + 3u) / 4u) - 1u): \ + return stringify(_reg_) +#define CASE_DIGEST(_reg_) \ + case R_##_reg_...(R_##_reg_ + 1u): \ return stringify(_reg_) switch (swreg) { - CASE_RANGE(SCRATCH); - CASE_RANGE(VENDOR_TEST_DIGEST); + CASE_RANGE(VENDOR_TEST_SCRATCH); + CASE_DIGEST(VENDOR_TEST_DIGEST); + CASE_RANGE(CREATOR_SW_CFG_DIO_ATTR); CASE_RANGE(CREATOR_SW_CFG_AST_CFG); + CASE_RANGE(CREATOR_SW_CFG_AST_SPARES); + CASE_SCALAR(CREATOR_SW_CFG_AST_AVGSFUSECTL); + CASE_SCALAR(CREATOR_SW_CFG_AST_AVGSHDRCFG); + CASE_SCALAR(CREATOR_SW_CFG_AST_RINGOSC_TRIM_CTL); + CASE_SCALAR(CREATOR_SW_CFG_AST_RINGOSC_FREQ_COUNT_CTL); + CASE_SCALAR(CREATOR_SW_CFG_AST_RINGOSC_FREQ_TH_SLOW); + CASE_SCALAR(CREATOR_SW_CFG_AST_RINGOSC_FREQ_TH_FAST); CASE_SCALAR(CREATOR_SW_CFG_AST_INIT_EN); + CASE_RANGE(CREATOR_SW_CFG_OVERRIDES); CASE_SCALAR(CREATOR_SW_CFG_ROM_EXT_SKU); CASE_SCALAR(CREATOR_SW_CFG_SIGVERIFY_RSA_MOD_EXP_IBEX_EN); CASE_RANGE(CREATOR_SW_CFG_SIGVERIFY_RSA_KEY_EN); @@ -2532,7 +2506,7 @@ static const char *ot_otp_dj_swcfg_reg_name(unsigned swreg) CASE_SCALAR(CREATOR_SW_CFG_RNG_ALERT_THRESHOLD); CASE_SCALAR(CREATOR_SW_CFG_RNG_HEALTH_CONFIG_DIGEST); CASE_SCALAR(CREATOR_SW_CFG_SRAM_KEY_RENEW_EN); - CASE_RANGE(CREATOR_SW_CFG_DIGEST); + CASE_DIGEST(CREATOR_SW_CFG_DIGEST); CASE_SCALAR(OWNER_SW_CFG_ROM_ERROR_REPORTING); CASE_SCALAR(OWNER_SW_CFG_ROM_BOOTSTRAP_DIS); CASE_SCALAR(OWNER_SW_CFG_ROM_ALERT_CLASS_EN); @@ -2550,64 +2524,63 @@ static const char *ot_otp_dj_swcfg_reg_name(unsigned swreg) CASE_SCALAR(OWNER_SW_CFG_ROM_KEYMGR_ROM_EXT_MEAS_EN); CASE_SCALAR(OWNER_SW_CFG_MANUF_STATE); CASE_SCALAR(OWNER_SW_CFG_ROM_RSTMGR_INFO_EN); - CASE_RANGE(OWNER_SW_CFG_DIGEST); + CASE_DIGEST(OWNER_SW_CFG_DIGEST); CASE_RANGE(OWNERSHIP_SLOT_STATE_ROT_OWNER_AUTH); CASE_RANGE(OWNERSHIP_SLOT_STATE_PLAT_INTEG_AUTH); CASE_RANGE(OWNERSHIP_SLOT_STATE_PLAT_OWNER_AUTH); CASE_RANGE(ROT_CREATOR_AUTH_NON_RAW_MFW_CODESIGN_KEY); - CASE_RANGE(ROT_CREATOR_AUTH_OWNERSHIP_STATE); CASE_RANGE(ROT_CREATOR_AUTH_ROM2_PATCH_SIGVERIFY_KEY); CASE_RANGE(ROT_CREATOR_AUTH_KEYMANIFEST_KEY); - CASE_RANGE(ROT_CREATOR_AUTH_UNLOCK4XFER_KEY); CASE_RANGE(ROT_CREATOR_AUTH_IDENTITY_CERT); - CASE_RANGE(ROT_CREATOR_AUTH_DIGEST); + CASE_RANGE(ROT_CREATOR_AUTH_IDENTITY_CERT_CMAC); + CASE_DIGEST(ROT_CREATOR_AUTH_DIGEST); CASE_RANGE(ROT_OWNER_AUTH_SLOT0_KEYMANIFEST_KEY); CASE_RANGE(ROT_OWNER_AUTH_SLOT0_UNLOCK4XFER_KEY); - CASE_RANGE(ROT_OWNER_AUTH_SLOT0_DIGEST); + CASE_DIGEST(ROT_OWNER_AUTH_SLOT0_DIGEST); CASE_RANGE(ROT_OWNER_AUTH_SLOT1_KEYMANIFEST_KEY); CASE_RANGE(ROT_OWNER_AUTH_SLOT1_UNLOCK4XFER_KEY); - CASE_RANGE(ROT_OWNER_AUTH_SLOT1_DIGEST); + CASE_DIGEST(ROT_OWNER_AUTH_SLOT1_DIGEST); CASE_RANGE(PLAT_INTEG_AUTH_SLOT0_KEYMANIFEST_KEY); CASE_RANGE(PLAT_INTEG_AUTH_SLOT0_UNLOCK4XFER_KEY); - CASE_RANGE(PLAT_INTEG_AUTH_SLOT0_DIGEST); + CASE_DIGEST(PLAT_INTEG_AUTH_SLOT0_DIGEST); CASE_RANGE(PLAT_INTEG_AUTH_SLOT1_KEYMANIFEST_KEY); CASE_RANGE(PLAT_INTEG_AUTH_SLOT1_UNLOCK4XFER_KEY); - CASE_RANGE(PLAT_INTEG_AUTH_SLOT1_DIGEST); + CASE_DIGEST(PLAT_INTEG_AUTH_SLOT1_DIGEST); CASE_RANGE(PLAT_OWNER_AUTH_SLOT0_KEYMANIFEST_KEY); CASE_RANGE(PLAT_OWNER_AUTH_SLOT0_UNLOCK4XFER_KEY); - CASE_RANGE(PLAT_OWNER_AUTH_SLOT0_DIGEST); + CASE_DIGEST(PLAT_OWNER_AUTH_SLOT0_DIGEST); CASE_RANGE(PLAT_OWNER_AUTH_SLOT1_KEYMANIFEST_KEY); CASE_RANGE(PLAT_OWNER_AUTH_SLOT1_UNLOCK4XFER_KEY); - CASE_RANGE(PLAT_OWNER_AUTH_SLOT1_DIGEST); + CASE_DIGEST(PLAT_OWNER_AUTH_SLOT1_DIGEST); CASE_RANGE(PLAT_OWNER_AUTH_SLOT2_KEYMANIFEST_KEY); CASE_RANGE(PLAT_OWNER_AUTH_SLOT2_UNLOCK4XFER_KEY); - CASE_RANGE(PLAT_OWNER_AUTH_SLOT2_DIGEST); + CASE_DIGEST(PLAT_OWNER_AUTH_SLOT2_DIGEST); CASE_RANGE(PLAT_OWNER_AUTH_SLOT3_KEYMANIFEST_KEY); CASE_RANGE(PLAT_OWNER_AUTH_SLOT3_UNLOCK4XFER_KEY); - CASE_RANGE(PLAT_OWNER_AUTH_SLOT3_DIGEST); + CASE_DIGEST(PLAT_OWNER_AUTH_SLOT3_DIGEST); CASE_RANGE(EXT_NVM_ANTIREPLAY_FRESHNESS_CNT); CASE_RANGE(ROM_PATCH_DATA); - CASE_RANGE(ROM_PATCH_DIGEST); - CASE_RANGE(DEVICE_ID); - CASE_RANGE(MANUF_STATE); - CASE_RANGE(HW_CFG0_DIGEST); - CASE_SCALAR(SOC_DBG_STATE); - CASE_SCALAR(EN_SRAM_IFETCH); - CASE_RANGE(HW_CFG1_DIGEST); - CASE_RANGE(TEST_UNLOCK_TOKEN); - CASE_RANGE(TEST_EXIT_TOKEN); - CASE_RANGE(SECRET0_DIGEST); - CASE_RANGE(FLASH_ADDR_KEY_SEED); - CASE_RANGE(FLASH_DATA_KEY_SEED); - CASE_RANGE(SRAM_DATA_KEY_SEED); - CASE_RANGE(SECRET1_DIGEST); - CASE_RANGE(RMA_TOKEN); - CASE_RANGE(CREATOR_ROOT_KEY_SHARE0); - CASE_RANGE(CREATOR_ROOT_KEY_SHARE1); - CASE_RANGE(CREATOR_SEED); - CASE_RANGE(SECRET2_DIGEST); - CASE_RANGE(OWNER_SEED); - CASE_RANGE(SECRET3_DIGEST); + CASE_DIGEST(ROM_PATCH_DIGEST); + CASE_RANGE(HW_CFG0_DEVICE_ID); + CASE_RANGE(HW_CFG0_MANUF_STATE); + CASE_DIGEST(HW_CFG0_DIGEST); + CASE_SCALAR(HW_CFG1_SOC_DBG_STATE); + CASE_SCALAR(HW_CFG1_EN_SRAM_IFETCH); + CASE_DIGEST(HW_CFG1_DIGEST); + CASE_RANGE(SECRET0_TEST_UNLOCK_TOKEN); + CASE_RANGE(SECRET0_TEST_EXIT_TOKEN); + CASE_DIGEST(SECRET0_DIGEST); + CASE_RANGE(SECRET1_FLASH_ADDR_KEY_SEED); + CASE_RANGE(SECRET1_FLASH_DATA_KEY_SEED); + CASE_RANGE(SECRET1_SRAM_DATA_KEY_SEED); + CASE_DIGEST(SECRET1_DIGEST); + CASE_RANGE(SECRET2_RMA_TOKEN); + CASE_RANGE(SECRET2_CREATOR_ROOT_KEY_SHARE0); + CASE_RANGE(SECRET2_CREATOR_ROOT_KEY_SHARE1); + CASE_RANGE(SECRET2_CREATOR_SEED); + CASE_DIGEST(SECRET2_DIGEST); + CASE_RANGE(SECRET3_OWNER_SEED); + CASE_DIGEST(SECRET3_DIGEST); CASE_RANGE(LC_TRANSITION_CNT); CASE_RANGE(LC_STATE); default: @@ -2661,15 +2634,15 @@ static MemTxResult ot_otp_dj_swcfg_read_with_attrs( uint64_t pc; pc = ibex_get_current_pc(); - trace_ot_otp_io_read_out((uint32_t)addr, ot_otp_dj_swcfg_reg_name(reg), - val32, pc); + trace_ot_otp_io_swcfg_read_out((uint32_t)addr, + ot_otp_dj_swcfg_reg_name(reg), val32, pc); *data = (uint64_t)val32; return MEMTX_OK; } -static uint64_t ot_otp_dj_csrs_read(void *opaque, hwaddr addr, unsigned size) +static uint64_t ot_otp_dj_csr_read(void *opaque, hwaddr addr, unsigned size) { (void)opaque; (void)size; @@ -2696,13 +2669,13 @@ static uint64_t ot_otp_dj_csrs_read(void *opaque, hwaddr addr, unsigned size) } uint32_t pc = ibex_get_current_pc(); - trace_ot_otp_io_read_out((uint32_t)addr, CSR_NAME(reg), val32, pc); + trace_ot_otp_io_csr_read_out((uint32_t)addr, CSR_NAME(reg), val32, pc); return (uint64_t)val32; } -static void ot_otp_dj_csrs_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) +static void ot_otp_dj_csr_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) { (void)opaque; (void)size; @@ -2711,7 +2684,7 @@ static void ot_otp_dj_csrs_write(void *opaque, hwaddr addr, uint64_t value, hwaddr reg = R32_OFF(addr); uint32_t pc = ibex_get_current_pc(); - trace_ot_otp_io_write((uint32_t)addr, CSR_NAME(reg), val32, pc); + trace_ot_otp_io_csr_write((uint32_t)addr, CSR_NAME(reg), val32, pc); switch (reg) { case R_CSR0: @@ -2769,13 +2742,13 @@ static void ot_otp_dj_load_hw_cfg(OtOTPDjState *s) OtOTPStorage *otp = s->otp; OtOTPHWCfg *hw_cfg = s->hw_cfg; - memcpy(hw_cfg->device_id, &otp->data[R_DEVICE_ID], + memcpy(hw_cfg->device_id, &otp->data[R_HW_CFG0_DEVICE_ID], sizeof(*hw_cfg->device_id)); - memcpy(hw_cfg->manuf_state, &otp->data[R_MANUF_STATE], + memcpy(hw_cfg->manuf_state, &otp->data[R_HW_CFG0_MANUF_STATE], sizeof(*hw_cfg->manuf_state)); - hw_cfg->soc_dbg_state = otp->data[R_SOC_DBG_STATE]; - hw_cfg->en_sram_ifetch = (uint8_t)otp->data[R_EN_SRAM_IFETCH]; + hw_cfg->soc_dbg_state = otp->data[R_HW_CFG1_SOC_DBG_STATE]; + hw_cfg->en_sram_ifetch = (uint8_t)otp->data[R_HW_CFG1_EN_SRAM_IFETCH]; } static void ot_otp_dj_load_tokens(OtOTPDjState *s) @@ -2794,15 +2767,15 @@ static void ot_otp_dj_load_tokens(OtOTPDjState *s) switch (tkx) { case OTP_TOKEN_TEST_UNLOCK: partition = OTP_PART_SECRET0; - reg = R_TEST_UNLOCK_TOKEN; + reg = R_SECRET0_TEST_UNLOCK_TOKEN; break; case OTP_TOKEN_TEST_EXIT: partition = OTP_PART_SECRET0; - reg = R_TEST_EXIT_TOKEN; + reg = R_SECRET0_TEST_EXIT_TOKEN; break; case OTP_TOKEN_RMA: partition = OTP_PART_SECRET2; - reg = R_RMA_TOKEN; + reg = R_SECRET2_RMA_TOKEN; break; default: g_assert_not_reached(); @@ -2925,8 +2898,9 @@ static void ot_otp_dj_generate_otp_sram_key(OtOTPDjState *s, OtOTPKey *key) bool valid = pctrl->locked && !pctrl->failed; g_assert(ot_otp_dj_is_buffered(OTP_PART_SECRET1)); const uint32_t *sram_data_key_seed = - &pctrl->buffer.data[R_SRAM_DATA_KEY_SEED - - OTP_PART_SECRET1_OFFSET / sizeof(uint32_t)]; + &pctrl->buffer + .data[R_SECRET1_SRAM_DATA_KEY_SEED - + OtOTPPartDescs[OTP_PART_SECRET1].offset / sizeof(uint32_t)]; uint32_t tmpkey[SRAM_KEY_WORDS]; for (unsigned rix = 0; rix < SRAM_KEY_WIDTH / 64u; rix++) { uint64_t data = RND_CNST_DIGEST_IV; @@ -3097,11 +3071,9 @@ static void ot_otp_dj_lci_write_complete(OtOTPDjState *s, bool success) const OtOTPPartDesc *lcdesc = &OtOTPPartDescs[OTP_PART_LIFE_CYCLE]; unsigned lc_data_off = lcdesc->offset / sizeof(uint32_t); uintptr_t offset = (uintptr_t)s->otp->data - (uintptr_t)s->otp->storage; - // NOLINTBEGIN(clang-analyzer-optin.core.EnumCastOutOfRange) - if (blk_pwrite(s->blk, (int64_t)(intptr_t)(offset + lcdesc->offset), - lcdesc->size, &s->otp->data[lc_data_off], - (BdrvRequestFlags)0)) { - // NOLINTEND(clang-analyzer-optin.core.EnumCastOutOfRange) + if (ot_otp_dj_write_backend(s, &s->otp->data[lc_data_off], + (unsigned)(offset + lcdesc->offset), + lcdesc->size)) { error_report("%s: cannot update OTP backend", __func__); if (lci->error == OTP_NO_ERROR) { lci->error = OTP_MACRO_ERROR; @@ -3343,9 +3315,9 @@ static Property ot_otp_dj_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static const MemoryRegionOps ot_otp_dj_regs_ops = { - .read = &ot_otp_dj_regs_read, - .write = &ot_otp_dj_regs_write, +static const MemoryRegionOps ot_otp_dj_reg_ops = { + .read = &ot_otp_dj_reg_read, + .write = &ot_otp_dj_reg_write, .endianness = DEVICE_NATIVE_ENDIAN, .impl.min_access_size = 4, .impl.max_access_size = 4, @@ -3358,9 +3330,9 @@ static const MemoryRegionOps ot_otp_dj_swcfg_ops = { .impl.max_access_size = 4, }; -static const MemoryRegionOps ot_otp_dj_csrs_ops = { - .read = &ot_otp_dj_csrs_read, - .write = &ot_otp_dj_csrs_write, +static const MemoryRegionOps ot_otp_dj_csr_ops = { + .read = &ot_otp_dj_csr_read, + .write = &ot_otp_dj_csr_write, .endianness = DEVICE_NATIVE_ENDIAN, .impl.min_access_size = 4, .impl.max_access_size = 4, @@ -3459,7 +3431,7 @@ static void ot_otp_dj_init(Object *obj) SW_CFG_WINDOW + SW_CFG_WINDOW_SIZE); sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio.ctrl); - memory_region_init_io(&s->mmio.sub.regs, obj, &ot_otp_dj_regs_ops, s, + memory_region_init_io(&s->mmio.sub.regs, obj, &ot_otp_dj_reg_ops, s, TYPE_OT_OTP "-regs", REGS_SIZE); memory_region_add_subregion(&s->mmio.ctrl, 0u, &s->mmio.sub.regs); @@ -3469,7 +3441,7 @@ static void ot_otp_dj_init(Object *obj) memory_region_add_subregion(&s->mmio.ctrl, SW_CFG_WINDOW, &s->mmio.sub.swcfg); - memory_region_init_io(&s->prim.csrs, obj, &ot_otp_dj_csrs_ops, s, + memory_region_init_io(&s->prim.csrs, obj, &ot_otp_dj_csr_ops, s, TYPE_OT_OTP "-prim", CSRS_SIZE); sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->prim.csrs); @@ -3527,6 +3499,9 @@ static void ot_otp_dj_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); (void)data; + g_assert(OTP_PART_LIFE_CYCLE_SIZE == + OtOTPPartDescs[OTP_PART_LIFE_CYCLE].size); + dc->reset = &ot_otp_dj_reset; dc->realize = &ot_otp_dj_realize; device_class_set_props(dc, ot_otp_dj_properties); diff --git a/hw/opentitan/ot_otp_eg.c b/hw/opentitan/ot_otp_eg.c index 30d60c23070c..377033bdb720 100644 --- a/hw/opentitan/ot_otp_eg.c +++ b/hw/opentitan/ot_otp_eg.c @@ -708,7 +708,7 @@ static void ot_otp_eg_direct_digest(OtOTPEgState *s) qemu_log_mask(LOG_UNIMP, "%s: OTP change is not supported\n", __func__); } -static uint64_t ot_otp_eg_regs_read(void *opaque, hwaddr addr, unsigned size) +static uint64_t ot_otp_eg_reg_read(void *opaque, hwaddr addr, unsigned size) { OtOTPEgState *s = OT_OTP_EG(opaque); (void)size; @@ -826,13 +826,13 @@ static uint64_t ot_otp_eg_regs_read(void *opaque, hwaddr addr, unsigned size) } uint32_t pc = ibex_get_current_pc(); - trace_ot_otp_io_read_out((uint32_t)addr, REG_NAME(reg), val32, pc); + trace_ot_otp_io_reg_read_out((uint32_t)addr, REG_NAME(reg), val32, pc); return (uint64_t)val32; } -static void ot_otp_eg_regs_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) +static void ot_otp_eg_reg_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) { OtOTPEgState *s = OT_OTP_EG(opaque); (void)size; @@ -841,7 +841,7 @@ static void ot_otp_eg_regs_write(void *opaque, hwaddr addr, uint64_t value, hwaddr reg = R32_OFF(addr); uint32_t pc = ibex_get_current_pc(); - trace_ot_otp_io_write((uint32_t)addr, REG_NAME(reg), val32, pc); + trace_ot_otp_io_reg_write((uint32_t)addr, REG_NAME(reg), val32, pc); switch (reg) { case R_INTR_STATE: @@ -1039,8 +1039,8 @@ static uint64_t ot_otp_eg_swcfg_read(void *opaque, hwaddr addr, unsigned size) uint64_t pc; pc = ibex_get_current_pc(); - trace_ot_otp_io_read_out((uint32_t)addr, ot_otp_eg_swcfg_reg_name(reg), - val32, pc); + trace_ot_otp_io_swcfg_read_out((uint32_t)addr, + ot_otp_eg_swcfg_reg_name(reg), val32, pc); return (uint64_t)val32; } @@ -1060,7 +1060,7 @@ static void ot_otp_eg_swcfg_write(void *opaque, hwaddr addr, uint64_t value, addr, ot_otp_eg_swcfg_reg_name(reg)); } -static uint64_t ot_otp_eg_csrs_read(void *opaque, hwaddr addr, unsigned size) +static uint64_t ot_otp_eg_csr_read(void *opaque, hwaddr addr, unsigned size) { (void)opaque; (void)size; @@ -1087,13 +1087,13 @@ static uint64_t ot_otp_eg_csrs_read(void *opaque, hwaddr addr, unsigned size) } uint32_t pc = ibex_get_current_pc(); - trace_ot_otp_io_read_out((uint32_t)addr, CSR_NAME(reg), val32, pc); + trace_ot_otp_io_csr_read_out((uint32_t)addr, CSR_NAME(reg), val32, pc); return (uint64_t)val32; } -static void ot_otp_eg_csrs_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) +static void ot_otp_eg_csr_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) { (void)opaque; (void)size; @@ -1102,7 +1102,7 @@ static void ot_otp_eg_csrs_write(void *opaque, hwaddr addr, uint64_t value, hwaddr reg = R32_OFF(addr); uint32_t pc = ibex_get_current_pc(); - trace_ot_otp_io_write((uint32_t)addr, CSR_NAME(reg), val32, pc); + trace_ot_otp_io_csr_write((uint32_t)addr, CSR_NAME(reg), val32, pc); switch (reg) { case R_CSR0: @@ -1219,9 +1219,9 @@ static Property ot_otp_eg_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static const MemoryRegionOps ot_otp_eg_regs_ops = { - .read = &ot_otp_eg_regs_read, - .write = &ot_otp_eg_regs_write, +static const MemoryRegionOps ot_otp_eg_reg_ops = { + .read = &ot_otp_eg_reg_read, + .write = &ot_otp_eg_reg_write, .endianness = DEVICE_NATIVE_ENDIAN, .impl.min_access_size = 4, .impl.max_access_size = 4, @@ -1235,9 +1235,9 @@ static const MemoryRegionOps ot_otp_eg_swcfg_ops = { .impl.max_access_size = 4, }; -static const MemoryRegionOps ot_otp_eg_csrs_ops = { - .read = &ot_otp_eg_csrs_read, - .write = &ot_otp_eg_csrs_write, +static const MemoryRegionOps ot_otp_eg_csr_ops = { + .read = &ot_otp_eg_csr_read, + .write = &ot_otp_eg_csr_write, .endianness = DEVICE_NATIVE_ENDIAN, .impl.min_access_size = 4, .impl.max_access_size = 4, @@ -1375,7 +1375,7 @@ static void ot_otp_eg_init(Object *obj) memory_region_init(&s->mmio.ctrl, obj, TYPE_OT_OTP ".ctrl", 0x2000u); sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio.ctrl); - memory_region_init_io(&s->mmio.sub.regs, obj, &ot_otp_eg_regs_ops, s, + memory_region_init_io(&s->mmio.sub.regs, obj, &ot_otp_eg_reg_ops, s, TYPE_OT_OTP ".regs", REGS_SIZE); memory_region_add_subregion(&s->mmio.ctrl, 0u, &s->mmio.sub.regs); @@ -1385,7 +1385,7 @@ static void ot_otp_eg_init(Object *obj) memory_region_add_subregion(&s->mmio.ctrl, SW_CFG_WINDOW, &s->mmio.sub.swcfg); - memory_region_init_io(&s->prim.csrs, obj, &ot_otp_eg_csrs_ops, s, + memory_region_init_io(&s->prim.csrs, obj, &ot_otp_eg_csr_ops, s, TYPE_OT_OTP ".prim", CSRS_SIZE); sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->prim.csrs); diff --git a/hw/opentitan/ot_pwrmgr.c b/hw/opentitan/ot_pwrmgr.c index af301eda60a0..74435ae4b749 100644 --- a/hw/opentitan/ot_pwrmgr.c +++ b/hw/opentitan/ot_pwrmgr.c @@ -239,16 +239,16 @@ struct OtPwrMgrState { IbexIRQ cpu_enable; IbexIRQ pwr_lc_req; IbexIRQ pwr_otp_req; + IbexIRQ reset_req; OtPwrMgrFastState f_state; OtPwrMgrSlowState s_state; OtPwrMgrEvents fsm_events; uint32_t *regs; - OtPwrMgrResetReq reset_req; + OtPwrMgrResetReq reset_request; char *ot_id; - OtRstMgrState *rstmgr; uint8_t num_rom; uint8_t version; bool main; /* main power manager (for machines w/ multiple PwrMgr) */ @@ -500,16 +500,16 @@ static void ot_pwrmgr_rst_req(void *opaque, int irq, int level) } s->regs[R_RESET_STATUS] |= rstbit; - g_assert(s->reset_req.domain == OT_PWRMGR_NO_DOMAIN); + g_assert(s->reset_request.domain == OT_PWRMGR_NO_DOMAIN); - s->reset_req.domain = OT_PWRMGR_SLOW_DOMAIN; + s->reset_request.domain = OT_PWRMGR_SLOW_DOMAIN; int req = PWRMGR_RESET_DISPATCH[s->version][src]; if (req < 0) { /* not yet implemented */ g_assert_not_reached(); } - s->reset_req.req = req; + s->reset_request.req = req; trace_ot_pwrmgr_reset_req(s->ot_id, "scheduling reset", src); @@ -538,10 +538,10 @@ static void ot_pwrmgr_sw_rst_req(void *opaque, int irq, int level) s->regs[R_RESET_STATUS] |= rstbit; - g_assert(s->reset_req.domain == OT_PWRMGR_NO_DOMAIN); + g_assert(s->reset_request.domain == OT_PWRMGR_NO_DOMAIN); - s->reset_req.req = OT_RSTMGR_RESET_SW; - s->reset_req.domain = OT_PWRMGR_FAST_DOMAIN; + s->reset_request.req = OT_RSTMGR_RESET_SW; + s->reset_request.domain = OT_PWRMGR_FAST_DOMAIN; trace_ot_pwrmgr_reset_req(s->ot_id, "scheduling SW reset", 0); @@ -643,9 +643,10 @@ static void ot_pwrmgr_fast_fsm_tick(OtPwrMgrState *s) /* fallthrough */ case OT_PWR_FAST_ST_RESET_PREP: PWR_CHANGE_FAST_STATE(s, RESET_WAIT); - ot_rstmgr_reset_req(s->rstmgr, (bool)s->reset_req.domain, - s->reset_req.req); - s->reset_req.domain = OT_PWRMGR_NO_DOMAIN; + ibex_irq_set(&s->reset_req, + OT_RSTMGR_RESET_REQUEST(s->reset_request.domain, + s->reset_request.req)); + s->reset_request.domain = OT_PWRMGR_NO_DOMAIN; break; /* NOLINTNEXTLINE */ case OT_PWR_FAST_ST_RESET_WAIT: @@ -880,8 +881,6 @@ static Property ot_pwrmgr_properties[] = { DEFINE_PROP_UINT8("version", OtPwrMgrState, version, UINT8_MAX), DEFINE_PROP_BOOL("fetch-ctrl", OtPwrMgrState, fetch_ctrl, false), DEFINE_PROP_BOOL("main", OtPwrMgrState, main, true), - DEFINE_PROP_LINK("rstmgr", OtPwrMgrState, rstmgr, TYPE_OT_RSTMGR, - OtRstMgrState *), DEFINE_PROP_END_OF_LIST(), }; @@ -917,8 +916,6 @@ static void ot_pwrmgr_reset_enter(Object *obj, ResetType type) c->parent_phases.enter(obj, type); } - assert(s->rstmgr); - timer_del(s->cdc_sync); memset(s->regs, 0, REGS_SIZE); @@ -938,6 +935,7 @@ static void ot_pwrmgr_reset_enter(Object *obj, ResetType type) ibex_irq_set(&s->pwr_otp_req, 0); ibex_irq_set(&s->pwr_lc_req, 0); ibex_irq_set(&s->alert, 0); + ibex_irq_set(&s->reset_req, 0); } static void ot_pwrmgr_reset_exit(Object *obj) @@ -991,6 +989,7 @@ static void ot_pwrmgr_init(Object *obj) ibex_qdev_init_irq(obj, &s->pwr_otp_req, OT_PWRMGR_OTP_REQ); ibex_qdev_init_irq(obj, &s->cpu_enable, OT_PWRMGR_CPU_EN); ibex_qdev_init_irq(obj, &s->strap, OT_PWRMGR_STRAP); + ibex_qdev_init_irq(obj, &s->reset_req, OT_PWRMGR_RST_REQ); s->cdc_sync = timer_new_ns(OT_VIRTUAL_CLOCK, &ot_pwrmgr_cdc_sync, s); diff --git a/hw/opentitan/ot_rstmgr.c b/hw/opentitan/ot_rstmgr.c index 050e500ce9fa..357ce106a09d 100644 --- a/hw/opentitan/ot_rstmgr.c +++ b/hw/opentitan/ot_rstmgr.c @@ -43,7 +43,7 @@ #include "hw/riscv/ibex_common.h" #include "hw/riscv/ibex_irq.h" #include "hw/sysbus.h" -#include "sysemu/hw_accel.h" +#include "sysemu/runstate.h" #include "trace.h" @@ -146,6 +146,7 @@ struct OtRstMgrState { SysBusDevice parent_obj; MemoryRegion mmio; + IbexIRQ soc_reset; IbexIRQ sw_reset; IbexIRQ alerts[PARAM_NUM_ALERTS]; QEMUBH *bus_reset_bh; @@ -154,6 +155,7 @@ struct OtRstMgrState { uint32_t *regs; char *ot_id; + uint32_t fatal_reset; bool por; /* Power-On Reset property */ }; @@ -198,19 +200,6 @@ static const char *OT_RST_MGR_REQUEST_NAMES[] = { OT_RST_MGR_REQUEST_NAMES[(_req_)] : \ "?" -/* -------------------------------------------------------------------------- */ -/* Public API */ -/* -------------------------------------------------------------------------- */ - -void ot_rstmgr_reset_req(OtRstMgrState *s, bool fastclk, OtRstMgrResetReq req) -{ - s->regs[R_RESET_INFO] = 1u << req; - - trace_ot_rstmgr_reset_req(REQ_NAME(req), req, fastclk); - - qemu_bh_schedule(s->bus_reset_bh); -} - /* -------------------------------------------------------------------------- */ /* Private implementation */ /* -------------------------------------------------------------------------- */ @@ -239,12 +228,7 @@ static void ot_rstmgr_reset_bus(void *opaque) } qemu_notify_event(); - cpu_synchronize_state(s->cpu); - /* Reset all OpenTitan devices connected to RSTMGR parent bus */ - bus_cold_reset(s->parent_obj.parent_obj.parent_bus); - cpu_synchronize_post_reset(s->cpu); - - /* TODO: manage reset tree (depending on power domains, etc.) */ + ibex_irq_raise(&s->soc_reset); } static int ot_rstmgr_sw_rst_walker(DeviceState *dev, void *opaque) @@ -301,6 +285,30 @@ static void ot_rstmgr_update_sw_reset(OtRstMgrState *s, unsigned devix) g_free(desc.path); } +static void ot_rstmgr_reset_req(void *opaque, int irq, int level) +{ + OtRstMgrState *s = opaque; + + if (!level) { + /* reset line released */ + return; + } + + g_assert(irq == 0); + + bool fastclk = ((unsigned)level >> 8u) & 1u; + + level &= 0xff; + g_assert(level < OT_RSTMGR_RESET_COUNT); + + OtRstMgrResetReq req = (OtRstMgrResetReq)level; + s->regs[R_RESET_INFO] = 1u << req; + + trace_ot_rstmgr_reset_req(REQ_NAME(req), req, fastclk); + + qemu_bh_schedule(s->bus_reset_bh); +} + static uint64_t ot_rstmgr_regs_read(void *opaque, hwaddr addr, unsigned size) { OtRstMgrState *s = opaque; @@ -380,7 +388,15 @@ static void ot_rstmgr_regs_write(void *opaque, hwaddr addr, uint64_t val64, * "Upon completion of reset, this bit is automatically cleared by * hardware." */ - ibex_irq_set(&s->sw_reset, (int)true); + ibex_irq_raise(&s->sw_reset); + if (s->fatal_reset) { + s->fatal_reset--; + if (!s->fatal_reset) { + error_report("fatal reset triggered"); + qemu_system_shutdown_request_with_code( + SHUTDOWN_CAUSE_GUEST_SHUTDOWN, 1); + } + } } break; case R_RESET_INFO: @@ -469,6 +485,7 @@ static void ot_rstmgr_regs_write(void *opaque, hwaddr addr, uint64_t val64, static Property ot_rstmgr_properties[] = { DEFINE_PROP_STRING("ot_id", OtRstMgrState, ot_id), + DEFINE_PROP_UINT32("fatal_reset", OtRstMgrState, fatal_reset, 0), /* this property is only used to store initial reset reason state */ DEFINE_PROP_BOOL("por", OtRstMgrState, por, true), DEFINE_PROP_END_OF_LIST(), @@ -522,7 +539,8 @@ static void ot_rstmgr_reset(DeviceState *dev) s->regs[R_SW_RST_CTRL_N_0 + ix] = 0x1u; } - ibex_irq_set(&s->sw_reset, 0); + ibex_irq_lower(&s->soc_reset); + ibex_irq_lower(&s->sw_reset); ot_rstmgr_update_alerts(s); } @@ -536,9 +554,13 @@ static void ot_rstmgr_init(Object *obj) s->regs = g_new0(uint32_t, REGS_COUNT); + ibex_qdev_init_irq(obj, &s->soc_reset, OT_RSTMGR_SOC_RST); ibex_qdev_init_irq(obj, &s->sw_reset, OT_RSTMGR_SW_RST); ibex_qdev_init_irqs(obj, s->alerts, OT_DEVICE_ALERT, PARAM_NUM_ALERTS); + qdev_init_gpio_in_named(DEVICE(obj), &ot_rstmgr_reset_req, + OT_RSTMGR_RST_REQ, 1); + s->bus_reset_bh = qemu_bh_new(&ot_rstmgr_reset_bus, s); } diff --git a/hw/opentitan/ot_spi_device.c b/hw/opentitan/ot_spi_device.c index 61296ebd8b0a..26e1806e2485 100644 --- a/hw/opentitan/ot_spi_device.c +++ b/hw/opentitan/ot_spi_device.c @@ -978,8 +978,8 @@ static void ot_spi_device_update_irqs(OtSPIDeviceState *s) uint32_t levels = s->spi_regs[R_INTR_STATE] & s->spi_regs[R_INTR_ENABLE]; for (unsigned ix = 0; ix < PARAM_NUM_IRQS; ix++) { bool level = (bool)((levels >> ix) & 0x1u); - if (level && !ibex_irq_get_level(&s->irqs[ix])) { - trace_ot_spi_device_set_irq(IRQ_NAME(ix), ix); + if (level != (bool)ibex_irq_get_level(&s->irqs[ix])) { + trace_ot_spi_device_set_irq(IRQ_NAME(ix), ix, level); } ibex_irq_set(&s->irqs[ix], (int)level); } @@ -1162,7 +1162,7 @@ static void ot_spi_device_flash_decode_command(OtSPIDeviceState *s, uint8_t cmd) return; } - bool set_busy = (bool)f->cmd_info & CMD_INFO_BUSY_MASK; + bool set_busy = (bool)(f->cmd_info & CMD_INFO_BUSY_MASK); if (set_busy) { s->spi_regs[R_FLASH_STATUS] |= R_FLASH_STATUS_BUSY_MASK; } @@ -1525,6 +1525,8 @@ static void ot_spi_device_flash_decode_sw_command(OtSPIDeviceState *s) FLASH_CHANGE_STATE(f, UP_DUMMY); } else if (ot_spi_device_flash_has_input_payload(f->cmd_info)) { ot_spi_device_flash_init_payload(s); + } else { + s->spi_regs[R_UPLOAD_STATUS2] = 0; } } diff --git a/hw/opentitan/trace-events b/hw/opentitan/trace-events index 70684e55e069..16cee47fd4e2 100644 --- a/hw/opentitan/trace-events +++ b/hw/opentitan/trace-events @@ -90,15 +90,16 @@ ot_csrng_try_schedule_genbits(unsigned slot, bool ready, bool queued, unsigned r ot_dev_proxy_dispatch_request(char a, char b) "%c%c" ot_dev_proxy_fe_error(int err) "error: %d" ot_dev_proxy_intercept_irq(const char *dname, const char *did, const char *iid, bool enable) "%s (%s) %s: enable %u" -ot_dev_proxy_read_buffer(const char *prefix, unsigned devix, bool mbx, unsigned offset, unsigned count) "%s #%u mbx:%u 0x%02x %u" -ot_dev_proxy_read_memory(const char *prefix, unsigned devix, unsigned offset, unsigned count) "%s #%u 0x%08x 0x%x" -ot_dev_proxy_read_reg(const char *prefix, unsigned devix, unsigned offset) "%s #%u 0x%08x" +ot_dev_proxy_read_buffer(const char *desc, bool mbx, unsigned offset, unsigned count) "%s mbx:%u 0x%02x %u" +ot_dev_proxy_read_memory(const char *desc, unsigned offset, unsigned count) "%s 0x%08x 0x%x" +ot_dev_proxy_read_reg(const char *desc, unsigned offset) "%s 0x%08x" ot_dev_proxy_route_irq(const char *dname, const char *did, unsigned irq, int level) "%s (%s) %u: level %d" ot_dev_proxy_signal_irq(const char *dname, const char *did, unsigned irq, int level) "%s (%s) %u: level %d" ot_dev_proxy_uid_error(const char *msg, unsigned expuid, unsigned realuid) "%s: expected %u, received %u" -ot_dev_proxy_write_buffer(const char *prefix, unsigned devix, bool mbx, unsigned offset, unsigned count) "%s #%u mbx:%u 0x%02x %u" -ot_dev_proxy_write_memory(const char *prefix, unsigned devix, unsigned offset, unsigned count) "%s #%u 0x%08x 0x%x" -ot_dev_proxy_write_reg(const char *prefix, unsigned devix, unsigned offset, unsigned value) "%s #%u 0x%08x 0x%08x" +ot_dev_proxy_unassigned_irq(int irq) "%d non-assigned intercepted IRQ signaled" +ot_dev_proxy_write_buffer(const char *desc, bool mbx, unsigned offset, unsigned count) "%s mbx:%u 0x%02x %u" +ot_dev_proxy_write_memory(const char *desc, unsigned offset, unsigned count) "%s 0x%08x 0x%x" +ot_dev_proxy_write_reg(const char *desc, unsigned offset, unsigned value) "%s 0x%08x 0x%08x" # ot_dm_tl.c @@ -288,22 +289,25 @@ ot_otbn_request_entropy(unsigned ep) "ep:%u" # ot_otp.c -ot_otp_addr_to_part(uint32_t addr, const char *part, unsigned pix) "addr 0x%08x partition %s (#%u)" ot_otp_access_error_on(int part, uint32_t addr, const char *msg) "part #%d, addr 0x%04x: %s" +ot_otp_addr_to_part(uint32_t addr, const char *part, unsigned pix) "addr 0x%08x partition %s (#%u)" ot_otp_dai_change_state(int line, const char *old, int nold, const char *new, int nnew) "@ %d [%s:%d] -> [%s:%d]" ot_otp_dai_read(const char* part, unsigned pix, uint32_t hi, uint32_t lo) "DAI read %s (#%u): 0x%08x%08x" ot_otp_initial_lifecycle(uint32_t lc_state, unsigned tcount) "lifecyle 0x%x, transition count %u" ot_otp_initialize(void) "" -ot_otp_io_read_out(uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "addr=0x%02x (%s), val=0x%x, pc=0x%x" -ot_otp_io_write(uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "addr=0x%02x (%s), val=0x%x, pc=0x%x" ot_otp_integrity_report(const char* part, unsigned pix, const char *msg) "partition %s (#%u) %s" +ot_otp_io_csr_read_out(uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "addr=0x%02x (%s), val=0x%x, pc=0x%x" +ot_otp_io_csr_write(uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "addr=0x%02x (%s), val=0x%x, pc=0x%x" +ot_otp_io_reg_read_out(uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "addr=0x%02x (%s), val=0x%x, pc=0x%x" +ot_otp_io_reg_write(uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "addr=0x%02x (%s), val=0x%x, pc=0x%x" +ot_otp_io_swcfg_read_out(uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "addr=0x%02x (%s), val=0x%x, pc=0x%x" ot_otp_keygen_entropy(unsigned slot, bool resched) "%u slots, resched: %u" ot_otp_lc_broadcast(unsigned sig, bool level) "bcast %u, level %u" -ot_otp_load_token(const char *token, unsigned tkx, uint64_t hi, uint64_t lo, const char *valid) "%s (%u) 0x%016" PRIx64 "%016" PRIx64 ": %svalid" ot_otp_lci_change_state(int line, const char *old, int nold, const char *new, int nnew) "@ %d [%s:%d] -> [%s:%d]" ot_otp_lci_write(unsigned pos, uint16_t cval, uint16_t nval) "@ %u 0x%04x -> 0x%04x" ot_otp_load_backend(unsigned ver, const char *mode) "loading OTP image v%u in %s mode" -ot_otp_mismatch_digest(const char* part, unsigned pix, uint64_t sdig, uint64_t ldig) "Mismatch digest on %s (#%u), stored 0x%" PRIx64 " found 0x%" PRIx64 +ot_otp_load_token(const char *token, unsigned tkx, uint64_t hi, uint64_t lo, const char *valid) "%s (%u) 0x%016" PRIx64 "%016" PRIx64 ": %svalid" +ot_otp_mismatch_digest(const char* part, unsigned pix, uint64_t sdig, uint64_t ldig) "Mismatch digest on %s (#%u), computed 0x%" PRIx64 " stored 0x%" PRIx64 ot_otp_pwr_otp_req(const char *where) "%s" ot_otp_reset(void) "" ot_otp_set_error(unsigned pix, const char* err, unsigned eix) "#%u: %s (%u)" @@ -395,7 +399,7 @@ ot_spi_device_gen_rx_timeout(unsigned count) "%d" ot_spi_device_gen_update_fifo(const char *fifo, int line, uint32_t val) "%s@%d: 0x%08x" ot_spi_device_io_spi_read_out(uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "addr=0x%02x (%s), val=0x%x, pc=0x%x" ot_spi_device_io_spi_write_in(uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "addr=0x%02x (%s), val=0x%x, pc=0x%x" -ot_spi_device_set_irq(const char *name, unsigned irq) "%s [%u]" +ot_spi_device_set_irq(const char *name, unsigned irq, bool level) "%s [%u]: %u" ot_spi_device_io_tpm_read_out(uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "addr=0x%02x (%s), val=0x%x, pc=0x%x" ot_spi_device_io_tpm_write_in(uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "addr=0x%02x (%s), val=0x%x, pc=0x%x" ot_spi_device_update_last_read_addr(uint32_t addr) "0x%08x" diff --git a/hw/riscv/ibex_common.c b/hw/riscv/ibex_common.c index b9bec6408822..2dcbe8d0c0cd 100644 --- a/hw/riscv/ibex_common.c +++ b/hw/riscv/ibex_common.c @@ -231,9 +231,9 @@ void ibex_realize_devices(DeviceState **devices, BusState *bus, } } -void ibex_map_devices_mask(DeviceState **devices, MemoryRegion **mrs, - const IbexDeviceDef *defs, unsigned count, - uint32_t region_mask) +void ibex_map_devices_mask_offset(DeviceState **devices, MemoryRegion **mrs, + const IbexDeviceDef *defs, unsigned count, + uint32_t region_mask, uint32_t offset) { for (unsigned idx = 0; idx < count; idx++) { DeviceState *dev = devices[idx]; @@ -256,7 +256,8 @@ void ibex_map_devices_mask(DeviceState **devices, MemoryRegion **mrs, if (mr) { ibex_mmio_map_device(busdev, mr, mem, IBEX_MEMMAP_GET_ADDRESS( - memmap->base), + memmap->base) + + offset, memmap->priority); } } @@ -268,9 +269,9 @@ void ibex_map_devices_mask(DeviceState **devices, MemoryRegion **mrs, } } -void ibex_map_devices_ext_mask(DeviceState *dev, MemoryRegion **mrs, - const IbexDeviceMapDef *defs, unsigned count, - uint32_t region_mask) +void ibex_map_devices_ext_mask_offset( + DeviceState *dev, MemoryRegion **mrs, const IbexDeviceMapDef *defs, + unsigned count, uint32_t region_mask, uint32_t offset) { for (unsigned ix = 0; ix < count; ix++) { const IbexDeviceMapDef *def = &defs[ix]; @@ -294,7 +295,8 @@ void ibex_map_devices_ext_mask(DeviceState *dev, MemoryRegion **mrs, if (mr) { ibex_mmio_map_device(sdev, mr, mem, IBEX_MEMMAP_GET_ADDRESS( - memmap->base), + memmap->base) + + offset, memmap->priority); } } @@ -710,6 +712,13 @@ uint32_t ibex_get_current_pc(void) return cs && cs->cc->get_pc ? (uint32_t)cs->cc->get_pc(cs) : 0u; } +int ibex_get_current_cpu(void) +{ + CPUState *cs = current_cpu; + + return cs ? cs->cpu_index : -1; +} + /* x0 is replaced with PC */ static const char ibex_ireg_names[32u][4u] = { "pc", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", diff --git a/hw/riscv/ot_darjeeling.c b/hw/riscv/ot_darjeeling.c index ccb8b95afaa6..7b4ad1fc099e 100644 --- a/hw/riscv/ot_darjeeling.c +++ b/hw/riscv/ot_darjeeling.c @@ -77,6 +77,7 @@ #include "hw/riscv/ot_darjeeling.h" #include "hw/ssi/ssi.h" #include "sysemu/blockdev.h" +#include "sysemu/hw_accel.h" #include "sysemu/reset.h" #include "sysemu/sysemu.h" @@ -92,6 +93,8 @@ static void ot_dj_soc_otp_ctrl_configure( DeviceState *dev, const IbexDeviceDef *def, DeviceState *parent); static void ot_dj_soc_tap_ctrl_configure( DeviceState *dev, const IbexDeviceDef *def, DeviceState *parent); +static void ot_dj_soc_spi_device_configure( + DeviceState *dev, const IbexDeviceDef *def, DeviceState *parent); static void ot_dj_soc_uart_configure(DeviceState *dev, const IbexDeviceDef *def, DeviceState *parent); @@ -339,6 +342,8 @@ static const uint32_t ot_dj_pmp_addrs[] = { #define OT_DJ_MSECCFG IBEX_MSECCFG(1, 1, 0) +#define OT_DJ_SOC_RST_REQ TYPE_RISCV_OT_DJ_SOC "-reset" + #define OT_DJ_SOC_GPIO(_irq_, _target_, _num_) \ IBEX_GPIO(_irq_, OT_DJ_SOC_DEV_##_target_, _num_) @@ -1195,6 +1200,7 @@ static const IbexDeviceDef ot_dj_soc_devices[] = { }, [OT_DJ_SOC_DEV_SPI_DEVICE] = { .type = TYPE_OT_SPI_DEVICE, + .cfg = &ot_dj_soc_spi_device_configure, .memmap = MEMMAPENTRIES( { .base = 0x30310000u } ), @@ -1227,10 +1233,9 @@ static const IbexDeviceDef ot_dj_soc_devices[] = { OT_DJ_SOC_SIGNAL(OT_PWRMGR_CPU_EN, 0, IBEX_WRAPPER, OT_IBEX_WRAPPER_CPU_EN, OT_IBEX_PWRMGR_CPU_EN), OT_DJ_SOC_SIGNAL(OT_PWRMGR_STRAP, 0, GPIO, - OT_GPIO_STRAP_EN, 0) - ), - .link = IBEXDEVICELINKDEFS( - OT_DJ_SOC_DEVLINK("rstmgr", RSTMGR) + OT_GPIO_STRAP_EN, 0), + OT_DJ_SOC_SIGNAL(OT_PWRMGR_RST_REQ, 0, RSTMGR, + OT_RSTMGR_RST_REQ, 0) ), .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_UINT_PROP("num-rom", 2u), @@ -1470,6 +1475,20 @@ static void ot_dj_soc_tap_ctrl_configure( } } +static void ot_dj_soc_spi_device_configure( + DeviceState *dev, const IbexDeviceDef *def, DeviceState *parent) +{ + (void)parent; + (void)def; + + Chardev *chr; + + chr = ibex_get_chardev_by_id("spidev"); + if (chr) { + qdev_prop_set_chr(dev, "chardev", chr); + } +} + static void ot_dj_soc_uart_configure(DeviceState *dev, const IbexDeviceDef *def, DeviceState *parent) { @@ -1482,6 +1501,20 @@ static void ot_dj_soc_uart_configure(DeviceState *dev, const IbexDeviceDef *def, /* SoC */ /* ------------------------------------------------------------------------ */ +static void ot_dj_soc_hw_reset(void *opaque, int irq, int level) +{ + OtDjSoCState *s = opaque; + + g_assert(irq == 0); + + if (level) { + CPUState *cs = CPU(s->devices[OT_DJ_SOC_DEV_HART]); + cpu_synchronize_state(cs); + bus_cold_reset(sysbus_get_default()); + cpu_synchronize_post_reset(cs); + } +} + static void ot_dj_soc_reset_hold(Object *obj) { OtDjSoCClass *c = RISCV_OT_DJ_SOC_GET_CLASS(obj); @@ -1625,6 +1658,11 @@ static void ot_dj_soc_realize(DeviceState *dev, Error **errp) object_property_add_child(OBJECT(dev), "ctn-dma", oas); ot_address_space_set(OT_ADDRESS_SPACE(oas), ctn_dma_as); + qdev_connect_gpio_out_named(DEVICE(s->devices[OT_DJ_SOC_DEV_RSTMGR]), + OT_RSTMGR_SOC_RST, 0, + qdev_get_gpio_in_named(DEVICE(s), + OT_DJ_SOC_RST_REQ, 0)); + /* load kernel if provided */ ibex_load_kernel(cpu); } @@ -1635,6 +1673,9 @@ static void ot_dj_soc_init(Object *obj) s->devices = ibex_create_devices(ot_dj_soc_devices, ARRAY_SIZE(ot_dj_soc_devices), DEVICE(s)); + + qdev_init_gpio_in_named(DEVICE(obj), &ot_dj_soc_hw_reset, OT_DJ_SOC_RST_REQ, + 1); } static void ot_dj_soc_class_init(ObjectClass *oc, void *data) diff --git a/hw/riscv/ot_earlgrey.c b/hw/riscv/ot_earlgrey.c index 6e97a795c59e..fb1a7882f5ff 100644 --- a/hw/riscv/ot_earlgrey.c +++ b/hw/riscv/ot_earlgrey.c @@ -68,6 +68,7 @@ #include "hw/riscv/ot_earlgrey.h" #include "hw/ssi/ssi.h" #include "sysemu/blockdev.h" +#include "sysemu/hw_accel.h" #include "sysemu/sysemu.h" /* ------------------------------------------------------------------------ */ @@ -84,6 +85,8 @@ static void ot_eg_soc_otp_ctrl_configure( DeviceState *dev, const IbexDeviceDef *def, DeviceState *parent); static void ot_eg_soc_tap_ctrl_configure( DeviceState *dev, const IbexDeviceDef *def, DeviceState *parent); +static void ot_eg_soc_spi_device_configure( + DeviceState *dev, const IbexDeviceDef *def, DeviceState *parent); static void ot_eg_soc_uart_configure(DeviceState *dev, const IbexDeviceDef *def, DeviceState *parent); @@ -200,6 +203,8 @@ static const uint32_t ot_eg_pmp_addrs[] = { #define OT_EG_MSECCFG IBEX_MSECCFG(1, 1, 0) +#define OT_EG_SOC_RST_REQ TYPE_RISCV_OT_EG_SOC "-reset" + #define OT_EG_SOC_GPIO(_irq_, _target_, _num_) \ IBEX_GPIO(_irq_, OT_EG_SOC_DEV_##_target_, _num_) @@ -444,6 +449,7 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { }, [OT_EG_SOC_DEV_SPI_DEVICE] = { .type = TYPE_OT_SPI_DEVICE, + .cfg = &ot_eg_soc_spi_device_configure, .memmap = MEMMAPENTRIES( { .base = 0x40050000u } ), @@ -636,19 +642,18 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_GPIO_SYSBUS_IRQ(0, PLIC, 152), /* loopback signal since Earlgrey OTP signal are not supported yet*/ OT_EG_SOC_SIGNAL(OT_PWRMGR_OTP_REQ, 0, PWRMGR, - OT_PWRMGR_OTP_RSP, 0), + OT_PWRMGR_OTP_RSP, 0), OT_EG_SOC_REQ(OT_PWRMGR_LC, LC_CTRL), OT_EG_SOC_SIGNAL(OT_PWRMGR_CPU_EN, 0, IBEX_WRAPPER, - OT_IBEX_WRAPPER_CPU_EN, - OT_IBEX_PWRMGR_CPU_EN) + OT_IBEX_WRAPPER_CPU_EN, + OT_IBEX_PWRMGR_CPU_EN), + OT_EG_SOC_SIGNAL(OT_PWRMGR_RST_REQ, 0, RSTMGR, + OT_RSTMGR_RST_REQ, 0) ), .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_UINT_PROP("num-rom", 1u), IBEX_DEV_UINT_PROP("version", OT_PWMGR_VERSION_EG) ), - .link = IBEXDEVICELINKDEFS( - OT_EG_SOC_DEVLINK("rstmgr", RSTMGR) - ), }, [OT_EG_SOC_DEV_RSTMGR] = { .type = TYPE_OT_RSTMGR, @@ -1120,6 +1125,20 @@ static void ot_eg_soc_tap_ctrl_configure( } } +static void ot_eg_soc_spi_device_configure( + DeviceState *dev, const IbexDeviceDef *def, DeviceState *parent) +{ + (void)parent; + (void)def; + + Chardev *chr; + + chr = ibex_get_chardev_by_id("spidev"); + if (chr) { + qdev_prop_set_chr(dev, "chardev", chr); + } +} + static void ot_eg_soc_uart_configure(DeviceState *dev, const IbexDeviceDef *def, DeviceState *parent) { @@ -1132,6 +1151,20 @@ static void ot_eg_soc_uart_configure(DeviceState *dev, const IbexDeviceDef *def, /* SoC */ /* ------------------------------------------------------------------------ */ +static void ot_eg_soc_hw_reset(void *opaque, int irq, int level) +{ + OtEGSoCState *s = opaque; + + g_assert(irq == 0); + + if (level) { + CPUState *cs = CPU(s->devices[OT_EG_SOC_DEV_HART]); + cpu_synchronize_state(cs); + bus_cold_reset(sysbus_get_default()); + cpu_synchronize_post_reset(cs); + } +} + static void ot_eg_soc_reset_hold(Object *obj) { OtEGSoCClass *c = RISCV_OT_EG_SOC_GET_CLASS(obj); @@ -1192,6 +1225,11 @@ static void ot_eg_soc_realize(DeviceState *dev, Error **errp) ibex_map_devices(s->devices, mrs, ot_eg_soc_devices, ARRAY_SIZE(ot_eg_soc_devices)); + qdev_connect_gpio_out_named(DEVICE(s->devices[OT_EG_SOC_DEV_RSTMGR]), + OT_RSTMGR_SOC_RST, 0, + qdev_get_gpio_in_named(DEVICE(s), + OT_EG_SOC_RST_REQ, 0)); + /* load kernel if provided */ ibex_load_kernel(NULL); } @@ -1202,6 +1240,9 @@ static void ot_eg_soc_init(Object *obj) s->devices = ibex_create_devices(ot_eg_soc_devices, ARRAY_SIZE(ot_eg_soc_devices), DEVICE(s)); + + qdev_init_gpio_in_named(DEVICE(obj), &ot_eg_soc_hw_reset, OT_EG_SOC_RST_REQ, + 1); } static void ot_eg_soc_class_init(ObjectClass *oc, void *data) diff --git a/include/exec/memory.h b/include/exec/memory.h index 8626a355b310..8dbe866c09ae 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -2578,6 +2578,9 @@ void memory_global_dirty_log_start(unsigned int flags); void memory_global_dirty_log_stop(unsigned int flags); void mtree_info(bool flatview, bool dispatch_tree, bool owner, bool disabled); +void mtree_print_as_flatview(AddressSpace *as, bool dispatch_tree, bool owner); +void mtree_print_as_simple(AddressSpace *as, bool dispatch_tree, bool owner, + bool disabled); bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr, unsigned size, bool is_write, diff --git a/include/hw/opentitan/ot_pwrmgr.h b/include/hw/opentitan/ot_pwrmgr.h index fe5d5c6295c9..98f6d2eeff7d 100644 --- a/include/hw/opentitan/ot_pwrmgr.h +++ b/include/hw/opentitan/ot_pwrmgr.h @@ -57,6 +57,7 @@ typedef enum { #define OT_PWRMGR_OTP_REQ TYPE_OT_PWRMGR "-otp-req" #define OT_PWRMGR_CPU_EN TYPE_OT_PWRMGR "-cpu-en" #define OT_PWRMGR_STRAP TYPE_OT_PWRMGR "-strap" +#define OT_PWRMGR_RST_REQ TYPE_OT_PWRMGR "-reset-req" /* input lines */ #define OT_PWRMGR_LC_RSP TYPE_OT_PWRMGR "-lc-rsp" diff --git a/include/hw/opentitan/ot_rstmgr.h b/include/hw/opentitan/ot_rstmgr.h index 5ad44524bf82..546202d970bb 100644 --- a/include/hw/opentitan/ot_rstmgr.h +++ b/include/hw/opentitan/ot_rstmgr.h @@ -33,8 +33,6 @@ #define TYPE_OT_RSTMGR "ot-rstmgr" OBJECT_DECLARE_SIMPLE_TYPE(OtRstMgrState, OT_RSTMGR) -#define OT_RSTMGR_SW_RST TYPE_OT_RSTMGR "-sw-rst" - typedef enum { OT_RSTMGR_RESET_POR, OT_RSTMGR_RESET_LOW_POWER, @@ -49,12 +47,14 @@ typedef enum { OT_RSTMGR_RESET_COUNT, } OtRstMgrResetReq; -/* - * Request a system reset - * - * @fastclk true for fast clock domain, @c false for aon/slow clock - * @req type of reset request - */ -void ot_rstmgr_reset_req(OtRstMgrState *s, bool fastclk, OtRstMgrResetReq req); +#define OT_RSTMGR_RESET_REQUEST(_fast_, _req_) \ + ((int)((1u << 31u) | (((int)(bool)_fast_) << 8u) | _req_)) + +/* output lines */ +#define OT_RSTMGR_SOC_RST TYPE_OT_RSTMGR "-soc-reset" +#define OT_RSTMGR_SW_RST TYPE_OT_RSTMGR "-sw-reset" + +/* input lines */ +#define OT_RSTMGR_RST_REQ TYPE_OT_RSTMGR "-reset-req" #endif /* HW_OPENTITAN_OT_RSTMGR_H */ diff --git a/include/hw/riscv/ibex_common.h b/include/hw/riscv/ibex_common.h index b3c87178ea3b..d1b3b9b4f445 100644 --- a/include/hw/riscv/ibex_common.h +++ b/include/hw/riscv/ibex_common.h @@ -155,11 +155,20 @@ typedef struct { }; } IbexDevicePropDef; +typedef enum { + IBEX_MEM_MAP_ENTRY_FLAG_LAST, + IBEX_MEM_MAP_ENTRY_FLAG_SKIP, + IBEX_MEM_MAP_ENTRY_FLAG_COUNT +} IbexMemMapEntryFlags; + typedef struct IbexMemMapEntry { hwaddr base; int8_t priority; + uint8_t flags; /* bitfield of IbexMemMapEntryFlags */ } IbexMemMapEntry; +#define IBEX_MEM_MAP_ENTRY_FLAG(_f_) (1u << (IBEX_MEM_MAP_ENTRY_FLAG_##_f_)) + /* Device definition */ struct IbexDeviceDef { /** Registered type of the device */ @@ -231,10 +240,12 @@ typedef struct { (((_par_) << IBEX_DEVLINK_RMT_SHIFT) | ((_ix_) & IBEX_DEVLINK_IDX_MASK)) /* MemMapEntry that should be ignored (i.e. skipped, not mapped) */ -#define IBEX_MEMMAP_LAST ((hwaddr)0ull) -#define IBEX_MEMMAP_SKIP { .base = HWADDR_MAX } -#define IBEX_MEMMAP_IS_LAST(_mmap_) ((_mmap_)->base == IBEX_MEMMAP_LAST) -#define IBEX_MEMMAP_IGNORE(_mmap_) ((_mmap_)->base == HWADDR_MAX) +#define IBEX_MEMMAP_LAST { .flags = IBEX_MEM_MAP_ENTRY_FLAG(LAST) } +#define IBEX_MEMMAP_SKIP { .flags = IBEX_MEM_MAP_ENTRY_FLAG(SKIP) } +#define IBEX_MEMMAP_IS_LAST(_mmap_) \ + ((bool)((_mmap_)->flags & IBEX_MEM_MAP_ENTRY_FLAG(LAST))) +#define IBEX_MEMMAP_IGNORE(_mmap_) \ + ((bool)((_mmap_)->flags & IBEX_MEM_MAP_ENTRY_FLAG(SKIP))) /** * Create memory map entries, each arg is MemMapEntry definition @@ -242,10 +253,7 @@ typedef struct { #define MEMMAPENTRIES(...) \ (const IbexMemMapEntry[]) \ { \ - __VA_ARGS__, \ - { \ - .base = IBEX_MEMMAP_LAST \ - } \ + __VA_ARGS__, IBEX_MEMMAP_LAST \ } /** @@ -424,14 +432,20 @@ void ibex_realize_devices(DeviceState **devices, BusState *bus, void ibex_connect_devices(DeviceState **devices, const IbexDeviceDef *defs, unsigned count); #define ibex_map_devices(_devs_, _mrs_, _defs_, _cnt_) \ - ibex_map_devices_mask(_devs_, _mrs_, _defs_, _cnt_, \ - IBEX_MEMMAP_DEFAULT_REG_MASK); -void ibex_map_devices_mask(DeviceState **devices, MemoryRegion **mrs, - const IbexDeviceDef *defs, unsigned count, - uint32_t region_mask); -void ibex_map_devices_ext_mask(DeviceState *dev, MemoryRegion **mrs, - const IbexDeviceMapDef *defs, unsigned count, - uint32_t region_mask); + ibex_map_devices_offset(_devs_, _mrs_, _defs_, _cnt_, 0u) +#define ibex_map_devices_offset(_devs_, _mrs_, _defs_, _cnt_, _off_) \ + ibex_map_devices_mask_offset(_devs_, _mrs_, _defs_, _cnt_, \ + IBEX_MEMMAP_DEFAULT_REG_MASK, _off_) +#define ibex_map_devices_mask(_devs_, _mrs_, _defs_, _cnt_, _msk_) \ + ibex_map_devices_mask_offset(_devs_, _mrs_, _defs_, _cnt_, _msk_, 0u) +void ibex_map_devices_mask_offset(DeviceState **devices, MemoryRegion **mrs, + const IbexDeviceDef *defs, unsigned count, + uint32_t region_mask, uint32_t offset); +#define ibex_map_devices_ext_mask(_dev_, _mrs_, _defs_, _cnt_, _msk_) \ + ibex_map_devices_ext_mask_offset(_dev_, _mrs_, _defs_, _cnt_, _msk_, 0u) +void ibex_map_devices_ext_mask_offset( + DeviceState *dev, MemoryRegion **mrs, const IbexDeviceMapDef *defs, + unsigned count, uint32_t region_mask, uint32_t offset); void ibex_configure_devices(DeviceState **devices, BusState *bus, const IbexDeviceDef *defs, unsigned count); void ibex_identify_devices(DeviceState **devices, const char *id_prop, @@ -480,6 +494,14 @@ uint32_t ibex_load_kernel(CPUState *cpu); */ uint32_t ibex_get_current_pc(void); +/** + * Helper for device debugging: report the current guest CPU index, if any. + * + * If a HW access is performed from another device but the CPU, reported CPU + * is -1. + */ +int ibex_get_current_cpu(void); + enum { RV_GPR_PC = (1u << 0u), RV_GPR_RA = (1u << 1u), diff --git a/scripts/opentitan/dtm.py b/scripts/opentitan/dtm.py index 8ee99aabdc6a..8e4950b77a79 100755 --- a/scripts/opentitan/dtm.py +++ b/scripts/opentitan/dtm.py @@ -65,8 +65,8 @@ def main(): default=JtagBitbangController.DEFAULT_PORT, help=f'JTAG port, ' f'default: {JtagBitbangController.DEFAULT_PORT}') - qvm.add_argument('-Q', '--no-quit', action='store_true', default=False, - help='do not ask the QEMU to quit on exit') + qvm.add_argument('-t', '--terminate', action='store_true', + help='terminate QEMU when done') dmi = argparser.add_argument_group(title='DMI') dmi.add_argument('-l', '--ir-length', type=int, default=DEFAULT_IR_LENGTH, @@ -114,7 +114,11 @@ def main(): configure_loggers(args.verbose, 'dtm.rvdm', -1, 'dtm', 'jtag') - sock = create_connection((args.host, args.port), timeout=0.5) + try: + sock = create_connection((args.host, args.port), timeout=0.5) + except OSError as exc: + raise RuntimeError(f'Cannot connect to {args.host}:{args.port}: ' + f'{exc}') from exc sock.settimeout(0.1) ctrl = JtagBitbangController(sock) eng = JtagEngine(ctrl) @@ -172,21 +176,16 @@ def main(): if not rvdm: rvdm = DebugModule(dtm, args.base) rvdm.initialize() - try: - rvdm.halt() - if args.file: - mode = 'rb' if args.mem == 'write' else 'wb' - with open(args.file, mode) as mfp: - rvdm.memory_copy(mfp, args.mem, args.address, - args.size, no_check=args.fast_mode) - else: - mfp = BytesIO() - rvdm.memory_copy(mfp, args.mem, args.address, args.size, - no_check=args.fast_mode) - dump_buffer(mfp, args.address) - finally: - if not args.no_exec: - rvdm.resume() + if args.file: + mode = 'rb' if args.mem == 'write' else 'wb' + with open(args.file, mode) as mfp: + rvdm.memory_copy(mfp, args.mem, args.address, + args.size, no_check=args.fast_mode) + else: + mfp = BytesIO() + rvdm.memory_copy(mfp, args.mem, args.address, args.size, + no_check=args.fast_mode) + dump_buffer(mfp, args.address) if args.elf: if not ElfBlob.LOADED: argparser.error('pyelftools module not available') @@ -212,7 +211,7 @@ def main(): if args.execute: argparser.error('Cannot execute without loaded an ELF file') finally: - if not args.no_quit: + if args.terminate: ctrl.quit() # pylint: disable=broad-except diff --git a/scripts/opentitan/ot/dm/dm.py b/scripts/opentitan/ot/dm/dm.py index 910b85cf8ea4..6483d906fa7c 100644 --- a/scripts/opentitan/ot/dm/dm.py +++ b/scripts/opentitan/ot/dm/dm.py @@ -378,7 +378,10 @@ def memory_copy(self, mfp: BinaryIO, mop: str, addr: int, self._wait_sb_idle(check=True) lap = now() - start rate = size / (lap * 1024) - self._log.info('copied %d KB @ %.1f KB/s', size//1024, rate) + if size > 1024: + self._log.info('copied %d KB @ %.1f KB/s', size//1024, rate) + else: + self._log.info('copied %d bytes @ %.1f KB/s', size, rate) def read32(self, addr: int) -> int: """Read a single word from memory.""" diff --git a/scripts/opentitan/ot/otp/partition.py b/scripts/opentitan/ot/otp/partition.py index 54cb6f30fba1..37408d53b2a2 100644 --- a/scripts/opentitan/ot/otp/partition.py +++ b/scripts/opentitan/ot/otp/partition.py @@ -164,11 +164,15 @@ def emit(fmt, *args): if itdef.get('ismubi'): emit('%-46s (decoded) %s', name, str(OtpMap.MUBI8_BOOLEANS.get(ival, ival))) - elif itsize == 4 and ival in OtpMap.HARDENED_BOOLEANS: + continue + if itsize == 4 and ival in OtpMap.HARDENED_BOOLEANS: emit('%-46s (decoded) %s', name, str(OtpMap.HARDENED_BOOLEANS[ival])) - else: - emit('%-46s %x', name, ival) + continue + emit('%-46s %x', name, ival) + if self._digest_bytes is not None: + emit('%-46s %s', f'{pname}:DIGEST', + hexlify(self._digest_bytes).decode()) class OtpLifecycleExtension(OtpPartitionDecoder): diff --git a/scripts/opentitan/ot/spi/__init__.py b/scripts/opentitan/ot/spi/__init__.py new file mode 100644 index 000000000000..ea3258d4ff96 --- /dev/null +++ b/scripts/opentitan/ot/spi/__init__.py @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Rivos, Inc. +# SPDX-License-Identifier: Apache2 + +"""SPI device tools.""" + +from .spi_device import SpiDevice # noqa: F401 diff --git a/scripts/opentitan/ot/spi/spi_device.py b/scripts/opentitan/ot/spi/spi_device.py new file mode 100644 index 000000000000..48ca9b6fb71a --- /dev/null +++ b/scripts/opentitan/ot/spi/spi_device.py @@ -0,0 +1,342 @@ +# Copyright (c) 2023-2024, Rivos, Inc. +# All rights reserved. + +"""SPI device proxy. + + :author: Emmanuel Blot +""" + +from binascii import hexlify +from logging import getLogger +from select import POLLIN, poll as spoll +from socket import (create_connection, socket, IPPROTO_TCP, TCP_NODELAY, + SHUT_RDWR, timeout as LegacyTimeoutError) +from struct import calcsize as scalc, pack as spack +from time import sleep, time as now +from typing import Optional + + +class SpiDevice: + """SPI device proxy that implements the SPI device protocol over TCP.""" + + TIMEOUT = 2.0 + """Default allowed timeout to complete an exchange with the remote target. + """ + + POLL_TIMEOUT = 0.05 + """Maximum time to wait on a blocking operation. + """ + + VERSION = 0 + """Protocol version.""" + + CS_HEADER_FMT = '3sBBxH' + """CS header format.""" + + CS_HEADER_SIZE = scalc(CS_HEADER_FMT) + """Size of a CS header.""" + + BUSY = 1 << 0 + """Status register BUSY bit.""" + + WEL = 1 << 1 + """Status register write enabled bit.""" + + READ_BUFFER_SIZE = 0x400 + """1 KiB HW buffer.""" + + MAILBOX_SIZE = 0x400 + """1 KiB mailbox.""" + + COMMANDS = { + 'PAGE_PROGRAM': 0x02, + 'READ_DATA': 0x3, + 'WRITE_DISABLE': 0x04, + 'READ_STATUS': 0x05, + 'WRITE_ENABLE': 0x06, + 'FAST_READ': 0x0b, + 'READ_SFDP': 0x5a, + 'READ_JEDEC_ID': 0x9f, + 'ENTER_ADDR4': 0xb7, + 'POWER_DOWN': 0xb9, + 'EXIT_ADDR4': 0xe9, + 'CHIP_ERASE': 0xc7, + 'BLOCK_ERASE': 0xd8, + 'SECTOR_ERASE': 0x20, + 'RESET1': 0x66, + 'RESET2': 0x99, + } + """Supported *25 SPI data flash device commands.""" + + def __init__(self): + self._log = getLogger('spidev') + self._socket: Optional[socket] = None + self._mode = 0 + self._4ben = False + self._rev_rx = False + self._rev_tx = False + + def connect(self, host: str, port: int) -> None: + """Open a TCP connection to the remote host. + + @param host the host name + @paran port the TCP port + """ + if self._socket: + raise RuntimeError('Cannot open multiple comm port at once') + try: + self._socket = create_connection((host, port), timeout=self.TIMEOUT) + except OSError: + self._log.fatal('Cannot connect to %s:%d', host, port) + raise + # use poll + self._socket.settimeout(None) + self._socket.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1) + + def quit(self) -> None: + """Close the communication socket.""" + if self._socket: + self._socket.shutdown(SHUT_RDWR) + self._socket.close() + self._socket = None + + def transmit(self, cmd: Optional[int] = None, + in_payload: Optional[bytes | bytearray | int] = None, + out_len: int = 0, release: bool = True) -> bytes: + """SPI data transfer. + + :param cmd: the command to send + :param in_payload: the payload to send + :param out_len: the count of meaningful bytes to receive + :param release: whether to release /CS line (to manage transactions) + """ + if isinstance(in_payload, int): + in_payload = bytes([0xff] * in_payload) + elif in_payload is not None: + assert isinstance(in_payload, (bytes, bytearray)) + else: + in_payload = bytes() + assert isinstance(out_len, int) and 0 <= out_len <= 0xffff + if cmd is not None: + assert 0 <= cmd <= 0xff + tx_payload = b''.join((bytes([cmd]), in_payload, bytes(out_len))) + else: + tx_payload = b''.join((in_payload, bytes(out_len))) + if self._rev_tx: + tx_payload = bytes(SpiDevice.rev8(x) for x in tx_payload) + rx_payload = self._exchange(tx_payload, release) + if self._rev_rx: + rx_payload = bytes(SpiDevice.rev8(x) for x in rx_payload) + assert len(rx_payload) == len(tx_payload) + return rx_payload[-out_len:] + + def read_status_register(self) -> int: + """Read out the flash status register.""" + resp = self.transmit(self.COMMANDS['READ_STATUS'], out_len=1) + return resp[0] + + def is_busy(self, sreg: Optional[int] = None) -> bool: + """Check if the flash device is busy.""" + if sreg is None: + sreg = self.read_status_register() + return bool(sreg & self.BUSY) + + def is_wel(self, sreg: Optional[int] = None) -> bool: + """Check if the flash device is write-enabled.""" + if sreg is None: + sreg = self.read_status_register() + return bool(sreg & self.WEL) + + def wait_idle(self, timeout: float = 1.0, pace: float = 0.0005): + """Wait for the flash device to become idle. + + :param timeout: raise a TimeoutError if flash does not become + available after this delay + :param pace: delay between each flash device poll request. + """ + timeout += now() + while True: + status = self.read_status_register() + if not status & self.BUSY: + break + if now() > timeout: + raise TimeoutError('Flash stuck to busy') + sleep(pace) + + def read_jedec_id(self) -> bytes: + """Read out the flash device JEDEC ID.""" + jedec = bytearray() + self.transmit(self.COMMANDS['READ_JEDEC_ID'], release=False) + while True: + manuf = self.transmit(out_len=1, release=False)[0] + if manuf != 0x7f: + jedec.append(manuf) + break + jedec.extend(self.transmit(out_len=2)) + return jedec + + def read_sfdp(self, address: int = 0) -> bytes: + """Read out the flash device SFTP descriptor.""" + payload = spack('>I', address) + return self.transmit(self.COMMANDS['READ_SFDP'], payload, 256) + + def enable_write(self): + """Enable write.""" + self.transmit(self.COMMANDS['WRITE_ENABLE']) + + def disable_write(self): + """Disable write.""" + self.transmit(self.COMMANDS['WRITE_DISABLE']) + + def enable_4b_address(self, enable: bool): + """Enable or disable 4-byte addressing mode.""" + self.transmit(self.COMMANDS['ENTER_ADDR4' if enable else 'EXIT_ADDR4']) + self._4ben = enable + + def page_program(self, address: int, buffer: bytes): + """Program a page (usually 256 bytes) into the flash device. + + :param address: address of the first byte to program + :param buffer: the page content + """ + addr = spack('>I', address) + if not self.is_4b_addr: + if address >= (1 << 24): + raise ValueError('Cannot encode address') + addr = addr[1:] + self.transmit(self.COMMANDS['PAGE_PROGRAM'], b''.join((addr, buffer))) + + def power_down(self): + """Power down the device (may trigger a QEMU shurtdown).""" + self.transmit(self.COMMANDS['POWER_DOWN']) + + def chip_erase(self): + """Erase the content of the whole chip.""" + self.transmit(self.COMMANDS['CHIP_ERASE']) + + def block_erase(self, address: int): + """Erase a 64 KiB block.""" + address &= ~(64 << 10) + addr = spack('>I', address) + if not self.is_4b_addr: + if address >= (1 << 24): + raise ValueError('Cannot encode address') + addr = addr[1:] + self.transmit(self.COMMANDS['BLOCK_ERASE'], addr) + + def sector_erase(self, address: int): + """Erase a 4 KiB block.""" + address &= ~(4 << 10) + addr = spack('>I', address) + if not self.is_4b_addr: + if address >= (1 << 24): + raise ValueError('Cannot encode address') + addr = addr[1:] + self.transmit(self.COMMANDS['SECTOR_ERASE'], addr) + + def reset(self): + """Reset the flash device.""" + # self.transmit(self.COMMANDS['RESET1']) + self.transmit(self.COMMANDS['RESET2']) + + def read(self, address: int, length: int, fast: bool = False) -> bytes: + """Read out from the flash device. + + :param address: the address of the first byte to read + :param length: how many bytes to read + :param fast: whether to use the fast SPI read command + """ + if fast: + cmd = self.COMMANDS['FAST_READ'] + dummy = True + else: + cmd = self.COMMANDS['READ_DATA'] + dummy = False + addr = spack('>I', address) + if not self.is_4b_addr: + if address >= (1 << 24): + raise ValueError('Cannot encode address') + addr = addr[1:] + if dummy: + addr.append(0) + return self.transmit(cmd, addr, length) + + @staticmethod + def rev8(num: int) -> int: + """Bit-wise reversal for a byte.""" + num = ((num >> 1) & 0x55) | ((num & 0x55) << 1) + num = ((num >> 2) & 0x33) | ((num & 0x33) << 2) + num = ((num >> 4) & 0x0f) | (num << 4) + return num & 0xff + + def enable_rx_lsb(self, enable: bool): + """Change RX bit ordering.""" + self._rev_rx = enable + if enable: + self._mode |= 1 << 3 + else: + self._mode &= ~(1 << 3) + + def enable_tx_lsb(self, enable: bool): + """Change TX bit ordering.""" + self._rev_tx = enable + if enable: + self._mode |= 1 << 2 + else: + self._mode &= ~(1 << 2) + + @property + def is_4b_addr(self) -> bool: + """Report wether 4-byte addressing mode is active.""" + return self._4ben + + def _build_cs_header(self, size: int, release: bool = True) -> bytes: + mode = self._mode & 0xf + if not release: + mode |= 0x80 + header = spack(self.CS_HEADER_FMT, b'/CS', self.VERSION, mode, + size) + self._log.debug('Header: %s', hexlify(header).decode()) + return header + + def _send(self, buf: bytes, release: bool = True): + data = b''.join((self._build_cs_header(len(buf), release), buf)) + self._log.debug('TX[%d]: %s %s', len(buf), hexlify(buf).decode(), + '/' if release else '...') + self._socket.send(data) + + def _receive(self, size: int) -> bytes: + buf = bytearray() + rem = size + timeout = now() + self.TIMEOUT + poller = spoll() + poller.register(self._socket, POLLIN) + while rem: + for _ in poller.poll(self.POLL_TIMEOUT): + try: + data = self._socket.recv(rem) + buf.extend(data) + rem -= len(data) + if rem == 0: + break + except (TimeoutError, LegacyTimeoutError): + self._log.error('Unexpected timeout w/ poll') + raise + if rem == 0: + break + if now() > timeout: + raise TimeoutError('Failed to receive response') + else: + raise TimeoutError(f'{"No" if len(buf) == 0 else "Truncated"} ' + f'response from host') + self._log.debug("RX[%d]: %s", len(buf), hexlify(buf).decode()) + return bytes(buf) + + def _exchange(self, requ: bytes, release: bool = True) -> bytes: + txlen = len(requ) + self._send(requ, release) + resp = self._receive(txlen) + rxlen = len(resp) + if rxlen != txlen: + raise RuntimeError(f'Response truncated {rxlen}/{txlen}') + return resp diff --git a/scripts/opentitan/ot/util/log.py b/scripts/opentitan/ot/util/log.py index 9f696802f15e..7196cc68a9d9 100644 --- a/scripts/opentitan/ot/util/log.py +++ b/scripts/opentitan/ot/util/log.py @@ -11,7 +11,7 @@ from typing import NamedTuple, Union import logging - +from logging.handlers import MemoryHandler try: getLevelNamesMapping = logging.getLevelNamesMapping @@ -95,8 +95,15 @@ def format(self, record): log_fmt = self._color_formats[record.levelno] if self._use_ansi \ else self._plain_format scr, ecr = ('', '') - if self._use_ansi and record.name in self._logger_colors: - scr, ecr = self._logger_colors[record.name] + if self._use_ansi: + logname = record.name + while logname: + if logname in self._logger_colors: + scr, ecr = self._logger_colors[logname] + break + if '.' not in logname: + break + logname = logname.rsplit('.', 1)[0] setattr(record, 'scr', scr) setattr(record, 'ecr', ecr) formatter = logging.Formatter(log_fmt, *self._formatter_args) @@ -131,9 +138,15 @@ def configure_loggers(level: int, *lognames: list[Union[str | int | Color]], if isinstance(lnames, str): lnames = [lnames] loglevels[lvl] = tuple(lnames) + quiet = kwargs.pop('quiet', False) formatter = ColorLogFormatter(**kwargs) - logh = logging.StreamHandler(stderr) - logh.setFormatter(formatter) + shandler = logging.StreamHandler(stderr) + shandler.setFormatter(formatter) + if quiet: + logh = MemoryHandler(100000, target=shandler, flushOnClose=False) + shandler.setLevel(loglevel) + else: + logh = shandler loggers: list[logging.Logger] = [] logdefs: list[tuple[list[str], logging.Logger]] = [] color = None diff --git a/scripts/opentitan/ot/util/misc.py b/scripts/opentitan/ot/util/misc.py index 7fdb82bda484..4dac0feb9469 100644 --- a/scripts/opentitan/ot/util/misc.py +++ b/scripts/opentitan/ot/util/misc.py @@ -6,6 +6,7 @@ :author: Emmanuel Blot """ +from io import BytesIO from sys import stdout from typing import Any, Iterable, Optional, TextIO @@ -62,10 +63,23 @@ def __dir__(self) -> Iterable[Any]: yield from sorted(items) +def group(lst, count): + """Group a list into consecutive count-tuples. Incomplete tuples are + discarded. + + `group([0,3,4,10,2,3], 2) => [(0,3), (4,10), (2,3)]` + + From: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/303060 + """ + return list(zip(*[lst[i::count] for i in range(count)])) + + def dump_buffer(buffer: Buffer, addr: int = 0, file: Optional[TextIO] = None) \ -> None: """Dump a binary buffer, same format as hexdump -C.""" - if isinstance(buffer, memoryview): + if isinstance(buffer, BytesIO): + view = buffer.getbuffer() + elif isinstance(buffer, memoryview): view = buffer.getbuffer() else: view = buffer diff --git a/scripts/opentitan/pyot.py b/scripts/opentitan/pyot.py index fb3ae2927667..4ee111d51dd1 100755 --- a/scripts/opentitan/pyot.py +++ b/scripts/opentitan/pyot.py @@ -20,11 +20,10 @@ except ImportError: # fallback on legacy JSON syntax otherwise from json import load as jload -from logging import CRITICAL, DEBUG, INFO, ERROR, WARNING, getLogger from os import close, curdir, environ, getcwd, linesep, pardir, sep, unlink from os.path import (abspath, basename, dirname, exists, isabs, isdir, isfile, join as joinpath, normpath, relpath) -from re import Match, compile as re_compile, error as re_error, sub as re_sub +from select import POLLIN, POLLERR, POLLHUP, poll as spoll from shutil import rmtree from socket import socket, timeout as LegacyTimeoutError from subprocess import Popen, PIPE, TimeoutExpired @@ -35,7 +34,10 @@ from traceback import format_exc from typing import Any, Iterator, NamedTuple, Optional -from ot.util.log import Color as LogColor, configure_loggers +import logging +import re + +from ot.util.log import ColorLogFormatter, configure_loggers from ot.util.misc import EasyDict @@ -44,6 +46,8 @@ DEFAULT_TIMEOUT = 60 # seconds DEFAULT_TIMEOUT_FACTOR = 1.0 +getLogger = logging.getLogger + class ExecTime(float): """Float with hardcoded formatter. @@ -105,6 +109,58 @@ def _show_row(self, widths: list[int], cols: list[str]) -> None: print(f'|{line}|') +class LogMessageClassifier: + """Log level classifier for log messages. + + :param classifiers: a map of loglevel, list of RE-compatible strings + to match messages + :param qemux: the QEMU executable name, to filter out useless messages + """ + + def __init__(self, classifiers: Optional[dict[str, list[str]]] = None, + qemux: Optional[str] = None): + self._qemux = qemux + if classifiers is None: + classifiers = {} + self._regexes: dict[int, re.Pattern] = {} + for klv in 'error warning info debug'.split(): + uklv = klv.upper() + cstrs = classifiers.get(klv, []) + if not isinstance(cstrs, list): + raise ValueError(f'Invalid log classifiers for {klv}') + regexes = [f'{klv}: ', f'^{uklv} ', f' {uklv} '] + for cstr in cstrs: + try: + # only sanity-check pattern, do not use result + re.compile(cstr) + except re.error as exc: + raise ValueError(f"Invalid log classifier '{cstr}' for " + f"{klv}: {exc}") from exc + regexes.append(cstr) + if regexes: + lvl = getattr(logging, uklv) + self._regexes[lvl] = re.compile(f"({'|'.join(regexes)})") + else: + lvl = getattr(logging, 'NOTSET') + # never match RE + self._regexes[lvl] = re.compile(r'\A(?!x)x') + + def classify(self, line: str, default: int = logging.ERROR) -> int: + """Classify log level of a line depending on its content. + + :param line: line to classify + :param default: defaut log level in no classification is found + :return: the logger log level to use + """ + if self._qemux and line.startswith(self._qemux): + # discard QEMU internal messages that cannot be disable from the VM + return logging.NOTSET + for lvl, pattern in self._regexes.items(): + if pattern.search(line): + return lvl + return default + + class QEMUWrapper: """A small engine to run tests with QEMU. @@ -124,7 +180,7 @@ class QEMUWrapper: such as SIGABRT. """ - ANSI_CRE = re_compile(rb'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]') + ANSI_CRE = re.compile(rb'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]') """ANSI escape sequences.""" GUEST_ERROR_OFFSET = 40 @@ -134,16 +190,11 @@ class QEMUWrapper: NO_MATCH_RETURN_CODE = 100 """Return code when no matching string is found in guest output.""" - LOG_LEVELS = {'D': DEBUG, 'I': INFO, 'E': ERROR} - """OpenTitan log levels.""" - - def __init__(self, tcpdev: tuple[str, int], debug: bool): - # self._mterm: Optional[MiniTerm] = None - self._device = tcpdev + def __init__(self, log_classifiers: dict[str, list[str]], debug: bool): + self._log_classifiers = log_classifiers self._debug = debug self._log = getLogger('pyot') self._qlog = getLogger('pyot.qemu') - self._vcplog = getLogger('pyot.vcp') def run(self, tdef: EasyDict[str, Any]) -> tuple[int, ExecTime, str]: """Execute the specified QEMU command, aborting execution if QEMU does @@ -152,6 +203,7 @@ def run(self, tdef: EasyDict[str, Any]) -> tuple[int, ExecTime, str]: :param tdef: test definition and parameters - command, a list of strings defining the QEMU command to execute with all its options + - vcp_map: how to connect to QEMU virtual communication ports - timeout, the allowed time for the command to execute, specified as a real number - expect_result, the expected outcome of QEMU (exit code). Some @@ -170,15 +222,13 @@ def run(self, tdef: EasyDict[str, Any]) -> tuple[int, ExecTime, str]: # stdout and stderr belongs to QEMU VM # OT's UART0 is redirected to a TCP stream that can be accessed through # self._device. The VM pauses till the TCP socket is connected - xre = re_compile(self.EXIT_ON) - otre = r'^([' + ''.join(self.LOG_LEVELS.keys()) + r'])\d{5}\s' - lre = re_compile(otre) + xre = re.compile(self.EXIT_ON) if tdef.trigger: sync_event = Event() if tdef.trigger.startswith("r'") and tdef.trigger.endswith("'"): try: - tmo = re_compile(tdef.trigger[2:-1].encode()) - except re_error as exc: + tmo = re.compile(tdef.trigger[2:-1].encode()) + except re.error as exc: raise ValueError('Invalid trigger regex: {exc}') from exc def trig_match(bline): @@ -193,11 +243,12 @@ def trig_match(bline): trig_match = None ret = None proc = None - sock = None xstart = None xend = None log = self._log last_error = '' + vcp_map = tdef.vcp_map + vcp_ctxs: dict[int, tuple[str, socket, bytearray]] = {} try: workdir = dirname(tdef.command[0]) log.debug('Executing QEMU as %s', ' '.join(tdef.command)) @@ -206,29 +257,14 @@ def trig_match(bline): stderr=PIPE, encoding='utf-8', errors='ignore', text=True) try: - # ensure that QEMU starts and give some time for it to set up - # its VCP before attempting to connect to it - self._log.debug('Waiting %.1fs for VM init', tdef.start_delay) - proc.wait(tdef.start_delay) + proc.wait(0.1) except TimeoutExpired: pass else: ret = proc.returncode log.error('QEMU bailed out: %d for "%s"', ret, tdef.test_name) raise OSError() - sock = socket() - log.debug('Connecting QEMU VCP as %s:%d', *self._device) - try: - # timeout for connecting to VCP - sock.settimeout(1) - sock.connect(self._device) - except OSError as exc: - log.error('Cannot connect to QEMU VCP port: %s', exc) - raise - # timeout for communicating over VCP - sock.settimeout(0.05) log.debug('Execute QEMU for %.0f secs', tdef.timeout) - vcp_buf = bytearray() # unfortunately, subprocess's stdout calls are blocking, so the # only way to get near real-time output from QEMU is to use a # dedicated thread that may block whenever no output is available @@ -241,6 +277,45 @@ def trig_match(bline): args=(proc, log_q, True)).start() Thread(target=self._qemu_logger, name='qemu_err_logger', args=(proc, log_q, False)).start() + poller = spoll() + connect_map = vcp_map.copy() + timeout = now() + tdef.start_delay + # ensure that QEMU starts and give some time for it to set up + # when multiple VCPs are set to 'wait', one VCP can be connected at + # a time, i.e. QEMU does not open all connections at once. + vcp_lognames = [] + vcplogname = 'pyot.vcp' + while connect_map: + if now() > timeout: + raise TimeoutError(f'Cannot connect to QEMU VCPs ' + f'{", ".join(connect_map)}') + connected = [] + for vcpid, (host, port) in connect_map.items(): + try: + # timeout for connecting to VCP + sock = socket() + sock.settimeout(1) + sock.connect((host, port)) + connected.append(vcpid) + vcp_name = re.sub(r'^.*[-\.+]', '', vcpid) + vcp_lognames.append(vcp_name) + vcp_log = getLogger(f'{vcplogname}.{vcp_name}') + vcp_ctxs[sock.fileno()] = [vcpid, sock, bytearray(), + vcp_log] + # remove timeout for VCP comm, as poll is used + sock.settimeout(None) + poller.register(sock, POLLIN | POLLERR | POLLHUP) + except ConnectionRefusedError: + continue + except OSError as exc: + log.error('Cannot setup QEMU VCP connection %s: %s', + vcpid, exc) + print(format_exc(chain=False), file=stderr) + raise + # removal from dictionary cannot be done while iterating it + for vcpid in connected: + del connect_map[vcpid] + self._colorize_vcp_log(vcplogname, vcp_lognames) xstart = now() if tdef.context: try: @@ -254,17 +329,22 @@ def trig_match(bline): ret = 126 last_error = str(exc) raise + qemu_exec = f'{basename(tdef.command[0])}: ' + classifier = LogMessageClassifier(classifiers=self._log_classifiers, + qemux=qemu_exec) abstimeout = float(tdef.timeout) + now() + qemu_default_log = logging.ERROR + vcp_default_log = logging.DEBUG while now() < abstimeout: while log_q: err, qline = log_q.popleft() if err: - level = self.classify_log(qline) - if level == INFO and \ + level = classifier.classify(qline, qemu_default_log) + if level == logging.INFO and \ qline.find('QEMU waiting for connection') >= 0: - level = DEBUG + level = logging.DEBUG else: - level = INFO + level = logging.INFO self._qlog.log(level, qline) if tdef.context: wret = tdef.context.check_error() @@ -285,52 +365,58 @@ def trig_match(bline): logfn('Abnormal QEMU termination: %d for "%s"', ret, tdef.test_name) break - try: - data = sock.recv(4096) - except (TimeoutError, LegacyTimeoutError): - continue - vcp_buf += data - if not vcp_buf: - continue - lines = vcp_buf.split(b'\n') - vcp_buf = bytearray(lines[-1]) - for line in lines[:-1]: - line = self.ANSI_CRE.sub(b'', line) - if trig_match and trig_match(line): - self._log.info('Trigger pattern detected') - # reset timeout from this event - abstimeout = float(tdef.timeout) + now() - log.debug('Resuming for %.0f secs', tdef.timeout) - sync_event.set() - trig_match = None - xmo = xre.search(line) - if xmo: - xend = now() - exit_word = xmo.group(1).decode('utf-8', - errors='ignore') - ret = self._get_exit_code(xmo) - log.info("Exit sequence detected: '%s' -> %d", - exit_word, ret) - if ret == 0: - last_error = '' - break - sline = line.decode('utf-8', errors='ignore').rstrip() - lmo = lre.search(sline) - if lmo: - level = self.LOG_LEVELS.get(lmo.group(1)) - if level == ERROR: - err = re_sub(r'^.*:\d+]', '', sline).lstrip() + for vfd, event in poller.poll(0.01): + if event in (POLLERR, POLLHUP): + poller.modify(vfd, 0) + continue + vcpid, vcp, vcp_buf, vcp_log = vcp_ctxs[vfd] + try: + data = vcp.recv(4096) + except (TimeoutError, LegacyTimeoutError): + log.error('Unexpected timeout w/ poll on %s', vcp) + continue + vcp_buf += data + if not vcp_buf: + continue + lines = vcp_buf.split(b'\n') + vcp_buf[:] = bytearray(lines[-1]) + for line in lines[:-1]: + line = self.ANSI_CRE.sub(b'', line) + if trig_match and trig_match(line): + # reset timeout from this event + abstimeout = float(tdef.timeout) + now() + log.info('Trigger pattern detected, resuming for ' + '%.0f secs', tdef.timeout) + sync_event.set() + trig_match = None + xmo = xre.search(line) + if xmo: + xend = now() + exit_word = xmo.group(1).decode('utf-8', + errors='ignore') + ret = self._get_exit_code(xmo) + log.info("Exit sequence detected: '%s' -> %d", + exit_word, ret) + if ret == 0: + last_error = '' + break + sline = line.decode('utf-8', errors='ignore').rstrip() + level = classifier.classify(sline, vcp_default_log) + if level == logging.ERROR: + err = re.sub(r'^.*:\d+]', '', sline).lstrip() # be sure not to preserve comma as this char is # used as a CSV separator. last_error = err.strip('"').replace(',', ';') + vcp_log.log(level, sline) else: - level = DEBUG # fall back when no prefix is found - self._vcplog.log(level, sline) - else: - # no match - continue - # match - break + # no match for exit sequence on current VCP + continue + if ret is not None: + # match for exit sequence on current VCP + break + if ret is not None: + # match for exit sequence on last VCP + break if ret is None: log.warning('Execution timed out for "%s"', tdef.test_name) ret = 124 # timeout @@ -341,8 +427,9 @@ def trig_match(bline): finally: if xend is None: xend = now() - if sock: + for _, sock, _, _ in vcp_ctxs.values(): sock.close() + vcp_ctxs.clear() if proc: if xend is None: xend = now() @@ -368,27 +455,46 @@ def trig_match(bline): return abs(ret) or 0, xtime, last_error @classmethod - def classify_log(cls, line: str, default: int = ERROR) -> int: + def classify_log(cls, line: str, default: int = logging.ERROR, + qemux: Optional[str] = None) -> int: """Classify log level of a line depending on its content. :param line: line to classify :param default: defaut log level in no classification is found :return: the logger log level to use """ + if qemux and line.startswith(qemux): + # discard QEMU internal messages that cannot be disable from the VM + return logging.NOTSET if (line.find('info: ') >= 0 or line.startswith('INFO ') or line.find(' INFO ') >= 0): # noqa - return INFO + return logging.INFO if (line.find('warning: ') >= 0 or line.startswith('WARNING ') or line.find(' WARNING ') >= 0): # noqa - return WARNING + return logging.WARNING if (line.find('debug: ') >= 0 or line.startswith('DEBUG ') or line.find(' DEBUG ') >= 0): # noqa - return DEBUG + return logging.DEBUG return default + def _colorize_vcp_log(self, vcplogname: str, lognames: list[str]) -> None: + vlog = getLogger(vcplogname) + clr_fmt = None + while vlog: + for hdlr in vlog.handlers: + if isinstance(hdlr.formatter, ColorLogFormatter): + clr_fmt = hdlr.formatter + break + vlog = vlog.parent + if not clr_fmt: + return + colors = ('blue', 'yellow', 'red', 'magenta', 'cyan', 'green') + for logname, color in zip(lognames, colors): + clr_fmt.add_logger_colors(f'{vcplogname}.{logname}', color) + def _qemu_logger(self, proc: Popen, queue: deque, err: bool): # worker thread, blocking on VM stdout/stderr stream = proc.stderr if err else proc.stdout @@ -397,7 +503,7 @@ def _qemu_logger(self, proc: Popen, queue: deque, err: bool): if line: queue.append((err, line)) - def _get_exit_code(self, xmo: Match) -> int: + def _get_exit_code(self, xmo: re.Match) -> int: groups = xmo.groups() if not groups: self._log.debug('No matching group, using defaut code') @@ -410,7 +516,7 @@ def _get_exit_code(self, xmo: Match) -> int: pass # try to find in the regular expression whether the match is one of # the alternative in the first group - alts = re_sub(rb'^.*\((.*?)\).*$', r'\1', xmo.re.pattern).split(b'|') + alts = re.sub(rb'^.*\((.*?)\).*$', r'\1', xmo.re.pattern).split(b'|') try: pos = alts.index(match) if pos: @@ -480,13 +586,13 @@ def interpolate(self, value: Any) -> str: :param value: input value :return: interpolated value as a string """ - def replace(smo: Match) -> str: + def replace(smo: re.Match) -> str: name = smo.group(1) val = self._env[name] if name in self._env \ else environ.get(name, '') return val svalue = str(value) - nvalue = re_sub(r'\$\{(\w+)\}', replace, svalue) + nvalue = re.sub(r'\$\{(\w+)\}', replace, svalue) if nvalue != svalue: self._log.debug('Interpolate %s with %s', value, nvalue) return nvalue @@ -498,14 +604,14 @@ def define(self, aliases: dict[str, Any]) -> None: :param aliases: an alias JSON (sub-)tree """ - def replace(smo: Match) -> str: + def replace(smo: re.Match) -> str: name = smo.group(1) val = self._env[name] if name in self._env \ else environ.get(name, '') return val for name in aliases: value = str(aliases[name]) - value = re_sub(r'\$\{(\w+)\}', replace, value) + value = re.sub(r'\$\{(\w+)\}', replace, value) if exists(value): value = normpath(value) aliases[name] = value @@ -540,7 +646,7 @@ def interpolate_dirs(self, value: str, default: str) -> str: none :return: the interpolated string """ - def replace(smo: Match) -> str: + def replace(smo: re.Match) -> str: name = smo.group(1) if name == '': name = default @@ -552,7 +658,7 @@ def replace(smo: Match) -> str: if not tmp_dir.endswith(sep): tmp_dir = f'{tmp_dir}{sep}' return tmp_dir - nvalue = re_sub(r'\@\{(\w*)\}/', replace, value) + nvalue = re.sub(r'\@\{(\w*)\}/', replace, value) if nvalue != value: self._log.debug('Interpolate %s with %s', value, nvalue) return nvalue @@ -673,7 +779,7 @@ def _configure_logger(self, tool) -> None: log = getLogger('pyot') flog = tool.logger # sub-tool get one logging level down to reduce log messages - floglevel = min(CRITICAL, log.getEffectiveLevel() + 10) + floglevel = min(logging.CRITICAL, log.getEffectiveLevel() + 10) flog.setLevel(floglevel) for hdlr in log.handlers: flog.addHandler(hdlr) @@ -771,7 +877,7 @@ def _run(self): self._log.info('Waiting for sync') while self._resume: if self._sync.wait(0.1): - self._log.info('Sync triggered') + self._log.debug('Synchronized') break self._sync.clear() # pylint: disable=consider-using-with @@ -780,11 +886,14 @@ def _run(self): errors='ignore', text=True) Thread(target=self._logger, args=(proc, True)).start() Thread(target=self._logger, args=(proc, False)).start() + qemu_exec = f'{basename(self._cmd[0])}: ' + classifier = LogMessageClassifier(qemux=qemu_exec) while self._resume: while self._log_q: err, qline = self._log_q.popleft() if err: - self._log.log(QEMUWrapper.classify_log(qline), qline) + loglevel = classifier.classify(qline) + self._log.log(loglevel, qline) else: self._log.debug(qline) if proc.poll() is not None: @@ -985,6 +1094,18 @@ class QEMUExecuter: virtual UART port. """ + DEFAULT_SERIAL_PORT = 'serial0' + """Default VCP name.""" + + LOG_SHORTCUTS = { + 'A': 'in_asm', + 'E': 'exec', + 'G': 'guest_errors', + 'I': 'int', + 'U': 'unimp', + } + """Shortcut names for QEMU log sources.""" + def __init__(self, qfm: QEMUFileManager, config: dict[str, any], args: Namespace): self._log = getLogger('pyot.exec') @@ -993,7 +1114,6 @@ def __init__(self, qfm: QEMUFileManager, config: dict[str, any], self._args = args self._argdict: dict[str, Any] = {} self._qemu_cmd: list[str] = [] - self._vcp: Optional[tuple[str, int]] = None self._suffixes = [] if hasattr(self._args, 'opts'): setattr(self._args, 'global_opts', getattr(self._args, 'opts')) @@ -1008,7 +1128,6 @@ def build(self) -> None: """ exec_info = self._build_qemu_command(self._args) self._qemu_cmd = exec_info.command - self._vcp = exec_info.connection self._argdict = dict(self._args.__dict__) self._suffixes = [] suffixes = self._config.get('suffixes', []) @@ -1029,7 +1148,8 @@ def run(self, debug: bool, allow_no_test: bool) -> int: :return: success or the code of the first encountered error """ - qot = QEMUWrapper(self._vcp, debug) + log_classifiers = self._config.get('logclass', {}) + qot = QEMUWrapper(log_classifiers, debug) ret = 0 results = defaultdict(int) result_file = self._argdict.get('result') @@ -1094,6 +1214,8 @@ def run(self, debug: bool, allow_no_test: bool) -> int: # pylint: disable=broad-except except Exception as exc: self._log.critical('%s', str(exc)) + if debug: + print(format_exc(chain=False), file=stderr) tret = 99 xtime = 0.0 err = str(exc) @@ -1190,48 +1312,50 @@ def _cleanup_temp_files(self, storage: dict[str, set[str]]) -> None: for filename in files: delete_file(filename) - def _build_qemu_command(self, args: Namespace, - opts: Optional[list[str]] = None) \ - -> EasyDict[str, Any]: - """Build QEMU command line from argparser values. - - :param args: the parsed arguments - :param opts: any QEMU-specific additional options - :return: a dictionary defining how to execute the command - """ - if args.qemu is None: - raise ValueError('QEMU path is not defined') - qemu_args = [ - args.qemu, - '-M', - args.machine - ] + def _build_qemu_fw_args(self, args: Namespace) \ + -> tuple[str, str, list[str]]: rom_exec = bool(args.rom_exec) roms = args.rom or [] multi_rom = (len(roms) + int(rom_exec)) > 1 # generate pre-application ROM option - rom_count = 0 - for rom in roms: - rom_path = self._qfm.interpolate(rom) - if not isfile(rom_path): - raise ValueError(f'Unable to find ROM file {rom_path}') - rom_ids = [] - if args.first_soc: - rom_ids.append(f'{args.first_soc}.') - rom_ids.append('rom') - if multi_rom: - rom_ids.append(f'{rom_count}') - rom_id = ''.join(rom_ids) - rom_opt = f'ot-rom-img,id={rom_id},file={rom_path},digest=fake' - qemu_args.extend(('-object', rom_opt)) - rom_count += 1 + fw_args: list[str] = [] + machine = args.machine + variant = args.variant + chiplet_count = 1 + if variant: + machine = f'{machine},variant={variant}' + try: + chiplet_count = sum(int(x) + for x in re.split(r'[A-Za-z]', variant) + if x) + except ValueError: + self._log.warning('Unknown variant syntax %s', variant) + for chip_id in range(chiplet_count): + rom_count = 0 + for rom in roms: + rom_path = self._qfm.interpolate(rom) + if not isfile(rom_path): + raise ValueError(f'Unable to find ROM file {rom_path}') + rom_ids = [] + if args.first_soc: + if chiplet_count == 1: + rom_ids.append(f'{args.first_soc}.') + else: + rom_ids.append(f'{args.first_soc}{chip_id}.') + rom_ids.append('rom') + if multi_rom: + rom_ids.append(f'{rom_count}') + rom_id = ''.join(rom_ids) + rom_opt = f'ot-rom-img,id={rom_id},file={rom_path},digest=fake' + fw_args.extend(('-object', rom_opt)) + rom_count += 1 xtype = None if args.exec: exec_path = self.abspath(args.exec) xtype = self.guess_test_type(exec_path) if xtype == 'spiflash': - qemu_args.extend(('-drive', - f'if=mtd,format=raw,file={exec_path}')) + fw_args.extend(('-drive', + f'if=mtd,bus=0,format=raw,file={exec_path}')) else: if xtype != 'elf': raise ValueError(f'No support for test type: {xtype} ' @@ -1240,17 +1364,78 @@ def _build_qemu_command(self, args: Namespace, # generate ROM option for the application itself rom_ids = [] if args.first_soc: - rom_ids.append(f'{args.first_soc}.') + if chiplet_count == 1: + rom_ids.append(f'{args.first_soc}.') + else: + rom_ids.append(f'{args.first_soc}0.') rom_ids.append('rom') if multi_rom: rom_ids.append(f'{rom_count}') rom_id = ''.join(rom_ids) rom_opt = (f'ot-rom-img,id={rom_id},file={exec_path},' f'digest=fake') - qemu_args.extend(('-object', rom_opt)) + fw_args.extend(('-object', rom_opt)) rom_count += 1 else: - qemu_args.extend(('-kernel', exec_path)) + fw_args.extend(('-kernel', exec_path)) + return machine, xtype, fw_args + + def _build_qemu_log_sources(self, args: Namespace) -> list[str]: + if not args.log: + return [] + log_args = [] + for arg in args.log: + if arg.lower() == arg: + log_args.append(arg) + continue + for upch in arg: + try: + logname = self.LOG_SHORTCUTS[upch] + except KeyError as exc: + raise ValueError(f"Unknown log name '{upch}'") from exc + log_args.append(logname) + return ['-d', ','.join(log_args)] + + def _build_qemu_vcp_args(self, args: Namespace) -> \ + tuple[list[str], dict[str, tuple[str, int]]]: + device = args.device + devdesc = device.split(':') + host = devdesc[0] + try: + port = int(devdesc[1]) + if not 0 < port < 65536: + raise ValueError(f'Invalid serial TCP port: {port}') + except IndexError as exc: + raise ValueError(f'TCP port not specified: {device}') from exc + except TypeError as exc: + raise ValueError(f'Invalid TCP serial device: {device}') from exc + mux = f'mux={"on" if args.muxserial else "off"}' + vcps = args.vcp or [self.DEFAULT_SERIAL_PORT] + vcp_args = ['-display', 'none'] + vcp_map = {} + for vix, vcp in enumerate(vcps): + vcp_map[vcp] = (host, port+vix) + vcp_args.extend(('-chardev', + f'socket,id={vcp},host={host},port={port+vix},' + f'{mux},server=on,wait=on')) + if vcp == self.DEFAULT_SERIAL_PORT: + vcp_args.extend(('-serial', 'chardev:serial0')) + return vcp_args, vcp_map + + def _build_qemu_command(self, args: Namespace, + opts: Optional[list[str]] = None) \ + -> EasyDict[str, Any]: + """Build QEMU command line from argparser values. + + :param args: the parsed arguments + :param opts: any QEMU-specific additional options + :return: a dictionary defining how to execute the command + """ + if args.qemu is None: + raise ValueError('QEMU path is not defined') + machine, xtype, fw_args = self._build_qemu_fw_args(args) + qemu_args = [args.qemu, '-M', machine] + qemu_args.extend(fw_args) temp_files = defaultdict(set) if all((args.otp, args.otp_raw)): raise ValueError('OTP VMEM and RAW options are mutually exclusive') @@ -1293,15 +1478,12 @@ def _build_qemu_command(self, args: Namespace, args.trace.close() qemu_args.extend(('-trace', f'events={self.abspath(args.trace.name)}')) - if args.log: - qemu_args.append('-d') - qemu_args.append(','.join(args.log)) + qemu_args.extend(self._build_qemu_log_sources(args)) if args.singlestep: qemu_args.append('-singlestep') if 'icount' in args: if args.icount is not None: qemu_args.extend(('-icount', f'shift={args.icount}')) - mux = f'mux={"on" if args.muxserial else "off"}' try: start_delay = float(getattr(args, 'start_delay') or self.DEFAULT_START_DELAY) @@ -1310,24 +1492,12 @@ def _build_qemu_command(self, args: Namespace, from exc start_delay *= args.timeout_factor trigger = getattr(args, 'trigger', '') - device = args.device - devdesc = device.split(':') - try: - port = int(devdesc[1]) - if not 0 < port < 65536: - raise ValueError('Invalid serial TCP port') - tcpdev = (devdesc[0], port) - qemu_args.extend(('-display', 'none')) - qemu_args.extend(('-chardev', - f'socket,id=serial0,host={devdesc[0]},' - f'port={port},{mux},server=on,wait=on')) - qemu_args.extend(('-serial', 'chardev:serial0')) - except TypeError as exc: - raise ValueError('Invalid TCP serial device') from exc + vcp_args, vcp_map = self._build_qemu_vcp_args(args) + qemu_args.extend(vcp_args) qemu_args.extend(args.global_opts or []) if opts: qemu_args.extend((str(o) for o in opts)) - return EasyDict(command=qemu_args, connection=tcpdev, + return EasyDict(command=qemu_args, vcp_map=vcp_map, tmpfiles=temp_files, start_delay=start_delay, trigger=trigger) @@ -1405,7 +1575,7 @@ def _enumerate_from(self, config_entry: str) -> Iterator[str]: incf_dir = dirname(incf) with open(incf, 'rt', encoding='utf-8') as ifp: for testfile in ifp: - testfile = re_sub('#.*$', '', testfile).strip() + testfile = re.sub('#.*$', '', testfile).strip() if not testfile: continue testfile = self._qfm.interpolate(testfile) @@ -1503,8 +1673,8 @@ def _build_test_context(self, test_name: str) -> QEMUContext: if not isinstance(cmd, str): raise ValueError(f'Invalid command #{pos} in ' f'"{ctx_name}" for test {test_name}') - cmd = re_sub(r'[\n\r]', ' ', cmd.strip()) - cmd = re_sub(r'\s{2,}', ' ', cmd) + cmd = re.sub(r'[\n\r]', ' ', cmd.strip()) + cmd = re.sub(r'\s{2,}', ' ', cmd) cmd = self._qfm.interpolate(cmd) cmd = self._qfm.interpolate_dirs(cmd, test_name) context[ctx_name].append(cmd) @@ -1538,7 +1708,9 @@ def main(): 'ticks per inst. or \'auto\'') qvm.add_argument('-L', '--log_file', help='log file for trace and log messages') - qvm.add_argument('-M', '--log', action='append', + qvm.add_argument('-M', '--variant', + help='machine variant (machine specific)') + qvm.add_argument('-N', '--log', action='append', help='log message types') qvm.add_argument('-m', '--machine', help=f'virtual machine (default to {DEFAULT_MACHINE})') @@ -1547,8 +1719,10 @@ def main(): qvm.add_argument('-q', '--qemu', help=f'path to qemu application ' f'(default: {rel_qemu_path})') + qvm.add_argument('-P', '--vcp', action='append', + help='serial port devices (default: use serial0)') qvm.add_argument('-p', '--device', - help=f'serial port device name ' + help=f'serial port device name / template name ' f'(default to {DEFAULT_DEVICE})') qvm.add_argument('-t', '--trace', type=FileType('rt', encoding='utf-8'), help='trace event definition file') @@ -1607,6 +1781,8 @@ def main(): extra = argparser.add_argument_group(title='Extras') extra.add_argument('-v', '--verbose', action='count', help='increase verbosity') + extra.add_argument('-V', '--vcp-verbose', action='count', + help='increase verbosity of QEMU virtual comm ports') extra.add_argument('-d', action='store_true', help='enable debug mode') extra.add_argument('--log-time', action='store_true', @@ -1636,7 +1812,8 @@ def main(): args.result = tmp_result log = configure_loggers(args.verbose, 'pyot', - LogColor('blue'), 'pyot.vcp', + args.vcp_verbose or 0, + 'pyot.vcp', name_width=16, ms=args.log_time, debug=args.debug, info=args.info, warning=args.warn)[0] @@ -1714,7 +1891,7 @@ def main(): if debug: print(format_exc(chain=False), file=stderr) argparser.error(str(exc)) - ret = qexc.run(args.debug, args.zero) + ret = qexc.run(debug, args.zero) if args.summary: rfmt = ResultFormatter() rfmt.load(args.result) diff --git a/scripts/opentitan/spidevflash.py b/scripts/opentitan/spidevflash.py new file mode 100755 index 000000000000..81190803a8b8 --- /dev/null +++ b/scripts/opentitan/spidevflash.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 + +"""SPI device flasher tool. + + :author: Emmanuel Blot +""" + +# Copyright (c) 2024 Rivos, Inc. +# SPDX-License-Identifier: Apache2 + +from argparse import ArgumentParser, FileType +from logging import getLogger +from os import linesep +from sys import exit as sysexit, modules, stderr +from time import sleep, time as now +from traceback import format_exc + +from ot.spi import SpiDevice +from ot.util.log import configure_loggers +from ot.util.misc import HexInt + + +class SpiDeviceFlasher: + "Simple SPI device flasher, using OT protocol." + + DEFAULT_PORT = 8004 + """Default TCP port for SPI device.""" + + def __init__(self): + self._log = getLogger('spidev.flash') + self._spidev = SpiDevice() + + def connect(self, host: str, port: int): + """Connect to the remote SPI device and wait for sync.""" + self._spidev.connect(host, port) + self._wait_for_remote() + + def disconnect(self): + """Disconnect from the remote host.""" + self._spidev.power_down() + + def program(self, data: memoryview, offset: int = 0): + """Programm a buffer into the remote flash device.""" + start = now() + total = 0 + page_size = 256 + page_count = (len(data) + page_size - 1) // page_size + log = getLogger('spidev') + log.info('\nRead SFTP') + self._spidev.read_sfdp() + log.info('\nChip erase') + self._spidev.enable_write() + self._spidev.chip_erase() + self._spidev.wait_idle() + for pos in range(0, len(data), page_size): + page = data[pos:pos+page_size] + log.debug('Program page @ 0x%06x %d/%d, %d bytes', + pos + offset, pos//page_size, page_count, len(page)) + self._spidev.enable_write() + self._spidev.page_program(pos + offset, page) + sleep(0.003) + self._spidev.wait_idle(pace=0.001) # bootrom is slow :-) + total += len(page) + delta = now() - start + msg = f'{delta:.1f}s to send {total/1024:.1f}KB: ' \ + f'{total/(1024*delta):.1f}KB/s' + log.info('%s', msg) + self._spidev.reset() + + def _wait_for_remote(self): + # use JEDEC ID presence as a sycnhronisation token + # remote SPI device firware should set JEDEC ID when it is full ready + # to handle requests + timeout = now() + 3.0 + while now() < timeout: + jedec = set(self._spidev.read_jedec_id()) + if len(jedec) > 1 or jedec.pop() not in (0x00, 0xff): + return + raise RuntimeError('Remote SPI device not ready') + + +def main(): + """Main routine""" + debug = True + try: + desc = modules[__name__].__doc__.split('.', 1)[0].strip() + argparser = ArgumentParser(description=f'{desc}.') + argparser.add_argument('-f', '--file', type=FileType('rb'), + required=True, + help='Binary file to flash') + argparser.add_argument('-a', '--address', type=HexInt.parse, + default='0', + help='Address in the SPI flash (default to 0)') + argparser.add_argument('-r', '--host', + default='127.0.0.1', + help='remote host name (default: localhost)') + argparser.add_argument('-p', '--port', type=int, + default=SpiDeviceFlasher.DEFAULT_PORT, + help=f'remote host TCP port (defaults to ' + f'{SpiDeviceFlasher.DEFAULT_PORT})') + argparser.add_argument('-v', '--verbose', action='count', + help='increase verbosity') + argparser.add_argument('-d', '--debug', action='store_true', + help='enable debug mode') + args = argparser.parse_args() + debug = args.debug + + configure_loggers(args.verbose, 'spidev') + + flasher = SpiDeviceFlasher() + flasher.connect(args.host, args.port) + data = args.file.read() + args.file.close() + flasher.program(data, args.address) + flasher.disconnect() + + sysexit(0) + # pylint: disable=broad-except + except Exception as exc: + print(f'{linesep}Error: {exc}', file=stderr) + if debug: + print(format_exc(chain=False), file=stderr) + sysexit(1) + except KeyboardInterrupt: + sysexit(2) + + +if __name__ == '__main__': + main() diff --git a/system/memory.c b/system/memory.c index a229a79988fc..3ad0f18d4977 100644 --- a/system/memory.c +++ b/system/memory.c @@ -3436,6 +3436,38 @@ static void mtree_print_flatview(gpointer key, gpointer value, qemu_printf("\n"); } +void mtree_print_as_flatview(AddressSpace *as, bool dispatch_tree, bool owner) +{ + struct FlatViewInfo fvi = { + .counter = 0, + .dispatch_tree = dispatch_tree, + .owner = owner, + }; + + FlatView *view = address_space_get_flatview(as); + AccelClass *ac = ACCEL_GET_CLASS(current_accel()); + if (ac->has_memory) { + fvi.ac = ac; + } + + GArray *ases = g_array_new(false, false, sizeof(as)); + g_array_append_val(ases, as); + + mtree_print_flatview(view, ases, &fvi); + + g_array_free(ases, false); +} + +static void mtree_info_as(bool dispatch_tree, bool owner, bool disabled, + AddressSpace *sas); + +void mtree_print_as_simple(AddressSpace *as, bool dispatch_tree, bool owner, + bool disabled) +{ + mtree_info_as(dispatch_tree, owner, disabled, as); +} + + static gboolean mtree_info_flatview_free(gpointer key, gpointer value, gpointer user_data) { @@ -3529,7 +3561,8 @@ static gboolean mtree_info_as_free(gpointer key, gpointer value, return true; } -static void mtree_info_as(bool dispatch_tree, bool owner, bool disabled) +static void mtree_info_as(bool dispatch_tree, bool owner, bool disabled, + AddressSpace *sas) { MemoryRegionListHead ml_head; MemoryRegionList *ml, *ml2; @@ -3545,6 +3578,9 @@ static void mtree_info_as(bool dispatch_tree, bool owner, bool disabled) QTAILQ_INIT(&ml_head); QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { + if (sas && as != sas) { + continue; + } /* Create hashtable, key=AS root MR, value = list of AS */ as_same_root_mr_list = g_hash_table_lookup(views, as->root); as_same_root_mr_list = g_slist_insert_sorted(as_same_root_mr_list, as, @@ -3574,7 +3610,7 @@ void mtree_info(bool flatview, bool dispatch_tree, bool owner, bool disabled) if (flatview) { mtree_info_flatview(dispatch_tree, owner); } else { - mtree_info_as(dispatch_tree, owner, disabled); + mtree_info_as(dispatch_tree, owner, disabled, NULL); } } diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 991b8450ab08..6f745f8bde3a 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -42,7 +42,7 @@ /* RISC-V CPU definitions */ static const char riscv_single_letter_exts[] = "IEMAFDQCBPVH"; const uint32_t misa_bits[] = {RVI, RVE, RVM, RVA, RVF, RVD, RVV, - RVC, RVS, RVU, RVH, RVJ, RVG, RVB, 0}; + RVC, RVS, RVU, RVH, RVJ, RVG, RVB, RVX, 0}; /* * From vector_helper.c @@ -679,7 +679,7 @@ static void rv32_lowrisc_ibexdemo_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; RISCVCPU *cpu = RISCV_CPU(obj); - riscv_cpu_set_misa_ext(env, RVI | RVM | RVC); + riscv_cpu_set_misa_ext(env, RVI | RVM | RVC | RVU); env->priv_ver = PRIV_VERSION_1_12_0; #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(cpu, VM_1_10_MBARE); @@ -701,7 +701,7 @@ static void rv32_lowrisc_opentitan_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; RISCVCPU *cpu = RISCV_CPU(obj); - riscv_cpu_set_misa_ext(env, RVI | RVM | RVC); + riscv_cpu_set_misa_ext(env, RVI | RVM | RVC | RVU | RVX); env->priv_ver = PRIV_VERSION_1_12_0; #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(cpu, VM_1_10_MBARE); @@ -1519,7 +1519,8 @@ static const MISAExtInfo misa_ext_info_arr[] = { MISA_EXT_INFO(RVJ, "x-j", "Dynamic translated languages"), MISA_EXT_INFO(RVV, "v", "Vector operations"), MISA_EXT_INFO(RVG, "g", "General purpose (IMAFD_Zicsr_Zifencei)"), - MISA_EXT_INFO(RVB, "x-b", "Bit manipulation (Zba_Zbb_Zbs)") + MISA_EXT_INFO(RVB, "x-b", "Bit manipulation (Zba_Zbb_Zbs)"), + MISA_EXT_INFO(RVX, "x", "Non-standard extensions") }; static void riscv_cpu_validate_misa_mxl(RISCVCPUClass *mcc) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index a5d862d51a02..10718ed7c16d 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -71,6 +71,7 @@ typedef struct CPUArchState CPURISCVState; #define RVJ RV('J') #define RVG RV('G') #define RVB RV('B') +#define RVX RV('X') extern const uint32_t misa_bits[]; const char *riscv_get_misa_ext_name(uint32_t bit);