这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » pxa270开发板 linux的uboot分析

共1条 1/1 1 跳转至

pxa270开发板 linux的uboot分析

菜鸟
2009-05-23 13:55:06     打赏
 BootLoader实验 【实验目的】 1、了解BootLoader的基本概念和框架结构 2、了解BootLoader引导操作系统的过程 3、掌握bootloader程序的编译方法 4、掌握BootLoader程序的使用方法 【实验原理】 1bootLoader的作用        PC 机中的引导加载程序由 BIOS和位于硬盘 MBR 中的 OS Boot Loader一起组成。BIOS 在完成硬件检测和资源分配后,将硬盘 MBR 中的 Boot Loader 读到系统的 RAM 中,然后将控制权交给 OS Boot Loader。Boot Loader 的主要运行任务就是将内核映象从硬盘上读到 RAM 中,然后跳转到内核的入口点去运行,也即开始启动操作系统。        嵌入式系统中,通常并没有像 BIOS 那样的固件程序,因此整个系统的加载启动任务完全由 bootLoader 来完成。bootloader的主要作用: (1)、初始化硬件设备 (2)、建立内存空间的映射图 (3)、完成内核的加载,为内核设置启动参数 2bootLoader程序结构框架        嵌入式系统中的boot Loader 的实现完全依赖于 CPU 的体系结构,因此大多数 Boot Loader 都分为第一阶段和第二阶段两大部分,依赖于CPU体系结构的代码,比如设备初始化代码等,通常都放在阶段1中,而且通常都用汇编语言来实现,以达到短小精悍的目的。而阶段2 则通常用C语言来实现,这样可以实现一些复杂的功能,而且代码会具有更好的可读性和可移植性。 1)、Boot Loader 的阶段1通常主要包括以下步骤: l         硬件设备初始化; l         拷贝Boot Loader的程序到RAM空间中; l         设置好堆栈; l         跳转到阶段2的C入口点。 2)、Boot Loader的阶段2通常主要包括以下步骤: l         初始化本阶段要使用到的硬件设备; l         系统内存映射(memory map); l         将kernel映像和根文件系统映像从Flash读到RAM空间中; l         为内核设置启动参数; l         调用内核。 3bootLoader程序架构分析 3.1 Boot Loader 阶段1分析 (1基本的硬件初始化        Boot Loader一开始就执行基本硬件初始化操作,其目的是为阶段2的执行以及随后的内核的执行准备好一些基本的硬件环境。它通常包括以下步骤: l         初始化GPIO功能,通过GPIO来驱动LED,其目的是表明系统的状态是OK还是Error。如果板子上没有LED,那么也可以通过初始化UART向串口打印Boot Loader的Logo字符信息来完成这一点。(参考fixgpio.S

@ fixgpio.S define_gpio: ……        ldr          r1, =GPIO_BASE /* 0x40E00000*/          ldr          r0, =_GPSR0           /*0x00003000*/        str          r0, [r1, #GPSR0]        /*GPIO<13,12> is set as output */        ldr          r0, =_GPCR0      /* 0x00000800*/        str          r0, [r1, #GPCR0]   /*GPIO<11> is clear to level zero*/        ldr          r0, =_GAFR0L       /* 0x80000000*/        str          r0, [r1, #GAFR0L] /* GPIO(15) is set as alternate functions 2->nCS<1>*/        ldr          r0, =_GAFR0U      /* 0x00000010 | (2<<0 )*/        str          r0, [r1, #GAFR0U] /*GPIO<18,16> set as alternate functions 2 ……    

l         设置CPU的速度和时钟频率。(参考setup_memory.S部分代码)

clock_enable :/* start.S*/ #if defined(CONFIG_PXA25x)        ldr          r0, =0x0001FFFF #elif defined(CONFIG_PXA27x)        ldr          r0, =0x01FFFFFF #endif        ldr          r1, =CKEN        str          r0, [r1]        mov        pc, lr

l         存储控制单元初始化。包括正确地设置系统动静态存储控制器的各个寄存器等。

setup_memory : /* memsetup.S*/        @ change cpu speed function        ldr          r1, =CCCR        ldr          r0, =_CCCR        str          r0, [r1]                                @ set CCCR  ……

(2)、将bootLoader程序加载到RAM空间

       /* copy bootloader to dynamic memory area*/        ldr          r0, =0x00        ldr          r1, =__boot_start /* @boot.ld.in file */        ldr          r2, =__boot_end     /* @boot.ld.in file */  1:   ldmia       r0!, {r3-r10}        stmia       r1!, {r3-r10}        cmp        r1, r2        blt           1b
(3)、设置堆栈指针sp

       堆栈指针的设置是为了执行C语言代码作好准备。通常我们可以把sp的值安排在RAM 空间的最顶端(堆栈向下生长)。此外,在设置堆栈指针sp之前,也可以关闭led灯,以提示准备跳转到阶段2。经过上述这些执行步骤后,系统的物理内存布局应该如图3-1所示。

       @ set stack point        ldr          sp, =stack_point-4  /*stack_point = __boot_start + 0x00100000;*/

图3-1 系统的物理内存布局 (4)、跳转到阶段2的C入口点        在上述一切都就绪后,就可以跳转到Boot Loader的阶段2去执行了。在ARM系统中, 可以通过修改PC寄存器为合适的地址来实现。

ldr          pc, =main /* @ start.S file*/

3.2 Boot Loader 阶段2分析        阶段2的代码通常用C语言来实现,以便于实现更复杂的功能和取得更好的代码可读性和可移植性。但是与普通C语言应用程序不同的是,在编译和链接Boot Loader程序时,不能使用glibc库中的任何支持函数。可以直接把main()函数的起始地址作为整个阶段2执行映像的入口点。

       @ jump to c code        ldr          pc, =main

1)、初始化本阶段要使用到的硬件设备;        本阶段初始化的硬件设备通常包括: l         初始化至少一个串口,以便和终端用户进行I/O输出信息; l         初始化计时器、 l         初始化网络传输等。        在初始化这些设备之前,也可以重新把LED灯点亮,以表明程序bootLoader程序已经进入main()函数执行。设备初始化完成后,可以输出一些打印信息,程序名字字符串、版本号等。(参考main.c文件

    …… (*(volatile unsigned short  *)(0x0a000000)) |= (1<<9)|(1<<8)|(1<<6)|(1<<15);             uart_init();     //初始化串口        time_init();      //初始化定时器        config_init();   //内存映射配置初始化        //信息提示        printf("\033[H\033[J\n");              // clear screen.     printf(" %s : bootloader for Xscale 270 board\n", PACKAGE);     printf(" Copyright (C) 2002-2004 Emdoor Co,. ltd.\n");        printf(" support : http://www.emdoor.com\n");          iflash_init();    //flash存储器初始化     PWMPCR0 = 0xff;     PWMDCR0 = (0x4ff>>2);         //let eth CS is ok         (*(volatile unsigned long *)(0x4800000c)) = _MSC1_ED;        eth_init(); //网络初始化 ……

(2)、系统的内存映射        所谓内存映射就是指在整个4GB物理地址空间中有哪些地址范围被分配用来寻址系统的RAM单元。虽然CPU通常预留出一大段足够的地址空间给系统RAM,但是在搭建具体的嵌入式系统时却不一定会实现CPU预留的全部RAM地址空间。也就是说,具体的嵌入式系统往往只把CPU预留的全部RAM地址空间中的一部分映射到RAM单元上。开发板的bootloader程序利用map __bsetup parts[]结构体对内存的分配进行配置(参考partition.c),从内存分布可以看出,PXA27X开发板SRAM和SDRAM起始地址的存储分布情况: bootloader:   0x00000000_0x00040000,共占256K,SDRAM起始地址:0xA1E00000 kernel:         0x00040000_0x00180000,共占1.25M ,SDRAM起始地址:0xA0008000 root:     0x00180000_0x02000000,共占30.5M,SDRAM起始地址0xA0000000

struct map __bsetup parts[] = {        {               .name   = "loader",               .sramb = LOADER_SRAM_BASE,           //0x00000000               .srams = LOADER_MAX_SIZE,              //0x00040000->256K               .dramb = LOADER_DRAM_BASE,          //0xA1E00000               .drams = 0,               .maxs   = LOADER_MAX_SIZE,             }, {               .name   = "kernel",               .sramb = KERNEL_SRAM_BASE,            //0x00040000               .srams = KERNEL_MAX_SIZE,        //0x00140000->1.25M               .dramb = KERNEL_DRAM_BASE,           //0xA0008000               .drams = 0,               .maxs   = KERNEL_MAX_SIZE,        }, {               .name   = "ramdisk",               .sramb = RAMDISK_SRAM_BASE,        //0x00180000               .srams = RAMDISK_MAX_SIZE,            //0x00300000->3M               .dramb = RAMDISK_DRAM_BASE, //0xA1000000               .drams = 0,               .maxs   = RAMDISK_MAX_SIZE,        }, {               .name   = "root",               .sramb = ROOTFS_SRAM_BASE,           //0x00180000               .srams = ROOTFS_MAX_SIZE,                     //0x01e80000->30.5M               .dramb = ROOTFS_DRAM_BASE,          //0xA0000000               .drams = 0,               .maxs   = ROOTFS_MAX_SIZE,        } };

  (3)、加载内核映像和根文件系统映像 l         规划内存占用的布局        这里包括两个方面:① 内核映像所占用的内存范围;② 根文件系统所占用的内存范围。在规划内存占用的布局时,主要考虑基地址和映像的大小两个方面。        对于内核映像,一般将其拷贝到从(MEM_START+0x8000)这个基地址开始的大约1MB大小的内存范围内(嵌入式Linux的内核一般都不操过1MB)。为什么要把从MEM_START到MEM_START+0x8000这段32KB大小的内存空出来呢?这是因为Linux内核要在这段内存中放置一些全局数据结构,如:启动参数和内核页表等信息。        而对于根文件系统映像,则一般将其拷贝到MEM_START+0x00100000开始的地方。如果用Ramdisk作为根文件系统映像,则其解压后的大小一般是1MB。 (4)、设置内核的启动参数        应该说,在将内核映像和根文件系统映像拷贝到RAM空间中后,就可以准备启动Linux 内核了。但是在调用内核之前,应该作一步准备工作,即:设置Linux内核的启动参数。 Linux 2.4.x 以后的内核都倾向以标记列表(tagged list)的形式来传递启动参数。启动参数标记列表以标记ATAG_CORE开始,以标记ATAG_NONE结束。每个标记由tag_header结构和随后的特定参数值数据结构来组成。(参考文件:linux.c)

…… #define ATAG_NONE    0x00000000 struct tag_header {        uint32 size;        uint32 tag; }; …… 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;               /*                * DC21285 specific                */               struct tag_memclk memclk;        } u; };

       在嵌入式Linux系统中,通常需要由Boot Loader设置的常见启动参数有:ATAG_CORE、 ATAG_MEM、ATAG_CMDLINE、ATAG_RAMDISK、ATAG_INITRD等。 比如,设置ATAG_CORE的代码如下:

void create_tags(void){        tags = (struct tag *)BOOT_PARAMS;        setup_tag_core(0, 0);        setup_tag_initrd2(0xA1000000, 0x00420000);        setup_end_tag();        return; }   static void setup_tag_core(uint32 rootdev, uint32 flags){        tags->hdr.tag = ATAG_CORE;        tags->hdr.size = tag_size(tag_core);        tags->u.core.flags = flags;                                 // not use.        tags->u.core.pagesize = 0;                                 // set read/write.        tags->u.core.rootdev = 0;        tags = tag_next(tags);        return; }

       其中,BOOT_PARAMS 表示内核启动参数在内存中的起始基地址,指针tags是一个struct tag类型的指针。宏tag_next()将以指向当前标记的指针为参数,计算出当前标记的下一个标记的起始地址。注意,内核的根文件系统所在的设备ID就是在这里设置的。        下面是设置ATAG_INITRD的示例代码,它告诉内核在RAM中的什么地方可以找到initrd映象(压缩格式)以及它的大小:

static void setup_tag_initrd2(uint32 start, uint32 size){        tags->hdr.tag = ATAG_INITRD2;        tags->hdr.size = tag_size(tag_initrd);        tags->u.initrd.start = start;        tags->u.initrd.size = size;        tags = tag_next(tags);        return; }

最后,设置ATAG_NONE标记,结束整个启动参数列表:

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

(5)、调用内核        Boot Loader调用Linux内核的方法是直接跳转到内核的第一条指令处,也即直接跳转 到MEM_START+0x8000地址处。在跳转时,下列条件要满足: l         CPU寄存器的设置:        R0=0;        R1=机器类型ID;关于机器类型号,可以参见linux/arch/arm/tools/mach-types;        R2=启动参数标记列表在RAM中起始基地址; l         CPU 模式:        必须禁止中断(IRQs和FIQs);        CPU必须SVC模式; l         Cache和MMU的设置:        MMU必须关闭;        指令Cache可以打开也可以关闭;        数据Cache必须关闭; 如果用C语言,可以像下列示例代码这样来调用内核:(粗体表示)

static bool do_boot(int argc, char **argv){        void (*kernel)(int zero, int arch);        if (argc == 1) {               struct map *mp;               mp = find_map("kernel");               if (!mp){ printf(" can't found map for kernel.\n"); goto invalid; }               kernel = (void *)mp->dramb;        } else if (argc == 2){               bool res;               ulong tmp;               res = strtoul(argv[1], &tmp, 16);               if (!res) goto invalid;               kernel = (void *)tmp;        } else goto invalid;        if (!get_kernel_size(kernel)){ printf(" error: kernel is not exists.\n"); return false; }        create_tags();        printf("starting kernel ...\n");        kernel(0, 200);        return true; invalid :        boot_usage();        return false; }

  【实验仪器】 1、装有Linux操作系统的PC机一台; 2、XSBase270或XSBase255 ARM实验开发平台一套 【实验内容】 1bootLoader程序的编译        为了编译Bootloader程序,需要事先在目标板上安装交叉编译工具Toolchain。(见linux使用手册Toolchain安装部分)。 (1)、利用 tar zxvf Boot-XSBase270.tar.gz 指令解压。 [root@localhost BootLoader]$tar zxvf Boot-XSBase270.tar.gz        利用上述命令解压后,bootloader源代码解压到当前目录中Boot-XSBase270文件夹中。 (2)、编译。在解压的目录里进行make编译。 [root@localhost BootLoader]$ cd Boot-XSBase270 [root@localhost Boot-XSBase270]$make        编译完成后, 在当前目录下会生成bootloader映象文件boot。 2bootLoader程序的下载        将bootloader的映象文件boot拷贝Jflash-XSBase270目录下,连好JTAG下载器,并利用Jflash-XSBase270目录中jflashmm程序将 bootloader映象文件boot烧写到开发板上。 [root@localhost Boot-XSBase270]$cp boot /root/EmdoorARM/Jflash/Jflash-XSBase270/ [root@localhost Boot-XSBase270]$ cd /root/EmdoorARM/Jflash/Jflash-XSBase270 [root@localhost Boot-XSBase270]$ ./jflashmm boot 3、bootLoader的使用方法  Bootloader命令的使用方法。 help
用法 帮助
描述 简短显示各命令的介绍
参数
举例 Bboot> Help
Load
用法 load [kernel/ramdisk]
描述 把存放在FLASH中的映像文件拷贝到SDRAM中。在Autoboot 过程中会自动运行,把内核映像从FLASH加载到SDRAM中。
参数 Kernel    -    把内核映像从FLASH拷贝到SDRAM中 Ramdisk-     从FLASH中拷贝RAMDISK到SDRAM
举例 Bboot> load kernel
bootp
用法 Bootp
描述 运行bootp命令用来获取HOST主机发送的BOOTP的数据包,解析 BOOTP的数据包,获取本机的IP地址
参数
举例 Bboot> bootp
tftp
用法 Tftp 文件名 {address/loader/kernel/root/ramdisk}
描述 通过以太网下载主机的数据或文件到目标平台的SDRAM
参数 文件名 - 主机平台需要传输的文件名 loader - 把传输到目标平台的文件放置在SDRAM的loader区域 kernel - 把传输到目标平台的文件放置在SDRAM的kernel区域 root - 把传输到目标平台的文件放置在SDRAM的root区域 ramdisk - 把传输到目标平台的文件放置在SDRAM的ramdisk区域 address - 把传输到目标平台的文件放置在SDRAM的指定地址
举例 Bboot> tftp zImage kernel
flash
用法 Flash {loader/kernel/root/ramdisk}
描述 把SDRAM中的数据烧录到FLASH中特定的地址
参数 loader - 把SDRAM中的数据烧录到FLASH中的loader区域 kernel – 把SDRAM中的数据烧录到FALSH中的kernel区域 root – 把SDRAM中的数据烧录到FLASH中的root区域 ramdisk – 把SDRAM中的数据烧录到FLASH中的ramdisk的区域
举例 Bboot> flash kernel
erase
用法 erase {loader/kernel/ramdisk/root}
描述 擦除FALSH中的相应区域
参数 loader – 擦除FALSH中loder区域 kernel – 擦除FLASH中的kernel区域 root – 擦除FLASH中的root区域 ramdisk – 擦除FLASH中的ramdisk区域
举例 bboot> erase kernel
boot
用法 Boot boot [addr]
描述 在SDRAM中运行kernel 通过参数中指定的地址运行kernel
参数 addr – kernel image address
举例 bboot> boot
set
用法 set [name] [value]
描述 设置IP地址,MAC地址以及autoboot参数
参数 Name [myipaddr] [destipaddr] [myhaddr] [autoboot] Value [ip] [ip] [mac address] [load kernel; boot]
举例 bboot> set        //输出设置信息 bboot> set myipaddr 192.168.100.X    //改变目标平台的IP地址 bboot> set destipaddr 192.168.100.XX //改变主机平台的IP地址 bboot> set myhaddr 00:0E:6F:CE:59:21 //设置目标平台的MAC地址 bboot> set autoboot load kernel; boot   //装载kernel后自动启动
ping
用法 Ping
描述 检查目标平台和主机平台的网络连接
参数 Ping主机平台的ip地址
举例 Ping 192.168.100.xx
reboot
用法 Reboot
描述 软件复位
参数 None
举例 Reboot
【思考题】 1、分析bootloader源程序中的flash.c代码,画出该代码的流程图 2、利用实验二Makefile的知识点,分析bootloader源程序三个Makefile的结构与关系 3、某同学在bootloader源程序目录中,利用make编译bootloader源程序,出现如下错误: [root@hostlocal Boot-XSBase270]make compile start.S make[1]: arm-linux-gcc: Command not found make[1]:***[start.o] Error 127 make: *** [all] Error 2        请分析产生错误的原因,并给出解决办法 4、bootloader主要功能有哪些? 5、请在阅读完bootloader程序后,画出bootloader程序框架流程.。    
上海鹰龙pxa270 开发板,全国最低价格
http://www.embedchina.cn
021-51873921

 

 

 

Pxa270开发平台主要是面向计算机、软件专业的高端平台,微处理器主频稳定运行在520MHz,可运行Linux 2.6.x及WinCE.net 6.0操作系统,支持Qt/E嵌入式图形界面,提供完整的驱动和应用程序,既适合作为计算机、软、硬件等专业开设嵌入式软件课程的教学平台,又适合广大从事PMP、PDA、智能手机的厂商和科研单位作为参考设计平台。
平台由处理器核心板、主板及LCD三部份组成。

核心板:

 基于Xscale技术的Intel PXA270处理器 
* 系统稳定工作在520MHZ主频 
* 内部集成iwmmx指令
* 64MB SDRAM
* 64MB Nand Flash 
* 16MB Nor Flash

主板:

* 3.5' 320*240 TFT真彩LCD 
* IIS音频CODEC
* 触摸屏  
* 立体声耳机、线路、MIC接口
* VGA接口  
* 红外通信IrDA
* 1个主USB口、1个从USB口 
* CF卡接口(PC Card模式) 
* 一个100M网口 
* IDE接口 
* 4键小键盘
* 1个RS232标准串口 1个RS485 
* SD/MMC 接口 
* 实时时钟
* JTAG接口(包括14Pin和20Pin标准) 
* IIC接口 
* SPI接口


 

软件资源:
Linux:
系统引导程序: Blob
操作系统: Linux2.6.x
文件系统: cramfs JFFS2  YAFFS
图形用户界面: 支持Qt/E
设备驱动: 串口,Ethernet,Audio,SD卡,IDE,CF卡,AD/DA,USB,红外,蓝牙,LCD,触摸屏,SPI,I2C,RTC,GPIO等
开发工具: JTAG烧写Nor Flash工具,arm-linux-gcc交叉编译器,GDB,GDBSERVER调试工具,SourceInsight 代码编辑器,文件系统制作工具等
多媒体软件: mplayer媒体播放器,实现MPEG、MPEG2、MPEG4、AVI、WMV等多种媒体解码;madplay音频播放器

WinCE:
板级支持包: WinCE.net 5.0  BSP
设备驱动: 串口,Ethernet,Audio,IDE,CF卡,USB,LCD,触摸屏,RTC,SD卡


 一共16个实验,每个实验基本都有实验文档和实验源码。

实验内容:
实验一 常用命令以及工具实验
实验二 Makefile实验.
实验三 BootLoader实验
实验四 内核编译实验
实验五 文件系统制作实验
实验六 GUI应用程序实验
实验七 驱动程序结构实验
实验八 IO口驱动实验
实验九  SD卡驱动程序实验
实验十  USB驱动配置实验
实验十一 QT移植实验
实验十二 串口通讯实验
实验十三 GPS和GSM通信实验
实验十四 Webserver的移植与网络通讯实验
实验十五 USB摄像头实验
实验十六 嵌入式数据库实验

下面的图片是开发板LCD显示游戏

下图是游戏在pxa270上运行,在VGA和TFT液晶同时显示,右边的大液晶是开发用的计算机,左边的液晶接pxa270的VGA输出口

下图是播放u盘录像

下图是linux运行时的情况

运行linux的情况

点击数:44  录入时间:200



关键词: pxa270     开发     linux     uboot     分析         

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]