How can I assign a value to the stack pointer of an ARM chip in Rust?

I am trying to write a bootloader for STM32 in Rust, and I cannot figure out how to properly populate the stack pointer. Next, as I can say, the code should be:

asm!("MOV SP, $0" :: "0"(stack_pointer)); // set the stack pointer 

but the compiler does not agree:

 error: invalid operand in inline asm: 'MOV SP, $0' --> src/main.rs:38:5 | 38 | asm!("MOV SP, $0" :: "0"(stack_pointer)); // set the stack pointer | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: <inline asm>:1:11: error: unexpected token in operand MOV SP, ^ --> src/main.rs:38:5 | 38 | asm!("MOV SP, $0" :: "0"(stack_pointer)); // set the stack pointer | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

What am I doing wrong? He seems to be complaining about the dollar sign, but I got it directly from the documentation .

In the conversation in the comments, I tried two things, both of which compile (!), But none of them work (but this may be for some one billionth reason that is still working on it):

Version A:

 asm!("MOV R0, #0x0800"); asm!("LSL R0, R0, #16"); asm!("MOV R1, #0x8000"); asm!("ORR R2, R1, R0"); asm!("LDRT R0, [R2]"); asm!("MOV SP, R0"); entry_point() 

Version B:

 #[inline(never)] unsafe fn go(_addr: u32, entry_point: fn()->()) { asm!("MOV SP, R0"); entry_point() } 
+5
source share
2 answers

I think you have two problems:

  • figure out what the assembly code should look like at the end.
  • how to create it from rust.

The second part seems easy with global_asm! :

 #![feature(global_asm)] global_asm!(r#" .global go go: mov sp, r0 bx r1 "#); extern "C" { pub fn go(addr: u32, entry_point: extern fn()); } 

or with normal asm! :

 #![feature(asm)] #[no_mangle] pub unsafe fn go(addr: u32, entry_point: fn()) { asm!("mov sp, r0" :: "{r0}"(addr) : "sp"); entry_point() } 

I think the "0"(stack_pointer) not working because stack_pointer not a constant.

Your version of B contains the same ASM code; but it really should mean "sp" as clobbered, and "{r0}"(addr) ensures that the first argument is indeed in r0 .

Clifford seems to prefer passing a pointer to a "vector table", which might look like this:

 #[repr(C)] pub struct VectorTable { stack_pointer: u32, entry_point: extern fn() -> !, } global_asm!(r#" .global go go: ldr sp, [r0] ldr pc, [r0, #4] "#); extern "C" { pub fn go(vt: &VectorTable) -> !; } 
+3
source

As a result, I came across an implementation of @stefan @clifford approach and the following code to call it:

 let firmware_address = 0x08008000u32; unsafe { let scb = &*stm32f40x::SCB::ptr(); scb.vtor.write(firmware_address); asm::isb(); go(&*(firmware_address as *const VectorTable)); } 
0
source

Source: https://habr.com/ru/post/1275555/


All Articles