基于s3c2440的简易bootloader实现

长平狐 发布于 2013/06/17 13:13
阅读 281
收藏 0

先MARK下,方便以后学习

一、目的

        编写一个能够加载并启动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里。

转载自:http://blog.csdn.net/shengnan_wu/article/details/8579503


原文链接:http://blog.csdn.net/mybelief321/article/details/9104527
加载中
返回顶部
顶部