<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    嵌入式 uboot引導kernel,kernel引導fs

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接
    1、uboot引導kernel:
          u-boot中有個bootm命令,它可以引導內存中的應用程序映像(Kernel),bootm命令對應
    common/cmd_bootm.c中的do_bootm()函數,此函數實現下面幾個功能:
        1)讀flash中的內核映像文件
        2)解壓內核
        3)校驗內核
        4)跳到內核執行(調用do_bootm_linux()函數)
        {

    1、Stage1 start.S代碼結構 u-boot的stage1代碼通常放在start.S文件中,他用匯編語言寫成,其主要代碼部分如下

     

    (1) 定義入口。: 

    該工作通過修改連接器腳本來完成。

    (2)設置異常向量(Exception Vector)。 

    (3)設置CPU的速度、時鐘頻率及終端控制寄存器。 

    (4)初始化內存控制器。 

    (5)將ROM中的程序復制到RAM中。 

    (6)初始化堆棧。 

    (7)轉到RAM中執行,該工作可使用指令ldr pc來完成。

     

    2、Stage2 C語言代碼部分 lib_arm/board.c中的start arm boot是C語言開始的函數也是整個啟動代碼中C語言的主函數,同時還是整個u-boot(armboot)的主函數,該函數只要完成如下操作: 

    (1)調用一系列的初始化函數。 

    (2)初始化Flash設備。 

    (3)初始化系統內存分配函數。 

    (4)如果目標系統擁有NAND設備,則初始化NAND設備。 

    (5)如果目標系統有顯示設備,則初始化該類設備。 

    (6)初始化相關網絡設備,填寫IP、MAC地址等。 

    (7)進去命令循環(即整個boot的工作循環),接受用戶從串口輸入的命令,然后進行相應的工作。

    }
    
    
    2、kernel引導fs:
        1)獲得可運行的Linux內核
        2)內核裝載時的內存空間映射
        3)內核啟始相關文件分析
        4)arch/i386/boot/bootsect.S
        5)arch/i386/boot/setup.S
        6)arch/i386/boot/compressed/head.S
        7)arch/i386/kernel/head.S
        8)start_kernel
        {

    在start_kernel()函數中:

      輸出Linux版本信息(printk(_banner))

      設置與體系結構相關的環境(setup_arch())

      頁表結構初始化(paging_init())

      使用"arch/alpha/kernel/entry.S"中的入口點設置系統自陷入口(trap_init())

      使用alpha_mv結構和entry.S入口初始化系統IRQ(init_IRQ())

      核心進程調度器初始化(包括初始化幾個缺省的Bottom-half,sched_init())

      時間、定時器初始化(包括讀取CMOS時鐘、估測主頻、初始化定時器中斷等,time_init())

      提取并分析核心啟動參數(從環境變量中讀取參數,設置相應標志位等待處理,(parse_options())

      控制臺初始化(為輸出信息而先于PCI初始化,console_init())

      剖析器數據結構初始化(prof_buffer和prof_len變量)

      核心Cache初始化(描述Cache信息的Cache,kmem_cache_init())

      延遲校準(獲得時鐘jiffies與CPU主頻ticks的延遲,calibrate_delay())

      內存初始化(設置內存上下界和頁表項初始值,mem_init())

      創建和設置內部及通用cache("slab_cache",kmem_cache_sizes_init())

      創建uid taskcount SLAB cache("uid_cache",uidcache_init())

      創建文件cache("files_cache",filescache_init())

      創建目錄cache("dentry_cache",dcache_init())

      創建與虛存相關的cache("vm_area_struct","mm_struct",vma_init())

      塊設備讀寫緩沖區初始化(同時創建"buffer_head"cache用戶加速訪問,buffer_init())

      創建頁cache(內存頁hash表初始化,page_cache_init())

      創建信號隊列cache("signal_queue",signals_init())

      初始化內存inode表(inode_init())

      創建內存文件描述符表("filp_cache",file_table_init())

      檢查體系結構漏洞(對于alpha,此函數為空,check_bugs())

      SMP機器其余CPU(除當前引導CPU)初始化(對于沒有配置SMP的內核,此函數為空,smp_init())

      啟動init過程(run_init_process() 創建第一個核心線程,調用init()函數,原執行序列調用cpu_idle() 等待調度,init())

      至此start_kernel()結束,基本的核心環境已經建立起來了。

        }
        9)第一個內核線程 - kernel_init
    
    
    三、start_kernel函數流程:
    asmlinkage void __init start_kernel(void)
    {
    	char * command_line;
    	extern const struct kernel_param __start___param[], __stop___param[];
    
    
    	smp_setup_processor_id();//首先判斷是否是SMP (對稱多處理器)對單核SOC來說,mpidr = 0;
    
    
    	/*
    	 * 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();//stack_canary的是帶防止棧溢出攻擊保護的堆棧
    
    
    	/**
    	 * cgroup_init_early - cgroup initialization at system boot
    	 *
    	 * Initialize cgroups at system boot, and initialize any
    	 * subsystems that request early init.
    	 */
    	cgroup_init_early(); 
    
    
    	local_irq_disable();
    	early_boot_irqs_disabled = true;
    
    
    /*
     * Interrupts are still disabled. Do necessary setups, then
     * enable them
     */
    	//初始化time ticket,時鐘
    	tick_init(); 
    
    
    	//用以啟動的CPU進行初始化。也就是初始化CPU0
    	boot_cpu_init();
    
    
    	//初始化頁面
    	page_address_init();
    
    
    	printk(KERN_NOTICE "%s", linux_banner);
    
    
    	//CPU架構相關的初始化
    	setup_arch(&command_line);
    	
    	//初始化內存管理		
    	mm_init_owner(&init_mm, &init_task);
    	mm_init_cpumask(&init_mm);
    	
    	//處理啟動命令行
    	setup_command_line(command_line);
    
    
    	//可能多余的初始化可能去判斷cpu的最大支持個數
    	setup_nr_cpu_ids();
    
    
    	//為每個CPU開辟一塊區域?
    	setup_per_cpu_areas();
    
    
    	//準備boot_cpu.如果是SMP環境,則設置boot CPU的一些數據。在引導過程中使用的CPU稱為boot CPU
    	smp_prepare_boot_cpu();	/* arch-specific boot-cpu hooks */
    
    
    	//Linux將所有物理內存分為三個區,ZONE_DMA, ZONE_NORMAM, ZONE_HIGHMEM
    	build_all_zonelists(NULL);
    	
    	//初始化page allocation相關結構
    	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);
    	/*
    	 * These use large bootmem allocations and must precede
    	 * kmem_cache_init()
    	 */
    	setup_log_buf(0);
    
    
    	//初始化process ID hash表
    	pidhash_init();
    
    
    	//文件系統caches預初始化
    	vfs_caches_init_early();
    
    
    	//初始化exception table
    	sort_main_extable();
    
    
    	//初始化trap,用以處理錯誤執行代碼
    	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();
    	
    	//Read_Copy_Update機制初始 /*初始化互斥機制*/  
    	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(一個內核性能調式工具)功能進行初始化 */    
    	profile_init();
    	
    	call_function_init();//???
    	if (!irqs_disabled())
    		printk(KERN_CRIT "start_kernel(): bug: interrupts were "
    				 "enabled early\n");
    	early_boot_irqs_disabled = false;
    
    
    	 /*打開IRQ中斷*/ 
    	local_irq_enable();
    
    
    	/* Interrupts are enabled now so all GFP allocations are safe. */
    	gfp_allowed_mask = __GFP_BITS_MASK;
    
    
    	//初始化CPU Cache
    	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
    	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_INITRD
    	if (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;
    	}
    #endif
    
    
    	//頁面初始
    	page_cgroup_init();
    
    
    	//頁面分配debug啟用
    	enable_debug_pagealloc();
    	debug_objects_mem_init();
    	
    	//memory leak 偵測初始化
    	kmemleak_init();
    	
    	//設置每個CPU的頁面集合
    	setup_per_cpu_pageset();
    	numa_policy_init();
    	if (late_time_init)
    		late_time_init();
    
    
    	//初始化調度時鐘
    	sched_clock_init();
    
    
    	/*校驗延時函數的精確度*/  
    	calibrate_delay();
    
    
    	/*進程號位圖初始化,一般用一個page來只是所有的進程PID占用情況*/ 
    	pidmap_init();
    
    
    	//anonymous page?什么意思?
    	anon_vma_init();
    
    
    #ifdef CONFIG_X86
    	if (efi_enabled)
    		efi_enter_virtual_mode();
    #endif
    
    
    	//初始化thread info
    	thread_info_cache_init();
    
    
    	//credential
    	cred_init();
    	
    	//初始化fork
    	fork_init(totalram_pages);
    	
    	//初始化/proc的cache?
    	proc_caches_init();
    	
    	buffer_init();
    	key_init();
    	security_init();
    	dbg_late_init();
    
    
    	//文件系統cache初始化
    	vfs_caches_init(totalram_pages);
    	signals_init();
    	
    	/* rootfs populating might need page-writeback */
    	page_writeback_init();
    
    
    #ifdef CONFIG_PROC_FS
    	proc_root_init();//本文件系統??
    #endif
    
    
    	cgroup_init();
    	cpuset_init();
    	taskstats_init_early();
    	delayacct_init();
    
    
    	check_bugs();
    
    
    	acpi_early_init(); /* before LAPIC and SMP init */
    
    
    	//simple firmware interface
    	sfi_init_late();
    
    
    	ftrace_init();
    
    
    	/* Do the rest non-__init'ed, we're now alive */
    	rest_init();
    }
    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全