Archive for the ‘device tree’ Category

kenrel: how a memblock is added

December 13, 2015

This post discusses how a memblock is added.

reference code base
Qualcomm msm8994 LA.BF64.1.1-06510-8×94.0 with Android 5.0.2(LRX22G), bootloader (L)ittle (K)ernel and Linux kernel 3.10.49.

kernel config
CONFIG_HAVE_MEMBLOCK=y
CONFIG_NO_BOOTMEM=y

call stack

start_kernel()
-> setup_arch()
   -> setup_machine_fdt()
      -> early_init_dt_scan()
         -> early_init_dt_scan_chosen()
            -> early_init_dt_check_for_initrd()
         -> early_init_dt_scan_root()
         -> early_init_dt_scan_memory()
            -> early_init_dt_add_memory_arch()
               -> memblock_add()
      -> of_flat_dt_get_machine_name()
   -> arm64_memblock_init()
   -> paging_init()
-> build_all_zonelists()

what is memblock
The physical memory kernel could manage is represented by many intervals of memblocks.

early_init_dt_scan()
early_init_dt_scan() reads many basic system setting from device tree.

  1. It assigns DTB address to initial_boot_params.
  2. It calls early_init_dt_scan_chosen() to read /chosen/bootargs as kernel command line
  3. It calls early_init_dt_scan_root() to read /memory/#address-cells as address-cells, and read /memory/#size-cells as size-cells.
  4. It calls early_init_dt_scan_memory() to parse /memory/reg to get all DDRs. It then calls memblock_add() to add memblock for each DDR.
