Article count:1385 Read by:1972833

Featured Content
Account Entry

Transfer of Linux device tree and parsing of device tree in kernel

Latest update time:2023-08-17
    Reads:

When U-Boot loads the device tree into the specified location in the memory, the ARM core SoC uses the general register r2 to transfer the address of the dtb in the memory. After the kernel obtains the address, it further processes the dtb file.


#Device tree transfer

When using bootm to load the kernel image (bootz is an encapsulation and functional extension of bootm, essentially the same). The entry function for U-Boot to jump to the kernel is boot_jump_linux

The C file of this function is under arch/arm/lib, which shows that the method of transferring the device tree is related to the SoC architecture. This function is particularly important when different SoCs are bring-up. This is a key API for connecting and exchanging information between U-Boot and the kernel. After the execution of this function of U-Boot is completed, the control of the CPU is completely handed over to the kernel.
/* Subcommand: GO */static void boot_jump_linux(bootm_headers_t *images, int flag){...  debug("## Transferring control to Linux (at address %08lx)" \    "...\n", (ulong) kernel_entry);  bootstage_mark(BOOTSTAGE_ID_RUN_OS);  announce_and_cleanup(fake);
if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) r2 = (unsigned long)images->ft_addr; else    r2 = gd->bd->bi_boot_params;...}

r2 is a register that stores the address of the device tree. There are two ways to obtain its value: instantiating ft_addr of the bootm_header_t data structure, and using U-Boot's board-level startup parameters as the address of the device tree.


##bootm_header_tmethod

The data structure bootm_header_t is defined as follows and is used by SoCs with various cores. Each manufacturer instantiates each member differently according to the characteristics of its own CPU.

/* * Legacy and FIT format headers used by do_bootm() and do_bootm_<os>() * routines. */typedef struct bootm_headers {  ...  char    *ft_addr;  /* flat dev tree address */  ulong    ft_len;    /* length of flat device tree */  ...} bootm_headers_t;

Using the bootm_header_t method, U-Boot needs to support device tree and non-empty files.

ft_len and ft_addr belong to bootm_header_t. When U-Boot parses the image file, these two members are instantiated. The function call stack is as follows:

do_bootz(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])-bootz_start()--bootm_find_images(int flag, int argc, char *const argv[], ulong start,ulong size)---boot_get_fdt(flag, argc, argv, IH_ARCH_DEFAULT, &images,&images.ft_addr, &images.ft_len);   u-boot-v2021.04/common/image-fdt.c


##gd->bd->bi_boot_params method

This is a relatively old method and is basically not used now. bi_boot_params is an address that stores kernel startup parameters, usually specified in board-level initialization.


When the code is executed here, whether r2 is the expected value can be confirmed by printing and using debugging tools. #kernel’s parsing of the device tree

The analysis is divided into two stages. The first stage performs verification and readjustment of startup parameters; the second stage completes the decompression of the device tree, that is, changing the device tree from FDT to EDT and creating device_node. ##The first stage

The first entry related to the device tree in the kernel startup log is printed as follows, which prints out the model name of the current hardware device, "OF: fdt: Machine model: V2P-CA9"

Booting Linux on physical CPU 0x0Linux version 5.4.124 (qemu@qemu) (gcc version 6.5.0 (Linaro GCC 6.5-2018.12)) #3 SMP Fri Jun 25 15:26:02 CST 2021CPU: ARMv7 Processor [410fc090] revision 0 (ARMv7), cr=10c5387dCPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cacheOF: fdt: Machine model: V2P-CA9

This model name is defined at the head of the device tree file and defines the overall name of the current device.

// SPDX-License-Identifier: GPL-2.0/* * ARM Ltd. Versatile Express * * CoreTile Express A9x4 * Cortex-A9 MPCore (V2P-CA9) * * HBI-0191B */
/dts-v1/;#include "vexpress-v2m.dtsi"
/ { model = "V2P-CA9"; ... }

But this is not the first time the kernel handles the device tree. There have been other operations before this. The function call stack is as follows:

setup_arch(char **cmdline_p) arch/arm/kernel/setup.c    atags_vaddr = FDT_VIRT_BASE(__atags_pointer);     setup_machine_fdt(void *dt_virt) arch/arm/kernel/devtree.c        early_init_dt_verify()        of_flat_dt_match_machine()  drivers/of/fdt.c        early_init_dt_scan_nodes();        __machine_arch_type = mdesc->nr;

Line 2 __atags_pointer is the address of dtb in memory. This address is obtained during the assembly phase (if the image is zImage, then it is completed during the decompression phase). Since mmu has been enabled and the 4K segment page table has been mapped when setup_arch is executed, and the device tree fdt address passed by U-Boot to the kernel belongs to the physical address, the physical address needs to be converted into a virtual address.

  head-common.S  .align  2  .type  __mmap_switched_data, %object__mmap_switched_data:#ifdef CONFIG_XIP_KERNEL#ifndef CONFIG_XIP_DEFLATED_DATA  .long  _sdata        @ r0  .long  __data_loc      @ r1  .long  _edata_loc      @ r2#endif  .long  __bss_stop      @ sp (temporary stack in .bss)#endif
.long __bss_start @ r0 .long __bss_stop @ r1 .long init_thread_union + THREAD_START_SP @ sp
.long processor_id @ r0 .long __machine_arch_type @ r1 .long __atags_pointer @ r2

The configuration of the device tree in the first stage mainly includes:

A 对dtb文件进行crc32校验,检测设备树文件是否合法early_init_dt_verify()B early_init_dt_scan_nodes()        /* Retrieve various information from the /chosen node */        of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);        /* Initialize {size,address}-cells info */        of_scan_flat_dt(early_init_dt_scan_root, NULL);        /* Setup memory, calling early_init_dt_add_memory_arch */        of_scan_flat_dt(early_init_dt_scan_memory, NULL);C 更新__machine_arch_typeD 更新chosen

The above chosen information can be checked again after the kernel is started to see what modifications have been made. ##second stage

The second stage is simply to decompress the device tree ABI file, change it from FDT to EDT, and generate the corresponding device_node node.

The function call stack at this stage is as follows:

unflatten_device_tree();    *__unflatten_device_tree()        /* First pass, scan for size */        size = unflatten_dt_nodes(blob, NULL, dad, NULL);                /* Second pass, do actual unflattening */        unflatten_dt_nodes(blob, mem, dad, mynodes);            unflatten_dt_nodes()                populate_node()

The device_nodes nodes are as follows:


After device_node is created, when the kernel creates platform_device, it registers the corresponding device based on the work completed at this stage for use by the driver code.

end


A mouthful of Linux


Follow and reply [ 1024 ] Massive Linux information will be given away

Collection of wonderful articles


Article recommendation

【Album】 ARM
【Album】 Fans Q&A
Album Introduction to linux
Album Computer Network
Album Linux driver

 
EEWorld WeChat Subscription

 
EEWorld WeChat Service Number

 
AutoDevelopers

About Us Customer Service Contact Information Datasheet Sitemap LatestNews

Room 1530, Zhongguancun MOOC Times Building,Block B, 18 Zhongguancun Street, Haidian District,Beijing, China Tel:(010)82350740 Postcode:100190

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号