转载uboot目录结构
转载uboot源码分析
转载移植uboot-2012.4
最简单的bootloader的编写步骤:
- 初始化硬件:关看门狗、设置时钟、初始化SDRAM、初始化NAND FLASH
- 如果bootloader比较大,要把它重定位到SDRAM
- 把内核从NAND FLASH读到SDRAM
- 设置"要传给内核的参数"
- 跳转执行内核
start.S
#define S3C2440_MPLL_200MHZ (0x5c<<12)|(1<<4)|(0x02<<0)
#define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01))
#define MEM_CTL_BASE 0x48000000 //sdram控制器基址
.text
.global _start
_start:
/*关看门狗,把0写入WTCON*/
ldr r0,=0x53000000
mov r1,#0
str r1,[r0]
/*设置时钟 , CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8 */
ldr r0,=0x4c000014
mov r1,#0x05
str r1,[r0]
/* 设置CPU工作于异步模式 */
mrc p15,0,r0,c1,c0,0
orr r0,r0,#0xc0000000 //R1_nF:OR:R1_iA
mcr p15,0,r0,c1,c0,0
/* 设置MPLLCON(0x4C000004) */
ldr r0, =0x4C000004
ldr r1, =S3C2440_MPLL_400MHZ
str r1, [r0]
/* 启动icache,提高启动速度 */
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #(1<<12) /* r0 = r0 or (1<<12) */
mcr p15, 0, r0, c1, c0, 0
/*初始化SDRAM*/
ldr r0,=MEM_CTL_BASE
adr r1,sdram_config//获得地址
add r3,r0,#(13*4)//r3=r0+52
1:
ldr r2,[r1],#4 //r2=[r1],r1+4
str r2,[r0],#4 //[r0]=r2,r0+4
cmp r0,r3
bne 1b
/*重定位*/
ldr sp,=0x34000000
bl copy_code_to_sdram
bl clean_bss
/*执行main*/
ldr lr,=halt//main执行完后返回地址
ldr pc,=main//绝对跳转-》sdram
halt:
b halt
sdram_config:
.long 0x22011110 //BWSCON
.long 0x00000700 //BANKCON0
.long 0x00000700 //BANKCON1
.long 0x00000700 //BANKCON2
.long 0x00000700 //BANKCON3
.long 0x00000700 //BANKCON4
.long 0x00000700 //BANKCON5
.long 0x00018005 //BANKCON6
.long 0x00018005 //BANKCON7
.long 0x008C04F4 // REFRESH
.long 0x000000B1 //BANKSIZE
.long 0x00000030 //MRSRB6
.long 0x00000030 //MRSRB7
init.c
/* NAND FLASH控制器 */
#define NFCONF (*((volatile unsigned long *)0x4E000000))
#define NFCONT (*((volatile unsigned long *)0x4E000004))
#define NFCMMD (*((volatile unsigned char *)0x4E000008))
#define NFADDR (*((volatile unsigned char *)0x4E00000C))
#define NFDATA (*((volatile unsigned char *)0x4E000010))
#define NFSTAT (*((volatile unsigned char *)0x4E000020))
/* GPIO */
#define GPHCON (*(volatile unsigned long *)0x56000070)
#define GPHUP (*(volatile unsigned long *)0x56000078)
/* UART registers*/
#define ULCON0 (*(volatile unsigned long *)0x50000000)
#define UCON0 (*(volatile unsigned long *)0x50000004)
#define UFCON0 (*(volatile unsigned long *)0x50000008)
#define UMCON0 (*(volatile unsigned long *)0x5000000c)
#define UTRSTAT0 (*(volatile unsigned long *)0x50000010)
#define UTXH0 (*(volatile unsigned char *)0x50000020)
#define URXH0 (*(volatile unsigned char *)0x50000024)
#define UBRDIV0 (*(volatile unsigned long *)0x50000028)
/* 115200,8n1 */
void uart0_init()
{
GPHCON |= 0xa0; // GPH2,GPH3用作TXD0,RXD0
GPHUP = 0x0c; // GPH2,GPH3内部上拉
ULCON0 = 0x03; // 8N1(8个数据位,无较验,1个停止位)
UCON0 = 0x05; // 查询方式,UART时钟源为PCLK
UFCON0 = 0x00; // 不使用FIFO
UMCON0 = 0x00; // 不使用流控
UBRDIV0 = 26; // 波特率为115200
/* 设置波特率 */
/* UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1
* UART clock = 50M
* UBRDIVn = (int)( 50000000 / ( 115200 x 16) ) –1 = 26
*/
}
void putc(unsigned char c)
{
/* UTRSTAT0 UTXH0 */
while (!(UTRSTAT0 & (1<<2)));
UTXH0 = c;
}
void puts(char *s)
{
while (*s)
{
putc(*s);
s++;
}
}
void nand_init(void)
{
#define TACLS 0
#define TWRPH0 1
#define TWRPH1 0
/* 设置时序 */
NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
/* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
NFCONT = (1<<4)|(1<<1)|(1<<0);
}
void nand_select(void)
{
NFCONT &= ~(1<<1);
}
void nand_deselect(void)
{
NFCONT |= (1<<1);
}
void nand_cmd(unsigned char cmd)
{
volatile int i;
NFCMMD = cmd;
for (i = 0; i < 10; i++);
}
void nand_addr(unsigned int addr)
{
unsigned int col = addr % 2048;
unsigned int page = addr / 2048;
volatile int i;
NFADDR = col & 0xff;
for (i = 0; i < 10; i++);
NFADDR = (col >> 8) & 0xff;
for (i = 0; i < 10; i++);
NFADDR = page & 0xff;
for (i = 0; i < 10; i++);
NFADDR = (page >> 8) & 0xff;
for (i = 0; i < 10; i++);
NFADDR = (page >> 16) & 0xff;
for (i = 0; i < 10; i++);
}
void nand_page(unsigned int page)
{
volatile int i;
NFADDR = page & 0xff;
for (i = 0; i < 10; i++);
NFADDR = (page >> 8) & 0xff;
for (i = 0; i < 10; i++);
NFADDR = (page >> 16) & 0xff;
for (i = 0; i < 10; i++);
}
void nand_col(unsigned int col)
{
volatile int i;
NFADDR = col & 0xff;
for (i = 0; i < 10; i++);
NFADDR = (col >> 8) & 0xff;
for (i = 0; i < 10; i++);
}
void nand_wait_ready(void)
{
while (!(NFSTAT & 1));
}
unsigned char nand_data(void)
{
return NFDATA;
}
/*判断坏块*/
int nand_bad(unsigned int addr)
{
unsigned int col = 2048;
unsigned int page = addr / 2048;
unsigned char val;
/* 1. 选中 */
nand_select();
/* 2. 发出读命令00h */
nand_cmd(0x00);
/* 3. 发出地址(分5步发出) */
nand_col(col);
nand_page(page);
/* 4. 发出读命令30h */
nand_cmd(0x30);
/* 5. 判断状态 */
nand_wait_ready();
/* 6. 读数据 */
val = nand_data();
/* 7. 取消选中 */
nand_deselect();
if (val != 0xff)
return 1; /* bad blcok */
else
return 0;
}
void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
{
int col = addr % 2048;
int i = 0;
while (i < len)
{
if (!(addr & 0x1FFFF) && nand_bad(addr)) /* 一个block只判断一次 */
{
addr += (128*1024); /* 跳过当前block */
continue;
}
/* 1. 选中 */
nand_select();
/* 2. 发出读命令00h */
nand_cmd(0x00);
/* 3. 发出地址(分5步发出) */
nand_addr(addr);
/* 4. 发出读命令30h */
nand_cmd(0x30);
/* 5. 判断状态 */
nand_wait_ready();
/* 6. 读数据 */
for (; (col < 2048) && (i < len); col++)
{
buf[i] = nand_data();
i++;
addr++;
}
col = 0;
/* 7. 取消选中 */
nand_deselect();
}
}
int isBootFromNorFlash(void)
{
volatile int *p = (volatile int *)0;
int val;
val = *p;
*p = 0x12345678;
if (*p == 0x12345678)
{
/* 写成功, 是nand启动 */
*p = val;
return 0;
}
else
{ /* NOR不能像内存一样写 */
return 1;
}
}
void copy_code_to_sdram(void)
{
/* 要从lds文件中获得 __code_start, __bss_start
* 然后从0地址把数据复制到__code_start */
extern int __code_start, __bss_start;
volatile unsigned int *dest = (volatile unsigned int *)&__code_start;
volatile unsigned int *end = (volatile unsigned int *)&__bss_start;
volatile unsigned int *src = (volatile unsigned int *)0;
unsigned int len = (unsigned int)(&__bss_start) - (unsigned int)(&__code_start);
if (isBootFromNorFlash())
{
while (dest < end)
{
*dest++ = *src++;
}
}
else
{
nand_init();
nand_read((unsigned int)src, (unsigned char *)dest, len);
}
}
void clean_bss(void)
{
/* 要从lds文件中获得 __bss_start, _end*/
extern int _end, __bss_start;
volatile unsigned int *start = (volatile unsigned int *)&__bss_start;
volatile unsigned int *end = (volatile unsigned int *)&_end;
while (start <= end)
{
*start++ = 0;
}
}
u-boot.s
#include "setup.h"
extern void uart0_init();
extern void puts(const char *s);
extern void nand_read(unsigned int addr, unsigned char *buf, unsigned int len);
static struct tag *params;
int strlen(char *str)
{
int i=0;
while(str[i])
{
i++;
}
return i;
}
void strcpy (char *dest,const char *src)
{
while((*dest++=*src++)!='\0');
}
void setup_start_tag()
{
params = (struct tag *) 0x30000100;//tag存放的位置
/*tag头部*/
params->hdr.tag = ATAG_CORE;//标记0x54410001,标签列表开始标志
params->hdr.size = tag_size (tag_core);//整个结构体大小:头加联合体
params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;
params = tag_next (params);
}
void setup_memory_tags ()
{ /*内存参数*/
params->hdr.tag = ATAG_MEM;//内存信息标签
params->hdr.size = tag_size (tag_mem32);
params->u.mem.start = 0x30000000;//内存起始地址
params->u.mem.size = 64*1024*1024;//内存大小64M
params = tag_next (params);
}
void setup_commandline_tag(char *cmdline)
{ /*命令行参数*/
int len=strlen(cmdline)+1;
params->hdr.tag = ATAG_CMDLINE;//command line字符串标签
params->hdr.size =(sizeof (struct tag_header) + len+3) >> 2;//向4取整>>2/除4
strcpy (params->u.cmdline.cmdline, cmdline);
params = tag_next (params);
}
void setup_end_tag()
{
params->hdr.tag = ATAG_NONE;//标签列表结束标志
params->hdr.size = 0;
}
int main()
{
void (*theKernel)(int zero,int arch,unsigned int params);
/*0、帮内核设置串口,内核启动时会打印信息*/
uart0_init();
/*1、从nand flash里把内核读入内存(sdram)*/
puts("Copy kernel from nand\n\r");
nand_read((unsigned int)0x60000+64,(unsigned char *)0x30008000,(unsigned int)0x200000);
/*设置参数*/
puts("Set boot params\n\r");
setup_start_tag();
setup_memory_tags ();
setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");
setup_end_tag();
/*跳转到内核执行,传参数给内核*/
puts("Jump kernel\n\r");
theKernel=(void(*)(int,int,unsigned int))0x30008000;
theKernel(0,362,0x30000100);//s3c2440机器ID,参数的位置
/* mov r0,#0
ldr r1,=362
ldr r2,=0x30000100
mov pc, #0x30008000
程序不再回到这*/
return -1;
}
uboot.lds
SECTIONS
{
. = 0x33f80000;
__code_start = .;
. = ALIGN(4);
.text :
{
*(.text)
}
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) *(.COMMON) }
_end = .;
}