Linux系统体系架构初始化过程(AM335X体系结构初始化)

来源:互联网 发布:算法导论哪些可以不看 编辑:程序博客网 时间:2024/05/28 18:42

如题,Linux系统体系架构初始化过程一般按照如下流程

start_kernel() ==> setup_arch(&command_line) ==> mdesc = setup_machine_fdt(__atags_pointer)==> for_each_machine_desc(mdesc) ==> return mdesc_best;

1、在linux中,内核启动后调用的第一个C函数是位于linux/init/main.c的Start_kernel()函数,具体实现如下:

asmlinkage void __init start_kernel(void){char * command_line;extern const struct kernel_param __start___param[], __stop___param[];smp_setup_processor_id();/* * Need to run as early as possible, to initialize the * lockdep hash: */lockdep_init();debug_objects_early_init();/* * Set up the the initial canary ASAP: */boot_init_stack_canary();cgroup_init_early();local_irq_disable();early_boot_irqs_disabled = true;/* * Interrupts are still disabled. Do necessary setups, then * enable them */tick_init();boot_cpu_init();page_address_init();printk(KERN_NOTICE "%s", linux_banner);setup_arch(&command_line);mm_init_owner(&init_mm, &init_task);mm_init_cpumask(&init_mm);setup_command_line(command_line);setup_nr_cpu_ids();setup_per_cpu_areas();smp_prepare_boot_cpu();/* arch-specific boot-cpu hooks */build_all_zonelists(NULL);page_alloc_init();printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);parse_early_param();parse_args("Booting kernel", static_command_line, __start___param,   __stop___param - __start___param,   &unknown_bootoption);jump_label_init();/* * These use large bootmem allocations and must precede * kmem_cache_init() */setup_log_buf(0);pidhash_init();vfs_caches_init_early();sort_main_extable();trap_init();mm_init();/* * Set up the scheduler prior starting any interrupts (such as the * timer interrupt). Full topology setup happens at smp_init() * time - but meanwhile we still have a functioning scheduler. */sched_init();/* * Disable preemption - early bootup scheduling is extremely * fragile until we cpu_idle() for the first time. */preempt_disable();if (!irqs_disabled()) {printk(KERN_WARNING "start_kernel(): bug: interrupts were ""enabled *very* early, fixing it\n");local_irq_disable();}idr_init_cache();perf_event_init();rcu_init();radix_tree_init();/* init some links before init_ISA_irqs() */early_irq_init();init_IRQ();prio_tree_init();init_timers();hrtimers_init();softirq_init();timekeeping_init();time_init();profile_init();call_function_init();if (!irqs_disabled())printk(KERN_CRIT "start_kernel(): bug: interrupts were " "enabled early\n");early_boot_irqs_disabled = false;local_irq_enable();/* Interrupts are enabled now so all GFP allocations are safe. */gfp_allowed_mask = __GFP_BITS_MASK;kmem_cache_init_late();/* * HACK ALERT! This is early. We're enabling the console before * we've done PCI setups etc, and console_init() must be aware of * this. But we do want output early, in case something goes wrong. */console_init();if (panic_later)panic(panic_later, panic_param);lockdep_info();/* * Need to run this when irqs are enabled, because it wants * to self-test [hard/soft]-irqs on/off lock inversion bugs * too: */locking_selftest();#ifdef CONFIG_BLK_DEV_INITRDif (initrd_start && !initrd_below_start_ok &&    page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "    "disabling it.\n",    page_to_pfn(virt_to_page((void *)initrd_start)),    min_low_pfn);initrd_start = 0;}#endifpage_cgroup_init();enable_debug_pagealloc();debug_objects_mem_init();kmemleak_init();setup_per_cpu_pageset();numa_policy_init();if (late_time_init)late_time_init();sched_clock_init();calibrate_delay();pidmap_init();anon_vma_init();#ifdef CONFIG_X86if (efi_enabled)efi_enter_virtual_mode();#endifthread_info_cache_init();cred_init();fork_init(totalram_pages);proc_caches_init();buffer_init();key_init();security_init();dbg_late_init();vfs_caches_init(totalram_pages);signals_init();/* rootfs populating might need page-writeback */page_writeback_init();#ifdef CONFIG_PROC_FSproc_root_init();#endifcgroup_init();cpuset_init();taskstats_init_early();delayacct_init();check_bugs();acpi_early_init(); /* before LAPIC and SMP init */sfi_init_late();ftrace_init();/* Do the rest non-__init'ed, we're now alive */rest_init();}

2、首先看Start_kernel()函数第33行setup_arch(&command_line)函数;

setup_arch函数在linux/arch/arm/kernel/setup.c中,定义如下:

void __init setup_arch(char **cmdline_p){struct machine_desc *mdesc;setup_processor();mdesc = setup_machine_fdt(__atags_pointer);if (!mdesc)mdesc = setup_machine_tags(machine_arch_type);machine_desc = mdesc;machine_name = mdesc->name;if (mdesc->restart_mode)reboot_setup(&mdesc->restart_mode);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;/* populate cmd_line too for later use, preserving boot_command_line */strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);*cmdline_p = cmd_line;parse_early_param();sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL);sanity_check_meminfo();arm_memblock_init(&meminfo, mdesc);paging_init(mdesc);request_standard_resources(mdesc);if (mdesc->restart)arm_pm_restart = mdesc->restart;unflatten_device_tree();#ifdef CONFIG_SMPif (is_smp())smp_init_cpus();#endifreserve_crashkernel();tcm_init();#ifdef CONFIG_MULTI_IRQ_HANDLERhandle_arch_irq = mdesc->handle_irq;#endif#ifdef CONFIG_VT#if defined(CONFIG_VGA_CONSOLE)conswitchp = &vga_con;#elif defined(CONFIG_DUMMY_CONSOLE)conswitchp = &dummy_con;#endif#endifearly_trap_init();if (mdesc->init_early)mdesc->init_early();}

