自己动手编写嵌入式Bootloader之(1)

Uboot编译过程(Makefile和配置(mkconfig)详解 目录 2.4.1.uboot主Makefile分析1 2.4.2.uboot主Makefile分析2 2.4.3.uboot主Makefile分析3 2.4.1.uboot主Makefile分析1 1.uboot version确定(Makefile的24-29行) (1)uboot的版本号分3个级别: VERSION:主板本号 PATCHLEVEL:次版本号 SUBLEVEL:再次版本号 EXTRAVERSION:另外附加的版本信息 这4个用.分隔开共同构成了最终的版... 阅读详情

 

第一部分:基本功能流程

CPU上电后会从IO空间的某地址取第一条指令。但此时:PLL没有启动,CPU工作频率为外部输入晶振频率,非常低;CPU工作模式、中断设置等不确定;存储空间的各个BANK(包括内存)都没有驱动,内存不能使用。在这种情况下必须在第一条指令处做一些初始化工作,这段初始化程序与操作系统独立分开,称之为bootloader。

 
实际上,很少有必要自己写一个Bootloader,因为U-Boot已经强大到能够满足各种需要。但是强大必然复杂,一个初学者想要分析U-Boot的源代码,还是有些难度的。出于学习的目的,我写了这个史上最简单的启动加载器,它只包含最基本的功能,却囊括了一个嵌入式Bootloader应该有的核心和精华。我把这个启动加载器命名为S-Boot, 是Simple Bootloader的缩写,亦可进一步简称为SB。
 

 
使用的实验环境为OK2440开发板,板上处理器为S3C2440A,有64M内存,Nand存储器为K9F1208,64M。网口芯片为CS8900A。我们要实现的功能是:从串口下载Linux内核映像到RAM;从网口下载Linux内核映像到RAM;从RAM启动内核挂载NFS根文件系统。
1. 第一阶段的汇编代码:start.S
一个嵌入式Bootloader最初始部分的代码几乎必须是用汇编语言写成的,因为开发板刚上电后没有准备好C程序运行环境,比如堆栈指针SP没有指到正确的位置。汇编代码应该完成最原始的硬件设备初始化,并准备好C运行环境,这样后面的功能就可以用C语言来写了。

 
对我们的S-Boot来说,上电后的起始运行代码是 start/start.S。

 

.text
.global _start
_start:
b Reset @ 0x00: 发生复位异常时从地址零处开始运行
    b HandleUndef @ 0x04: 未定义指令中止模式的向量地址
    b HandleSWI   @ 0x08: 管理模式的向量地址,通过SWI指令进入此模式
    b HandlePrefetchAbort @ 0x0C: 指令预取终止导致的异常的向量地址
    b HandleDataAbort     @ 0x10: 数据访问终止导致的异常的向量地址
    b HandleNotUsed       @ 0x14: 保留
    b HandleIRQ           @ 0x18: 中断模式的向量地址
    b HandleFIQ           @ 0x1C: 快中断模式的向量地址
 
这里,汇编指示符.text表明以下内容属于代码段,.global _start指明_start是全局可访问的符号(Give the symbol external linkage)。按照ARM920T的规定,从地址0x00到0x1C放置异常向量表,向量表每个条目占四个字节,正好可以放置一条跳转指令,跳转到相应异常的服务程序中去。在S-Boot中没有使用中断,所以除Reset异常外,其它异常的服务程序都可简单地写个死循环。Reset异常是系统上电后自动触发的,所以我们的代码都写在Reset的服务程序里面。
 
实际上,异常向量表不一定非要位于地址0x00处,CP15协处理器中的c1寄存器的第13位用来控制异常向量表的起始地址。该位为0时,异常向量表位于低地址0x00处;该位为1时,异常向量表位于高地址 0xFFFF0000处。我们没有必要改变这个位的值,使用默认的低地址就行了。
 

Reset:
        mrs r0,cpsr       @set cpu to SVC32 mode
        bic r0,r0,#0x1F
        orr r0,r0,#0xD3
        msr cpsr,r0       @cpsr=11x10011, IRQ/FIQ disabled
 
代码最初始的任务是设置CPU工作在SVC32模式,关闭所有中断,禁用看门狗。实际上,即使不设置工作模式,CPU在复位之后将自动工作在管理模式。在整个S-Boot运行期间,我们没有使用中断,也没有改变CPU工作模式,它将一直工作在SVC32模式。
 
 
MMU、ICache、DCache的打开和关闭都是由CP15协处理器的c1寄存器控制的。实际上在复位之后这三者都是自动关闭的,所以省略了关闭它们的代码。
 


 
S3C2440A的PSR寄存器(Program Status Reguster)中每个Bit位的含义如图1所示。Bit4~Bit0为模式位,用来设置CPU工作模式,现在只要知道 M[4:0] = 10011 表示SVC32模式就行了。Bit5为状态位,T=0表示工作在ARM状态,T=1表示工作在Thumb状态,默认为0,不需要改变。Bit6为快速中断禁止位,F=1为禁止快速中断,F=0为使能快速中断。Bit7为中断禁止位,I=1为禁止中断,F=0为使能中断。其它Bit位暂时可以不必理会。

 
mrs 和msr是在PSR寄存器和其它寄存器间传递数据的指令。如:mrs r0,cpsr 把cpsr的值传送到r0中, msr cpsr,r0 把r0的值传送到cpsr中。bic是位清零(Bit Clear)指令,bic r0,r0,#0x1F 意思是把r0的Bit[4:0]位清零(由0x1F指示),然后把结果写入r0中。 orr是按位求或指令,orr r0,r0,#0xD3 表示把r0的 Bit7,Bit6,Bit4,Bit1,Bit0 置为1,其它位保持不变。

 
执行完上述操作后,cpsr中的 I=1, F=1, T保持不变(默认为0),M[4:0]=10011,意思是禁止IRQ,禁止FIQ,工作在ARM状态,工作在SVC32模式。
 
 

        ldr r0, =0x53000000
        mov r1, #0x0
        str r1, [r0] @disable watch dog
 
禁用看门狗更简单,因为WTCON寄存器的地址为0x53000000,直接向该寄存器写0即可。
 

 
到目前为止,CPU工作在外接晶振12MHz频率之下。使用以下代码设置PLL,提升工作频率。
 
 

        ldr r0, =0x4C000014 @CLKDIVN register

        mov r1, #0x05 @FCLK:HCLK:PCLK = 1:4:8
        str r1, [r0]

        mrc p15,0,r0,c1,c0,0 @if HDIVN Not 0, must asynchronous bus mode
        orr r0,r0,#0xC0000000 @see S3C2440A manual P7-9
        mcr p15,0,r0,c1,c0,0

        ldr r0, =0x4C000004 @MPLLCON register
        ldr r1, =0x0005C011 @((92<<12)|(1<<4)|(1))
&
创建自己的uboot-基于IMX6 Linux 系统要启动就必须需要一个 bootloader 程序,上电后首先运行的程序,初始化DDR等外设,然后将Linux内核flash(NAND,NOR FLASH,SD,MMC 等)拷贝到 DDR 中,最后启动 Linux 内核,一个启动流程。因此我们需要一个bootloader,目前有很多现成的 bootloader 软件可以使用,比如 U-Boot、vivi、RedBoot 等等,其中以 U-Boot 使用最为广泛,因此我们学习uboot。根据硬件平台,搭建适合平台的uboot这里用I.MX6U 阅读详情

相关推荐

Uboot开发与移植笔记(超详细代码讲解)(一)

本文对UBoot源码进行详细讲解,逐一带你从0修改UBoot源码进行移植工作

qq_46037552的博客 1万+

移植、制作uboot、Linux(一)

u-boot、linux烧录

zichuanning520的博客 847

在天问block环境下LU-ASR01与51单片机的基础运用

正确步骤将模块和电脑连接后,仍然显示未连接(如4.1中图片中的编译下载后面显示未连接),可以尝试关闭软件后尝试,如果仍然不行换一条type-c线再试;以上方式都不行,可能要怀疑ASR01硬件损坏,跟商家联系!!!

BUG7073的博客 1万+

(一)uboot的移植与制作

目录(一)环境(二)流程分析(三)具体步骤 在裸机启动流程里涉及到BL1,BL2为系统的加载启动项,全称为BootLoader。 Boot Loader 是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。通常,Boot Loader 是严重地依赖于硬件而实现的...

水枂的博客 1768

[转载]自己动手编写嵌入式Bootloader之(1

第一部分:基本功能流程CPU上电后会从IO空间的某地址取第一条指令。但此时:PLL没有启动,CPU工作频率为外部输入晶振频率,非常低;CPU工作模式、中断设置等不确定;存储空间的各个BANK(包括内存)都没有驱动,内存不能使用。在这种情况下必须在第一条指令处做一些初始化工作,这段初始化程序与操作系统独立分开,称之为bootloader。实际上,很少有必要自己一个Bootloader,因为

DerekYao的专栏 1672

b halt 汇编_[原创]自己动手编写嵌入式Bootloader之(1

第一部分:基本功能流程CPU上电后会从IO空间的某地址取第一条指令。但此时:PLL没有启动,CPU工作频率为外部输入晶振频率,非常低;CPU工作模式、中断设置等不确定;存储空间的各个BANK(包括内存)都没有驱动,内存不能使用。在这种情况下必须在第一条指令处做一些初始化工作,这段初始化程序与操作系统独立分开,称之为bootloader。实际上,很少有必要自己一个Bootloader,因为U-Bo...

weixin_39885067的博客 264

嵌入式实战】STM32 Bootloader 快速实现(超详细)

我是 AidenHinGwenW,本文介绍如何快速实现 STM32 BootLoader 的引导。 嵌入式的设备,或多或少都需要对设备进行更新已适配更多的需求,`bootLoader` 的设计就是为了设备能够进行远程升级或者只用指令升级,极大简便了升级需要的步骤,做到傻瓜式升级,极大增强了产品的后续维护性。 下面我来介绍如何快速实现 STM32 BootLoader 的引导,帮助正在读文章的您更快将此技术运用起来!

HinGwenWoong的博客 7万+

一步步操作系统(一) BOOT启动

一步步操作系统(一) 0.介绍 很久之前就有了一个操作系统的想法,参考了很多书籍,主要包括《自己动手操作系统》(余渊)和《30天自制操作系统》(川合秀实),总体感觉就是,川合秀实版本的比较注重界面描绘与优化,介绍了内存分配和时钟函数等,但是对于操作系统底层并没有做太多介绍,使得读者知其然而不知其所以然。余渊版本的就比较细致,介绍了GDT,LDT,IDT等等,但是最终的成品也可以看到,使用

stophin的专栏 4611

Uboot编写(一)

初始化异常向量表: 异常:因为外部或内部一些事件,导致处理器停下正在处理的工作,转而处理这些发生的事件。共七种异常:reset,undefined instructions, Software Interruption(SWI),Prefetch Abort,Data Absort,IRQ,FIQ。当一种异常发生,ARM处理器会跳转到对应该异常的固定地址去执行异常程序,而这个固定地址就是异常向量

wangbin1990的专栏 1833

u-boot使用实验(烧录和命令)

u-boot

chenzhjlf的专栏 3290

() 自己简单的u-boot

前言:想想 uboot 的代码量,我们说自己一个 bootloader 是不是口出狂言了?然而并没有,bootloader 的唯一目的只有一个,那便是启动内核内核就是一大段可执行程序,我们只要跳转到它的入口地址去执行不就OK? 所以,一个简单的 bootloader 并不困难。    现在来思考一下,目的是启动内核,那么内核在哪里?刚上电的时候,内核肯定是位于 nandflash 里的,我们得

Linux Openharmony Android Graphics Stack! 3891

Boot——自己编写简单的bootloader

bootlaoder目标:启动内核 1.从FLASH上把内核读入内存; 需要可以读FLASH;初始化时钟,内存,其他; 2.启动 设置参数;跳转执行; 最简单bootloader编写步骤: 1.初始化硬件:关看门狗(防止自动复位整个开发板);设置时钟,SDRAM,NAND FALSH; 2.如果bootloader比较大需要将其重定位至SDRAM; 3.把内核从NAND FLASH读到SDRAM中; 4.设置需要传给内核的启动参数; 5.跳转执行内核; 假设是NOR启动: 将代码直接从NOR FALSH

没实力的码农写的渣渣博客 1690

uboot配置和编译过程详解

▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼分享一个大神朋友的人工智能教程。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到人工智能的队伍中来!点击浏览教程。得特别用心喔~ →→→→→→大神朋友简介:从事十几年人工智能研究,麻省理工博士学位,目前在百度继续进行着人工智能的研究。。。 ▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲...

Linux Openharmony Android Graphics Stack! 2万+

深度解析:LPDDR5 Receiver 的挑战与应对

LPDDR5 的数据速率已经来到Tbit​DataRate1​≈156ps在6400Mbps时也就是说,。👉 这就是为什么成为 LPDDR5 的“标配”。

weixin_43199439的博客 177

基于深度学习的车牌识别

基于深度学习的车牌识别数据集介绍以及识别结果可查看:https://blog.csdn.net/weixin_45724232/article/details/112851523?spm=1001.2014.3001.5502可以识别带有一定角度的车牌,由两阶段完成,首先使用检测网络检测车牌区域,然后使用识别网络识别车牌,内涵数据集,可以直接运行,也包含说明文件,该有的注释也都有,代码易懂。里面有训练好的模型。由两阶段完成,首先使用检测网络检测车牌区域,然后使用识别网络识别车牌,内涵数据集,可以直接运行,也包含说明文件,该有的注释也都有,代码易懂。里面有训练好的模型。由两阶段完成,首先使用检测网络检测车牌区域,然后使用识别网络识别车牌,内涵数据集,可以直接运行,也包含说明文件,该有的注释也都有,代码易懂。里面有训练好的模型。由两阶段完成,首先使用检测网络检测车牌区域,然后使用识别网络识别车牌,内涵数据集,可以直接运行,也包含说明文件,该有的注释也都有,代码易懂。里面有训练好的模型。由两

上一篇: 太搞笑了,是个80后的女的写给她自己未来儿子(女儿)
下一篇: 自己动手编写嵌入式Bootloader之(2)
jun2ran
博客等级 码龄18年 101粉丝 183原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值