# Platform Init flow ## Basic Knowledge 1. What is the linker script? ![](https://i.imgur.com/5uEpuLq.jpg) 2. Layout your own section ``` __attribue__((section("FOO"))) int global = 42; __attribue__((section("FOO2"))) void foo() { ... } ``` ## Bootloader 1. Write the machine type to register of r1. ``` CPU register settings r0 = 0. r1 = machine type number discovered in (3) above. r2 = physical address of tagged list in system RAM. ``` https://www.arm.linux.org.uk/developer/booting.php 2. Load the Device Tree Image to DRAM with the specific address ``` #define DDR_START get_ddr_start() #define ABOOT_FORCE_KERNEL_ADDR DDR_START + 0x8000 #define ABOOT_FORCE_KERNEL64_ADDR DDR_START + 0x80000 #define ABOOT_FORCE_RAMDISK_ADDR DDR_START + 0x2000000 #define ABOOT_FORCE_TAGS_ADDR DDR_START + 0x1E00000 ``` ## Kernel 1. Start up entry Point ``` arch/arm/kernel/head.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 dtb pointer. * ... ldr r13,=__mmap_switched @address to jump to after ``` ``` arch/arm/kernel/head-common.S ... __mmap_switched_data: .long processor_id .long __machine_arch_type .long __atags_pointer ... b start_kernel ``` ``` arch/arm/kernel/vmlinux.lds.s section ... .init.arch.info:{ __arch_info_begin = .; *(.arch.info.init) __arch_info_end =.; } ``` ## Machine Init ``` /* * Machine type table - also only accessible during boot */ extern const struct machine_desc __arch_info_begin[], __arch_info_end[]; #define for_each_machine_desc(p) \ for (p = __arch_info_begin; p < __arch_info_end; p++) ``` ``` setup_machine_fdt(__atags_pointer) => const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys) {} ``` ``` ... static void __init iq80331_init_machine(void) { platform_device_register_simple("gpio-iop", 0, iq80331_gpio_res, ARRAY_SIZE(iq80331_gpio_res)); platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c1_device); platform_device_register(&iop33x_uart0_device); platform_device_register(&iop33x_uart1_device); platform_device_register(&iq80331_flash_device); platform_device_register(&iop3xx_dma_0_channel); platform_device_register(&iop3xx_dma_1_channel); platform_device_register(&iop3xx_aau_channel); } MACHINE_START(IQ80331, "Intel IQ80331") /* Maintainer: Intel Corp. */ .atag_offset = 0x100, .map_io = iop3xx_map_io, .init_irq = iop33x_init_irq, .init_time = iq80331_timer_init, .init_machine = iq80331_init_machine, .restart = iop3xx_restart, MACHINE_END https://elixir.bootlin.com/linux/v4.19/source/arch/arm/mach-iop33x/iq80331.c ``` https://blog.csdn.net/hongzg1982/article/details/54884878 ## Kernel common init ``` static int __init iq80331_pci_init(void) { if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) && machine_is_iq80331()) pci_common_init(&iq80331_pci); return 0; } subsys_initcall(iq80331_pci_init); ``` ``` #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS #define ___define_initcall(fn, id, __sec) \ __ADDRESSABLE(fn) \ asm(".section \"" #__sec ".init\", \"a\" \n" \ "__initcall_" #fn #id ": \n" \ ".long " #fn " - . \n" \ ".previous \n"); #else #define ___define_initcall(fn, id, __sec) \ static initcall_t __initcall_##fn##id __used \ __attribute__((__section__(#__sec ".init"))) = fn; #endif #define __define_initcall(fn, id) ___define_initcall(fn, id, .initcall##id) #define subsys_initcall(fn) __define_initcall(fn, 4) ``` ``` .init.data : { INIT_DATA INIT_SETUP(16) INIT_CALLS CON_INITCALL INIT_RAM_FS *(.init.rodata.* .init.bss) /* from the EFI stub */ } ``` ``` start_kernel --> arch_call_rest_init --> rest_init --> kthread_create(kernel_init) --> kernel_init_freeable --> do_basic_setup --> do_initcalls ``` ``` static initcall_entry_t *initcall_levels[] __initdata = { __initcall0_start, __initcall1_start, __initcall2_start, __initcall3_start, __initcall4_start, __initcall5_start, __initcall6_start, __initcall7_start, __initcall_end, }; static const char *initcall_level_names[] __initdata = { "pure", "core", "postcore", "arch", "subsys", "fs", "device", "late", }; static void __init do_initcalls(void) { int level; for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++) do_initcall_level(level); } static void __init do_initcall_level(int level) { initcall_entry_t *fn; strcpy(initcall_command_line, saved_command_line); parse_args(initcall_level_names[level], ┊ initcall_command_line, __start___param, ┊ __stop___param - __start___param, ┊ level, level, ┊ NULL, &repair_env_string); trace_initcall_level(initcall_level_names[level]); for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++) do_one_initcall(initcall_from_entry(fn)); } int __init_or_module do_one_initcall(initcall_t fn) { int count = preempt_count(); char msgbuf[64]; int ret; if (initcall_blacklisted(fn)) return -EPERM; do_trace_initcall_start(fn); ret = fn(); do_trace_initcall_finish(fn, ret); msgbuf[0] = 0; if (preempt_count() != count) { sprintf(msgbuf, "preemption imbalance "); preempt_count_set(count); } if (irqs_disabled()) { strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf)); local_irq_enable(); } WARN(msgbuf[0], "initcall %pF returned with %s\n", fn, msgbuf); add_latent_entropy(); return ret; } ```