免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1957 | 回复: 0
打印 上一主题 下一主题

Linux移植参考手册--2.uboot-1.1.6移植 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-12-23 01:27 |只看该作者 |倒序浏览
第二章 uboot-1.1.6移植 2.1 编译环境准备

从网上http://sourceforge.net/projects/u-boot/下载U-boot-1.1.6,解压后可以看到它的全部源代码,我们需要针对自己使用的CPU和开发板进行特定修改。

设置你的PATH环境变量,使其可以找到你的交叉编译工具链

        mkdir /home/arm2410

        useradd -G root -g root -d/home/arm2410 arm

        su arm

        cd /home/arm2410

        vi    ~/.bashrc

        export PATH = /usr/local/arm/3.3.2/bin:$PATH

        source ~/.bashrc

解压uboot源代码

        mkdir  /home/arm2410/uboot

        cd     /home/arm2410/uboot

tar   xvjf   u-boot-1.1.6.tar.bz2

  cd    u-boot-1.1.6

2.2 修改顶层Makefile

U-Boot是通过gccMakefile组织编译的。顶层目录下的Makefile可以设置开发板的定义,然后递归地调用各级子目录下的Makefile,最后把编译过的代码连接成u-boot映像。

在顶层Makefile中先要定义交叉编译器,这里就使用我们上一次实验中构建的交叉编译器。查找ifeq ($(ARCH),arm),修改确认CROSS_COMPILE的值

ifeq ($(ARCH),arm)

CROSS_COMPILE = arm-linux-

然后在顶层Makefile中,你只要找到smdk2410_config这一行:

smdk2410_config : unconfig

@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0

然后参考上面一行增加arm2410_config,如下:

arm2410_config : unconfig

@$(MKCONFIG) $(@:_config=) arm  arm920t  arm2410  NULL  s3c24x0

解释一下这行配置中各项的意思

Ø arm: CPU 的架构(ARCH) 

Ø arm920t: CPU 的类型(CPU),其对应于 cpu/arm920t 子目录。  

Ø arm2410: 开发板的类型,对应于 board/arm2410 目录。  

Ø NULL: 开发者/或经销商(vender)。 

Ø s3c24x0: 片上系统(SOC)

2.3 arm2410平台新建一个目录

我们参考smdk2410开发板的配置,在smdk2410平台的基础上进行移植的。不过为了不破换U-Boot本身的代码,我们在board目录下将smdk2410文件夹复制为arm2410,并将该目录下的smdk2410.c重命名为arm2410.c

cd  board

cp  -r  smdk2410  arm2410

cd  arm2410

mv  smdk2410.c  arm2410.c

2.4 board/arm2410目录下增加nand.c文件

board/arm2410目录下增加nand.c文件,文件内容如下:

#include <common.h>

#include <s3c2410.h>

#include <config.h>

#define TACLS 0

#define TWRPH0 3

#define TWRPH1 0

#define U32 unsigned int

extern unsigned long nand_probe(unsigned long physadr);

static void NF_Reset(void)

{

int i;

NF_nFCE_L();  

NF_CMD(0xFF); 

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

NF_WAITRB(); 

NF_nFCE_H();  

}

void NF_Init(void)

{

rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)\

|(TWRPH1<<0);

   NF_Reset();

}

int nand_read_whole(unsigned char *buf, unsigned long start_addr, int size)

{

int i, j;

if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {

    return 1;

     }

NF_nFCE_L();

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

   i = start_addr;

while(i < start_addr + size) {

rNFCMD = 0;

rNFADDR = i & 0xff;

rNFADDR = (i >> 9) & 0xff;

rNFADDR = (i >> 17) & 0xff;

rNFADDR = (i >> 25) & 0xff;

NF_WAITRB();

    for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {

      *buf = (rNFDATA & 0xff);

       buf++;

    }

   }

   NF_nFCE_H();

   return 0;

}

void nand_init(void)

{

NF_Init(); /* nand_reset();*/

printf ("%4lu MB\n", nand_probe((unsigned long)CFG_NAND_BASE) >> 20);

}

2.5 修改board/arm2410目录下的Makefile

修改:

COBJS := smdk2410.o flash.o

为下面一行:

COBJS := arm2410.o  nand.o  flash.o 

这是因为前面将smdk2410.c改成arm2410.c,而且新增加了个nand.c文件,所以要在Makefile中告诉编译器将arm2410.cnand.c文件分别编译链接成nand.oarm2410.o这两个目标文件。

2.6 arm2410平台配置头文件arm2410.h

每块开发板都有一个头文件,位于include/configs目录下,它是为开发板定义配置选项和参数的,如smdk2410开发板对应的头文件是smdk2410.h

这个头文件中主要定义了两类变量,一类是选项,前缀是CONFIG_,用来选择处理器,命令,参数等。如:

#define CONFIG_S3C2410  1

一类是参数,前缀是CFG_,用来定义总线参数,串口波特率,flash地址等。如:

#define CFG_LOAD_ADDR 0x30008000

接下来,我们将参考smdk2410.h,进行适当的修改,为arm2410来设定相关的选项和配置。首先进入include/configs目录,复制smdk2410.harm2410.h

include/configs/arm2410.h需要做的修改有以下几处:

Ø 第一处:在“#define CONFIG_SMDK2410   1”这一行下面添加以下几行:

#define CONFIG_SMDK2410   1

#define CONFIG_S3C2410_NAND_BOOT   1   

