根据u-boot-1.1.6启动流程来划分,u-boot功能主要划分为四个部分
1,硬件初始化 -->start.S init.c
2,从 flash 拷贝内核到 ram -->main.c
3,设置 tag 参数 -->tag.c tag.h
4,跳到内核,执行内核代码 --> main.c
start.s源码:
.extern main .text .global _start _start: bl disable_watchdog bl clock_init bl open_icache bl sdram_init bl uart0_init bl nand_init ldr sp, =0x34000000 ldr r0,=0 ldr r1,=_start ldr r2,=__bss_start @0x33f80000 sub r2,r2,r1 bl copy_uboot_to_sdram ldr pc,=on_sdram on_sdram: bl clean_bss ldr lr,=main_return ldr pc,=main main_return: b main_return
init.c源码:
//watchdog #define WTCON (*(volatile unsigned long *)0x53000000) //clock #define CLOCKTIME (*(volatile unsigned long *)0x4c000000) #define MPLLCON (*(volatile unsigned long *)0x4c000004) #define CLKDIVN (*(volatile unsigned long *)0x4c000014) #define CAMDIVN (*(volatile unsigned long *)0x4c000018) //sdram #define BWSCON (*(volatile unsigned long *)0x48000000) #define BANKCON0 (*(volatile unsigned long *)0x48000004) #define BANKCON1 (*(volatile unsigned long *)0x48000008) #define BANKCON2 (*(volatile unsigned long *)0x4800000c) #define BANKCON3 (*(volatile unsigned long *)0x48000010) #define BANKCON4 (*(volatile unsigned long *)0x48000014) #define BANKCON5 (*(volatile unsigned long *)0x48000018) #define BANKCON6 (*(volatile unsigned long *)0x4800001c) #define BANKCON7 (*(volatile unsigned long *)0x48000020) #define REFRESH (*(volatile unsigned long *)0x48000024) #define BANKSIZE (*(volatile unsigned long *)0x48000028) #define MRSRB6 (*(volatile unsigned long *)0x4800002c) #define MRSRB7 (*(volatile unsigned long *)0x48000030) //nand #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) //uart #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 UERSTAT0 (*(volatile unsigned long *)0x50000014) #define UTXH0 (*(volatile unsigned char *)0x50000020) #define URXH0 (*(volatile unsigned char *)0x50000024) #define UBRDIV0 (*(volatile unsigned long *)0x50000028) //GPH #define GPHCON (*(volatile unsigned long *)0x56000070) #define GPHDAT (*(volatile unsigned long *)0x56000074) #define GPHUP (*(volatile unsigned long *)0x56000078) /**************************************** watchdog_init ********************************************/ void disable_watchdog(void) { WTCON=0; } /****************************************** colck_init ********************************************/ void clock_init(void) { MPLLCON = ((0x5c<<12)|(0x01<<4)|(0x02)); CLKDIVN = ((1<<1)|(1<<0)); //200 MHZ // CAMDIVN = ((1<<1)|(1<<0)); //1:2:4 200M:100M:50M __asm__ ( " mrc p15,0,r1,c1,c0,0 " " orr r1, r1,#0xc0000000 " " mcr p15,0,r1,c1,c0,0 " ); } void open_icache(void) { __asm__ ( " mrc p15, 0, r0, c1, c0, 0 " " orr r0, r0, #(1<<12) " " mcr p15, 0, r0, c1, c0, 0 " ); } /****************************************** sdram_init *******************************************/ void sdram_init(void) { BWSCON = 0x22011110 ; //BWSCON BANKCON0 = 0x00000700; //BANKCON0 BANKCON1 =0x00000700; //BANKCON1 BANKCON2 = 0x00000700; //BANKCON2 BANKCON3 = 0x00000700; //BANKCON3 BANKCON4 = 0x00000700; //BANKCON4 BANKCON5 =0x00000700; //BANKCON5 BANKCON6 =0x00018005; //BANKCON6 BANKCON7 = 0x00018005; //BANKCON7 REFRESH =0x008C04F4 ; // REFRESH BANKSIZE = 0x000000B1; //BANKSIZE MRSRB6 = 0x00000030; //MRSRB6 MRSRB7 = 0x00000030 ; //MRSRB7 } /****************************************** nand_flash_init ********************************************/ void select_chip(void) { NFCONT &= ~(1<<1); } void disselect_chip(void) { NFCONT |= (1<<1); } void write_command(unsigned char cmd) { NFCMMD=cmd; volatile int i; for (i = 0; i < 10; i++); } unsigned char read_data(void) { return NFDATA; } void write_addr(unsigned int addr) { unsigned int row,col; int i=0; row=addr/2048; col=addr%2048; NFADDR= 0xff & col; for (i = 0; i < 10; i++); NFADDR=(col>>8)& 0xff; for (i = 0; i < 10; i++); NFADDR=row& 0xff; for (i = 0; i < 10; i++); NFADDR=(row>>8)& 0xff; for (i = 0; i < 10; i++); NFADDR=(row>>16)& 0xff; for (i = 0; i < 10; i++); } int nand_ready(void) { return (NFSTAT & 1); } void nand_init(void) { NFCONF = (0<<12|1<<8|0<<4); NFCONT = (1<<4|1<<1|1<<0); } void nand_read(unsigned int sour,unsigned char* dest,int copy_size) { int col=sour % 2048; int i=0; select_chip(); while(i<copy_size) { write_command(0x00); write_addr(sour); write_command(0x30); while(!nand_ready()); for(; (col<2048)&&(i<copy_size);col++) //page read { dest[i]=read_data(); sour++; i++; } col=0; } disselect_chip(); } /****************************************** copy_uboot_to_sdram ********************************************/ int nand_boot(void) { volatile unsigned long* top = (volatile unsigned long *)0x00000000; int value=*top; *top=1234; if(*top==1234) { *top=value; return 1; } else return 0; } void copy_uboot_to_sdram(unsigned char* sour1,unsigned char *dest,int copy_size) { int i=0; unsigned char *sour = sour1; if(nand_boot()) // nand_boot { while(i<copy_size) { dest[i]=sour[i];i++; } } else //nor_boot { nand_read((unsigned long)sour,dest,copy_size); } } /*********************************************clean_bss*************************************************/ void clean_bss(void) { extern long __bss_end, __bss_start; int* p = &__bss_start; for(;p < &__bss_end ;p++) *p=0; } /********************************************uart_init*****************************************************/ void uart0_init(void) { GPHCON|=0xa0; GPHUP=0x0c; ULCON0=0x03; UCON0=0x05; UFCON0=0x00; UMCON0=0x00; UBRDIV0=((50000000/(115200*16))-1); } unsigned char getc(void) { while(!(UTRSTAT0 & 0x01)); return URXH0; } void putc(unsigned char date) { while(!(UTRSTAT0 & 0x02)); UTXH0=date; } void puts(char *str) { while(*str) putc(*str++); } void puthex(unsigned int val) { /* 0x1234abcd */ int i; int j; puts("0x"); for (i = 0; i < 8; i++) { j = (val >> ((7-i)*4)) & 0xf; if ((j >= 0) && (j <= 9)) putc('0' + j); else putc('A' + j - 0xa); } }
tag.c源码:
/*****************************************string_lib***********************************************/ int strlen(char *str) { int i=0; while(str[i] != 0) i++; return i; } void strcopy(char *dest,char *sour) { while((*dest++ = *sour++)!= 0); } /*****************************************tag_init************************************************/ #define tag_next(type) (struct tag *) ((unsigned long *)(type) + (type)->hdr.size) #define tag_size(size) ((sizeof(struct tag_header)+sizeof(struct size))>>2) struct tag_header { unsigned long size; unsigned long tag_type; }; struct tag_core { unsigned long flags; unsigned long pagesize; unsigned long rootdevf; }; struct tag_mem32 { unsigned long size; unsigned long start; }; struct tag_cmdline { char cmdline[1]; }; struct tag { struct tag_header hdr; union { struct tag_core core; struct tag_mem32 mem32; struct tag_cmdline cmdline; }u; }; static struct tag *params=(struct tag *)0x30000100; void set_start_tag(void) { params->hdr.size=tag_size(tag_core); params->hdr.tag_type=0x54410001; params->u.core.flags= 0; params->u.core.pagesize= 0; params->u.core.rootdevf= 0; params=tag_next(params); } void set_memory_tag(void) { params->hdr.size= tag_size(tag_mem32); params->hdr.tag_type = 0x54410002; params->u.mem32.size =64*1024*1024; params->u.mem32.start = 0x30000000; params=tag_next(params); } void set_cmdline_tag(char *cmdline) { int len=strlen(cmdline)+1; params->hdr.size = (sizeof(struct tag_header)+len+3)>>2; params->hdr.tag_type = 0x54410009; strcopy(params->u.cmdline.cmdline ,cmdline); params=tag_next(params); } void set_end_tag(void) { params->hdr.size = 0; params->hdr.tag_type = 0; }
tag.h源码:
#ifndef _TAG_H_ #define _TAG_H_ void set_cmdline_tag(char * cmdline); void set_end_tag(void); void set_memory_tag(void); void set_start_tag(void); #endif
main.c源码:
extern void nand_read(unsigned long sour, unsigned char * dest, int copy_size); extern void puts(char * str); void putc(unsigned char date); void puthex(unsigned int val); #include"tag.h" int main(void) { void (*thekernel)(int zero,int arch,unsigned int params); puts("bootloader start..... "); //copy kernel puts("1. copy kernal to sdram "); nand_read(0x60000+64,(unsigned char *)0x30008000,0x200000); //set params set_start_tag(); set_memory_tag(); set_cmdline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0"); set_end_tag(); puts("2. set kernel parameters "); //jump to kernel puts("3. jump to kernel "); thekernel=(void (*)(int,int ,unsigned int))0x30008000; thekernel(0,362,0x30000100); //error puts("something wrong "); return 0; }
编译用的Makefile文件:
OBJS := start.o init.o tag.o main.o CFLAGS := -O2 -Wall CPPFLAGS := -nostdinc -fno-builtin CC = arm-linux-gcc LD = arm-linux-ld OBJCOPY = arm-linux-objcopy OBJDUMP = arm-linux-objdump uboot.bin: ${OBJS} ${LD} -Tuboot.lds -o uboot.elf $^ ${OBJCOPY} -O binary -S uboot.elf $@ ${OBJDUMP} -D -m arm uboot.elf > uboot.dis %.o:%.c ${CC} ${CPPFLAGS} ${CFLAGS} -o $@ -c $< %.o:%.s ${CC} ${CPPFLAGS} ${CFLAGS} -o $@ -c $< clean: rm -f *.o *.bin *.elf *.dis
连接脚本:
SECTIONS { . = 0x33f80000; .text : {*(.text)} . = ALIGN(4); .rodata : {*(.rodata*)} . = ALIGN(4); .data : {*(.data)} . = ALIGN(4); __bss_start = .; .bss : {*(.bss) *(COMMON)} __bss_end = .; }