您尚未登录。

楼主 #1 2018-04-10 00:54:46

sunwei
会员
注册时间: 2018-04-09
已发帖子: 77
积分: 77

xboot 启动代码分析

/*

  • start.S
    *

  • Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>

  • Official site: http://xboot.org

  • Mobile phone: +86-18665388956

  • QQ: 8192542
    *

  • This program is free software; you can redistribute it and/or modify

  • it under the terms of the GNU General Public License as published by

  • the Free Software Foundation; either version 2 of the License, or

  • (at your option) any later version.
    *

  • This program is distributed in the hope that it will be useful,

  • but WITHOUT ANY WARRANTY; without even the implied warranty of

  • MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

  • GNU General Public License for more details.
    *

  • You should have received a copy of the GNU General Public License

  • along with this program; if not, write to the Free Software Foundation,

  • Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    *
    */

/*

  • Exception vector table
    */
    .text
    .arm

.global _start
_start:
/ Boot head information for BROM /
.long 0xea000016
.byte 'e', 'G', 'O', 'N', '.', 'B', 'T', '0'
.long 0, 0x3a00
.byte 'S', 'P', 'L', 2
.long 0, 0
.long 0, 0, 0, 0, 0, 0, 0, 0
.long 0, 0, 0, 0, 0, 0, 0, 0 / 0x40 - boot params, 0x58 - fel boot type, 0x5c - dram size /

_vector:
b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq

_undefined_instruction:
.word undefined_instruction
_software_interrupt:
.word software_interrupt
_prefetch_abort:
.word prefetch_abort
_data_abort:
.word data_abort
_not_used:
.word not_used
_irq:
.word irq
_fiq:
.word fiq

/*

  • The actual reset code
    */
    reset:
    / Save boot params to 0x00000040 /
    ldr r0, =0x00000040
    str sp, [r0, #0] / 0x00000040 = 保存堆栈/
    str lr, [r0, #4] / 0x00000044 = 保存返回地址/
    mrs lr, cpsr / 读 状态机/
    str lr, [r0, #8] / 0x00000048 = 保存状态寄存器/
    mrc p15, 0, lr, c1, c0, 0 / 读 MMU及相关的/
    str lr, [r0, #12] / 0x0000004c = MMU及相关的/
    mrc p15, 0, lr, c1, c0, 0 / 读 MMU及相关的/
    str lr, [r0, #16] / 0x00000050 = MMU及相关的/

/ Check boot type just for fel /
mov r0, #0x0
ldr r1, [r0, #8] / R1 = 0x00000008地址内的数据/
ldr r2, =0x4c45462e / r2 = 0x4c45462e /
cmp r1, r2 / 比较 r1 和 r2 /
bne 1f / 不相等跳到 1f = 向后调到 1: /
ldr r1, =0x1 / r1 = 0x01 /
str r1, [r0, #0x58] / (0x00000058) = 0x1 这里放的是启动是不是在FEL模式*/
/* 以上就是 比较0x00000008的内容与0x4c45462e 是不是想等 相等 跳过 ,不等 设置 0x00000058的内容为1
1: nop

/ Enter svc mode and mask interrupts /
mrs r0, cpsr / 读状态寄存器 /
bic r0, r0, #0x1f / r0 = r0 & (!0x0000001f) 清零处理器工作模式/
orr r0, r0, #0xd3 / r0 = r0 | 0x000000d3 设置处理器为系统模式,并关闭IRQ FIQ 中断/
msr cpsr, r0 / 写状态寄存器/

/ Set vector to the low address /
mrc p15, 0, r0, c1, c0, 0
bic r0, #(1<<13) / 设置异常向量地址为 0x0到0x1c /
mcr p15, 0, r0, c1, c0, 0

/ Copy vector to the correct address /
adr r0, _vector /相对寻址到_vector,并把里面的内容读到r0,相对寻址的好处就是,可以做到代码与链接地址无关/
mrc p15, 0, r2, c1, c0, 0 / 读协处理器寄存器/
ands r2, r2, #(1 << 13) / 检查异常向量地址高端低端设置位 /
ldreq r1, =0x00000000 / if((向量地址设置位) == 1) r1 = 0x00000000; /
ldrne r1, =0xffff0000 / if((向量地址设置位) != 1) r1 = 0xffff0000; /
ldmia r0!, {r2-r8, r10}
stmia r1!, {r2-r8, r10} / 将r2-r8,r10 放到 按顺序放到 r0 指向的地址; /
ldmia r0!, {r2-r8, r10}
stmia r1!, {r2-r8, r10}
/ 常向量地址高端低端设置位,从本代啊的位置拷贝向量到系统设置的向量地址/

/ Initial system clock, ddr add uart /
bl sys_clock_init
bl sys_dram_init
bl sys_uart_init

/ Copyself to link address 自我复制到链接器编译后的绝对地址。 链接时是ddr的内存地址,要搞清楚这时执行的地址可能在0x0000,或是spi闪存的映射地址/
adr r0, _start / r0 = _start相对的地址 /
ldr r1, =_start / r1 = _start绝对的地址 /
cmp r0, r1 / 比较有没有跑过现代码 /
beq 1f / 跑过向后调到 1:/
bl sys_copyself
1: nop

/ Initialize stacks /
mrs r0, cpsr
bic r0, r0, #0x1f
orr r1, r0, #0x1b /进入未定义异常/
msr cpsr_cxsf, r1
ldr sp, _stack_und_end

bic r0, r0, #0x1f
orr r1, r0, #0x17 /进入中止异常/
msr cpsr_cxsf, r1
ldr sp, _stack_abt_end

bic r0, r0, #0x1f
orr r1, r0, #0x12 /进入IRQ异常/
msr cpsr_cxsf, r1
ldr sp, _stack_irq_end

bic r0, r0, #0x1f
orr r1, r0, #0x11 /进入FIQ异常/
msr cpsr_cxsf, r1
ldr sp, _stack_fiq_end

bic r0, r0, #0x1f
orr r1, r0, #0x13 /进入管理异常/
msr cpsr_cxsf, r1
ldr sp, _stack_srv_end

/ Copy data section /
ldr r0, _data_start /目的地址/
ldr r1, _data_shadow_start /源地址 /
ldr r2, _data_shadow_end
sub r2, r2, r1 /拷贝个数/
bl memcpy /memcpy(r0,r1,r2); 在keil 里这些是不需要做的/

/ Clear bss section /
ldr r0, _bss_start
ldr r2, _bss_end
sub r2, r2, r0
mov r1, #0
bl memset /memset(r0,r1,r2); 在keil 里这些是不需要做的/

/ Call _main /
ldr r1, =_main
mov pc, r1
_main:
mov r0, #1;
mov r1, #0;
bl xboot_main
b _main

/ * 注意: 非常重要的情况,一定要搞清芯片内部的BROM程序是不是和你现在的启动代码及相关的代码相对应。
否则买到的是特制的BROM的芯片,将来会有很大的麻烦。
因为你需要咨询原厂要他提供特制BROM芯片的用法,再修改现在的代码。
但我估计芯片厂商是和客户签订了协议的,一般不会提供。*/

/* 补记忆
https://blog.csdn.net/gameit/article/details/13169405 协处理寄存器描述
https://www.cnblogs.com/armlinux/archive/2011/03/23/2396833.html 状态寄存器描述
CP15 的寄存器 C0:
MRC P15,0,R0,C0,C0,0 #将主标示符寄存器的内容读到AMR寄存器R0中
MRC P15,0,R0,C0,C0,1 #将cache类型标识符寄存器的内容读到AMR寄存器R0中

CP15 的寄存器 C1:
mrc p15, 0, r0, c1, c0{, 0} ;将 CP15 的寄存器 C1 的值读到r0中
mcr p15, 0, r0, c1, c0{, 0} ;将 r0 的值写到 CP15 的寄存器C1中

CP15 的寄存器 C2:
C2寄存器的别名:Translation table base (TTB) register
C2寄存器用来保存页表的基地址,即一级映射描述符表的基地址。其编码格如下所示:

CP15 的寄存器 C3:
CP15 中的寄存器 C3 定义了 ARM 处理器的 16 个域的访问权限。

CP15 的寄存器 C5:
CP15 中的寄存器 C5 是失效状态寄存器,分为指令状态失效和数据状态失效。
MRC p15, 0, <Rd>, c5, c0, 0 访问数据失效状态寄存器
MRC p15, 0, <Rd>, c5, c0, 1 访问指令状态失效寄存器

CP15的寄存器C6:
CP15 中的寄存器 C6 是失效地址寄存器,其中保存了引起存储访问失效的地址,分为数据失效地址寄存器和指令失效地址寄存器
MRC p15, 0, <Rd>, c6, c0, 0 访问数据失效地址寄存器
MRC p15, 0, <Rd>, c6, c0, 2 访问指令失效地址寄存器

CP15的寄存器C7:
CP15 的 C7 寄存器用来控制 cache 和写缓存,它是一个只写寄存器,读操作将产生不可预知的后果。
访问 CP15 的 C7 寄存器的指令格式如下所示:
mcr p15, 0, <rd>, <c7>, crm, <opcode_2> ;<rd> 、 <crm> 和 <opcode_2> 的不同取值组合,实现不同功能

CP15的寄存器C8:
系统协处理器CP15的寄存器C8就是清除TLB内容的相关操作。它是一个只写的寄存器。
MCR p15,0,Rd,c8,CRm,opcode_2

CP15的寄存器C12
CP15寄存器C12用来设置异常向量基地址,其编码格式如下所示:
MCR p15, 0, <Rd>, c12, c0, 0 ;Rd中存放要修改的异常向量基地址

CP15的寄存器C13
CP15中的寄存器C13用于快速上下文切换。其编码格式如下所示。
*/
/*
cpu 引导过程 当上电时 跑BROM的程序 会检测spi闪存内有没有符合规范的引导信息。 所以这里的_start小段常数里就放了这些信息
注意代码编译好了还需要 用mksunxi.exe将这个位置的某些地方修改一下保存到bin文件,再烧到闪存才有效。

如果再仔细研究一下fel.exe 的代码,里面很多小段小段的2进制代码,这些2进制的汇编源码在fel源代码码里也注释了。
这样就可以直接通过jatg调试器按规则下载那些小段小段的代码到芯片执行,之后直接下载自己的编译代码到内存运行。
就可以快速执行调试代码了,效率比烧闪存要快很多,并且我是想用keil,效率更高,因为可以直观的看断点后的所有寄存器和变量等。

关于怎么在keil下,编译后下载代码到内存,并执行代码,可参考asm9260t.ini 文件

(只要不烧本代码到闪存,新片就会进入FEL模式,并且usb也变成了下载程序的接口)

目前手上没f1c100的板子。在h2+的板子上测试了下xboot,但是先下载spl ,才能下载xboot执行,
并不是像填坑网讲的那样。直接下xboot,因为EFL模式下,会检测到xboot的代码超过了长度。
不知道f1c100是不是支持直接下xboot,还是说他的spi闪存里有spl的代码。

昨天看了填坑网的实验。原来是spi闪存里有spl引导程序 ,也就是原厂固件的前16k,有了这前16k,代码就不需要进入FEL模了,
芯片启动后会执行这里的代码。

我在思考一个问题。
1 对于不是定制的芯片,一定要在程序里做自己的加密和防止代码被复制的可能,当然在开源的代码下,没有必要,因为要遵循开源协议。
国产的系体没有这个限制,因为它的协议是,自己代码的部分可以不开源。

2 到底是定制spl ,还是定制BROM, 否则怎么区别世面上同类被仿照的产品。spl可以不需要芯片厂商的参与,自己解决,相对麻烦少很多。
但代码被复制的可能性很大。也可以通过软件的手段解决,但也会有麻烦事情。

3 很多通用的mcu, 其实都有这些所谓的BROM和SPL,只不过从来没有出现过。
导致他们认为自己的代码很安全。对于芯片厂商都是虚设。
如果某个芯片厂商人员外泄,一切都变得不安全。

只要开网络你们就把我的鼠标搞到不能正常。我靠

1 GM8136s 25的价格不能接受。 2功耗 3 keil 不支持arm v6, 快捷的调试很重要。
*/
.global return_to_fel
return_to_fel:
mov r0, #0x4
mov r1, #'e'
strb r1, [r0, #0]
mov r1, #'G'
strb r1, [r0, #1]
mov r1, #'O'
strb r1, [r0, #2]
mov r1, #'N'
strb r1, [r0, #3]
mov r1, #'.'
strb r1, [r0, #4]
mov r1, #'F'
strb r1, [r0, #5]
mov r1, #'E'
strb r1, [r0, #6]
mov r1, #'L'
strb r1, [r0, #7]
ldr r0, =0x00000040
ldr sp, [r0, #0]
ldr lr, [r0, #4]
ldr r1, [r0, #16]
mcr p15, 0, r1, c1, c0, 0
ldr r1, [r0, #12]
mcr p15, 0, r1, c1, c0, 0
ldr r1, [r0, #8]
msr cpsr, r1
bx lr
/ 将BROM程序 进入本复位代码时保存的现场及相关又恢复,并返回到BROM程序 /
/*

  • Exception handlers 下面的需要修改到系统需要的。

  • 一般系统会提供一些函数给异常调用,还有保存现场和恢复现场的代码。 这样看xboot,还离做系统很远。
    */
    .align 5
    undefined_instruction:
    b .

.align 5
software_interrupt:
b .

.align 5
prefetch_abort:
b .

.align 5
data_abort:
b .

.align 5
not_used:
b .

.align 5
irq:
ldr sp, _stack_irq_end
sub sp, sp, #72
stmia sp, {r0 - r12}
add r8, sp, #60
stmdb r8, {sp, lr}^
str lr, [r8, #0]
mrs r6, spsr
str r6, [r8, #4]
str r0, [r8, #8]
mov r0, sp
bl arm32_do_irq
ldmia sp, {r0 - lr}^
mov r0, r0
ldr lr, [sp, #60]
add sp, sp, #72
subs pc, lr, #4

.align 5
fiq:
ldr sp, _stack_irq_end
sub sp, sp, #72
stmia sp, {r0 - r12}
add r8, sp, #60
stmdb r8, {sp, lr}^
str lr, [r8, #0]
mrs r6, spsr
str r6, [r8, #4]
str r0, [r8, #8]
mov r0, sp
bl arm32_do_fiq
ldmia sp, {r0 - lr}^
mov r0, r0
ldr lr, [sp, #60]
add sp, sp, #72
subs pc, lr, #4

/*

  • The location of section
    */
    .align 4
    _image_start:
    .long __image_start
    _image_end:
    .long __image_end
    _data_shadow_start:
    .long __data_shadow_start
    _data_shadow_end:
    .long __data_shadow_end
    _data_start:
    .long __data_start
    _data_end:
    .long __data_end
    _bss_start:
    .long __bss_start
    _bss_end:
    .long __bss_end
    _stack_und_end:
    .long __stack_und_end
    _stack_abt_end:
    .long __stack_abt_end
    _stack_irq_end:
    .long __stack_irq_end
    _stack_fiq_end:
    .long __stack_fiq_end
    _stack_srv_end:
    .long __stack_srv_end

离线

#2 2018-04-10 06:50:13

daydayup
会员
注册时间: 2017-10-09
已发帖子: 343
积分: 343

Re: xboot 启动代码分析

感谢分析

离线

#3 2018-04-10 10:33:35

kgp0213
会员
注册时间: 2018-01-15
已发帖子: 149
积分: 149

Re: xboot 启动代码分析

用心的楼主,版主可以过来开一个xboot的专栏板块了

离线

#4 2018-04-11 19:46:19

kgp0213
会员
注册时间: 2018-01-15
已发帖子: 149
积分: 149

Re: xboot 启动代码分析

请问楼主,我要把你这个转载走可以吧,会给你署名的。

离线

#5 2018-09-01 07:29:27

awfans
会员
注册时间: 2018-04-03
已发帖子: 264
积分: 264

Re: xboot 启动代码分析

放狗搜了一圈,又回到挖坑网, 太好了,顶上去.

离线

#6 2019-10-30 19:55:42

ffplay
会员
注册时间: 2019-08-31
已发帖子: 92
积分: 92

Re: xboot 启动代码分析

用心的楼主, 居然跟着注释看懂一点点了.

离线

#7 2022-06-26 15:50:03

go369
会员
注册时间: 2022-06-07
已发帖子: 24
积分: 60

Re: xboot 启动代码分析

楼主还有进一步的教程吗?这xboot到目前为止,还无从下手进行开发测试。

离线

#8 2022-11-23 10:04:12

zhongzhong17
会员
注册时间: 2022-11-22
已发帖子: 9
积分: 4

Re: xboot 启动代码分析

xboot 和 uboot 都没搞清楚的我 捂脸飘过

离线

#10 2023-08-04 10:02:52

wuxing0911
会员
注册时间: 2023-07-29
已发帖子: 4
积分: 4

Re: xboot 启动代码分析

编译完成后下载进去后没有任何反应是怎么回事呢?

离线

#12 2023-08-06 12:31:43

bidezhi7777
会员
注册时间: 2021-04-22
已发帖子: 23
积分: 3

Re: xboot 启动代码分析

wuxing0911 wrote:

编译完成后下载进去后没有任何反应是怎么回事呢?

注意代码编译好了还需要 用mksunxi.exe将这个位置的某些地方修改一下保存到bin文件,再烧到闪存才有效。

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn


东莞哇酷科技有限公司开发