uboot分析

15年10月31日19:44:27


(一) start.S

写这一段代码前,先要清楚bootloader开始的时候都做什么了。无非就是硬件的初始化,我们想要写一个简单的bootloader,它的功能只是要能启动内核就行,因此,与uboot相比,它要做的东西很少。

总结出来就是:

(1)关看门狗;

(2)初始化时钟,设置分频系数,让板子跑的更快点;

(3)重定位代码,根据ARM的启动方式,如果是从NOR FLASH启动的话,首地址就是0,直接启动就行,把代码复制到SDRAM中即可,如果是NAND FLASH启动的话,一上电自动把前4K代码复制到steppingstone中,然后重新把代码复制到它的链接地址中。这样的话,在复制之前,就需要先初始化SDRAM。如果是NAND启动,同时需要先把NAND FLASH初始化了。

(4)清BSS段;

(5)跳到main函数,执行启动的第二阶段 。


以下是所有代码的全部注释,源代码是带灰色阴影的,注释是没有背景的。


/*

 * =============================================================================

 *

        Filename:  start.S

 


     Description:  自己写bootloader,第一个启动文件。

 


         Version:  1.0

 
        Created:  2015年10月26日 20时13分24秒

        Revision:  none

 
       Compiler:  arm-linux-gcc

 *

          Author:  Snoopy (ybx), [email protected]

 
   Organization:  TJPU

 *

 * =============================================================================

 /


#define MPLL_200MHZ ((92<<12) | (1<<4) | (1<<1))


.text

.global _start

_start:


/
1. 关看门狗 /

    ldr r0, =0x53000000

    mov r1, #0

    str r1, [r0]


/
对于2440来说,看门狗的地址是0x53000000,只要将它置为0即可。 /


/
2. 初始化时钟 /

    ldr r0, =0x4c000014

    mov r1, #0x03;

    str r1, [r0]


/
其中 0x4c000014 为CLKDIVN寄存器的地址值,CLKDIVN寄存器用于控制FCLK,HCLK,PCLK之间的比例关系,想要设置分频比为FCLK:HCLK:PCLK=1:2:4,需要设置CLKDIVN寄存器,HDIVN=1,PDIVN=1,即CLKDIVN的第[0]位为1,第[2:1]位为01。 /

 

    /
change the mode to the asynchronous bus mode /

    mrc p15, 0, r1, c1, c0, 0       /
读出控制寄存器 /

    orr r1, r1,  #0xc0000000        /
设置为“asynchronous bus mode” /

    mcr p15, 0, r1, c1, c0, 0       /
写入控制寄存器 /


/
如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode”,这个是数据手册里面说的。在上面的设置中,可以看到HDIVN=1,所以需要完成这样的改变。 /


    /
设置分频系数 /

    ldr r0, =0x4c000004

    ldr r1, = MPLL_200MHZ

    str r1, [r0]


/
0x4c000004是MPLLCON寄存器的地址值,MPLLCON寄存器用于控制FCLK和Fin的比例关系,

FCLK = (2mFin) / (p2^s),在上式中,m=MDIV+8,p=PDIV+2,s=SDIV。其中MDIV是MPLLCON的[19:12]位, PDIV是MPLLCON的[9:4]位, SDIV 是MPLLCON的[1:0]位。已知系统外部晶振输入为12MHz,需要FCLK输出为200MHz,可以算出来MDIV=92,PDIV=4,SDIV=1。 /


/
3. 初始化SDRAM /

    ldr r0, =0x48000000

    adr r1, sdram_init

    add r3, r1, #52

1:

    ldr r2, [r1], #4

    str r2, [r0], #4

    cmp r3, r1

    bne 1b


/
0x48000000是BWSCON 寄存器的地址值,这里其实是设置存储控制器的,2440一共有8个BANK,关于各个BANK的性质,在这里不再叙述,需要按照数据手册,将BWSCON,BANKCON0~7,REFRESH,BANKSIZE,MRSRB6,MRSRB7这几个寄存器的值一一算出来,然后依次存到寄存器中,sdram_init 是程序的一个标号,用来存放算出来的这些值,然后用上面的方法一一存进去,这种方法在uboot中很常用,必须能够熟练使用。同时使用到了adr这个中等范围取址指令。 /


/
4. 重定位 /

    ldr sp, =0x34000000


/
在使用c语言前需要先设置好栈,SDRAM的地址为0x30000000,一共有64M,64
10241024就是0x4000000,所以就把栈设置在最高处吧~ /


    bl nand_init


/
因为下面的copy_code_to_sdram代码中需要使用NAND FLASH,所以需要提前初始化它,就在这初始化了。 /


    mov r0, #0

    ldr r1, =_start

    ldr r2, =__bss_start

    sub r2, r2, r1


    bl copy_code_to_sdram   /
这个函数需要3个参数,所以需要在上面写出对应的r0,r1,r2;

                     * 源是从0开始,目的是程序的链接地址,长度是程序长度,即bss段开始                     * 的地址减去链接地址,正好就是程序的长度。

                     /

    bl clear_bss


/
5. 执行main /

    ldr lr, =halt_loop

    ldr pc, =main

halt_loop:

    b halt_loop


/
设置循环的目的是防止程序跑飞了,如果非要问程序为啥会跑飞,大致答案是这样的:ARM是一条一条取址执行的,如果在执行完main函数后,或者由于某种原因从main函数中跳出来了,那程序就会继续往下执行,但是程序是写在ram中的,后面的东西是不可预测的,所以就在这设置一个死循环,就让它在这一直转圈就好了~~~ /


sdram_init:

    .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

/


 
=====================================================================================

 *

        Filename:  init.c

 


     Description:  c语言的一些初始化函数等。

 


         Version:  1.0

 
        Created:  2015年10月26日 22时22分53秒

        Revision:  none

 
       Compiler:  arm-linux-gcc

 *

          Author:  Snoopy (ybx), [email protected]

 
   Organization:  TJPU

 *

 * =====================================================================================

 /


/
NAND FLASH registers /

#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)


/
serial /

#define PCLK 50000000

#define UART_BAUDRATE 115200

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


/
GPIO registers /

#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)


void nand_read (unsigned int addr, unsigned char buf, unsigned int len);



/


 
===  FUNCTION  ======================================================================

          Name:  is_boot_from_norflash

 
  Description:  判断程序是否从norflash启动的。

 * =====================================================================================

 
/

int

is_boot_from_norflash (void)

{

    volatile int p = (volatile int )0;

    int val;


    val = p;

    p = 0x12345678;

    if (val == p)

    {

        /
NOR /

        return 1;

    }

    else

    {

        /
NAND /

        p = val;

        return 0;

    }


}        /
-----  end of function isBootFromNorFlash  ----- /


/
对于这个函数,它在copy_code_to_sdram 函数中使用,用于判断程序是否从norflash启动,怎么判断呢,这就是根据nor flash与nand flash的特性不同来判断,nor flash只能读,不能往里面写入值,我们就从0地址取一个值(你也可以从其他地方…但是不能超出4k,最好是0地址),将0x12345678赋给它,如果它的值变成 0x12345678了,就说明写入成功,就是nand flash,写入成功的话就把代码原来的值毁了,还需要将原来的值赋回去,如果没有变成 0x12345678,那它就是nor flash。 /


/


 
===  FUNCTION  ======================================================================

          Name:  copy_code_to_sdram

 
  Description:  把代码复制到sdram中。

 * =====================================================================================

 
/

void

copy_code_to_sdram (unsigned char src, unsigned char dst, unsigned int len)

{

    int i = 0;


    if (is_boot_from_norflash())

    {

        /
从nor flash 启动的 /

        while (i < len)

        {

            dst[i] = src[i];

            i++;

        }

    }

    else

    {

        /
从nand flash 启动的 /

        //nand_init();

        nand_read((unsigned int)src, dst, len);

    }


}        /
-----  end of function copy_code_to_sdram  ----- /


/
对于这个函数,首先应该明确三点:源,目的,长度。如果是从nor flash启动的话,直接dst[i] = src[i]就行了,简单粗暴。如果是从nand 启动的话,就麻烦一点了,需要先初始化nand flash,然后用nand_read函数来读取。如果想用nand_read函数,就需要发地址,发命令,片选等等一大堆nand操作函数,所以一会慢慢写这些函数。 /



/


 
===  FUNCTION  ======================================================================

 
         Name:  clear_bss

 
  Description:  清bss段。

 
=====================================================================================

 /

void

clear_bss (void)

{

    extern int __bss_start, __bss_end;

    int p = &__bss_start;


    for (; p < &__bss_end; p++)

    {

        p = 0;

    }

}        /
-----  end of function clear_bss  ----- /



/
清BSS段,就是把BSS段里面的值都写为0,需要用到链接脚本中的BSS段的起始地址。在c语言中就是如上所示那样调用的。 /


/
以下几个就是nand flash的操作函数,在裸板程序中都写过了,就不一一分析了。 /


/


 
===  FUNCTION  ======================================================================

          Name:  nand_init

 
  Description:  nand初始化函数,设置一些时间参数等。

 * =====================================================================================

 
/

void

nand_init (void)

{

    NFCONF = (0<<12) | (3<<8) | (0<<4);

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


}        /* -----  end of function nand_init  ----- /



/


 * ===  FUNCTION  ======================================================================

          Name:  nand_select

 
  Description:  片选函数。

 * =====================================================================================

 /

void

nand_select (void)

{

    NFCONT &= ~(1<<1);

}        /
-----  end of function nand_select  ----- /



/


 * ===  FUNCTION  ======================================================================

          Name:  nand_deselect

 
  Description:  取消片选函数。

 * =====================================================================================

 /

void

nand_deselect (void)

{

    NFCONT |= (1<<1);

}        /
-----  end of function nand_deselect  ----- /



/


 * ===  FUNCTION  ======================================================================

          Name:  nand_cmd

 
  Description:  nand中发送命令函数。

 * =====================================================================================

 /

void

nand_cmd (unsigned char cmd)

{

    int i;

    NFCMMD = cmd;

    for (i = 0; i < 10; i++);


}        /
-----  end of function nand_cmd  ----- /


/
发送命令函数,就是往 NFCMMD这个寄存器里面写cmd命令就好,加循环就是为了让它多写一会~ /


/


 * ===  FUNCTION  ======================================================================

          Name:  nand_addr

 
  Description:  nand中发送地址函数。

 * =====================================================================================

 /

void

nand_addr (unsigned int addr)

{

    int i;

    int col, page;


    col = addr % 2048;

    page = addr / 2048;


    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++);


}        /
-----  end of function nand_addr  ----- /


/
发送地址函数,主要是需要好好理解col和page的算法,col是这一页中的第几个数据,用addr % 2048取余运算来做,余数正好就是第几个,page是需要求出是2048的几倍,用除法来做就好了~在计算机中,除法只会保存整数,因为我们定义的数据类型都是int类型的。 /


/


 * ===  FUNCTION  ======================================================================

          Name:  nand_wait_idle

 
  Description:  等待就绪函数。

 * =====================================================================================

 /

void

nand_wait_idle (void)

{

    while (!(NFSTAT & 1));

}        /
-----  end of function nand_wait_idle  ----- /



/


 * ===  FUNCTION  ======================================================================

          Name:  nand_read_data

 
  Description:  读取NFDATA寄存器中的数据函数。

 * =====================================================================================

 /

unsigned long

nand_read_data (void)

{

    return NFDATA;

}        /
-----  end of function nand_read_data  ----- /



/


 * ===  FUNCTION  ======================================================================

          Name:  nand_read

 
  Description:  nand读函数。

 * =====================================================================================

 /

void

nand_read (unsigned int addr, unsigned char buf, unsigned int len)

{

    int col = addr % 2048;

    int i = 0;


    /
1. 选中芯片 /

    nand_select();

    

    while (i < len)

    {

        /
2. 发送00命令 /

        nand_cmd(0x00);

    

        /
3. 发送地址 /

        nand_addr(addr);


        /
4. 发送30命令 /

        nand_cmd(0x30);


        /
5. 等待发送完毕 /

        nand_wait_idle();


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

        {

            buf[i] = nand_read_data();

            i++;

            addr++;

            /
我用下面这几句话就不对,为什么?其他的都一样。

             * buf = nand_read_data();

             * buf++;

             * addr++;

             /

        }

        col = 0;

    }


    /
6. 取消片选 /

    nand_deselect();


}        /
-----  end of function nand_read  ----- /


/
这个函数中不解的就是我在函数中注释那几句,可能是自己的c语言知识不过关吧,先放在这,以后再解决。 /


/
以下几个是串口函数的操作函数。 /

/


 
===  FUNCTION  ======================================================================

 
         Name:  uart0_init

   Description:  初始化串口函数。

 
=====================================================================================

 /

void

uart0_init(void)

{

    GPHCON = 0xa0;

    GPHUP = 0x0c;


    ULCON0 = 0x03;

    UCON0 = 0x05;

    UFCON0 = 0x00;

    UMCON0 = 0x00;

    UBRDIV0 = UART_BRD;

}        /
-----  end of function uart0_init  ----- /



/
-----------------------------------------------------------------------------

   等待输入函数,在这个程序中其实不需要。

 
-----------------------------------------------------------------------------/

unsigned char getc(void)

{

    while (!(UTRSTAT0 & (1<<0)));

    return URXH0;

}



/
-----------------------------------------------------------------------------

   输出一个字符的函数。

 
-----------------------------------------------------------------------------/

void putc(unsigned char c)

{

    UTXH0 = c;

    while (!(UTRSTAT0 & (1<<2)));

}



/
-----------------------------------------------------------------------------

   输出字符串函数。

 
-----------------------------------------------------------------------------/

void puts(char str)

{

    int i = 0;

    while (str[i])

    {

        putc(str[i]);

        i++;

    }

}



/
-----------------------------------------------------------------------------

 
  将val以16进制的形式输出。

 -----------------------------------------------------------------------------/

void puthex(unsigned int val)

{

    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);

    }

}


(三)boot.c  启动代码的第二阶段。

这一段代码就是设置bootloader传给内核的参数,然后启动内核就行了。

(1)首先从nand flash中把内核读入内存中,用nand_read函数即可,但是源,目的,长度是多少呢?我们把内核映像uImage放在了0x00060000的地方,uImage是64字节的头部+真正的内核(zImage),所以源地址是0x00060000+64,读到哪呢?在uImage的64字节头部中,有一个image_head_t结构体,里面重要的参数有两个,一个是in_load(加载地址),另一个是in_ep(入口地址),在启动内核的过程中,如果uboot发现uImage不位于它的加载地址的话,就将把它移到加载地址处,若直接位于加载地址上的话,就不需要移动了,这样就可以减少加载时间,所以我们就直接将它放在加载地址上面,就是0x30008000,读2M肯定够用了,一般内核会剪裁到2M以下,所以直接读2M,其实也可以查看uImage的准确大小,读那么大也行。所以nand_read函数如下所示:

nand_read(0x60000+64, (unsigned char )0x30008000, 0x200000);

(2)那么bootloader和内核是如何传递参数的呢?内核启动的时候,bootloader已经死掉了…所以它肯定是把这些参数放在一个固定的位置,然后内核去这个固定的位置取就行~即所谓的在某个地址(0x30000100),按照某种格式(tag)保存数据。

参照uboot中do_bootm_linux中,设置setup_start_tag();setup_memory_tag();setup_commandline_tag(“…”);setup_end_tag();将这些tag设置好即可。

下面贴图来显示这个tag在内存中的分布:


对于size的大小和next的定位,仔细查看setup.h中的函数定义,就能够分析出来。

(3)跳转执行。

<1>跳到内核的入口地址去执行,即0x30008000。

theKernel = (void (
) (int, int ,uint))0x30008000;

这个函数在uboot中的原型是:theKernel = (void (
)(int, int, uint))ntohl(hdr->ih_ep);

跳到内核的入口地址处。

<2>执行:

theKernel (0, 362, 0x30000100);

函数原型是:void (theKernel) (int zero, int arch,unsigned int params);

其中第一个参数是0,第二个参数是机器ID,2440为362,第三个参数为内核需要的参数的存放地址,即那些tag的存放地址(0x30000100)。


这些其实是参照uboot里面写的,下一篇文章会仔细分析分析uboot的代码。


需要注意的是,bootloader是不依赖任何库函数来执行的,所有的函数比如strlen等等都是需要自己写的,这个也就同时锻炼了自己的c语言能力。其中用到的 setup.h 这个头文件,是直接从uboot里面拷贝过来的,同时简单修改了一点,比如u32,u16的宏定义,里面定义了tag结构体以及设置tag用到的一些宏和函数。应该仔细研究研究这些代码。


/


 * =====================================================================================

 *

        Filename:  boot.c

 


     Description:  启动代码,bootloader的第二阶段。

 


         Version:  1.0

 
        Created:  2015年10月27日 15时38分20秒

        Revision:  none

 
       Compiler:  arm-linux-gcc

 *

          Author:  Snoopy (ybx), [email protected]

 
   Organization:  TJPU

 *

 * =====================================================================================

 /


#include    “setup.h”


extern void uart0_init(void);

extern void nand_read(unsigned int addr, unsigned char buf, unsigned int len);

extern void puts(char str);

extern void puthex(unsigned int val);


static struct tag params;

 

/
-----------------------------------------------------------------------------

 
strlen函数,需要自己实现。

 
-----------------------------------------------------------------------------
/

int strlen(char str)

{

    int i = 0;

    while (str[i])

    {

        i++;

    }

    return i;

}



/
-----------------------------------------------------------------------------

   strcpy函数,同样需要自己去实现。

 
-----------------------------------------------------------------------------/

void strcpy(char dst, char src)

{

    while ((dst++ = src++) != ‘\0’);

}


/
-----------------------------------------------------------------------------

 
设置传给内核的参数(tag),这是第一个tag,tag_size这个函数也是需要自己去实现的,

 
在setup.h中用宏定义的形式实现的。

 
-----------------------------------------------------------------------------
/

static void setup_start_tag()

{

    params = (struct tag )0x30000100;

    params->hdr.tag = ATAG_CORE;

    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);

}



/
-----------------------------------------------------------------------------

   设置memory_tag。

 
-----------------------------------------------------------------------------/

static void setup_memory_tag()

{

    params->hdr.tag = ATAG_MEM;

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


    params->u.mem.start = 0x30000000;    /
SDRAM的起始地址 /

    params->u.mem.size = 64
10241024;    / 大小为64M /


    params = tag_next(params);

}



/
-----------------------------------------------------------------------------

   设置commandline_tag。

 
-----------------------------------------------------------------------------/

static void setup_commandline_tag(char cmdline)

{

    int len = strlen(cmdline) + 1;


    params->hdr.tag = ATAG_CMDLINE;

    params->hdr.size = (sizeof(struct tag_header) + len + 3) >> 2;    /
这里要4字节对齐 /


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


    params = tag_next(params);

}



/
-----------------------------------------------------------------------------

 
  最后结束的时候,需要设置这个end_tag。给它赋0即可。

 -----------------------------------------------------------------------------/

static void setup_end_tag()

{

    params->hdr.tag = ATAG_NONE;

    params->hdr.size = 0;

}


/*

 * ===  FUNCTION  ======================================================================

          Name:  main

 
  Description:  这个是主函数,完成启动内核的任务。

 * =====================================================================================

 /

int

main (void)

{

    void (theKernel)(int zero, int arch, unsigned int params);

    //volatile unsigned int p = (volatile unsigned int )0x30008000;


    /
0. 帮内核初始化串口,这样就可以有打印信息从串口打印出来,否则内核会卡死在这里。 /

    uart0_init();


    /
1. 从NAND FLASH 中把内核读入内存 /

    puts(“Copy kernel from nand\n\r”);

    nand_read(0x60000+64, (unsigned char )0x30008000, 0x200000);

    //puthex(0x1234ABCD);

    //puts("\n\r");

    //puthex(p);

    //puts("\n\r");


    /
2. 设置参数(TAGS)
/

    puts(“Set boot params\n\r”);

    setup_start_tag();

    setup_memory_tag();

    setup_commandline_tag(“noinitrd root=/dev/mtdbolck3 init=/linuxrc                                         console=ttySAC0”);

    setup_end_tag();


    /
3. 跳转执行 /

    puts(“Boot the Kernel\n\r”);

    theKernel = (void (
)(int, int, unsigned int))0x30008000;

    theKernel(0, 362, 0x30000100);


    /
正常情况下不会执行到这里,如果执行到这里就是肯定出错了,打印出错信息。 /

    puts(“Error!\n\r”);


    return -1;

}                /
----------  end of function main  ---------- /




(四)boot.lds  链接脚本


SECTIONS {

    . = 0x33f80000;

    .text : {
(.text)}


    . = ALIGN(4);

    .rodata : {
(.rodata
)}

 

    . = ALIGN(4);

    .data : {(.data)}


    . = ALIGN(4);

    __bss_start = .;

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

    __bss_end = .;

}


(五)Makefile


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 -nostdlib -fno-builtin


objs := start.o init.o boot.o


boot.bin: KaTeX parse error: Expected 'EOF', got '&' at position 13: (objs)
&̲nbsp;  &nb…
{LD} -Tboot.lds -o boot.elf KaTeX parse error: Expected 'EOF', got '&' at position 8: ^
&̲nbsp;  &nb…
{OBJCOPY} -O binary -S boot.elf KaTeX parse error: Expected 'EOF', got '&' at position 8: @
&̲nbsp;  &nb…
{OBJDUMP} -D -m arm boot.elf > boot.dis

    

%.o:%.c

    ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ KaTeX parse error: Expected 'EOF', got '&' at position 1: &̲lt;

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


clean:

    rm -f .o .bin .elf .dis

    

(六)setup.h

/


 
  linux/include/asm/setup.h

 


 
  Copyright © 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 long


/*

 * 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










阅读(169) | 评论(0) | 转发(0) |



0

上一篇:ARM的启动和中断向量表


下一篇:u-boot-1.1.6源码分析


      
	  
    
  
  
给主人留下些什么吧!~~
评论热议

你可能感兴趣的:(uboot,uboot分析)