实现简单的 u-boot

根据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 = .;
}

 
原文地址:https://www.cnblogs.com/zsy12138/p/10396988.html