3、setup_arch函数第六行mdesc = setup_machine_fdt(__atags_pointer);

这里用的一个重要的结构体struct machine_desc *mdesc;内核通过machine_desc结构体来控制系统体系架构相关部分的初始化。machine_desc结构体通过MACHINE_START宏来初始化

首先来看setup_machine_fdt源码:

/** * setup_machine_fdt - Machine setup when an dtb was passed to the kernel * @dt_phys: physical address of dt blob * * If a dtb was passed to the kernel in r2, then use it to choose the * correct machine_desc and to setup the system. */struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys){struct boot_param_header *devtree;struct machine_desc *mdesc, *mdesc_best = NULL;unsigned int score, mdesc_score = ~1;unsigned long dt_root;const char *model;if (!dt_phys)return NULL;devtree = phys_to_virt(dt_phys);/* check device tree validity */if (be32_to_cpu(devtree->magic) != OF_DT_HEADER)return NULL;/* Search the mdescs for the 'best' compatible value match */initial_boot_params = devtree;dt_root = of_get_flat_dt_root();for_each_machine_desc(mdesc) {score = of_flat_dt_match(dt_root, mdesc->dt_compat);if (score > 0 && score < mdesc_score) {mdesc_best = mdesc;mdesc_score = score;}}if (!mdesc_best) {const char *prop;long size;early_print("\nError: unrecognized/unsupported "    "device tree compatible list:\n[ ");prop = of_get_flat_dt_prop(dt_root, "compatible", &size);while (size > 0) {early_print("'%s' ", prop);size -= strlen(prop) + 1;prop += strlen(prop) + 1;}early_print("]\n\n");dump_machine_table(); /* does not return */}model = of_get_flat_dt_prop(dt_root, "model", NULL);if (!model)model = of_get_flat_dt_prop(dt_root, "compatible", NULL);if (!model)model = "<unknown>";pr_info("Machine: %s, model: %s\n", mdesc_best->name, model);/* Retrieve various information from the /chosen node */of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);/* Initialize {size,address}-cells info */of_scan_flat_dt(early_init_dt_scan_root, NULL);/* Setup memory, calling early_init_dt_add_memory_arch */of_scan_flat_dt(early_init_dt_scan_memory, NULL);/* Change machine number to match the mdesc we're using */__machine_arch_type = mdesc_best->nr;return mdesc_best;}

4、第28-34行

for_each_machine_desc(mdesc)&score = of_flat_dt_match(dt_root, mdesc->dt_compat);

遍历体系架构类型表,找到一个合适的,return mdesc_best;


5、另外,struct machine_desc *mdesc的初始化:

arch/arm/include/asm/mach/arch.h

struct machine_desc {unsigned intnr;/* architecture number*/const char*name;/* architecture name*/unsigned longatag_offset;/* tagged list (relative) */const char**dt_compat;/* array of device tree * 'compatible' strings*/unsigned intnr_irqs;/* number of IRQs */#ifdef CONFIG_ZONE_DMAunsigned longdma_zone_size;/* size of DMA-able area */#endifunsigned intvideo_start;/* start of video RAM*/unsigned intvideo_end;/* end of video RAM*/unsigned charreserve_lp0 :1;/* never has lp0*/unsigned charreserve_lp1 :1;/* never has lp1*/unsigned charreserve_lp2 :1;/* never has lp2*/charrestart_mode;/* default restart mode*/void(*fixup)(struct tag *, char **, struct meminfo *);void(*reserve)(void);/* reserve mem blocks*/void(*map_io)(void);/* IO mapping function*/void(*init_early)(void);void(*init_irq)(void);struct sys_timer*timer;/* system tick timer*/void(*init_machine)(void);#ifdef CONFIG_MULTI_IRQ_HANDLERvoid(*handle_irq)(struct pt_regs *);#endifvoid(*restart)(char, const char *);};
MACHINE_START和MACHINE_END宏定义
/* * Set of macros to define architecture features.  This is built into * a table by the linker. */#define MACHINE_START(_type,_name)\static const struct machine_desc __mach_desc_##_type\ __used\ __attribute__((__section__(".arch.info.init"))) = {\.nr= MACH_TYPE_##_type,\.name= _name,#define MACHINE_END\};
MACHINE_START(AM335XEVM, "am335xevm")/* Maintainer: Texas Instruments */.atag_offset= 0x100,.map_io= am335x_evm_map_io,.init_early= am33xx_init_early,.init_irq= ti81xx_init_irq,.handle_irq     = omap3_intc_handle_irq,.timer= &omap3_am33xx_timer,.init_machine= am335x_evm_init,MACHINE_END
AM335X体系结构初始化
linux/arch/arm/mach-omap2/Board-arm335xevm.c
以上基于linux3.2.0内核版本

0 0
原创粉丝点击