I am trying to run a rust application on an Arduino R4 WiFi. There is a HAL at GitHub - atan2l/ra-hal: Renesas RA HAL, forked from https://git.sr.ht/~az1/ra-hal · GitHub, but the linker script does not appear to be verified. I'm willing to put in the work to create a functional linker script, but I've never done this before; does anyone know where I can find a reference for the memory.x file format so that I can actually know what I'm doing? Thanks in advance!
what do you mean by "verified"? do you mean the memory layout agrees with the specific hardware model?
the memory.x is a config file that is typically provided by the appication developer, and many chip or board support libraries (a.k.a. hal crates) also provides a default config for common use cases, but it can be overriden if the app needs to customize the linking process. also, tools may override the default config for their purpose, one such example is flip-link, you can read the source code to see how it works:
the memory.x file is "include"-ed from the master linker script, which is typically defined in the architecture runtime crate. I looked up ra4m1, and it is a cortex-m4 microcontroller, so the runtime crate should be cortex-m-rt, and here's its documentation about memory.x:
if you want to see the full master linker script, the source code is here. note it's a template because it needs some preprocessing work which is done in build.rs.
Correct. The file in the HAL crate has 2 parts, one uncommented and one commented out. The uncommented portion agreed with the script I wrote based on the memory map in the manual, but using this bricked my device because there is an OSM section inside of the on-chip flash section and overwriting it made it impossible to re-flash the device.
The commented out section has some stuff that plausibly looks like it accounts for the OSM section but I don't know how to read it properly. For example, it has the line SEC_MPU : ORIGIN = 0x408, LENGTH = 4 * 13 - I don't know what meaning, if any, the symbol SEC_MPU has in the linker script. The documentation in the cortex_m_rt crate that you linked to doesn't mention this symbol at all. The full master script has some interesting information, but still does not clarify these symbols. The fact that the commented out section begins with the phrase "Could look a little like this" does not instill me with confidence.
the symbol does not has pre-defined meanings, as far as the master linker script (thus the linker) is concerned. you can define custom regions and symbols to suit the application needs, but these are not required.
cortex-m-rt's build configuration expects there's at least a ROM region (named FLASH) and a RAM region. it puts all the sections containing code and readonly data into FLASH, and put the stack, heap, and mutable static variables (.data and .bss sections) into RAM. note, the .data section contains non-zero static variables, and is linked with its VMA in RAM, but its LMA placed in ROM.
most importantly, the runtime crate contains the reset and exception handler entries, and it puts the vector table at the start of the FLASH region. if your chip cannot be configured like this, you'll have to use a modified linker script, remember to change the -Tlink.x linker flag in this case, which is typcally set in the workspace .cargo/config.toml file.
since I'm not familar with the chip model you are using, I can't give you concrete advices, but I think I can describe some of the concepts using examples that I do know well.
here's a simple example for a nrf52832 device, where a portion of the memory (both ROM and RAM) is reserved for softdevice (a proprietary blob containing the chip vendor's bluetooth stack and some low level code), so the rust app code is linked and placed at an offset:
in this case, the app's vector table is placed at an offset, whoes value depends on the version of softdevice being used. the "real" vector table is defined by the vendor's bootloader, referred to as mbr.
note, you don't need to use the vendor's bootloader code if you are not using softdevice (technically, you don't need the bootloader even if you use softdevice, but I never tried that).
here's another example of custom regions being used. the nrf52840 chip has 1 MiB on-chip flash, this test application reserved several pages at the end of flash as non-volatile storage for config data. the memory.x defines an extra CONFIG region in addition to the mandatory FLASH and RAM, and exports the address as the _config symbol:
in the app code, it imports (renamed via the #[link_name] attribute) the _config symbol as an extern "C" byte array:
and here's another even more complicated setup. the rp2040's on-chip bootrom is factory fused and not programmable, user code are stored in an external flash chip connected to the mcu via Quad-SPI interface (or Dual-SPI, or even single SPI, depending on the hardware design).
normal code is expected to run in xip mode, but the bootrom does not know the correct configuration for every possible external flash chips, so it uses a very conservative method (slow but maximally compatible, non xip mode) to load the first 256 bytes from the external flash, which is called BOOT2. BOOT2 then configures the qspi controller into xip mode and jumps to the app code.
the external flash is mapped to address 0x1000_0000, note memory.x puts the FLASH region at offset 256, while the first 256 bytes are defined as a separate BOOT2 region:
the actual boot2 is included as a blob in the app (or bsp) code, annotated with the #[link_section = ".boot2"] attribute:
finally, memory.x also defines the .boot2 section and inserts it before the .text section (defined in the master linker script):
btw, if you need an even more complex config, you can check this example memory.x, but I can't explain all of it in short words, so you'll have to refer to the datasheet if you are not already familiar with rp2040:
Thank you for the detailed notes! I think this is enough for me to try a new linker script, but I won't be able to test until my new arduino arrives.