bool __init early_init_dt_scan(void *params)
{
	if (!params)
		return false;

	/* Setup flat device-tree pointer */
	initial_boot_params = params;

	/* check device tree validity */
	if (fdt_check_header(params)) {
		initial_boot_params = NULL;
		return false;
	}

	/* 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);

	return true;
}

how kernel parses physical memory from device tree and adds memblocks
early_init_dt_scan_root() reads #address-cells and #size-cells.

  1. dt_root_addr_cells = 2
  2. dt_root_size_cells = 2

early_init_dt_scan_memory() reads memory/reg. It then calls memblock_add() for each memory.

  • memory[0].base = reg[0..1] = 0x
  • memory[0].size = reg[2..3] = 0x60000000
  • memory[1].base = reg[4..5] = 0x80000000
  • memory[1].size = reg[6..7] = 0x60000000
  •     memory {
            device_type = "memory";
            reg = <0x0 0x0 0x0 0x60000000 0x0 0x80000000 0x0 0x60000000>;
            #address-cells = <0x2>;
            #size-cells = <0x2>;
    

    check memblock layout from debugfs
    /sys/kernel/debug/memblock/memory exports information for each memblocks. The memblocks exported by the system is subset of above device tree setting. This is because many memblocks are removed in arm64_memblock_init() for exclusive use of some subsystem or drivers.

    $ adb shell cat /sys/kernel/debug/memblock/memory
       0: 0x0000000000000000..0x00000000057fffff
       1: 0x000000000f900000..0x000000005fffffff
       2: 0x0000000080000000..0x00000000dfffffff
    

    conclusion
    This post discusses how memblocks are added in the code flow. It also shows an example in which kernel read memory settings from device tree, and calls memblock_add() for each memblock(). kernel also export memblock information in debugfs /sys/kenrel/debug/memblock.

    Advertisements

    android: qcom: dts, dtb, dtc, and make

    December 12, 2015

    This post discusses dts, dtb, dtc, and make.

    reference code base
    Qualcomm msm8994 LA.BF64.1.1-06510-8×94.0 with Android 5.0.2(LRX22G), bootloader (L)ittle (K)ernel and Linux kernel 3.10.49.

    what are dts, dtb, and dtc

  • A dts(device tree source) file is a text file describing a device tree.
  • A dtb file is a binary file compiled from a dts file.
  • dtc is device tree compiler and de-compiler. It could compile dts file into a dtb file. It could also de-compile a dtb file into a dts file.
  • make dtc in kernel
    If CONFIG_DTC is set, then it could make dtc with target scripts in kernel source code. The target scripts is built by default.

    $ make -C kernel O=$(PWD)/$(kernel_out) scripts
    
    subdir-$(CONFIG_MODVERSIONS) += genksyms
    subdir-y                     += mod
    subdir-$(CONFIG_SECURITY_SELINUX) += selinux
    subdir-$(CONFIG_DTC)         += dtc
    

    make dtb
    DTB files are built while building kernel. A dtb file is compiled if it is added into dtb-y. In this case, CONFIG_ARCH_MSM8994=y, so dtb-y will include below dtb files. For example, dtc will compile msm8994-v1-fluid.dts into msm8994-v1-fluid.dtb.

    dtb-$(CONFIG_ARCH_MSM8994) += msm8994-v1-sim.dtb \
    	msm8994-rumi.dtb \
    	msm8994-v1-cdp.dtb \
    	msm8994-pmi8994-pm8004-v1-cdp.dtb \
    	msm8994-v1-mtp.dtb \
    	msm8994-pmi8994-pm8004-v1-mtp.dtb \
    	msm8994-v1-liquid.dtb \
    	msm8994-v1-fluid.dtb \
    	apq8094-v1-cdp.dtb \
    	apq8094-v1-mtp.dtb \
    	apq8094-v1-liquid.dtb \
    	apq8094-v1-fluid.dtb \
    	apq8094-v1-dragonboard.dtb \
    	msm8994-v2-sim.dtb \
    	msm8994-v2-cdp.dtb \
    	msm8994-pmi8994-pm8004-v2-cdp.dtb \
    	msm8994-v2-mtp.dtb \
    	msm8994-pmi8994-pm8004-v2-mtp.dtb \
    	msm8994-v2-liquid.dtb \
    	msm8994-v2-fluid.dtb \
    	apq8094-v2-cdp.dtb \
    	apq8094-v2-mtp.dtb \
    	apq8094-v2-liquid.dtb \
    	apq8094-v2-fluid.dtb \
    	apq8094-v2-dragonboard.dtb
    

    After building boot.img which depends on kernel and dt.img. We could see below dtb files are compiled by dtc.

    $ make bootimage
    $ ls out/target/product/msm8994/obj/KERNEL_OBJ/arch/arm64/boot/dts
    apq8094-v1-cdp.dtb
    apq8094-v1-dragonboard.dtb
    apq8094-v1-fluid.dtb
    apq8094-v1-liquid.dtb
    apq8094-v1-mtp.dtb
    apq8094-v2.0-cdp.dtb
    apq8094-v2.0-dragonboard.dtb
    apq8094-v2.0-fluid.dtb
    apq8094-v2.0-liquid.dtb
    apq8094-v2.0-mtp.dtb
    apq8094-v2.1-cdp.dtb
    apq8094-v2.1-dragonboard.dtb
    apq8094-v2.1-fluid.dtb
    apq8094-v2.1-liquid.dtb
    apq8094-v2.1-mtp.dtb
    msm8992-cdp.dtb
    msm8992-mtp.dtb
    msm8992-rumi.dtb
    msm8992-sim.dtb
    msm8994-pmi8994-pm8004-v1-cdp.dtb
    msm8994-pmi8994-pm8004-v1-mtp.dtb
    msm8994-pmi8994-pm8004-v2.0-cdp.dtb
    msm8994-pmi8994-pm8004-v2.0-mtp.dtb
    msm8994-pmi8994-pm8004-v2.1-cdp.dtb
    msm8994-pmi8994-pm8004-v2.1-mtp.dtb
    msm8994-rumi.dtb
    msm8994-v1-cdp.dtb
    msm8994-v1-fluid.dtb
    msm8994-v1-liquid.dtb
    msm8994-v1-mtp.dtb
    msm8994-v1-sim.dtb
    msm8994-v2.0-cdp.dtb
    msm8994-v2.0-fluid.dtb
    msm8994-v2.0-liquid.dtb
    msm8994-v2.0-mtp.dtb
    msm8994-v2.1-cdp.dtb
    msm8994-v2.1-fluid.dtb
    msm8994-v2.1-liquid.dtb
    msm8994-v2.1-mtp.dtb
    msm8994-v2-sim.dtb
    

    how use dtc transform dtb and dts
    We could use dtc to decompile a dtb file into a dts file. And then use dtc to compile this dts file into a dtb file again. The two dtb files are the same.

    $ cd msm8994/out/target/product/msm8994/obj/KERNEL_OBJ
    $ scripts/dtc/dtc -I dtb -O dts arch/arm64/boot/dts/mm8994-v1-liquid.dtb > test.dts
    $ scripts/dtc/dtc -I dts -O dtb test.dts > test.dtb
    $ diff arch/arm64/boot/dts/mm8994-v1-liquid.dtb test.dtb
    

    conclusion
    This post discusses dts, dtb, dtc, and make. It shows how to make dtb files and how to use dtc to transform between a dtb file and a dts file.

    android: qcom: dt.img and make

    December 12, 2015

    This post discusses dt.img and make.

    reference code base
    Qualcomm msm8994 LA.BF64.1.1-06510-8×94.0 with Android 5.0.2(LRX22G), bootloader (L)ittle (K)ernel and Linux kernel 3.10.49.

    what is dt.img
    dt.img comprises many DTBs(Device tree blobs) while building kernel of boot.img.

    dt.img in AOSP
    In AOSP boot.img format, the boot.img is composed of kernel and ramdisk. Some SOC vendors appends dt.img to the end of kernel.

    /*
    ** +-----------------+ 
    ** | boot header     | 1 page
    ** +-----------------+
    ** | kernel          | n pages  
    ** +-----------------+
    ** | ramdisk         | m pages  
    ** +-----------------+
    ** | second stage    | o pages
    ** +-----------------+
    **
    ** n = (kernel_size + page_size - 1) / page_size
    ** m = (ramdisk_size + page_size - 1) / page_size
    ** o = (second_size + page_size - 1) / page_size
    

    dt.img in msm8994
    In the reference code base, boot.img is composed of kernel, ramdisk, and dt.img.

    /*
    ** +-----------------+ 
    ** | boot header     | 1 page
    ** +-----------------+
    ** | kernel          | n pages  
    ** +-----------------+
    ** | ramdisk         | m pages  
    ** +-----------------+
    ** | second stage    | o pages
    ** +-----------------+
    ** | device tree     | p pages
    ** +-----------------+
    **
    ** n = (kernel_size + page_size - 1) / page_size
    ** m = (ramdisk_size + page_size - 1) / page_size
    ** o = (second_size + page_size - 1) / page_size
    ** p = (dt_size + page_size - 1) / page_size
    **
    

    how to build dt.img
    dt.img is built while build boot.img. It could also be built by itself.

    $ make dt.img
    

    how does make dt.img work
    Because of make dependency, dt.img is built after kernel and dtbTool are built successfully. The build system calls macro build-dtimage-target to build dt.img.

    This macro calls $(DTBTOOL) -o $@ -s $(BOARD_KERNEL_PAGESIZE) -p $(KERNEL_OUT)/scripts/dtc/ $(dtb_dir).
    In this case:

    • $(DTBTOOL) = out/host/linux-x86/bin/dtbTool
    • $@ = out/target/product/msm8994/dt.img
    • $(BOARD_KERNEL_PAGESIZE) = 4096
    • $(KERNEL_OUT) = out/target/product/msm8994/obj/KERNEL_OBJ
    • $(dtb_dir) = $(KERNEL_OUT)/arch/arm64/boot/dts/ $(KERNEL_OUT)/arch/arm/boot/dts/ $(KERNEL_OUT)/arch/arm/boot/
    #----------------------------------------------------------------------
    # Generate device tree image (dt.img)
    #----------------------------------------------------------------------
    ifneq ($(strip $(TARGET_NO_KERNEL)),true)
    ifeq ($(strip $(BOARD_KERNEL_SEPARATED_DT)),true)
    ifeq ($(strip $(BUILD_TINY_ANDROID)),true)
    include device/qcom/common/dtbtool/Android.mk
    endif
    
    DTBTOOL := $(HOST_OUT_EXECUTABLES)/dtbTool$(HOST_EXECUTABLE_SUFFIX)
    
    INSTALLED_DTIMAGE_TARGET := $(PRODUCT_OUT)/dt.img
    
    possible_dtb_dirs = $(KERNEL_OUT)/arch/$(TARGET_KERNEL_ARCH)/boot/dts/ $(KERNEL_OUT)/arch/arm/boot/dts/ $(KERNEL_OUT)/arch/arm/boot/
    dtb_dir = $(firstword $(wildcard $(possible_dtb_dirs)))
    
    define build-dtimage-target
        $(call pretty,"Target dt image: $(INSTALLED_DTIMAGE_TARGET)")
        $(hide) $(DTBTOOL) -o $@ -s $(BOARD_KERNEL_PAGESIZE) -p $(KERNEL_OUT)/scripts/dtc/ $(dtb_dir)
        $(hide) chmod a+r $@
    endef
    
    $(INSTALLED_DTIMAGE_TARGET): $(DTBTOOL) $(INSTALLED_KERNEL_TARGET)
    	$(build-dtimage-target)
    
    ALL_DEFAULT_INSTALLED_MODULES += $(INSTALLED_DTIMAGE_TARGET)
    ALL_MODULES.$(LOCAL_MODULE).INSTALLED += $(INSTALLED_DTIMAGE_TARGET)
    endif
    endif
    

    conclusion
    The post discusses what dt.img is and how to make it.

    android: qcom: dt.img and dtbTool

    December 12, 2015

    This post discusses dt.img and dtbTool.

    reference code base
    Qualcomm msm8994 LA.BF64.1.1-06510-8×94.0 with Android 5.0.2(LRX22G), bootloader (L)ittle (K)ernel and Linux kernel 3.10.49.

    relation between dt.img and dtbTool
    As discussed in android: qcom: dt.img and make, dtbTool scans all DTBs(device three blob) which are created while building kernel, and puts them into a single image called dt.img.

    format of dt.img
    dt.img format is determined by dtbTool. The first 12 bytes are header which includes magic, version, and number of DTBs.

    Following the header is the DTB entry for each DTBs. Each DTB entry has offset and size fields to indicate the real DTB corresponding to this DTB entry.

                                     size
       x      +------------------+
       |      | MAGIC ("QCDT")   |   4B
       |      +------------------+
     header   | VERSION          |   uint32 (version 3)
       |      +------------------+
       |      | num of DTBs      |   uint32 (number of DTB entries)
       x      +------------------+
       |      | platform id #1   |   uint32 (e.g. ID for MSM8974)
       |      +------------------+
       |      | variant id #1    |   uint32 (e.g. ID for CDP, MTP)
       |      +------------------+
       |      | subtype id #1    |   uint32 (e.g. ID for subtype) (QCDT v2)
     device   +------------------+
      #1      | soc rev #1       |   uint32 (e.g. MSM8974 v2)
     entry    +------------------+
       |      | pmic0 #1         |   uint32 (pmic0-> first smallest SID of existing pmic)
       |      +------------------+
       |      | pmic1 #1         |   uint32 (pmic1-> secondary smallest SID of existing pmic)
       |      +------------------+
       |      | pmic2 #1         |   uint32 (pmic2-> third smallest SID of existing pmic)
       |      +------------------+
       |      | pmic3 #1         |   uint32 (pmic3-> fourth smallest SID of existing pmic)
       |      +------------------+
       |      | offset #1        |   uint32 (byte offset from start/before MAGIC
       |      +------------------+           to DTB entry)
       |      | size #1          |   uint32 (size in bytes of DTB blob)
       x      +------------------+
       .              .
       .              .  (repeat)
       .              .
    
       x      +------------------+
       |      | platform id #Z   |   uint32 (e.g. ID for MSM8974)
       |      +------------------+
      device  | variant id #Z    |   uint32 (e.g. ID for CDP, MTP)
      #Z      +------------------+
      entry   | subtype id #Z    |   uint32 (e.g. ID for subtype) (QCDT v2)
      (last)  +------------------+
       |      | soc rev #Z       |   uint32 (e.g. MSM8974 v2)
       |      +------------------+
       |      | pmic0 #1         |   uint32 (pmic0-> first smallest SID of existing pmic)
       |      +------------------+
       |      | pmic1 #1         |   uint32 (pmic1-> secondary smallest SID of existing pmic)
       |      +------------------+
       |      | pmic2 #1         |   uint32 (pmic2-> third smallest SID of existing pmic)
       |      +------------------+
       |      | pmic3 #1         |   uint32 (pmic3-> fourth smallest SID of existing pmic)
       |      +------------------+
       |      | offset #Z        |   uint32 (byte offset from start/before MAGIC
       x      +------------------+           to DTB entry)
              | 0 ("zero")       |   uint32 (end of list delimiter)
              +------------------+           to DTB entry)
              | padding          |   variable length for next DTB to start on
              +------------------+           page boundary
              | DTB #1           |   variable (start is page aligned)
              |                  |
              |                  |
              +------------------+
              | padding          |   variable length for next DTB to start on
              +------------------+           page boundary
                      .
                      .
                      .
    
              +------------------+
              | DTB #Z (last)    |   variable (start is page aligned)
              |                  |
              |                  |
              +------------------+
    

    conclusion
    This post discusses the relation between dt.img and dtbTool and the format of dt.img.


    %d bloggers like this: