It is recommended to refer to the article "[Kernel START process] Previous--vmlinux.lds analysis".
[kernel START process] Series : [Kernel Start process] previous--vmlinux.lds analysis [kernel START process] (chapter I) overview [kernel START process] (chapter II) Phase one--setting up an SVC, shutting down interrupts [ker Nel START Process] (chapter III) acquisition of the first stage of--proc info [kernel START process] (fourth) verification of the first stage of--DTB [kernel Start process] (fifth) phase one-creation of the Temporary kernel page table [kernel START process] (chapter sixth First phase-open MMU [kernel START process] (seventh) phase one--jump to Start_kernel
Recommended reference Documentation : ARMV7 official data sheet arm's CP15 coprocessor registers
================================================ First, kernel before the start of the preparation action
The preparation before the kernel starts is done by bootloader. So no matter what bootloader, such as Uboot, LK, superboot, etc., you need to implement the following preparation actions. This refers to the concept of description and does not involve code.
the bootloader we use in Project X projects is Uboot, and the specific code references the fourth section, "Kernel the implementation of the prepare action in Uboot" 1. Kernel image to the appropriate location of the DDR
Kernel images typically exist on storage devices, such as Flash\emmc\sdcard.
Therefore, the kernel image needs to be loaded into the RAM location before the CPU can access the kernel.
The implementation method is determined by bootloader, which can be either automatic replication or whether the command entered under bootloader cmdline mode is copied.
note, however, that the load location is required and is typically loaded into the physical RAM offset 0x8000, which is to reserve 32K of RAM in front. Kernel will start extracting from the loaded location, while the 32K free RAM in front of kernel, 16K as the boot params,16k as a temporary page table
These are described in the following article in the kernel startup process.
For example, the starting address for S5PV210 's physical RAM is 0x20000000, so kernel's load address should be 0x20008000. 2. Hardware Requirements
According to Arch/arm/kernel/head. The comment header of the stext (kernel's entry function) of S
/
* * Kernel Startup entry point.
*---------------------------
*
* This is normally called from the Decompressor code. The requirements
* Are:mmu = off, D-cache = off, i-cache = dont care, r0 = 0,
* r1 = machine nr, r2 = atags or dt b pointer.
So there are the following requirements
* MMU = off
The MMU is used to handle the mapping of physical addresses to virtual memory addresses, so it is necessary that the software need to configure its mapping table first (that is, the page table described in subsequent articles). In the case of the MMU shutdown, the address addressed by the CPU is a physical address, which means that no conversion is required to directly access the appropriate hardware. Once opened, all the addresses that are addressed by the CPU are virtual addresses that are mapped to the actual physical address by the MMU, even if you access a physical address in your code and are used as a virtual memory address. The
and the mapping table is created by kernel itself, so the kernel access address is a physical address before the mapping table is created, so it is important to ensure that the MMU is off.
* D-cache = off
Cache is a buffer between the CPU and memory, and is divided into data buffer d-cache and instruction buffer i-cache. The specific meaning here is not much explained.
Data cache must be shut down, otherwise it may kernel just start the process, to fetch data, from the cache, and this time in the RAM data has not been cache, resulting in data prefetch exception. The
's own understanding is that, assuming the MMU is open, the cache has an entry "address 0x20000000, Data 0xffff0000", and after the MMU is opened, the 0x20000000 address (virtual address) data is read, but the entry is read directly from the cache. Address 0x20000000, Data 0xffff0000 ", but actually corresponds to the physical address of the data is not this, so it will cause the data read error.
* r0 = 0
Hard to specify R0 register is 0, no meaning.
* r1 = machine nr
R1 Register contains machine ID.
* r2 = atags or DTB pointer
R2 registers contain atags or DTB address pointers. 3, jump to the corresponding location of the kernel mirror entry
Bootloader needs to implement the kernel jump by setting the PC pointer to the kernel's entry code (that is, the kernel loading location).
For example, the PC of tiny210 (s5pv210) is set to 0x20008000 to achieve a jump to kernel. second, kernel START process entrance instructions
1. Designation of kernel entry address
In ARCH/ARM/KERNEL/VMLINUX.LDS.S
ENTRY (stext)
So the entry code that kernel starts is located in Arch/arm/kernel/head. S
This is also the core Code section of our subsequent analysis of the kernel startup process.
2.Kernel entrance Address
* Connection address, through System.map view, you can see Stext's connection address is 0xc0008000
c0008000 T Stext
Load the address, because uboot loads the kernel into the 0x20008000 location, so kernel's entrance is 0x20008000
Depending on the connection script, Stext is the entry for the kernel (above), so the stext is at the beginning of the kernel image, so the stext load address should be 0x20008000.
iii. Description of two phases of kernel initiation
Kernel was mainly divided into two stages during the initial phase of launch. 1, the first stage: jump from the entrance to Start_kernel before the stage.
The corresponding code arch/arm/kernel/head. The implementation of Stext in S:
ENTRY (stext)
This stage is mainly implemented by assembly language.
This phase is primarily responsible for some of the operations before the MMU opens, as well as opening the MMU operation.
because the MMU is not open at this stage, and the kernel load address and connection address are consistent, you need to use location-independent design. Run the address and load the address consistently during the run (if you do not understand it is recommended to refer to the [kernel start process] previous--vmlinux.lds analysis).
The main processes are as follows:
* set to SVC mode, turn off all interrupts
What is the SVC mode. Why to set the SVC mode.
How to turn off all interrupts. Why do you want to shut down all interrupts?
@ Ensure SVC mode and all interrupts masked
Safe_svcmode_maskall R9
Refer to [Kernel startup process] (chapter II) Phase one--setting up the SVC, shutting down interrupts
* get the CPU ID and extract the corresponding proc info
Where to extract the Proc_info?
What is stored inside the proc_info. This data structure should be important so it is necessary to get it before opening the MMU.
MRC P15, 0, R9, C0, C0 @ Get processor ID
BL __lookup_processor_type @ r5=procinfo r9=cpuid
movs< C11/>r10, R5 @ Invalid processor (r5=0)?
THUMB (It eq) @ Force fixup-able Long Branch encoding
beq __error_p @ Yes, error ' P '
Refer to [Kernel START process] (chapter III) acquisition of the first stage of--proc info
* Verify tags or dtb
How to verify the validity of the DTB.
BL __vet_atags
Refer to [Kernel Start process] (fourth) verification of the first phase of the--DTB
* Create a page table entry for the Temporary Kernel page table
The role of the page table entry. Basic knowledge. and the MMU relationship.
* To create page table entries for which memory areas. Why.
BL __create_page_tables
Refer to [Kernel Start process] (fifth) phase one--creation of temporary kernel page table
* Configure the R13 register, that is, set the function to jump to after opening the MMU.
Why would you want to configure it before opening the MMU?
Ldr R13, =__mmap_switched @ address to jump to after
@ MMU have been enabled
Enable MMU
How to enable the MMU.
The Swapper_pg_dir variable.
LDR R12, [R10, #PROCINFO_INITFUNC]
add R12, R12, R10
ret R12
1: b __enable _mmu
Refer to [kernel start-up process] (sixth) phase one-opening the MMU
* jump to Start_kernel
How do I jump to start_kernel?
Refer to [Kernel START process] (seventh) stage one--jump to Start_kernel
Analysis of the code can be combined with the above questions to analyze.
subsequent analysis of the startup code will document the process and questions described above. 2, the second stage: Start_kernel start stage.
This stage is mainly implemented by C language.
The remaining operations in the kernel startup process are implemented here.
There is not much to say, the follow-up will be article description. Iv. Realization of kernel preparation action in Uboot
Take tiny210 as an example: 1, kernel image is loaded to the appropriate location in the DDR
The storage device tiny210 in the Project-x project is temporarily designed to be sdcard and is automatically loaded into the DDR on kernel.
Kernel mirrors have a traditional uimage approach and fit mode.
This is illustrated in the traditional Uimage way.
The specific implementation is as follows:
U-boot/board/samsung/tiny210/board.c
#define Kernel_text_base 0x20008000
void copy_kernel_to_ddr (void)
{
u32 sdmmc_base_addr;
Copy_sd_mmc_to_mem copy_bl2 = (COPY_SD_MMC_TO_MEM) (* (u32*) copysdmmctomem);
SDMMC_BASE_ADDR = * (U32 *) sdmmc_base;
if (sdmmc_base_addr = = sdmmc_ch2_base_addr)
{
copy_bl2 (2, Movi_kernel_sdcard_pos, movi_kernel_blkcnt, (U32 *) Kernel_text_base, 0);
}
}
Movi_kernel_sdcard_pos represents the position of the KERNEL mirror on the sdcard.
Kernel_text_base represents the location to load onto RAM, note that is 0x20008000.
The copy action on the SDcard to the DDR is achieved by COPY_SD_MMC_TO_MEM. 2. The closure of MMU and D-cache
Both the MMU and D-cache of ARM are managed by the coprocessor CP15.
For instructions and registers of CP15, please search the information on your own website.
Some bits of the C1 register are used to configure some operations in the MMU, and the C1 0-bit control disables/enable MMU, a simple example is as follows:
MRC p15,0,r0,c1,0,0
ORR R0, #01
MCR p15,0,r0,c1,0,0
Uboot s5pv210 Close the MMU and D-cache position in (in fact, the default is closed)
U-boot/arch/arm/cpu/armv7/start. S
ENTRY (CPU_INIT_CP15)
MRC P15, 0, R0, C1, C0, 0
Bic r0, R0, #0x00002000 @ clear bits (--v-)
Bic r0, R0, #0x0 0000007 @ Clear Bits 2:0 (-cam)
Orr r0, R0, #0x00000002 @ set bit 1 (--a-) Align
Orr r0, R0, #0x00000800 @ set bit One (Z---) BTB
#ifdef config_sys_icache_off
Bic r0, R0, #0x00001000 @ clear bit (I) I-cache
#else
Orr R 0, R0, #0x00001000 @ set bit (I) i-cache
#endif
mcr p15, 0, R0, C1, C0, 0
It is easy to understand this part of the code by referencing the operating instructions and register documents of the CP15. 3, r0 R1 R2 register settings and kernel jump
U-boot/arch/arm/lib/bootm.c
static void Boot_jump_linux (bootm_headers_t *images, int flag)
{
unsigned long Machid = Gd->bd->bi_arch_ number;//get mechine_id
void (*kernel_entry) (int zero, int arch, uint params);
Kernel_entry = (void (*) (int, int, uint)) images->ep;//Gets the entry address to be transferred
debug ("# # Transferring control to Linux (at Addre SS%08lx) "\
" ... \ n ", (ULONG) kernel_entry);
r2 = (unsigned long) images->ft_addr;//gets the DTB address.
kernel_entry (0, Machid, r2);
}
Finally jumps to Kernel_entry (0, Machid, r2), which is the location of the 0x20008000, and through the parameters, pass 0 incoming to R0,machid to R1,DTB address. Eventually it was called to the entrance to the kernel.
In the serial output you will see the following log:
# # Transferring control to Linux (at address 20008000) ...