ARM bootloader: the value of TEXT_BASE - arm

It's important to calculate correctly the value of TEXT_BASE when we begin to program the bootloader, but I haven't found a tutorial well explaining how to find this value according to platform datasheet or other materials. For example, for arm920t and sumsang s3c24x0, u-boot defines TEXT_BASE=0x33F80000 with this reason:
SMDK2410 has 1 bank of 64 MB DRAM
3000'0000 to 3400'0000
Linux-Kernel is expected to be at 3000'8000, entry 3000'8000 optionally with a ramdisk at 3080'0000
we load ourself to 33F8'0000
download area is 3300'0000
Can anyone explain the logic? Thanks!
ps: I also hope to know the memory layout of u-boot after load into the ram, the address of each data/instruction part, bss, rodata,zi, etc and the size. I expecte someone offer me some concerning tutorials to anaylyse, thank you!

TEXT_BASE is, unsurprisingly, the base address of the U-boot image i.e. where it starts executing from. So if U-boot is running straight from flash, it's the address of the flash. Or if ROM/firmware is responsible for loading U-boot then it's whatever address in RAM U-boot gets loaded to. Thus if you set TEXT_BASE to a different address it'll be linked wrong and will probably break at the relocation step.
As for the image layout, what's to ask? Either read the linker scripts, or just run a build then disassemble the u-boot ELF image that u-boot.bin is created from.

Related

how does the program gets loaded in memory when you have several memory region?

