Mini2440学习日记(2)_U-boot的启动流程分析

Mini2440学习日记(1

--U-boot简介及启动流程分析

一、U-boot的引入

我们来回忆一下PC的体系结构:PC机中的引导加载程序是由BIOS和位于硬盘MBR中的OS Boot Loader(比如LILOGRUB等)一起组成的,BIOS在完成硬件检测和资源分配后,将硬盘MBR中的Boot Loader读到系统的RAM中,然后将控制权交给OS Boot LoaderBoot Loader的主要运行任务就是将内核映象从硬盘上读到RAM中,然后跳转到内核的入口点去运行,即开始启动操作系统。在嵌入式系统中,通常并没有像BIOS那样的固件程序(注:有的嵌入式cpu也会内嵌一段短小的启动程序),因此整个系统的加载启动任务就完全由Boot Loader来完成。比如在一个基于ARM7TDMI core的嵌入式系统中,系统在上电或复位时通常都从地址0x00000000处开始执行,而在这个地址处安排的通常就是系统的Boot Loader程序。

二、一个嵌入式的存储设备的分区

 

图1 一个典型的NandFlash分区

三、BootLoader的启动方式

Bootloader的启动方式主要有网络启动方式、磁盘启动方式和Flash启动方式。

 

图2 网络启动方式

四、U-boot的源码目录结构

图3 U-boot的源码目录结构及作用

五、U-boot的启动流程图

u-bootstage1代码通常放在cpu/xxxx/start.S文件中,用汇编语言写成,u-bootstage2代码通常放在lib_xxxx/board.c文件中,用C语言写成。

图4 U-boot的启动流程图和内存搬运图

六、U-boot最小代码量分析

最小源代码目录:

 

Start.s文件(U-boot的第一阶段启动代码)

.text

.global _start

_start:

  /*1 设置栈 */

ldr sp,=4096

    /*1 关闭看门狗 */

bl disable_watchdog

bl disable_interrupt

/*1 设置时钟 */

bl clock_init

/*1 初始化SDRAM */

bl sdram_init

        bl nand_init

/*1 初始化NAND FLASH */

/*1 确定三个参数 */

       mov r0, #0

ldr r1, =_start

ldr r2, = __bss_start

       sub r2,r2,r1

/*1 UBOOT NAND FLASH 拷贝到SDRAM*/

bl copy_uboot_to_sdram

/*1 清除BSS */

bl clear_bss

/*1 跳转到MIAN函数*/

ldr lr, =halt

       ldr sp, =0x34000000

ldr pc, =main

halt:

b  halt

 

Boot.c文件(U-boot的第二阶段启动代码):

#include "setup.h"

#define PWTCON *(volatile unsigned int *)0x5300000

#define GPBCON *(volatile unsigned long *)0X56000010

#define GPBDAT *(volatile unsigned long *)0x56000014

#define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x1<<4)|(0x01<<0))

#define MPLLCON *(volatile unsigned int *)0x4c000004

#define CLKDIVN *(volatile unsigned int *)0x4C000014

#define ULCON0  *(volatile unsigned long *)0x50000000

#define UCON0    *(volatile unsigned long *)0x50000004

#define UTXH0    *(volatile unsigned long *)0x50000020

#define UTRSTAT0 *(volatile unsigned long *)0x50000010

#define UBRDIV0  *(volatile unsigned long *)0x50000028  

#define GPHCON   *(volatile unsigned long *)0x56000070  

#define GPHUP    *(volatile unsigned long *)0x56000078  

#define PCLK            50000000    // init.c中的clock_init函数设置PCLK50MHz

#define UART_CLK        PCLK        //  UART0的时钟源设为PCLK

#define UART_BAUD_RATE  115200      // 波特率

#define UART_BRD        ((PCLK/(UART_BAUD_RATE * 16)) - 1)

void disable_watchdog(void)

{

PWTCON = 0;

}

#define INTMSK *(volatile unsigned int *)0x4A000008

void disable_interrupt(void)

{

INTMSK = 0xffffffff;

}

void uart_init(void)

{

ULCON0  =0x3;   //8 N 1

UCON0   =0x5;   //中断或者查询模式

GPHCON  =0xa0;  //设置GPH2TX0

GPHUP   =0x0c;  //设置上拉

UBRDIV0 =UART_BRD;

}

void putc(char c)

{

while(0 == (UTRSTAT0 & 0x4));

UTXH0 = c;

}

void puts(char *p)

{

if(!p) return;

while(*p !='\0')

{

putc(*p);

p++;

}

}

void printout()

{

   static char i=0;

   i++;

   if(i>4)

    i=0;

    putc(0x30+i);

    putc('\n');

}

void clock_init(void)

{

CLKDIVN = 0x5;

__asm__(

    "mrc    p15, 0, r1, c1, c0, 0\n"        /* 读出控制寄存器 */

    "orr    r1, r1, #0xc0000000\n"          /* 设置为“asynchronous bus mode*/

    "mcr    p15, 0, r1, c1, c0, 0\n"        /* 写入控制寄存器 */

    );

MPLLCON = S3C2440_MPLL_400MHZ;

}

void sdram_init(void)

{

volatile unsigned int *p = (volatile unsigned int *)0x48000000;

   p[0] =0x22011110,     //BWSCON

   p[1] =0x00000700,     //BANKCON0    

   p[2] =0x00000700,     //BANKCON1

   p[3] =0x00000700,     //BANKCON2

   p[4] =0x00000700,     //BANKCON3  

   p[5] =0x00000700,     //BANKCON4

   p[6] =0x00000700,     //BANKCON5

   p[7] =0x00018005,     //BANKCON6

   p[8] =0x00018005,     //BANKCON7             

   p[9] =0x008C04F4,  //REFRESH

   p[10]=0x000000B1,     //BANKSIZE

   p[11]=0x00000030,     //MRSRB6

   p[12]=0x00000030;     //MRSRB7

}

#define NFCONF *(volatile unsigned int *)0x4e000000

#define NFCONT *(volatile unsigned int *)0x4e000004

#define NFCMMD *(volatile unsigned char*)0x4e000008

#define NFADDR *(volatile unsigned int *)0x4e00000C

#define NFDATA *(volatile unsigned char *)0x4e000010

#define NFSTAT *(volatile unsigned int *)0x4e000020

#if 1

void nand_init(void)

{

#define TACLS  0

#define TWRPH0 1

#define TWRPH1 0

NFCONF |= (TACLS << 12)|(TWRPH0 << 8)|(TWRPH1 <<4);

NFCONT |= ((1 << 4) | (1 << 1) | (1 << 0));

}

void nand_select(void)

{

NFCONT &= ~(1<<1);

}

 

void nand_disselect(void)

{

NFCONT |= (1<<1);

}

void nand_command(unsigned char cmd)

{

unsigned int i = 0 ;

NFCMMD = cmd;

for(i = 20 ; i>0;i--);

}

 

#define NAND_PAGE_SIZE 2048

void nand_address(unsigned int addr)

{

unsigned int page = addr/NAND_PAGE_SIZE;

unsigned int col  = addr%NAND_PAGE_SIZE;

unsigned i = 0 ;

 

NFADDR = (col & 0xff);

for(i = 20 ; i>0;i--);

NFADDR = ((col >> 8) & 0xff);

for(i = 20 ; i>0;i--);

 

NFADDR = (page & 0xff);

for(i = 20 ; i>0;i--);

 

NFADDR = ((page >> 8) & 0xff);

for(i = 20 ; i>0;i--);

NFADDR = ((page >> 16) & 0xff);

for(i = 20 ; i>0;i--);

 

}

 

unsigned char nand_data(void)

{

return NFDATA;

}

void nand_ready(void)

{

while(0 == (NFSTAT&0x1));

}

 

void nand_read1(unsigned char* src , unsigned char* dest ,unsigned int len)

{

     

int col = (unsigned long)src % NAND_PAGE_SIZE;

int i = 0 ;

nand_select();

while(i < len)

{

nand_command(0x00);

nand_address((unsigned int)src);

nand_command(0x30);

nand_ready();

for(; (col < NAND_PAGE_SIZE)&&(i<len);col++)

{

dest[i] = nand_data();

i++;

src++;

}

col = 0;

}

nand_disselect();

}

void nand_read2(unsigned char* src , unsigned char* dest ,unsigned int len)

{

       puts("tioashi1\r\n");

int col = (unsigned long)src % NAND_PAGE_SIZE;

int i = 0 ;

nand_select();

puts("tioashi2\r\n");

while(i < len)

{

nand_command(0x00);

nand_address((unsigned int)src);

nand_command(0x30);

nand_ready();

for(; (col < NAND_PAGE_SIZE)&&(i<len);col++)

{

dest[i] = nand_data();

i++;

src++;

}

col = 0;

puts("tioashi3-------------------------------\r\n");

putc(0x30+i);

}

puts("tioashi4\r\n");

nand_disselect();

}

#endif

int BootFromNandFlash_or_NorFlash(void)

{

volatile int *p = (volatile int *)0;

int val = *p;

*p =  0x12345678;

if(*p==0x12345678)

{

*p = val;

return 1;

}

else

return 0;

}

int copy_uboot_to_sdram(unsigned char* src , unsigned char *dest , unsigned int len)

{

int i = 0 ;

if( BootFromNandFlash_or_NorFlash()==1)

{

nand_read1(src,dest,len);

}

else

{

while(i < len)

{

dest[i]= src[i];

dest++;

src++;

i++;

}

}

return 0;

}

void clear_bss(void)

{

extern unsigned int  __bss_start,__bss_end;

volatile unsigned int *p = &__bss_start;

while(p < &__bss_end)

{

*p = 0;

p++;

}

}

static struct tag *params;

static void setup_start_tag (void)

{

params = (struct tag*)0x30000100;

params->hdr.tag = ATAG_CORE ;

params->hdr.size = tag_size (tag_core);//3

params->u.core.flags = 0;//read-only

params->u.core.pagesize = 0;//

params->u.core.rootdev = 0;

params = tag_next (params);

}

static void setup_memory_tags (void)

{

 

params->hdr.tag = ATAG_MEM;

params->hdr.size = tag_size (tag_mem32);//

params->u.mem.start = 0x30000000;//内存的其实地址0x30000000

params->u.mem.size = 64*1024*1024;//64M

params = tag_next (params);

}

/*uboot不依赖任何标准库程序,因此字符串处理函数还需要自己写*/

char * strcpy(char * dest,const char *src)

{

char *tmp = dest;

while ((*dest++ = *src++) != '\0')

/* nothing */;

return tmp;

}

 

unsigned int strlen(const char * s)

{

const char *sc;

 

for (sc = s; *sc != '\0'; ++sc)

/* nothing */;

return sc - s;

}

static void setup_commandline_tag (char *commandline)

{

char *p = commandline;

 

if (!commandline)

return;

 

params->hdr.tag = ATAG_CMDLINE ;

params->hdr.size =(sizeof (struct tag_header) + strlen (p) + 1 + 3) >> 2;

 

strcpy (params->u.cmdline.cmdline, p);

 

params = tag_next (params);

}

 

static void setup_end_tag (void)

{

params->hdr.tag = 0x00000000;

params->hdr.size = 0;

}

void len_on(void)

{

 GPBCON |=(0x1<<10);

     GPBDAT =0;

}

int main(void)

{

/*定义一个函数指针*/

void (* thekernel)(int zero,int arch,unsigned int params);

/*初始化串口,内核启动后打印内核信息*/

uart_init();

/*将内核拷贝到SDRAM*/

puts("copy kernel to SDRAN...\r\n");

nand_read2((unsigned char*)(0x60000+64),(unsigned char *)0x30008000,(unsigned int)0x200000);

/*设置启动参数*/

puts("shezhiqidongcanshu...\r\n");

setup_start_tag();

setup_memory_tags();

setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");

setup_end_tag();

/*跳到内核的入口地址去执行*/

puts("boot the kernel...\r\n");

thekernel = (void(*)(int,int,unsigned int))0x30008000;

thekernel(0,263,0x30000100);

puts("error\r\n");

    return 0;

}

Boot.ldsU-boot代码的链接文件):