#define STACK_BASE   0x33f00000 //0x33f0000--0x33f80000堆栈

#define STACK_SIZE   0x8000 //堆栈大小

#define UBOOT_RAM_BASE    0x33f80000  //0x33f80000--0x34000000 Uboot

其中第一行是配置目标板从NandFlash启动,第二行和第三行配置堆栈的基地址和堆栈空间的大小,第四行配置U-BootRAM中的基地址。大家要注意,千成不能把添加的语句加到上面一行的注释中了,不然编译时候会报错。

Ø 第二处:增加配置命令 CFG_CMD_NAND

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

 * Command definition

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

#define CONFIG_COMMANDS \

(CONFIG_CMD_DFL  | \

CFG_CMD_CACHE  | \

CFG_CMD_NAND  | \ //取消注释,加入nand相关命令

            CFG_CMD_NET      | \ //主要是添加ping命令需求

            CFG_CMD_PING      | \ //添加ping命令,只能从ARMPC

/*CFG_CMD_EEPROM |*/ \

/*CFG_CMD_I2C  |*/ \

/*CFG_CMD_USB  |*/ \

CFG_CMD_REGINFO  | \

CFG_CMD_DATE  | \

CFG_CMD_ELF)

/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */

该配置用来增加操作NandFlash的相关命令,如读写(nand readnand write),擦除(nand erase)等操作命令,添加ping命令,配置好PC机和ARM板,只能从ARM pingPC

Ø 第三处:配置u-boot环境变量,这些环境变量也可以在u-boot烧写到Flash以后再配置,在这里,不介绍这些环境变量的具体含义,参见本文有关U-Boot环境变量。

#include <cmd_confdefs.h>

#define CONFIG_BOOTDELAY 5

#define CONFIG_BOOTARGS "root=ramfs devfs=mount console=ttySA0,115200" 

#define CONFIG_ETHADDR 08:00:3e:26:0a:5b 

#define CONFIG_NETMASK 255.255.255.0

#define CONFIG_IPADDR 192.168.0.68

#define CONFIG_SERVERIP 192.168.0.67

#define CONFIG_BOOTFILE "zImage.img

#define CONFIG_BOOTCOMMAND "tftp; bootm" 

#if (CONFIG_COMMANDS & CFG_CMD_KGDB)

Ø 第四处:配置命令提示符(command prompt),这个属于个性化配置范畴了,你可以根据自己的喜好配,也可以用默认的。

#define CFG_LONGHELP /* undef to save memory */

#define CFG_PROMPT "ARM2410 # "  /* 把这儿设置成自己的拼音缩写 */

#define CFG_CBSIZE 256 /* Console I/O Buffer Size */

Ø 第五处:配置装载地址为0x30008000

#undef  CFG_CLKS_IN_HZ /* everything, incl board info, in Hz */

#define CFG_LOAD_ADDR 0x30008000 /* default load address */

#define CFG_TFTP_LOADADDR 0x30008000

这两个装载地址是U-Boot通过Flash启动或者TFTP引导内核时的默认装载地址,这样说读者或许还不太明白,先暂且放着不管,后面用到这个参数的时候笔者还会介绍,那时就容易理解了。

Ø 第六处:在文件末尾处,#endif之前进行如下修改

注释掉下面两行:

/*#define CFG_ENV_IS_IN_FLASH 1

#define CFG_ENV_SIZE 0x10000  *//* Total Size of Environment Sector */

增加如下代码:

#define CFG_ENV_IS_IN_NAND  1

#define CFG_ENV_SIZE  0x4000 /* Total Size of Environment Sector */

#define CFG_ENV_OFFSET (0x04000000-0x8000) 

  //1.环境变量会saveenvnand接近最顶处

  //(0x04000000-0x8000)

    //2.打算在第三块放置yaffs文件系统

  //nand分配,256KB2M-256K30M32M

  //所以把环境变量放在(0x00040000-0x8000) 

   //uboot256KB只用来109KB左右

     //3.或者重新分配nand1M3M30M30M

    //环境变量放在(1M-0x8000)=(0x00100000-0x8000)

    //利用uboot指令bdinfo可以查看到

/*********define mach_type ***********/

#define CONFIG_ARCH_SMDK2410 1

/* define nand command support */

#if (CONFIG_COMMANDS & CFG_CMD_NAND)

#define CFG_NAND_LEGACY 1

#define CFG_NAND_BASE 0x4E000000  //nand flash控制器基址

#define CFG_MAX_NAND_DEVICE //一个nand设备

#define SECTORSIZE   512 

#define NAND_SECTOR_SIZE SECTORSIZE

#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)

#define ADDR_COLUMN

#define ADDR_PAGE

#define ADDR_COLUMN_PAGE

#define NAND_ChipID_UNKNOWN 0x00 

#define NAND_MAX_FLOORS 1

#define NAND_MAX_CHIPS 1

#define WRITE_NAND_COMMAND(d, adr)  do {rNFCMD = d;} while(0)

#define WRITE_NAND_ADDRESS(d, adr) do {rNFADDR = d;} while(0)

#define WRITE_NAND(d, adr)  do {rNFDATA = d;} while(0)

#define READ_NAND(adr)  (rNFDATA)

#define NAND_WAIT_READY(nand)  {while(!(rNFSTAT&(1<<0)));}

#define NAND_DISABLE_CE(nand)  {rNFCONF |= (1<<11);}

#define NAND_ENABLE_CE(nand) {rNFCONF &= ~(1<<11);}

#define NAND_CTL_CLRALE(nandptr)

#define NAND_CTL_SETALE(nandptr)

#define NAND_CTL_CLRCLE(nandptr)

#define NAND_CTL_SETCLE(nandptr)

#define CONFIG_MTD_NAND_VERIFY_WRITE 1

#endif /* CONFIG_COMMANDS & CFG_CMD_NAND*/

#ifdef CONFIG_S3C2410_NAND_BOOT

#define rNFCONF (*(volatile unsigned int *)0x4e000000) //nand flash控制器基址0x4e000000

#define rNFCMD (*(volatile unsigned char *)0x4e000004)

#define rNFADDR (*(volatile unsigned char *)0x4e000008)

#define rNFDATA (*(volatile unsigned char *)0x4e00000c)

#define rNFSTAT (*(volatile unsigned int *)0x4e000010)

#define rNFECC (*(volatile unsigned int *)0x4e000014)

#define rNFECC0 (*(volatile unsigned char *)0x4e000014)

#define rNFECC1 (*(volatile unsigned char *)0x4e000015)

#define rNFECC2 (*(volatile unsigned char *)0x4e000016)

#define NF_CMD(cmd)  {rNFCMD=cmd;}

#define NF_ADDR(addr)  {rNFADDR=addr;}

#define NF_nFCE_L()  {rNFCONF&=~(1<<11);}

#define NF_nFCE_H()  {rNFCONF|=(1<<11);}

#define NF_RSTECC() {rNFCONF|=(1<<12);}

#define NF_RDDATA()  (rNFDATA)

#define NF_WRDATA(data) {rNFDATA=data;}

#define NF_WAITRB()  {while(!(rNFSTAT&(1<<0)));}

#endif /* CONFIG_S3C2410_NAND_BOOT */

/********CONFIG FOR COMMANDLINE***********/

//加入ubootlinux内核传递的参数,如命令行commandline

#ifndef CONFIG_SETUP_MEMORY_TAGS

#define CONFIG_SETUP_MEMORY_TAGS 1

#endif

#ifndef CONFIG_CMDLINE_TAG

#define CONFIG_CMDLINE_TAG 1

#endif

#ifndef CONFIG_INITRD_TAG

#define CONFIG_INITRD_TAG 1

#endif

//其余的暂时还用不到,如果加进去将会编译出错

//#ifndef CONFIG_SERIAL_TAG

//#define CONFIG_SERIAL_TAG 1

//#endif

//#ifndef CONFIG_REVISION_TAG

//#define CONFIG_REVISION_TAG 1

//#endif

//#ifndef CONFIG_VFG

//#define CONFIG_VFD 1

//#endif

//#ifndef CONFIG_LCD

//#define CONFIG_LCD 1

//#endif

/***********CONFIG FOR COMMAND LINE************/

2.7修改使显示uboot commandline和所在的参数地址

修改lib_arm/armlinux.c,使显示uboot commandline 和所在的参数地址

245行左右,找到CONFGI_CMDLINE_TAG,在setup_commandline_tag(bd,commandline)下面加入如下语句:

printf("uboot params adderss: 0x%x\n", gd->bd->bi_boot_params);

  //显示传递的参数起始地址,默认0x30000100

  //保存在gd全局变量的目标板信息变量bd

printf("uboot command line: %s\n", commandline);  //显示ubootcommandline

上面这些配置选项都是与NandFlash有关的,有兴趣了解的可以直接查阅U-BootREADME文件。涉及到的nand.cstart.Senv_nand.c文件的修改大部分是与NandFlash相关,这些文件的修改只是针对“FS2410”的,鉴于各个开发板上NandFlash的特殊性,这些修改不一定适合其他的开发板。

2.8 修改cpu/arm920t目录下的start.S文件

Ø 第一处(165行左右):在“#ifndef CONFIG_SKIP_RELOCATE_UBOOT”这一行

后面增加:

#ifdef CONFIG_S3C2410_NAND_BOOT

/* relocate uboot from NAND Flash instead of NOR Flash */

bl  copy_myself

#else

187行左右ble  copy_loop后面增加:

#endif  /* CONFIG_S3C2410_NAND_BOOT */

Ø 第二处(230行左右):在_start_armboot: .word start_armboot这一行下面增加如下内容:

#ifdef CONFIG_S3C2410_NAND_BOOT

copy_myself:

mov  r10, lr

ldr  sp, DW_STACK_START 

mov  fp, #0 

bl  NF_Init 

@read UBOOT from Nand Flash to RAM

ldr  r0, =UBOOT_RAM_BASE 

mov  r1, #0x0

mov  r2, #0x20000

bl  nand_read_whole

tst  r0, #0x0

beq  ok_nand_read

1:    b   1b

ok_nand_read:

mov  r0, #0x00000000 

ldr  r1, =UBOOT_RAM_BASE

mov  r2, #0x400

go_next:

ldr  r3, [r0], #4

ldr  r4, [r1], #4

teq  r3, r4

bne  notmatch

subs  r2, r2, #4

beq  done_nand_read

bne  go_next

notmatch:

1:    b   1b

done_nand_read:

mov  pc, r10

#endif /* CONFIG_S3C2410_NAND_BOOT */

Ø 第三处:在文件末尾增加下面几行内容:

