Some Details on Arm Linux Boot

embedded linux ARM booting address

What I would like to know is from which datasheet/UM/RM or any document they get the number: bs=512 seek=2, -a 0x81000000 (Load address), -e 0x81000000 (Entry point)

The bs=512 seek=2 specification should be from the NXP/Freescale reference manual for the SoC (e.g. the "Expansion Device: SD, eSD and SDXC" section of the System Boot chapter).

When configured to boot from an SDcard, the ROM boot program (of the SoC) will look for a program image (e.g. U-Boot) at byte offset 0x400 (or 2 * 512 = 1024), which is the third 512-byte sector.

The first sector is presumed to be the MBR, and the second sector is reserved for an optional Secondary Image Table (using terminology from NXP document).

Allwinner SoCs use a similar booting scheme for SDcard (i.e. the U-Boot image is at a fixed location in raw sectors not part of a partition), but the image starts at the 17th sector.

Instead of loading raw sectors, some SoCs (e.g. Atmel) boot from SDcard by loading a file from a FAT partition.

Please also explain what Load address/entry point address mean?

These values are specified to the mkimage utility so that they can be installed in the uImage header. U-Boot will then use these values when the uImage is loaded and unpacked.

The load address specifies to U-Boot the required memory address to locate the image. The image is copied to that memory address.

The entry point specifies to U-Boot the memory address to jump/branch to in order to execute the image. This value is typically the same address as the load address.

For an ARM Linux kernel the recommended load and entry-point addresses are 0x8000 from the start of physical memory, according to (Vincent Sanders') Booting ARM Linux.

See Building kernel uImage using LOADADDR for more details.

What is the booting process for ARM?

Currently, there are two exception models in the ARM architecture (reset is considered a kind of exception):

The classic model, used in pre-Cortex chip and current Cortex-A/R chips. In it, the memory at 0 contains several exception handlers:

 Offset  Handler
===============
00 Reset
04 Undefined Instruction
08 Supervisor Call (SVC)
0C Prefetch Abort
10 Data Abort
14 (Reserved)
18 Interrupt (IRQ)
1C Fast Interrupt (FIQ)

When the exception happens, the processor just starts execution from a specific offset, so usually this table contains single-instruction branches to the complete handlers further in the code. A typical classic vector table looks like following:

00000000   LDR   PC, =Reset
00000004 LDR PC, =Undef
00000008 LDR PC, =SVC
0000000C LDR PC, =PrefAbort
00000010 LDR PC, =DataAbort
00000014 NOP
00000018 LDR PC, =IRQ
0000001C LDR PC, =FIQ

At runtime, the vector table can be relocated to 0xFFFF0000, which is often implemented as a tightly-coupled memory range for the fastest exception handling. However, the power-on reset usually begins at 0x00000000 (but in some chips can be set to 0xFFFF0000 by a processor pin).

The new microcontroller model is used in the Cortex-M line of chips. There, the vector table at 0 is actually a table of vectors (pointers), not instructions. The first entry contains the start-up value for the SP register, the second is the reset vector. This allows writing the reset handler directly in C, since the processor sets up the stack. Again, the table can be relocated at runtime. The typical vector table for Cortex-M begins like this:

__Vectors       DCD     __initial_sp              ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
[...more vectors...]

Note that in the modern complex chips such as OMAP3 or Apple's A4 the first piece of code which is executed is usually not user code but the on-chip Boot ROM. It might check various conditions to determine where to load the user code from and whether to load it at all (e.g. it could require a valid digital signature). In such cases, the user code might have to conform to different start-up conventions.

How do I find ARM Linux entry point when it fails to uncompress?

We seem to have ported Das U-Boot successfully.

There's evidence that that is a faulty assumption.

Just before calling the kernel, the pointer theKernel is 10008000 and not 10800000.

Which version of U-Boot are you using?

In both 2012.10 and 2013.04 versions of U-Boot, the variable theKernel is only declared and used by code for arches like AVR32 and MIPS.

There is no ARM code that should be using theKernel.

u-boot-2012.10$ find . -print | xargs grep theKernel
./arch/avr32/lib/bootm.c: void (*theKernel)(int magic, void *tagtable);
./arch/avr32/lib/bootm.c: theKernel = (void *)images->ep;
./arch/avr32/lib/bootm.c: theKernel, params_start);
./arch/avr32/lib/bootm.c: theKernel(ATAG_MAGIC, params_start);
./arch/microblaze/lib/bootm.c: void (*theKernel) (char *, ulong, ulong);
./arch/microblaze/lib/bootm.c: theKernel = (void (*)(char *, ulong, ulong))images->ep;
./arch/microblaze/lib/bootm.c: (ulong) theKernel, rd_data_start, (ulong) of_flat_tree);
./arch/microblaze/lib/bootm.c: theKernel (commandline, rd_data_start, (ulong) of_flat_tree);
./arch/mips/lib/bootm.c: void (*theKernel) (int, char **, char **, int *);
./arch/mips/lib/bootm.c: theKernel = (void (*)(int, char **, char **, int *))images->ep;
./arch/mips/lib/bootm.c: (ulong) theKernel);
./arch/mips/lib/bootm.c: theKernel(linux_argc, linux_argv, linux_env, 0);
./arch/mips/lib/bootm_qemu_mips.c: void (*theKernel) (int, char **, char **, int *);
./arch/mips/lib/bootm_qemu_mips.c: theKernel = (void (*)(int, char **, char **, int *))images->ep;
./arch/mips/lib/bootm_qemu_mips.c: (ulong) theKernel);
./arch/mips/lib/bootm_qemu_mips.c: theKernel(0, NULL, NULL, 0);
./arch/nds32/lib/bootm.c: void (*theKernel)(int zero, int arch, uint params);
./arch/nds32/lib/bootm.c: theKernel = (void (*)(int, int, uint))images->ep;
./arch/nds32/lib/bootm.c: (ulong)theKernel);
./arch/nds32/lib/bootm.c: theKernel(0, machid, bd->bi_boot_params);
u-boot-2012.10$


