加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

(六) 自己写简单的u-boot

发布时间:2020-12-15 19:53:52 所属栏目:百科 来源:网络整理
导读:前言:想想 uboot 的代码量,我们说自己写一个 bootloader 是不是口出狂言了?然而并没有,bootloader 的唯一目的只有一个,那便是启动内核。内核就是一大段可执行程序,我们只要跳转到它的入口地址去执行不就OK? 所以,写一个简单的 bootloader 并不困难。

前言:想想 uboot 的代码量,我们说自己写一个 bootloader 是不是口出狂言了?然而并没有,bootloader 的唯一目的只有一个,那便是启动内核。内核就是一大段可执行程序,我们只要跳转到它的入口地址去执行不就OK? 所以,写一个简单的 bootloader 并不困难。

    现在来思考一下,目的是启动内核,那么内核在哪里?刚上电的时候,内核肯定是位于 nandflash 里的,我们得具备初始化 nandflash 并读取的功能。那么,我们将内核去读到 sdram 然后跳转到入口地址去执行就够了么?然而还不行,bootloader 启动内核时还需要给内核传递一些信息(tag),两个必不可少的信息是 内存标记和命令行参数。信息传递完,那么内核就一定能起得来么?未必,启动内核时,我们还会传递一个机器ID,如果Uboot传递进去的机器ID和内核支持的机器ID不匹配,那么内核也无法启动。想必,分析过 uboot 的同学对这个并不陌生。

一、自己写 bootloader ,或者移植 uboot ,需要知道的一些信息

  • 1、内核在 nandflash 中的地址,是 uImage 还是 zImage,我这里用的是 uImage,在 nandflash 里的 0x60000处,uImage 是用来支持 uboot 启动的,不过我们自己写的话用 uImage 也没关系,因为 uImage 就是在 zImage 的基础上加了一个 64 字节的头部,用来告诉 uboot 内核的信息,比如版本号、加载地址、链接地址、编译时间等。uboot 会获取到这个头部,干一些事情。我们自己写的话,就不需要头部了,从NAND FLASH里把内核读入内存,直接跳到 uImage 启示地址 + 64 的地方去读就OK 。

  • 2、内核的链接地址:0x30008000,这个连接地址实际上应该说是“真正”内核的链接地址,如果是 uImage ,不应该包含它的头部。知道什么意思了吧,使用 uImage 时,我们应当将整个 uImage 拷贝到 0x30008000 - 64 的地方去,也就是 0x30007fc0 。

  • 3、bootloader 的连接地址:uboot的链接地址一般为 0x3ff80000 处,我们自己写的也用这个地址好了。说到这里,必须得提一下,对于2440来说,不管是 nand 启动,还是 nor 启动,刚上电的时候我们的 bootloader 并不是运行在链接地址处,那么这时候跑在非链接地址处的这些指令就得有特殊要求——位置无关码<了解更多点我跳转>。我个人做法,在将自身代码拷贝到链接地址处之前,能用汇编写的尽量不用C写,因为用汇编我们自己可以分得清哪些是位置无关码,迫不得已的情况下用C写,写完看反汇编,看看那些跳转指令是否依赖于当前PC值。
  • 4、标记 tag 的地址,2440 常用的做法是放在 0x30000100 处,我们同样也放在这里。其实放那都行,地址会作为参数传递给内核的。tag的放置方法,可以参考 uboot ,必须以 ATAG_CORE 类型的开头,以 ATAG_NONE 类型的结尾。
  • 5、启动内核时传递给内核的参数,3个,第一个默认0,第三个是前边提到的 tag 的地址,第二个是机器ID。内核中所有支持的“机器”或者称作开发板、单板都用一个 MACHINE_START 宏来定义,这个宏的作用就是填充一个 machine_desc 类型的结构体,填充的过程中会对它的 .nr 成员赋值,这个 nr 就是所谓的机器ID。举个例子:
MACHINE_START(HALIBUT,"Halibut Board (QCT SURF7200A)")    
    .boot_params      = 0x10000100,.map_io           = halibut_map_io,.init_irq         = halibut_init_irq,.init_machine     = halibut_init,.timer            = &msm_timer,MACHINE_END   
struct machine_desc __mach_desc_HALIBUT{    
__used                                                              
__attribute__((__section__(".arch.info.init")))= {    
    .nr               = MACH_TYPE_HALIBUT,.name             = "HalibutBoard (QCT SURF7200A)",.boot_params      = 0x10000100,}; 

MACH_TYPE_HALIBUT 这个宏,搜遍代码也没找到,我在 linux-2.6.32.2archarmtoolsmach-types 里发现了一点踪迹,应该是在这里的信息生成的宏吧。对于 JZ2440 来说,机器ID定义的是 362 。这里边也有个 boot_params 和前边实际tag存放的地址要一致。

  • 6、内核刚启动时会打印一些信息,但是那时候内核自己并不会初始化串口,也为了方便自己调试,bootloader里需要初始化串口。

二、概括一下自己写bootloader的步骤

根据前面的分析大概知道了bootloader需要干什么

这里写图片描述

start.S

#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
#define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01))
#define MEM_CTL_BASE 0x48000000

.text
.global _start
_start:

/* 1. 关看门狗 */
    ldr r0,=0x53000000
    mov r1,#0
    str r1,[r0]

/* 2. 设置时钟 */
    ldr r0,=0x4c000014
    //mov r1,#0x03; // FCLK:HCLK:PCLK=1:2:4,HDIVN=1,PDIVN=1
    mov r1,#0x05; // FCLK:HCLK:PCLK=1:4:8,HDIVN=4,PDIVN=1
    str r1,[r0]

    /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
    mrc p15,0,r1,c1,c0,0       /* 读出控制寄存器 */ 
    orr r1,#0xc0000000 /* 设置为“asynchronous bus mode” */
    mcr p15,0       /* 写入控制寄存器 */

    /* MPLLCON = S3C2440_MPLL_400MHZ */
    ldr r0,=0x4c000004
    ldr r1,=S3C2440_MPLL_400MHZ
    str r1,[r0]

    /* 启动ICACHE */
    mrc p15,r0,0 @ read control reg
    orr r0,#(1<<12)
    mcr p15,0 @write it back

    /* 3. 初始化SDRAM */
    ldr r0,=MEM_CTL_BASE
    adr r1,sdram_config     /* sdram_config的当前地址 */
    add r3,#(13*4)
1:
    ldr r2,[r1],#4
    str r2,[r0],#4
    cmp r0,r3
    bne 1b

    /* 4. 设置栈 */
    ldr sp,=0x34000000
/* 4. 重定位 : 把bootloader本身的代码从Nor_flash或者Nand_flash复制到SDRAM */
/* copy_code_to_sdram(unsigned char *src,unsigned char *dest,unsigned int len) */
    mov r0,#0 //第一个参数起始地址:r0:0
    ldr r1,=_start //第二个参数链接地址:r1:链接地址 _start=0X33f80000
    ldr r2,=__bss_start
    sub r2,r2,r1 //r2:__bss_start - _start(参考链接脚本)0X33f80000开始存放

    bl copy_code_to_sdram

/* 5. 清楚bss段 */ 
    bl clear_bss

/* 6. 执行main */
    ldr lr,=halt
    ldr pc,=main
halt:
    b halt

sdram_config:
    .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

/* NAND FLASH控制器 */
#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))

/* GPIO */
#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)

#define TXD0READY (1<<2)


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

/* Norflash可以像内存那样读,但是不能写 */
/* 我们先写一个值,看能不能成功。最后将该地址处的值还原 */
/* 如果成功就证明是Nand_Flash启动,否则就是NorFlash启动 */
int isBootFromNorFlash(void)
{
    volatile int *p = (volatile int *)0;
    int val;

    val = *p;
    *p = 0x12345678;
    if (*p == 0x12345678)
    {
        /* 写成功,是nand启动 */
        *p = val;
        return 0;
    }
    else
    {
        /* NOR不能像内存一样写 */
        return 1;
    }
}

void copy_code_to_sdram(unsigned char *src,unsigned char *dest,unsigned int len)
{   
    int i = 0;

    /* 如果是NOR启动 */
    if (isBootFromNorFlash())
    {
        while (i < len)
        {
            dest[i] = src[i];
            i++;
        }
    }
    else
    {
        nand_init();
        nand_read((unsigned int)src,dest,len);
    }
}

void clear_bss(void)
{
    extern int __bss_start,__bss_end;
    int *p = &__bss_start;

    for (; p < &__bss_end; p++)
        *p = 0;
}

void nand_init(void)
{
#define TACLS 0
#define TWRPH0 1
#define TWRPH1 0
    /* 设置时序 */
    NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
    /* 使能NAND Flash控制器,初始化ECC,禁止片选 */
    NFCONT = (1<<4)|(1<<1)|(1<<0);  
}

void nand_select(void)
{
    NFCONT &= ~(1<<1); 
}

void nand_deselect(void)
{
    NFCONT |= (1<<1);   
}

void nand_cmd(unsigned char cmd)
{
    volatile int i;
    NFCMMD = cmd;
    for (i = 0; i < 10; i++);
}

void nand_addr(unsigned int addr)
{
    unsigned int col  = addr % 2048;
    unsigned int page = addr / 2048;
    volatile int i;

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

void nand_wait_ready(void)
{
    while (!(NFSTAT & 1));
}

unsigned char nand_data(void)
{
    return NFDATA;
}

void nand_read(unsigned int addr,unsigned int len)
{
    int col = addr % 2048;
    int i = 0;

    /* 1. 选中 */
    nand_select();

    while (i < len)
    {
        /* 2. 发出读命令00h */
        nand_cmd(0x00);

        /* 3. 发出地址(分5步发出) */
        nand_addr(addr);

        /* 4. 发出读命令30h */
        nand_cmd(0x30);

        /* 5. 判断状态 */
        nand_wait_ready();

        /* 6. 读数据 */
        for (; (col < 2048) && (i < len); col++)
        {
            buf[i] = nand_data();
            i++;
            addr++;
        }

        col = 0;
    }

    /* 7. 取消选中 */       
    nand_deselect();
}

#define PCLK 50000000 // init.c中的clock_init函数设置PCLK为50MHz
#define UART_CLK PCLK // UART0的时钟源设为PCLK
#define UART_BAUD_RATE 115200 // 波特率
#define UART_BRD ((UART_CLK / (UART_BAUD_RATE * 16)) - 1)

/* * 初始化UART0 * 115200,8N1,无流控 */
void uart0_init(void)
{
    GPHCON  |= 0xa0;    // GPH2,GPH3用作TXD0,RXD0
    GPHUP   = 0x0c;     // GPH2,GPH3内部上拉

    ULCON0  = 0x03;     // 8N1(8个数据位,无较验,1个停止位)
    UCON0   = 0x05;     // 查询方式,UART时钟源为PCLK
    UFCON0  = 0x00;     // 不使用FIFO
    UMCON0  = 0x00;     // 不使用流控
    UBRDIV0 = UART_BRD; // 波特率为115200
}

/* * 发送一个字符 */
void putc(unsigned char c)
{
    /* 等待,直到发送缓冲区中的数据已经全部发送出去 */
    while (!(UTRSTAT0 & TXD0READY));

    /* 向UTXH0寄存器中写入数据,UART即自动将它发送出去 */
    UTXH0 = c;
}

void puts(char *str)
{
    int i = 0;
    while (str[i])
    {
        putc(str[i]);
        i++;
    }
}

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

    }

}

boot.c

#include "setup.h"

extern void uart0_init(void);
extern void nand_read(unsigned int addr,unsigned int len);
extern void puts(char *str);
extern void puthex(unsigned int val);


static struct tag *params;

void setup_start_tag(void)
{
    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);
}

void setup_memory_tags(void)
{
    params->hdr.tag = ATAG_MEM;
    params->hdr.size = tag_size (tag_mem32);

    params->u.mem.start = 0x30000000;
    params->u.mem.size  = 64*1024*1024;

    params = tag_next (params);
}

