您的位置:首页 > 其它

自己动手写一个简单的bootloader

2016-08-24 15:28 225 查看
自己动手写一个简单的bootloader

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), 471685488@qq.com

 *   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 = (2*m*Fin) / (p*2^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*1024*1024就是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), 471685488@qq.com

 *   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), 471685488@qq.com

 *   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*1024*1024;    /* 大小为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: $(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 *.o *.bin *.elf *.dis

    

(六)setup.h

/*

 *  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 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


<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>

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

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

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

相关热门文章
欢迎寻找简单在ChinaUnix博客...

QEMU源码分析系列(四)...

Python 包管理工具解惑

MyBatis 入门(五)--分页查询(...

app开发费用

SHTML是什么_SSI有什么用...

卡尔曼滤波的原理说明...

shell中字符串操作

关于java中的“错误:找不到或...

linux设备驱动归纳总结...

linux dhcp peizhi roc

关于Unix文件的软链接

求教这个命令什么意思,我是新...

sed -e "/grep/d" 是什么意思...

谁能够帮我解决LINUX 2.6 10...

给主人留下些什么吧!~~

评论热议
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: