您的位置:首页 > 其它

基于s3c2440的简易bootloader实现

2013-02-12 22:33 417 查看
一、目的

编写一个能够加载并启动OS内核的bootloader。

二、思路

第一阶段:

(1)arm920t的异常向量表有两种存放方式,一种是低端存放(从0x00000000处开始存放),另一种是高端存放(从0xfff000000处开始存放)。选择低端存放,建立异常向量表。

(2)s3c2440的看门狗在上电启动时默认是开启的,所有要先把看门狗关了先。免得代码运行还没完成就强制复位。

(3)屏蔽掉所有中断。

(4)初始化时钟。

(5)初始化内存。

(6)清零bss段。

(7)设置好各个模式下的栈空间。

(8)重定位代码,使得代码的运行地址与链接地址相对应,之后就可以直接使用绝对地址。

(9)使用绝对跳转指令跳转到第二阶段,用c语言来实现。

第二阶段:

(1)初始化串口0,一方面方便我们的调试,一方面也为内核启动时打印信息做好初始化。

(2)初始化nand flash,需要把nand flash里的内核镜像拷贝到内存。

(3)把内核镜像拷贝到内存指定位置。

(4)设置好传递给内核的参数,并放置在约定的位置。

(5)跳转到内核起始地址处开始启动内核。

完毕。

三、流程图设计



四、代码树结构



(1)drivers里的src目录放置与外围设备相关配置的编程文件,inc目录放置相关头文件。对应的makefile放在drivers目录里。

①drivers/Makefile

#把src目录下的所有.c文件的字符串替换成.o字符串

