linux bootloader原理,Bootloader原理详解

文章一:

1.BootLoader 的介绍

引导加载程序BootLoader 是系统加电后运行的第一段代码。我们熟悉的PC 中的引导程序一般由BIOS

和位于硬盘MBR中的OS bootloader(例如LILO 或者GRUB)一起组成。然而在嵌入式系统中通常没有像BIOS

那样的固件程序(有的嵌入式CPU 有),因此整个系统的加载启动任务就完全由bootloader 来完成。比如在一个基于ARM920T

core 的嵌入式系统中,系统在上电或复位时都从地址0x00000000

开始执行,而在这个地址处安排的通常就是系统的BootLoader 程序。

简单地说,BootLoader

就是在操作系统内核或用户应用程序运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核或用户应用程序准备好正确的环境。

Bootloader 是依赖于硬件而实现的,特别是在嵌入式系统中。不同的体系结构需求的Bootloader

是不同的;除了体系结构,Bootloader

还依赖于具体的嵌入式板级设备的配置。也就是说,对于两块不同的嵌入式板而言,即使它们基于相同的CPU

构建,运行在其中一块电路板上的Bootloader,未必能够运行在另一块电路开发板上。

Bootloader

的启动过程可以是单阶段的,也可以是多阶段的。通常多阶段的Bootloader能提供更为复杂的功能,以及更好的可移植性。从固态存储设备上启动的Bootloader

大多数是二阶段的启动过程,也即启动过程可以分为stage 1 和stage 2 两部分。

2.BootLoader 操作模式

大多数bootloader

都包含两种不同的操作模式:“启动加载”模式和“下载”模式,这种区别对于开发人员才有意义。但从最终用户的角度看,Bootloader

的作用永远就是用来加载操作系统,而并不存在所谓的启动加载模式与下载工作模式的区别。

启动加载模式:这种模式也称为“自主”模式,即Bootloader 从目标机上的某个固体存储设备上将操作系统加载到RAM

中运行,整个过程没有用户的介入。这种模式是Bootloader的正常工作模式,因此当以嵌入式产品发布的时候,Bootloader

必须工作在这种模式下。

下载模式:在这种模式下,目标机上的Bootloader

将通过串口或者网络连接或者其它通信手段从主机下载文件,比如:下载内核镜像和根文件系统镜像等。从主机下载的文件通常首先被Bootloader

保存到目标机的RAM 中,然后被Bootloader 写到目标机上的FLASH 类固态存储设备中。Bootloader

的这种模式通常在第一次安装内核与根文件系统时使用;此外,以后的系统更新也会使用Bootloader

的这种工作模式。工作于这种模式下的Bootloader 通常都会向它的中断用户提供一个简单的命令行接口。

3.bootloader 的功能说明和结构框架

在设计时,我们将Booloader 分为两个阶段:阶段1 (stage 1) 和阶段2 (stage 2):

阶段1:主要用汇编语言,它主要进行与CPU 核以及存储设备密切相关的处理工作,进行一些必要的初始化工作,是一些依赖于CPU

体系结构的代码,为了增加效率以及因为涉及到协处理器的设置,只能用汇编编写,这部分直接在FLASH 中执行;

阶段2:一般用C 语言来实现一般的流程以及对板级的一些驱动支持,这部分会被拷贝到RAM

中执行。这样设计的话,代码具有更好的可读性与可移植性:若对于相同的CPU 以及存储设备,要增加外设支持,阶段1

的代码可以维护不变,只对阶段2 的代码进行修改;若要支持不同的CPU,则基础代码只需在阶段1 中修改。

Bootloader 的阶段1(stage1)通常包括下面的步骤(以执行的先后顺序):

·硬件设备初始化;

·为加载Boot Loader的stage2准备 RAM 空间;

·拷贝Boot Loader的stage2 到RAM空间中;

·设置好堆栈;

·跳转到 stage2 的 C 入口点。

Bootloader 的阶段2(stage2)通常包括下面的步骤(以执行的先后顺序):

·初始化本阶段要使用到的硬件设备;

·检测系统内存映射(memory map);

·将kernel 映像和根文件系统映像从flash上读到 RAM 空间中;

·为内核设置启动参数;

·调用内核。

文章二

在将Linux内核移植到ARM处理器时,有一个问题不能忽视,那就是移植Bootloader,Linux内核启动部分的代码需要判断从Bootloader传递过来的寄存器值。

为什么需要Bootloader呢?这与硬件本身的启动方式有关,有了Bootloader可以方便系统的开发。通过这段Bootloader小程序,可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。

(1) Bootloader所支持的CPU和嵌入式板

每种不同的CPU体系结构都有不同的Bootloader,有些Bootloader也支持多种体系结构的CPU,如Uboot。除了依赖于CPU的体系结构外,Bootloader实际上也依赖于具体的嵌入式板级设备的配置。这也就是说,对于两块不同的嵌入式板而言,即使它们是基于同一种CPU而构建的,要想让运行在一块板子上的Bootloader程序也能运行在另一块板子上,通常也都需要修改Bootloader的源程序。

(2) Bootloader的安装媒介

系统加电或复位后,所有的CPU通常都从某个预先安排的地址上取指令。比如,基于ARM内核的CPU在复位时通常都从地址0x00000000取它的第一条指令。而基于CPU构建的嵌入式系统通常都有某种类型的固态存储设备(比如:rom、eeprom或Flash等)被映射到这个预先安排的地址上。因此在系统加电后,CPU将首先执行Bootloader程序。

(3) 用来控制Bootloader的设备或机制

主机和目标机之间一般通过串口建立连接,Bootloader软件在执行时通常会通过串口来进行I/O,比如:输出打印信息到串口,从串口读取用户控制字符等。

(4) Bootloader的启动过程是单阶段还是多阶段

通常多阶段的boot-loader能提供更为复杂的功能,以及更好的可移植性。从固态存储设备上启动的Bootloader大多都是2阶段的启动过程,即启动过程可以分为stage

1和stage2两部分。

(5) Bootloader的操作模式

大多数Bootloader都包含两种不同的操作模式:“启动加载”模式和“下载”模式,这两种区别不是很大。从最终用户的角度看,Bootloader的作用就是用来加载操作系统,而并不存在所谓的启动加载模式与下载工作模式的区别。

启动加载模式:这种模式也称为“自主”模式。即Bootloader从目标机上的某个固态存储设备上将操作系统加载到SDRAM中运行,整个过程并没有用户的介入。这种模式是Bootloader的正常工作模式,因此在嵌入式产品发布时,Bootloader必须工作在这种模式下。

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

(6) Bootloader与主机之间进行文件传输所用的通信设备及协议

最常见的情况就是,目标机上的Bootloader通过串口与主机之间进行文件传输,传输协议通常是xmodem/ymodem/zmodem协议中的一种。但是,串口传输的速度是有限的,因此通过以太网连接并借助tftp协议来下载文件是个更好的选择。此外,主机方所用的软件也要考虑。比如,在通过以太网连接和tftp协议来下载文件时,主机方必须有一个软件用来提供tftp服务。

(7) Bootloader的主要任务与典型结构框架

首先做一个假定:假定内核映像与根文件系统映像都被加载到SDRAM中运行。因为,在嵌入式系统中内核映像与根文件系统映像也可以直接在ROM或Flash这样的固态存储设备中直接运行,但这种做法无疑是以运行速度的牺牲为代价的。从操作系统的角度看,Bootloader的总目标就是正确地调用内核来执行。

另外,由于Bootloader依赖于CPU的体系结构,因此大多数Bootloader都分为stage 1和stage

2两大部分。依赖于CPU体系结构的代码,比如设备初始化代码等,通常都放在stage1中,而且通常都用ARM汇编语言来实现,以达到短小精悍的目的。而stage

2则通常用C语言来实现,这样可以实现更复杂的功能,而且代码会具有更好的可读性和可移植性。

(8) 串口终端

Bootloader程序设计与实现后,串口终端就能正确地收到打印信息了。此外,向串口终端打印信息也是一个非常重要而又有效的调试手段。

但是,经常会碰到串口终端显示乱码或根本没有显示的问题。发生这样的问题主要有两种原因:(1)

Bootloader对串口的初始化设置不正确;(2)

运行在host端的终端仿真程序对串口的设置不正确,这包括波特率、奇偶校验、数据位和停止位等方面的设置。

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

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

其次Bootloader对串口的初始化设置可能会和内核对串口的初始化设置不一致,例如,Bootloader和内核对其CPU时钟频率的设置不一致。

最后,还要确认Bootloader所用的内核基地址必须和内核映像在编译时所用的运行基地址一致,尤其是对于ARM

