admin管理员组文章数量:1122850
[TI
前段时间在准备AM437x启动相关的一些事情,对MLO、SPL等事情也是有些糊涂,于是分享下面这篇文章
转自:
参考文件:
1,AM335x ARM Cortex-A8 Microprocessors (MPUs) Technical Reference Manual.pdf;
2,am3359.pdf;
目录
- 1.am335x的cpu上电后,会跳到哪个地址去执行?
- 1.1.第一级 bootloader:
- 1.2.第二级 bootloader:
- 1.3.第三级 bootloader:
- 2.第二级 bootloader:MLO(SPL)做了哪些事情?
- 2.1.SPL内存重映射
- 2.2.保存启动参数 bl save_boot_params
- 2.3.设置 CPU 为 SVC32 模式
- 2.4.CPU的初始化
- 2.5.执行 s_init() 函数,实现 CPU 的初始化
- 2.6.使能第二级缓冲区
- 2.7.关闭看门狗(WDT)
- 2.8.给外设设置好 PLL 和 时钟频率等
- 2.9.使能 32-KHz 频率的实时时钟
- 2.10.使能UART0
- 2.11.初始化 定时器
- 2.12.初始化控制台,通过UART可以查看相关信息
- 2.13.配置 DDR
- 2.14.设置 internal RAM 内存空间的栈指针,调用 board_init_f()函数
- 2.15.代码重定向
- 2.16.清空 bss 段
- 2.17.调用函数 board_init_r,用以完成 MLO(SPI)阶段的所有初始化,并跳转到 uboot.img 阶段
- 3.第三级 bootloader:uboot.img 做了哪些事情?
1.am335x的cpu上电后,会跳到哪个地址去执行?
答:芯片到uboot启动流程 :Internal-ROM → MLO(SPL)→ uboot.img
AM335x 中bootloader被分成了 3 个部分:
1.1.第一级 bootloader:
引导加载程序,板子上电后会自动执行这些代码,如选择哪种方式启动(NAND,SDcard,UART。。。),然后跳转转到第二级 bootloader。这些代码应该是存放在 176KB 的 ROM 中。
1.2.第二级 bootloader:
MLO(SPL),用以硬件初始化:关闭看门狗,关闭中断,设置 CPU 时钟频率、速度等操作。然后会跳转到第三级bootloader。MLO文件应该会被映射到 64 KB的 Internal SRAM 中。
1.3.第三级 bootloader:
uboot.img,C代码的入口。
其中第一级 bootloader 是板子固化的,第二级和第三级是通过编译 uboot 所得的。
2.第二级 bootloader:MLO(SPL)做了哪些事情?
MLO(SPL)内存分布如下:
2.1.SPL内存重映射
< PATH : /arch/arm/cpu/armv7/omap-common/u-boot-spl.lds > MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\LENGTH = CONFIG_SPL_MAX_SIZE } MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \LENGTH = CONFIG_SPL_BSS_MAX_SIZE }OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS {.text :{__start = .;arch/arm/cpu/armv7/start.o (.text)*(.text*)} >.sram. = ALIGN(4);.rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram. = ALIGN(4);.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram. = ALIGN(4);__image_copy_end = .;_end = .;.bss :{. = ALIGN(4);__bss_start = .;*(.bss*). = ALIGN(4);__bss_end__ = .;} >.sdram }
<PATH : /include/configs/am335x_evm.h> #define CONFIG_SPL_TEXT_BASE 0x402F0400 #define CONFIG_SPL_MAX_SIZE (46 * 1024) #define CONFIG_SPL_STACK LOW_LEVEL_SRAM_STACK#define CONFIG_SPL_BSS_START_ADDR 0x80000000 #define CONFIG_SPL_BSS_MAX_SIZE 0x80000 /* 512 KB */ <span style="font-size:16px;color:#003399;"><strong></strong></span>
2.2.保存启动参数 bl save_boot_params
<PATH : /arch/arm/cpu/armv7/start.S> /** the actual reset code*/reset:bl save_boot_params
<PATH : /arch/arm/cpu/armv7/omap-common/lowlevel_init.S> .global save_boot_params save_boot_params:/** See if the rom code passed pointer is valid:* It is not valid if it is not in non-secure SRAM* This may happen if you are booting with the help of* debugger*/ldr r2, =NON_SECURE_SRAM_STARTcmp r2, r0bgt 1fldr r2, =NON_SECURE_SRAM_ENDcmp r2, r0blt 1f/** store the boot params passed from rom code or saved* and passed by SPL*/cmp r0, #0beq 1fldr r1, =boot_paramsstr r0, [r1]
/*《PATH: /arch/arm/include/asm/arch-ti81xx/omap.h》* Non-secure SRAM Addresses* Non-secure RAM starts at 0x40300000 for GP devices. But we keep SRAM_BASE* at 0x40304000(EMU base) so that our code works for both EMU and GP*/ #define NON_SECURE_SRAM_START 0x40304000 #define NON_SECURE_SRAM_END 0x4030E000 #define LOW_LEVEL_SRAM_STACK 0x4030B7FC问题:这些参数是保存在哪里的?大概有哪些参数?
答:这些参数保存的内存地址为 64 KB 的 OCM RAM 中:
注:Dowloaded Image 区域:是用来保存 MLO(SPL) 文件的,其最大可达到 109 KB
2.3.设置 CPU 为 SVC32 模式
<PATH :/arch/arm/cpu/armv7/start.S> /** set the cpu to SVC32 mode*/mrs r0, cpsrbic r0, r0, #0x1forr r0, r0, #0xd3msr cpsr,r0
- CPSR:程序状态寄存器(current program status register)(当前程序状态寄存器),在任何处理器模式下被访问。它包含了条件标志位、中断禁止位、当前处理器模式标志以及其他的一些控制和状态位。
CPSR在用户级编程时用于存储条件码。
- SPSR:程序状态保存寄存器(saved program statusregister),每一种处理器模式下都有一个状态寄存器SPSR,SPSR用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。当特定的异常中断发生时,这个寄存器用于存放当前程序状态寄存器的内容。在异常中断退出时,可以用SPSR来恢复CPSR。由于用户模式和系统模式不是异常中断模式,所以他没有SPSR。当用户在用户模式或系统模式访问SPSR,将产生不可预知的后果。
详解:.html
2.4.CPU的初始化
《PATH : /arch/arm/cpu/armv7/start.S》/* the mask ROM code should have PLL and others stable */ #ifndef CONFIG_SKIP_LOWLEVEL_INITbl cpu_init_crit #endif
<PATH : /arch/arm/cpu/armv7/omap-common/lowlevel_init.S>
.globl lowlevel_init lowlevel_init:/** Setup a temporary stack*/ldr sp, =LOW_LEVEL_SRAM_STACK/** Save the old lr(passed in ip) and the current lr to stack*/push {ip, lr}/** go setup pll, mux, memory*/bl s_initpop {ip, pc}
问题:CPU的初始化有哪些内容?
答:@b1@ 首先要设置堆栈区,因为将会调用 C函数来实现CPU的初始化
问题:这个堆栈在什么位置,其内存大小是多少?
答:
《PATH :/arch/arm/include/asm/arch-ti81xx/omap.h》 #define LOW_LEVEL_SRAM_STACK 0x4030B7FC<strong></strong>
2.5.执行 s_init() 函数,实现 CPU 的初始化
<PATH : /board/ti/am335x/evm.c> /** early system init of muxing and clocks.*/ void s_init(void) {/* Can be removed as A8 comes up with L2 enabled */l2_cache_enable();/* WDT1 is already running when the bootloader gets control* Disable it to avoid "random" resets*/__raw_writel(0xAAAA, WDT_WSPR);while(__raw_readl(WDT_WWPS) != 0x0);__raw_writel(0x5555, WDT_WSPR);while(__raw_readl(WDT_WWPS) != 0x0);#ifdef CONFIG_SPL_BUILD/* Setup the PLLs and the clocks for the peripherals */pll_init();/* Enable RTC32K clock */rtc32k_enable();/* UART softreset */u32 regVal;u32 uart_base = DEFAULT_UART_BASE;enable_uart0_pin_mux();/* IA Motor Control Board has default console on UART3*//* XXX: This is before we've probed / set board_id */if (board_id == IA_BOARD) {uart_base = UART3_BASE;}regVal = __raw_readl(uart_base + UART_SYSCFG_OFFSET);regVal |= UART_RESET;__raw_writel(regVal, (uart_base + UART_SYSCFG_OFFSET) );while ((__raw_readl(uart_base + UART_SYSSTS_OFFSET) &UART_CLK_RUNNING_MASK) != UART_CLK_RUNNING_MASK);/* Disable smart idle */regVal = __raw_readl((uart_base + UART_SYSCFG_OFFSET));regVal |= UART_SMART_IDLE_EN;__raw_writel(regVal, (uart_base + UART_SYSCFG_OFFSET));/* Initialize the Timer */init_timer();preloader_console_init();printf("\nlocation /board/ti/am335x\n"); //@@ /*@@*/ // led(); /*@@*/config_am335x_ddr();#endif }
2.6.使能第二级缓冲区
/* Can be removed as A8 comes up with L2 enabled */ l2_cache_enable();<PATH : /arch/arm/cpu/armv7/ti81xx/cache.S> l2_cache_enable:push {r0, r1, r2, lr}mrc 15, 0, r3, cr1, cr0, 1orr r3, r3, #2mcr 15, 0, r3, cr1, cr0, 1pop {r1, r2, r3, pc}
2.7.关闭看门狗(WDT)
/* WDT1 is already running when the bootloader gets control* Disable it to avoid "random" resets*/ __raw_writel(0xAAAA, WDT_WSPR); while(__raw_readl(WDT_WWPS) != 0x0); __raw_writel(0x5555, WDT_WSPR); while(__raw_readl(WDT_WWPS) != 0x0);
<PATH : /arch/arm/include/asm/arch-ti81xx/cpu.h> #define WDT_WSPR (WDT_BASE + 0x048)<PATH : /arch/arm/include/asm/arch-ti81xx/hardware.h> /* Watchdog Timer */ #ifdef CONFIG_AM335X #define WDT_BASE 0x44E35000 #else #define WDT_BASE 0x480C2000 #endif
2.8.给外设设置好 PLL 和 时钟频率等
/* Setup the PLLs and the clocks for the peripherals */ pll_init();<PATH : /board/ti/am335x/pll.c> /** Configure the PLL/PRCM for necessary peripherals*/ void pll_init() {mpu_pll_config(MPUPLL_M_500);core_pll_config();per_pll_config();ddr_pll_config();/* Enable the required interconnect clocks */interface_clocks_enable();/* Enable power domain transition */power_domain_transition_enable();/* Enable the required peripherals */per_clocks_enable(); }
2.9.使能 32-KHz 频率的实时时钟
/* Enable RTC32K clock */ rtc32k_enable();《PATH : /board/ti/am335x/evm.c》 static void rtc32k_enable(void) {/* Unlock the rtc's registers */__raw_writel(0x83e70b13, (AM335X_RTC_BASE + RTC_KICK0_REG));__raw_writel(0x95a4f1e0, (AM335X_RTC_BASE + RTC_KICK1_REG));/* Enable the RTC 32K OSC */__raw_writel(0x48, (AM335X_RTC_BASE + RTC_OSC_REG)); }<PATH : /arch/arm/include/asm/arch-ti81xx/hardware.h> /* RTC base address */ #define AM335X_RTC_BASE 0x44E3E000<PATH : /board/ti/am335x/evm.c> #define RTC_KICK0_REG 0x6c #define RTC_KICK1_REG 0x70 #define RTC_OSC_REG 0x54
2.10.使能UART0
/* UART softreset */u32 regVal;u32 uart_base = DEFAULT_UART_BASE;enable_uart0_pin_mux();/* IA Motor Control Board has default console on UART3*//* XXX: This is before we've probed / set board_id */if (board_id == IA_BOARD) {uart_base = UART3_BASE;}regVal = __raw_readl(uart_base + UART_SYSCFG_OFFSET);regVal |= UART_RESET;__raw_writel(regVal, (uart_base + UART_SYSCFG_OFFSET) );while ((__raw_readl(uart_base + UART_SYSSTS_OFFSET) &UART_CLK_RUNNING_MASK) != UART_CLK_RUNNING_MASK);/* Disable smart idle */regVal = __raw_readl((uart_base + UART_SYSCFG_OFFSET));regVal |= UART_SMART_IDLE_EN;__raw_writel(regVal, (uart_base + UART_SYSCFG_OFFSET));<PATH : /arch/arm/include/asm/arch-ti81xx/cpu.h> #ifdef CONFIG_AM335X #define DEFAULT_UART_BASE UART0_BASE #endif<PATH : /arch/arm/include/asm/arch-ti81xx/hardware.h> #ifdef CONFIG_AM335X #define UART0_BASE 0x44E09000 #else #define UART0_BASE 0x48020000 #endif
2.11.初始化 定时器
/* Initialize the Timer */ init_timer();<PATH : /board/ti/am335x/evm.c> static void init_timer(void) {/* Reset the Timer */__raw_writel(0x2, (DM_TIMER2_BASE + TSICR_REG));/* Wait until the reset is done */while (__raw_readl(DM_TIMER2_BASE + TIOCP_CFG_REG) & 1);/* Start the Timer */__raw_writel(0x1, (DM_TIMER2_BASE + TCLR_REG)); }<PATH : /arch/arm/include/asm/arch-ti81xx/hardware.h> /* DM Timer base addresses */ #define DM_TIMER0_BASE 0x4802C000 #define DM_TIMER1_BASE 0x4802E000 #define DM_TIMER2_BASE 0x48040000 #define DM_TIMER3_BASE 0x48042000 #define DM_TIMER4_BASE 0x48044000 #define DM_TIMER5_BASE 0x48046000 #define DM_TIMER6_BASE 0x48048000 #define DM_TIMER7_BASE 0x4804A000
2.12.初始化控制台,通过UART可以查看相关信息
preloader_console_init();《PATH : /arch/arm/cpu/armv7/omap-common/spl.c》 /* This requires UART clocks to be enabled */ void preloader_console_init(void) {const char *u_boot_rev = U_BOOT_VERSION;char rev_string_buffer[50];gd = &gdata;gd->bd = &bdata;gd->flags |= GD_FLG_RELOC;gd->baudrate = CONFIG_BAUDRATE;serial_init(); /* serial communications setup *//* Avoid a second "U-Boot" coming from this string */u_boot_rev = &u_boot_rev[7];printf("\nU-Boot SPL %s (%s - %s)\n", u_boot_rev, U_BOOT_DATE,U_BOOT_TIME);omap_rev_string(rev_string_buffer);printf("Texas Instruments %s\n", rev_string_buffer); }
2.13.配置 DDR
config_am335x_ddr();《PATH :》 /* void DDR2_EMIF_Config(void); */ static void config_am335x_ddr(void) {int data_macro_0 = 0;int data_macro_1 = 1;enable_ddr_clocks();config_vtp();Cmd_Macro_Config();Data_Macro_Config(data_macro_0);Data_Macro_Config(data_macro_1);__raw_writel(PHY_RANK0_DELAY, DATA0_RANK0_DELAYS_0);__raw_writel(PHY_RANK0_DELAY, DATA1_RANK0_DELAYS_0);__raw_writel(DDR_IOCTRL_VALUE, DDR_CMD0_IOCTRL);__raw_writel(DDR_IOCTRL_VALUE, DDR_CMD1_IOCTRL);__raw_writel(DDR_IOCTRL_VALUE, DDR_CMD2_IOCTRL);__raw_writel(DDR_IOCTRL_VALUE, DDR_DATA0_IOCTRL);__raw_writel(DDR_IOCTRL_VALUE, DDR_DATA1_IOCTRL);__raw_writel(__raw_readl(DDR_IO_CTRL) & 0xefffffff, DDR_IO_CTRL);__raw_writel(__raw_readl(DDR_CKE_CTRL) | 0x00000001, DDR_CKE_CTRL);config_emif_ddr2(); }《PATH : /arm/include/asm/arch-ti81xx/cpu.h》 #define DATA0_RANK0_DELAYS_0 (DDR_PHY_BASE_ADDR + 0x134) #define DATA1_RANK0_DELAYS_0 (DDR_PHY_BASE_ADDR + 0x1D8)/* DDR offsets */ #define DDR_PHY_BASE_ADDR 0x44E12000 #define DDR_IO_CTRL 0x44E10E04 #define DDR_CKE_CTRL 0x44E1131C #define CONTROL_BASE_ADDR 0x44E10000
2.14.设置 internal RAM 内存空间的栈指针,调用 board_init_f()函数
/* Set stackpointer in internal RAM to call board_init_f */ call_board_init_f:ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ldr r0,=0x00000000bl board_init_f
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_INIT_RAM_ADDR + \CONFIG_SYS_INIT_RAM_SIZE - \GENERATED_GBL_DATA_SIZE)#define CONFIG_SYS_INIT_RAM_ADDR SRAM0_START #define CONFIG_SYS_INIT_RAM_SIZE SRAM0_SIZE#ifdef CONFIG_AM335X #define SRAM0_START 0x402F0400 #else #define SRAM0_START 0x40300000 #endif#if defined(CONFIG_AM335X) || defined(CONFIG_TI814X) #define SRAM0_SIZE (0x1B400) /* 109 KB */ #define SRAM_GPMC_STACK_SIZE (0x40) #endif#define GENERATED_GBL_DATA_SIZE (128) /* (sizeof(struct global_data) + 15) & ~15 */
void board_init_f(ulong dummy) {/** We call relocate_code() with relocation target same as the* CONFIG_SYS_SPL_TEXT_BASE. This will result in relocation getting* skipped. Instead, only .bss initialization will happen. That's* all we need*/debug(">>board_init_f()\n");relocate_code(CONFIG_SPL_STACK, &gdata, CONFIG_SPL_TEXT_BASE); }#define CONFIG_SPL_TEXT_BASE 0x402F0400 #define CONFIG_SPL_MAX_SIZE (46 * 1024) #define CONFIG_SPL_STACK LOW_LEVEL_SRAM_STACK#define LOW_LEVEL_SRAM_STACK 0x4030B7FC
/** void relocate_code (addr_sp, gd, addr_moni)** This "function" does not return, instead it continues in RAM* after relocating the monitor code.**/.globl relocate_code relocate_code:mov r4, r0 /* save addr_sp */mov r5, r1 /* save addr of gd */mov r6, r2 /* save addr of destination 0x402F0400*/</path>
2.15.代码重定位
代码重定向,它首先检测自己(MLO)是否已经在内存中:
如果是直接跳到下面的堆栈初始化代码 clear_bss。
如果不是就将自己从Nor Flash中拷贝到内存中。
Nor Flash 和Nand Flash 本质区别就在于是否进行代码拷贝,也就是下面代码所表述:无论
是Nor Flash 还是Nand Flash,核心思想就是将 uboot 代码搬运到内存中去运行,但是没有拷
贝bss 后面这段代码,只拷贝bss 前面的代码,bss 代码是放置全局变量的。Bss 段代码是为
了清零,拷贝过去再清零重复操作。
/* Set up the stack */ stack_setup:mov sp, r4adr r0, _startcmp r0, r6moveq r9, #0 /* no relocation. relocation offset(r9) = 0 */beq clear_bss /* skip relocation */mov r1, r6 /* r1 <- scratch for copy_loop */ldr r3, _image_copy_end_ofsadd r2, r0, r3 /* r2 <- source end address */copy_loop: /* 自拷贝 */ldmia r0!, {r9-r10} /* copy from source address [r0] */stmia r1!, {r9-r10} /* copy to target address [r1] */cmp r0, r2 /* until source end address [r2] */blo copy_loop@a6@ 清空 bss 段
2.16.清空 bss 段
clear_bss:ldr r0, _bss_start_ofsldr r1, _bss_end_ofsmov r4, r6 /* reloc addr */add r0, r0, r4add r1, r1, r4mov r2, #0x00000000 /* clear */clbss_l:str r2, [r0] /* clear loop... */add r0, r0, #4cmp r0, r1bne clbss_l/** These are defined in the board-specific linker script.*/ .globl _bss_start_ofs _bss_start_ofs:.word __bss_start - _start /* __bss_start = 0x80000000 */
2.17.调用函数 board_init_r,用以完成 MLO(SPI)阶段的所有初始化,并跳转到 uboot.img 阶段
/** We are done. Do not return, instead branch to second part of board* initialization, now running from RAM.*/ jump_2_ram: /** If I-cache is enabled invalidate it*/ #ifndef CONFIG_SYS_ICACHE_OFFmcr p15, 0, r0, c7, c5, 0 @ invalidate icachemcr p15, 0, r0, c7, c10, 4 @ DSBmcr p15, 0, r0, c7, c5, 4 @ ISB #endifldr r0, _board_init_r_ofsadr r1, _startadd lr, r0, r1add lr, lr, r9/* setup parameters for board_init_r */mov r0, r5 /* gd_t */mov r1, r6 /* dest_addr *//* jump to it ... */mov pc, lr_board_init_r_ofs:.word board_init_r - _start
《PATH : /arch/arm/cpu/armv7/omap-common/spl.c 》 void board_init_r(gd_t *id, ulong dummy) {u32 boot_device;debug(">>spl:board_init_r()\n");timer_init();i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);#ifdef CONFIG_SPL_BOARD_INITspl_board_init(); #endifboot_device = omap_boot_device();debug("boot device - %d\n", boot_device);switch (boot_device) { #ifdef CONFIG_SPL_MMC_SUPPORTcase BOOT_DEVICE_MMC1:case BOOT_DEVICE_MMC2:spl_mmc_load_image();break; #endif #ifdef CONFIG_SPL_NAND_SUPPORTcase BOOT_DEVICE_NAND:spl_nand_load_image();break; #endif #ifdef CONFIG_SPL_YMODEM_SUPPORTcase BOOT_DEVICE_UART:spl_ymodem_load_image();break; #endifdefault:printf("SPL: Un-supported Boot Device - %d!!!\n", boot_device);hang();break;}switch (spl_image.os) {case IH_OS_U_BOOT:debug("Jumping to U-Boot\n");jump_to_image_no_args();break;default:puts("Unsupported OS image.. Jumping nevertheless..\n");jump_to_image_no_args();} }
3,第三级 bootloader:uboot.img 做了哪些事情?
uboot.img 内存分布如下:
访问 /arch/arm/lib/board.c 中 的 board_init_f() 函数:
在 uboot.img 运行过程中,有两个非常重要的结构体:gd_t 和 bd_t 。
其中 gd_t :global_data 数据结构的定义,位于:/arch/arm/include/asm/global_data.h 中。
其成员主要是一些全局的系统初始化参数。
其中 bd_t :bd_info 数据结构的定义,位于:/arch/arm/include/asm/u-boot.h 中。
其成员是开发板的相关参数。
/** The following data structure is placed in some memory which is* available very early after boot (like DPRAM on MPC8xx/MPC82xx, or* some locked parts of the data cache) to allow for a minimum set of* global variables during system initialization (until we have set* up the memory controller so that we can use RAM).** Keep it *SMALL* and remember to set GENERATED_GBL_DATA_SIZE > sizeof(gd_t)*/typedef struct global_data {bd_t *bd;unsigned long flags;unsigned long baudrate;unsigned long have_console; /* serial_init() was called */unsigned long env_addr; /* Address of Environment struct */unsigned long env_valid; /* Checksum of Environment valid? */unsigned long fb_base; /* base address of frame buffer */ #ifdef CONFIG_FSL_ESDHCunsigned long sdhc_clk; #endif #ifdef CONFIG_AT91FAMILY/* "static data" needed by at91's clock.c */unsigned long cpu_clk_rate_hz;unsigned long main_clk_rate_hz;unsigned long mck_rate_hz;unsigned long plla_rate_hz;unsigned long pllb_rate_hz;unsigned long at91_pllb_usb_init; #endif #ifdef CONFIG_ARM/* "static data" needed by most of timer.c on ARM platforms */unsigned long timer_rate_hz;unsigned long tbl;unsigned long tbu;unsigned long long timer_reset_value;unsigned long lastinc; #endif #ifdef CONFIG_IXP425unsigned long timestamp; #endifunsigned long relocaddr; /* Start address of U-Boot in RAM */phys_size_t ram_size; /* RAM size */unsigned long mon_len; /* monitor len */unsigned long irq_sp; /* irq stack pointer */unsigned long start_addr_sp; /* start_addr_stackpointer */unsigned long reloc_off; #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))unsigned long tlb_addr; #endifvoid **jt; /* jump table */char env_buf[32]; /* buffer for getenv() before reloc. */ } gd_t;#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")typedef struct bd_info {int bi_baudrate; /* serial console baudrate */unsigned long bi_ip_addr; /* IP Address */ulong bi_arch_number; /* unique id for this board */ulong bi_boot_params; /* where this board expects params */struct /* RAM configuration */{ulong start;ulong size;} bi_dram[CONFIG_NR_DRAM_BANKS]; } bd_t;
其中 DECLARE_GLOBAL_DATA_PTR 宏定义在系统初始化过程中会被频繁调用,
其的作用是,声明gd这么一个全局的指针,这个指针指向gd_t结构体类型,并且这个gd指针是保存在ARM的r8这个寄存器里面的。
uboot.img 第一个运行的文件还是 start.o,其在运行访问的 board_init_f() 函数定义在 /arch/arm/lib/board.c 中:
void board_init_f(ulong bootflag) {bd_t *bd;init_fnc_t **init_fnc_ptr;gd_t *id;ulong addr, addr_sp;/* Pointer is writable since we allocated a register for it */gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);/* compiler optimization barrier needed for GCC >= 3.4 */__asm__ __volatile__("": : :"memory");memset((void *)gd, 0, sizeof(gd_t));... }
#define CONFIG_SYS_INIT_RAM_ADDR SRAM0_START #define CONFIG_SYS_INIT_RAM_SIZE SRAM0_SIZE #define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_INIT_RAM_ADDR + \CONFIG_SYS_INIT_RAM_SIZE - \GENERATED_GBL_DATA_SIZE)#define SRAM0_START 0x402F0400#define SRAM0_SIZE (0x1B400) /* 109 KB */#define GENERATED_GBL_DATA_SIZE (128) /* (sizeof(struct global_data) + 15) & ~15 */
因此,系统初始化参数将会被保存在 (保存 MLO(SPL)文件的内存空间的)末尾 2 KB 处。
通过计算的 gb 指针指向的内存空间地址为 gb = 0x4030B000
gb_t 结构体中某些元素的值是来自于 uboot.img's header,这个header的数据保存在内存的0x807FFFCO,大小为 64字节
/** Legacy format image header,* all data in network byte order (aka natural aka bigendian).*/ typedef struct image_header {uint32_t ih_magic; /* Image Header Magic Number */uint32_t ih_hcrc; /* Image Header CRC Checksum */uint32_t ih_time; /* Image Creation Timestamp */uint32_t ih_size; /* Image Data Size */uint32_t ih_load; /* Data Load Address */uint32_t ih_ep; /* Entry Point Address */uint32_t ih_dcrc; /* Image Data CRC Checksum */uint8_t ih_os; /* Operating System */uint8_t ih_arch; /* CPU architecture */uint8_t ih_type; /* Image Type */uint8_t ih_comp; /* Compression Type */uint8_t ih_name[IH_NMLEN]; /* Image Name */ } image_header_t;
/** 8MB into the SDRAM to allow for SPL's bss at the beginning of SDRAM.* 64 bytes before this address should be set aside for u-boot.img's* header. That is 0x807FFFC0--0x80800000 should not be used for any* other needs.*/ #define CONFIG_SYS_TEXT_BASE 0x80800000</path>
void board_init_f(ulong bootflag) {bd_t *bd;init_fnc_t **init_fnc_ptr;gd_t *id;ulong addr, addr_sp;/* Pointer is writable since we allocated a register for it */gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);/* compiler optimization barrier needed for GCC >= 3.4 */__asm__ __volatile__("": : :"memory");memset((void *)gd, 0, sizeof(gd_t));... }
转载于:.html
本文标签: TI
版权声明:本文标题:[TI 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/biancheng/1701274245a369314.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论