From cca24e0b35c8ed0ffe9dda0674bf9e6405677fd9 Mon Sep 17 00:00:00 2001 From: Maciej Nowak Date: Thu, 12 May 2022 18:32:43 +0200 Subject: [PATCH] JTAG trampoline for running HSS over JTAG Signed-off-by: Maciej Nowak --- Makefile | 1 + jtag_trampoline/Makefile | 64 ++++++ jtag_trampoline/README.md | 18 ++ jtag_trampoline/jtag_trampoline.ld | 257 ++++++++++++++++++++++++ jtag_trampoline/jtag_trampoline_crt.S | 126 ++++++++++++ jtag_trampoline/jtag_trampoline_funcs.c | 51 +++++ jtag_trampoline/run-hss.cfg | 20 ++ 7 files changed, 537 insertions(+) create mode 100644 jtag_trampoline/Makefile create mode 100644 jtag_trampoline/README.md create mode 100644 jtag_trampoline/jtag_trampoline.ld create mode 100644 jtag_trampoline/jtag_trampoline_crt.S create mode 100644 jtag_trampoline/jtag_trampoline_funcs.c create mode 100644 jtag_trampoline/run-hss.cfg diff --git a/Makefile b/Makefile index 5627f5c2..e79628a2 100644 --- a/Makefile +++ b/Makefile @@ -85,6 +85,7 @@ DEPENDENCIES+=include/tool_versions.h endif include envm-wrapper/Makefile +include jtag_trampoline/Makefile ################################################################################################ # diff --git a/jtag_trampoline/Makefile b/jtag_trampoline/Makefile new file mode 100644 index 00000000..b3404f97 --- /dev/null +++ b/jtag_trampoline/Makefile @@ -0,0 +1,64 @@ +# +# MPFS HSS Embedded Software +# +# Copyright 2019-2021 Microchip Corporation. +# +# SPDX-License-Identifier: MIT +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. +# +# +# Boot HSS over JTAG trampoline + + +OBJS-jtag_trampoline = \ + jtag_trampoline/jtag_trampoline_crt.o \ + jtag_trampoline/jtag_trampoline_funcs.o \ + baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/mss_l2_cache.o + +EXTRA_OBJS-jtag_trampoline= + +LINKER_SCRIPT-jtag_trampoline = jtag_trampoline/jtag_trampoline.ld + +jtag_trampoline/jtag_trampoline_crc.o: CFLAGS=$(CFLAGS_GCCEXT) +jtag_trampoline/jtag_trampoline_funcs.o: CFLAGS=$(CFLAGS_GCCEXT) + +$(TARGET-jtag_trampoline): LIBS:= +$(TARGET-jtag_trampoline): $(OBJS-jtag_trampoline) $(BINDIR)/run-hss.cfg + $(call main-build-target,jtag_trampoline) + @$(ECHO) " HEX `basename $@ .elf`.hex"; + $(OBJCOPY) -O ihex $(BINDIR)/$@ $(BINDIR)/`basename $@ .elf`.hex + $(SIZE) $(BINDIR)/$(TARGET-jtag_trampoline) 2>/dev/null + +jtag_trampoline_clean: + -$(RM) $(COMPRESSED_TARGET) $(OBJS-jtag_trampoline) $(BINDIR)/$(TARGET-jtag_trampoline) $(BINDIR)/`basename $(TARGET-jtag_trampoline) .elf`.sym $(BINDIR)/`basename $(TARGET-jtag_trampoline) .elf`.bin + +HEX_FILE-jtag_trampoline=$(BINDIR)/$(TARGET-jtag_trampoline:.elf=.hex) +BIN_FILE-jtag_trampoline=$(BINDIR)/$(TARGET-jtag_trampoline:.elf=.bin) + +BIN_FILE-jtag_trampoline: $(TARGET-jtag_trampoline) + +COPY_CMD := cp + +ifeq ($(OS),Windows_NT) + COPY_CMD := cmd /c copy +endif + +$(BINDIR)/run-hss.cfg: jtag_trampoline/run-hss.cfg + $(SHELL) -c "cp jtag_trampoline/run-hss.cfg $(BINDIR)/run-hss.cfg" diff --git a/jtag_trampoline/README.md b/jtag_trampoline/README.md new file mode 100644 index 00000000..5a24731d --- /dev/null +++ b/jtag_trampoline/README.md @@ -0,0 +1,18 @@ +# HSS-over-JTAG +During development it might be useful to run HSS in boot mode 0 and without need to write HSS executable to eNVM. HSS itself is running from L2 scratchpad but there are some initialization steps required for HSS to execute correctly. In bootmodes 1..3 that initialization is performed by `envm-wrapper`. In bootmode 0 `jtag_trampoline` with OpenOCD script can be used to achieve the same results. + +## Running HSS-over-JTAG +1. Build HSS binaries. +2. Connect debug adapter to target +3. Execute OpenOCD command: `openocd -f -c "set HSS_DIR /Default" -f /Default/run-hss.cfg` +4. HSS will be started + + +## Details of operation +1. `hss-jtag_trampoline.hex` is loaded into E51 DTIM and E51 ITIM memories +2. Harts are resumed starting from address `0x01800000` (E51 ITIM). OpenOCD hangs on `wait_halt` command. +3. HSS initialization steps are performed: L2 scratchpad configuration, clocks setups +4. `ebreak` instruction is invoked. OpenOCD command `wait_halt` ends and resumes script. +5. `hss-l2scratch.bin` is loaded into L2 scratchpad area. +6. Harts are resumed from address `0x0A000000`. +7. HSS is running diff --git a/jtag_trampoline/jtag_trampoline.ld b/jtag_trampoline/jtag_trampoline.ld new file mode 100644 index 00000000..927acada --- /dev/null +++ b/jtag_trampoline/jtag_trampoline.ld @@ -0,0 +1,257 @@ +/******************************************************************************* + * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MPFS HAL Embedded Software + * + */ +/******************************************************************************* + * + * file name : mpfs_lim.ld + * Used when debugging code. The debugger loads the code to LIM. + * + * You can find details on the PolarFireSoC Memory map in the mpfs-memory-hierarchy.md + * which can be found under the link below: + * https://github.com/polarfire-soc/polarfire-soc-documentation + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +/*----------------------------------------------------------------------------- + +-- MSS hart Reset vector + +The MSS reset vector for each hart is stored securely in the MPFS. +The most common usage will be where the reset vector for each hart will be set +to the start of the envm at address 0x2022_0100, giving 128K-256B of contiguous +non-volatile storage. Normally this is where the initial boot-loader will +reside. (Note: The first 256B page of envm is used for metadata associated with +secure boot. When not using secure boot (mode 0,1), this area is still reserved +by convention. It allows easier transition from non-secure to secure boot flow +during the development process. +When debugging a bare metal program that is run out of reset from envm, a linker +script will be used whereby the program will run from LIM instead of envm. +In this case, the reset vector in the linker script is normally set to the +start of LIM, 0x0800_0000. +This means you are not continually programming the envm each time you load a +program and there is no limitation with break points when debugging. +See the mpfs-lim.ld example linker script when runing from LIM. + + +------------------------------------------------------------------------------*/ + +MEMORY +{ + dtim (rwx) : ORIGIN = 0x01000000, LENGTH = 8k + e51_itim (rwx) : ORIGIN = 0x01800000, LENGTH = 28k + scratchpad(rwx) : ORIGIN = 0x0A000000, LENGTH = 256k + + l2lim (rwx) : ORIGIN = 0x08000000, LENGTH = 1920k + l2zerodevice (rwx) : ORIGIN = 0x0A000000, LENGTH = 512k +} + +HEAP_SIZE = 0k; /* needs to be calculated for your application if using */ +PROVIDE(STACK_SIZE_PER_HART = 4k); + +/* STACK_SIZE_PER_HART needs to be calculated for your */ +/* application. Must be aligned */ +/* Also Thread local storage (AKA hart local storage) allocated for each hart */ +/* as part of the stack +/* So memory map will look like once apportion in startup code: */ +/* */ +/* stack hart0 Actual Stack size = (STACK_SIZE_PER_HART - HLS_DEBUG_AREA_SIZE) */ +/* TLS hart 0 */ +/* stack hart1 */ +/* TLS hart 1 */ +/* etc */ +/* note: HLS_DEBUG_AREA_SIZE is defined in mss_sw_config.h */ +/* STACK_SIZE_PER_HART = 8k; */ + +/* + * There is common area for shared variables, accessed from a pointer in a harts HLS + */ +SIZE_OF_COMMON_HART_MEM = 128; + +/* + * Stack size for each hart's application. + * These are the stack sizes that will be allocated to each hart before starting + * each hart's application function, e51(), u54_1(), u54_2(), u54_3(), u54_4(). + */ +STACK_SIZE_E51_APPLICATION = 2k; + + +SECTIONS +{ + PROVIDE(__dtim_start = ORIGIN(dtim)); + PROVIDE(__dtim_end = ORIGIN(dtim) + LENGTH(dtim)); + PROVIDE(__e51itim_start = ORIGIN(e51_itim)); + PROVIDE(__e51itim_end = ORIGIN(e51_itim) + LENGTH(e51_itim)); + + PROVIDE(__l2lim_start = ORIGIN(l2lim)); + PROVIDE(__l2lim_end = ORIGIN(l2lim) + LENGTH(l2lim)); + PROVIDE(__l2_start = ORIGIN(l2zerodevice)); + PROVIDE(__l2_end = ORIGIN(l2zerodevice) + LENGTH(l2zerodevice)); + + /* text: text code section */ + + .text : ALIGN(0x10) + { + __text_load = LOADADDR(.text); + __text_start = .; + *(.entry) + *(.text.init) + . = ALIGN(0x10); + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + + . = ALIGN(0x10); + __text_end = .; + . = ALIGN(0x10); + } > e51_itim + + .l2_scratchpad : ALIGN(0x10) + { + . = ALIGN (0x10); + __l2_scratchpad_load = LOADADDR(.l2_scratchpad); + __l2_scratchpad_start = .; + __l2_scratchpad_vma_start = .; + *(.l2_scratchpad) + . = ALIGN(0x10); + __l2_scratchpad_end = .; + __l2_scratchpad_vma_end = .; + } >scratchpad AT> e51_itim + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + /* offset used with gp(gloabl pointer) are +/- 12 bits, so set point to middle of expected sdata range */ + /* If sdata more than 4K, linker used direct addressing. Perhaps we should add check/warning to linker script if sdata is > 4k */ + __global_pointer$ = . + 0x800; + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > dtim AT>e51_itim + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > dtim AT>e51_itim + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > dtim + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > dtim + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > dtim + + /* must be on 4k boundary- corresponds to page size */ + .stack : ALIGN(0x1000) + { + PROVIDE(__stack_bottom_h0$ = .); + PROVIDE(__app_stack_bottom_h0 = .); + . += STACK_SIZE_E51_APPLICATION; + PROVIDE(__app_stack_top_h0 = .); + PROVIDE(__stack_top_h0$ = .); + + } > dtim + + /* + * memory shared accross harts. + * The boot Hart Local Storage holds a pointer to this area for each hart if + * when enabled by setting MPFS_HAL_SHARED_MEM_ENABLED define in the + * mss_sw_config.h + */ + .app_hart_common : /* ALIGN(0x1000) */ + { + PROVIDE(__app_hart_common_start = .); + . += SIZE_OF_COMMON_HART_MEM; + PROVIDE(__app_hart_common_end = .); + } > dtim + + /* + * These are unused it the bootloader program but need to be preset for + * compilation, as used in non-bootloader function. + */ + .unused_non_bootloader : ALIGN(0x10) + { + PROVIDE(__uninit_bottom$ = .); + PROVIDE(__uninit_top_h$ = .); + PROVIDE(__app_stack_bottom = .); + PROVIDE(__app_stack_top = .); + PROVIDE(__uninit_top_h$ = .); + } > dtim + + __dtim_trampoline_end = .; +} diff --git a/jtag_trampoline/jtag_trampoline_crt.S b/jtag_trampoline/jtag_trampoline_crt.S new file mode 100644 index 00000000..da550cf5 --- /dev/null +++ b/jtag_trampoline/jtag_trampoline_crt.S @@ -0,0 +1,126 @@ +#include "config.h" +#include +#include +#include +#include +#include + + + .section .entry, "ax", @progbits + .attribute unaligned_access, 0 + .attribute stack_align, 16 + .align 3 + .globl _start + +_start: + #j _start + la t0, .early_trap_handler + csrw CSR_MTVEC, t0 + li ra, 0 +.reset_regs: + // flush the instruction cache + fence.i + + // Reset all registers except ra, a0, a1 and a2 + li gp, 0 + li sp, 0 + li tp, 0 + li t0, 0 + li t1, 0 + li t2, 0 + li s0, 0 + li s1, 0 + li a3, 0 + li a4, 0 + li a5, 0 + li a6, 0 + li a7, 0 + li s2, 0 + li s3, 0 + li s4, 0 + li s5, 0 + li s6, 0 + li s7, 0 + li s8, 0 + li s9, 0 + li s10, 0 + li s11, 0 + li t3, 0 + li t4, 0 + li t5, 0 + li t6, 0 + csrw CSR_MSCRATCH, 0 + +.configure: + li a0, 0 + la a1, 0 + + la s8, STACK_SIZE_PER_HART + csrr a0, CSR_MHARTID + + la tp, __stack_bottom_h0$ + 63 + and tp, tp, -64 + li a1, 1 + +.setup_stack: + mul a2, s8, a0 + add tp, tp, a2 + la sp, STACK_SIZE_PER_HART + add sp, sp, tp + +.disable_and_clear_interrupts: + csrw CSR_MIE, zero # disable all interrupts + csrw CSR_MIP, zero # clear all interrupts + +.do_work: + call config_l2_cache + call .clear_dtim + call .clear_l2lim + call .clear_l2scratchpad + call HSS_Setup_Clocks + ebreak + +.done: + j . + + .align 3 +.early_trap_handler: + j .early_trap_handler + +.clear_l2scratchpad: + // Clear the LIM + // + // On reset, the first 15 ways are L2 and the last way is cache + // We can initialize all, as cache write through to DDR is blocked + // until DDR is initialized, so will have no effect other than clear ECC + // + // NOTE: we need to check if we are debugging from LIM,if so do not initialize + la a4, __l2_start + la a5, __l2_end + j 1f +.clear_l2lim: + // Clear the LIM + // + // On reset, the first 15 ways are L2 and the last way is cache + // We can initialize all, as cache write through to DDR is blocked + // until DDR is initialized, so will have no effect other than clear ECC + // + // NOTE: we need to check if we are debugging from LIM,if so do not initialize + // + la a4, __l2lim_start + la a5, __l2lim_end + j 1f +.clear_dtim: + // + // Clear the E51 DTIM to prevent any memory errors on initial access + // to the cache + // + la a4, __dtim_trampoline_end + la a5, __dtim_end +1: + // common loop used by both .clear_l2lim and .clear_dtim + REG_S x0, 0(a4) + add a4, a4, __SIZEOF_POINTER__ + blt a4, a5, 1b +.done_clear: + ret \ No newline at end of file diff --git a/jtag_trampoline/jtag_trampoline_funcs.c b/jtag_trampoline/jtag_trampoline_funcs.c new file mode 100644 index 00000000..7484d24e --- /dev/null +++ b/jtag_trampoline/jtag_trampoline_funcs.c @@ -0,0 +1,51 @@ +#include +#include +#include "mpfs_hal/mss_hal.h" + +bool HSS_Setup_Clocks(void); + +bool HSS_Setup_Clocks(void) +{ + static const uint32_t hss_subblk_clock_Config = 0xFFFFFFFFu; + const uint32_t hss_soft_reset_Config = SYSREG->SOFT_RESET_CR & + ~( + SOFT_RESET_CR_SGMII_MASK | + SOFT_RESET_CR_CFM_MASK | + SOFT_RESET_CR_ATHENA_MASK | + SOFT_RESET_CR_FIC3_MASK | + SOFT_RESET_CR_FIC2_MASK | + SOFT_RESET_CR_FIC1_MASK | + SOFT_RESET_CR_FIC0_MASK | + SOFT_RESET_CR_DDRC_MASK | + SOFT_RESET_CR_GPIO2_MASK | + SOFT_RESET_CR_GPIO1_MASK | + SOFT_RESET_CR_GPIO0_MASK | + SOFT_RESET_CR_QSPI_MASK | + SOFT_RESET_CR_RTC_MASK | + SOFT_RESET_CR_FPGA_MASK | + SOFT_RESET_CR_USB_MASK | + SOFT_RESET_CR_CAN1_MASK | + SOFT_RESET_CR_CAN0_MASK | + SOFT_RESET_CR_I2C1_MASK | + SOFT_RESET_CR_I2C0_MASK | + SOFT_RESET_CR_SPI1_MASK | + SOFT_RESET_CR_SPI0_MASK | + SOFT_RESET_CR_MMUART4_MASK | + SOFT_RESET_CR_MMUART3_MASK | + SOFT_RESET_CR_MMUART2_MASK | + SOFT_RESET_CR_MMUART1_MASK | + SOFT_RESET_CR_MMUART0_MASK | + SOFT_RESET_CR_TIMER_MASK | + SOFT_RESET_CR_MMC_MASK | + SOFT_RESET_CR_MAC1_MASK | + SOFT_RESET_CR_MAC0_MASK | + SOFT_RESET_CR_ENVM_MASK); + + SYSREG->SOFT_RESET_CR = 0x3FFFFFFEu; // everything but ENVM + SYSREG->SOFT_RESET_CR = hss_soft_reset_Config; + SYSREG->SUBBLK_CLOCK_CR = hss_subblk_clock_Config; + + SYSREG->FABRIC_RESET_CR = FABRIC_RESET_CR_ENABLE_MASK; + + return true; +} diff --git a/jtag_trampoline/run-hss.cfg b/jtag_trampoline/run-hss.cfg new file mode 100644 index 00000000..e15af2fa --- /dev/null +++ b/jtag_trampoline/run-hss.cfg @@ -0,0 +1,20 @@ +if {![exists HSS_DIR]} { + error "HSS_DIR variable not set. Use set HSS_DIR