[233]树莓派裸机代码bootloader学习总结
[233]树莓派裸机代码bootloader学习总结
提莫队长 发表于2年前
[233]树莓派裸机代码bootloader学习总结
  • 发表于 2年前
  • 阅读 76
  • 收藏 0
  • 点赞 0
  • 评论 0

移动开发云端新模式探索实践 >>>   

摘要: 学渣受不了linux了,挖了个大坑,坚决地要造个别具风格的轮子,名字就叫233

代码来源:https://github.com/dwelch67/raspberrypi/tree/master/bootloader05

前要:po学渣,想造车轮,于是开始了不归路。

树莓派启动流程(照搬github主原文):

  1. boots off of an on chip rom of some sort
  2. reads the sd card and looks for additional gpu specific boot filesbootcode.bin and start.elf in the root dir of the first partition(fat32 formatted, loader.bin no longer used/required)
  3. in the same dir it looks for config.txt which you can do things likechange the arm speed from the default 700MHz, change the address whereto load kernel.img, and many others
  4. it reads kernel.img the arm boot binary file and copies it to memory
  5. releases reset on the arm such that it runs from the address where the kernel.img data was written.

所以kernel.img会被gpu加载到0x8000的地方,我们要写的代码于是就从这里开始。

file:vectors.s

.globl _start
_start:
    b skip

.space 0x200000-0x8004,0  ;这里将0x8004到0x200000的数据统统填为0

skip:
    mov sp,#0x08000000
    bl notmain
....

为什么填0x8004,原因是0x8000地址开始是要写一个跳转指令,跳转到skip这边来。

所以,原理一下子就明晰了,写代码然后做成kernel.img给gpu加载到内存0x8000的地方并让cpu去执行。

剩下的就是如何组织代码结构的问题了。

github主的方法是,cpu加载他的代码,然后他的代码配置uart,并等待数据传输进来,然后从0x8000这里开始堆放代码数据,最后执行跳转到0x8000执行您传输的数据。

file:periph.c
.......
#define AUX_ENABLES     0x20215004
#define AUX_MU_IO_REG   0x20215040
#define AUX_MU_IER_REG  0x20215044
#define AUX_MU_IIR_REG  0x20215048
#define AUX_MU_LCR_REG  0x2021504C
#define AUX_MU_MCR_REG  0x20215050
#define AUX_MU_LSR_REG  0x20215054
#define AUX_MU_MSR_REG  0x20215058
#define AUX_MU_SCRATCH  0x2021505C
#define AUX_MU_CNTL_REG 0x20215060
#define AUX_MU_STAT_REG 0x20215064
#define AUX_MU_BAUD_REG 0x20215068
.......

github主说uart地址在0x20215000这里开始,树莓派的datasheet却写的是0x7E20 1000(arm pl011)和0x7E21 5000(mini uart)

当然,kernel.img我也没具体运行过,懒。既然mmu也没启用,肯定是github主写错了,要不就是我错了(已解决,看下面的更新)。

然后github主弄了个判断xmodem传输协议(看下面的更新解释)的代码来判断数据传输状态

file:bootloader05.c
//SOH 0x01
//ACK 0x06
//NAK 0x15
//EOT 0x04
.......
if(state==0)
        {
            if(xstring[state]==0x04)
            {
                uart_send(0x06);
                for(ra=0;ra<30;ra++) hexstring(ra);
                hexstring(0x11111111);
                hexstring(0x22222222);
                hexstring(0x33333333);
                uart_flush();
                BRANCHTO(ARMBASE);
                break;
            }
        }
........

当接受的数据块头标识着EOT(我猜全称是end of transmit)时,就完成数据写入,并反馈,然后跳转执行您发送的数据。

由于我要造轮子,所以研究到这还不够。于是打开了bootloader05.list,并打开kernel.img和vectors.o继续研究。

kernel.img与vectors.o前面一部份相同,原因是kernel.img是vectors.o与其他文件一同链接成的(elf文件格式)然后生成的纯代码块(elf应该是linux下一种软件执行标准)。

kernel.img开头就是FE DF 07 EA,这应该就跳转指令,由于大小端的原因(其实我并不知道具体意思...)实际加载到cpu是EA 07 DF FE,对比bootloader05.list即可分析出来。

然后查表,armv7架构arm指令里跳转指令是b,由于有几种处理器都是32位的,所以有个cond这个值用来判断处理器(这句话我瞎编的,我也不知道是干嘛的)。

但后边的1010确实是A,所以应该就是这个指令。07 DF FE 是imm24,是有符号的值,用来表示当前运行地址指针(不知道是什么指针,先不研究)要偏移的量。

参考过的文章:http://blog.csdn.net/logicworldzju/article/details/8923596

更新:

前面的地址问题,我弄明白了。一共有三种地址

  1. ARM virtual addresses (standard Linux kernel only)(这个地址是开启了mmu后的地址)
  2. ARM physical addresses(cpu访问的地址,实际访问时的地址)
  3. Bus addresses(总线地址,arm总线amba连接外围设备,然后芯片厂商将总线上的设备地址转换给cpu能用的地址去访问)

所以,由于没有开启mmu,实际的设备地址在cpu看来应该是从0x7E00 0000偏移到了0x2000 000。

偏移量为0x5E00 0000,所以mini uart的地址是0x7E21 5000 - 0x5E00 0000 = 0x2021 5000。

关于XModem协议

XModem协议介绍:
XModem是一种在串口通信中广泛使用的异步文件传输协议,分为XModem和1k-XModem协议两种,前者使用128字节的数据块,后者使用1024字节即1k字节的数据块。

这里说的异步文件传输,不知道这个异步到底是个什么异步。看了下这个文章,估计是指每块数据块之间不严格限定时间间隔。

  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 1
博文 3
码字总数 3196
×
提莫队长
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: