Start文件:
/* start.s文件中的 reset 部分 */
.global _Reset
_Reset:
ldr x1,=arm_vector_table
msr vbar_el1,x1
msr vbar_el2,x1
// 5-7行将定义好的异常向量表加载到el1与el2的vbar中
// vbar_eln 寄存器是用来存储异常向量表基地址的,该异常向量表存放的为发生在eln的异常
adrp x19, stack_top_el2
mov sp,x19 // 将栈指针设为el2的栈顶
MSR SPSEL, #1 // switch to SP_ELn,即使用当前的异常等级栈指针
ldr x6,=_el1_enter
```
_el1_enter:
adrp x19, stack_top_el1
mov sp,x19 // 设置栈顶指针为el1的栈顶指针地址
msr daifclr, #1 // f位置0->FIQ异常不会被屏蔽
msr daifclr, #2 // i位置0->IRQ异常不会被屏蔽
msr daifclr, #4 // a位置0->SError异常不会被屏蔽
msr daifclr, #8 // d位置0->当前异常级别的观察点、断点和软件步骤异常不会被屏蔽。
BL el1_entry // el1_entry中清零了bss段,初始化了gic时钟,设置了计时器为1000ms
ldr x6,=_el0_enter
···
.global _el0_enter
_el0_enter:
adrp x19, stack_top_el0
mov sp,x19 // 设置栈指针指向el0的栈顶
bl el0_entry // el0_entry中启动操作系统
b .
···
msr elr_el1,x6 // 要从el1返回时的地址为_el0_enter
MOV X0, XZR
bic X0, X0, #(1 << 4) // x0的bit4置0
MSR SPSR_EL1, X0 // 存入bit4为0的数,表明运行在AArch64执行状态
eret
```
msr elr_el2,x6 // 设置el2的异常返回地址为_el1_enter
MOV X0, XZR
ORR X0, X0, #(7 << 6) // 禁止IRQ,FIQ,SError位
bic X0, X0, #(1 << 4) // M[4]=0代表为AArch64
ORR X0, X0, #(1 << 2)
ORR X0, X0, #(1 << 0) // M[0:3] = 0b0101,表示挑选栈顶指针为EL1h,即选择了SP_EL1
MSR SPSR_EL2, X0 // 保存el2的spsr,禁止IRQ,FIQ,SError
mov x0,xzr
orr x0,x0,#(1<<31) // x0为0x80000000,即只有bit31为1
MSR hCR_EL2, X0 // hcr的bit31为RW位,对较低异常级别的执行状态控制。0:低层的特权等级全部都是AArch32;1:低一层的特权等级是 AArch64
mrs x5,sctlr_el1
orr x5,x5,#(1<<9)//enable el0 daifconfig
msr sctlr_el1,x5 // bit9控制EL0是否可以访问cpu状态寄存器的PSTATE.{D,A, I, F}比特,为1则可以访问
eret // 返回指令,PE从SPSR恢复PSTATE,并分支到ELR中保存的地址
串口输出模块:
volatile unsigned int * const UART0DR = (unsigned int *)0xc280000; // UART Transmitter Holding Register 的地址
volatile unsigned int * const ULSR = (unsigned int *)0xc280014; // UART LSR (UART Line Status Register)的地址
#define UTHR 0x00 /* UART Transmit Holding Register */
#define ULSR_THRE (1 << 5) /* Transmit Holding Register Empty */
void print_char(const char *s) {
while(*s != '\0') { /* Loop until end of string */
while ((*ULSR & ULSR_THRE) == 0); // 当LSR寄存器的5bit位为0时,Transmit holding register不空,应阻塞
*UART0DR = (unsigned int)(*s); /* Transmit char */
s++; /* Next char */
}
}