您的位置:首页 > 运维架构 > Linux

Linux开发三_基于newlib的bootloader

2015-11-01 01:00 447 查看

Linux开发三

基于newlib的bootloader

象棋小子 1048272975
bootloader是嵌入式系统上电后第一段执行的代码,它先初始化CPU和相关的硬件,建立内存空间映射,把内核或应用程序加载到相应的内存执行位置,最后调用内核或应用程序,释放CPU控制权,完成整个bootloader的流程。bootloader以及应用程序开发往往是离不开c库的,笔者此处就s3c2416基于newlib的bootloader以及裸机应用开发作一个简单的介绍。

1. bootloader概述

一般对于一个bootloader应实现两种不同的操作模式:启动加载模式和下载模式。启动加载模式就是bootloader从设备系统的某个固态储存器中将操作系统或应用程序加载进RAM,整个过程无需用户的介入,这种模式是设备成型后bootloader的正常工作模式。下载模式是bootloader可以通过串口、USB或网络等通信手段从主机下载文件,并最终写入到到设备系统的某个固态储存器中,这种模式用在设备开发调试中,用于刷机升级。此处笔者从自己的角度简单介绍s3c2416 bootloader实现的一般流程。

与bootloader相关的代码文件放在System目录文件夹中,目录架构如下:

s3c2416.S,启动代码文件,代码执行时的入口,控制了整个bootloader的执行流程,最终建立起c运行环境后,进入到应用程序main入口。
LowLevelInit.S,板级初始化代码,包括CPU时钟的初始化、DDR2内存控制器初始化、代码加载实现(sd/mmc卡启动、Nand flash启动)。
Coprocessor.c,协处理器相关代码,主要是CP15协处理器I/D Cache、MMU内存映射、中断向量基址等操作代码。
NandBoot.c,实现Nand flash启动相关Nand驱动代码,实现相应Nand代码下载、Nand代码启动的接口实现,支持IROM Nand、Nand Boot启动。
Download.c,实现代码下载调试功能,支持代码直接下载内存调试运行,支持代码下载进Nand flash以及Nand下载固化。
Exception.c,异常处理相关代码,支持中断处理的完整架构,如中断嵌套处理、中断注册、中断开启等接口实现,为系统应用架构实现。
Retarge.c,所有newlib操作系统移植层的重定向实现,如标准输入、输出流重定向到串口、文件操作重定向到相应的文件系统接口实现等,大部分为空实现。
s3c2416.lds,gcc下链接文件,指定板载内存范围,代码以及RAM等布局。

1.1. 异常向量表

ARM核在异常发生时,会从异常向量表中取得相应的异常向量地址执行,发生IRQ中断则从异常向量表0x18偏移处取得IRQ异常向量地址。异常向量表就是用来记录各个异常进入时的代码处理位置。除了Cortex-M处理器有嵌套向量中断控制器(NVIC),以下的异常向量处理对所有系列的ARM核均是成立的。

.text

.arm

.align 2

.globl _start

_start:

B Reset_Handler

LDR PC, Undef_Addr

LDR PC, SWI_Addr

LDR PC, PAbt_Addr

LDR PC, DAbt_Addr

LDR PC, Notuse_Addr

LDR PC, IRQ_Addr

LDR PC, FIQ_Addr

.word 0x55aa55aa // 0x20位置用来判断代码的运行区域

.extern Undef_Handler

.extern SWI_Handler

.extern PAbt_Handler

.extern DAbt_Handler

.extern IRQ_Handler

.extern FIQ_Handler

Reset_Addr:

.word Reset_Handler

Undef_Addr:

.word Undef_Handler

SWI_Addr:

.word SWI_Handler

PAbt_Addr:

.word PAbt_Handler

DAbt_Addr:

.word DAbt_Handler

Notuse_Addr:

.word 0 // Reserved Address

IRQ_Addr:

.word IRQ_SaveContext

FIQ_Addr:

.word FIQ_Handler

IRQ_SaveContext:

// 保存中断上下文,支持中断嵌套

SUB LR, LR, #4 // 计算返回地址

STMFD SP!, {R0-R12, LR} // 所有寄存器压栈保存

MRS R0, SPSR // 保存中断前的CPSR(即现在的SPSR)

STMFD SP!, {R0}

MSR CPSR_cxsf, #(Mode_SYS |I_Bit) // 切换到系统模式

STMFD SP!, {LR} // 压栈系统模式LR

LDR R0, =IRQ_Handler // 系统模式下进行IRQ代码处理

MOV LR, PC // 准备函数的返回地址

BX R0 // 调用中断处理函数

LDMFD SP!, {LR} // 出栈系统模式LR

MSR CPSR_cxsf, #(Mode_IRQ |I_Bit) // 切换到IRQ模式

LDMFD SP!, {R0} // 返回中断前的CPSR

MSR SPSR_cxsf, R0

LDMFD SP!, {R0-R12, PC}^// ^表同时从spsr恢复给cpsr

1.2. 关看门狗

复位代码最先做的事应该是关看门狗,因为如果看门狗打开的话,在启动代码进行初始化过程中是无法喂狗的,可能造成处理器一直不停复位。

// 看门狗关闭

LDR R0, =WT_BASE

LDR R1, =0

STR R1, [R0]

1.3. 关闭所有中断

启动代码未完成时,各个状态都还不是确定的,如果有中断打开并引起中断异常,可能造成代码跑飞。

// 关闭所有外设中断

LDR R0, =INT_BASE

LDR R1, =0xFFFFFFFF

STR R1, [R0, #INTMSK1_OFS]

STR R1, [R0, #INTMSK2_OFS]

STR R1, [R0, #INTSUBMSK_OFS]

1.4. 初始化系统时钟

一般来说,处理器复位后都是运行在一个较低速的时钟下,为加快启动,通常尽可能快地设置处理器的各个时钟。

// 系统时钟设置

.extern Clock_Init

BL Clock_Init

1.5. 初始化外部内存

除了Nor flash可以直接执行代码外,其它的代码存储器如nand flash、sd/mmc都是不能直接执行代码的。一般对于应用处理器,代码都是加载进RAM后执行。

// 外部内存控制设置

.extern ERAM_Init

BL ERAM_Init ;// 外部RAM初始化

LDR SP, =__StackTop

1.6. 代码加载

对于代码存储在Nand flash、sd/mmc等不能直接执行代码的存储器,bootloader是一定需要把用户代码从这些设备读入到特定的内存中执行的。而对于Nor flash可直接执行代码的存储器,通常为了提高性能,也是会把代码从Nor flash读出,在内存中执行的。

// 拷贝用户代码到RAM

.extern CopyCodeToRAM

BL CopyCodeToRAM

1.7. 下载模式

在调试开发阶段,可以通过直接下载代码到RAM调试执行,避免重复地烧写固态存储器,加快调试开发,在确定代码OK后,再把代码下载进固态存储器(Nandflash)即可。在开发完成后,下载模式代码可注释掉。

// 检查是否进入串口下载模式,开机时按住空格键进入串口下载模式

.extern DownloadCheck

BL DownloadCheck

1.8. MMU内存映射

为了提高CPU的处理性能,MMU必须开启,在开启之前,需先建立相应的内存空间映射表,设置相应的内存区域访问权限等。开启MMU后,也必须同时开启I/D Cache,不然CPU的性能将极其低下,有几十倍的性能差异。

// MMU初始化

LDR SP, =__StackTop

.extern MMU_Init

BL MMU_Init

1.9. 初始化栈

ARM核有多种工作模式,每种模式的栈是一定要分配及初始化的,这样才能在相应模式下正确地执行代码。

// 堆栈初始化

LDR R0, =__StackTop

// EnterUndefined Instruction Mode and set its Stack Pointer

MSR CPSR_c, #(Mode_UND | I_Bit | F_Bit)

MOV SP, R0

SUB R0, R0, #UND_Stack_Size

// Enter AbortMode and set its Stack Pointer

MSR CPSR_c, #(Mode_ABT | I_Bit | F_Bit)

MOV SP, R0

SUB R0, R0, #ABT_Stack_Size

// Enter FIQMode and set its Stack Pointer

MSR CPSR_c, #(Mode_FIQ | I_Bit | F_Bit)

MOV SP, R0

SUB R0, R0, #FIQ_Stack_Size

// Enter IRQMode and set its Stack Pointer

MSR CPSR_c, #(Mode_IRQ | I_Bit | F_Bit)

MOV SP, R0

SUB R0, R0, #IRQ_Stack_Size

// EnterSupervisor Mode and set its Stack Pointer

MSR CPSR_c, #(Mode_SVC | I_Bit | F_Bit)

MOV SP, R0

SUB R0, R0, #SVC_Stack_Size

// Enter SystemMode and set its Stack Pointer

MSR CPSR_c, #Mode_SYS

MOV SP, R0

SUB SL, SP, #USR_Stack_Size

1.10. 初始化c运行环境

进入c入口之前是需要初始化c环境的,如清0全局变量、静态变量区;对于加载域与运行域不一至的段,需从加载域加载进运行域;对于c++,可能需执行构造函数等。此处用c开发,并且已经由bootloader把整个代码段、数据段等加载进RAM运行域了。

Clear_bss:

LDR R0, =_sbss

LDR R1, =_ebss

MOV R2, #0

Clear_bss_loop:

CMP R0, R1

BGE Clear_bss_done

STR R2, [R0], #4

B Clear_bss_loop

Clear_bss_done:

1.11. 跳转到main

整个c环境构架起来后,即可跳转到应用程序入口main函数,用绝对地址跳转到c入口main,bootloader释放CPU控制权,完成整个流程。

// 绝对地址跳转到c入口

.extern main

LDR R0, =main

BX R0

2. Makefile

Makefile用来构建和管理工程,工程顶级目录下有三个make文件config.mk、Makefile、rules.mk。

rules.mk,用来解决依赖关系,修改了某一文件,将会重新编译所有依赖于该文件的源文件。

Makefile,控制各个目录的编译、链接生成相应的目标对象。

config.mk,不同的项目,只需改config.mk,该文件定义了交叉工具链、项目名、需编译的目录、编译选项、链接文件、库链接等。其中在这个文件指定c库链接为newlib

3. 链接文件

s3c2416.lds为项目链接文件,一般无需更改。bootloader相关的代码链接在最开始的8k范围内,链接文件提供相应的段位置信息来界定堆位置、.bss区等。其中.mem_uninit为未初始化段,定义在这段的内存变量在软复位后也不会被改变,可以保存复位信息等;.mem_ncnb为cache、写缓存关闭,定义在这段的内存变量不会有cache数据一致性的问题;.mem_cnb为内存写通模式,定义在这段的内存变量数据可cache,写数据即使命中,也将数据更新到主存中;.mem_ncb为cache不会命中、开启写缓存,定义在这段的内存变量数据每次访问均访问主存,写数据时先写入写缓存;默认的内存模式为写回模式。

SECTIONS

{

. =0x00000000;

. = ALIGN(4);

.text :

{

_scode = .;

./System/s3c2416.o (.text* .rodata*)

./System/LowLevelInit.o (.text* .rodata*)

./System/NandBoot.o (.text* .rodata*)

./System/Coprocessor.o (.text* .rodata*)

./System/Download.o (.text* .rodata*)

*(.text*)

}

. = ALIGN(4);

.rodata : {*(.rodata*) }

. = ALIGN(4);

.data :

{

_sdata = .;

*(.data*)

_edata = .;

}

_ecode = .;

. = ALIGN(4);

.bss :

{

_sbss = .;

*(.bss*)

*(COMMON*)

_ebss = .;

}

. = ALIGN(4);

.heap(NOLOAD):

{

PROVIDE(end = .);

*(.heap*)

}

. = ALIGN(4);

.stack(NOLOAD):

{

*(.stack*)

}

. = ALIGN(4);

.mem_uninit(NOLOAD):

{

*(.mem_uninit)

}

/* cache off,write buffer off */

. = ALIGN(0x100000);

.mem_ncnb(NOLOAD):

{

_smem_ncnb = .;

*(.mem_ncnb)

_emed_ncnb = .;

}

/* cache off,write buffer on */

. =ALIGN(0x100000);

.mem_ncb(NOLOAD):

{

_smem_ncb = .;

*(.mem_ncb)

_emem_ncb = .;

}

/* cache on,write through */

. =ALIGN(0x100000);

.mem_cnb(NOLOAD):

{

_smem_cnb = .;

*(.mem_cnb)

_emem_cnb = .;

}

}

4.应用编程

在main中实现用户功能函数,可以任意使用newlib中的c库函数。

#include "ProjectConfig.h"

#include "Uart.h"

#include "Speed.h"

int main(void)

{

int i;

Uart_Init();

printf("CPU: S3C2416@%dMHz\n", get_ARMCLK()/1000000);

printf(" Fclk = %dMHz, Hclk = %dMHz, Pclk = %dMHz\n",

get_FCLK()/1000000,get_HCLK()/1000000, get_PCLK()/1000000);

i = 0;

while (1) {

Delay_ms(1000);

printf("i= %d\n", i);

i++;

}

}

打开shell终端,执行make,编译完成后即可在顶层目录生成Bootloader.elf、Bootloader.map、Bootloader.srec、Bootloader.bin、Bootloader.dis这五个文件。其中,Bootloader.map为链接Mapping文件,Bootloader.dis为工程的汇编生成文件,这是编译器经过编译所有的源码并进行链接最终给出的汇编文件,Bootloader.bin即为我们用来烧录进sd卡或nand等存储器的二进制代码文件。

5. 代码烧写

代码可以存储在Nand flash或sd/mmc卡中,一般先把代码烧写进sd/mmc卡中,这样无需复杂的操作以及昂贵的烧录器等。sd/mmc卡启动后通过里面的Bootloader下载功能把主机上的相应代码下载进设备的Nand flash上,之后无需再用sd/mmc卡,设置Nand flash启动,代码更新也通过Nandflash上的Bootloader下载更新即可。

sd/mmc卡启动需要专用的烧录软件SdBoot,SdBoot.exe为笔者在windows下针对三星S3C2416和S5PV210这两个平台开发的sd/mmc启动烧录工具。sd/mmc启动需要相应的代码格式以及需烧录进sd/mmc卡指定的位置,SdBoot.exe工具集代码格式转换以及sd/mmc卡烧录于一体,可以烧录S3C2416和S5PV210这两个平台下笔者编写的裸机bootloader,wince bootloader,uboot,工具简单易用。



图5-1 SdBoot.exe工具

6. Bootloader下载功能

Bootloader通过串口实现主机代码文件的下载,主机端代码下载需要三星专用的工具dnw.exe工具,连接好串口后,按住空格键后,目标板上电会进入Bootloader的下载模式。



图6-1 Bootloader下载模式
其中选项1可以基于笔者Bootloader开发的应用,下载进RAM,并直接调试运行。下载进RAM的代码均是编译器直接编译出来的代码,未经过SdBoot工具格式转换。

选项2用于代码烧录进Nand flash,把编译器直接编译出来的代码下载进Nand flash,之后设置Nand flash启动即可。

7. 附录

附录为arm交叉编译工具链下基于newlib的s3c2416 bootloader工程,附带了newlib库,sd卡windows下烧录工具,工程直接make即可。

http://pan.baidu.com/s/1sjOPtGL

arm交叉编译工具链下基于newlib的s3c2416 uCGUI工程,基于bootloader的uCGUI协议栈、定时器、电容屏、IIC、RGB屏等驱动。

http://pan.baidu.com/s/1pJovBFP
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: