1. kernel startup address
1.1. Glossary
Ztextaddr
Extract the start address of the Code. There is no physical address or virtual address, because MMU is disabled at this time. The RAM address may be a storage medium such as flash that supports read/write addressing.
Start address of decompressor. here's no point in talking about virtual or physical addresses here, since the MMU will be off at the time when you call the decompressor code. you normally call the kernel at this address
Start it booting. This doesn't have to be located in Ram, it can be in flash or other read-only or read-write addressable medium.
Zreladdr
The address of the kernel startup in Ram. The compressed kernel image is extracted to this address and then executed.
This is the address where the decompressed kernel will be written, and eventually executed. The following constraint must be valid:
_ Pai_to_phys (textaddr) = zreladdr
The initial part of the kernel is carefully coded to be position independent.
Textaddr
The virtual address of kernel startup, which corresponds to zreladdr. Generally, the virtual address started by the kernel is 0x8000 added to the First Bank address of RAM.
Textaddr = page_offset + textoffst
Virtual start address of kernel, normally page_offset + 0x8000. this is where the kernel image ends up. with the latest kernels, it must be located at 32768 bytes into a 128 MB region. previous kernels placed a restriction
Of 256 MB here.
Textoffset
Kernel offset address. Set in arch/ARM/makefile.
Phys_offset
The physical start address of the First Bank of RAM.
Physical start address of the First Bank of RAM.
Page_offset
The virtual start address of the First Bank of RAM.
Virtual start address of the First Bank of Ram. During the kernel
Boot phase, virtual address page_offset will be mapped to physical
Address phys_offset, along with any other mappings you supply.
This shoshould be the same value as task_size.
1.2. Check the kernel startup address
The boot address of the kernel is determined by BOOTP. LDS. BOOTP. LDS: ARCH/ARM/Bootp
Output_arch (ARM)
Entry (_ start)
Sections
{
. = 0;
. Text :{
_ Stext = .;
* (. Start)
* (. Text)
Initrd_size = initrd_end-initrd_start;
_ Etext = .;
}
}
From top. = 0, you can determine that the start address of the decompressed code is 0x0. The value of ztextaddr determines this value.
Makefile: ARCH/ARM/boot/compressed
If you set the kernel to start from Rom, you can set the start address of the decompressed code on the make menuconfig configuration interface. Otherwise, the start address of the decompressed code is 0x0. In fact, the start address of the decompressed code is 0x0 by default when starting from Rom.
Feq ($ (config_zboot_rom), Y)
Ztextaddr: = $ (config_zboot_rom_text)
Zbssaddr: = $ (config_zboot_rom_bss)
Else
Ztextaddr: = 0 zbssaddr: = align (4)
Endif
Sedflags = s/text_start/$ (ztextaddr)/; S/bss_start/$ (zbssaddr )/
......
$ (OBJ)/vmlinux. LDS: $ (OBJ)/vmlinux. LDS. In ARCH/ARM/mach-s3c2410/makefile. config
@ Sed "$ (sedflags)" <$ <>$ @
@ Sed "$ (sedflags)" <$ <> $ @ the rule sets text_start to ztextaddr. Text_start is used in arch/ARM/boot/compressed/vmlinux. LDS. In to set the start address of the decompressed code.
Output_arch (ARM)
Entry (_ start)
Sections
{
. = Text_start;
_ Text = .;
. Text :{
_ Start = .;
* (. Start)
* (. Text)
* (. Text .*)
......
}
}
Kernel compilation relies on vmlinux. LDS. vmlinux. LDS is generated by vmlinux. LDS. S. The following code shows that the virtual address of kernel startup is set to page_offset + text_offset, and the physical address of kernel startup zreladdr is set in arch/ARM/boot/makefile.
Output_arch (ARM)
Entry (stext)
Sections
{
# Ifdef config_xip_kernel
. = Xip_virt_addr (config_xip_phys_addr );
# Else
. = Page_offset + text_offset;
# Endif
. Init: {/* init code and Data */
_ Stext = .;
_ Sinittext = .;
* (. Init. Text)
_ Einittext = .;
......
}
}
# Arch/ARM/boot/makefile
# Note: The following conditions must always be true:
# Zreladdr = pai_to_phys (page_offset + text_offset)
# Params_phys must be within 4 MB of zreladdr
# Initrd_phys must be in Ram
Zreladdr: = $ (zreladdr-y)
# ---> Zrealaddr-y is specified with 0x30008000 in arch/ARM/boot/makefile. boot
Params_phys: = $ (params_phys-y)
Initrd_phys: = $ (initrd_phys-y)
Export zreladdr initrd_phys params_phys
Run the following command to compile the kernel image. The entry address of-a and-E is set to zreladdr, which is specified in zreladdr :=$ (zreladdr-Y.
Quiet_pai_uimage = uimage $ @
Export _uimage = $ (config_shell) $ (mkimage)-A arm-O Linux-T kernel \
-C none-A $ (zreladdr)-E $ (zreladdr )\
-N'linux-$ (kernelrelease) '-d $ <$ @
1.3. Summary
From the above analysis, we can know that after the Linux kernel is copied to ram by bootloader, the decompressed code starts to run from ztextaddr (this code is a location-independent pic ). The kernel is decompressed to zrealaddr, that is, the physical address of the kernel startup. Correspondingly, the virtual address of kernel startup is set to textaddr, which meets the following conditions:
Textaddr = page_offset + text_offset
The physical and virtual addresses of kernel startup meet the following conditions:
Zreladdr = pai_to_phys (page_offset + text_offset) = pai_to_phys (textaddr)
Assume that the Development Board is smdk2410:
Virtual Address of kernel startup
Textaddr = 0xc0008000
Physical address of kernel startup
Zreladdr = 0x30008000
If it is started directly from flash, you also need to set the ztextaddr address.
2. kernel Startup Process Analysis
The kernel startup process is divided into two phases: Kernel Image Self-boot and kernel sub-module initialization.
Start
Decompress_kernel ()
Call_kernel
Stext:
Prepare_namespace
Do_basic_setup
Init
Rest_init
Setup_arch ......
Start_kernel
_ Enable_mmu
Execve ("/sbin/init "))
Kernel startup Flowchart
2.1. kernel Image Self-boot
The main task at this stage is to decompress the compressed kernel and enter the kernel code entry.
After bootloader completes system boot, the kernel image is transferred to the physical address ztextaddr specified by the memory. A typical kernel image consists of a self-boot program and a compressed vmlinux. Therefore, you need to decompress the kernel before starting the kernel. The first code at the kernel image entry is the self-guided program. It is in the arch/ARM/boot/compressed/head. s file.
The main function of the head. s file is to decompress the compressed kernel and jump to the kernel vmlinux kernel entry. Decompress_kernel (): ARCH/ARM/boot/compressed/Misc. C and call_kernel functions implement the above functions. Before calling decompress_kernel () to decompress the kernel, make sure that the decompressed kernel code does not overwrite the original kernel image. And set the kernel code entry address zrealaddr.
. Text
ADR r0, lc0
Ldmia r0, {R1, R2, R3, R4, R5, R6, IP, SP}
. Type lc0, # object
Lc0:. Word lc0 @ r1
. Word _ bss_start @ r2
. Word _ end @ r3
. Word zreladdr @ r4
. Word _ start @ R5
. Word _ got_start @ R6
. Word _ got_end @ IP
. Word user_stack + 4096 @ sp
The above code gets the entry address of the kernel code, which is saved in R4.
/*
* Check to see if we will overwrite ourselves.
* R4 = final kernel address
* R5 = start of this image
* R2 = end of malloc space (and therefore this image)
* We basically want:
* R4> = R2-> OK
* R4 + image length <= R5-> OK
*/
CMP R4, r2
BHS wont_overwrite
Add r0, R4, #4096*1024 @ 4 MB largest kernel size
CMP r0, R5
BLS wont_overwrite
MoV R5, R2 @ decompress after malloc Space
MoV r0, R5
MoV R3, r7
BL decompress_kernel
B call_kernel
The code above checks whether the extracted kernel code will overwrite the original kernel image, and then calls the kernel decompression function decompress_kernel ().
Ulg
Decompress_kernel (ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p,
Int arch_id)
{
Output_data = (UCH *) output_start;/* specify the kernel execution address and save it in R4 */
Free_mem_ptr = free_mem_ptr_p;
Free_mem_ptr_end = free_mem_ptr_end_p;
_ Machine_arch_type = arch_id;
Arch_decomp_setup ();/* initialize and set before decompression, including serial port baud rate settings */
Makecrc ();/* CRC check */
Putstr ("Uncompressing Linux ...");
Gunzip ();/* call the extract function */
Putstr ("done, booting the kernel. \ n ");
Return output_ptr;
}