TARGET := $(patsubst %.c,%.o,$(notdir $(wildcard ./src/*.c)) )

TARGET += $(patsubst %.S,%.o,$(notdir $(wildcard ./src/*.S)) )

all:$(TARGET)

echo "$(TARGET) 编译完成"

GPATH=$(PWD)

vpath %.c ./src

vpath %.S ./src

%.o:%.c

$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

%.o:%.S

$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

clean:

rm -f *.o

②drivers/inc

nand.h

#ifndef _NAND_H

#define _NAND_H

/**

*提取出页内列号,块内页号,块号

*/

#define dnand_addr2ColAddr(addr) (addr & 0x7FF)

#define dnand_addr2RowAddr(addr) (( addr & 0xFC00 ) >> 11)

#define dnand_addr2BlockAddr(addr) (addr >> 17)

//初始化NAND Flash , 时钟频率改变了这个一定要记得改

#define dnand_init() \

do{ \

NFCONT = 0x73;\

NFCONF = (3<<12) | (1<<8) | (1<<4);\

}while(0)

//复位

void fnand_reset(void);

//等待NAND Flash就绪

#define dnand_waitReady() while(!(NFSTAT & 0x1))

//发出片选信号

#define dnand_enable() (NFCONT &= ~(1<<1))

//取消片选信号

#define dnand_disable() (NFCONT |= (1<<1))

//发出命令

#define dnand_writeCmd(cmd) (NFCMMD = cmd)

//读数据

#define dnand_readData() (*(volatile unsigned char *)&NFDATA)

//写数据

#define dnand_writeData(data) *(volatile unsigned char *)&NFDATA = data

//写地址

#define dnand_writeAddr(addr) \

do{ NFADDR = addr & 0xff;\

NFADDR = (addr >> 8) & 0x0f; \

NFADDR = (addr >> 11) & 0xff;\

NFADDR = (addr >> 19) & 0xff;\

}while(0)

//擦除块

unsigned char fnand_eraseBlocks(unsigned int startBlockNum , unsigned int blockCount);

//从nand闪存里的sourAddr地址处读取size大小的数据到内存destAddr处。

void fnand_readOfSize(unsigned char *destAddr , unsigned int sourAddr , unsigned int size);

//。从内存sourAddr处读取size大小的数据到nand闪存里的destAddr地址处

unsigned char fnand_writeOfSize(unsigned char *sourAddr , unsigned int destAddr , unsigned int size);

#endif

uart0.h

#ifndef UART0_H

#define UART0_H

#define TXD0_READY (0x01<<1)

#define UBRDIV0_VAL (101250000UL/(115200*16)-1)

/**********初始化uart0中断的配置***********/

void uart0_init(void);

/*******把string消息通过uart0发送出去******/

void uart0_sent_msg(char *string);

void uart0_sent_byte(char byte);

/*打印hex数据*/

void uart0_sent_hex_word(unsigned int val);

#endif

③drivers/src

nand.c

#include "nand.h"

#include "s3c2440.h"

/**

* 复位

*/

void fnand_reset(void)

{

dnand_enable();

dnand_writeCmd(0xff); // 复位命令

dnand_waitReady();

dnand_disable();

}

/**

*块擦除函数

*/

unsigned char fnand_eraseBlocks(unsigned int startBlockNum , unsigned int blockCount)

{

unsigned int i;

dnand_enable();

for( i = 0 ; i < blockCount ; i++ ){

//发送擦除命令

dnand_writeCmd( 0x60 );

dnand_writeAddr( startBlockNum << 6 );

dnand_writeCmd(0xD0);

dnand_waitReady();

//读取状态

dnand_writeCmd( 0x70 );

if ( ( dnand_readData() & 0x01 ) ){

return 1;

}

startBlockNum += 1;

}

dnand_disable();

return 0;

}

void fnand_readOfSize(unsigned char *destAddr , unsigned int sourAddr , unsigned int size)

{

unsigned int j , col;

col = sourAddr & 0x7FF ; //该地址可能不是从页的0地址开始读 ,所以要先取出列地址

dnand_enable();

for( j = 0 ; j < size ; ){

//发出read命令

dnand_writeCmd( 0x00 );

dnand_writeAddr( sourAddr );

dnand_writeCmd( 0x30 );

dnand_waitReady( );

//开始读一页数据到destAddr里 ,

for( ; (col < 2048)&&(j<size) ; col++ ){

*destAddr++ = dnand_readData();

j++;

sourAddr++;

}

col = 0;

}

dnand_disable();

}

/**

*从内存的sourAddr处写入pageCount页数据到nand flash的destAddr地址处

*/

unsigned char fnand_writeOfSize(unsigned char *sourAddr , unsigned int destAddr , unsigned int size)

{

unsigned int col, j;

unsigned int startBlockNum , blockCount ,pageCount;

col = destAddr & 0x7FF ;

pageCount = size/2048 + ( (col)? 1 : 0 ) ;

startBlockNum = dnand_addr2BlockAddr( destAddr ) ;

blockCount = ( dnand_addr2RowAddr( destAddr ) + pageCount ) >> 6 ;

if ( ( dnand_addr2RowAddr( destAddr ) + pageCount ) & 0x3F ){

blockCount++;

}

if ( fnand_eraseBlocks( startBlockNum , blockCount ) ){

return 1;

}

dnand_enable();

for( j = 0 ; j < size ; ){

//发出read命令

dnand_writeCmd( 0x80 );

dnand_writeAddr( destAddr );

//开始写一页数据到destAddr里

for( ; (col < 2048)&&(j < size) ; col++ ){

dnand_writeData( *sourAddr++ );

destAddr++;

j++;

}

col = 0;

dnand_writeCmd( 0x10 );

dnand_waitReady();

//发送读取状态命令

dnand_writeCmd( 0x70 );

if ( ( dnand_readData() & 0x01 ) ){

return 1;

}

}

dnand_disable();

return 0;

}

uart0.c

#include "Uart0.h"

#include "s3c2440.h"

/*

****************************************

初始化uart0中断的配置

****************************************

*/

void uart0_init(void)

{

GPHCON |= 0xa0;

GPHUP |= 0x0f;

ULCON0 = 0x03; //普通模式,禁止奇偶校验,1个结束位,8-bit字长

UBRDIV0 = UBRDIV0_VAL; //波特率选择115200,所以UBRDIV0=54

UCON0 = 0x005; //时钟源=PCLK

//Rx,Tx水平触发,禁止接收超时中断,禁止接收错误状态中断,

//不使用回路模式,不发送break信号

//中断方式发送接收数据到缓冲寄存器

}

/*

*****************************************************

*uart0发送消息

***************************************************

*/

void uart0_sent_msg(char *string)

{

do {

while( !(UTRSTAT0&TXD0_READY) );

UTXH0 = *string++;

}while(*string != '\0');

}

void uart0_sent_byte(char byte)

{

while(!(UTRSTAT0&TXD0_READY));

UTXH0 = byte;

}

void uart0_sent_hex_word(unsigned int val)

{

char i ,j;

uart0_sent_msg("0x");

for ( i = 0 ; i < 8 ; i++) {

j = (char)((val >> ((7-i)*4) ) & 0x0f);

if( (j >= 0) && ( j <= 9)) {

uart0_sent_byte('0'+j);

}else{

uart0_sent_byte('A'+j-0xa);

}

}

uart0_sent_msg(" ");

}

(2)cpu里的src目录里放置与arm920t内核相关的编程文件,inc目录放置相关头文件。

cpu/Makefile

#把src目录下的所有.c文件的字符串替换成.o字符串

TARGET := $(patsubst %.c,%.o,$(notdir $(wildcard ./src/*.c)) )

TARGET += $(patsubst %.S,%.o,$(notdir $(wildcard ./src/*.S)) )

all:$(TARGET)

echo "$(TARGET) 编译完成"

GPATH=$(PWD)

vpath %.c ./src

vpath %.S ./src

%.o:%.c

$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

%.o:%.S

$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

clean:

rm -f *.o

cpu/src

ClkConflg.S

#把src目录下的所有.c文件的字符串替换成.o字符串

TARGET := $(patsubst %.c,%.o,$(notdir $(wildcard ./src/*.c)) )

TARGET += $(patsubst %.S,%.o,$(notdir $(wildcard ./src/*.S)) )

all:$(TARGET)

echo "$(TARGET) 编译完成"

GPATH=$(PWD)

vpath %.c ./src

vpath %.S ./src

%.o:%.c

$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

%.o:%.S

$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

clean:

rm -f *.o

MemCofig.S

@与内存相关

.equ BWSCON , 0x48000000

.equ BANKCON6 , 0x4800001C

.equ REFRESH , 0x48000024

.equ BANKSIZE , 0x48000028

.equ MRSRB6 , 0x4800002C

.global MemConfigure

MemConfigure:

/*******内存初始化子程序*********/

@BWSCON[27:24] = 0 0 10B

ldr r0 , =BWSCON

ldr r1 , [r0]

ldr r2 , =(0x0F<<24)

bic r1 , r1 , r2

ldr r2 , =(0x02<<24)

orr r1 , r1 , r2

str r1 , [r0]

@BANKCON6[16:15]=11B,BANKCON6[3:0]=00 01B

ldr r0 , =BANKCON6

ldr r1 , [r0]

ldr r2 , =(0x03<<15)

bic r1 , r1 , r2

orr r1 , r1 , r2

ldr r2 , =0x0F

bic r1 , r1 , r2

ldr r2 , = 0x01

orr r1 , r1 , r2

str r1 , [r0]

@这里的Trp要大于20ns , Trc要大于70ns,HCLK=101.25MHz

@故时钟周期=1s/HCLK=9.8ns,Trp*9.8>20ns ==> Trp>=3 ==> Trp域=01b

@Trp*9.8+Tsrc*9.8>70ns ==> Tsrc>=5 ==> Tsrc域=01b

@REFRESH[23:18] = 1 0 01 01B,REFRESH[10:0] = 0x4E8

ldr r0 , =REFRESH

ldr r1 , [r0]

ldr r2 , =(0x3F<<18)

bic r1 , r1 , r2

ldr r2 , =(0x25<<18)

orr r1 , r1 , r2

ldr r2 , =0x7FF

bic r1 , r1 , r2

ldr r2 , =0x4E9

orr r1 , r1 , r2

str r1 , [r0]

@BANKSIZE[7:0] = 1 0 1 1 0 001 B

ldr r0 , =BANKSIZE

ldr r1 , [r0]

ldr r2 , =0xFF

bic r1 , r1 , r2

ldr r2 , =0xB1

orr r1 , r1 , r2

str r1 , [r0]

@MRSRB6[11:0] = 0 00 011 0 000 B

ldr r0 , =MRSRB6

ldr r1 , [r0]

ldr r2 , =0x3FF

bic r1 , r1 , r2

ldr r2 , =0x030

orr r1 , r1 , r2

str r1 , [r0]

bx lr @函数返回

/******END内存初始化子程序*******/

(3)根目录下的src放置其它通用源文件,inc放置通用头文件。

./inc/common.h

#ifndef _COMMON_H

#define _COMMON_H

#define u32 unsigned long

#define u8 unsigned char

/*****************声明外部变量********************/

extern unsigned int _wsnboot_start;

extern unsigned int _bss_start;

extern unsigned int _bss_end;

/*****************只使用类型***********/

#define sizeof(type) ( (unsigned long)( (type *)0 + 1 ) )

/********************粗略延时函数*******************/

inline void delay_s(volatile unsigned long second);

inline void delay_ms(volatile unsigned long time_ms);

unsigned int strlen( char *string );

char *strcpy(char *destAddr ,char *srcAddr);

/*************填充指定内存区域*********/

unsigned char *memclr(unsigned char *a ,unsigned int c, unsigned int len);

#endif

./inc/bootparams.h

#ifndef _BOOTPARAMS_H

#define _BOOTPARAMS_H

//参考uboot的setup.h文件

#define CONFIG_NR_DRAM_BANKS 1

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

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

enum {

ATAG_CORE = 0x54410001,

ATAG_MEM = 0x54410002,

ATAG_CMDLINE = 0x54410009,

ATAG_INITRD2 = 0x54410005,

ATAG_VIDEOLFB = 0x54410008,

ATAG_SERIAL = 0x54410006,

ATAG_REVISION = 0x54410007,

ATAG_NONE = 0x00000000

};

typedef struct tag_header {

u32 size;

u32 tag;

}tag_header;

typedef struct tag_core {

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

u32 pagesize;

u32 rootdev;

}tag_core;

typedef struct tag_mem32 {

u32 size;

u32 start; /* physical start address */

}tag_mem32;

typedef struct tag_cmdline {

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

}tag_cmdline;

typedef struct tag {

tag_header hdr;

union {

tag_core core;

tag_mem32 mem;

tag_cmdline cmdline;

}u;

}tag ;

tag *setup_start_tag (tag *params);

tag *setup_memory_tags (tag *params);

tag *setup_commandline_tag (tag *params, char *commandline);

void setup_end_tag (tag *params);

tag *setParamsAddr( unsigned int paramsAddr , char *commandline );

#endif

./src/start.S

@与看门狗相关

.equ WTCON , 0x53000000

@与中断相关

.equ INTMSK , 0x4A000008

@与LED有关的

.equ GPBCON , 0x56000010

.equ GPBDAT , 0x56000014

.global _start

.global _wsnboot_start

.global _bss_start

.global _bss_end

.text

_start:

/***********设置中断向量表*************/

b ResetInit @复位异常入口

HandlerUndef:

ldr pc , =HandlerUndef @未定义异常入口

HandlerSWI:

ldr pc , =HandlerSWI @软中断异常入口

HandlerPabort:

ldr pc , =HandlerPabort @取指中止异常入口

HandlerDabort:

ldr pc , =HandlerDabort @数据中止异常入口

HandlerNotUsed:

ldr pc , =HandlerNotUsed @保留

ldr pc , =HandlerIRQ @中断异常入口

HandlerFIQ:

ldr pc , =HandlerFIQ @快中断异常入口

_wsnboot_start: .word _start

_bss_start: .word __bss_start

_bss_end: .word __bss_end

ResetInit:

/**************关闭看门狗**************/

ldr r0 , =WTCON

mov r1 , #0x0

str r1 , [r0]

/***************屏蔽中断***************/

ldr r0 , =INTMSK

ldr r1 , =0xffffffff

str r1 , [r0]

/*************初始化LED管脚************/

LedConf:

bl LedConfigure

/***************初始化时钟*************/

ClkConf:

bl ClkConfigure

/***************初始化内存*************/

MemConf:

bl MemConfigure

/***************清零bss段**************/

Clear_Bss:

bl clear_bss

/***************设置栈顶指针***********/

SetSp:

ldr sp , =0x34000000

/***重定位,设置传递给第二阶段的参数***/

CopyToSdram:

bl copy_bootloader_to_sdram @重定位之后,此时的运行地址跟链接地址还不一致。

/*************跳转到第二阶段***********/

jump:

ldr pc , =start_armboot @重定位之后,尽快让pc跳转到链接地址去执行,之后运行地址跟链接地址一致。

/**************************************/

loop: b loop

/*******************END************************/

/***********LED管脚初始化,利于调试***********/

LedConfigure:

@把LED1_2_3_4管脚置为输出

ldr r0 , =GPBCON

ldr r1 , [r0]

ldr r2 , =(0xFF<<10)

bic r1 , r1 ,r2

ldr r2 , =(0x55<<10)

orr r1 , r1 , r2

str r1 , [r0]

@灯全灭

ldr r0 , =GPBDAT

ldr r1 , [r0]

mov r2 , #(0x0F<<5)

orr r1 , r1 , r2

str r1 , [r0]

bx lr

/*****************清零bss段*******************/

clear_bss:

ldr r0 , =__bss_start

ldr r1 , =__bss_end

mov r2 , #0x0

clear: str r2 , [r0] , #4

cmp r0 , r1

ble clear @这里选择小于或等于就跳转,可以处理bss没有占用内存的情况

bx lr

/***************拷贝bootloader到sdram**********/

copy_bootloader_to_sdram:

mov r2 , #0x0 @r2保存了代码段的加载起始地址

ldr r0 , =_start @r0保存了代码的链接起始地址

ldr r1 , =__bss_start

sub r1 , r1 , r0 @r1保存代码段的大小

cmp r1 , #4096

ble copy_all @如果小于或等于4K就跳到copy执行,一次性拷完整个代码

copy_sram:

ldr r3 , [r2] , #4

str r3 , [r0] , #4

cmp r2 , #4096

bne copy_sram

mov r2 , #0x00 @r2:指明是否拷贝了所有代码(’0‘表示没拷完)

sub r1 , r1 , #4096 @r1:剩余要拷贝的代码大小

mov r0 , #4096 @r0:剩余代码的起始地址

bx lr

copy_all:

ldr r3 , [r2] , #4

str r3 , [r0] , #4

cmp r2 , r1

bne copy_all

mov r2 , #0x01 @r3=1表示代码已经拷完

bx lr

/**********LED调试*******************/

@灯全亮

ldr r0 , =GPBDAT

ldr r1 , [r0]

mov r2 , #(0x0F<<5)

bic r1 , r1 , r2

str r1 , [r0]

/************************************/

./src/boot.c

#include "uart0.h"

#include "nand.h"

#include "s3c2440.h"

#include "common.h"

#include "bootparams.h"

void start_armboot(unsigned int left_code_addr , unsigned int left_code_size , unsigned char is_left_code)

{

unsigned int destAddr;

tag *params;

volatile unsigned int *p;

/***************************声明一个函数指针,该函数指针为内核的启动函数的地址***********************/

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

/***********************初始化串口0,用于bootloader调试用,也用于内核启动时信息打印******************/

uart0_init();

uart0_sent_msg("bootloader first stage is finish!!!\n\r");

uart0_sent_msg(" ............\n\r");

uart0_sent_msg("bootloader second stage is begin!!!\n\r");

/******************************************nand flash 的初始化****************************************/

dnand_init();

fnand_reset();

/**********************由第一阶段传递过来的参数判段是否还剩有代码需要被拷贝***************************/

if( 1 == is_left_code ) {

uart0_sent_msg("all the code is copy completed!!!!\n\r");

}else {

uart0_sent_msg("coping the left code!!!\n\r");

destAddr = _wsnboot_start + 4096 ; /******计算拷贝期间的中断地址*********/

fnand_readOfSize( (unsigned char *)destAddr , left_code_addr , left_code_size );

uart0_sent_msg("all the code is copy completed!!!!\n\r");

}

/*****************************************设置传递给内核的参数*****************************************/

uart0_sent_msg("setting the boot params......!!!!\n\r");

params = setParamsAddr( (unsigned int )0x30000100, "noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0" ) ;

if( (0x30000100 == (unsigned long)params) ) {

uart0_sent_msg("boot params setting completed......!!!!\n\r");

}

/**************************************把内核从nand flash拷贝到sdram***********************************/

uart0_sent_msg("beging copying the kenel......!!!!\n\r");

fnand_readOfSize( (unsigned char *)0x30008000 , 0x60000 , 0x200000 );

p = (volatile unsigned int *)(0x30008000+80);

uart0_sent_hex_word(*p);

uart0_sent_msg("copying the kenel is completing....!!!!\n\r");

/**************************************跳转到内核起始地址执行内核**************************************/

uart0_sent_msg("boot the operating system , congratulations for you...!!!\n\r");

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

JumpToKenel( 0 , 362 , (unsigned int )params );

uart0_sent_msg("boot the operating system fail...!!!\n\r");

while(1);

}

./src/common.c

#include "common.h"

inline void delay_s(volatile unsigned long second)

{

volatile unsigned long i;

while(second--){

i=1000000;

while(--i);

}

}

inline void delay_ms(volatile unsigned long time_ms)

{

volatile unsigned long i;

while(time_ms--){

i=1000;

while(--i);

}

}

/*************填充指定内存区域*********/

unsigned char *memclr(unsigned char *a ,unsigned int c, unsigned int len)

{

unsigned char *b = a;

do{

*a++ = c;

}while (--len);

return b;

}

unsigned int strlen( char *string )

{

unsigned int i=0;

while(*string != '\0'){

++string;

++i;

}

return i;

}

char *strcpy(char *destAddr ,char *srcAddr)

{

char *dest = destAddr;

while( (*destAddr++ = *srcAddr++ ) != '\0');

/*************最后加上字串结束标志符***********/

*dest = '\0';

return dest;

}

./src/common.c

#include "common.h"

inline void delay_s(volatile unsigned long second)

{

volatile unsigned long i;

while(second--){

i=1000000;

while(--i);

}

}

inline void delay_ms(volatile unsigned long time_ms)

{

volatile unsigned long i;

while(time_ms--){

i=1000;

while(--i);

}

}

/*************填充指定内存区域*********/

unsigned char *memclr(unsigned char *a ,unsigned int c, unsigned int len)

{

unsigned char *b = a;

do{

*a++ = c;

}while (--len);

return b;

}

unsigned int strlen( char *string )

{

unsigned int i=0;

while(*string != '\0'){

++string;

++i;

}

return i;

}

char *strcpy(char *destAddr ,char *srcAddr)

{

char *dest = destAddr;

while( (*destAddr++ = *srcAddr++ ) != '\0');

/*************最后加上字串结束标志符***********/

*dest = '\0';

return dest;

}

./src/pootparams.c

#include "common.h"

#include "bootparams.h"

#include "uart0.h"

tag *setup_start_tag (tag *params)

{

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 *)tag_next(params);

return params;

}

tag *setup_memory_tags (tag *params)

{

int i;

for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {

params->hdr.tag = ATAG_MEM;

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

params->u.mem.start = 0x30000000;

params->u.mem.size = 0x4000000;

params = (tag *)tag_next (params);

}

return params;

}

tag *setup_commandline_tag (tag *params, char *commandline)

{

params->hdr.tag = ATAG_CMDLINE;

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

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

uart0_sent_msg("boot params = ");

uart0_sent_msg(params->u.cmdline.cmdline);

uart0_sent_msg("\n\r");

params = (tag *)tag_next (params);

return params;

}

void setup_end_tag (tag *params)

{

params->hdr.tag = ATAG_NONE;

params->hdr.size = 0;

}

tag *setParamsAddr( unsigned int paramsAddr , char *commandline )

{

tag *params = (tag *)memclr( (unsigned char *)paramsAddr , 0 , (unsigned int)sizeof(tag) );

params = setup_start_tag (params);

params = setup_memory_tags (params);

params = setup_commandline_tag(params , commandline);

setup_end_tag (params);

return (tag *)paramsAddr;

}

(4)一级makefile跟链接脚本都放在根目录下。

./Makefile

ifndef CROSS_COMPILE

CROSS_COMPILE = arm-linux-

endif

export CROSS_COMPILE

ifndef XECHO

XECHO = echo

endif

export XECHO

ifndef LKSCRIPT

LKSCRIPT = wsnboot.lds

endif

ifndef OUTPUTNAME

OUTPUTNAME = wsnboot

endif

TOPTREE = $(PWD)

SRCDIRS := $(TOPTREE)/src $(TOPTREE)/cpu/src $(TOPTREE)/drivers/src

OBJDIRS := $(TOPTREE) $(TOPTREE)/cpu $(TOPTREE)/drivers

INCDIRS := $(TOPTREE)/inc $(TOPTREE)/cpu/inc $(TOPTREE)/drivers/inc

INCLUDES:= $(addprefix -I,${INCDIRS})

SUBDIRS := $(TOPTREE)/cpu $(TOPTREE)/drivers

OUTPUTDIR= $(TOPTREE)/output

export TOPTREE SRCDIRS OBJDIRS INCDIRS INCLUDES

#函数foreach把OBJDIRS中的单词逐个放在OBJTREE临时变量里,然后执行第三个参数(表达式),

#一直到OBJDIRS中的单词被取完,把表达式多次返回的结果都返回。

OBJS := $(patsubst %.c, %.o, $(foreach OBJTREE,${SRCDIRS},$(notdir $(wildcard ${OBJTREE}/*.c))))

OBJS += $(patsubst %.S, %.o, $(foreach OBJTREE,${SRCDIRS},$(notdir $(wildcard ${OBJTREE}/*.S))))

GPATH=$(PWD)

vpath %.o $(OBJDIRS)

vpath %.c $(SRCDIRS)

vpath %.S $(SRCDIRS)

AR = $(CROSS_COMPILE)ar

AS = $(CROSS_COMPILE)as

CC = $(CROSS_COMPILE)gcc

LD = $(CROSS_COMPILE)ld

OBJDUMP = $(CROSS_COMPILE)objdump

OBJCOPY = $(CROSS_COMPILE)objcopy

export AR AS CC LD OBJDUMP OBJCOPY

MAKE = make

CFLAGS := -Wall -O2

CPPFLAGS :=-nostdinc -nostdlib -fno-builtin

export MAKE CFLAGS CPPFLAGS

subdirs:

@for dir in $(SUBDIRS) ; do\

$(MAKE) -C $$dir ;\

done

$(MAKE) $(OUTPUTNAME).bin

$(OUTPUTNAME).bin:$(OBJS)

@$(XECHO) "链接开始"

$(LD) -T$(LKSCRIPT) -o $(OUTPUTDIR)/$(OUTPUTNAME).elf $^

$(OBJCOPY) -O binary -S $(OUTPUTDIR)/$(OUTPUTNAME).elf $(OUTPUTDIR)/$@

$(OBJDUMP) -D -m arm $(OUTPUTDIR)/$(OUTPUTNAME).elf \

> $(OUTPUTDIR)/$(OUTPUTNAME).dis

@$(XECHO) "链接已完成!!!!目标生成在output目录下....."

%.o:%.c

$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

%.o:%.S

$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

clean:

@for dir in $(SUBDIRS) ; do\

$(MAKE) clean -C $$dir ;\

done

rm -f *.o *.bin *.bak *.elf *.dis $(OUTPUTDIR)/*

./wsnboot.lds

/*指定输出机器架构为arm*/

OUTPUT_ARCH(arm)

/*设置入口点*/

ENTRY(_start)

SECTIONS

{

. = 0x33f80000;

. = ALIGN(4);

_start = . ;

.text :

{

start.o(.text)

./cpu/*.o(.text)

*(.text)

}

. = ALIGN(4);

.rodata : {*(.rodata)}

. = ALIGN(4);

.data : {*(.data)}

. = ALIGN(4);

__bss_start = . ;

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

__bss_end = . ;

}

(5)最终的bin输出文件被输出到output里。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: