Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GD32VF103] Jump to embedded bootloader from user code #29

Closed
KarlK90 opened this issue Jul 5, 2021 · 5 comments
Closed

[GD32VF103] Jump to embedded bootloader from user code #29

KarlK90 opened this issue Jul 5, 2021 · 5 comments

Comments

@KarlK90
Copy link
Contributor

KarlK90 commented Jul 5, 2021

I'm wondering if it is possible to jump to the embedded bootloader that is present at 0x1FFFB000 in the devices ROM without a reset and externally pulling Boot0 high?

So far I have tried to jump to 0x1FFFB000 immediately after the device has been reset in the startup code. Observing the execution path with a debugger I can confirm that this indeed produced a valid jump, but the bootloader code is not executed successfully e.g. with a USB connection it doesn't show up as a USB-DFU device.

I know that this is possible with STM32F103 and GD32F103, so there is a chance that this possible as well?

@fanghuaqi
Copy link
Member

Hi @KarlK90 , I also didn't know what is happening in gd32v bootrom(it is not a chip made by Nuclei, we just provided RISC-V CORE ip to Gigabyte), maybe you need to check the datasheet for more details.

@KarlK90
Copy link
Contributor Author

KarlK90 commented Jul 6, 2021

@fanghuaqi Thanks for clarification! I share my findings with you or others that maybe have the same question.

Some further investigation in the disassembly of the bootloader revealed that it wasn't compiled to be position independent. E.g in the startup assembly the gp and sp pointers are calculated from the current pc which produces invalid addresses if the bootloader is not aliased to 0x0. Unfortunately there is no way to change the memory aliasing at runtime (like on some STM32 with the SYSCFG register).

I tried to rewrite the startup code and vector table with the correct values and jump over the original startup assembly. but it just traps at runtime. Maybe I did an error but it seems ATM as if this is just not possible with the current bootloader code.

See below update.

; Init gp
0x0000018c      auipc gp, 0x20001
0x00000190      addi gp, gp, -684
; Bootloader running from 0x1FFFB000 gives invalid address
; 0x1FFFB18C + 0x20001000 = 0x3FFFBEE0
;
; Bootloader running from 0x0 gives valid address
; 0x0000018C + 0x20001000 = 0x20000EE0
;
; Init sp
0x00000194      auipc sp, 0x20001
0x00000198      addi sp, sp, 1644  
; Bootloader running from 0x1FFFB000 gives invalid address
; 0x1FFFB194 + 0x20001000  + 1644 = 0x3FFFC800
;
; Bootloader running from 0x0 gives valid address
; 0x00000194 + 0x20001000 + 1644 = 0x20001800
rewritten startup assembly
#define BOOTLOADER_ADDRESS 0x1FFFB000
#define VECTOR_TABLE_BASE 0x20001800 // Address needs 512 Byte alignment
#define VECTOR_TABLE_END (VECTOR_TABLE_BASE + (87 * 4))

#define VECTOR_TIMER2_OFFSET (0xC0 + VECTOR_TABLE_BASE)
#define VECTOR_TIMER2_ADDR (0x216C + BOOTLOADER_ADDRESS)

#define VECTOR_USART0_OFFSET (0xE0 + VECTOR_TABLE_BASE)
#define VECTOR_USART0_ADDR (0x20CC + BOOTLOADER_ADDRESS)

#define VECTOR_USART1_OFFSET (0xE4 + VECTOR_TABLE_BASE)
#define VECTOR_USART1_ADDR (0x211C + BOOTLOADER_ADDRESS)

#define VECTOR_USBFS_OFFSET (0x158 + VECTOR_TABLE_BASE)
#define VECTOR_USBFS_ADDR (0x20B4 + BOOTLOADER_ADDRESS)

/*
* Set the the NMI base mnvec to share
* with mtvec by setting CSR_MMISC_CTL
* bit 9 NMI_CAUSE_FFF to 1
*/
li t0, MMISC_CTL_NMI_CAUSE_FFF
csrs CSR_MMISC_CTL, t0

/*
* Intialize ECLIC vector interrupt
* base address mtvt to bootloader entry
*/
la t0, VECTOR_TABLE_BASE
csrw CSR_MTVT, t0

