7、浅谈剖析Arm linux 内核移植及体系初始化的进程 咨询QQ:313807838
MACHINE_START(SMDK2410, “SMDK2410”) /* @TODO: request a new identifier and switch
* to SMDK2410 */
/* Maintainer: Jonas Dietsche */
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = smdk2410_map_io,
.init_irq = s3c24xx_init_irq,
.init_machine = smdk_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END
由此可见在.arch.info.init段内存放了__desc_mach_desc_SMDK2410结构体。初始化了相应的初始化函数指针。问题又来了, 这些初始化指针函数是什么时分被调用的呢?
剖析发现,纷歧而同。
如 s3c24xx_init_irq()函数是经过start_kernel()里的init_IRQ()函数调用init_arch_irq()完结的。 由于在MACHINE_START结构体中 .init_irq = s3c24xx_init_irq,而在setup_arch()函数中init_arch_irq = mdesc->init_irq, 所以调用init_arch_irq()就相当于调用了s3c24xx_init_irq()。
又如smdk_machine_init()函数 的初始化。在MACHINE_START结构体中,函数指针赋值,.init_machine = smdk_machine_init。而init_machine()函数被linux/arch/arm/kernel/setup.c文件中的 customize_machine()函数调用并被arch_initcall(Fn)宏处 理,arch_initcall(customize_machine)。 被arch_initcall(Fn)宏处理过函数将linux/init/main.c
do_initcalls()函数调用。 详细参看下边的部分。
void __init setup_arch(char cmdline_p)
{
struct tag *tags = (struct tag *)&init_tags;
struct machine_desc *mdesc;
char *from = default_command_line;
setup_processor();
mdesc = setup_machine(machine_arch_type);//machine_arch_type =SMDK2410 by edwin
machine_name = mdesc->name;
if (mdesc->soft_reboot)
reboot_setup(“s”);
if (mdesc->boot_params)
tags = phys_to_virt(mdesc->boot_params);
/*
* If we have the old style parameters, convert them to
* a tag list.
*/
if (tags->hdr.tag != ATAG_CORE)
convert_to_tag_list(tags);
if (tags->hdr.tag != ATAG_CORE)
tags = (struct tag *)&init_tags;
if (mdesc->fixup)
mdesc->fixup(mdesc, tags, &from, &meminfo);
if (tags->hdr.tag == ATAG_CORE) {
if (meminfo.nr_banks != 0)
squash_mem_tags(tags);
parse_tags(tags);
}
init_mm.start_code = (unsigned long) &_text;
init_mm.end_code = (unsigned long) &_etext;
init_mm.end_data = (unsigned long) &_edata;
init_mm.brk = (unsigned long) &_end;
memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
8、浅谈剖析Arm linux 内核移植及体系初始化的进程 咨询QQ:313807838
saved_command_line[COMMAND_LINE_SIZE-1] = /0;
parse_cmdline(cmdline_p, from);
paging_init(&meminfo, mdesc);
request_standard_resources(&meminfo, mdesc);
#ifdef CONFIG_SMP
smp_init_cpus();
#endif
cpu_init();
/*
* Set up various architecture-specific pointers
*/
init_arch_irq = mdesc->init_irq;
system_timer = mdesc->timer;
init_machine = mdesc->init_machine;
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
conswitchp = &dummy_con;
#endif
#endif
}
5.3. rest_init()函数剖析
下面咱们来剖析下rest_init()函数。
Start_kernel() 函数担任初始化内核各子体系,最终调用reset_init(),发动一个叫做init的内核线程,持续初始化。在init内核线程中,将履行下列 init()函数的程序。Init()函数担任完结根文件体系的挂接、初始化设备驱动程序和发动用户空间的init进程等重要工作。
static void noinline rest_init(void)
__releases(kernel_lock)
{
kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND);
numa_default_policy();
unlock_kernel();
/*
* The boot idle thread must execute schedule()
* at least one to get things moving:
*/
preempt_enable_no_resched();
schedule();
preempt_disable();
/* Call into cpu_idle with preempt disabled */
cpu_idle();
}
static int init(void * unused)
{
lock_kernel();
/*
* init can run on any cpu.
*/
set_cpus_allowed(current, CPU_MASK_ALL);
/*
* Tell the world that were going to be the grim
* reaper of innocent orphaned children.
*
* We dont want people to have to make incorrect
* assumptions about where in the task array this
* can be found.
*/
child_reaper = current;
smp_prepare_cpus(max_cpus);
do_pre_smp_initcalls();
smp_init();
sched_init_smp();
cpuset_init_smp();
/*
* Do this before initcalls, because some drivers want to access
* firmware files.
*/
populate_rootfs(); //挂接根文件体系
do_basic_setup(); //初始化设备驱动程序
/*
* check if there is an early userspace init. If yes, let it do all
* the work //发动用户空间的init进程
9、浅谈剖析Arm linux 内核移植及体系初始化的进程 咨询QQ:313807838
*/
if (!ramdisk_execute_command)
ramdisk_execute_command = “/init”;
if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
ramdisk_execute_command = NULL;
prepare_namespace();
}
/*
* Ok, we have completed the initial bootup, and
* were essentially up and running. Get rid of the
* initmem segments and start the user-mode stuff..
*/
free_initmem();
unlock_kernel();
mark_rodata_ro();
system_state = SYSTEM_RUNNING;
numa_default_policy();
if (sys_open((const char __user *) “/dev/console”, O_RDWR, 0) < 0)
printk(KERN_WARNING “Warning: unable to open an initial console./n”);
(void) sys_dup(0);
(void) sys_dup(0);
if (ramdisk_execute_command) {
run_init_process(ramdisk_execute_command);
printk(KERN_WARNING “Failed to execute %s/n”,
ramdisk_execute_command);
}
/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
if (execute_command) {
run_init_process(execute_command);
printk(KERN_WARNING “Failed to execute %s. Attempting “
“defaults…/n”, execute_command);
}
run_init_process(“/sbin/init”);
run_init_process(“/etc/init”);
run_init_process(“/bin/init”);
run_init_process(“/bin/sh”);
panic(“No init found. Try passing init= option to kernel.”);
}
5.3.1. 挂接根文件体系
Linux/init/ramfs.c
void __init populate_rootfs(void)
{
char *err = unpack_to_rootfs(__initramfs_start,
__initramfs_end – __initramfs_start, 0);
if (err)
panic(err);
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start) {
#ifdef CONFIG_BLK_DEV_RAM
int fd;
printk(KERN_INFO “checking if image is initramfs…”);
err = unpack_to_rootfs((char *)initrd_start,
initrd_end – initrd_start, 1);
if (!err) {
printk(” it is/n”);
unpack_to_rootfs((char *)initrd_start,
initrd_end – initrd_start, 0);
free_initrd();
return;
}
printk(“it isnt (%s); looks like an initrd/n”, err);