参考文件:

1,AM335x ARM Cortex-A8 Microprocessors (MPUs) Technical Reference Manual.pdf;

2,am3359.pdf;

1,am335x的cpu上电后,会跳到哪个地址去执行?

答:

芯片到uboot启动流程:ROM → MLO(SPL)→ uboot.img

AM335x 中bootloader被分成了 3 个部分:

第一级 bootloader:引导加载程序,板子上电后会自动执行这些代码,如选择哪种方式启动(NAND,SDcard,UART。。。),然后跳转转到第二级 bootloader。这些代码应该是存放在 176KB 的 ROM 中。

第二级 bootloader:MLO(SPL),用以硬件初始化:关闭看门狗,关闭中断,设置 CPU 时钟频率、速度等操作。然后会跳转到第三级bootloader。MLO文件应该会被映射到 64 KB的 Internal SRAM 中。

第三级 bootloader:uboot.img,C代码的入口。

其中第一级 bootloader 是板子固化的,第二级和第三级是通过编译 uboot 所得的。

2,第二级 bootloader:MLO(SPL)做了哪些事情?

MLO(SPL)内存分布如下:

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

}

#define CONFIG_SPL_TEXT_BASE0x402F0400

#define CONFIG_SPL_MAX_SIZE(46 * 1024)

#define CONFIG_SPL_STACKLOW_LEVEL_SRAM_STACK

#define CONFIG_SPL_BSS_START_ADDR0x80000000

#define CONFIG_SPL_BSS_MAX_SIZE0x80000/* 512 KB */

@1@ 保存启动参数bl    save_boot_params

/*

* the actual reset code

*/

reset:

blsave_boot_params

.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_START

cmpr2, r0

bgt1f

ldrr2, =NON_SECURE_SRAM_END

cmpr2, r0

blt1f

/*

* store the boot params passed from rom code or saved

* and passed by SPL

*/

cmpr0, #0

beq1f

ldrr1, =boot_params

strr0, [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_START0x40304000

#define NON_SECURE_SRAM_END0x4030E000

#define LOW_LEVEL_SRAM_STACK0x4030B7FC

问题:这些参数是保存在哪里的?大概有哪些参数?

答:

这些参数保存的内存地址为 64 KB 的 OCM RAM 中:

注:Dowloaded Image 区域:是用来保存 MLO(SPL) 文件的,其最大可达到 109 KB

@a2@ 设置 CPU 为 SVC32 模式

/*

* set the cpu to SVC32 mode

*/

mrsr0, cpsr

bicr0, r0, #0x1f

orrr0, r0, #0xd3

msrcpsr,r0

CPSR:程序状态寄存器(current program status register)

(当前程序状态寄存器),在任何处理器模式下被访问。它包含了条件标志位、中断禁止位、当前处理器模式标志以及其他的一些控制和状态位。

CPSR在用户级编程时用于存储条件码。

SPSR:程序状态保存寄存器(saved program status

register),每一种处理器模式下都有一个状态寄存器SPSR,SPSR用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。当特定

的异常中断发生时,这个寄存器用于存放当前程序状态寄存器的内容。在异常中断退出时,可以用SPSR来恢复CPSR。由于用户模式和系统模式不是异常中断

模式,所以他没有SPSR。当用户在用户模式或系统模式访问SPSR,将产生不可预知的后果。

CPSR格式如下所示。SPSR和CPSR格式相同。

31 30 29 28 27 26 7 6 5 4 3 2 1 0

N Z C V Q DNM(RAZ) I F T M4 M3 M2 M1 M0

@a3@ CPU的初始化

《PATH : /arch/arm/cpu/armv7/start.S》

/* the mask ROM code should have PLL and others stable */

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

blcpu_init_crit

#endif

.globl lowlevel_init

lowlevel_init:

/*

* Setup a temporary stack

*/

ldrsp, =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

*/

bls_init

pop{ip, pc}

问题:CPU的初始化有哪些内容?

答:

@b1@ 首先要设置堆栈区,因为将会调用 C函数来实现CPU的初始化

问题:这个堆栈在什么位置,其内存大小是多少?

《PATH :/arch/arm/include/asm/arch-ti81xx/omap.h》

#define LOW_LEVEL_SRAM_STACK0x4030B7FC

@b2@ 执行 s_init() 函数,实现 CPU 的初始化

/*

* 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

}

@c1@ 使能第二级缓冲区

/* Can be removed as A8 comes up with L2 enabled */

l2_cache_enable();

l2_cache_enable:

push{r0, r1, r2, lr}

mrc15, 0, r3, cr1, cr0, 1

orrr3, r3, #2

mcr15, 0, r3, cr1, cr0, 1

pop{r1, r2, r3, pc}

@c2@ 关闭看门狗(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);

#define WDT_WSPR(WDT_BASE + 0x048)

/* Watchdog Timer */

#ifdef CONFIG_AM335X

#define WDT_BASE0x44E35000

#else

#define WDT_BASE0x480C2000

#endif

@c3@给外设设置好 PLL 和 时钟频率等

/* Setup the PLLs and the clocks for the peripherals */

pll_init();

/*

* 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();

}

@c4@ 使能 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));

}

/* RTC base address */

#define AM335X_RTC_BASE            0x44E3E000

#define RTC_KICK0_REG        0x6c

#define RTC_KICK1_REG        0x70

#define RTC_OSC_REG        0x54

@c5@ 使能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));

