单片机
返回首页

浅谈分析Arm linux 内核移植及系统初始化的过程四

2016-06-15 来源:eefocus

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 we're going to be the grim
 * reaper of innocent orphaned children.
 *
 * We don't 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
 * we're 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 isn't (%s); looks like an initrd/n', err);

进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

最新器件
精选电路图
  • 离子检测器电路分析

  • 非常简单的150W功放电路图

  • 如何使用LED驱动器LM3915制作振动计

  • 分享一个电网倾角计电路

  • 使用NE555和磁簧开关的橱柜照明电路

  • 电谐波图形均衡器示意图

    相关电子头条文章