diff --git a/sw/device/silicon_creator/imm_rom_ext/BUILD b/sw/device/silicon_creator/imm_rom_ext/BUILD index 86d8cb1f26b6e..51587a60f0d95 100644 --- a/sw/device/silicon_creator/imm_rom_ext/BUILD +++ b/sw/device/silicon_creator/imm_rom_ext/BUILD @@ -57,6 +57,7 @@ ld_library( deps = [ "//hw/top_earlgrey/sw/autogen:top_earlgrey_memory", "//sw/device:info_sections", + "//sw/device/silicon_creator/lib/base:static_critical_sections", ], ) @@ -69,6 +70,7 @@ cc_library( hdrs = ["hello_world.h"], target_compatible_with = [OPENTITAN_CPU], deps = [ + "//sw/device/silicon_creator/lib/base:static_critical", "//sw/device/silicon_creator/lib/drivers:uart", ], ) @@ -85,6 +87,7 @@ opentitan_binary( linker_script = ":ld_hello_world", deps = [ ":hello_world", + "//sw/device/lib/crt", ], ) diff --git a/sw/device/silicon_creator/imm_rom_ext/hello_world.c b/sw/device/silicon_creator/imm_rom_ext/hello_world.c index 81b350269f418..00644725ca268 100644 --- a/sw/device/silicon_creator/imm_rom_ext/hello_world.c +++ b/sw/device/silicon_creator/imm_rom_ext/hello_world.c @@ -6,15 +6,27 @@ #include "sw/device/silicon_creator/lib/drivers/uart.h" +// These arrays are used to "HelloWorld!" to the UART console. +// o l l e H +uint64_t kArray1[8] = {0x6f6c6c6548}; +// The value will be updated in the main function. +uint64_t kArray2[8]; + void imm_rom_ext_main(void) { // Print "Immutable" to the UART console. // l b a t u m m I const uint64_t kStr1 = 0x6c626174756d6d49; - // e - const uint32_t kStr2 = 0x65; + // : e + const uint32_t kStr2 = 0x3a65; + const uint32_t kSpace = 0x20; const uint32_t kNewline = 0x0a0d; uart_write_imm(kStr1); uart_write_imm(kStr2); + uart_write_imm(kSpace); + // ! d l r o W + kArray2[0] += 0x21646c726f57; + uart_write_imm(kArray1[0]); // To test the .data section. + uart_write_imm(kArray2[0]); // To test the .bss section. uart_write_imm(kNewline); // Wait until the UART is done transmitting. diff --git a/sw/device/silicon_creator/imm_rom_ext/hello_world.ld b/sw/device/silicon_creator/imm_rom_ext/hello_world.ld index 47b757cded97d..6c45899b02531 100644 --- a/sw/device/silicon_creator/imm_rom_ext/hello_world.ld +++ b/sw/device/silicon_creator/imm_rom_ext/hello_world.ld @@ -6,6 +6,19 @@ * TODO(#24368): Adapt the linker script for real IMM_ROM_EXT. This linker * script only works for hello-world IMM_ROM_EXT. */ + +INCLUDE hw/top_earlgrey/sw/autogen/top_earlgrey_memory.ld + +/** + * Symbols to be used in the setup of the address translation for IMM_ROM_EXT. + */ + +MEMORY { + imm_rom_ext_virtual(rx) : ORIGIN = ORIGIN(rom_ext_virtual) + 0x400, LENGTH = 0x80000 - 0x400 +} + +REGION_ALIAS("rom_ext_flash", imm_rom_ext_virtual); + OUTPUT_ARCH(riscv) /** @@ -19,28 +32,131 @@ _dv_log_offset = 0x10000; ENTRY(_imm_rom_ext_start_boot) SECTIONS { - .rom_ext_immutable : ALIGN(4) { - /* Ibex */ - *(.vectors) - . = ALIGN(256); - /* CRT */ - *(.crt) - . = ALIGN(4); - /* Text */ + /** + * Ibex interrupt vector. + * + * This has to be set up at a 256-byte offset, so that we can use it with + * Ibex. + */ + .vectors : ALIGN(256) { + _text_start = .; + _rom_ext_immutable_start = .; + KEEP(*(.vectors)) + } > rom_ext_flash + + /** + * C runtime (CRT) section, containing program initialization code. + */ + .crt : ALIGN(4) { + KEEP(*(.crt)) + } > rom_ext_flash + + /** + * Standard text section, containing program code. + */ + .text : ALIGN(4) { *(.text) *(.text.*) + + /* Ensure section end is word-aligned. */ . = ALIGN(4); - /* Read-only Data */ + } > rom_ext_flash + + /** + * Shutdown text section, containing shutdown function(s). + * + * This must be the last executable section in the ROM_EXT flash image. + */ + .shutdown : ALIGN(4) { + *(.shutdown) + *(.shutdown.*) + + /* Ensure section end is word-aligned. */ + . = ALIGN(4); + _text_end = .; + } > rom_ext_flash + + /** + * Read-only data section, containing all large compile-time constants, like + * strings. + */ + .rodata : ALIGN(4) { + /* Small read-only data comes before regular read-only data for the same + * reasons as in the data section */ *(.srodata) *(.srodata.*) *(.rodata) *(.rodata.*) - . = ALIGN(4); + } > rom_ext_flash + + /** + * Critical static data that is accessible by both the ROM and the ROM + * extension. + */ + INCLUDE sw/device/silicon_creator/lib/base/static_critical.ld + + /** + * Mutable data section, at the bottom of ram_main. This will be initialized + * from flash at runtime by the CRT. + * + * Load this by copying the bytes from [_data_init_start, _data_init_end] into + * the range [_data_start, _data_end]. + */ + .data : ALIGN(4) { + _data_start = .; + _data_init_start = LOADADDR(.data); + + /* This will get loaded into `gp`, and the linker will use that register for + * accessing data within [-2048,2047] of `__global_pointer$`. + * + * This is much cheaper (for small data) than materializing the + * address and loading from that (which will take one extra instruction). + */ + __global_pointer$ = . + 2048; + + /* Small data should come before larger data. This helps to ensure small + * globals are within 2048 bytes of the value of `gp`, making their accesses + * hopefully only take one instruction. */ + *(.sdata) + *(.sdata.*) + + /* Other data will likely need multiple instructions to load, so we're less + * concerned about address materialisation taking more than one instruction. + */ *(.data) + *(.data.*) + + /* Ensure section end is word-aligned. */ . = ALIGN(4); + _data_end = .; + _data_init_end = LOADADDR(.data) + SIZEOF(.data); + _rom_ext_immutable_end = LOADADDR(.data) + SIZEOF(.data); + + /* This puts it in ram_main at runtime (for the VMA), but puts the section + * into flash for load time (for the LMA). This is why `_data_init_*` uses + * `LOADADDR`. + * + * Using `AT>` means we don't have to keep track of the next free part of + * flash, as we do in our other linker scripts. */ + } > ram_main AT> rom_ext_flash + + /** + * Standard BSS section. This will be zeroed at runtime by the CRT. + */ + .bss : ALIGN(4) { + _bss_start = .; + + /* Small BSS comes before regular BSS for the same reasons as in the data + * section */ + *(.sbss) + *(.sbss.*) *(.bss) + *(.bss.*) + + /* Ensure section end is word-aligned. */ . = ALIGN(4); - } + _bss_end = .; + } > ram_main INCLUDE sw/device/info_sections.ld } diff --git a/sw/device/silicon_creator/imm_rom_ext/hello_world_start.S b/sw/device/silicon_creator/imm_rom_ext/hello_world_start.S index f90d7a861da8c..cf382cf8cd5ae 100644 --- a/sw/device/silicon_creator/imm_rom_ext/hello_world_start.S +++ b/sw/device/silicon_creator/imm_rom_ext/hello_world_start.S @@ -2,13 +2,90 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -// TODO(#24368): Adapt the startup assembly for real IMM_ROM_EXT. This startup -// assembly only works for hello-world IMM_ROM_EXT. #include "hw/top_earlgrey/sw/autogen/top_earlgrey_memory.h" +#include "sw/device/lib/base/hardened_asm.h" + /** + * 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. + * + * This symbol is jumped to from `rom_boot` using the `entry_point` field + * of the manifest. + */ .balign 4 .global _imm_rom_ext_start_boot .type _imm_rom_ext_start_boot, @function _imm_rom_ext_start_boot: + + .option push + .option norelax + + /** + * Set up the global pointer `gp`. + */ + la gp, __global_pointer$ + + .option pop + + /** + * Save registers. + */ + addi sp, sp, -8 + sw ra, 4(sp) + + /** + * Disable Interrupts. + * + * We cannot disable exceptions, or Ibex's non-maskable interrupts (interrupt + * 31), so we still need to be careful. + */ + + // Clear `MIE` field of `mstatus` (disable interrupts globally). + csrci mstatus, 0x8 + + /** + * Clear all the machine-defined interrupts, `MEIE`, `MTIE`, and `MSIE` fields + * of `mie`. + */ + li t0, 0xFFFF0888 + csrc mie, t0 + + /** + * Setup C Runtime + */ + /** + * Initialize the `.data` section in RAM from ROM. + */ + la a0, _data_start + la a1, _data_end + la a2, _data_init_start + jal ra, crt_section_copy + + /** + * Initialize the `.bss` section. + * + * We do this despite zeroing all of SRAM above, so that we still zero `.bss` + * once we've enabled SRAM scrambling. + */ + la a0, _bss_start + la a1, _bss_end + jal ra, crt_section_clear + + + /** + * Restore registers. + */ + lw ra, 4(sp) + addi sp, sp, 8 + + /** + * Jump to IMM_ROM_EXT. + */ tail imm_rom_ext_main + .size _imm_rom_ext_start_boot, .-_imm_rom_ext_start_boot