/*
* Set ECLIC non-vector entry to be controlled
* by mtvt2 CSR register.
* Intialize ECLIC non-vector interrupt
* base address mtvt2 to irq_handler.
*/
#define IRQ_HANDLER 0x1FFFD1C4
la t0, IRQ_HANDLER
csrw CSR_MTVT2, t0
csrs CSR_MTVT2, 0x1

/* Set the interrupt processing mode to ECLIC mode */
li t0, 0x3f
csrc CSR_MTVEC, t0
csrs CSR_MTVEC, 0x3

/* Set Exception Entry MTVEC */
#define EXCEPTION_HANDLER 0x1FFFD180
la t0, EXCEPTION_HANDLER
csrw CSR_MTVEC, t0

/* Set bootloader global pointer */
la gp, 0x20000EE0 /* 0x20001000+0x18c-684 */

/* Set bootloader stack pointer */
la sp, 0x20001800 /*0x20001000+0x194+1644*/

#define DATA_BASE 0x20000000 /* 0x20000000 + 0x1a4 - 420 */
#define DATA_END  0x20000708 /* 0x20000000 + 0x1ac + 1372 */
#define DATA_ROM  0x1FFFED14 /* 0x4000 + 0x19c - 1160 + BOOTLOADER_ADDRESS */

/* Data initialization. */

la      a0, DATA_ROM
la      a1, DATA_BASE 
la      a2, DATA_END
dloop_boot:
bge     a1, a2, enddloop_boot
lw      a3, 0(a0)
sw      a3, 0(a1)
addi    a0, a0, 4
addi    a1, a1, 4
j       dloop_boot
enddloop_boot:

#define BSS_BASE 0x20000708 /* 0x20000000 + 0x1c8 + 1344 */
#define BSS_END 0x20001270 /* gp + 912 = 0x20000EE0 + 912  */

/* BSS initialization. */
la      a1, BSS_BASE
la      a2, BSS_END
bloop_boot:
bge     a1, a2, endbloop_boot
sw      zero, 0(a1)
addi    a1, a1, 4
j       bloop_boot
endbloop_boot:

/* Reconstruct vector table. */
la      a1, VECTOR_TABLE_BASE
la      a2, VECTOR_TABLE_END
vloop_boot:
bge     a1, a2, endvloop_boot
sw      zero, 0(a1)
addi    a1, a1, 4
j       vloop_boot
endvloop_boot:

la a1 , VECTOR_TIMER2_OFFSET
la a2, VECTOR_TIMER2_ADDR
sw a2, 0(a1)

la a1 , VECTOR_USART0_OFFSET
la a2, VECTOR_USART0_ADDR
sw a2, 0(a1)

la a1 , VECTOR_USART1_OFFSET
la a2, VECTOR_USART1_ADDR
sw a2, 0(a1)

la a1 , VECTOR_USBFS_OFFSET
la a2, VECTOR_USBFS_ADDR
sw a2, 0(a1)

/* Jump into bootloader after inti section. */
la a0, (BOOTLOADER_ADDRESS + 0x1E2)
jr a0

@KarlK90
Copy link
Contributor Author

KarlK90 commented Jul 6, 2021

Actually I got the numbers for the data section wrong and the vector table was outside the SRAM region... After updating the numbers the bootloader doesn't trap anymore and tries to enumerate as a USB device now. But it fails the setup, the code is caught in a loop. This is very similar to the behavior often seen when putting the device into bootloader mode via BOOT0 pin.

[ 8837.860409] usb 1-1.3: new full-speed USB device number 9 using xhci_hcd
[ 8837.968448] usb 1-1.3: device descriptor read/64, error -32
[ 8838.156448] usb 1-1.3: device descriptor read/64, error -32
[ 8838.262241] usb 1-1-port3: attempt power cycle

@fanghuaqi
Copy link
Member

Hi @KarlK90 , sorry I can't give you more help with this issue, I didn't know too much details in side the bootrom of gd32v.

@KarlK90
Copy link
Contributor Author

KarlK90 commented Jul 12, 2021

@fanghuaqi no problem, as stated above jumping into the bootloader is not an easily accomplished. Therefore I have started to port the tinyuf2 userland bootloader for the GD32VF103. There are some problems with the USB peripheral, but when this is sorted this should solve my problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants