U-boot startup Kernel Analysis

Source: Internet
Author: User
Tags crc32
First, I will reference this article "ARM Linux kernel startup requirements". ARM Linux kernel boot requirements was written by Russell king, the maintainer of the ARM Linux kernel.
  • CPU register settings

    • R0 = 0.
    • R1 = machine type number.
    • R2 = physical address of tagged list in system Ram.
  • CPU Mode
    • All forms of interrupts must be disabled (irqs and fiqs .)
    • The CPU must be in SVC mode. (a special exception exists for Angel .)
  • Caches, mmus
    • The MMU must be off.
    • Instruction Cache may be on or off.
    • Data Cache must be off and must not contain any stale data.
  • Devices
    • DMA to/from devices shocould be quiesced.
  • The boot loader is expected to call the kernel image by jumping directly to the first instruction of the kernel image.
This is basically the above conditions. Please pay special attention to the first one. This is basically the essential difference between the go command of U-boot and the bootm command. First, let's take a look at the implementation of the bootm command, starting from line 119th of common/consumer _bootm.c:

#ifdef CONFIG_PPC
static boot_os_Fcn do_bootm_linux;
#else
extern boot_os_Fcn do_bootm_linux;
#endif

The precompiled macro here illustrates that the do_bootm_linux () function of the CPU that is not in the PPC architecture is not implemented in this file (extern ). It is conceivable that the implementation of this function should be related to the architecture. Specifically, the implementation of the ARM architecture is in the lib_arm/armlinux. c file. We can see that row 77th in lib_arm/armlinux. c is the implementation of the do_bootm_linux () function. Row 3 declares a function pointer Thekernel:

void (*theKernel)(int zero, int arch, uint params);

Look at its name and parameter name. We can also guess that this is actually the pointer to the kernel entry function. The naming of several parameters also illustrates the first requirement for starting the ARM Linux kernel mentioned above, because according to the ACPs (ARM/thumb procedure call standard), these three parameters use R0 in sequence, r1 and R2. The next row is to assign a value to the function pointer:

theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);

We can see that Thekernel is assigned a value of HDR-> ih_ep. This HDR refers to a header added before linux.bin.gz when uimageis produced using the tools/mkimagetool, ih_ep struct members store the value of the-e parameter specified when mkimage is used, that is, the entry point of the kernel ). After learning the meaning of HDR-> ih_ep, it is taken for granted to assign this value to Thekernel. The last is the call to the kernel entry function, which occurs in row 270th:

theKernel (0, bd->bi_arch_number, bd->bi_boot_params);

Assign a value to the parameter during the call. For example, R0 = 0, R1 = BD-> bi_arch_number, R2 = BD-> bi_boot_params. So far U-boot's mission has been completed, and it has begun to enter the beautiful new world of ARM Linux. ========================================================== ======================================== You Need To Know which address is to start the kernel, which address is used to start the file system? To analyze the function do_bootm in common/cmd_bootm.c, because the bootstrap kernel is the work of the bootm command, and do_bootm is the execution function of the bootm command.

The bootm command is used to guide the kernel image packaged by the mkimage tool after U-boot. What is the kernel image packaged by the mkimage tool after U-boot, this depends on the mkimage code to see what it has done. Although I hope you will not be lazy and take a look at it seriously, I know that many people are too lazy to do this, then I will summarize the mkimage code and tell you what mkimage has done and how to use this tool.

 

Mkimage usage
The tools/directory of uboot Source Code contains the mkimage tool, which can be used to create a variety of startup image files without compression or compression.

When creating an image file, mkimage adds a 0x40 header before the original executable image file to record the information specified by the parameter, in this way, uboot can identify the CPU architecture, OS, type, memory location, the entry point, and image name of the image.

Root @ glym:/tftpboot #./mkimage
Usage:./mkimage-l Image
-L ==> list image header information
./Mkimage-A arch-O OS-T type-C comp-A ADDR-e EP-N name-D data_file [: data_file...] Image
-A ==> set architecture to 'arch'
-O => Set Operating System to 'OS'
-T => set image type to 'type'
-C ==> set compression type 'comp'
-A ==> Set Load address to 'addr '(HEX)
-E => set entry point to 'EP' (HEX)
-N => set image name to 'name'
-D => Use Image Data from 'datafile'
-X ==> set xip (execute in place)
Parameter description:

-A: Specify the CPU architecture:

Architecture represented by values
Alpha
Arm a RM
X86 Intel x86
IA64 IA64
MIPs
Mips64 MIPS 64 bit
PPC powerpc
S390 IBM s390
Sh superh
Type
Sparc64 iSCSI 64 bit
M68k mc68000

-O: Specifies the operating system type. The following values can be used:
OpenBSD, NetBSD, FreeBSD, 4_4bsd, Linux, svr4, esix, Solaris, Irix, SCO, Dell, NCR, lynxos, VxWorks, PSOs, QNX, U-boot, RTEMS, Artos

-T specifies the image type. The following values can be taken:
Standalone, kernel, ramdisk, multi, firmware, script, filesystem

-C: Specifies the image compression method. The following values can be taken:
None
Gzip Compression Method
Bzip2 is compressed with Bzip2

-A specifies the image loading address in the memory. When the image is downloaded to the memory, the image must be downloaded according to the address value specified by this parameter when the image is created using mkimage.

-E specifies the image running entry point address, which is the value specified by-a plus 0x40 (because there is a mkimage header with 0x40 bytes added)

-N indicates the image name.

-D specifies the source file for image creation.

 

Now let's analyze the do_bootm function in common/cmd_bootm.c, which is the processing function of the bootm command.

......

Image_header_t header;

Ulong load_addr = pai_load_addr;/* default load address */

Int do_bootm (pai_tbl_t * cmdtp, int flag, int argc, char * argv [])
{
Ulong iflag;
Ulong ADDR;
Ulong data, Len, checksum;
Ulong * len_ptr;
Uint unc_len = 0x400000;
Int I, verify;
Char * Name, * s;
INT (* appl) (INT, char * []);
Image_header_t * HDR = & header;

Read the uboot environment variable verify. If the environment variable verify is equal to 'n', the local variable verify is assigned 0; if the environment variable verify is empty (that is, no environment variable verify is defined) or if the environment variable verify is not equal to 'n', the local variable verify is assigned a value of 1.

S = getenv ("verify ");
Verify = (S & (* s = 'n '))? 0: 1;

If the number of parameters is less than 2 (only bootm is input), use the default loading address pai_load_addr; otherwise, use the second parameter as the loading address.
If (argc <2 ){
ADDR = load_addr;
} Else {
ADDR = simple_strtoul (argv [1], null, 16 );
}

Show_boot_progress (1 );
Printf ("# booting image at % 08lx.../N", ADDR );

Add mkimage to the header of the image file and extract it to the header of the image_header_t structure variable.
/* Copy header so we can blank CRC Field for re-calculation */
Config_has_dataflash is defined, indicating that Atmel data flash exists in the system.
# Ifdef config_has_dataflash
If (addr_dataflash (ADDR )){
Read_dataflash (ADDR, sizeof (image_header_t), (char *) & header );
} Else
# Endif
Memmove (& header, (char *) ADDR, sizeof (image_header_t ));

Determine whether the magic of the image header matches. If the magic matches, an error occurs during the download process.
If (ntohl (HDR-> ih_magic )! = Ih_magic ){
# Ifdef _ i386 _/* correct image format not implemented yet-Fake It */
If (fake_header (HDR, (void *) ADDR,-1 )! = NULL ){
/* To compensate for the addition below */
ADDR-= sizeof (image_header_t );
/* Turnof verify,
* Fake_header () does not fake the data CRC
*/
Verify = 0;
} Else
# Endif/* _ i386 __*/
{
Puts ("Bad magic number/N ");
Show_boot_progress (-1 );
Return 1;
}
}
Show_boot_progress (2 );

Check the CRC of the image header and the CRC of the image data. If the verification does not match, an error occurs during the download process.
Data = (ulong) & header;
Len = sizeof (image_header_t );

Checksum = ntohl (HDR-> ih_hcrc );
HDR-> ih_hcrc = 0;

If (CRC32 (0, (char *) data, Len )! = Checksum ){
Puts ("Bad header checksum/N ");
Show_boot_progress (-2 );
Return 1;
}
Show_boot_progress (3 );

/* For multi-file images we need the data part, too */
Print_image_hdr (image_header_t *) ADDR );

