代码来源:https://github.com/dwelch67/raspberrypi/tree/master/bootloader05
前要:po学渣,想造车轮,于是开始了不归路。
树莓派启动流程(照搬github主原文):
- boots off of an on chip rom of some sort
- 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)
- 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
- it reads kernel.img the arm boot binary file and copies it to memory
- 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的数据统统填为0skip: 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这里开始,却写的是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
更新:
前面的地址问题,我弄明白了。一共有:
- ARM virtual addresses (standard Linux kernel only)(这个地址是开启了mmu后的地址)
- ARM physical addresses(cpu访问的地址,实际访问时的地址)
- Bus addresses(总线地址,arm总线amba连接外围设备,然后芯片厂商将总线上的设备地址转换给cpu能用的地址去访问)
所以,由于没有开启mmu,实际的设备地址在cpu看来应该是从0x7E00 0000偏移到了0x2000 000。
偏移量为0x5E00 0000,所以mini uart的地址是0x7E21 5000 - 0x5E00 0000 = 0x2021 5000。
关于:
XModem协议介绍:
XModem是一种在串口通信中广泛使用的异步文件传输协议,分为XModem和1k-XModem协议两种,前者使用128字节的数据块,后者使用1024字节即1k字节的数据块。
这里说的异步文件传输,不知道这个异步到底是个什么异步。看了下,估计是指每块数据块之间不严格限定时间间隔。