Please explain how you are able to trace a variable that should not be defined or assigned on an ARM processor.

The next output after U-Boot prints "Starting kernel ..." should be "Uncompressing Linux...".

For the Freescale arch this text output is dependent on the proper passing of the machine type number (aka arch_id) by U-Boot to the kernel.

You need to verify that this machine type number is properly defined in U-Boot.

What does your configuration file for U-Boot look like?

I tried adding some register manipulation code to signal GPIOs in compressed/head.S with no response.

Did you sanity check this code to ensure that it works as you expect?

Did you try out the GPIO operations from the U-Boot command line?

My question is, how can I make sure U-Boot is calling the correct entry point?

For the ARM arch, it is a jump to the address specified in the bootm command.

Since the uImage load address and the bootm specify the same 0x10800000 address, that should be good (assuming that U-Boot is correctly configured and built for ARM).

Just before calling the kernel, the pointer theKernel is 10008000 and not 10800000. Does this mean U-boot is jumping at the wrong location?

YES.
If you check the source code (for AVR32 or MIPS), you'd find that theKernel is assigned from the image header, specifically the entry point value. U-Boot would then jump to this location.

But the real problem is that your ARM Cortex A9 should not be using this code or this variable.

It seems as if that U-Boot is not configured for the proper arch and/or the machine type may not be correctly defined.

CORRECTIONS:

As the OP pointed out, older versions of U-Boot did use the variable theKernel even for the ARM arch.

The line of U-Boot output:

   Loading Kernel Image ... OK  

indicates that U-Boot has (successfully) copied the kernel image (without the image information header) from the bootm address of 0x10800000 (plus offset 0x40 for the header length) to the load address of 0x10008000. This memory move operation is performed by the procedure bootm_load_os() in common/cmd_bootm.c.

So the value of 0x10008000 that you reported is correct for theKernel.

There is no indication that U-Boot is jumping to the wrong location.

As already mentioned, you should verify that the machine type is correctly defined. The value would be used in __arch_decomp_setup() in arch/arm/plat-mxc/include/mach/uncompress.h so that text could be output during the decompression prior to the kernel booting.

memory location for linux kernel for u-boot

So what I've done is loaded a copy of linux compiled for ARM devices onto a sd-card ...

Unlike x86, there is no one build of a Linux kernel that executes on all "ARM devices".

Older ARM Linux kernels (i.e. pre-Device Tree) were configured and built specifically for each SoC/board variation.

Modern ARM Linux kernels can be built for one or more SoCs, and the kernel is booted with a Device Tree blob to describe the board in use.

You haven't provided any details to indicate if the kernel you have is sufficient to boot your "ARM device".

The problem now is what memory location do I tell U-boot to boot up the vmlinuz linux kernel?

ARM Linux should boot using a zImage file, not a vmlinuz file.

What is the start address of physical RAM on your device?

The convention is that the ARM Linux kernel will execute at the base of physical RAM plus an offset of 0x8000 (32K). See this answer for more details.

The zImage file is self-extracting, and can be loaded (by U-Boot from your SD card) to any suitable memory address above the kernel's load/execute address (while leaving room for the DT blob and not clobber U-Boot).

Or pointing out some resources would be great as well.

Try Russel King's Booting ARM Linux and Vincent Sanders' Booting ARM Linux.



Related Topics



Leave a reply



Submit