polarfire-soc / polarfire-soc-documentation

PolarFire SoC Documentation
Other
37 stars 19 forks source link

Avoid resetting the target when loading an elf #11

Closed fcuzzocrea closed 2 years ago

fcuzzocrea commented 2 years ago

I am not sure where asking this, but I am putting it here with the hope of getting some sort of guidance.

I am using the Microsemi polarfire soc, to be more accurate, I am using the Microchip Polarfire ICICLE Kit and the version of openocd which comes with the latest version of Softconsole.

Versions Microchip SoftConsole version is v2021.1-6.6.0.507, while openocd version is 0.10.0+dev-00859-g95a8cd9b5-dirty (2020-10-21-21:16)

Problem What I would like to do is to be able to attach to a running program without resetting the board in order to load an elf into the memory (L2LIM) and start executing it.

In the normal use case scenario what I do is this:

Sadly however, when openocd connects it resets the soc, so I lost the initialization done by the bootloader, and when the app start executing I end up trapped in here

By default the microsemi-riscv.cfg file is doing

proc do_board_reset_init {}

what I have tried so far is to modify this file and instead of the aforementioned line I putted:

reset_config none

but neither this worked.

The command I am using with gdb to load the elf are:

    set arch riscv:rv64
    set mem inaccessible-by-default off
    target extended-remote localhost:3333
    monitor halt
    load
    monitor resume
    monitor shutdown
    quit

What I further tried is to modify my board/microsemi-riscv.cfg adding the following commands:

 $_TARGETNAME_0 configure -event gdb-flash-erase-start {
    # halt execution
    halt
}

$_TARGETNAME_0 configure -event gdb-flash-write-end {
    # resume execution after write
    resume
}

$_TARGETNAME_0 configure -event gdb-attach {
    # halt execution on debugger attach
    halt
}

My application does not start, but now it does not trap anymore, but it is just stucked somewhere in the code. I can say that because if I start again openocd and connect trough GDB I can see were it is stucked:

Reading symbols from build/debug/c3app.elf...
(gdb) set architecture riscv
riscv       riscv:rv32  riscv:rv64  
(gdb) set architecture riscv:rv64 
The target architecture is set to "riscv:rv64".
(gdb) set mem inaccessible-by-default off
(gdb) target extended-remote localhost:3333
Remote debugging using localhost:3333
MSS_RTC_reset_counter () at ../../ext/pfsoc_platform/drivers/mss/mss_rtc/mss_rtc.c:561
561     } while (upload_in_progress);

Is there any way to achieve my goal?

I tried to dig trough openOCD code but I didnt found anything. Furthermore I wasnt able to figure out where the sources of the openOCD version which is shipped with SoftConsole are stored.

hughbreslin commented 2 years ago

Hi @fcuzzocrea yes this should be possible, I'm not sure exactly what to do (wanted to get you a response at least!) - my reasoning is our provided debug configurations in softconsole, if you have a look below in the "all-harts debug" configuration "Initial reset" is selected along with "Load executable" to reset the target and download the application:

image

Whereas in the "all-harts attach" the target is not reset and the application is not downloaded:

image

I'll see if I can find out what deselecting these options translates into but if you can figure it out in the mean time go for it 😄

fcuzzocrea commented 2 years ago

Just a brief update to let you know that I was able to achieve my goal using ebreak. Probably it is just an hack, but maybe could be useful for someone else in future.

Basically I have created a wait_for_debugger() function:

void wait_for_debugger(HLS_DATA* hls, MODE_CHOICE mode_choice,
                       uint64_t next_addr)
{
    /* Store current hardid */
    uint32_t hartid = read_csr(mhartid);

    /* Restore PLIC to known state */
    __disable_irq();
    PLIC_init();

    /* Disable all interrupts: */
    write_csr(mie, 0);

    switch (mode_choice) {
    default:
    case M_MODE:
        /**
         * User application execution should now start and never return
         * here....
         */
        write_csr(mepc, next_addr);
        break;
    case S_MODE:
        /**
         * User application execution should now start and never return
         * here....
         */
        write_csr(mepc, next_addr);
        break;
    }

    register unsigned long a0 asm("a0") = hartid;
    register unsigned long a1 asm("a1") = (unsigned long)hls;

    /* Hold for debugger to upload the app */
    __asm__("ebreak");

    __asm__ __volatile__("mret" : : "r"(a0), "r"(a1));
    __builtin_unreachable();
}

Of course I know the value of next_addr as the entry point of the elf I want to load is the start of the LIM, so I can just hardcode it.

When my bootloader is started from a debugging environment (Trace32 or OpenOCD+GDB), it executes the function and then hits the ebreak, so wait for the application to be loaded in the LIM.

With GDB I do:

fcuzzocrea@Latitude-5420:~$ riscv64-unknown-elf-gdb build/debug/c3app.elf 
GNU gdb (GDB) 10.1
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=x86_64-pc-linux-gnu --target=riscv64-unknown-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Really redefine built-in command "remote"? (y or n) [answered Y; input not from terminal]
Reading symbols from build/debug/c3app.elf...
(gdb) set mem inaccessible-by-default off
(gdb) set $target_riscv=1
(gdb) set arch riscv:rv64
The target architecture is set to "riscv:rv64".
(gdb) target extended-remote localhost:3333
Remote debugging using localhost:3333
0x000000002022149a in ?? ()
(gdb) start
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Function "main" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n
Starting program: /home/fcuzzocrea/Documenti/Progetti/core3_template_app/build/debug/c3app.elf 
Disabling abstract command writes to CSRs.

Program received signal SIGTRAP, Trace/breakpoint trap.
0x0000000020221ed8 in ?? ()
(gdb) load
Loading section .text, size 0x22200 lma 0x8000000
Loading section .sdata, size 0x70 lma 0x8022200
Loading section .data, size 0x3930 lma 0x8022270
Loading section .sdram, size 0x1388 lma 0x8025ba0
Start address 0x0000000008000000, load size 159528
Transfer rate: 9 KB/sec, 13294 bytes/write.
(gdb) continue
Continuing.

And my application loads correctly.

As I said, this probably it is just an hack, and can hardly be integrated into an IDE to allow interactive debugging (because when the start is exectued the IDE GDB frontend crash), but at least it is working and I can use GDB from the CLI.

FWIW I also tried replacing the ebreak with a while loop, but when I attach and program the app on the LIM, once the app starts executing it just traps (I do not understand why tho).

hughbreslin commented 2 years ago

Hey, closing this issue as there has been no activity in several months. If this issue persists or you require more information please add a comment and we can re-open it 🙂