# Platform Init flow
## Basic Knowledge
1. What is the linker script?

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