#ifdef CONFIG_S3C2410_NAND_BOOT

        .align    2

DW_STACK_START:

         .word    STACK_BASE + STACK_SIZE - 4

#endif

2.9 修改common目录下的env_nand.c文件

Ø 第一处: 将“#include <nand.h>”这一行去掉,然后添加下面的内容

#if (CONFIG_COMMANDS & CFG_CMD_NAND)

#ifdef CFG_NAND_LEGACY

#include <linux/mtd/nand_legacy.h>

extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];

extern int curr_device;

extern int nand_legacy_erase(struct nand_chip *nand, size_t ofs,

size_t len, int clean);

extern int nand_legacy_rw(struct nand_chip *nand, int cmd, size_t start,

size_t len, size_t *retlen, u_char *buf);

extern void nand_print(struct nand_chip *nand);

extern void nand_print_bad(struct nand_chip *nand);

extern int nand_read_oob(struct nand_chip *nand, size_t ofs,

size_t len, size_t *retlen, u_char *buf);

extern int nand_write_oob(struct nand_chip *nand, size_t ofs,

size_t len, size_t *retlen, const u_char *buf);

struct nand_chip* nand = &nand_dev_desc[0];

#else /* !CFG_NAND_LEGACY */

#include <linux/mtd/nand.h>

#include <nand.h>

#endif /* !CFG_NAND_LEGACY */

#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */

Ø 第二处:找到下面几行内容,注释掉。

int nand_legacy_rw (struct nand_chip* nand, int cmd,

     size_t start, size_t len,

     size_t * retlen, u_char * buf);

/* info for NAND chips, defined in drivers/nand/nand.c */

extern nand_info_t nand_info[];

Ø 第三处:该文件中有两个int saveenv(void)函数,我们修改第二个,即"#else /* ! CFG_ENV_OFFSET_REDUND */"这一行后面的int saveenv(void)函数,将该函数体中的内容更改如下:

int saveenv(void)

{

int ret = 0;

#ifndef CFG_NAND_LEGACY

ulong total;

puts ("Erasing Nand...");

if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))

return 1;

puts ("Writing to Nand... ");

total = CFG_ENV_SIZE;

ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);

#else

ulong off = CFG_ENV_OFFSET;

ulong size = CFG_ENV_SIZE;

puts ("Erasing Nand Environment...");

ret = nand_legacy_erase (nand,off, size, 1);

printf("%s\n", ret ? "ERROR\n" : "OK\n");

if (ret!=0) return ret;

puts ("Writing new Environment Variables to Nand...");

int total;

ret = nand_legacy_rw (nand, 0x0, off, size,(size_t *)&total,(u_char*)env_ptr);

#endif /* CFG_NAND_LEGACY */

if (ret || total != CFG_ENV_SIZE){

puts("undone!!!\n");

return 1;

}

puts ("done\n");

return ret;

}

Ø 第四处:该文件中有两个void env_relocate_spec (void)函数,我们也是修改第二个,即"#else /* ! CFG_ENV_OFFSET_REDUND */ */"这一行后面的void env_relocate_spec (void),将该函数体中的内容更改如下:

void env_relocate_spec (void)

{

#if !defined(ENV_IS_EMBEDDED)

#ifndef CFG_NAND_LEGACY

ulong total;

int ret;

total = CFG_ENV_SIZE;

ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);

if (ret || total != CFG_ENV_SIZE)

return use_default();

if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)

return use_default();

#else

ulong total;

int ret;

ret = nand_legacy_rw(nand, 1, CFG_ENV_OFFSET, CFG_ENV_SIZE, 

(size_t *)&total, (u_char*)env_ptr);

if (ret || total != CFG_ENV_SIZE)

return use_default();

if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)

return use_default();

#endif /* CFG_NAND_LEGACY*/

#endif /* ! ENV_IS_EMBEDDED */

}

千万要注意,不要把后面的函数删除了,很多同学都不小心把后面一个函数删除了,造成编译时候出错。

2.10 修改common目录下的cmd_boot.c文件

Ø 第一处:找到头文件下面的几行,注释掉“#if defined(CONFIG_I386)”和“#endif”:

//#if defined(CONFIG_I386)

 DECLARE_GLOBAL_DATA_PTR;

//#endif

Ø 第二处:在60行左右的“#if !defined(CONFIG_NIOS)”这一行下面添加如下几行:

if(argc==2)

rc = ((ulong (*)(int, char *[]))addr) (0, gd->bd->bi_arch_number);

else

2.11 交叉编译u-boot-1.1.6

上述文件修改完毕以后,进入u-boot顶层目录执行一下命令,编译。

make    clobber

make   arm2410_config

make

编译生成u-boot目标文件执行make命令,开始对U-Boot进行编译,编译完成之后,顶层目录下面增加了u-boot各种格式的映像文件和符号表。如下表所示:

文件

说明

u-boot.map

 U-Boot符号对映

u-boot  

 U-Boot可执行文件,采用 ELF 二进制格式

u-boot.bin   

 U-Boot 原始二进制映像,可以被写入引导储存设备

u-boot.srec 

 U-Boot 映像S-Recoad格式

2.12 烧写u-boot开发板nand

如果开发板本身无法启动u-boot环境,我们就必须使用jtag线或者仿真器对u-boot进行烧写,如果已经可以启动到u-boot的环境下,我们可以通过tftp对它进行烧写,下面我们分别对它进行介绍。

2.12.1 使用sjf2410.exewindows下烧写

ARM板上没有uboot,使用sjf2410.exewindows下烧写Nand Flash

1)先用20 针排线将FS2410 20 JTAG 接口与DragonJTAG 20 针接口相连。 然后将光盘里的“Flash 烧写”文件夹拷贝到盘(硬盘的其他地方也行)。

注意:要确保 DragonJTAG 处于了SJF 状态。

2)安装 giveio 驱动,进入“Flash 烧写”文件夹下,点击“安装驱动.exe”,将弹出

如下界面:

先点击“InStall Parallel Port Driver”栏目下的“Remove”按纽,然后点击该栏目下的“Install”按纽。

出现“Service is installed and run”说明giveio 驱动安装成功。

3)修改SJF2410_BIOS.BAT使其中文件名为u-boot.bin然后点击该文件夹下的SJF2410_BIOS.BAT 批处理文件,显示信息如下:

烧写程序所支持的FLASH 都列出来了,有K9S1208NAND64M)、28F128J3AAM29LV800SST39VF160/1 等。

4)在出现上面的界面后,我们在“Select the Function to test:”提示下,输入‘0’,然后回车,这时将选择K9S1208 进行烧写,显示如下:

5)接着在“Select the function to test :”提示下,输入“0”,然后回车,选择 K9F1208

进行烧写,接着在“Input target block number:”栏下输入偏移地址“0”,显示信

息如下:

接着回车,开始烧写程序,程序烧写完成后,输入“2,再回车,便可退出。

6最后reset重启。

2.12.2 使用优龙Nor中自带bootloader烧写nand

ARM板上Nor Flash中有优龙自带的bootloader,可以利用它进行烧写nand

1拿下JP1OM0)的短路帽上电nor启动开发板,进BIOS 界面:

2点击“Serial Port”->”Transmit”选项,选择u-boot.bin

下载结束后,会提示是否要立即运行,这时输入n,将再次进入主功能菜单。

3下载成功后,在出现主功能菜单后,选择“2“,将出现如下界面。

在出现上面的提示后,输入“1”,在接下来的提示输入“Y”,将u-boot.bin烧写

NAND FLASH 的分区中。烧写成功后,会自动进入主功能菜单。

2.12.3 使用原uboot下载烧写新u-boot-1.1.6

ARM板上有uboot,使用原来uboot下载烧写,上电启动。

        tftp 0x31000000 u-boot.bin

nand erase 0x00 0x40000

  nand write 0x310000 0x00 0x40000

然后reset重启。

2.13 arm板上运行u-boot-1.1.6

U-Boot烧写到目标机的Flash之后,用串口线将目标机与宿主机连接起来,进入宿主机Linux系统,运行minicom或者windows下超级终端,再打开目标机电源,如果U-Boot烧写成功,会看到下面的提示信息:

U-Boot 1.1.6 (Oct 19 2009 - 03:01:55)

DRAM:  64 MB

Flash: 512 kB

NAND:    64 MB

In:    serial

Out:   serial

Err:   serial

Hit any key to stop autoboot:  5 

通过它,就可以不用仿真器实现对linux内核的烧写,实现后面的开发过程。

2.14 #minicom的配置使用

1)切换到root用户.

su

2)查找有效串设备.

cat /proc/devices

显示

...

4 ttyS

...

188 ttyUSB

...

如果是普通串口设备设备名前缀为ttyS, 第一串口为ttyS0, 第二串口为ttyS1,依次类推

如果是USB转串口的设备设备名前缀为ttyUSB, 第一串口为ttyUSB0

3配置ttyUSB设备

minicom -s ttyUSB0

会出现一个configuration窗口

┌──[configuration]─────┐

│ Filenames and paths 

│ File transfer protocols     

│ Serial port setup          

│ Modem and dialing       

│ Screen and keyboard      

│ Save setup as ttyUSB0    

│ Save setup as..          

│ Exit                   

│ Exit from Minicom       

└─────────────┘

选择Serial port setup配置会出现如下窗口

┌─────────────────────────────────┐

│ A - Serial Device : /dev/ttyUSB0 

│ B - Lockfile Location : /var/lock 

│ C - Callin Program : 

│ D - Callout Program : 

│ E - Bps/Par/Bits : 115200 8N1 

│ F - Hardware Flow Control : No 

│ G - Software Flow Control : No 

│ 

│ Change which setting? 

└─────────────────────────────────┘

设置如上所示设置完成后 Change which setting?项上按回车退出当前窗口回到第一个窗口按 Save setup as ttyUSB0保存设置再按Exit from Minicom退出Minicom

4启动minicom

minicom

Noteminicom -s是设置minicom,如果启动,直接 minicom就可以。必须在root下。

2.15 #uboot参数设置

可以通过printenv命令查看环境变量的设置。

ARM2410 # printenv

bootdelay=5

baudrate=115200

netmask=255.255.0.0

ethaddr=12:34:56:78:90:ab

bootfile="uImage"

bootargs=root=/dev/mtdblock2 init=/linuxrc console=ttySAC0,115200

bootcmd=tftp ;bootm

serverip=192.168.0.66

ipaddr=192.168.0.68

stdin=serial

stdout=serial

stderr=serial

ARM2410 #

下表是常用环境变量的含义解释。通过printenv命令可以打印出这些变量的值。

环境变量

解释说明

bootdelay

定义执行自动启动的等候秒数

baudrate

定义串口控制台的波特率

netmask

定义以太网接口的掩码

ethaddr

定义以太网接口的MAC地址

bootfile

定义缺省的下载文件

bootargs

定义传递给Linux内核的命令行参数

bootcmd

定义自动启动时执行的几条命令

serverip

定义tftp服务器端的IP地址

ipaddr

定义本地的IP地址

stdin

定义标准输入设备,一般是串口

stdout

定义标准输出设备,一般是串口

stderr

定义标准出错信息输出设备,一般是串口

U-Boot的环境变量都可以有缺省值,也可以修改并且保存在参数区。U-Boot的参数区一般有EEPROMFlash两种设备。

Ø 例一 设置自动启动命令

setenv nandtoram nand read 0x30008000 0x100000 0x180000

setenv bootram bootm 0x30008000 //如果删除,设置为空set bootram

setenv bootcmd run nandtoram\;run bootram //如果改回来为set bootcmd tftp\; bootm

set    bootfile "uImage" //可以是set

sa

boot

Ø 例二 设置nfs启动

启动信息只在标准输出上显示(串口)

setenv bootargs console=ttySAC0,115200 root=/dev/nfs init=/linuxrc 

  nfsroot=192.168.0.66:/home/arm2410/rootfs/root 

  ip=192.168.0.68:192.168.0.66:192.168.0.1:255.255.255.0:www.richardnee.com:eth0:off

启动信息双显示,即在标准输出上显示(串口),也在lcd上显示

setenv bootargs console=tty0 console=ttySAC0,115200 root=/dev/nfs init=/linuxrc 

  nfsroot=192.168.0.66:/home/arm2410/rootfs/root

  ip=192.168.0.68:192.168.0.66:192.168.0.1:255.255.255.0:www.richardnee.com:eth0:off

Ø 例三 设置cramfs启动

第二分区cramfs文件系统,只在标准输出上显示(串口)

setenv bootargs root=/dev/mtdblock2 init=/linuxrc console=ttySAC0,115200

只在lcd上显示

setenv bootargs root=/dev/mtdblock2 init=/linuxrc console=tty0

参考:uboot启动参数说明

http://blog.csdn.net/dongliqiang2006/article/details/4224249

Uboot下载内核和文件系统的步骤:

http://hi.baidu.com/%C1%D6%D3%C6%BE%D3%CA%BF/blog/item/b4ef85102887671ab9127b01.html

2.16 #uboot引导linux内核参数传递解析

本节可以先跳过不看,动手实践后有了直观印象后在深入分析。

2.16.1 #基本概念:ubootbootargslinuxcommadline

Ø 如果ubootbootargs设置了,kernelBoot options中的Default kernel command string设置与否,都不启作用,即bootargs覆盖掉设置的Default kernel command string,打印的信息也是bootargs传过来的command string(当然uboot中的参数能够正确放置才行,CONFIG_CMDLINE_TAG必须定义了!

Ø 如果ubootbootargs未设置的话CONFIG_CMDLINE_TAG未定义kernel就以Boot options中的Default kernel command string的设置进行启动。

Ø 总之不管是从NAND还是NOR起动,uboot是用来引导linux的,如果ubootbootargs设置了的话,uboot在引导Linux时会用bootargs替换掉linuxcommand stringLinuxCONFIG_CMDLINEbootloader无法给内核传递参数的情况下才有用,一般是用不到linux内核自己配的CONFIG_CMDLINE的 。

2.16.2 #uboot怎样传递参数给linux

生成的内核镜象有两种zImageuImage,其中zImage下载到目标板中后,能直接用uboot的命令go来进行直接跳转。这时候内核直接解压启动。不过无法挂载文件系统,因为go命令没有将内核需要的相关的启动参数传递给内核。

传递启动参数我们必须使用命令bootm来进行跳转Bootm命令跳转只处理uImage的镜象。uboot原始码的tools/目录下有mkimage工具,这个工具能用来制作不压缩或压缩的多种可启动映象文件。

mkimage在制作映象文件的时候,是在原来的可执行映象文件的前面加上一个0x40字节的头,记录参数所指定的信息,这样uboot才能识别这个映象是针对哪个CPU体系结构,哪个OS,哪种类型,加载内存中的哪个位置, 入口点在内存的个位置及映象名是什么

1启动参数的传递过程
启动参数是包装在数据结构里的linux kernel启动的时候bootloader把这个数据结构拷贝到某个地址(在arm板中,uboot默认放在0x30000100),在改动PC跳向内核接口的同时通过通用寄存器R2来传递这个地址的值下面这句话就是uboot跳向linux kernel的代码(bootm命令lib_arm/armlinux.c->do_bootm_linux()函数中,270行左右)

theKernel (0,   bd->bi_arch_number,   bd->bi_boot_params);


theKernel其实不是个函数而是指向内核入口地址的指针(在arm板中,uboot默认0x30008000),把它强行转化为带三个参数的函数指针会把三个参数保存到通用寄存器中实现了向kernel传递信息的功能

theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep); //ih_ep=0x30000100?

在这个例子里会把 R0赋值为0

R1赋值为机器号

R2赋值为启动参数数据结构的首地址

因此要向内核传递参数很简单只要把启动参数封装在linux预定好的数据结构里拷贝到某个地址(一般约定俗成是内存首地址+0x100,如arm板中uboot默认放在0x30000100处)。

2启动参数的数据结构
启动参数可保存在两种数据结构中param_structtag前者是2.4内核用的后者是2.6以后的内核更期望用的但是到目前为止2.6的内核也可以兼容前一种结构两种数据结构具体定义如下,可以参考./include/asm-arm/setup.h.

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];
};

Ø 如上,param_struct只需要设置cmmandlineu1.s.page_sizeu1.s.nr_pages三个域。

Ø 对于tag来说,在实际使用中是一个struct tag组成的列表

tag->tag_header一项是u32 tag(重名注意类型)其值用宏:      

ATAG_CORE,

ATAG_MEM,

ATAG_CMDLINE,

ATAG_NONE

等等来表示此时下面union就会使用与之相关的数据结构

同时规定tag列表中第一项必须是ATAG_CORE最后一项必须是ATAG_NONE

比如在linux代码中找到启动参数之后首先看tag列表中的第一项的tag->hdr.tag是否为ATAG_CORE如果不是就会认为启动参数不是tag结构而是param_struct 结构然后调用函数来转换

tag->tag_header另一项是u32 size表示tag的大小tag组成列表的方式就是指针+size实际使用中用tag_next (params)

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;
          struct tag_acorn          acorn;           //Acorn specific
          struct tag_omap          omap;          //OMAP specific
          struct tag_memclk      memclk;       //DC21285 specific
      } u;
 };

需要注意的是这两个数据结构在uboot中和linux中分别有定义这个定义必须一致才能正常传递参数如果实际使用中不一致的话就不能正常传递可以自行修改

3) 通过两种数据结构传递参数的具体例子
例子一通过param_structuboot中的go命令可以传递参数
分析:  go的代码在common/cmd_boot.c,里面并没有拷贝启动参数的代码转向内核的时候也没有传送启动参数所在的地址因此添加如下代码用于拷贝参数可以看到对于param_struct只需要设置cmmandlineu1.s.page_sizeu1.s.nr_pages三个域 

char *commandline = getenv("bootargs");
struct param_struct*lxy_params=(struct param_struct *)0x80000100;
   
printf("setup linux parameters at 0x80000100\n");
memset(lxy_params,   0,   sizeof(struct param_struct)); 

// clear struct param_struct 's mm space

//  then init struct
lxy_params->u1.s.page_size=(0x1<<12);  //4K 这个是必须有的,否则无法启动
lxy_params->u1.s.nr_pages=(0x4000000)>>12;  //64M 这个是必须有的,否则无法启动


memcpy(lxy_params->commandline, commandline, strlen(commandline)+1);
printf("linux command line is: \"%s\"\n",lxy_params->commandline);


//然后还要向内核传递参数地址,将下面一行代码修改:
rc = ((ulong (*)(int, char *[]))addr) (--argc, &argv[1]);        //需要被修改的代码

rc = ((ulong(*)(int,int,uint))addr) (0, gd->bd->bi_arch_number,  gd->bd->bi_boot_params);     //修改之后的代码

例子二bootm命令中通过拷贝tag传递参数
为方便阅读,进行了少许修改但功能不变该函数参数为存放启动参数的地址

static void  setup_linux_tag(ulong param_base)
 {
   struct tag *params = (struct tag *)param_base;
   char *linux_cmd;
   char *p;
   
  memset(params, 0, sizeof(struct tag));
   
  /* step1: setup start tag */
   params->hdr.tag = ATAG_CORE;
   params->hdr.size = tag_size(tag_core);
   params->u.core.flags = 0;
   params->u.core.pagesize = LINUX_PAGE_SIZE;
   params->u.core.rootdev = 0;
   params = tag_next(params);
   
  /* step2: setup cmdline tag */
  params->hdr.tag = ATAG_CMDLINE;
   linux_cmd = getenv("bootargs");
   /* eat leading white space */
  for (p=linux_cmd; *p==' '; p++) {/* do nothing */;}
   params->hdr.size = (sizeof(struct tag_header)+strlen(linux_cmd)+1+4) >> 2;
   memcpy(params->u.cmdline.cmdline, linux_cmd, strlen(linux_cmd)+1);
   params = tag_next(params);
   
  /* step3: setup end tag */
  params->hdr.tag = ATAG_NONE;
   params->hdr.size = 0;
 }

4) 如何开启uboot传递参数
uboot进行设置tag的函数都在lib_arm/armlinux.c在这些函数前面是有#ifdef

#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
      defined (CONFIG_CMDLINE_TAG) || \
      defined (CONFIG_INITRD_TAG) || \
      defined (CONFIG_SERIAL_TAG) || \
      defined (CONFIG_REVISION_TAG) || \
      defined (CONFIG_LCD) || \
      defined (CONFIG_VFD)

只要有一个被定义就可以传递参数,如果要传递commandline,则要定义CONFIG_CMDLINE_TAG

#ifdef CONFIG_CMDLINE_TAG

char *commandline = getenv ("bootargs");

#endif

..........

#ifdef CONFIG_CMDLINE_TAG

setup_commandline_tag (bd, commandline);

#endif

因此如果你的bootm命令不能传递内核参数就应该是在你的boardconfig文件里没有对上述的宏进行设置定义一下即可。我的arm板的linux2.6.24内核关于这的定义在include/configs/arm2410.h中。

/********CONFIG FOR COMMANDLINE***********/

//加入ubootlinux内核传递的参数,如命令行commandline

