核使用R52,参考汇编模板,一步一步来实现。
首先是ld文件,这个没啥好说的,主要是关注给vector_table划一块地址、stack地址,如下:
- .text.intvec :
- {
- _vectors_start = .;
- KEEP(*(.text.intvec))
- _vectors_end = .;
- } > BOOTROM
-
- .irq_stack :
- {
- . = ALIGN(16);
- __IrqStackBase = .;
- /* Place the irq_stack here. */
- KEEP(*(.irq_stack))
- . = irq_stack_size;
- __IrqStackLimit = .;
- } > ATCMx
注意哦,我特别没有在这里还对齐处理,原因是想在.S里验证对齐的作用。
现在开始写vector_table。
默认情况下,R52复位后是在EL2(Hyp mode).
因此首先是要把EL2、1等级下的中断向量表给做出来,例如:EL2_Vector_Tabel
- .macro vector_section label
- .section .text.intvec, "ax"
- .endm
-
- vector_section EL2_VectorTable:
- ldr pc, = el2_reset_entry
- ldr pc, = el2_undefine_entry
- ...
- ldr pc, = el2_irq_entry
- ldr pc, = el2_fiq_entry
-
- .align 5
- EL1_VectorTable:
- nop
- ...
- ldr pc, = el1_irq_entry
- ldr pc, = el1_fiq_entry
注意看,我在table前面加了个宏,这个标签有什么用呢?
就是将EL2的table放到链接文件指定的section .text.intvec。
后面我陆续试过,如果EL2table没有这个标签,会直接放到.text段;如果是放在EL2table下面,那么之后的代码会放到.intvec段,所以,这个宏感觉有点像块砖,哪里需要哪里搬。但是我后面又设计了一下,EL2Table放.intvec段,EL1Table放.text,就必须在EL1Table前加.text的放置。除了上述方式,参考#pragma。
关于EL1的vectorTable定义,我特地没有做el1_reset_entry。因为R52 reset默认进入EL2模式,因此好像不太需要这个entry,直接定义一个el1的处理函数,这里留个口子,看以后是否会遇到reset 进el1的情况。
此外,对EL1的table做了对齐,.align 5 表示以2^5对齐。
el2_reset_entry,以word对齐,为啥?我们现在用的32位,因此填充PC肯定是32位。这里没有.word也没关系,编译器会自动处理。
现在R52进到了el2的reset_entry里,那么首先要做的就是再确认下是不是el2的模式,为啥?因为pc指针指向的只是一个地址,这个地址里可以是el1_vector_table、也可以是el2的。所以要确认,怎么确认?读取cpsr.mode,如果该mode ==hyp,跳转到正式处理hyp的函数里。否则panic。
这里就主要是设置hyp的中断向量表到HVBAR,使能hyp的cache加快启动速度。
步骤如下:
在EL1_init最先需要做啥?
毫无疑问如果没有在EL2设置VBAR,那么就要在这里做VBAR。
第二个事情就是,初始化C运行环境,具体如下:
如下:
- cps #17 /* FIQ mode */
- ldr sp, =__FiqStackLimit
- cps #18 /* IRQ mode */
- ldr sp, =__IrqStackLimit
- cps #23 /* Abort mode */
- ldr sp, =__AbtStackLimit
- cps #27 /* Undef mode */
- ldr sp, =__UndStackLimit
- cps #31 /* System mode */
- ldr sp, =__SysStackLimit
- cps #19 /* SVC mode */
- ldr sp, =__SvcStackLimit
- dsb
- isb
最后跳转至main
舒服,学到了一些技巧