int strlen(char *str)
{
    int i = 0;
    while (str[i])
    {
        i++;
    }
    return i;
}

void strcpy(char *dest,char *src)
{
    while ((*dest++ = *src++) != '');
}

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;

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

    params = tag_next (params);
}

void setup_end_tag(void)
{
    params->hdr.tag = ATAG_NONE;
    params->hdr.size = 0;
}


int main(void)
{
    void (*theKernel)(int zero,int arch,unsigned int params);
    volatile unsigned int *p = (volatile unsigned int *)0x30008000;

    /* 8. 帮内核设置串口: 内核启动的开始部分会从串口打印一些信息,但是内核一开始没有初始化串口 */
    uart0_init();

    /* 9. 从NAND FLASH里把内核读入内存 */
    /* 0x60000+64(64字节的头部=>我们直接跳过头部读取zimage就行了) */
    /* 内核地址0x30008000(内核中配置好的地址)nand_read的实现 */
    puts("CZG!!!");
    puts("rn");
    puts("Copy kernel from nandnr");
    nand_read(0x60000+64,(unsigned char *)0x30008000,0x200000);
    puthex(0x1234ABCD);
    puts("nr");
    puthex(*p);
    puts("nr");

    /* 10. 设置参数 */
    puts("Set boot paramsnr");
    /* 下面几个函数,都向地址内写入了 */
    /* (1)参数代号 */
    /* (2)本参数所占内存大小 */
    /* (3)参数内容 */
    /* (4)每个参数设置最后都指向了下一参数设置地址 */

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

    /* 3. 跳转执行,启动内核 */
    puts("Boot kernelnr");
    theKernel = (void (*)(int,int,unsigned int))0x30008000;
    theKernel(0,362,0x30000100);  
    /* * mov r0,#0 * ldr r1,=362 * ldr r2,=0x30000100 * mov pc,#0x30008000 */

    puts("Error!nr");
    /* 如果一切正常,不会执行到这里 */

    return -1;
}

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:  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_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

Makefile

CC      = arm-linux-gcc
LD      = arm-linux-ld
AR      = arm-linux-ar
OBJCOPY = arm-linux-objcopy
OBJDUMP = arm-linux-objdump


CFLAGS      := -Wall -O2  -fno-builtin #-Wall:打开警告信息 -O2:2级优化(常用) -fno-builtin:不使用内建函数(如putchar)
CPPFLAGS    := -nostdinc  -nostdlib #-nostdinc:不在标准系统目录中搜索头文件,只在-I指定的目录中搜索 
                                                     #-nostdlib:不连接标准启动文件和标准库文件

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 *.dis *.elf

boot.lds

SECTIONS {
    . = 0x33f80000;/*设置当前运行地址为0x33f80000*/
    .text          :   { *(.text) }/*所有输入文件的代码段*/

    . = ALIGN(4);
    .rodata  : {*(.rodata)} /*ALIGN(4),表示运行地址4字节对齐。*/

    . = ALIGN(4);
    .data  : { *(.data) }

    . = ALIGN(4);
    __bss_start = .;
    .bss   : { *(.bss)  *(COMMON) }
    __bss_end = .;
}

启动LOG

Copy kernel from nand  
0x1234ABCD  
0xE1A00000  
Set boot params  
Boot kernel  
Uncompressing Linux...................................................................................................................... done,booting the kernel.  
Linux version 2.6.22.6 (book@book-desktop) (gcc version 3.4.5) #1 Fri Aug 23 15:33:35 CST 2013  
CPU: ARM920T [41129200] revision 0 (ARMv4T),cr=c0007177 Machine: SMDK2440 Memory policy: ECC disabled,Data cache writeback CPU S3C2440A (id 0x32440001) S3C244X: core 200.000 MHz,memory 100.000 MHz,peripheral 50.000 MHz S3C24XX Clocks,(c) 2004 Simtec Electronics **************************************************

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读