Linux而言。假设内核映像在编译时用的基地址是0xc0028000,但Bootloader却将它加载到0xc0010000处去执行,那么内核映像就不能正确地执行。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以进行编辑,复制,打印的pdf 第1章 Linux快速入门 1 1.1 嵌入式Linux基础 1 1.1.1 Linux发展概述 1 1.1.2 Linux作为嵌入式操作系统的优势 2 1.1.3 Linux发行版本 3 1.1.4 如何学习Linux 4 1.2 Linux安装 5 1.2.1 基础概念 5 1.2.2 硬件需求 7 1.2.3 安装准备 7 1.2.4 安装过程 8 1.3 Linux文件及文件系统 11 1.3.1 文件类型及文件属性 11 1.3.2 文件系统类型介绍 13 1.3.3 Linux目录结构 14 1.4 实验内容——安装Linux操作系统 17 本章小结 17 思考与练习 18 第2章 Linux基础命令 19 2.1 Linux常用操作命令 19 2.1.1 用户系统相关命令 20 2.1.2 文件目录相关命令 27 2.1.3 压缩打包相关命令 38 2.1.4 比较合并文件相关命令 40 2.1.5 网络相关命令 45 2.2 Linux启动过程详解 50 2.2.1 概述 51 2.2.2 内核引导阶段 51 2.2.3 init阶段 52 2.3 Linux系统服务 54 2.3.1 独立运行的服务 55 2.3.2 xinetd设定的服务 56 2.3.3 设定服务命令常用方法 56 2.4 实验内容 57 2.4.1 在Linux下解压常见软件 57 2.4.2 定制Linux系统服务 58 本章小结 60 思考与练习 60 第3章 Linux下的C编程基础 61 3.1 Linux下C语言编程概述 61 3.1.1 C语言简单回顾 61 3.1.2 Linux下C语言编程环境概述 62 3.2 进入Vi 63 3.2.1 Vi的模式 63 3.2.2 Vi的基本流程 63 3.2.3 Vi的各模式功能键 65 3.3 初探Emacs 66 3.3.1 Emacs的基本操作 67 3.3.2 Emacs的编译概述 70 3.4 Gcc编译器 71 3.4.1 Gcc编译流程解析 71 3.4.2 Gcc编译选项分析 74 3.5 Gdb调试器 77 3.5.1 Gdb使用流程 78 3.5.2 Gdb基本命令 81 3.6 Make工程管理器 86 3.6.1 Makefile基本结构 86 3.6.2 Makefile变量 87 3.6.3 Makefile规则 90 3.6.4 Make管理器的使用 91 3.7 使用autotools 92 3.7.1 autotools使用流程 92 3.7.2 使用autotools所生成的Makefile 96 3.8 实验内容 98 3.8.1 Vi使用练习 98 3.8.2 用Gdb调试有问题的程序 99 3.8.3 编写包含多文件的Makefile 101 3.8.4 使用autotools生成包含多文件的Makefile 103 本章小结 105 思考与练习 105 第4章 嵌入式系统基础 106 4.1 嵌入式系统概述 106 4.1.1 嵌入式系统简介 106 4.1.2 嵌入式系统发展历史 107 4.1.3 嵌入式系统的特点 108 4.1.4 嵌入式系统的体系结构 108 4.1.5 几种主流嵌入式操作系统分析 109 4.2 ARM处理器硬件开发平台 111 4.2.1 ARM处理器简介 111 4.2.2 ARM体系结构简介 113 4.2.3 ARM9体系结构 113 4.2.4 S3C2410处理器详解 116 4.3 嵌入式软件开发流程 121 4.3.1 嵌入式系统开发概述 121 4.3.2 嵌入式软件开发概述 122 4.4 实验内容——使用JTAG烧写NAND Flash 128 本章小结 131 思考与练习 132 第5章 嵌入式Linux开发环境的搭建 133 5.1 嵌入式开发环境的搭建 133 5.1.1 嵌入式交叉编译环境的搭建 133 5.1.2 超级终端和Minicom配置及使用 135 5.1.3 下载映像到开发板 142 5.1.4 编译嵌入式Linux内核 145 5.1.5 Linux内核目录结构 149 5.1.6 制作文件系统 149 5.2 U-Boot移植 153 5.2.1 Bootloader介绍 153 5.2.2 U-Boot概述 155 5.2.3 U-Boot源码导读 156 5.2.4 U-Boot移植主要步骤 163 5.2.5 U-Boot常见命令 164 5.3 实验内容——移植Linux内核 164 本章小结 165 思考与练习 165 第6章 文件I/O编程 166 6.1 Linux系统调用及用户编程接口(API) 166 6.1.1 系统调用 166 6.1.2 用户编程接口(API) 167 6.1.3 系统命令 167 6.2 Linux中文件及文件描述符概述 168 6.3 不带缓存的文件I/O操作 168 6.3.1 open和close 168 6.3.2 read、write和lseek 170 6.3.3 fcntl 173 6.3.4 select 178 6.4 嵌入式Linux串口应用开发 183 6.4.1 串口概述 183 6.4.2 串口设置详解 184 6.4.3 串口使用详解 191 6.5 标准I/O开发 194 6.5.1 打开和关闭文件 194 6.5.2 文件读写 197 6.5.3 输入输出 198 6.6 实验内容 201 6.6.1 文件读写及上锁 201 6.6.2 多路复用式串口读写 204 本章小结 207 思考与练习 207 第7章 进程控制开发 208 7.1 Linux下进程概述 208 7.1.1 进程相关基本概念 208 7.1.2 Linux下的进程结构 210 7.1.3 Linux下进程的模式和类型 210 7.1.4 Linux下的进程管理 211 7.2 Linux进程控制编程 212 7.3 Linux守护进程 224 7.3.1 守护进程概述 224 7.3.2 编写守护进程 224 7.3.3 守护进程的出错处理 229 7.4 实验内容 232 7.4.1 编写多进程程序 232 7.4.2 编写守护进程 235 本章小结 238 思考与练习 239 第8章 进程间通信 240 8.1 Linux下进程间通信概述 240 8.2 管道通信 241 8.2.1 管道概述 241 8.2.2 管道创建与关闭 242 8.2.3 管道读写 244 8.2.4 标准流管道 246 8.2.5 FIFO 249 8.3 信号通信 253 8.3.1 信号概述 253 8.3.2 信号发送与捕捉 255 8.3.3 信号的处理 258 8.4 共享内存 264 8.4.1 共享内存概述 264 8.4.2 共享内存实现 265 8.5 消息队列 267 8.5.1 消息队列概述 267 8.5.2 消息队列实现 268 8.6 实验内容 272 8.6.1 管道通信实验 272 8.6.2 共享内存实验 275 本章小结 277 思考与练习 278 第9章 多线程编程 279 9.1 Linux下线程概述 279 9.1.1 线程概述 279 9.1.2 线程分类 280 9.1.3 Linux线程技术的发展 280 9.2 Linux线程实现 281 9.2.1 线程基本操作 281 9.2.2 线程访问控制 288 9.3 实验内容——“生产者消费者”实验 298 本章小结 302 思考与练习 303 第10章 嵌入式Linux网络编程 304 10.1 TCP/IP协议概述 304 10.1.1 OSI参考模型及TCP/IP参考模型 304 10.1.2 TCP/IP协议族 305 10.1.3 TCP和UDP 306 10.2 网络基础编程 308 10.2.1 socket概述 308 10.2.2 地址及顺序处理 309 10.2.3 socket基础编程 314 10.3 网络高级编程 322 10.4 ping源码分析 326 10.4.1 ping简介 326 10.4.2 ping源码分析 327 10.5 实验内容——NTP协议实现 345 本章小结 352 思考与练习 352 第11章 嵌入式Linux设备驱动开发 353 11.1 设备驱动概述 353 11.1.1 设备驱动简介及驱动模块 353 11.1.2 设备文件分类 354 11.1.3 设备号 355 11.1.4 驱动层次结构 355 11.1.5 设备驱动程序与外界的接口 355 11.1.6 设备驱动程序的特点 356 11.2 字符设备驱动编写 356 11.3 LCD驱动编写实例 363 11.3.1 LCD工作原理 363 11.3.2 LCD驱动实例 365 11.4 块设备驱动编写 374 11.4.1 块设备驱动程序描述符 374 11.4.2 块设备驱动编写流程 375 11.5 中断编程 381 11.6 键盘驱动实现 382 11.6.1 键盘工作原理 382 11.6.2 键盘驱动综述 383 11.6.3 键盘驱动流程 384 11.7 实验内容——skull驱动 394 本章小结 398 思考与练习 399 第12章 Qt图形编程 400 12.1 嵌入式GUI简介 400 12.1.1 Qt/Embedded 401 12.1.2 MiniGUI 401 12.1.3 Microwindows、Tiny X等 402 12.2 Qt/Embedded开发入门 402 12.2.1 Qt/Embedded介绍 402 12.2.2 Qt/Embedded信号和插槽机制 405 12.2.3 搭建Qt/Embedded开发环境 409 12.2.4 Qt/Embedded窗口部件 410 12.2.5 Qt/Embedded图形界面编程 414 12.2.6 Qt/Embedded对话框设计 416 12.3 实验内容——使用Qt编写“Hello,World”程序 420 本章小结 428

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值