bootloader如何固化?

本文探讨了Bootloader如何烧写到非易失性存储介质中,并介绍了编程器的概念及应用。文中还详细分析了不同处理器如何利用串口或JTAG下载线作为编程器进行Bootloader的烧写。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

来源:http://blog.chinaunix.net/u/21948/showart_274141.html

关于bootloader,先简要地总结一下。经过了第一个阶段的学习,对bootloader有了一个整体的认识,其实把它当作一个功能单元就可以了,职责就是完成从硬件加电到操作系统内核运行之前的所有工作,这些工作包括硬件检测、硬件初始化、加载kernel。这些工作怎么完成呢?按照功能分为两个部分比较合适,硬件检测和初始化功能实现作为stage1;加载kernel作为stage2。stage1完全依赖于硬件,这一部分用汇编语言实现;stage2与操作系统有关,一般用C语言来实现。在嵌入式系统的开发过程中,bootloader有两种选择,要么自行开发,要么移植。我还没有写过bootloader,只是移植过U-boot,使用过Redboot。

 
    这里讨论一个问题,bootloader如何烧写(固化)到非易失性存储介质(比如Nor Flash,NAND Flash等)里呢?
 
    讨论之前,先要理解编程器的概念。虽然学通信工程,应该对这些工具不陌生,但是本科下来,对这些概念确实没有深刻的印象。实际用到,才发现自己基础太差,只能努力的弥补。我写blog,很大程度上是对基础知识的巩固,相信基础扎实了,知识体系才可以慢慢的完善,才能最终胜任更高难度的工作。
 
    编程器也叫device programmer,是对非易失性存储介质和其他电可编程设备进行编程的工具。传统的编程器,需要把Flash(举例)从电路板上取下来,插到编程器的接口上,以完成擦除和烧写。现在的编程器发展的方向是ISP(In-System Programming,在系统可编程),就是指电路板上的空白器件可以编程写入最终用户代码,而不需要从电路板上取下器件。已经编程的器件也可以用ISP方式擦除或再编程,如Nor Flash支持重复擦写10万次左右。可见,ISP,智能编程器是发展的方向。
 
    利用编程器可以解决前面提高的问题,不仅可以烧写bootloader,还可以烧写kernel,fs等等。也就是都属于固化最终用户代码的过程。
 
    下面考虑两种实际情况:
    1、厂商已经提供固化的程序代码,不允许对其修改。那么这种情况下,用不到编程器。
    2、厂商提供的硬件没有固化代码,或者固化了部分代码(后面举例说明),这样就需要用到编程器。
 
    第一种情况是对最终用户而言,第二种情况则对开发者而言。也就是在嵌入式开发过程中,我们总是需要用到编程器,不管原来是否知道这个概念,即使是下载线,也可以认为是简单的编程器。要想利用编程器进行数据交换,完成烧写擦除等操作,就必须硬件连接、软件操作。当然,复杂的地方在软件操作,因为对不同的硬件,软件操作是不同的。有些厂商把编程器、编辑器、编译器、汇编器、链接器、调试器集成在一起,提供软硬件解决方案,在学校学习大多是这种集成环境了。比如51单片机的仿真器和Keil开发环境。也因为这个原因,对于每个环节反而没有了概念。在Linux下开发的时候,这些问题就都凸现出来了。不过早出来早解决,这样无论对于自己的认识,还是对于以后的发展,都是有利的。
 
    有些厂商为了方便用户下载代码和调试,在其处理器内部集成了一个小的ROM,事先固化一小段代码。因为容量有限,所以代码的功能有限,一般只是初始化串口,然后等待从串口输入数据。这样,串口线实际上就成为了编程器的硬件连接了。比如,Cirrus Logic 的EP93XX系列,它内部集成了一个BootROM,固化代码初始化串口,支持从串口下载数据。那么在Host端只需要相应的开发一个相同串口协议的download程序,就可以完成bootloader(EP93XX系列使用的是Redboot)烧写到Falsh里【注:这里的编程器就可以认为是download+RS-232交叉线】,然后从Falsh启动,有Redboot进行下面的工作。因为Redboot实现了串口传输协议和TFTP协议,就可以通过RS-232来进行控制,通过Ethernet完成大的映象文件如kernel和fs的下载固化。这样,从硬件上电,到最后系统启动的所有环节就都很清晰了。ATMEL的AT91RM9200内部也集成了一个ROM,固化代码,同样初始化串口,启动串口传输协议Xmodem,等待输入【注:这里的编程器就可以认为是loader+RS-232交叉线】。官方提供的loader就是完成把U-boot下载固化到flash里面。因为kernel和fs比较大,可以采用压缩,官方提供boot来完成从flash启动后自动解压过程。这样,从flash启动就慢了许多。
 
    还有些厂商为了节省ROM空间,提高集成度,不支持从ROM启动模式。比如三星公司的S3C2410等。这样一种简单的方法就是采用JTAG下载线作为编程器的硬件连接,完成其Bootloader(如Vivi)的烧写。在Windows环境下,针对JTAG硬件连接,编程器的软件有JFlash(JTAG for Flash),SJF,Flash Programmer等,还是比较丰富的。在Linux环境下,我所知道的有JFlash的Linux版本【注:在Linux下,这里的编程器就可以认为是JFlash+JTAG下载线,S3C2410是提供JTAG接口的】。因为学校实验室有S3C2410的实验箱,所以下个阶段会尝试以S3C2410为中心,进行详细深入的学习。其中之一就是bootloader的研究。那么就可以分成两个部分:一是Linux环境下Flash烧写工具JFlash的工作原理,完成移植工作。二是移植Vivi(U-boot)。在这个过程中,重点学习一下U-boot的移植和组织形式,掌握JTAG对应的软件JFlash的源代码编写方法。然后尝试自己写一个简单的bootloader。我想,这样学习会更加有效。
 
    总结完之后,对bootloader的理解有了一个新的概念。把bootloader理解成烧写工具和功能实现两个部分,对于实际理解会更有帮助。这样,拿到一块板子,首先看它提供的启动方式有那些,是否支持从ROM启动,是否支持从Flash启动等等,针对启动方式,选择bootloader固化方式,如果提供编程器软件资源最好,如果不提供,那么要么编写,要么移植。不过,大而全在商业中是行不通的,如同周立功所说,专注于自己最擅长的,其他的外包。这是工作后应该信奉的原则现在还是以研究为目的,尽量弄明白每个环节的工作原理,形成清晰的认识,然后选择自己最为擅长的,作为谋生的手段。即使工作后,各个环节还是应该有所射猎,知识都是相通的,可能从别的方面得到启发,解决自己手头的难题。
 
    下一步,集中精力弄清楚研究JTAG和JFlash的原理。
 
### Python 运算符使用指南 Python 中的运算符是编程的核心组件之一,涵盖了多种类型和功能。以下是关于 Python 运算符的具体介绍,包括其分类、用法及注意事项。 #### 1. 赋值运算符 赋值运算符用于将表达式的值分配给变量。除了简单的等于号 (=),还有复合赋值运算符,如模运算符 (%=)、指数运算符 (**=) 和向下取整除法运算符 (//=)[^1]。 - **模数和赋值 (%)** 使用 `a %= 20` 等价于 `a = a % 20`,即先计算 `a` 对 20 的余数,再将其结果重新赋值给 `a`。 - **指数和赋值 (**=)** 使用 `a **= 2` 等价于 `a = a ** 2`,表示计算 `a` 的平方并将结果赋回给 `a`[^1]。 - **向下取整并赋值 (//=}** 执行 `a //= 2` 等价于 `a = a // 2`,意味着对 `a` 执行向下取整除法后再将结果赋值给 `a`[^1]。 #### 2. 条件运算符(三元运算符Python 支持一种简洁的形式来替代传统 `if-else` 结构,称为条件表达式或三元运算符。语法如下: ```python x = first_value if condition else second_value ``` 此结构会在满足条件时返回第一个值,否则返回第二个值。例如: ```python max_val = a if a > b else b ``` 这段代码通过单行实现了两数的最大值比较[^1]。 #### 3. 特殊运算符 特殊运算符主要用于更复杂的逻辑判断或数据操作。 - **身份运算符 (`is`, `is not`)** 这些运算符用于验证两个对象是否指向同一个内存位置,而非仅仅比较它们的内容相等性。例如: ```python a = [1, 2, 3] b = a print(a is b) # 输出 True ``` - **成员运算符 (`in`, `not in`)** 成员运算符用于检测某项是否存在特定序列中,适用于列表、字符串、集合等多种容器类型。例如: ```python letters = 'abcde' print('a' in letters) # 输出 True ``` #### 4. 运算符优先级 当一个表达式包含多个不同类型的运算符时,Python 将依据预设的优先级规则依次解析执行。通常情况下,括号内的子表达式拥有最高优先权;而诸如 lambda 表达式则处于较低层次。 #### 5. 运算符重载 Python 允许开发者针对自定义类重新定义标准运算符的行为,这一过程被称为运算符重载[^2]。例如,可以通过实现特殊的魔术方法(magic methods)使自己的对象支持加减乘除或其他常见操作。下面展示了一个简单例子——向量类支持加法运算: ```python class Vector: def __init__(self, components): self.components = components def __add__(self, other): new_components = [] for i in range(len(self.components)): new_components.append(self.components[i] + other.components[i]) return Vector(new_components) v1 = Vector([1, 2, 3]) v2 = Vector([4, 5, 6]) result = v1 + v2 print(result.components) # 输出 [5, 7, 9] ``` 在此案例中,我们通过覆盖 `__add__()` 方法赋予了矢量实例间 "+" 符号的新含义。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值