#ifdef CONFIG_AM335X

#define DEFAULT_UART_BASEUART0_BASE

#endif

#ifdef CONFIG_AM335X

#define UART0_BASE0x44E09000

#else

#define UART0_BASE0x48020000

#endif

@c6@ 初始化 定时器

/* Initialize the Timer */

init_timer();

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));

}

/* DM Timer base addresses */

#define DM_TIMER0_BASE0x4802C000

#define DM_TIMER1_BASE0x4802E000

#define DM_TIMER2_BASE0x48040000

#define DM_TIMER3_BASE0x48042000

#define DM_TIMER4_BASE0x48044000

#define DM_TIMER5_BASE0x48046000

#define DM_TIMER6_BASE0x48048000

#define DM_TIMER7_BASE0x4804A000

@c7@ 初始化控制台,通过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);

}

@c8@ 配置 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)

#defineDATA1_RANK0_DELAYS_0(DDR_PHY_BASE_ADDR + 0x1D8)

/* DDR offsets */

#defineDDR_PHY_BASE_ADDR0x44E12000

#defineDDR_IO_CTRL0x44E10E04

#defineDDR_CKE_CTRL0x44E1131C

#defineCONTROL_BASE_ADDR0x44E10000

@c DONE@

@b DONE@

@a4@ 设置 internal RAM 内存空间的栈指针,调用 board_init_f()函数

/* Set stackpointer in internal RAM to call board_init_f */

call_board_init_f:

ldrsp, =(CONFIG_SYS_INIT_SP_ADDR)

bicsp, sp, #7 /* 8-byte alignment for ABI compliance */

ldrr0,=0x00000000

blboard_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_ADDRSRAM0_START

#define CONFIG_SYS_INIT_RAM_SIZESRAM0_SIZE

#ifdef CONFIG_AM335X

#define SRAM0_START0x402F0400

#else

#define SRAM0_START0x40300000

#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_BASE0x402F0400

#define CONFIG_SPL_MAX_SIZE(46 * 1024)

#define CONFIG_SPL_STACKLOW_LEVEL_SRAM_STACK

#define LOW_LEVEL_SRAM_STACK0x4030B7FC

/*

* void relocate_code (addr_sp, gd, addr_moni)

*

* This "function" does not return, instead it continues in RAM

* after relocating the monitor code.

*

*/

.globlrelocate_code

relocate_code:

movr4, r0/* save addr_sp */

movr5, r1/* save addr of gd */

movr6, r2/* save addr of destination 0x402F0400*/

@a5@ 代码重定位

代码重定向,它首先检测自己(MLO)是否已经在内存中:

如果是直接跳到下面的堆栈初始化代码clear_bss。

如果不是就将自己从Nor Flash中拷贝到内存中。

Nor Flash 和Nand Flash 本质区别就在于是否进行代码拷贝,也就是下面代码所表述:无论

是Nor Flash 还是Nand Flash,核心思想就是将 uboot 代码搬运到内存中去运行,但是没有拷

贝bss 后面这段代码,只拷贝bss 前面的代码,bss 代码是放置全局变量的。Bss 段代码是为

了清零,拷贝过去再清零重复操作。

/* Set up the stack */

stack_setup:

movsp, r4

adrr0, _start

cmpr0, r6

moveqr9, #0/* no relocation. relocation offset(r9) = 0 */

beqclear_bss/* skip relocation */

movr1, r6/* r1

@a6@ 清空 bss 段

clear_bss:

ldrr0, _bss_start_ofs

ldrr1, _bss_end_ofs

movr4, r6/* reloc addr */

addr0, r0, r4

addr1, r1, r4

movr2, #0x00000000/* clear */

clbss_l:strr2, [r0]/* clear loop... */

addr0, r0, #4

cmpr0, r1

bneclbss_l

/*

* These are defined in the board-specific linker script.

*/

.globl _bss_start_ofs

_bss_start_ofs:

.word __bss_start - _start          /* __bss_start = 0x80000000 */

@a7@ 调用函数 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_OFF

mcrp15, 0, r0, c7, c5, 0@ invalidate icache

mcr p15, 0, r0, c7, c10, 4@ DSB

mcr p15, 0, r0, c7, c5, 4@ ISB

#endif

ldrr0, _board_init_r_ofs

adrr1, _start

addlr, r0, r1

addlr, lr, r9

/* setup parameters for board_init_r */

movr0, r5/* gd_t */

movr1, r6/* dest_addr */

/* jump to it ... */

movpc, 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_INIT

spl_board_init();

#endif

boot_device = omap_boot_device();

debug("boot device - %d\n", boot_device);

switch (boot_device) {

#ifdef CONFIG_SPL_MMC_SUPPORT

case BOOT_DEVICE_MMC1:

case BOOT_DEVICE_MMC2:

spl_mmc_load_image();

break;

#endif

#ifdef CONFIG_SPL_NAND_SUPPORT

case BOOT_DEVICE_NAND:

spl_nand_load_image();

break;

#endif

#ifdef CONFIG_SPL_YMODEM_SUPPORT

case BOOT_DEVICE_UART:

spl_ymodem_load_image();

break;

#endif

default:

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();

}

}

@a DONE@

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)

*/

