armv8(AArch64)编程总结(nx开发板)

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 */
    }
}

你可能感兴趣的:(嵌入式,嵌入式硬件,arm开发)