首先要了解210板子的内存配置情况,我的板子是512M内存,DMC0上接了256M,DMC1接了256M,为了保证地址连续,内存地址只能是0x30000000 ~ 0x4FFFFFFF
第一步运行start.S:
_TEXT_BASE:
.word TEXT_BASE//存放基址
/*由makefile内容:
x210_nand_config : unconfig
@$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110
@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk
得知TXET_BASE = 0xc3e00000,为什么超出了0x30000000 ~ 0x4FFFFFFF,因为dnw烧写在0xd0000010处的启动代码初始化DDR时做了内存映射的工作,这个映射方式是简单的线性映射,只是在把内存起始地址增加至0xc0000000。后面会提到。
*/
/*
* Below variable is very important because we use MMU in U-Boot.
* Without it, we cannot run code correctly before MMU is ON.
* by scsuh.
*/
_TEXT_PHY_BASE:
.word CFG_PHY_UBOOT_BASE
.globl _armboot_start
_armboot_start:
.word _start
/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
#if defined(CONFIG_USE_IRQ)
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif
/*
* the actual reset code
*/
reset:
/*
* set the cpu to SVC32 mode and IRQ & FIQ disable
*/
@;mrs r0,cpsr
@;bic r0,r0,#0x1f
@;orr r0,r0,#0xd3
@;msr cpsr,r0
msr cpsr_c, #0xd3 @ I & F disable, Mode: 0x13 - SVC
/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
cpu_init_crit:
#ifndef CONFIG_EVT1
#if 0
bl v7_flush_dcache_all
#else
bl disable_l2cache
mov r0, #0x0 @
mov r1, #0x0 @ i
mov r3, #0x0
mov r4, #0x0
lp1:
mov r2, #0x0 @ j
lp2:
mov r3, r1, LSL #29 @ r3 = r1(i) <<29
mov r4, r2, LSL #6 @ r4 = r2(j) <<6
orr r4, r4, #0x2 @ r3 = (i<<29)|(j<<6)|(1<<1)
orr r3, r3, r4
mov r0, r3 @ r0 = r3
bl CoInvalidateDCacheIndex
add r2, #0x1 @ r2(j)++
cmp r2, #1024 @ r2 < 1024
bne lp2 @ jump to lp2
add r1, #0x1 @ r1(i)++
cmp r1, #8 @ r1(i) < 8
bne lp1 @ jump to lp1
bl set_l2cache_auxctrl
bl enable_l2cache
#endif
#endif
bl disable_l2cache
bl set_l2cache_auxctrl_cycle
bl enable_l2cache
/*
* Invalidate L1 I/D
*/
mov r0, #0 @ set up for MCR
mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
/*
* disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align
orr r0, r0, #0x00000800 @ set bit 12 (Z---) BTB
mcr p15, 0, r0, c1, c0, 0
/* Read booting information */
ldr r0, =PRO_ID_BASE
ldr r1, [r0,#OMR_OFFSET]
bic r2, r1, #0xffffffc1
#ifdef CONFIG_VOGUES
/* PS_HOLD(GPH0_0) set to output high */
ldr r0, =ELFIN_GPIO_BASE
ldr r1, =0x00000001
str r1, [r0, #GPH0CON_OFFSET]
ldr r1, =0x5500
str r1, [r0, #GPH0PUD_OFFSET]
ldr r1, =0x01
str r1, [r0, #GPH0DAT_OFFSET]
#endif
/* NAND BOOT */
cmp r2, #0x0 @ 512B 4-cycle
moveq r3, #BOOT_NAND
cmp r2, #0x2 @ 2KB 5-cycle
moveq r3, #BOOT_NAND
cmp r2, #0x4 @ 4KB 5-cycle 8-bit ECC
moveq r3, #BOOT_NAND
cmp r2, #0x6 @ 4KB 5-cycle 16-bit ECC
moveq r3, #BOOT_NAND
cmp r2, #0x8 @ OneNAND Mux
moveq r3, #BOOT_ONENAND
/* SD/MMC BOOT */
cmp r2, #0xc
moveq r3, #BOOT_MMCSD
/* NOR BOOT */
cmp r2, #0x14
moveq r3, #BOOT_NOR
/*以上代码判断启动方式,保存到r3中*/
#if 0 /* Android C110 BSP uses OneNAND booting! */
/* For second device booting */
/* OneNAND BOOTONG failed */
cmp r2, #0x8
moveq r3, #BOOT_SEC_DEV
#endif
/* Uart BOOTONG failed */
cmp r2, #(0x1<<4)
moveq r3, #BOOT_SEC_DEV
ldr r0, =INF_REG_BASE
str r3, [r0, #INF_REG3_OFFSET]
/*
* Go setup Memory and board specific bits prior to relocation.
*/
ldr sp, =0xd0036000 /* end of sram dedicated to u-boot */
sub sp, sp, #12 /* set stack */
mov fp, #0
bl lowlevel_init /* go setup pll,mux,memory *//*进入
/* To hold max8698 output before releasing power on switch,
* set PS_HOLD signal to high
*/
@ldr r0, =0xE010E81C /* PS_HOLD_CONTROL register */
@ldr r1, =0x00005301 /* PS_HOLD output high */
@str r1, [r0]
/* get ready to call C functions */
ldr sp, _TEXT_PHY_BASE /* setup temp stack pointer */设置SP = 0x33e00000
sub sp, sp, #12
mov fp, #0 /* no previous frame, so fp=0 */
/* when we already run in ram, we don't need to relocate U-Boot.
* and actually, memory controller must be configured before U-Boot
* is running in ram.
*/
ldr r0, =0xff000fff
bic r1, pc, r0 /* r0 <- current base addr of code */
ldr r2, _TEXT_BASE /* r1 <- original base addr in ram */
bic r2, r2, r0 /* r0 <- current base addr of code */
cmp r1, r2 /* compare r0, r1 */
beq after_copy /* r0 == r1 then skip flash copy */
这里判断当前是否已经正常启动,如果r1 = r2,说明uboot已完成自拷贝,则跳转到after_copy,在after_copy中设置MMU映射表之后,开始正常运行初始化板子。
after_copy:
#if defined(CONFIG_ENABLE_MMU)
enable_mmu:
/* enable domain access */
ldr r5, =0x0000ffff
mcr p15, 0, r5, c3, c0, 0 @load domain access register
/* Set the TTB register */
ldr r0, _mmu_table_base
ldr r1, =CFG_PHY_UBOOT_BASE
ldr r2, =0xfff00000
bic r0, r0, r2
orr r1, r0, r1
mcr p15, 0, r1, c2, c0, 0
/* Enable the MMU */
mmu_on:
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #1
mcr p15, 0, r0, c1, c0, 0
nop
nop
nop
nop
#endif
skip_hw_init:
/* Set up the stack */
stack_setup:
#if defined(CONFIG_MEMORY_UPPER_CODE)
ldr sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0x1000)
#else
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#if defined(CONFIG_USE_IRQ)
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
#endif
clear_bss:
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
clbss_l:
str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
ldr pc, _start_armboot /*进入启动程序*/
回头看如果r1 != r2,那么需要进行自拷贝:
#if defined(CONFIG_EVT1)
/* If BL1 was copied from SD/MMC CH2 */
ldr r0, =0xD0037488 /*判断是否是SD卡启动*/
ldr r1, [r0]
ldr r2, =0xEB200000
cmp r1, r2
beq mmcsd_boot
#endif
ldr r0, =INF_REG_BASE
ldr r1, [r0, #INF_REG3_OFFSET]
cmp r1, #BOOT_NAND /* 0x0 => boot device is nand */
beq nand_boot
cmp r1, #BOOT_ONENAND /* 0x1 => boot device is onenand */
beq onenand_boot
cmp r1, #BOOT_MMCSD
beq mmcsd_boot
cmp r1, #BOOT_NOR
beq nor_boot
cmp r1, #BOOT_SEC_DEV
beq mmcsd_boot
nand_boot:
mov r0, #0x1000
bl copy_from_nand
b after_copy
onenand_boot:
bl onenand_bl2_copy
b after_copy
mmcsd_boot:
#if DELETE
ldr sp, _TEXT_PHY_BASE /*这里不会执行*/
sub sp, sp, #12
mov fp, #0
#endif
bl movi_bl2_copy
b after_copy
nor_boot:
bl read_hword
b after_copy
after_copy:
after_copy:
#if defined(CONFIG_ENABLE_MMU)
enable_mmu:
/* enable domain access */
ldr r5, =0x0000ffff
mcr p15, 0, r5, c3, c0, 0 @load domain access register
/* Set the TTB register */
ldr r0, _mmu_table_base
ldr r1, =CFG_PHY_UBOOT_BASE
ldr r2, =0xfff00000
bic r0, r0, r2
orr r1, r0, r1
mcr p15, 0, r1, c2, c0, 0
/* Enable the MMU */
mmu_on:
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #1
mcr p15, 0, r0, c1, c0, 0
nop
nop
nop
nop
#endif
skip_hw_init:
/* Set up the stack */
stack_setup:
#if defined(CONFIG_MEMORY_UPPER_CODE)
ldr sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0x1000)
#else
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#if defined(CONFIG_USE_IRQ)
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
#endif
clear_bss:
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
clbss_l:
str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
ldr pc, _start_armboot
_start_armboot:
.word start_armboot
我们直接看copy_from_nand
/** copy U-Boot to SDRAM and jump to ram (from NAND or OneNAND)* r0: size to be compared* Load 1'st 2blocks to RAM because U-boot's size is larger than 1block(128k) size*/.globl copy_from_nand
copy_from_nand:push {lr} /* save return address */mov r9, r0mov r9, #0x100 /* Compare about 8KB */bl copy_uboot_to_ramtst r0, #0x0bne copy_failed#if defined(CONFIG_EVT1)ldr r0, =0xd0020000
#else ldr r0, =0xd0030000
#endifldr r1, _TEXT_PHY_BASE /* 0x23e00000 */
1: ldr r3, [r0], #4ldr r4, [r1], #4teq r3, r4bne compare_failed /* not matched */subs r9, r9, #4bne 1bpop {pc} /* all is OK */copy_failed:nop /* copy from nand failed */b copy_failedcompare_failed:nop /* compare failed */b compare_failed
看看copy_uboot_toram,因为已经设置栈,可以执行C程序了;
#define NAND_CONTROL_ENABLE() (NFCONT_REG |= (1 << 0))
static void nand_readpage (ulong col, ulong row, uchar* buf, int len)
{
int i;
NAND_ENABLE_CE();
NFCMD_REG = NAND_CMD_READ0;
/* Write Column Address */
NFADDR_REG = (col) & 0xff;
NFADDR_REG = (col >> 8) & 0xff;
/* Write Row Address */
NFADDR_REG = (row) & 0xff;
NFADDR_REG = (row >> 8) & 0xff;
NFADDR_REG = (row >> 16) & 0xff;
NFCMD_REG = NAND_CMD_READSTART;
NF_TRANSRnB();
for (i = 0; i < len; i++) {
buf[i] = NFDATA8_REG;
}
NAND_DISABLE_CE();
}
static int nand_isbad (ulong addr)
{
int i;
int page_size = 2048;
uchar oob[2];
if (addr == 0)
return 0;
nand_readpage(page_size, addr, oob, 2);
if ((oob[0] == 0xFF) && (oob[1] == 0xFF))
return 0;
else
return 1;
}
/*
* address format
* 17 16 9 8 0
* --------------------------------------------
* | block(12bit) | page(5bit) | offset(9bit) |
* --------------------------------------------
*/
static int nandll_read_page (uchar *buf, ulong addr)
{
int i;
int page_size = 2048;
nand_readpage(0, addr, buf, page_size);
return 0;
}
/*
* Read data from NAND.
*/
static int nandll_read_blocks (ulong dst_addr, ulong size)
{
uchar *buf = (uchar *)dst_addr;
int i;
int skipped_page = 0;
uint page_shift = 11;
/* Read pages */
for (i = 0; i < (size>>page_shift); i++, buf+=(1<0x80)
large_block = 1;
else
return -1; // Do not support small page (512B) any more
/* read NAND blocks */
return nandll_read_blocks(CFG_PHY_UBOOT_BASE, COPY_BL2_SIZE);
}
回过头来分析after_copy,在这之前的代码应该都是位置无关码,甚至bl copy_fram_nand都是位置无关的因此都可以正确执行。
ldr r5, =0x0000ffff
mcr p15, 0, r5, c3, c0, 0@load domain access register
这里使能域访问。关于协处理器编程的方法请参考协处理器编程
/* Set the TTB register */
ldr r0, _mmu_table_base
ldr r1, =CFG_PHY_UBOOT_BASE
ldr r2, =0xfff00000
bic r0, r0, r2 /*MMU表地址高位清零*/
orr r1, r0, r1/*uboot物理加载地址的 与MMU地址低字节相或,得到0x33exxxxx,及mmu_table的地址*/
mcr p15, 0, r1, c2, c0, 0 /*将r1存入CP15*/
这里将MMU映射表所在基址转换成物理地址,存入TTB寄存器中。考虑到之前dnw下载的那段初始程序(以下简写为usb_dnw_init),这里我也有点疑惑,当执行usb_dnw_init后,dnw就能在0x23e00000处下载uboot了,到底usb_dnw_init有没有做MMU的工作呢。
当我写到这里,发现已经有前辈分析过210的uboot了。可以看看:这里
但是网友没有对MMU机制进行分析,我这里说明一下,
可参考《S3C6410之uboot回炉再造(3)》这篇文章。
#ifdef CONFIG_ENABLE_MMU#ifdef CONFIG_MCP_SINGLE
/** MMU Table for SMDKC110* 0x0000_0000 -- 0xBFFF_FFFF => Not Allowed* 0xB000_0000 -- 0xB7FF_FFFF => A:0xB000_0000 -- 0xB7FF_FFFF VA = PA* 0xC000_0000 -- 0xC7FF_FFFF => A:0x3000_0000 -- 0x37FF_FFFF 128M* 0xC800_0000 -- 0xDFFF_FFFF => Not Allowed* 0xE000_0000 -- 0xFFFF_FFFF => A:0xE000_0000 -- 0XFFFF_FFFF VA = PA*//* form a first-level section entry */
.macro FL_SECTION_ENTRY base,ap,d,c,b.word (\base << 20) | (\ap << 10) | \(\d << 5) | (1<<4) | (\c << 3) | (\b << 2) | (1<<1)
.endm
.section .mmudata, "a".align 14// the following alignment creates the mmu table at address 0x4000..globl mmu_table
mmu_table:.set __base,0// Access for iRAM.rept 0x100 //对应虚拟地址0 ~ 256MFL_SECTION_ENTRY __base,3,0,0,0.set __base,__base+1.endr// Not Allowed.rept 0x200 - 0x100 //对应虚拟地址256M ~ 512M.word 0x00000000.endr.set __base,0x200// should be accessed.rept 0x600 - 0x200//对应虚拟地址512M ~ 1.5GFL_SECTION_ENTRY __base,3,0,1,1.set __base,__base+1.endr.rept 0x800 - 0x600//对应虚拟地址1.5G ~ 2G.word 0x00000000.endr.set __base,0x800// should be accessed.rept 0xb00 - 0x800//对应虚拟地址2 ~ 2.75GFL_SECTION_ENTRY __base,3,0,0,0.set __base,__base+1.endr/* .rept 0xc00 - 0xb00.word 0x00000000.endr */.set __base,0xB00.rept 0xc00 - 0xb00//对应虚拟地址2.75G ~ 3G 256MBFL_SECTION_ENTRY __base,3,0,0,0.set __base,__base+1.endr.set __base,0x300// 256MB for SDRAM with cacheable.rept 0xD00 - 0xC00//对应虚拟地址3G ~ 3.25G, 256MBFL_SECTION_ENTRY __base,3,0,1,1.set __base,__base+1.endr// access is not allowed.@.rept 0xD00 - 0xC80//对应虚拟地址3G ~ 3.125G,128MB@.word 0x00000000@.endr.set __base,0xD00// 1:1 mapping for debugging with non-cacheable.rept 0x1000 - 0xD00//对应虚拟地址3.125G ~ 4G, 768MBFL_SECTION_ENTRY __base,3,0,0,0.set __base,__base+1.endr #else // CONFIG_MCP_AC, CONFIG_MCP_H, CONFIG_MCP_B
经过MMU映射后,0xc000 0000~0xcfff ffff映射到了物理内存0x3000 0000 ~ 0x4FFF FFFF中,这样uboot就能通过dnw下载运行了。