---
# System prepended metadata

title: Platform Init flow

---

# 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;
}
```