Data = ADDR + sizeof (image_header_t );
Len = ntohl (HDR-> ih_size );

# Ifdef config_has_dataflash
If (addr_dataflash (ADDR )){
Read_dataflash (data, Len, (char *) cfg_load_addr );
Data = pai_load_addr;
}
# Endif

If (verify ){
Puts ("verifying checksum ...");
If (CRC32 (0, (char *) data, Len )! = Ntohl (HDR-> ih_dcrc )){
Printf ("Bad Data CRC/N ");
Show_boot_progress (-3 );
Return 1;
}
Puts ("OK/N ");
}
Show_boot_progress (4 );

Judge the architecture.

Len_ptr = (ulong *) data;

# If defined (_ PPC __)
If (HDR-> ih_arch! = Ih_cpu_ppc)
# Elif defined (_ arm __)
If (HDR-> ih_arch! = Ih_cpu_arm)
# Elif defined (_ i386 __)
If (HDR-> ih_arch! = Ih_cpu_i386)
# Elif defined (_ MIPS __)
If (HDR-> ih_arch! = Ih_cpu_mips)
# Elif defined (_ NiO __)
If (HDR-> ih_arch! = Ih_cpu_nio)
# Elif defined (_ m68k __)
If (HDR-> ih_arch! = Ih_cpu_m68k)
# Elif defined (_ microblze __)
If (HDR-> ih_arch! = Ih_cpu_microblze)
# Else
# Error unknown CPU type
# Endif
{
Printf ("unsupported architecture 0x % x/N", HDR-> ih_arch );
Show_boot_progress (-4 );
Return 1;
}
Show_boot_progress (5 );

Determines the image type.

Switch (HDR-> ih_type ){
Case ih_type_standalone:
Name = "standalone application ";
/* A second argument overwrites the load address */
If (argc> 2 ){
HDR-> ih_load = simple_strtoul (argv [2], null, 16 );
}
Break;
Case ih_type_kernel:
Name = "kernel image ";
Break;
Case ih_type_multi:
Name = "Multi-file image ";
Len = ntohl (len_ptr [0]);
/* OS kernel is always the first image */
Data + = 8;/* kernel_len + Terminator */
For (I = 1; len_ptr [I]; ++ I)
Data + = 4;
Break;
Default: printf ("wrong image type for % s command/N", required TP-> name );
Show_boot_progress (-5 );
Return 1;
}
Show_boot_progress (6 );

/*
* We have reached the point of no return: We are going
* Overwrite all Exception vector code, so we cannot easily
* Recover from any failures any more...
*/

Iflag = disable_interrupts ();

# Ifdef config_amigaoneg3se
/*
* We 've possible left the caches enabled
* BIOS emulation, so turn them off again
*/
Icache_disable ();
Invalidate_l1_instruction_cache ();
Flush_data_cache ();
Dcache_disable ();
# Endif

Determine the image compression type

Switch (HDR-> ih_comp ){
Case ih_comp_none: no compression
If (ntohl (HDR-> ih_load) = ADDR) {if the loading address indicated in the image header is the same as the address specified in parameter 2 in the bootm command, copy is not required, it can be executed locally.
Printf ("xip % s...", name );
} Else {
# If defined (config_hw_watchdog) | defined (config_watchdog)
Size_t L = Len;
Void * To = (void *) ntohl (HDR-> ih_load );
Void * From = (void *) data;

Printf ("loading % s...", name );

While (L> 0 ){
Size_t tail = (L> chunksz )? Chunksz: L;
Watchdog_reset ();
Memmove (to, from, tail );
To + = tail;
From + = tail;
L-= tail;
}
# Else /*! (Config_hw_watchdog | config_watchdog )*/
If the loading address indicated in the image header is different from the address specified in parameter 2 in the bootm command, it indicates that the image data will be copied to the address specified by parameter 2 in the bootm command from the loading address indicated in the image header, and then executed.
Memmove (void *) ntohl (HDR-> ih_load), (uchar *) data, Len );
# Endif/* config_hw_watchdog | config_watchdog */
}
Break;
Case ih_comp_gzip:
Printf ("Uncompressing % s...", name );
If (gunzip (void *) ntohl (HDR-> ih_load), unc_len,
(Uchar *) data, (int *) & Len )! = 0 ){
Puts ("gunzip error-must reset board to recover/N ");
Show_boot_progress (-6 );
Do_reset (cmdtp, flag, argc, argv );
}
Break;
# Ifdef config_bzip2
Case ih_comp_bzip2:
Printf ("Uncompressing % s...", name );
/*
* If we 've got less than 4 MB of malloc () space,
* Use slower decompression algorithm which requires
* At most 2300 KB of memory.
*/
I = bz2_bzbufftobuffdecompress (char *) ntohl (HDR-> ih_load ),
& Unc_len, (char *) data, Len,
Performance_malloc_len <(4096*1024), 0 );
If (I! = Bz_ OK ){
Printf ("bunzip2 error % d-must reset board to recover/N", I );
Show_boot_progress (-6 );
Udelay (100000 );
Do_reset (cmdtp, flag, argc, argv );
}
Break;
# Endif/* config_bzip2 */
Default:
If (iflag)
Enable_interrupts ();
Printf ("unimplemented compression type % d/N", HDR-> ih_comp );
Show_boot_progress (-7 );
Return 1;
}
Puts ("OK/N ");
Show_boot_progress (7 );

Determine how to boot based on the type of the image.

Switch (HDR-> ih_type ){
Case ih_type_standalone:
If (iflag)
Enable_interrupts ();

/* Load (and uncompress), but don't start if "autostart"
* Is set to "no"
*/
If (S = getenv ("autostart "))! = NULL) & (strcmp (S, "no") = 0 )){
Char Buf [32];
Sprintf (BUF, "% lx", Len );
Setenv ("filesize", Buf );
Return 0;
}
Appl = (INT (*) (INT, char * []) ntohl (HDR-> ih_ep );
(* Appl) (argc-1, & argv [1]);
Return 0;
Case ih_type_kernel:
Case ih_type_multi:
/* Handled below */
Break; the following code specifically processes the two image types
Default:
If (iflag)
Enable_interrupts ();
Printf ("can't boot image type % d/N", HDR-> ih_type );
Show_boot_progress (-8 );
Return 1;
}
Show_boot_progress (8 );

Determine how to Boot Based on the image OS type

Switch (HDR-> ih_ OS ){
Default:/* handled by (original) Linux case */
Case ih_ OS _linux:
# Ifdef config_silent_console
Fixup_silent_linux ();
# Endif
Do_bootm_linux (kernel TP, flag, argc, argv,
ADDR, len_ptr, verify );
Break;
Case ih_ OS _netbsd:
Do_bootm_netbsd (cmdtp, flag, argc, argv,
ADDR, len_ptr, verify );
Break;

# Ifdef config_lynxkdi
Case ih_ OS _lynxos:
Do_bootm_lynxkdi (cmdtp, flag, argc, argv,
ADDR, len_ptr, verify );
Break;
# Endif

Case ih_ OS _rtems:
Do_bootm_rtems (effectp, flag, argc, argv,
ADDR, len_ptr, verify );
Break;

# If (config_commands & cmd_cmd_elf)
Case ih_ OS _vxworks:
Do_bootm_vxworks (cmdtp, flag, argc, argv,
ADDR, len_ptr, verify );
Break;
Case ih_ OS _qnx:
Do_bootm_qnxelf (cmdtp, flag, argc, argv,
ADDR, len_ptr, verify );
Break;
# Endif/* pai_pai_elf */
# Ifdef config_artos
Case ih_ OS _artos:
Do_bootm_artos (cmdtp, flag, argc, argv,
ADDR, len_ptr, verify );
Break;
# Endif
}

Show_boot_progress (-9 );
# Ifdef debug
Puts ("/N # control returned to monitor-Resetting.../N ");
Do_reset (cmdtp, flag, argc, argv );
# Endif
Return 1;
}

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.