精华内容
下载资源
问答
  • Boot Loader是定制Windows CE操作系统过程中一个重要开发环节。Boot Loader的作用正如...如果没有采用BIOS,那么Boot Loader的作用还包括实现BIOS基本功能;Loader,既加载操作系统,在整个系统正常启动后Boot Loa
    Boot Loader是定制Windows CE操作系统过程中一个重要的开发环节。Boot Loader的作用正如名字中的两个单词:Boot,既引导系统,如果基于CE的产品采用BIOS实现硬件初始化和配置,那么Boot Loader只需引导软件系统。如果没有采用BIOS,那么Boot Loader的作用还包括实现BIOS的基本功能;Loader,既加载操作系统,在整个系统正常启动后Boot Loader通过不同的方式加载CE的内核文件nk.bin。当Boot Loader把nk.bin解压到RAM后就把CPU控制权交给CE内核。x86平台的Boot Loader种类最多,下面就对x86平台的Boot Loader做一说明:

      x86 ROM Boot Loader

      又叫Rom Boot,记得以前写过的文章中提到了Rom Boot。Rom Boot 被设计存放在Flash/EEPROM中,也就是原来BIOS的位置,这样当上电后CPU到固定地址执行代码,也就是执行了Rom Boot包含的代码,它对整个硬件系统进行初始化和检测,并且支持通过网卡从远程机器上下载nk.bin或者从本地IDE/ATA 硬盘的活动分区中寻找nk.bin文件加载。Rom Boot的优点就是引导并且加载速度快,而且它自身完成了所有的操作,这样就不用BIOS、MSDOS,更不用Loadcepc了。缺点就是需要CE开发者读懂它的源码并修改。CE提供了Rom Boot的所有源码,读者可以查找标题为“x86 Source Organization”的帮助文档,在这个文档中列举了所有相关的目录及内容,另外还列举了四种网卡的驱动程序源码所在目录。

      x86 BIOS Boot Loader

      BIOS Boot Loader和MSDOS+Loadcepc两种方式差不多,BIOS Boot Loader只是不需要MSDOS操作系统,它仍然需要BIOS和FAT文件系统。下面讲一下采用BIOS Boot Loader的系统的引导顺序:系统上电后BIOS执行完硬件初始化和配置后,BIOS检查引导设备的启动顺序,如果引导设备是硬盘、CF卡、DOC(Disk-On-Chip)一类的存储设备,那么就加载这些存储器上的主引导扇区(Master Boot Sector)中的实模式代码到内存,然后执行这些代码。这里提到的代码被称为主引导记录(MBR)。MBR首先在分区表(同样位于主引导扇区)中寻找活动分区,如果存在活动分区,那么加载位于这个活动分区的第一个扇区上的代码到内存,然后执行这些代码。这里提到的活动分区的第一个扇区被称为引导扇区(Boot Sector)。引导扇区上的代码的功能是找到并且加载BIOS Boot Loader,BIOS Boot Loader再加载nk.bin。引导扇区的源码位于%_WINCEROOT%\Public\Common\Oak\Csp\i486\Biosloader\Bootsector目录下。有一个现成的引导扇区镜像文件,它的路径为%_WINCEROOT%\Public\Common\Oak\Csp\i486\Biosloader\Diskimages\Setupdisk\Bsect.img 。而对于BIOS Boot Loader,CE提供了Setupdisk.144和Bootdisk.144两个文件,以“.144”为扩展名的文件的解压我在前面的文章中讲过了。这两个文件解开后都包含了引导扇区和Boot Loader的镜像文件。执行“mkdisk C:”批处理命令将这两个镜像文件写到磁盘上。mkdisk会设置Boot Loader的隐藏属性,这样在列出根目录下所有文件时不会显示Boot Loader的文件。

      MSDOS+Loadcepc

      这种方式非常简单,在MSDOS启动后再执行loadcepc.exe,让loadcepc加载nk.bin到内存后再把CPU控制权交给CE内核程序。loadcepc在前面的文章中已经讲过了。

      下面根据一般的Boot Loader源码来分析一下Boot Loader的组成:

      Boot Loader由两部分组成:OEM启动代码(OEM startup code)和主代码(main code)。OEM启动代码是最先执行的部分,它的功能是初始化内存寄存器、设置CPU频率、初始化高速缓存等。之后它跳转到主代码中执行。一般OEM启动代码都是用汇编编写。主代码一般用C语言编写,它负责其它所有任务,在执行的同时还能够将执行的相关信息显示在屏幕上。一般添加公司LOGO或者其它启动LOGO都在此修改。

      主代码主要由几个部分组成:镜像下载代码,通过并口或者网卡来实现从远程计算机下载nk.bin;串口调试代码,包含对串口的读写函数,用户调用这些函数就可以通过串口在远程计算机和本地计算机之间通信;写flash代码,包含写镜像到flash的函数;硬件监控代码。
    展开全文
  • 对电子系统而言,FPGA的保密性极其重要。...在右边2005年进行的同类型系统设计中,不难发现FPGA已经成为系统设计的核心,它整合了原有ASIC部分ASSP芯片的功能,因此FPGA作为系统芯片直接取代了ASIC的功能。
  • 在右边2005年进行的同类型系统设计中,不难发现FPGA已经成为系统设计的核心,它整合了原有ASIC部分ASSP芯片的功能,因此FPGA作为系统芯片直接取代了ASIC的功能。随着FPGA性能、容量与功能的不断提升,今天的FPGA ...
  • 一起学nRF51xx 12 - flash

    2019-09-01 20:32:50
    在某些应用中需要固件升级功能及存储一些用户定义标志位,或者存储一些传感器数据,一般情况我们是用外挂FLASH、EEPROM,或者使用MCU内部EEPROM来解决。但是外挂EEPROM或者FLASH会增加成本和产品体积。...

    前言

    在某些应用中需要固件升级功能及存储一些用户定义的标志位,或者存储一些传感器的数据,一般情况我们是用外挂FLASH、EEPROM,或者使用MCU内部的EEPROM来解决。但是外挂EEPROM或者FLASH会增加成本和产品的体积。NORDIC提供了一个比较实用的方法:把这些数据存放在芯片的FLASH中。FLASH起了两个作用:1)程序的存储空间   2)用户自定义的数据存储空间。

    NRF51822中的CODE MEMORY有三个部分组成:

    1)Code FLASH

    用来存放我们编写的程序的存储空间。这一部分我们也可以用来存储自己的数据。

    2)   FICR

    Factory Information Configuration Register的缩写。存放的是芯片出厂的时候被烧进去的一些信息,比如芯片的FLASH分成多少个PAGE,每一个PAGE的大小是多少,工厂代码,RAM的块数,RAM块的大小,芯片地址等信息。FICR的信息是只读的,用户不可以修改或者擦除。

    3)   UICR

    是提供给用户存储自定义数据的存储区域。

     

    相关寄存器介绍

     

    在操作FLASH之前,需要通过配置寄存器来使能允许写或者允许擦除。当使能Wen以后,我们可以对FLASH进行写操作;当使能Een以后,我们可以对FLASH进行擦除。特别注意,Wen跟Een不能同时使能,否则会造成无法预见的后果。

     

     

    程序编写

    4.1  程序流程

    1)配置串口,用来打印信息。

    2)配置CONFIG寄存器的Een使能。

    3)擦除FLASH PAGE。

    4)获取串口输入的数据。

    5)配置CONFIG寄存器的Wen使能,把串口获取的数据写入到FLASH中。

    6)从刚才写数据的FLASH地址里面把数据读出,然后通过串口打印出来。

     

    本例程介绍了NRF51822芯片内部FLASH的读写。

     

     

     

    示例详解

    基于硬件平台:nrf51822ek_tm开发板。

     

    本示例所用的最小系统板原理图:

     

      1. 工程创建:
        1. 打开KEIL,新建一个空工程:Project->NewuVisionProject

    工程名为nrfxx-flash确认后按下图选择芯片为nrf51822_xxAA->ok

    在弹出的对话框中勾选CMSIS中的CORE;Device中的Startup(后面有nrf51Series字样的);在nrf_device中勾选nrf_gpio, nrf_uart, nrf_delay,nrf_err并在nrf_Libraries中勾选app_error,nrf_assert模块。

     

     

     

    OK之后工程自动生成如下代码:

    新建一个空白文档,保存为main.c,并加入工程中:

    配置工程,选择使用MicroLIB库,可以减小程序体积:

    加入NRF51定义,并选择化等级3,可以减小程序体积,但仿真运行时可能会出现与代码顺序不一致现象:

     

    调试工具选择J-LINK,并将接口设置为SW口勾选下载程序后自动复位及运行:

     

     

      1. 工程代码
        1. OK之后在man.c中加入如下代码:

     

          把程序编译,可以看到串口助手中打印了以下输出内容:

    关于nrf51xx及flash的更详细介绍可以参看《nRF51822_PS_v3.3.pdf》或https://infocenter.nordicsemi.com/index.jsp

     

    OK,本期实验完成!下期见!同时如果大家有什么疑问或是有想了解的其它内容,也欢迎大家留言!!最后喜欢这个公众号的同学们记得加关注了,会有不定期技术干货推出!!

    文中源码资料下载,在公众号里给十三发消息:

    下载|一起学nRF51xx 12

     

    关注十三公众号

     

    展开全文
  •  一、 Boot Loader概念和功能  1、嵌入式Linux软件结构与分布在一般情况下嵌入式Linux系统中软件主要分为以下部分: ...有的芯片比较复杂,比如Omap3,他在flash中没有代码时候有许
    

    一、    Boot Loader的概念和功能 

    1、嵌入式Linux软件结构与分布在一般情况下嵌入式Linux系统中的软件主要分为以下及部分:

    (1)引导加载程序:其中包括内部ROM中的固化启动代码和Boot Loader两部分。而这个内部固化ROM是厂家在芯片生产时候固化的,作用基本上是引导Boot Loader。有的芯片比较复杂,比如Omap3,他在flash中没有代码的时候有许多启动方式:USB、UART或以太网等等。而S3C24x0则很简单,只有Norboot和Nandboot。

    (2)Linux kernel 和drivers。

    (3)文件系统。包括根文件系统和建立于Flash内存设备之上的文件系统(EXT4、UBI、CRAMFS等等)。它是提供管理系统的各种配置文件以及系统执行用户应用程序的良好运行环境的载体。

    (4)应用程序。用户自定义的应用程序,存放于文件系统之中。
    在Flash 存储器中,他们的 一般分布如下:

    Boot Loader启动过程分析 - singleboy - singleboy的博客 

    但是以上只是大部分情况下的分布,也有一些可能根文件系统是initramfs,被一起压缩到了内核映像里,或者没有Bootloader参数区,等等。

    2、在嵌入式Linux中为什么要有BootLoader
    在linux内核的启动运行除了内核映像必须在主存的适当位置,CPU还必须具备一定的条件:

    【1】CPU寄存器设置:

    R0=0;

    R1=Machine ID(即Machine Type Number,定义在linux/arch/arm/tools/mach-types);

    R2=内核启动参数在RAM中起始基地址;

    【2】CPU模式:

    必须禁止中断(IRQs和FIQs);

    CPU 必须工作在是超级保护模式(SVC) 模式;

    【3】Cache和MMU的设置:

    MMU 必须关闭;

    指令Cache可以打开也可以关闭;

    数据Cache必须关闭;

    但是在CPU刚上电启动的时候,一般连内存控制器都没有配置过,根本无法在内存中运行程序,更不可能处在Linux内核的启动环境中。为了初始化CPU及其他外设,使得Linux内核可以在系统主存中跑起来,并让系统符合Linux内核启动的必备条件,必须要有一个先于内核运行的程序,他就是所谓的引导加载程序(Boot Loader)。

    而Boot Loader并不是Linux才需要,是几乎所有的运行操作系统的设备都具备的。我们的PC的BOIS就是Boot Loader的一部分(只是前期引导,后面一般还有外存中的各种Boot Loader),对于Linux PC来说,Boot Loader = BIOS + GRUB/LILO。

    正如前面所述,Boot Loader是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境,最后从别处(Flash、以太网、UART)载入内核映像并跳到入口地址。

    由于BootLoader直接操作硬件,所以她严重依赖于硬件,而且依据所引导的操作系统的不同。

    二、Boot Loader的工作模式

    大多数 Boot Loader 都包含两种不同的操作模式:“启动加载”模式和“下载”模式,这种区别仅对于开发人员才有意义。但从最终用户的角度看,Boot Loader 的作用就是用来加载操作系统,而并不存在所谓的启动加载模式与下载工作模式的区别。

    启动加载(Boot loading)模式:

    这种模式也称为"自主"(Autonomous)模式。也即 Boot Loader 从目标机上的某个固态存储设备上将操作系统加载到 RAM 中运行,整个过程并没有用户的介入。这种模式是 Boot Loader 的正常工作模式,因此在嵌入式产品发布的时侯,Boot Loader 显然必须工作在这种模式下。

    下载(Downloading)模式:

    在这种模式下,目标机上的 Boot Loader 将通过串口连接或网络连接等通信手段从主机(Host)下载文件,比如:下载内核映像和根文件系统映像等。从主机下载的文件通常首先被 Boot Loader 保存到目标机的 RAM 中,然后再被 Boot Loader 写到目标机上的FLASH 类固态存储设备中。Boot Loader 的这种模式通常在第一次安装内核与根文件系统时被使用;此外,以后的系统更新也会使用 Boot Loader 的这种工作模式。工作于这种模式下的 Boot Loader 通常都会向它的终端用户提供一个简单的命令行接口。

     象Blob 或U-Boot 等这样功能强大的Boot Loader 通常同时支持这两种工作模式,而且允许用户在这两种工作模式之间进行切换。比如,Blob 在启动时处于正常的启动加载模式,但是它会延时10 秒等待终端用户按下任意键而将 blob 切换到下载模式。如果在 10 秒内没有用户按键,则 blob 继续启动 Linux 内核。

    三、Boot Loader 与主机之间进行文件传输协议

    最常见的情况就是,目标机上的 Boot Loader 通过串口与主机之间进行文件传输,传输协议通常是 xmodem/ymodem/zmodem 协议中的一种。但是,串口传输的速度是有限的,因此通过以太网连接并借助 TFTP 协议来下载文件是个更好的选择。

    此外,在论及这个话题时,主机方所用的软件也要考虑。比如,在通过以太网连接和TFTP 协议来下载文件时,主机方必须有一个软件用来的提供 TFTP 服务。

    四、Bootloader的工作流程

    由于Boot Loader的实现依赖与CPU的体系结构,因此大多数的Boot Loader都分为stage1和stage2两个阶段:

    1,Bootloader 的第一阶段(Stage1),工作流程

    • 硬件设备初始化
    • 代码重定位,为加载 Boot Loader 的 stage2 准备 RAM 空间
    • 加载t第二阶段代码到RAM空间
    • 设置堆栈跳转到第二阶段代码入口

    1.1,硬件设备初始化通常包括如下步骤:(按先后顺序执行):

    【1】复位(reset)

    【2】设置CPU为超级保护模式(SVC) 即特权模式(Supervisor)

    【3】关闭看门狗,不必附加喂狗代码。

    【4】屏蔽所有中断,为中断提供服务通常是OS设备驱动程序的责任,因此在 Boot Loader 的执行全过程中可以不必响应任何中断。中断屏蔽可以通过写CPU的中断屏蔽寄存器或状态寄存器(比如 ARM 的 CPSR 寄存器)来完成。

    【5】设置系统时钟频率。

    【6】初始化内存控制器,包括正确地设置系统的内存控制器的功能寄存器以及各内存库控制寄存器等。

    【7】初始化串口等,典型地,初始化UART并向串口打印相关字符信息。

    【8】初始化LED。典型地,通过GPIO 来驱动LED,其目的是表明系统的状态是 OK 还是 Error。如果板子上没有 LED,那么也可以通过初始化 UART 向串口打印 Boot Loader 的Logo 字符信息来完成这一点。

    【9】关闭 CPU 内部指令/数据 cache。

    1.2,代码重定位主要检查自己是否在内存中。如果是跳到堆栈段(stack_setup代码段)设置堆栈,不是就加载自己到RAM空间。

    为了获得更快的执行速度,通常把 stage2 加载到 RAM 空间中来执行,因此必须为加载 Boot Loader 的 stage2 准备好一段可用的 RAM 空间范围。

    由于 stage2 通常是 C 语言执行代码,因此在考虑空间大小时,除了 stage2 可执行映象的大小外,还必须把堆栈空间也考虑进来。此外,空间大小最好是 memory page 大小(通常是 4KB)的倍数。一般而言,1M 的 RAM 空间已经足够了。具体的地址范围可以任意安排,比如 blob 就将它的 stage2 可执行映像安排到从系统 RAM 起始地址 0xc0200000 开始的 1M 空间内执行。但是,将 stage2 安排到整个 RAM 空间的最顶 1MB(也即(RamEnd-1MB) - RamEnd)是一种值得推荐的方法。

    为了后面的叙述方便,这里把所安排的RAM 空间范围的大小记为:stage2_size(字节),把起始地址和终止地址分别记为:stage2_start 和 stage2_end(这两个地址均以 4 字节边界对齐)。因此:

    stage2_end = stage2_start + stage2_size

    另外,还必须确保所安排的地址范围的的确确是可读写的RAM 空间,因此,必须对你所安排的地址范围进行测试。具体的测试方法可以采用类似于blob 的方法,也即:以 memory page 为被测试单位,测试每个 memory page 开始的两个字是否是可读写的。为了后面叙述的方便,我们记这个检测算法为:test_mempage,其具体步骤如下:

     【1】先保存 memory page 一开始两个字的内容。

     【2】向这两个字中写入任意的数字。比如:向第一个字写入 0x55,第 2 个字写入 0xaa。

     【3】 然后,立即将这两个字的内容读回。显然,我们读到的内容应该分别是 0x55 和 0xaa。如果不是,则说明这个 memory page 所占据的地址范围不是一段有效的 RAM 空间。

     【4】再向这两个字中写入任意的数字。比如:向第一个字写入 0xaa,第 2 个字中写入 0x55。

     【5】然后,立即将这两个字的内容立即读回。显然,我们读到的内容应该分别是 0xaa 和 0x55。如果不是,则说明这个 memory page 所占据的地址范围不是一段有效的 RAM 空间。

     【6】恢复这两个字的原始内容。测试完毕。

    为了得到一段干净的RAM 空间范围,我们也可以将所安排的 RAM 空间范围进行清零操作。

    1.3,加载Bootloader第二阶段代码到RAM空间,拷贝时要确定两点:(1) stage2 的可执行映象在固态存储设备的存放起始地址和终止地址;(2) RAM 空间的起始地址。Boot Loader启动过程分析 - singleboy - singleboy的博客

    1.4,设置好堆栈,强调下堆和栈的区别:栈区(stack) 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈;堆区(heap) 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。程序的局部变量存在于(栈)中,全局变量存在于(静态区 )中,动态申请数据存在于( 堆)中全局变量实际上是存在一个(一般来说正常的编译器)可读可写的内存空间,这个空间是在你写程序编译好的空间地址(由编译器决定),是固定的。

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

    1.5,跳转到第二阶段(Stage2)代码入口,在上述一切就绪后,就可以跳转到Boot Loader的Stage2执行了,在ARM系统中是通过修改PC寄存器为合适的地址来实现的。如U-Boot中是这样实现的:

    ldr pc, _start_armboot
    start_armboot是第二阶段(Stage2)的C程序的入口点。start_armboot是U-Boot执行的第一个C语言函数,完成系统初始化工作,进入主循环,处理用户输入的命令。

    2,Bootloader的第二阶段(Stage2)工作流程

    • 初始化本阶段要使用到的硬件设备
    • 检测系统内存映射
    • 加载内核映像和根文件系统映像
    • 设置内核的启动参数
    • 启动内核

    2.1,初始化本阶段要使用到的硬件设备,这通常包括:

    (1)设置时钟、初始化至少一个串口,以便和终端用户进行 I/O 输出信息;(2)初始化计时器等。在初始化这些设备之前,也可以重新把 LED 灯点亮,以表明我们已经进入 main_loop() 函数执行。

    board_init函数设置MPLL、改变系统时钟,它是开发板相关的函数,在board/samsung/smdk2440/smdk2440.c中实现。值得注意的是board_init函数还保存了机器类型ID,这将在调用内核的时候传递给内核。代码如下:

    gd->bd->bi_arch_number = MACH_TYPE_S3C2440;   //值为362

    串口的初始化函数主要是serial_init,它设置UART控制器,是CPU相关的函数。

    2.2,检测系统内存映射(memory map)

    所谓内存映射就是指在整个4GB 物理地址空间中有哪些地址范围被分配用来寻址系统的RAM 单元。比如,在SA-1100 CPU 中,从0xC000,0000 开始的512M 地址空间被用作系统的RAM 地址空间,而在Samsung S3C44B0X CPU 中,从 0x0c00,0000 到 0x1000,0000 之间的 64M 地址空间被用作系统的 RAM 地址空间。虽然CPU 通常预留出一大段足够的地址空间给系统 RAM,但是在搭建具体的嵌入式系统时却不一定会实现 CPU 预留的全部 RAM 地址空间。也就是说,具体的嵌入式系统往往只把 CPU 预留的全部 RAM 地址空间中的一部分映射到 RAM 单元上,而让剩下的那部分预留 RAM 地址空间处于未使用状态。由于上述这个事实,因此 Boot Loader 的 stage2 必须在它想干点什么 (比如,将存储在 flash 上的内核映像读到 RAM 空间中) 之前检测整个系统的内存映射情况,也即它必须知道 CPU 预留的全部 RAM 地址空间中的哪些被真正映射到 RAM 地址单元,哪些是处于 "unused" 状态的。

    对于smdk2440的开发板,其内存分布是明确的,一般内存起始地址为0x3000 0000,大小为64M = 0x0400 0000。代码如下:

    int dram_init(void)

    {

         gd->bd->bi_dram[0] . start = PHYS_SDRAM_1;          //即0x3000 0000

         gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;  //即0x0400 0000

    //这两个值都定义在include/configs/smdk2440.h中

    }

    2.3,将内核映像和根文件系统映像从Flash上读到RAM空间中。

    【1】 规划内存占用的布局

    这里包括两个方面:(1)内核映像所占用的内存范围;(2)根文件系统所占用的内存范围。在规划内存占用的布局时,主要考虑基地址和映像的大小两个方面。

    对于内核映像,一般将其拷贝到从(MEM_START+0x8000) 这个基地址开始的大约1MB大小的内存范围内(嵌入式 Linux 的内核一般都不操过 1MB)。为什么要把从 MEM_START 到 MEM_START+0x8000 这段 32KB 大小的内存空出来呢?这是因为 Linux 内核要在这段内存中放置一些全局数据结构,如:启动参数和内核页表等信息。

    而对于根文件系统映像,则一般将其拷贝到 MEM_START+0x0010,0000 开始的地方。如果用 Ramdisk 作为根文件系统映像,则其解压后的大小一般是1MB。

    【2】从 Flash 上拷贝

    由于像 ARM 这样的嵌入式 CPU 通常都是在统一的内存地址空间中寻址 Flash 等固态存储设备的,因此从 Flash 上读取数据与从 RAM 单元中读取数据并没有什么不同。用一个简单的循环就可以完成从 Flash 设备上拷贝映像的工作:

    while(count) {

    *dest++ = *src++; /* they are all aligned with word boundary */

    count -= 4; /* byte number */

    };

    2.4,为内核设置启动参数。

    应该说,在将内核映像和根文件系统映像拷贝到 RAM 空间中后,就可以准备启动 Linux 内核了。但是在调用内核之前,应该作一步准备工作,即:设置 Linux 内核的启动参数。

    U-Boot 是通过标记列表向内核传递参数。

    setup_memory_tags

    setup_commandline_tag

    这两个标记列表定义在arch/arm/lib/bootm.c中,需要在定义命令的文件include/configs/smdk2440.h中定义两个命令

    #define CONFIG_SETUP_MEMORY_TAGS  1

    #define CONFIG_CMDLINE_TAG                  1

    Linux 2.4.x 以后的内核都期望以标记列表(tagged list)的形式来传递启动参数。启动参数标记列表以标记ATAG_CORE 开始,以标记 ATAG_NONE 结束。每个标记由标识被传递参数的 tag_header 结构以及随后的参数值数据结构来组成。数据结构 tag 和 tag_header 定义在 Linux 内核源码的/arch/arm/include/asm/setup.h 头文件中:  

    /* The list ends with an ATAG_NONE node. */

    #define ATAG_NONE 0x00000000

    struct tag_header {

    u32 size; /* 注意,这里size是字数为单位的 */

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

      /*
       * Acorn specific
       */
      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 的代码如下:

    params = (struct tag *)BOOT_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_next(params);  

    其中,BOOT_PARAMS 表示内核启动参数在内存中的起始基地址,指针 params 是一个 struct tag 类型的指针。宏 tag_next() 将以指向当前标记的指针为参数,计算紧临当前标记的下一个标记的起始地址。注意,内核的根文件系统所在的设备ID就是在这里设置的。

    下面是设置内存映射情况的示例代码:  

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

    if(memory_map[i].used) {

    params->hdr.tag = ATAG_MEM;

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

    params->u.mem.start = memory_map[i].start;

    params->u.mem.size = memory_map[i].size;

    params = tag_next(params);
      }

    }

    可以看出,在 memory_map[]数组中,每一个有效的内存段都对应一个 ATAG_MEM 参数标记。 Linux 内核在启动时可以以命令行参数的形式来接收信息,利用这一点我们可以向内核提供那些内核不能自己检测的硬件参数信息,或者重载(override)内核自己检测到的信息。比如,我们用这样一个命令行参数字符串"console=ttyS0,115200n8"来通知内核以 ttyS0 作为控制台,且串口采用 "115200bps、无奇偶校验、8位数据位"这样的设置。下面是一段设置调用内核命令行参数字符串的示例代码:  

    char *p;

     /* eat leading white space */

     for(p = commandline; *p == ' '; p++)

      ;

     /* skip non-existent command lines so the kernel will still

      * use its default command line.

     */

     if(*p == '\0')

     return;

     params->hdr.tag = ATAG_CMDLINE;

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

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

     params = tag_next(params);

     

    请注意在上述代码中,设置 tag_header 的大小时,必须包括字符串的终止符'\0',此外还要将字节数向上圆整4个字节,因为 tag_header 结构中的size 成员表示的是字数。

    下面是设置 ATAG_INITRD 的示例代码,它告诉内核在 RAM 中的什么地方可以找到 initrd 映象(压缩格式)以及它的大小: 

    params->hdr.tag = ATAG_INITRD2;

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

    params->u.initrd.start = RAMDISK_RAM_BASE;

    params->u.initrd.size = INITRD_LEN;

    params = tag_next(params);

     
    下面是设置 ATAG_RAMDISK 的示例代码,它告诉内核解压后的 Ramdisk 有多大(单位是KB):

     

    params->hdr.tag = ATAG_RAMDISK;

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

    params->u.ramdisk.start = 0;

    params->u.ramdisk.size = RAMDISK_SIZE; /* 请注意,单位是KB */

    params->u.ramdisk.flags = 1; /* automatically load ramdisk */

    params = tag_next(params);

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

    static void setup_end_tag(void)

    {

    params->hdr.tag = ATAG_NONE;

    params->hdr.size = 0;

    }

    2.5,启动内核

    Boot Loader 调用 Linux 内核的方法是直接跳转到内核的第一条指令处,也即直接跳转到 MEM_START+0x8000 地址处。在跳转时,下列条件要满足:

    【1】CPU 寄存器的设置:

    R0=0;

    注:

    @R1=机器类型 ID;关于 Machine Type Number,可以参见 linux/arch/arm/tools/mach-types。

    @R2=启动参数标记列表在 RAM 中起始基地址;

    【2】CPU 模式:

    必须禁止中断(IRQs和FIQs);

    CPU 必须 SVC 模式;

    【3】Cache 和 MMU 的设置:

    MMU 必须关闭;

    指令 Cache 可以打开也可以关闭;

    数据 Cache 必须关闭;

    如果用 C 语言,可以像下列示例代码这样来调用内核:

    void (*theKernel)(int zero, int arch, u32 params_addr)
                 = (void (*)(int, int, u32))KERNEL_RAM_BASE;

    ……

    theKernel(0, ARCH_NUMBER, (u32) kernel_params_start); 
    注意,theKernel()函数调用应该永远不返回的。如果这个调用返回,则说明出错。

    对于ARM构架的CPU来说,都是通过../lib_arm/bootm.c中的do_bootm_linux函数来启动内核的。这个函数中,设置标记列表,最后通过

    theKernel = (void (*)(int, int, uint))images->ep;

    调用内核。其中,theKernel 指向内核存放的地址(对于ARM构架的CPU,通常这个地址是0x3000 8000)。传递的3个参数如下:

    void (*theKernel)(int zero, int arch, uint params);

    R0: 0

    R1: 机器类型ID -- gd->bd->bi_arch_number = MACH_TYPE_S3C2440;   //值为362

    R2: 启动参数标记列表在RAM中的起始地址 0x3000 0100

    五、 关于串口终端

    在 boot loader 程序的设计与实现中,没有什么能够比从串口终端正确地收到打印信息能更令人激动了。此外,向串口终端打印信息也是一个非常重要而又有效的调试手段。但是,我们经常会碰到串口终端显示乱码或根本没有显示的问题。造成这个问题主要有两种原因:(1) boot loader 对串口的初始化设置不正确。(2) 运行在 host 端的终端仿真程序对串口的设置不正确,这包括:波特率、奇偶校验、数据位和停止位等方面的设置。

    此外,有时也会碰到这样的问题,那就是:在 boot loader 的运行过程中我们可以正确地向串口终端输出信息,但当 boot loader 启动内核后却无法看到内核的启动输出信息。对这一问题的原因可以从以下几个方面来考虑:

    (1) 首先请确认你的内核在编译时配置了对串口终端的支持,并配置了正确的串口驱动程序。

    (2) 你的 boot loader 对串口的初始化设置可能会和内核对串口的初始化设置不一致。此外,对于诸如 s3c44b0x 这样的 CPU,CPU 时钟频率的设置也会影响串口,因此如果 boot loader 和内核对其 CPU 时钟频率的设置不一致,也会使串口终端无法正确显示信息。

    (3) 最后,还要确认 boot loader 所用的内核基地址必须和内核映像在编译时所用的运行基地址一致,尤其是对于 uClinux 而言。假设你的内核映像在编译时用的基地址是 0xc0008000,但你的 boot loader 却将它加载到 0xc0010000 处去执行,那么内核映像当然不能正确地执行了。

    六、 结束语

    Boot Loader 的设计与实现是一个非常复杂的过程。如果能从串口收到那激动人心的

    "uncompressing linux

    .................. done,

    booting the kernel……"

    内核启动信息,说明boot loader 已经成功地转起来了!。

    展开全文
  • 一、Boot Loader概念和功能 1、嵌入式Linux软件结构与分布在一般情况下嵌入式Linux系统中软件主要分为以下部分:(1)引导加载程序:其中包括内部ROM中固化启动代码和Boot Loader两部分。而这个内部固化ROM...

    一、Boot Loader的概念和功能
     
     
    1、嵌入式Linux软件结构与分布
    在一般情况下嵌入式Linux系统中的软件主要分为以下及部分:
    (1)引导加载程序:其中包括内部ROM中的固化启动代码和Boot Loader两部分。
    而这个内部固化ROM是厂家在芯片生产时候固化的,作用基本上是引导Boot Loader。有的芯片比较复杂,比如Omap3,他在flash中没有代码的时候有许多启动方式:USB、UART或以太网等等。而S3C24x0则很简单,只有Norboot和Nandboot。
    (2)Linux kernel 和drivers。
    (3)文件系统。
    包括根文件系统和建立于Flash内存设备之上的文件系统(EXT4、UBI、CRAMFS等等)。它是提供管理系统的各种配置文件以及系统执行用户应用程序的良好运行环境的载体。
    (4)应用程序。用户自定义的应用程序,存放于文件系统之中。
    在Flash 存储器中,他们的 一般分布如下:
     
    但是以上只是大部分情况下的分布,也有一些可能根文件系统是initramfs,被一起压缩到了内核映像里,或者没有Bootloader参数区,等等。

    2、在嵌入式Linux中为什么要有BootLoader
    在linux内核的启动运行除了内核映像必须在主存的适当位置,CPU还必须具备一定的条件:
    1. CPU 寄存器的设置:R0=0;R1=Machine ID(即Machine Type Number,定义在linux/arch/arm/tools/mach-types);R2=内核启动参数在 RAM 中起始基地址;
    2. CPU 模式:必须禁止中断(IRQs和FIQs);CPU 必须 SVC 模式;
    3. Cache 和 MMU 的设置:MMU 必须关闭;指令 Cache 可以打开也可以关闭;数据 Cache 必须关闭;         
     
    但是在CPU刚上电启动的时候,一般连内存控制器都没有配置过,根本无法在内存中运行程序,更不可能处在Linux内核的启动环境中。为了初始化CPU及其他外设,使得Linux内核可以在系统主存中跑起来,并让系统符合Linux内核启动的必备条件,必须要有一个先于内核运行的程序,他就是所谓的引导加载程序(Boot Loader)。
    而Boot Loader并不是Linux才需要,是几乎所有的运行操作系统的设备都具备的。我们的PC的BOIS就是Boot Loader的一部分(只是前期引导,后面一般还有外存中的各种Boot Loader),对于Linux PC来说,Boot Loader = BIOS + GRUB/LILO。

    3、Boot Loader的功能和选择
        通过上面的讲述,我们可以知道:Boot Loader是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境,最后从别处(Flash、以太网、UART)载入内核映像并跳到入口地址。
    由于BootLoader直接操作硬件,所以她严重依赖于硬件,而且依据所引导的操作系统的不同,也有不同的选择对于嵌入式世界中更是如此。就S3C24x0而言,如果是引导Linux,一般选用韩国的mizi公司设计的vivi或者DENX软件工程中心的U-boot,如果是引导Win CE,就选用Eboot。如果是开发StrongARM 构架下的LART,就可选用由Jan-Derk Bakker 和 Erik Mouw发布的Blob(Boot Loader Object)。如果是要引导eCos系统,就可以选用同是Redhat公司开发的Redboot。
         所以在嵌入式世界中建立一个通用的 BootLoader 几乎是不可能的,而有可能的是让一个 Boot Loader代码支持多种不同的构架和操作系统,并让她方便移植。U-boot就是支持多平台多操作系统的一个杰出代表。这也是为什么我喜欢用U-boot的原因,因为如果在开发S3C2440时熟悉了U-boot,再转到别的平台的时候就可以很快地完成这个平台下的U-boot移植,而且U-boot的代码结构越来越合理,对于新功能的添加也十分容易。
         值得一提的是国内的一个开源项目maxwit中的g-bios也是一个不错的开源BootLoader,同样支持多平台。
     
    展开全文
  • Boot Loader概念和功能

    千次阅读 2011-03-23 15:38:00
    牛人博客转载...而这个内部固化ROM是厂家在芯片生产时候固化作用基本上是引导Boot Loader。有的芯片比较复杂,比如Omap3,他在flash中没有代码时候有许多启动方式:USB、UART或以太
  • 而这个内部固化ROM是厂家在芯片生产时候固化作用基本上是引导Boot Loader。有的芯片比较复杂,比如Omap3,他在flash中没有代码时候有许多启动方式:USB、UART或以太网等等。而S3C24x0则很简单,只有Norboot和...
  • IoT网关负责海量物联网端侧设备与物联网云端应用沟通,发挥着承上启下重要作用,是实现万物互联关键一环。IoT网关已广泛应用于工业、农业、畜牧业、智能家居、智慧城市等等垂直行业。 LiteCoG(Lite Connect ...
  • 在文件最后加入Nand Flash的初始化函数,该函数在后面Nand Flash的操作都要用到。 u-boot运行到第2阶段会进入start_armboot()函数。其中nand_init()函数是对nand flash的最 初初始化函数。nand_init()函数在两个...
  • 以STM32为例,SWD、串口1,BOOT0脚,flash芯片建议作用标配硬件。 开发阶段调试就是确定下功能需求后,功能实现阶段,这一阶段调试主要依靠就是SWD在线调试串口打印调试。串口1还可以用于STM32代码烧写,产品...
  • 始下一个测量循环,因此该频率计具有连续测量的功能,同时实现量程的自动转 换。 数字频率计的硬件框图如图2.1 所示。 由此可以看出该频率计主要由八部分组成,分别是: (1)待测信号的放大整形电路 因为数字频率计的...
  • BootLoader启动过程分析

    2017-12-07 16:29:57
    一、 Boot Loader概念和功能 1、嵌入式Linux软件结构与分布在一般情况下嵌入式Linux系统中软件主要分为以下部分: ...有的芯片比较复杂,比如Omap3,他在flash中没有代码时候有许多启动方式
  • bootloader 启动过程

    千次阅读 2016-08-18 17:37:48
    一、 Boot Loader概念和功能 1、嵌入式Linux软件结构与分布在一般情况下嵌入式Linux系统中软件主要分为以下部分: (1)引导加载程序:其中...有的芯片比较复杂,比如Omap3,他在flash中没有代码时候有许多
  • Boot Loader启动过程分析

    千次阅读 2017-02-12 17:02:13
    一、 Boot Loader概念和功能  1、嵌入式Linux软件结构与分布在一般情况下嵌入式Linux系统中软件主要分为以下部分: ...有的芯片比较复杂,比如Omap3,他在flash中没有代码时候有许多启动方
  • 一、 Boot Loader概念和功能  1、嵌入式Linux软件结构与分布在一般情况下嵌入式Linux系统中软件主要分为以下部分: ...有的芯片比较复杂,比如Omap3,他在flash中没有代码时候有许
  • Boot Loader启动过程分析一、 Boot Loader概念和功能 1、嵌入式Linux软件结构与分布在一般情况下嵌入式Linux系统中软件主要分为以下部分:(1)引导加载程序:其中包括内部ROM中固化启动代码和Boot Loader两...
  • 单片机AT89S51强大的功能可为许多嵌入式控制应用系统提供高性价比的解决方案。 AT89C51芯片的引脚结构如图1所示: 1.1 功能特性概括: AT89S51提供以下标准功能:40个引脚、4K Bytes Flash片内程序存储器、128 ...
  • u-boot移植手册

    2010-08-17 17:12:00
    一、Boot Loader概念和功能 1、嵌入式Linux软件结构与分布 在一般情况下嵌入式Linux系统中软件主要分为以下部分: (1)引导加载程序:其中包括内部ROM中固化启动代码和Boot Loader两部分。...
  • 芯片为LQFP64封装, 内部有128 KB Flash和20 KB RAM,采用32位ARM CortexTM-M3内核, 最高支持主频72 MHz,拥有2个SPI接口、 2个USART接口、1个USB接口、2个I2C接口和7个定时器。支持SWD和JTAG调试模式IAP和ISP...
  • 1 方案选择 1.1 微控制器方案选择 方案一:采用瑞萨公司所生产 R5F100LEA 单片机为主 控芯片,单片机运算功能强,软件编程灵活、自由度大。且 功耗低,体积小,技术成熟;方案二:采用 51 系列单片机, 其运用广泛...
  • 嵌入式课件

    2012-04-06 16:48:49
    5.6.2 采用专用芯片的触摸屏控制接口 5.6.3 S3C2410A的触摸屏接口电路 思考题与习题 第6章 嵌入式系统总线接口 6.1 串行接口 6.1.1 串行接口基本原理与结构 6.1.2 S3C2410A的UART 6.1.3 与S3C2410A UART连接的串行...
  • Neon2013动画软件

    2012-12-22 22:10:52
    2、NeonEdit节拍编辑菜单下增加Flash/SWF转网格[TOL/COT]功能 2012-04-06==================================== 1、升级软件保护机制 2、增加编译系统:2048x16 3、修改 NeonPlay 菜单下打开不起作用的错误 4...
  • 5、NeonEdit 增加单线芯片的1024X16控制器的输出修改 6、NeonPlay 中修改属性设置过行列数后,再次显示属性时显示行列数都是1的错误 7、NeonPlay 修改图元分割时默认是图元分割 8、NeonPlay 修改花样编辑自动花样V型...
  • LED动画软件neon2013

    2013-01-12 19:46:19
    5、NeonEdit 增加单线芯片的1024X16控制器的输出修改 6、NeonPlay 中修改属性设置过行列数后,再次显示属性时显示行列数都是1的错误 7、NeonPlay 修改图元分割时默认是图元分割 8、NeonPlay 修改花样编辑自动花样V型...
  • 什么是VLAN

    2013-10-23 09:59:12
    这样就等于用一个物理端口确实现了两个逻辑接口的功能,这样就将原本只能划分一个网段的情形,扩展到了可以划分2个或者更多个网段的情形。这些网段因为是在逻辑接口下创建的,所以称之为虚拟局域网VLAN。  这是在...

空空如也

空空如也

1 2
收藏数 34
精华内容 13
关键字:

flash芯片的功能及作用