typedefstructglobal_data {

bd_t*bd;

unsigned longflags;

unsigned longbaudrate;

unsigned longhave_console;/* serial_init() was called */

unsigned longenv_addr;/* Address of Environment struct */

unsigned longenv_valid;/* Checksum of Environment valid? */

unsigned longfb_base;/* base address of frame buffer */

#ifdef CONFIG_FSL_ESDHC

unsigned longsdhc_clk;

#endif

#ifdef CONFIG_AT91FAMILY

/* "static data" needed by at91's clock.c */

unsigned longcpu_clk_rate_hz;

unsigned longmain_clk_rate_hz;

unsigned longmck_rate_hz;

unsigned longplla_rate_hz;

unsigned longpllb_rate_hz;

unsigned longat91_pllb_usb_init;

#endif

#ifdef CONFIG_ARM

/* "static data" needed by most of timer.c on ARM platforms */

unsigned longtimer_rate_hz;

unsigned longtbl;

unsigned longtbu;

unsigned long longtimer_reset_value;

unsigned longlastinc;

#endif

#ifdef CONFIG_IXP425

unsigned longtimestamp;

#endif

unsigned longrelocaddr;/* Start address of U-Boot in RAM */

phys_size_tram_size;/* RAM size */

unsigned longmon_len;/* monitor len */

unsigned longirq_sp;/* irq stack pointer */

unsigned longstart_addr_sp;/* start_addr_stackpointer */

unsigned longreloc_off;

#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))

unsigned longtlb_addr;

#endif

void**jt;/* jump table */

charenv_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 {

intbi_baudrate;/* serial console baudrate */

unsigned longbi_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_ADDRSRAM0_START

#define CONFIG_SYS_INIT_RAM_SIZESRAM0_SIZE

#define CONFIG_SYS_INIT_SP_ADDR(CONFIG_SYS_INIT_RAM_ADDR + \

CONFIG_SYS_INIT_RAM_SIZE - \

GENERATED_GBL_DATA_SIZE)

#define SRAM0_START0x402F0400

#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_tih_magic;/* Image Header Magic Number*/

uint32_tih_hcrc;/* Image Header CRC Checksum*/

uint32_tih_time;/* Image Creation Timestamp*/

uint32_tih_size;/* Image Data Size*/

uint32_tih_load;/* Data Load Address*/

uint32_tih_ep;/* Entry Point Address*/

uint32_tih_dcrc;/* Image Data CRC Checksum*/

uint8_tih_os;/* Operating System*/

uint8_tih_arch;/* CPU architecture*/

uint8_tih_type;/* Image Type*/

uint8_tih_comp;/* Compression Type*/

uint8_tih_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_BASE0x80800000

l28n和开发版_*** am335x开发板的疑问以及解答相关推荐

  1. am335x开发板的疑问以及解答

    am335x开发板的疑问以及解答  分类: 嵌入式 参考文件: 1,AM335x ARM Cortex-A8 Microprocessors (MPUs) Technical Reference Ma ...

  2. 3d数学基础图形与游戏开发第二版_游戏开发完整学习路线,都在这里了

    在软件开发中,游戏开发这个方向看起来目标很明确,但其实是个领域很广的方向,入门的时候如果得不到指点一二,很容易误入歧途,相反,如果走这条路之前能得到前人的一些指路,是可以事半功倍的. 平台与编程语言选 ...

  3. 3d游戏开发相关概念_游戏开发概念

    3d游戏开发相关概念 Game development is one of the most exciting fields of computer science and a major part ...

  4. 安卓app开发工具_怎么开发app软件需要多少钱?主流app开发工具盘点

    现在智能手机的快速普及让手机app在生活中越来越重要,很多企业及创业者也意识到了app的重要性,但是怎么开发app软件?有哪些主流app开发工具呢?这里就为大家分享一下如何快速开发app软件. 一.编 ...

  5. python怎么安装开发版_【干货】开发板上安装python的hiai库和opencv库

    Matrix是已经支持phthon接口了,但是发现目前python的hiai库并没有自动安装,需要自己安装: 话不多说下面是安装步骤: 步骤1. 开发板联网,如果已联网则跳过该步骤: 接下来需要在开发 ...

  6. c c++常用算法手册(第3版_嵌入式软件开发必看书籍推荐(C/C++/linux/软件)

    置顶/星标公众号,不错过每一条重要消息! 嵌入式是一门需要不断学习的技术,看书无疑是最直接最持久的方法,之前就总结过各类的书籍,但是读者反馈量太大,所以今天缩小范围,很多我都是读过的,其电子版本我都放 ...

  7. python 开发版-MicroPython的开发板

    比如: pyboard micro:bit ESP8266/ESP32 stm32等等 什么是pyboard? pyboard是官方的MicroPython微控制器板,完全支持软件功能.硬件有: ST ...

  8. excel手机版_微软开发于手机端的办公软件!

    点击上方蓝色字关注我们! 手机版Microsoft Office,微软基于安卓用户开放的手机办公软件,完美解决随时随地办公的需求!该软件不仅拥有与电脑版Microsoft Office比肩的word. ...

  9. 如何成为一个区块链开发人员_成为开发人员是社会工作

    如何成为一个区块链开发人员 Times have changed since the old days when an IT professional was this typical shy per ...

最新文章

  1. 操作系统:了解一下磁盘结构
  2. 【NOI2013】向量内积
  3. 彻底关掉win10自动更新_win10系统explorer.exe错误的解决教程
  4. Weex动态化方案与双十一实践
  5. Xpath语法学习记录
  6. 指针选择排序法,10个整数从小到大排序
  7. LeetCode 583. 两个字符串的删除操作(动态规划)
  8. eclipse打开文件所在目录
  9. thinkphp3.0 php7,tp3.1 for php7
  10. 堆与优先队列课内模板
  11. vagrant虚拟机网络设置
  12. js base64编码_使用psd.js将PSD转成SVG -- 基础篇(文字amp;图片)
  13. apt安装openjdk8
  14. 2020数学建模B题
  15. mysql如何实现cas机制_CAS机制详解
  16. 联想昭阳K22-80机器关闭或开启触摸板方法
  17. matlab如何提取文本词干,英文词干提取(stemming)算法 - Lovins, Porter
  18. Eureka自我保护机制原理及作用enable-self-preservation
  19. Win10系统磁盘扩展分区与恢复分区
  20. 我的创作纪念日的温柔与七夕的浪漫交织了在一起

热门文章

  1. Oracle 19c VLDB and Partitioning Guide 第4章:分区管理 读书笔记
  2. vue2.0 axios 登录post请求自动读取Set-Cookie设置
  3. Linux之(27)networkctl命令
  4. python3中 os.path.realpath(__file__) 的使用
  5. 微软欲模仿“微信”,打造一款超级 App?
  6. 解决oracle11卸载,Oracle11完全卸载方法
  7. 1.MySQL,JDBC
  8. python将panadas写入excel_python pandas写入excel文件的方法示例
  9. jQuery如何根据元素值删除数组元素
  10. c语言求解三角形的重心,计算几个三角形的重心