#ifndef CONFIG_SETUP_MEMORY_TAGS

#define CONFIG_SETUP_MEMORY_TAGS 1

#endif

#ifndef CONFIG_CMDLINE_TAG

#define CONFIG_CMDLINE_TAG 1

#endif

#ifndef CONFIG_INITRD_TAG

#define CONFIG_INITRD_TAG 1

#endif

//其余的暂时还用不到,如果加进去将会编译出错

//#ifndef CONFIG_SERIAL_TAG

//#define CONFIG_SERIAL_TAG 1

//#endif

//#ifndef CONFIG_REVISION_TAG

//#define CONFIG_REVISION_TAG 1

//#endif

//#ifndef CONFIG_VFG

//#define CONFIG_VFD 1

//#endif

//#ifndef CONFIG_LCD

//#define CONFIG_LCD 1

//#endif

/***********CONFIG FOR COMMAND LINE************/

 

5) 引导RAMFS方法

假设将文件系统rootfs下载到0x30300000
BOOTM引导内核和文件系统时,不仅需要将内核进行mkimage处理,文件系统也需要进行相应处理文件系统处理命令:

mkimage -n "RAMFS" -A arm -O linux -T ramdisk -C none -a 30300000 -e 30300040 -d    initrd.bin  initrd.img

进行处理后,与内核处理结果相似,会在原来的文件系统映像前面加上一个64字节的头,这个头里包含了幻数,CRC校验信息和最重要的:文件系统起始地址和长度

如果使用UBOOT引导内核,同时希望将文件系统一并引导,bootm命令后面需要跟两个参数,第一个参数是内核所在的地址,第二个参数是文件系统所在的位置,如

bootm 30008000 30300000

上面说的引导文件系统是利用了bootloader向内核标准传参方法,如果已经在内核将诸如机器号,文件系统地址等全部写死的话,则不需要进行上述操作,只需将PC切换到内核所在地址就可以了

6) tag的详细讲解

之前提到,bootloader巧妙地利用函数指针及传参规范将R0:0x0R1:机器号,R2:参数地址传递给内核由于R0R1比较简单,不需要再作说明需要花点时间了解的是R2寄存器

R2寄存器传递的是一个指针,这个指针指向一个TAG区域UBOOTLinux内核之间正是通过这个扩展了的TAG区域来进行复杂参数的传递,如command line,文件系统信息等等,用户也可以扩展这个TAG来进行更多参数的传递TAG区域存放的地址,也就是R2的值,是在/board/arm2410/arm2410.c里的board_init()函数中初始化的,如在其中初始化为:

gd->bd->bi_boot_params =0x30000100; //这是一个绝对地址

TAG区的结构比较简单,可以视为一个一个TAG的排列(数组?),每一个TAG传递一种特定类型的参数各种系统TAG的定义可以参考./include/asm-arm/setup.h下面是一个TAG区的例子:

0x30000100      00000005 54410001 00000000 00000000
  0x30000110      00000000 0000000F 54410009 746F6F72
  0x30000120      65642F3D 61722F76 7220306D 6F632077
  0x30000130      6C6F736E 74743D65 2C305379 30303639
  0x30000140      696E6920 6C2F3D74 78756E69 EA006372
  0x30000150      00000004 54420005 30300040 00200000
  0x30000160      00000000 00000000

我们可以看到一共有三个TAG

第一个TAG的长度是5个字,类型是ATAG_CORE54410001),有三个元素,均为全零TAG区必须以这个TAG开头

第二个TAG的长度是F个字,类型是ATAG_CMDLINE54410009),这是一个字符串,是向内核传递的kernel command line

第三个TAG的长度是4个字,类型是ATAG_INITRD254410005),有两个元素,第一个是start:3030004030300000+40),第二个是size:2000002M
如果说还有第四个TAG,那就是末尾的两个全零,这是TAG结束的标志

这些TAG是在./lib_arm/arm_linux.c中的do_bootm_linux函数中建立起来的具体建立哪些TAG,由相应的控制宏决定具体可以参考相应代码例子中第一个TAG是起始TAG,如果环境变量中有bootargs,则建立第二个TAG,如果bootm有两个参数(引导文件系统),则会读取文件系统头部的必要信息,建立第三个TAG
内核启动后,将根据R2寄存器的值找到这些TAG,并根据TAG类型,调用相应的处理函数进行处理,从而获取内核运行的必要信息

7) 文件系统的安排(未验证)

cramfs这种只读的压缩格式,linux内核是直接支持的,yaffs必须要自己来打补丁才能让内核支持,在yaffs2的目录内执行sh patch-ker.sh c $KERNEL 就可以让内核支持yaffs格式了。

至于根文件系统个人觉得cramfs要好些,即省空间又是只读的,对于产品来说安全性稍高一点点

首先需你有两个分区,一个cramfs和一个yaffs,这个要通过bootloader来实现。当根文件系统设置为cramfs后,修改一下初始化的脚本liunxrc

在里面加上一句mount /dev/mtdblockX /my 其中X为的yaffs分区number,即可实现两种分区共存。板子出厂时/dev/mtdblock/3cramfs格式/dev /mtdblock/4yaffs的,内核启动后用mount /dev/mtdblock/4 /root之后,就可以操纵那一块yaffs的空间了

本节2.14参考:

uboot--参数-->kernel

http://hi.baidu.com/kebey2004/blog/item/74809400c2b59191e850cd73.html

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP