| // Copyright 2023 Google LLC |
| // Copyright lowRISC contributors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "hw/top_matcha/sw/autogen/top_matcha_memory.h" |
| #include "sw/device/lib/base/macros.h" |
| #include "sw/device/lib/base/multibits_asm.h" |
| #include "ast_regs.h" |
| #include "csrng_regs.h" |
| #include "edn_regs.h" |
| #include "entropy_src_regs.h" |
| #include "otp_ctrl_regs.h" |
| #include "sensor_ctrl_regs.h" |
| #include "sram_ctrl_regs.h" |
| |
| /** |
| * Test ROM interrupt vectors. |
| * |
| * After reset all interrupts are disabled. Only exceptions (interrupt 0) and |
| * non-maskable interrupts (interrupt 31) are possible. For simplicity however |
| * we just set all interrupt handlers in the Test ROM to use the same handler, |
| * which loops forever. |
| * |
| * Interrupt vectors in Ibex have 32 entries for 32 possible interrupts. The |
| * vector must be 256-byte aligned, as Ibex's vectoring mechanism requires that. |
| * |
| * Note that the Ibex reset handler (entry point) immediately follows this |
| * interrupt vector and can be thought of as an extra entry. |
| * |
| * More information about Ibex's interrupts can be found here: |
| * https://ibex-core.readthedocs.io/en/latest/03_reference/exception_interrupts.html |
| */ |
| |
| // Push Test ROM interrupt vector options. |
| .option push |
| |
| // Disable RISC-V instruction compression: we need all instructions to |
| // be exactly word wide in the interrupt vector. |
| .option norvc |
| |
| // Disable RISC-V linker relaxation, as it can compress instructions at |
| // link-time, which we also really don't want. |
| .option norelax |
| |
| // NOTE: The "ax" flag below is necessary to ensure that this section |
| // is allocated executable space in ROM by the linker. |
| .section .vectors, "ax" |
| #ifdef PUPPETEER_ROM |
| bootrom_vector_table: |
| j default_irq_handler // Exception 0, Reserved |
| j default_irq_handler // Exception 1, Supervisor software interrupt |
| j default_irq_handler // Exception 2, Reserved |
| j default_irq_handler // Exception 3, Machine software interrupt |
| j default_irq_handler // Exception 4, Reserved |
| j default_irq_handler // Exception 5, Supervisor software interrupt |
| j default_irq_handler // Exception 6, Reserved |
| j default_irq_handler // Exception 7, Machine timer interrupt |
| j default_irq_handler // Exception 8, Reserved |
| j default_irq_handler // Exception 9, Supervisor external interrupt |
| j default_irq_handler // Exception 10, Reserved |
| j default_irq_handler // Exception 11, Machine external interrupt |
| j default_irq_handler // Exception 12, Reserved |
| j default_irq_handler // Exception 13, Reserved |
| j default_irq_handler // Exception 14, Reserved |
| j default_irq_handler // Exception 15, Reserved |
| j default_irq_handler // Exception 16, Ibex fast interrupt handler 0 |
| j default_irq_handler // Exception 17, Ibex fast interrupt handler 1 |
| j default_irq_handler // Exception 18, Ibex fast interrupt handler 2 |
| j default_irq_handler // Exception 19, Ibex fast interrupt handler 3 |
| j default_irq_handler // Exception 20, Ibex fast interrupt handler 4 |
| j default_irq_handler // Exception 21, Ibex fast interrupt handler 5 |
| j default_irq_handler // Exception 22, Ibex fast interrupt handler 6 |
| j default_irq_handler // Exception 23, Ibex fast interrupt handler 7 |
| j default_irq_handler // Exception 24, Ibex fast interrupt handler 8 |
| j default_irq_handler // Exception 25, Ibex fast interrupt handler 9 |
| j default_irq_handler // Exception 26, Ibex fast interrupt handler 10 |
| j default_irq_handler // Exception 27, Ibex fast interrupt handler 11 |
| j default_irq_handler // Exception 28, Ibex fast interrupt handler 12 |
| j default_irq_handler // Exception 29, Ibex fast interrupt handler 13 |
| j default_irq_handler // Exception 30, Ibex fast interrupt handler 14 |
| j default_irq_handler // Exception 31, Ibex NMI handler |
| j _reset_start // Ibex reset vector @ 0x8080 |
| #else |
| .balign 256 |
| .global _test_rom_interrupt_vector |
| .type _test_rom_interrupt_vector, @function |
| _test_rom_interrupt_vector: |
| |
| // Each jump instruction must be exactly 4 bytes in order to ensure that the |
| // entries are properly located. |
| .rept 32 |
| j _test_rom_irq_handler |
| .endr |
| |
| // Ibex reset vector, the initial entry point after reset. (This falls at IRQ |
| // handler 0x80.) |
| j _reset_start |
| |
| // Set size so this vector can be disassembled. |
| .size _test_rom_interrupt_vector, .-_test_rom_interrupt_vector |
| |
| // Pop ROM interrupt vector options. |
| // |
| // Re-enable compressed instructions, linker relaxation. |
| #endif |
| .option pop |
| |
| // ----------------------------------------------------------------------------- |
| #ifdef PUPPETEER_ROM |
| // The default interrupt handler during the first stage boot does nothing |
| // useful and just spins in a wfi loop. |
| |
| .section .crt, "ax" |
| default_irq_handler: |
| wfi |
| j default_irq_handler |
| |
| //------------------------------------------------------------------------------ |
| // Bare-metal entry point for Shodan's first-stage bootloader, stored in the |
| // on-die boot rom. |
| |
| .section .crt, "ax" |
| .global _reset_start |
| #else |
| /** |
| * Test ROM runtime initialization code. |
| */ |
| |
| // NOTE: The "ax" flag below is necessary to ensure that this section |
| // is allocated executable space in ROM by the linker. |
| .section .crt, "ax" |
| |
| /** |
| * Entry point after reset. This symbol is jumped to from the handler |
| * for IRQ 0x80. |
| */ |
| .balign 4 |
| .global _reset_start |
| .type _reset_start, @function |
| #endif |
| |
| _reset_start: |
| |
| // Set up the global pointer. This requires that we disable linker relaxations |
| // (or it will be relaxed to `mv gp, gp`). |
| .option push |
| .option norelax |
| la gp, __global_pointer$ |
| .option pop |
| |
| // Clobber all writeable registers. |
| li x1, 0x0 |
| li x2, 0x0 |
| li x4, 0x0 |
| li x5, 0x0 |
| li x6, 0x0 |
| li x7, 0x0 |
| li x8, 0x0 |
| li x9, 0x0 |
| li x10, 0x0 |
| li x11, 0x0 |
| li x12, 0x0 |
| li x13, 0x0 |
| li x14, 0x0 |
| li x15, 0x0 |
| li x16, 0x0 |
| li x17, 0x0 |
| li x18, 0x0 |
| li x19, 0x0 |
| li x20, 0x0 |
| li x21, 0x0 |
| li x22, 0x0 |
| li x23, 0x0 |
| li x24, 0x0 |
| li x25, 0x0 |
| li x26, 0x0 |
| li x27, 0x0 |
| li x28, 0x0 |
| li x29, 0x0 |
| li x30, 0x0 |
| li x31, 0x0 |
| |
| #ifdef PUPPETEER_ROM |
| // Set up the stack |
| la sp, _stack_end |
| |
| // With GP and SP set we can now technically run C code, but we need some |
| // additional configuration work to enable Ibex's security systems. Those are |
| // handled by _start below. |
| j _start |
| |
| //------------------------------------------------------------------------------ |
| // C-callable entry point for the first stage bootloader. Initializes AST, |
| // entropy sources, SRAM scrambling, and then clears RAM and jumps to |
| // _boot_start. |
| |
| .section .crt, "ax" |
| .global _start |
| #else |
| // Set up the stack. |
| la sp, _stack_end |
| |
| |
| // Explicit fall-through to `_start`. |
| .size _reset_start, .-_reset_start |
| |
| // ----------------------------------------------------------------------------- |
| |
| /** |
| * Callable entry point for the boot rom. |
| * |
| * Currently, this zeroes the `.bss` section, copies initial data to |
| * `.data`, and then jumps to the program entry point. |
| */ |
| .balign 4 |
| .global _start |
| .type _start, @function |
| #endif |
| _start: |
| #if !OT_IS_ENGLISH_BREAKFAST |
| #if !OTP_IS_RAM |
| // Check if AST initialization should be skipped. |
| li a0, (TOP_MATCHA_OTP_CTRL_CORE_BASE_ADDR + \ |
| OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET) |
| lw t0, OTP_CTRL_PARAM_CREATOR_SW_CFG_AST_INIT_EN_OFFSET(a0) |
| li t1, MULTIBIT_ASM_BOOL4_TRUE |
| bne t0, t1, .L_ast_init_skip |
| |
| // Copy the AST configuration from OTP. |
| li a0, (TOP_MATCHA_AST_BASE_ADDR) |
| li a1, (TOP_MATCHA_AST_BASE_ADDR + AST_REGAL_REG_OFFSET + 4) |
| li a2, (TOP_MATCHA_OTP_CTRL_CORE_BASE_ADDR + \ |
| OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET + \ |
| OTP_CTRL_PARAM_CREATOR_SW_CFG_AST_CFG_OFFSET) |
| call crt_section_copy |
| #else |
| j .L_ast_init_skip |
| #endif |
| |
| // Wait for AST initialization to complete. |
| li a0, TOP_MATCHA_SENSOR_CTRL_BASE_ADDR |
| .L_ast_done_loop: |
| lw t0, SENSOR_CTRL_STATUS_REG_OFFSET(a0) |
| srli t0, t0, SENSOR_CTRL_STATUS_AST_INIT_DONE_BIT // no-op as bit index is currently 0 |
| andi t0, t0, 0x1 |
| beqz t0, .L_ast_done_loop |
| |
| .L_ast_init_skip: |
| // The following sequence enables the minimum level of entropy required to |
| // initialize memory scrambling, as well as the entropy distribution network. |
| li a0, TOP_MATCHA_ENTROPY_SRC_BASE_ADDR |
| // Note for BOOT_ROM initialization the FIPS_ENABLE bit is set to kMultiBitBool4False |
| // to prevent the release of FIPS entropy until all the thresholds are set |
| li t0, (MULTIBIT_ASM_BOOL4_FALSE << ENTROPY_SRC_CONF_FIPS_ENABLE_OFFSET) | \ |
| (MULTIBIT_ASM_BOOL4_FALSE << ENTROPY_SRC_CONF_ENTROPY_DATA_REG_ENABLE_OFFSET) | \ |
| (MULTIBIT_ASM_BOOL4_FALSE << ENTROPY_SRC_CONF_THRESHOLD_SCOPE_OFFSET) | \ |
| (MULTIBIT_ASM_BOOL4_FALSE << ENTROPY_SRC_CONF_RNG_BIT_ENABLE_OFFSET) |
| sw t0, ENTROPY_SRC_CONF_REG_OFFSET(a0) |
| |
| li t0, (MULTIBIT_ASM_BOOL4_TRUE << ENTROPY_SRC_MODULE_ENABLE_MODULE_ENABLE_OFFSET) |
| sw t0, ENTROPY_SRC_MODULE_ENABLE_REG_OFFSET(a0) |
| |
| li a0, TOP_MATCHA_CSRNG_BASE_ADDR |
| li t0, (MULTIBIT_ASM_BOOL4_TRUE << CSRNG_CTRL_ENABLE_OFFSET) | \ |
| (MULTIBIT_ASM_BOOL4_TRUE << CSRNG_CTRL_SW_APP_ENABLE_OFFSET) | \ |
| (MULTIBIT_ASM_BOOL4_TRUE << CSRNG_CTRL_READ_INT_STATE_OFFSET) |
| sw t0, CSRNG_CTRL_REG_OFFSET(a0) |
| |
| li a0, TOP_MATCHA_EDN0_BASE_ADDR |
| li t0, (MULTIBIT_ASM_BOOL4_TRUE << EDN_CTRL_EDN_ENABLE_OFFSET) | \ |
| (MULTIBIT_ASM_BOOL4_TRUE << EDN_CTRL_BOOT_REQ_MODE_OFFSET) | \ |
| (MULTIBIT_ASM_BOOL4_FALSE << EDN_CTRL_AUTO_REQ_MODE_OFFSET) | \ |
| (MULTIBIT_ASM_BOOL4_FALSE << EDN_CTRL_CMD_FIFO_RST_OFFSET) |
| sw t0, EDN_CTRL_REG_OFFSET(a0) |
| |
| // Remove address space protections by configuring entry 15 as |
| // read-write-execute for the entire address space and then clearing |
| // all other entries. |
| // NOTE: This should happen before attemting to access any address outside |
| // the initial ePMP RX region at reset, e.g. `kDeviceType` which is in |
| // .rodata. |
| li t0, (0x9f << 24) // Locked NAPOT read-write-execute. |
| csrw pmpcfg3, t0 |
| li t0, 0x7fffffff // NAPOT encoded region covering entire 34-bit address space. |
| csrw pmpaddr15, t0 |
| csrw pmpcfg0, zero |
| csrw pmpcfg1, zero |
| csrw pmpcfg2, zero |
| #endif |
| // Scramble and initialize main memory (main SRAM). |
| // Memory accesses will stall until initialization is complete. |
| #ifndef PUPPETEER_ROM |
| // Skip SRAM initialization for DV sim device type, as the testbench handles |
| // this to optimize test run times. |
| lw t0, kDeviceType |
| beqz t0, .L_sram_init_skip |
| #endif |
| li a0, TOP_MATCHA_SRAM_CTRL_MAIN_REGS_BASE_ADDR |
| li t0, (1 << SRAM_CTRL_CTRL_INIT_BIT) |
| sw t0, SRAM_CTRL_CTRL_REG_OFFSET(a0) |
| |
| #ifndef PUPPETEER_ROM |
| .L_sram_init_skip: |
| #endif |
| // Zero out the `.bss` segment. |
| la a0, _bss_start |
| la a1, _bss_end |
| |
| #ifdef PUPPETEER_ROM |
| call crt_section_clear |
| |
| // Zero out the stack |
| la a0, _stack_start |
| la a1, _stack_end |
| #endif |
| call crt_section_clear |
| |
| // Initialize the `.data` segment from the `.idata` segment. |
| la a0, _data_start |
| la a1, _data_end |
| la a2, _data_init_start |
| call crt_section_copy |
| |
| // Clobber all temporary registers. |
| li t0, 0x0 |
| li t1, 0x0 |
| li t2, 0x0 |
| li t3, 0x0 |
| li t4, 0x0 |
| li t5, 0x0 |
| li t6, 0x0 |
| |
| // Clobber all argument registers. |
| li a0, 0x0 |
| li a1, 0x0 |
| li a2, 0x0 |
| li a3, 0x0 |
| li a4, 0x0 |
| li a5, 0x0 |
| li a6, 0x0 |
| li a7, 0x0 |
| |
| // Jump into the C program entry point. |
| call _boot_start |
| |
| // Enter a wait for interrupt loop, the device should reset shortly. |
| .L_wfi_loop: |
| wfi |
| j .L_wfi_loop |
| |
| #ifndef PUPPETEER_ROM |
| .size _start, .-_start |
| |
| // ----------------------------------------------------------------------------- |
| |
| /** |
| * Test ROM IRQ/exception handler; loops forever. |
| */ |
| .balign 4 |
| .section .text |
| .global _test_rom_irq_handler |
| .type _test_rom_irq_handler, @function |
| _test_rom_irq_handler: |
| wfi |
| j _test_rom_irq_handler |
| .size _test_rom_irq_handler, .-_test_rom_irq_handler |
| #endif |