• crt0.S(_main)代码分析


    crt0,S(_main)代码分析


    1. 设置sp寄存器地址

    //设置SP栈指针
    #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
    	ldr	sp, =(CONFIG_SPL_STACK)
    #else
    	ldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)
    #endif
    
    //设置地址八位对齐
    #if defined(CONFIG_CPU_V7M)	/* v7M forbids using SP as BIC destination*/
    	mov	r3, sp			   
    	bic	r3, r3, #7		   //* 后三位清零相当于堆栈地址八位对齐
    	mov	sp, r3				 
    #else
    	bic	sp, sp, #7	/* 8-byte alignment for ABI compliance */	
    #endif
    

    2. 在栈中为全局变量gd分配空间

    // r0寄存器传递函数的参数
    mov	r0, sp
    bl	board_init_f_alloc_reserve	//在栈中为全局数据分配空间
    mov	sp, r0		
    //函数调用后返回值在r0中,将其保存到sp寄存器中	
    //根据下面的board_init_f_alloc_reserve函数
    //函数返回值为分配gb后的指针位置
    

    board_init_f_alloc_reserve函数原型如下:

    ulong board_init_f_alloc_reserve(ulong top)
    {
    	//将栈顶指针传进来,栈顶指针减去全局变量的长度意味着数据入栈,即在栈里预留变量存储空间。
    	/* Reserve early malloc arena */
    #if defined(CONFIG_SYS_MALLOC_F)
    	top -= CONFIG_SYS_MALLOC_F_LEN;
    #endif
    	/* LAST : reserve GD (rounded up to a multiple of 16 bytes) */
    	top = rounddown(top-sizeof(struct global_data), 16);
    	return top;
    }
    

    3. 在栈中gd空间清零

    	mov	r9, r0	//将栈顶指针存到r9寄存器里面,方便后续设置gd指针
    	bl	board_init_f_init_reserve	//全局数据全部清零
    

    board_init_f_init_reserve 函数定义如下:

    void board_init_f_init_reserve(ulong base)
    {
    	struct global_data *gd_ptr;
    #ifndef _USE_MEMCPY
    	int *ptr;
    #endif
    
    	/*
    	 * clear GD entirely and set it up.
    	 * Use gd_ptr, as gd may not be properly set yet.
    	 * 清除GD分配空间
    	 */
    	
    	gd_ptr = (struct global_data *)base;
    	/* zero the area */
    #ifdef _USE_MEMCPY
    	memset(gd_ptr, '', sizeof(*gd));	//全局数据区全部清零
    #else
    	for (ptr = (int *)gd_ptr; ptr < (int *)(gd_ptr + 1); )
    		*ptr++ = 0;
    #endif
    
    	/* set GD unless architecture did it already */
    #if !defined(CONFIG_ARM)
    	arch_setup_gd(gd_ptr);
    #endif
    	/* next alloc will be higher by one GD plus 16-byte alignment */
    	base += roundup(sizeof(struct global_data), 16);
    
    	/*
    	 * record early malloc arena start.
    	 * Use gd as it is now properly set for all architectures.
    	 */
    
    #if defined(CONFIG_SYS_MALLOC_F)
    	/* go down one 'early malloc arena' */
    	gd->malloc_base = base;
    	/* next alloc will be higher by one 'early malloc arena' size */
    	base += CONFIG_SYS_MALLOC_F_LEN;
    #endif
    }
    

    4. 调用board_init_f,初始化各种硬件

    	mov	r0, #0
    	bl	board_init_f	// jump to ==> board_f.c
    

    在board_init_f函数中所进行的主要操作如下,其中init_sequence_f[ ]是一个数组,其内容为一系列初始化函数,在函数initcall_run_list中依次调用init_sequence_f数组的各个初始化函数。

    void board_init_f(ulong boot_flags)
    {
    	//此处省略多行代码
    	gd->flags = boot_flags;
    	gd->have_console = 0;
    	//通过调用initcall_run_list函数,执行各项初始化	
    	if (initcall_run_list(init_sequence_f)) 
    		hang();
    }
    

    initcall_run_list函数如下:

    int initcall_run_list(const init_fnc_t init_sequence[])
    {	
    	const init_fnc_t *init_fnc_ptr;
    	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
    		int ret;
    		//此处省略很多代码
    		//通过函数指针依次调用数组内函数
    		ret = (*init_fnc_ptr)();		
    	}
    return 0;
    }
    

    数组init_sequence_f[ ]定义如下,每个成员为一个函数指针,函数参数为void,返回类型为int

    static init_fnc_t init_sequence_f[] = {
    #ifdef CONFIG_SANDBOX
    	setup_ram_buf,
    #endif
    	setup_mon_len,
    #ifdef CONFIG_OF_CONTROL
    	fdtdec_setup,
    #endif
    #ifdef CONFIG_TRACE
    	trace_early_init,
    #endif
    	initf_malloc,
    	initf_console_record,
    #if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
    	/* TODO: can this go into arch_cpu_init()? */
    	probecpu,
    #endif
    #if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)
    	x86_fsp_init,
    #endif
    	arch_cpu_init,		/* basic arch cpu dependent setup */
    	mach_cpu_init,		/* SoC/machine dependent CPU setup */
    	initf_dm,
    	arch_cpu_init_dm,
    	mark_bootstage,		/* need timer, go after init dm */
    #if defined(CONFIG_BOARD_EARLY_INIT_F)
    	board_early_init_f,
    #endif
    	/* TODO: can any of this go into arch_cpu_init()? */
    #if defined(CONFIG_PPC) && !defined(CONFIG_8xx_CPUCLK_DEFAULT)
    	get_clocks,		/* get CPU and bus clocks (etc.) */
    #if defined(CONFIG_TQM8xxL) && !defined(CONFIG_TQM866M) 
    		&& !defined(CONFIG_TQM885D)
    	adjust_sdram_tbs_8xx,
    #endif
    	/* TODO: can we rename this to timer_init()? */
    	init_timebase,
    #endif
    #if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || 
    		defined(CONFIG_BLACKFIN) || defined(CONFIG_NDS32) || 
    		defined(CONFIG_SH) || defined(CONFIG_SPARC)
    	timer_init,		/* initialize timer */
    #endif
    #ifdef CONFIG_SYS_ALLOC_DPRAM
    #if !defined(CONFIG_CPM2)
    	dpram_init,
    #endif
    #endif
    #if defined(CONFIG_BOARD_POSTCLK_INIT)
    	board_postclk_init,
    #endif
    #if defined(CONFIG_SYS_FSL_CLK) || defined(CONFIG_M68K)
    	get_clocks,
    #endif
    	env_init,		/* initialize environment */
    #if defined(CONFIG_8xx_CPUCLK_DEFAULT)
    	/* get CPU and bus clocks according to the environment variable */
    	get_clocks_866,
    	/* adjust sdram refresh rate according to the new clock */
    	sdram_adjust_866,
    	init_timebase,
    #endif
    	init_baud_rate,		/* initialze baudrate settings */
    	serial_init,		/* serial communications setup */
    	console_init_f,		/* stage 1 init of console */
    #ifdef CONFIG_SANDBOX
    	sandbox_early_getopt_check,
    #endif
    	display_options,	/* say that we are here */
    	display_text_info,	/* show debugging info if required */
    #if defined(CONFIG_MPC8260)
    	prt_8260_rsr,
    	prt_8260_clks,
    #endif /* CONFIG_MPC8260 */
    #if defined(CONFIG_MPC83xx)
    	prt_83xx_rsr,
    #endif
    #if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SH)
    	checkcpu,
    #endif
    	print_cpuinfo,		/* display cpu info (and speed) */
    #if defined(CONFIG_MPC5xxx)
    	prt_mpc5xxx_clks,
    #endif /* CONFIG_MPC5xxx */
    #if defined(CONFIG_DTB_RESELECT)
    	embedded_dtb_select,
    #endif
    #if defined(CONFIG_DISPLAY_BOARDINFO)
    	show_board_info,
    #endif
    	INIT_FUNC_WATCHDOG_INIT
    #if defined(CONFIG_MISC_INIT_F)
    	misc_init_f,
    #endif
    	INIT_FUNC_WATCHDOG_RESET
    #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)
    	init_func_i2c,
    #endif
    #if defined(CONFIG_HARD_SPI)
    	init_func_spi,
    #endif
    	announce_dram_init,
    	/* TODO: unify all these dram functions? */
    #if defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_NDS32) || 
    		defined(CONFIG_MICROBLAZE) || defined(CONFIG_AVR32) || 
    		defined(CONFIG_SH)
    	dram_init,		/* configure available RAM banks */
    #endif
    #if defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_M68K)
    	init_func_ram,
    #endif
    #ifdef CONFIG_POST
    	post_init_f,
    #endif
    	INIT_FUNC_WATCHDOG_RESET
    #if defined(CONFIG_SYS_DRAM_TEST)
    	testdram,
    #endif /* CONFIG_SYS_DRAM_TEST */
    	INIT_FUNC_WATCHDOG_RESET
    
    #ifdef CONFIG_POST
    	init_post,
    #endif
    	INIT_FUNC_WATCHDOG_RESET
    	/*
    	 * Now that we have DRAM mapped and working, we can
    	 * relocate the code and continue running from DRAM.
    	 *
    	 * Reserve memory at end of RAM for (top down in that order):
    	 *  - area that won't get touched by U-Boot and Linux (optional)
    	 *  - kernel log buffer
    	 *  - protected RAM
    	 *  - LCD framebuffer
    	 *  - monitor code
    	 *  - board info struct
    	 */
    	setup_dest_addr,
    #if defined(CONFIG_BLACKFIN) || defined(CONFIG_XTENSA)
    	/* Blackfin u-boot monitor should be on top of the ram */
    	reserve_uboot,
    #endif
    #if defined(CONFIG_SPARC)
    	reserve_prom,
    #endif
    #if defined(CONFIG_LOGBUFFER) && !defined(CONFIG_ALT_LB_ADDR)
    	reserve_logbuffer,
    #endif
    #ifdef CONFIG_PRAM
    	reserve_pram,
    #endif
    	reserve_round_4k,
    #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && 
    		defined(CONFIG_ARM)
    	reserve_mmu,
    #endif
    #ifdef CONFIG_DM_VIDEO
    	reserve_video,
    #else
    # ifdef CONFIG_LCD
    	reserve_lcd,
    # endif
    	/* TODO: Why the dependency on CONFIG_8xx? */
    # if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) && 
    		!defined(CONFIG_ARM) && !defined(CONFIG_X86) && 
    		!defined(CONFIG_BLACKFIN) && !defined(CONFIG_M68K)
    	reserve_legacy_video,
    # endif
    #endif /* CONFIG_DM_VIDEO */
    	reserve_trace,
    #if !defined(CONFIG_BLACKFIN) && !defined(CONFIG_XTENSA)
    	reserve_uboot,
    #endif
    #ifndef CONFIG_SPL_BUILD
    	reserve_malloc,
    	reserve_board,
    #endif
    	setup_machine,
    	reserve_global_data,
    	reserve_fdt,
    	reserve_arch,
    	reserve_stacks,
    	setup_dram_config,
    	show_dram_config,
    #if defined(CONFIG_M68K) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || 
    	defined(CONFIG_SH)
    	setup_board_part1,
    #endif
    #if defined(CONFIG_PPC) || defined(CONFIG_M68K)
    	INIT_FUNC_WATCHDOG_RESET
    	setup_board_part2,
    #endif
    	display_new_sp,
    #ifdef CONFIG_SYS_EXTBDINFO
    	setup_board_extra,
    #endif
    	INIT_FUNC_WATCHDOG_RESET
    	reloc_fdt,
    	setup_reloc,
    #if defined(CONFIG_X86) || defined(CONFIG_ARC)
    	copy_uboot_to_ram,
    	clear_bss,
    	do_elf_reloc_fixups,
    #endif
    #if defined(CONFIG_XTENSA)
    	clear_bss,
    #endif
    #if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)
    	jump_to_copy,
    #endif
    	NULL,
    };
    
  • 相关阅读:
    [TPYBoard
    Ubuntu 16.04 搭建KVM环境
    kali kvm Requested operation is not valid: network 'default' is not active
    SFTP文件上传与下载(window 上传文件到linux服务器)
    如何在linux下查看目录的剩余空间大小
    虚拟机三种网络模式详解(Bridge,Nat,Host-only)
    Vmware虚拟机三种网络模式详解
    vmware的硬件选项里有关于虚拟化引擎的选项(虚拟机支持硬件虚拟化)
    liunx Swap 分区的作用
    linux中chmod与chown两个命令详解
  • 原文地址:https://www.cnblogs.com/gexin/p/7281633.html
Copyright © 2020-2023  润新知