我想标题应该写成”使用jlink启动uboot,通过uboot烧写uboot进nand“,这么写太长了,所以写短些,这里补充下,让大家明白意思
笔者最近使用S3C2410做一些开发工作,对于新买的核心板(无uboot),如何把uboot、内核、文件系统烧写进去呢?
初步分析如下
1.uboot已经支持烧写nand
2.uboot暂未支持烧写yaffs
3.如何通过jlink启动uboot
第一步已经支持,没问题
第二步,yaffs是由mkyaffsimage生成,这种yaffs文件系统是有带oob信息的,所以要将yaffs的oob信息一起写入,同时要注意oob的格式要一致,查了下内核的oob,修改下mkyaffsimage的oob,然后再uboot中添加支持烧写yaffs文件系统的接口,这一步ok
第三步,这些天花了些功夫在这个步骤上,uboot一直无法启动起来,后来发现其中有一个步骤被我忽略了,硬件接触不好,就是核心板和底板没接触好,导致uboot一直无法启动,严谨说是有启动,但是串口没输出,只有启动一部分,后来程序就跑飞了,启动的部分是由于uboot载入0地址的那段跑起来,所以导致一些奇怪的错误现象
我们分析下uboot的启动文件start.S
@ Start of executable code
@
@
ENTRY(_start)
ENTRY(ResetEntryPoint)
@#define CONFIG_PM
@#define CONFIG_TEST
#define CONFIG_S3C2410_NAND_BOOT
@#define CONFIG_DEBUG_LL
@ Exception vector table (physical address = 0x00000000)
@
.globl reset_cpu
reset_cpu:
@ 0x00: Reset
b Reset @复位
ldr pc, _undefined_instruction @异常地址
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
ENTRY(ResetEntryPoint)
@#define CONFIG_PM
@#define CONFIG_TEST
#define CONFIG_S3C2410_NAND_BOOT
@#define CONFIG_DEBUG_LL
@ Exception vector table (physical address = 0x00000000)
@
.globl reset_cpu
reset_cpu:
@ 0x00: Reset
b Reset @复位
ldr pc, _undefined_instruction @异常地址
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word fiq
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word fiq
@
@ VIVI magics
@
@ 0x20: magic number so we can verify that we only put
.long 0
@ 0x24:
.long 0
@ 0x28: where this vivi was linked, so we can put it in memory in the right place
.long _start
@ 0x2C: this contains the platform, cpu and machine id
.long ARCHITECTURE_MAGIC
@ 0x30: vivi capabilities
.long 0
#ifdef CONFIG_PM
@ 0x34:
b SleepRamProc
#endif
#ifdef CONFIG_TEST
@ 0x38:
b hmi
#endif
.globl _armboot_end_data
_armboot_end_data:
.word armboot_end_data
.globl _armboot_end
_armboot_end:
.word armboot_end
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
.globl _armboot_real_end
_armboot_real_end:
.word 0x0badc0de
.globl _armboot_start
_armboot_start:
.word _start
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
/*#ifdef CONFIG_S3C2410
led_light_on:
@ All LED on
@ 0x24:
.long 0
@ 0x28: where this vivi was linked, so we can put it in memory in the right place
.long _start
@ 0x2C: this contains the platform, cpu and machine id
.long ARCHITECTURE_MAGIC
@ 0x30: vivi capabilities
.long 0
#ifdef CONFIG_PM
@ 0x34:
b SleepRamProc
#endif
#ifdef CONFIG_TEST
@ 0x38:
b hmi
#endif
.globl _armboot_end_data
_armboot_end_data:
.word armboot_end_data
.globl _armboot_end
_armboot_end:
.word armboot_end
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
.globl _armboot_real_end
_armboot_real_end:
.word 0x0badc0de
.globl _armboot_start
_armboot_start:
.word _start
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
@
@ Start VIVI head
@
Reset: @复位后跳转到这里执行
@ disable watch dog timer
mov r1, #0x53000000
mov r2, #0x0
str r2, [r1]
@ bl led_on
#ifdef CONFIG_S3C2410_MPORT3 @未定义,不执行
mov r1, #0x56000000
mov r2, #0x00000005
str r2, [r1, #0x70]
mov r2, #0x00000001
str r2, [r1, #0x78]
mov r2, #0x00000001
str r2, [r1, #0x74]
#endif
@ Start VIVI head
@
Reset: @复位后跳转到这里执行
@ disable watch dog timer
mov r1, #0x53000000
mov r2, #0x0
str r2, [r1]
@ bl led_on
#ifdef CONFIG_S3C2410_MPORT3 @未定义,不执行
mov r1, #0x56000000
mov r2, #0x00000005
str r2, [r1, #0x70]
mov r2, #0x00000001
str r2, [r1, #0x78]
mov r2, #0x00000001
str r2, [r1, #0x74]
#endif
@ disable all interrupts
mov r1, #INT_CTL_BASE @屏蔽中断
mov r2, #0xffffffff
str r2, [r1, #oINTMSK]
ldr r2, =0x7ff
str r2, [r1, #oINTSUBMSK]
mov r1, #INT_CTL_BASE @屏蔽中断
mov r2, #0xffffffff
str r2, [r1, #oINTMSK]
ldr r2, =0x7ff
str r2, [r1, #oINTSUBMSK]
@ initialise system clocks
mov r1, #CLK_CTL_BASE
mvn r2, #0xff000000
str r2, [r1, #oLOCKTIME]
mov r1, #CLK_CTL_BASE
mvn r2, #0xff000000
str r2, [r1, #oLOCKTIME]
@ldr r2, mpll_50mhz
@str r2, [r1, #oMPLLCON]
#ifndef CONFIG_S3C2410_MPORT1
@ 1:2:4
mov r1, #CLK_CTL_BASE
mov r2, #0x3
str r2, [r1, #oCLKDIVN]
@str r2, [r1, #oMPLLCON]
#ifndef CONFIG_S3C2410_MPORT1
@ 1:2:4
mov r1, #CLK_CTL_BASE
mov r2, #0x3
str r2, [r1, #oCLKDIVN]
mrc p15, 0, r1, c1, c0, 0 @ read ctrl register 想问具体的,这个可以百度下为什么
orr r1, r1, #0xc0000000 @ Asynchronous
mcr p15, 0, r1, c1, c0, 0 @ write ctrl register
orr r1, r1, #0xc0000000 @ Asynchronous
mcr p15, 0, r1, c1, c0, 0 @ write ctrl register
@ now, CPU clock is 100 Mhz
mov r1, #CLK_CTL_BASE
ldr r2, mpll_200mhz
str r2, [r1, #oMPLLCON]
#endif
mov r1, #CLK_CTL_BASE
ldr r2, mpll_200mhz
str r2, [r1, #oMPLLCON]
#endif
.globl backlight_off
@ All LED on
backlight_off:
mov r1, #GPIO_CTL_BASE
add r1, r1, #oGPIO_G
ldr r2,=0x100
str r2, [r1, #oGPIO_CON]
mov r2, #0xff
str r2, [r1, #oGPIO_UP]
mov r2, #0x00
str r2, [r1, #oGPIO_DAT]
@ All LED on
backlight_off:
mov r1, #GPIO_CTL_BASE
add r1, r1, #oGPIO_G
ldr r2,=0x100
str r2, [r1, #oGPIO_CON]
mov r2, #0xff
str r2, [r1, #oGPIO_UP]
mov r2, #0x00
str r2, [r1, #oGPIO_DAT]
bl memsetup @dram初始化
#ifdef CONFIG_PM
@ Check if this is a wake-up from sleep
ldr r1, PMST_ADDR
ldr r0, [r1]
tst r0, #(PMST_SMR)
bne WakeupStart
#endif
@ Check if this is a wake-up from sleep
ldr r1, PMST_ADDR
ldr r0, [r1]
tst r0, #(PMST_SMR)
bne WakeupStart
#endif
/*#ifdef CONFIG_S3C2410
led_light_on:
@ All LED on
mov r1, #GPIO_CTL_BASE
add r1, r1, #oGPIO_F
ldr r2,=0x55aa
str r2, [r1, #oGPIO_CON]
mov r2, #0xff
str r2, [r1, #oGPIO_UP]
mov r2, #0x00
str r2, [r1, #oGPIO_DAT]
#endif*/
add r1, r1, #oGPIO_F
ldr r2,=0x55aa
str r2, [r1, #oGPIO_CON]
mov r2, #0xff
str r2, [r1, #oGPIO_UP]
mov r2, #0x00
str r2, [r1, #oGPIO_DAT]
#endif*/
#if 0
@ SVC
mrs r0, cpsr
bic r0, r0, #0xdf
orr r1, r0, #0xd3
msr cpsr_all, r1
#endif
@ SVC
mrs r0, cpsr
bic r0, r0, #0xdf
orr r1, r0, #0xd3
msr cpsr_all, r1
#endif
@ set GPIO for UART
mov r1, #GPIO_CTL_BASE @配置串口
add r1, r1, #oGPIO_H
ldr r2, gpio_con_uart
str r2, [r1, #oGPIO_CON]
ldr r2, gpio_up_uart
str r2, [r1, #oGPIO_UP]
bl InitUART
#ifdef CONFIG_DEBUG_LL
@ Print current Program Counter
ldr r1, SerBase
mov r0, #'\r'
bl PrintChar
mov r0, #'\n'
bl PrintChar
mov r0, #'@'
bl PrintChar
mov r0, pc
bl PrintHexWord
#endif
mov r1, #GPIO_CTL_BASE @配置串口
add r1, r1, #oGPIO_H
ldr r2, gpio_con_uart
str r2, [r1, #oGPIO_CON]
ldr r2, gpio_up_uart
str r2, [r1, #oGPIO_UP]
bl InitUART
#ifdef CONFIG_DEBUG_LL
@ Print current Program Counter
ldr r1, SerBase
mov r0, #'\r'
bl PrintChar
mov r0, #'\n'
bl PrintChar
mov r0, #'@'
bl PrintChar
mov r0, pc
bl PrintHexWord
#endif
#ifdef CONFIG_BOOTUP_MEMTEST
@ simple memory test to find some DRAM flaults.
bl memtest
#endif
#ifdef CONFIG_S3C2410_NAND_BOOT
#if 0
bl copy_myself
#else
adr r0, _start
ldr r1, =0x33f00000
cmp r0, r1
blne copy_myself @将代码从nand拷贝到dram的0x33f0 0000
#endif
@ simple memory test to find some DRAM flaults.
bl memtest
#endif
#ifdef CONFIG_S3C2410_NAND_BOOT
#if 0
bl copy_myself
#else
adr r0, _start
ldr r1, =0x33f00000
cmp r0, r1
blne copy_myself @将代码从nand拷贝到dram的0x33f0 0000
#endif
@ jump to ram
mov r1, #GPIO_CTL_BASE @板上的led灯指示
add r1, r1, #oGPIO_F
ldr r2,=0x55aa
str r2, [r1, #oGPIO_CON]
mov r2, #0xff
str r2, [r1, #oGPIO_UP]
mov r2, #0xb0
str r2, [r1, #oGPIO_DAT]
mov r1, #GPIO_CTL_BASE @板上的led灯指示
add r1, r1, #oGPIO_F
ldr r2,=0x55aa
str r2, [r1, #oGPIO_CON]
mov r2, #0xff
str r2, [r1, #oGPIO_UP]
mov r2, #0xb0
str r2, [r1, #oGPIO_DAT]
ldr r1, =on_the_ram @这个指令时重定位的关键,汇编代码可以看到这个不是基于pc的,它是一个固定值,指向dram的相应位置
add pc, r1, #0 @跳转到dram执行,
nop
nop
1: b 1b @ infinite loop
on_the_ram:
#endif
add pc, r1, #0 @跳转到dram执行,
nop
nop
1: b 1b @ infinite loop
on_the_ram:
#endif
#ifdef CONFIG_DEBUG_LL
ldr r1, SerBase
ldr r0, STR_STACK
bl PrintWord
ldr r0, DW_STACK_START
bl PrintHexWord
#endif
ldr r1, SerBase
ldr r0, STR_STACK
bl PrintWord
ldr r0, DW_STACK_START
bl PrintHexWord
#endif
我们就看这部分,我直接在代码加些注释了
在看下u-boot.lds
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x33f00000;
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x33f00000;
. = ALIGN(4);
.text :
{
cpu/arm920t/start.o (.text)
*(.text)
}
.text :
{
cpu/arm920t/start.o (.text)
*(.text)
}
. = ALIGN(4);
.rodata : { *(.rodata) }
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
.data : { *(.data) }
. = ALIGN(4);
.got : { *(.got) }
.got : { *(.got) }
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
armboot_end_data = .;
__bss_start =.;
. = ALIGN(4);
.bss : { *(.bss) }
_end =.;
armboot_end = .;
.bss : { *(.bss) }
_end =.;
armboot_end = .;
}
可以看出start.S优先链接,就放在启动地址下
从上可以看出,要通过jlink启动uboot,只要分两步
1.将uboot载入0地址,启动它,以下是在jlink输入的内容
loadbin E:\yr\tmp\u-boot.bin 0 //uboot路径
setpc 0
g
setpc 0
g
2.
将uboot载入0x33f0 0000地址,启动它,以下是在jlink输入的内容
loadbin E:\yr\tmp\u-boot.bin 0x33f00000
setpc 0x33f00000
g
setpc 0x33f00000
g
通过以上两个步骤,串口即可正常输出