简单BootLoader
title: 简单BootLoader
tags: linux
date: 2018-09-28 23:23:05
简单BootLoader
概述
目标: 启动内核,也就是需要读取内核到内存,也就是操作flash和内存
一个最基本的BootLoader应该有以下步骤:
- 初始化硬件:关看门狗、设置时钟、设置SDRAM、初始化NAND FLASH
- 如果bootloader比较大,要把它重定位到SDRAM
- 把内核从NAND FLASH读到SDRAM
- 设置要传给内核的参数
- 跳转执行内核
优化: 为了加快运行速度,应该提高主频,打开Icach
/* 启动ICACHE */
mrc p15, 0, r0, c1, c0, 0 @ read control reg
orr r0, r0, #(1<<12)
mcr p15, 0, r0, c1, c0, 0 @ write it back
NOR与NAND启动
参考文档 ARM裸机>启动流程
NAND 启动自动复制到4KRAM
NOR启动,片内RAM为0x4000,0000

链接脚本规划
我们从上图可以看到,SDRAM的起始地址为0x3000,0000,SDRAM大小为64M,也就是地址顶端为0x3400,0000.预留512K给Bootloader,也就是规划hex(0x34000000-512*1024)=0x33f8,0000为Bootloader的起始地址.链接脚本考虑字节对齐.
SECTIONS {
. = 0x33f80000;
.text : { *(.text) }
. = ALIGN(4);
.rodata : {*(.rodata*)}
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) *(COMMON) }
__bss_end = .;
}
链接脚本中有个COMMON段,这是未初始化的全局变量,一般情况下也是直接在链接阶段放在bss段进行清零.但是注意未初始化的全局变量与初始化为0的全局变量,并不对等.[未初始化的全局变量(COMMON段)为弱符号,如果有同名的全局变量,可能会存在覆盖的情况]
对于全局变量来说,如果初始化了不为0的值,那么该全局变量则被保存在data段,如果初始化的值为0,那么将其保存在bss段,如果没有初始化,则将其保存在common段,等到链接时再将其放入到BSS段。关于第三点不同编译器行为会不同,有的编译器会把没有初始化的全局变量直接放到BSS段。
链接脚本中值的获取,具体参考./链接脚本.md
//汇编方法1
.global _bss_start
_bss_start:
.word __bss_start
ldr r1, _bss_start //读取内存,这里是读取label所在内存的数据
//汇编方法2
ldr r1, =__bss_start
//C方法
extern int __bss_start;
int val =&__bss_start; //!< 获得__bss_start的值
初始化规划
#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
#define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01))
#define MEM_CTL_BASE 0x48000000
.text
.global _start
_start:
/* 1. 关看门狗 */
ldr r0, =0x53000000
mov r1, #0
str r1, [r0]
/* 2. 设置时钟 */
ldr r0, =0x4c000014
// mov r1, #0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
mov r1, #0x05; // FCLK:HCLK:PCLK=1:4:8
str r1, [r0]
/* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
mrc p15, 0, r1, c1, c0, 0 /* 读出控制寄存器 */
orr r1, r1, #0xc0000000 /* 设置为“asynchronous bus mode” */
mcr p15, 0, r1, c1, c0, 0 /* 写入控制寄存器 */
/* MPLLCON = S3C2440_MPLL_200MHZ */
ldr r0, =0x4c000004
ldr r1, =S3C2440_MPLL_400MHZ
str r1, [r0]
/* 启动ICACHE */
mrc p15, 0, r0, c1, c0, 0 @ read control reg
orr r0, r0, #(1<<12)
mcr p15, 0, r0, c1, c0, 0 @ write it back
/* 3. 初始化SDRAM */
ldr r0, =MEM_CTL_BASE
adr r1, sdram_config /* sdram_config的当前地址 */
add r3, r0, #(13*4)
1:
ldr r2, [r1], #4
str r2, [r0], #4
cmp r0, r3
bne 1b
/* 4. 重定位 : 把bootloader本身的代码从flash复制到它的链接地址去 */
ldr sp, =0x34000000
bl nand_init
mov r0, #0
ldr r1, =_start
ldr r2, =__bss_start
sub r2, r2, r1
bl copy_code_to_sdram
bl clear_bss
/* 5. 执行main */
ldr lr, =halt
ldr pc, =main
halt:
b halt
sdram_config:
.long 0x22011110 //BWSCON
.long 0x00000700 //BANKCON0
.long 0x00000700 //BANKCON1
.long 0x00000700 //BANKCON2
.long 0x00000700 //BANKCON3
.long 0x00000700 //BANKCON4
.long 0x00000700 //BANKCON5
.long 0x00018005 //BANKCON6
.long 0x00018005 //BANKCON7
.long 0x008C04F4 // REFRESH
.long 0x000000B1 //BANKSIZE
.long 0x00000030 //MRSRB6
.long 0x00000030 //MRSRB7
参数设置
nand_read(0x60000+64, (unsigned char *)0x30008000, 0x200000);
setup_start_tag();
setup_memory_tags();
setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");
setup_end_tag();
void setup_start_tag(void)
{
params = (struct tag *)0x30000100;
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);
}
内核存储在0x60000+64,读取到运行地址0x30008000,参数存储在0x30000100,最后传入机器ID=362
theKernel = (void (*)(int, int, unsigned int))0x30008000;
theKernel(0, 362, 0x30000100);
简单BootLoader的更多相关文章
- ucore-lab1-练习1report
练习1 report 问题1:OS镜像文件ucore.img是如何一步一步生成的(需要比较详细地解释Makefile中的每一条相关命令和命令参数的含义,以及说明命令导致的结果)? GNU make是一 ...
- stm32最简单的实现BootLoader
BootLoader大家应该都知道是干什么的,简单的来说就是程序开始运行前的一段程序. 在成熟的产品中,通常都是采用BootLoader方式来升级产品的程序.也就是IAP升级.在了解完基本的实现原理后 ...
- 最简单的bootloader的编写
目标:写出bootloader的第一阶段代码和第二阶段代码,并测试. 最简单的bootloader的编写步骤: 1. 初始化硬件:关看门狗.设置时钟.设置SDRAM.初始化NAND FLASH2. 如 ...
- Android Bootloader LittleKernel的两篇文章 【转】
转自:http://blog.csdn.net/loongembedded/article/details/41747523 2014-12-05 14:37 3599人阅读 评论(2) 收藏 举报 ...
- Xmodem Bootloader
了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). 多年前玩Cisco交换 ...
- 自己用C语言写单片机PIC16 serial bootloader
了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). 为什么自己写bootl ...
- PyInstaller 安装方法 及简单的编译exe (python3)
安装PyInstaller //地址 https://github.com/pyinstaller/pyinstaller/tree/python3 //上面的链接已经失效,新的(20160809更) ...
- bootloader(转)
本文详细地介绍了基于嵌入式系统中的 OS 启动加载程序 ―― Boot Loader 的概念.软件设计的主要任务以及结构框架等内容. 1. 引言在专用的嵌入式板子运行 GNU/Linux 系统已经变得 ...
- BootLoader 详解(3)
BootLoader的stage2 stage2的代码是C语言来实现的,以便于实现更复杂的功能和取得更好的代码可读性和移植性.它与普通C语言程序不同的是,在编译和链接BootLoader这样的程序时, ...
随机推荐
- hdu-1711(kmp)
题意:给你两串数字,问你第二串数字第一次出现在第一串数字的位置,没有输出-1: 解题思路:其是就是字符串匹配,就是这里是数字匹配,把char数组改成int型就可以了: 代码: #include< ...
- HTML5-SVG-基础篇
什么是SVG? SVG 指可伸缩矢量图形 (Scalable Vector Graphics) SVG 用于定义用于网络的基于矢量的图形 SVG 使用 XML 格式定义图形 SVG 图像在放大或改变尺 ...
- oracle复习(一)
一.系统操作cmd->sqlplus / as sysdba; //以管理员身份登录数据库alter user system account unlock; //解锁用户systemalter ...
- linux-内核参数优化参考指标
民间最全的Linux系统内核参数调优说 相信做运维的同仁,进行运维环境初建时,必须要考虑到操作系统内核参数的优化问题,本人经历数次的运维环境重建后,决定要自行收集一份比较完善的系统内核参数优化说明 ...
- 图灵机器人API接口
调用图灵API接口实现人机交互 流程一: 注册 图灵机器人官网: http://www.tuling123.com/ 第一步: 先注册, 然后创建机器人, 拿到一个32位的key 编码方式 UTF-8 ...
- python第三方库 - dateutil
简介 扩展并增强 datetime 模块的功能.支持 Python 2.3+. 官方文档 : http://labix.org/python-dateutil 安装 两种方法: easy_instal ...
- Get Luffy Out * HDU - 1816(2 - sat 妈的 智障)
题意: 英语限制了我的行动力....就是两个钥匙不能同时用,两个锁至少开一个 建个图 二分就好了...emm....dfs 开头low 写成sccno 然后生活失去希望... #include & ...
- 怎么用Verilog语言描述同步FIFO和异步FIFO
感谢 知乎龚大佬 打杂大佬 网上几个nice的博客(忘了是哪个了....) 前言 虽然FIFO都有IP可以使用,但理解原理还是自己写一个来得透彻. 什么是FIFO? Fist in first out ...
- 洛谷P4689 [Ynoi2016]这是我自己的发明(莫队,树的dfn序,map,容斥原理)
洛谷题目传送门 具体思路看别的题解吧.这里只提两个可能对常数和代码长度有优化的处理方法. I 把一个询问拆成\(9\)个甚至\(16\)个莫队询问实在是有点珂怕. 发现询问的一边要么是一个区间,要么是 ...
- Java和操作系统交互细节
结合 CPU 理解一行 Java 代码是怎么执行的 根据冯·诺依曼思想,计算机采用二进制作为数制基础,必须包含:运算器.控制器.存储设备,以及输入输出设备,如下图所示. enter image des ...