1:做好上一章的准备工作,下面我们开始移植uboot
首先修改交叉编译工具链:在主Makefile文件中的交叉编译工具链修改为:
# set default to nothing for native builds ifeq ($(HOSTARCH),$(ARCH)) CROSS_COMPILE ?=
else CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi- endif
下面把烧录文件移植到uboot中;
把三星移植好的uboot中的sd_fusing 复制到新的uboot的根目录中,烧录sd卡
输出信息如下,说明校验头失败;
分析sd_fusing目录下的C110-EVT1-mkbl1.c文件
这段代码中是把uboot的前8k中的前16个字节的内容当做头来使用,相当于把uboot_inand.bin的前8k复制到SD-bl1-8k.bin,但是这前8k的前16个字节用作一个header 从bit8-bit11用作校验头,以前uboot中前16字节特意设置为0;
我们可以修改这个代码,也修改修改uboot中的前16字节,一下为修改之后的代码:
#include <stdio.h> #include <string.h> #include <stdlib.h>
int main (int argc, char *argv[]) { FILE *fp; char *Buf, *a, *b; int BufLen; int nbytes, fileLen; unsigned int checksum; int i; //////////////////////////////////////////////////////////////
if (argc != 4) { printf("Usage: mkbl1 <source file> <destination file> <size> \n"); return -1; } //////////////////////////////////////////////////////////////
BufLen = atoi(argv[3]); Buf = (char *)malloc(BufLen + 16); memset(Buf, 0x00, BufLen + 16); //////////////////////////////////////////////////////////////
fp = fopen(argv[1], "rb"); if( fp == NULL) { printf("source file open error\n"); free(Buf); return -1; } fseek(fp, 0L, SEEK_END); fileLen = ftell(fp); fseek(fp, 0L, SEEK_SET); if ( BufLen > fileLen ) { printf("Usage: unsupported size\n"); free(Buf); fclose(fp); return -1; } /* ** bhc add */ b = Buf + 16; nbytes = fread(b, 1, BufLen, fp); if ( nbytes != BufLen ) { printf("source file read error\n"); free(Buf); fclose(fp); return -1; } fclose(fp); //////////////////////////////////////////////////////////////
a = b; for(i = 0, checksum = 0; i < BufLen - 16; i++) checksum += (0x000000FF) & *a++; /* ** bhc add */ a = Buf; *( (unsigned int *)a ) = 0x2000; a = Buf + 8; *( (unsigned int *)a ) = checksum; //////////////////////////////////////////////////////////////
fp = fopen(argv[2], "wb"); if (fp == NULL) { printf("destination file open error\n"); free(Buf); return -1; } a = Buf; nbytes = fwrite( a, 1, BufLen, fp); if ( nbytes != BufLen ) { printf("destination file write error\n"); free(Buf); fclose(fp); return -1; } free(Buf); fclose(fp); return 0; }
实验现象同修改uboot前16字节一样,说明校验和对了,通过这个实验我们可以知道,irom除了校验和一致以外,第一字节的值应该为0x2000;
按照三星修改的uboot头文件设置:
至于第一个为什么是0x2000按照三星irom_application_note中的说法第一个为uboot的大小,但是实际值也不是这样的;
修改以后重新编译如下所示:
下面我们来看一下start.S中的代码
最前面一段为设置异常向量表;
.globl _start _start: 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 #ifdef CONFIG_SPL_BUILD _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 _pad: .word 0x12345678 /* now 16*4=64 */
#else _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 _pad: .word 0x12345678 /* now 16*4=64 */
#endif /* CONFIG_SPL_BUILD */
以及一些用到的全局变量的初始化
.globl _TEXT_BASE _TEXT_BASE: #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE) .word CONFIG_SPL_TEXT_BASE #else .word CONFIG_SYS_TEXT_BASE #endif
/* * These are defined in the board-specific linker script. */ .globl _bss_start_ofs _bss_start_ofs: .word __bss_start - _start .globl _bss_end_ofs _bss_end_ofs: .word __bss_end - _start .globl _end_ofs _end_ofs: .word _end - _start #ifdef 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
/* IRQ stack memory (calculated at run-time) + 8 bytes */ .globl IRQ_STACK_START_IN IRQ_STACK_START_IN: .word 0x0badc0de
下面是真正的执行程序部分:
reset: bl save_boot_params /* * disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode, * except if in HYP mode already */ mrs r0, cpsr and r1, r0, #0x1f @ mask mode bits teq r1, #0x1a @ test for HYP mode bicne r0, r0, #0x1f @ clear all mode bits orrne r0, r0, #0x13 @ set SVC mode orr r0, r0, #0xc0 @ disable FIQ and IRQ msr cpsr,r0
save_boot_params 这个函数实际上就是直接 return 0;
ENTRY(save_boot_params)
bx lr @ back to my caller //直接转到lr
下面是设置为svc模式,禁止fir、irq中断;
下面是两个关键性的函数
bl cpu_init_cp15
cp15协处理器的初始化
bl cpu_init_crit 在看一下这个函数:
1 ENTRY(cpu_init_crit) 2 /*
3 * Jump to board specific initialization... 4 * The Mask ROM will have already initialized 5 * basic memory. Go here to bump up clock rate and handle 6 * wake up conditions. 7 */
8 b lowlevel_init @ go setup pll,mux,memory 9 ENDPROC(cpu_init_crit)
这个函数中就一个
b lowlevel_init
--------------------------------------
进入lowlevel_init函数中,在这里我们要进行串口的初始化并打印信息O
然后在进行dram的初始化,并打印信息K
dram初始化的时候记得把相关头文件复制过去就可以了;
然后返回_start函数中,进行重定位、清bss跳转到第二阶段
这里要注意:串口输出需要一个时间,所以要打印之前首先放一个delay函数;确定他发送完
注意在lowlevel_init函数中存在一些无关的代码如下面,io复位等,这些代码有可能会陷入死循环,跳转不出去,这些代码直接去掉;
返回到_start函数中并设置打印信息A
如下图:打印出了A,下面进行重定位
因为要调用c语言函数,所以首先要设置栈;
然后判断是否需要重定位,如果需要则重定位;
在链接脚本中设置的链接地址是从0x00000000开始的,但是