SECTIONS{

. = 0x33f80000;

.text  : {*(.text)}

. =ALIGN(4);

.rodata : {*(.rodata)}

. =ALIGN(4);

.data  : {*(.data)}

. =ALIGN(4);

__bss_start = .;

.bss : {*(.bss)  *(COMMON)}

__bss_end = .;

}

MakeFile文件(U-boot的编译文件):

CC      = arm-linux-gcc

LD      = arm-linux-ld

AR      = arm-linux-ar

OBJCOPY = arm-linux-objcopy

OBJDUMP = arm-linux-objdump

CFLAGS := -Wall -O2

CPPFLAGS    := -nostdinc -fno-builtin

objs := start.o boot.o

boot.bin: $(objs)

${LD} -Tboot.lds -o boot.elf $^

${OBJCOPY} -O binary -S boot.elf $@

${OBJDUMP} -D -m arm boot.elf > boot.dis

%.o:%.c

${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

%.o:%.s

${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

clean:

rm -f  *.bin *.elf  *.dis  *.o

Setup.h文件(U-boot中一些结构体的定义):

/*

 *  linux/include/asm/setup.h

 *

 *  Copyright (C) 1997-1999 Russell King

 *

 * This program is free software; you can redistribute it and/or modify

 * it under the terms of the GNU General Public License version 2 as

 * published by the Free Software Foundation.

 *

 *  Structure passed to kernel to tell it about the

 *  hardware it's running on.  See linux/Documentation/arm/Setup

 *  for more info.

 *

 * NOTE:

 *  This file contains two ways to pass information from the boot

 *  loader to the kernel. The old struct param_struct is deprecated,

 *  but it will be kept in the kernel for 5 years from now

 *  (2001). This will allow boot loaders to convert to the new struct

 *  tag way.

 */

#ifndef __ASMARM_SETUP_H

#define __ASMARM_SETUP_H

#define u8 unsigned  char

#define u16 unsigned short

#define u32 unsigned int

/*

 * Usage:

 *  - do not go blindly adding fields, add them at the end

 *  - when adding fields, don't rely on the address until

 *    a patch from me has been released

 *  - unused fields should be zero (for future expansion)

 *  - this structure is relatively short-lived - only

 *    guaranteed to contain useful data in setup_arch()

 */

#define COMMAND_LINE_SIZE 1024

 

/* This is the old deprecated way to pass parameters to the kernel */

struct param_struct {

    union {

struct {

    unsigned long page_size; /*  0 */

    unsigned long nr_pages; /*  4 */

    unsigned long ramdisk_size; /*  8 */

    unsigned long flags; /* 12 */

#define FLAG_READONLY 1

#define FLAG_RDLOAD 4

#define FLAG_RDPROMPT 8

    unsigned long rootdev; /* 16 */

    unsigned long video_num_cols; /* 20 */

    unsigned long video_num_rows; /* 24 */

    unsigned long video_x; /* 28 */

    unsigned long video_y; /* 32 */

    unsigned long memc_control_reg; /* 36 */

    unsigned char sounddefault; /* 40 */

    unsigned char adfsdrives; /* 41 */

    unsigned char bytes_per_char_h; /* 42 */

    unsigned char bytes_per_char_v; /* 43 */

    unsigned long pages_in_bank[4]; /* 44 */

    unsigned long pages_in_vram; /* 60 */

    unsigned long initrd_start; /* 64 */

    unsigned long initrd_size; /* 68 */

    unsigned long rd_start; /* 72 */

    unsigned long system_rev; /* 76 */

    unsigned long system_serial_low; /* 80 */

    unsigned long system_serial_high; /* 84 */

    unsigned long mem_fclk_21285;       /* 88 */

} s;

char unused[256];

    } u1;

    union {

char paths[8][128];

struct {

    unsigned long magic;

    char n[1024 - sizeof(unsigned long)];

} s;

    } u2;

    char commandline[COMMAND_LINE_SIZE];

};

 

 

/*

 * The new way of passing information: a list of tagged entries

 */

 

/* The list ends with an ATAG_NONE node. */

#define ATAG_NONE 0x00000000

 

struct tag_header {

u32 size;

u32 tag;

};

 

/* The list must start with an ATAG_CORE node */

#define ATAG_CORE 0x54410001

 

struct tag_core {

u32 flags; /* bit 0 = read-only */

u32 pagesize;

u32 rootdev;

};

 

/* it is allowed to have multiple ATAG_MEM nodes */

#define ATAG_MEM 0x54410002

 

struct tag_mem32 {

u32 size;

u32 start; /* physical start address */

};

 

/* VGA text type displays */

#define ATAG_VIDEOTEXT 0x54410003

 

struct tag_videotext {

u8 x;

u8 y;

u16 video_page;

u8 video_mode;

u8 video_cols;

u16 video_ega_bx;

u8 video_lines;

u8 video_isvga;

u16 video_points;

};

 

/* describes how the ramdisk will be used in kernel */

#define ATAG_RAMDISK 0x54410004

 

struct tag_ramdisk {

u32 flags; /* bit 0 = load, bit 1 = prompt */

u32 size; /* decompressed ramdisk size in _kilo_ bytes */

u32 start; /* starting block of floppy-based RAM disk image */

};

 

/* describes where the compressed ramdisk image lives (virtual address) */

/*

 * this one accidentally used virtual addresses - as such,

 * its depreciated.

 */

#define ATAG_INITRD 0x54410005

 

/* describes where the compressed ramdisk image lives (physical address) */

#define ATAG_INITRD2 0x54420005

 

struct tag_initrd {

u32 start; /* physical start address */

u32 size; /* size of compressed ramdisk image in bytes */

};

 

/* board serial number. "64 bits should be enough for everybody" */

#define ATAG_SERIAL 0x54410006

 

struct tag_serialnr {

u32 low;

u32 high;

};

 

/* board revision */

#define ATAG_REVISION 0x54410007

 

struct tag_revision {

u32 rev;

};

 

/* initial values for vesafb-type framebuffers. see struct screen_info

 * in include/linux/tty.h

 */

#define ATAG_VIDEOLFB 0x54410008

 

struct tag_videolfb {

u16 lfb_width;

u16 lfb_height;

u16 lfb_depth;

u16 lfb_linelength;

u32 lfb_base;

u32 lfb_size;

u8 red_size;

u8 red_pos;

u8 green_size;

u8 green_pos;

u8 blue_size;

u8 blue_pos;

u8 rsvd_size;

u8 rsvd_pos;

};

 

/* command line: \0 terminated string */

#define ATAG_CMDLINE 0x54410009

 

struct tag_cmdline {

char cmdline[1]; /* this is the minimum size */

};

 

/* acorn RiscPC specific information */

#define ATAG_ACORN 0x41000101

 

struct tag_acorn {

u32 memc_control_reg;

u32 vram_pages;

u8 sounddefault;

u8 adfsdrives;

};

/* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */

#define ATAG_MEMCLK 0x41000402

 

struct tag_memclk {

u32 fmemclk;

};

struct tag {

struct tag_header hdr;

union {

struct tag_core core;

struct tag_mem32 mem;

struct tag_videotext videotext;

struct tag_ramdisk ramdisk;

struct tag_initrd initrd;

struct tag_serialnr serialnr;

struct tag_revision revision;

struct tag_videolfb videolfb;

struct tag_cmdline cmdline;

 

/*

 * Acorn specific

 */

struct tag_acorn acorn;

 

/*

 * DC21285 specific

 */

struct tag_memclk memclk;

} u;

};

 

struct tagtable {

u32 tag;

int (*parse)(const struct tag *);

};

 

#define __tag __attribute__((unused, __section__(".taglist")))

#define __tagtable(tag, fn) \

static struct tagtable __tagtable_##fn __tag = { tag, fn }

 

#define tag_member_present(tag,member) \

((unsigned long)(&((struct tag *)0L)->member + 1) \

<= (tag)->hdr.size * 4)

 

#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))

#define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2)

 

#define for_each_tag(t,base) \

for (t = base; t->hdr.size; t = tag_next(t))

 

/*

 * Memory map description

 */

#define NR_BANKS 8

 

struct meminfo {

int nr_banks;

unsigned long end;

struct {

unsigned long start;

unsigned long size;

int           node;

} bank[NR_BANKS];

};

 

extern struct meminfo meminfo;

#endif

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值