Let's say I have SOC that have different processors (embedded SOC) and different memory regions. let's say it has internal ram for 3 different processors it has and an external ddr ram, let's call them sram1,sram2,sram3, and ddr1.
let's say I write some code and write a linker that uses all 4 different memories (and perhaps few sections per memory). I think what it means at this stage is that linker assumes your code is running at those addresses and resolves addresses based on them. But in order for this code to actually run, it has to be put in the correct addresses and then run. and I'm confused about this part, who makes sure that the code is copied into the right memory addresses before it's run ? is it the initial software that is running ?
In my case, the initial code (bootloader) is loaded by ROM. the ROM looks for an address in a specidfied format (specific to my processors) and copies the code from boot media (sd card) there. which is all the code in one region (let's say sram1). this makes sense, few hundred KBs of bootloader code gets copied in one of the regions which matches the linker file. What confuses me is after this : let's say my bootloader wants to load another app, and as I mentioned, that app uses all 4 different memory regions. is it the duty of bootloader to make sure the code is copied from sd card to the correct memory regions before passing control to it ? I think it should be, but then the bootloader should completely know how you have linked your app with the linker script, and I think this doesn't make sense. Can you enlighten me of how it works ?

How can I relocate firmware for stm32?

I have built firmware for stm32f4, so I have *.elf an *.bin files. If I load *.bin file into internal flash it runs correctly. But if I want load this firmware to another address different from default (0x08000000) and run it from my bootloader, of course it does not works. I fix memory area address in project settings (I use CooCox 1.7.6 if it matter) and it begins runing from the bootloader.
I don't want rebuild project every time I load firmware in standalone mode or using bootloader. So I'm looking for method that will allow me to make *.bin files from *.elf, which will be able to load from the different addresses.
I tried manualy interupt vector table fixing. It allow me to run small blinker project but it doesn't work for more complex projects. I must be missing something.
Then I tried objcopy with --change-addresses but unfortunately it doesn't work. I get the same file without any difference.
I think, it is a general problem and there are solution for it but I must be missing something important.
You have to compile your code as position independent. See the -fpic and -fPIC options of gcc. Or you need a loader that understands the relocation table of the ELF image.
I just happened to complete an odyssey on STM32 Cortex-M4 (and M0) with Position-Independent Code firmware images operated by a bootloader. I will give you and overview and link the full article below. My evaluation board is NUCLEO-L432KC with target MCU STM32L432KCU6U. The magic goes like this:
On high level, there are couple of things needed:
A very simple bootloader. It only needs to read 2 4-byte words from the flash location of the firmware image. First is stack pointer address and second is Reset_Handler address. Bootloader needs to jump to Reset_Handler. But as the firmware is relocated further in the flash, the Reset_Handler is actually a bit further. See this picture for clarification:
So, bootloader adds the correct offset before jumping to Reset_Handler of the firmware image. No other patching is done, but bootloader (in my solution at least) stores location and offset of the firmware image, calculates checksum and passes this information in registers for the firmware image to use.
Then we need modifications in firmware linker file to force the ISR vector table in the beginning of RAM. For Cortex-M4 and VTOR (Vector Offset Table Register) the ISR vector table needs to be aligned to 512 boundary. In the beginning of RAM it is there naturally. In linker script we also dedicate a position in RAM for Global Offset Table (GOT) for easier manipulation. Address ranges should be exported via linker script symbols also.
We need also C compiler options. Basically these:
-fpic
-mpic-register=r9
-msingle-pic-base
-mno-pic-data-is-text-relative
They go to C compiler only! This creates the Global Offset Table (GOT) accounting.
Finally we need dedicated and tedious assembly bootstrap routines in the firmware image project. These routines perform the normal startup task of setting up the C runtime environment, but they additionally also go and read ISR and GOT from flash and copy them to RAM. In RAM, the addresses of those tables pointing to flash are offset by the amount the firmware image is running apart from bootloader. Example pictures:
I spent last 6 months researching this subject and I have written an in-depth article about it here:
https://techblog.paalijarvi.fi/2022/01/16/portable-position-independent-code-pic-bootloader-and-firmware-for-arm-cortex-m0-and-cortex-m4/
I do not think so that would work well in your case because when you are compiling the file to run with boot loader, you also needs to make sure that Interrupt vector also have been moved to the new location else there will be a problem in executing some of the functions.

how to prevent boot region when program the sam4e using jtag

I am using at91sam4e16e and working on bootloader. boot region is defined at 0x400000 and application region is at 0x420000 onwards.
i have downloaded bootloader code into that region and compiled application code with 0x420000 link address. now I want to download that application to 0x420000 using Jtag but when I download it, all the memory goes erased and only application remains.
In avr, I could prevent the boot area in debugger option; How to do the same in sam4e?
regards,
shreyas.
Go to project options.
In Debugger -> Images you can download extra image.
Note that I have only used this with the Debug info only-option enabled, but I have bundled bootloader with my app, so it is a bit different situation. (You can bundle bootloader in Linker -> Input tab.)
I also had a problem that since application wasn't in normal starting location, I had to initialize program counter, and stack pointer registers manually. You can do this by defining a macro file in Debugger -> Setup.
Macro file could look like this (note that this is for different MCU, so you may have different registers/addresses):
execUserReset()
{
// Set the stack pointer
MSP = *(int*)0x00008000;
// Set the program counter
PC = *(int*)0x00008004;
}
This macro file skips bootloader when using debugger reset, but you could also make macro file which enters bootloader on reset by using different addresses.
Edit: Bundling the bootloader:
It's been a while since I have done this, so hopefully I remember everything.
You need to add your bootloader .bin file to Linker -> Input -> Raw binary image. Also define symbol bootloader, and section .bootloader. (I think alignment needs to be specified too, even if you use absolute placement.)
Add your bootloader symbol to Keep symbols: box above. This should make sure that bootloader is always included.
In your linker file, add line
place at address mem:0x00000000 { section .bootloader };
to place bootloader at specific address (change address to match your bootloader address).

How to load kernel into memory, from an ISO

At compile-time I link my Assembly bootstrap together with my kernel, into an *.img file, which I then convert into an *.iso image using MagicISO. I then boot from this *.iso image.
But the problem is that I want to read the second sector of the file (the kernel) into memory at 0x1000. But I only know how to do so, with a floppy disk image, so could someone please tell me how to do so, with an *.iso?
If you need any code or anything just tell me, and I'll provide it: ).
If your img file is a floppy image, the disc is loaded in a floppy-emulation environment. My conjecture is that you should be able to access the data just as you would on a floppy.

load-time ELF relocation

I am writing a simple user-space ELF loader under Linux (why? for 'fun'). My loader at the moment is quite simple and is designed to load only statically-linked ELF files containing position-independent code.
Normally, when a program is loaded by the kernel's ELF loader, it is loaded into its own address space. As such, the data segment and code segment can be loaded at the correct virtual address as specified in the ELF segments.
In my case, however, I am requesting addresses from the kernel via mmap, and may or may not get the addresses requested in the ELF segments. This is not a problem for the code segment since it is position independent. However, if the data segment is not loaded at the expected address, code will not be able to properly reference anything stored in the data segment.
Indeed, my loader appears to work fine with a simple assembly executable that does not contain any data. But as soon as I add a data segment and reference it, the executable fails to run correctly or SEGFAULTs.
How, if possible, can I fixup any references to the data segment to point to the correct place? Is there a relocation section stored in the (static) ELF file for this purpose?
If you modify the absolute addresses available in the .got section, (global offset table) your program should work. Make sure to modify the absolute address calculation to cater for the new distance between .text and .data, I'm afraid you need to figure out where this information comes from, for your architecture.
See this: Global Offset Table (Processor-Specific)
Good luck.
I don't see any way you can do that, unless you emulate the kernel-provided virtual address space completely, and run the code inside that virtual space. When you mmap the data section from the file, you are intrinsically relocating it to an unknown address of the virtual address space of your ELF interpreter, and your code will not be able to reference to it in any way.
Glad to be proven wrong. There's something very cool to learn here.

Resources