我是靠谱客的博主 怕孤独樱桃,最近开发中收集的这篇文章主要介绍SylixOS arm64 异常向量表,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

在VBAR_ELx寄存器中存放着异常向量基地址

;/*********************************************************************************************************
;  关中断并设置异常向量表
;*********************************************************************************************************/

    MSR     DAIFSET ,  #2
    ADRP    X0 ,       vector
    ADD     X0 ,       X0 , #:lo12:vector
    MSR     VBAR_EL1 , X0

vector 是 定义的函数。

;/*********************************************************************************************************
;  向量表定义
;*********************************************************************************************************/

MACRO_DEF(VENTRY label)
    .balign  128
    B      label
MACRO_END()

    .balign  2048
FUNC_DEF(vector)
    VENTRY(archEL1SyncInvalidEntry)                                     ;/*  Sync  EL1t                  */
    VENTRY(archEL1IrqInvalidEntry)                                      ;/*  IRQ   EL1t                  */
    VENTRY(archEL1FiqInvalidEntry)                                      ;/*  FIQ   EL1t                  */
    VENTRY(archEL1ErrInvalidEntry)                                      ;/*  Error EL1t                  */

    VENTRY(archEL1SyncExcEntry)                                         ;/*  Sync  EL1h                  */
    VENTRY(archEL1IrqEntry)                                             ;/*  IRQ   EL1h                  */
    VENTRY(archEL1FiqInvalidEntry)                                      ;/*  FIQ   EL1h                  */
    VENTRY(archEL1ErrInvalidEntry)                                      ;/*  Error EL1h                  */

    VENTRY(archEL2AArch64SyncExcEntry)                                  ;/*  Sync  EL0 AArch64           */
    VENTRY(archEL2AArch64IrqEntry)                                      ;/*  IRQ   EL0 AArch64           */
    VENTRY(archEL2AArch64FiqInvalidEntry)                               ;/*  FIQ   EL0 AArch64           */
    VENTRY(archEL2AArch64ErrInvalidEntry)                               ;/*  Error EL0 AArch64           */

    VENTRY(archEL2AArch32SyncExcEntry)                                  ;/*  Sync  EL0 AArch32           */
    VENTRY(archEL2AArch32IrqEntry)                                      ;/*  IRQ   EL0 AArch32           */
    VENTRY(archEL2AArch32FiqInvalidEntry)                               ;/*  FIQ   EL0 AArch32           */
    VENTRY(archEL2AArch32ErrInvalidEntry)                               ;/*  Error EL0 AArch32           */
    FUNC_END()

    FILE_END()

VENTRY 是定义的宏以128 字节对齐。 异常向量表必须是2K对齐,因为VBAR_ELx 后低12位不保存。

为什么以128字节对齐是因为arm定义的异常entry偏移。armv8中分同步异常和异步异常。IRQ,FIQ,SError 为异步异常

。什么是异步异常(asynchronous exception)和同步异常(synchronous exception)可以参考ARMV8异常处理,arm64启动-异常向量表。 下图文档中的介绍的偏移。为什么sync和error都是无效的可以参考ARM64的启动过程之(六):异常向量表的设定给的介绍。

 在SylixOS中最终无效的中断都会跳转到 ARCH_INVALID_EXC_ENTRY 这个宏定义

;/*********************************************************************************************************
;  Invalid 异常入口
;*********************************************************************************************************/

MACRO_DEF(ARCH_INVALID_EXC_ENTRY type)
    ;/*
    ; * 使用异常临时栈, 并在异常临时栈开辟临时上下文保存区, 将 volatile 寄存器保存到临时上下文保存区
    ; * SP 指向异常临时栈
    ; */
    EXC_SAVE_VOLATILE

    BL      API_InterEnter

    ;/*
    ; * 如果不是第一次进入中断, 跳转
    ; */
    CMP     X0 , #1
    BNE     1f

    ;/*
    ; * 获得当前任务 TCB 的 ARCH_REG_CTX 地址
    ; */
    BL      API_ThreadTcbInter                                          ;/*  get current tcb             */

    ;/*
    ; * 拷贝 volatile 寄存器到当前任务 TCB 的 ARCH_REG_CTX 里
    ; */
    EXC_COPY_VOLATILE

    ;/*
    ; * 保存 non volatile 寄存器到当前任务 TCB 的 ARCH_REG_CTX 里
    ; */
    EXC_SAVE_NON_VOLATILE

    MOV     X18, X0

    ;/*
    ; * 第一次进入中断: 获得当前 CPU 中断堆栈栈顶, 并设置 SP
    ; */
    BL      API_InterStackBaseGet
    MOV     SP , X0

    MOV     X0 , X18
2:
    ;/*
    ; * archInvalidExcHandle()
    ; */
    MRS     X1 , ESR_EL1
    MOV     X2 , type
    BL      archInvalidExcHandle

    ;/*
    ; * 来到这里, 说明发生了中断嵌套
    ; */
    MOV     X18 , SP
    RESTORE_BIG_REG_CTX                                                 ;/*  恢复所有寄存器              */

1:
    ;/*
    ; * 不是第一次进入中断
    ; */
    LDR     X0  , [SP, #XSP_OFFSET]                                     ;/*  获取异常前 SP               */
    SUB     X0  , X0 , ARCH_REG_CTX_SIZE                                ;/*  在异常堆栈开辟上下文保存区  */

    ;/*
    ; * 拷贝 volatile 寄存器到异常堆栈里的上下文保存区
    ; */
    EXC_COPY_VOLATILE

    ;/*
    ; * 保存 non volatile 寄存器到异常堆栈里
    ; */
    EXC_SAVE_NON_VOLATILE

    MOV     SP , X0                                                     ;/*  使用异常堆栈                */
    B       2b
    MACRO_END()

EXC_SAVE_VOLATILE 首先保存上下文寄存器。

MACRO_DEF(EXC_SAVE_VOLATILE)
    MRS     X18 , TPIDR_EL1                                             ;/*  读出异常临时堆栈地址        */
    SUB     X18 , X18 , ARCH_REG_CTX_SIZE                               ;/*  在临时堆栈开辟上下文保存区  */

    STP     X0  , X1  ,  [X18 , #XGREG_OFFSET(0)]
    STP     X2  , X3  ,  [X18 , #XGREG_OFFSET(2)]
    STP     X4  , X5  ,  [X18 , #XGREG_OFFSET(4)]
    STP     X6  , X7  ,  [X18 , #XGREG_OFFSET(6)]
    STP     X8  , X9  ,  [X18 , #XGREG_OFFSET(8)]
    STP     X10 , X11 ,  [X18 , #XGREG_OFFSET(10)]
    STP     X12 , X13 ,  [X18 , #XGREG_OFFSET(12)]
    STP     X14 , X15 ,  [X18 , #XGREG_OFFSET(14)]
    STP     X16 , X17 ,  [X18 , #XGREG_OFFSET(16)]
    STP     X29 , LR  ,  [X18 , #XGREG_OFFSET(29)]

    MRS     X2 , SPSR_EL1
    STR     X2 , [X18, #XPSTATE_OFFSET]                                 ;/*  保存 PSTATE                 */

    MOV     X2 , SP
    STR     X2 , [X18, #XSP_OFFSET]                                     ;/*  保存 SP 指针                */

    MRS     X2 , ELR_EL1
    STR     X2 , [X18, #XPC_OFFSET]

    MOV     SP , X18
    MACRO_END()

TPIDR_EL1 是线程ID寄存器,在SylixOS中使用这个寄存器保存了异常临时栈堆栈的地址。MSR指令将指针加载到X18寄存器,然后向下减,开辟出一个块保存上下文呢的区域。 STP 指令时同时将两个寄存器的值写入到存储中。LR 就是x30 寄存器,首先将x0 - x17寄存器保存外加x29 和x30。然后保存状态寄存器SPSR。因为系统时运行在EL1层所以当前操作的都是EL1的寄存器。然后保存栈指针寄存器SP。保存异常链接寄存器。然后更新了栈指针寄存器指向增加了上下文后的栈指针位置。  BL      API_InterEnter 跳转到内核中断入口函数API_InterEnter。

ULONG    API_InterEnter (ARCH_REG_T  reg0,
                         ARCH_REG_T  reg1,
                         ARCH_REG_T  reg2,
                         ARCH_REG_T  reg3)
{
    PLW_CLASS_CPU  pcpu;
    
    pcpu = LW_CPU_GET_CUR();
    pcpu->CPU_ulInterNesting++;

#if !defined(__SYLIXOS_ARM_ARCH_M__) || (LW_CFG_CORTEX_M_SVC_SWITCH > 0)
    archIntCtxSaveReg(pcpu, reg0, reg1, reg2, reg3);
#endif

#if (LW_CFG_CPU_FPU_EN > 0) && (LW_CFG_INTER_FPU > 0)
    if (LW_KERN_FPU_EN_GET()) {                                         /*  中断状态允许使用浮点运算    */
        __fpuInterEnter(pcpu);
    }
#endif                                                                  /*  LW_CFG_CPU_FPU_EN > 0       */
                                                                        /*  LW_CFG_INTER_FPU > 0        */
#if (LW_CFG_CPU_DSP_EN > 0) && (LW_CFG_INTER_DSP > 0)
    if (LW_KERN_DSP_EN_GET()) {                                         /*  中断状态允许使用 DSP        */
        __dspInterEnter(pcpu);
    }
#endif                                                                  /*  LW_CFG_CPU_DSP_EN > 0       */
                                                                        /*  LW_CFG_INTER_DSP > 0        */
    return  (pcpu->CPU_ulInterNesting);
}

API_InterEnter主要时当前cpu ID 中断嵌套基数。获取cpu ID。 获取当前cpu ID 使用如下函数


FUNC_DEF(archMpCur)
    MRS     X0 , TPIDR_EL1
    LDR     X0 , [X0 , #CPUID_OFFSET]
    RET
    FUNC_END()

也是从堆栈中获得,这里时启动时系统将从 MPIDR_EL1 寄存器获取的物理cpu信息存放在栈中。 具体可以参考另一篇文章文章链接

  CMP     X0 , #1    BNE     1f  这两句比对是不是头一次进中断,如果不是第一次跳转到 标签1处执行。如果是第一次继续向下执行。然后跳转到API_ThreadTcbInter函数,获取当前中断线程的tcp。

PLW_CLASS_TCB  API_ThreadTcbInter (VOID)
{
    PLW_CLASS_TCB   ptcbCur;
    
    LW_TCB_GET_CUR(ptcbCur);

    return  (ptcbCur);
}

此函数也是从堆栈中获取cpu id 然后从对用的cpu结构中获取tcp。由于返回值tcp 指针存放在x0寄存器中。所以调用EXC_COPY_VOLATILE 保存寄存器到tcp控制块中时直接使用x0作为基地址。

;/*********************************************************************************************************
;  拷贝 volatile 寄存器(参数 X0: 目的 ARCH_REG_CTX 地址, 参数 SP: 源 ARCH_REG_CTX 地址)
;*********************************************************************************************************/

MACRO_DEF(EXC_COPY_VOLATILE)
    LDP     X9  , X10 ,  [SP , #XGREG_OFFSET(0)]
    STP     X9  , X10 ,  [X0 , #XGREG_OFFSET(0)]
    LDP     X9  , X10 ,  [SP , #XGREG_OFFSET(2)]
    STP     X9  , X10 ,  [X0 , #XGREG_OFFSET(2)]
    LDP     X9  , X10 ,  [SP , #XGREG_OFFSET(4)]
    STP     X9  , X10 ,  [X0 , #XGREG_OFFSET(4)]
    LDP     X9  , X10 ,  [SP , #XGREG_OFFSET(6)]
    STP     X9  , X10 ,  [X0 , #XGREG_OFFSET(6)]
    LDP     X9  , X10 ,  [SP , #XGREG_OFFSET(8)]
    STP     X9  , X10 ,  [X0 , #XGREG_OFFSET(8)]
    LDP     X9  , X10 ,  [SP , #XGREG_OFFSET(10)]
    STP     X9  , X10 ,  [X0 , #XGREG_OFFSET(10)]
    LDP     X9  , X10 ,  [SP , #XGREG_OFFSET(12)]
    STP     X9  , X10 ,  [X0 , #XGREG_OFFSET(12)]
    LDP     X9  , X10 ,  [SP , #XGREG_OFFSET(14)]
    STP     X9  , X10 ,  [X0 , #XGREG_OFFSET(14)]
    LDP     X9  , X10 ,  [SP , #XGREG_OFFSET(16)]
    STP     X9  , X10 ,  [X0 , #XGREG_OFFSET(16)]
    LDP     X9  , X10 ,  [SP , #XGREG_OFFSET(29)]                       ;/*  X29, LR                     */
    STP     X9  , X10 ,  [X0 , #XGREG_OFFSET(29)]
    LDP     X9  , X10 ,  [SP , #XPC_OFFSET]                             ;/*  PC,  SP                     */
    STP     X9  , X10 ,  [X0 , #XPC_OFFSET]
    LDR     X9  ,        [SP , #XPSTATE_OFFSET]                         ;/*  PSTATE                      */
    STR     X9  ,        [X0 , #XPSTATE_OFFSET]
    MACRO_END()

在线程控制块的头部就是寄存器上下问定义,所以可以直接以x0写入

typedef struct __lw_tcb {
    ARCH_REG_CTX          TCB_archRegCtx;                               /*  寄存器上下文                */

在保存完后调用了EXC_SAVE_NON_VOLATILE

MACRO_DEF(EXC_SAVE_NON_VOLATILE)
    MOV     X1  , #0
    STR     X1  , [X0, #CTX_TYPE_OFFSET]                                ;/*  设置为大上下文              */
    STP     X19 , X20 , [X0 , #XGREG_OFFSET(19)]
    STP     X21 , X22 , [X0 , #XGREG_OFFSET(21)]
    STP     X23 , X24 , [X0 , #XGREG_OFFSET(23)]
    STP     X25 , X26 , [X0 , #XGREG_OFFSET(25)]
    STP     X27 , X28 , [X0 , #XGREG_OFFSET(27)]
    MACRO_END()

将剩下的寄存器保存。有个特别的地方,ARCH_REG_CTX 结构体的定义,第一个位置时定义了叫小上下文的变量。所以XGREG_OFFSET定义时是n+1

#define XGREG_OFFSET(n)         (ARCH_REG_SIZE * (n + 1))  

ESR_EL1 寄存器包含了一些当前一些信息。 

ESR_EL1 内容和 当前中断的类型传入到 archInvalidExcHandle函数。archInvalidExcHandle函数主要是打印一些必要的信息,然后重启系统。

在无效中断里其实只有archInvalidExcHandle有作用,其他函数并没有实际意义,只是SylixOS 中断框架是先保存一些上下文环境。

;/*********************************************************************************************************
;  同步异常入口
;*********************************************************************************************************/

FUNC_DEF(archEL1SyncExcEntry)
    ;/*
    ; * 使用异常临时栈, 并在异常临时栈开辟临时上下文保存区, 将 volatile 寄存器保存到临时上下文保存区
    ; * SP 指向异常临时栈
    ; */
    EXC_SAVE_VOLATILE

    BL      API_InterEnter
            
    ;/*
    ; * 如果不是第一次进入中断, 跳转
    ; */
    CMP     X0 , #1
    BNE     1f
    
    ;/*
    ; * 获得当前任务 TCB 的 ARCH_REG_CTX 地址
    ; */
    BL      API_ThreadTcbInter                                          ;/*  get current tcb             */

    ;/*
    ; * 拷贝 volatile 寄存器到当前任务 TCB 的 ARCH_REG_CTX 里
    ; */
    EXC_COPY_VOLATILE

    ;/*
    ; * 保存 non volatile 寄存器到当前任务 TCB 的 ARCH_REG_CTX 里
    ; */
    EXC_SAVE_NON_VOLATILE

    MOV     X18, X0
    ;/*
    ; * 第一次进入中断: 获得当前 CPU 中断堆栈栈顶, 并设置 SP
    ; */
    BL      API_InterStackBaseGet
    MOV     SP , X0

    MOV     X0 , X18
2:
    ;/*
    ; * archSyncExcHandle()
    ; */
    MRS     X1 , ESR_EL1    
    BL      archSyncExcHandle

    ;/*
    ; * API_InterExit()
    ; * 如果没有发生中断嵌套, 则 API_InterExit 会调用 archIntCtxLoad 函数
    ; */
    BL      API_InterExit

    ;/*
    ; * 来到这里, 说明发生了中断嵌套
    ; */
    MOV     X18 , SP
    RESTORE_BIG_REG_CTX                                                 ;/*  恢复所有寄存器              */

1:
    ;/*
    ; * 不是第一次进入中断
    ; */
    LDR     X0  , [SP, #XSP_OFFSET]                                     ;/*  获取异常前 SP               */
    SUB     X0  , X0 , ARCH_REG_CTX_SIZE                                ;/*  在异常堆栈开辟上下文保存区  */

    ;/*
    ; * 拷贝 volatile 寄存器到异常堆栈里的上下文保存区
    ; */
    EXC_COPY_VOLATILE

    ;/*
    ; * 保存 non volatile 寄存器到异常堆栈里
    ; */
    EXC_SAVE_NON_VOLATILE

    MOV     SP , X0                                                     ;/*  使用异常堆栈                */
    B       2b
    FUNC_END()

看同步异常入口,同步异常主要是指令执行产生的异常。首先也是保存当前上下文寄存器到临时栈,然后判断是第几次进入中断,如果是第一次进入中断获取当前cpu 的tcp将寄存器拷贝到tcp中保存。然后通过API_InterStackBaseGet函数获得当前 CPU 中断堆栈栈顶, 并设置 SP。在SylixOS每个核都有一个中断堆栈,在这里获取当前CPU中断堆栈是和SylixOS在中断中检测是否需要调度有关以及中断服务程序有关,中断服务程序执行使用CPU对应的中断堆栈。 然后调用archSyncExcHandle 函数,此时archSyncExcHandle函数参数是x0,x0保存的是当前tcp的指针。所以archSyncExcHandle函数第一个参数是是tcp指针,tcp结构题第一个就是上下文结构体,所以把上下文传入进来。第二个参数是x1 寄存器。寄存器中是ESR寄存器的值。根据ESR寄存器,在archSyncExcHandle函数中进行判断并做了相应的处理。

然后调用API_InterExit 函数,在API_InterExit函数中会将中断嵌套计数减1.同时在此函数中调用一个对系统调度很重要的函数__KERNEL_SCHED_INT 。此函数会查找当前系统是否有需要调用的任务。如果有会在此进行调用,最后在API_InterExit调用了archIntCtxLoad函数,进行任务加载。

;/*********************************************************************************************************
;  中断返回时, 线程装载 
;  参数为当前 CPU 控制块, 即 X0 为当前 CPU 控制块指针
;*********************************************************************************************************/

FUNC_DEF(archIntCtxLoad)
    LDR     X18 , [X0]                                                  ;/*  获取当前 TCB 的 REG_CTX 地址*/
    LDR     X9  , [X18, #CTX_TYPE_OFFSET]                               ;/*  获得上下文类型              */
    CMP     X9  , #0
    B.NE    _RestoreSmallCtx

    RESTORE_BIG_REG_CTX                                                 ;/*  恢复大寄存器上下文          */
    FUNC_END()

通过x0 获取当前的tcp。CTX_TYPE_OFFSET 当时在保存上下文寄存器的值是赋值为0,所以这里会跳转到RESTORE_BIG_REG_CTX这执行。不执行BNE 那条指令。

MACRO_DEF(RESTORE_BIG_REG_CTX)
    LDR     X1 , [X18 , #XSP_OFFSET]                                    ;/*  恢复 SP 指针                */
    MOV     SP , X1

    RESTORE_PSTATE                                                      ;/*  恢复 PSTATE                 */

    LDR     X1 , [X18 , #XPC_OFFSET]                                    ;/*  恢复 PC 到 ELR_EL1          */
    MSR     ELR_EL1 , X1

    LDP     X0  , X1  ,  [X18 , #XGREG_OFFSET(0)]
    LDP     X2  , X3  ,  [X18 , #XGREG_OFFSET(2)]
    LDP     X4  , X5  ,  [X18 , #XGREG_OFFSET(4)]
    LDP     X6  , X7  ,  [X18 , #XGREG_OFFSET(6)]
    LDP     X8  , X9  ,  [X18 , #XGREG_OFFSET(8)]
    LDP     X10 , X11 ,  [X18 , #XGREG_OFFSET(10)]
    LDP     X12 , X13 ,  [X18 , #XGREG_OFFSET(12)]
    LDP     X14 , X15 ,  [X18 , #XGREG_OFFSET(14)]
    LDP     X16 , X17 ,  [X18 , #XGREG_OFFSET(16)]
    LDP     X19 , X20 ,  [X18 , #XGREG_OFFSET(19)]
    LDP     X21 , X22 ,  [X18 , #XGREG_OFFSET(21)]
    LDP     X23 , X24 ,  [X18 , #XGREG_OFFSET(23)]
    LDP     X25 , X26 ,  [X18 , #XGREG_OFFSET(25)]
    LDP     X27 , X28 ,  [X18 , #XGREG_OFFSET(27)]
    LDP     X29 , LR  ,  [X18 , #XGREG_OFFSET(29)]
    LDR     X18 ,        [X18 , #XGREG_OFFSET(18)]

    ERET
    MACRO_END()

根据函数内容是将tcp中的上下文回复到寄存器中。如果有调度的进程,这里是把该任务tcp中的上下文寄存器恢复到arm 寄存器中。如果没有还是原来的tcp的上下文寄存器恢复回去。

不讨论中断嵌套情况,下面看进入到archEL1IrqEntry 函数,这也是普通外部中断进入的函数。

;/*********************************************************************************************************
;  中断入口
;*********************************************************************************************************/

FUNC_DEF(archEL1IrqEntry)
    ;/*
    ; * 使用异常临时栈, 并在异常临时栈开辟临时上下文保存区, 将 volatile 寄存器保存到临时上下文保存区
    ; * SP 指向异常临时栈
    ; */
    EXC_SAVE_VOLATILE

    BL      API_InterEnter

    ;/*
    ; * 如果不是第一次进入中断, 跳转
    ; */
    CMP     X0 , #1
    BNE     1f

    ;/*
    ; * 获得当前任务 TCB 的 ARCH_REG_CTX 地址
    ; */
    BL      API_ThreadTcbInter                                          ;/*  get current tcb             */

    ;/*
    ; * 拷贝 volatile 寄存器到当前任务 TCB 的 ARCH_REG_CTX 里
    ; */
    EXC_COPY_VOLATILE

    ;/*
    ; * 保存 non volatile 寄存器到当前任务 TCB 的 ARCH_REG_CTX 里
    ; */
    EXC_SAVE_NON_VOLATILE

    ;/*
    ; * 第一次进入中断: 获得当前 CPU 中断堆栈栈顶, 并设置 SP
    ; */
    BL      API_InterStackBaseGet
    MOV     SP , X0

2:
    ;/*
    ; * bspIntHandle()
    ; */
    BL      bspIntHandle

    ;/*
    ; * API_InterExit()
    ; * 如果没有发生中断嵌套, 则 API_InterExit 会调用 archIntCtxLoad 函数
    ; */
    BL      API_InterExit

    ;/*
    ; * 来到这里, 说明发生了中断嵌套
    ; */
    MOV     X18 , SP
    RESTORE_BIG_REG_CTX                                                 ;/*  恢复所有寄存器              */

1:
    ;/*
    ; * 不是第一次进入中断
    ; */
    LDR     X0  , [SP, #XSP_OFFSET]                                     ;/*  获取异常前 SP               */
    SUB     X0  , X0 , ARCH_REG_CTX_SIZE                                ;/*  在异常堆栈开辟上下文保存区  */

    ;/*
    ; * 拷贝 volatile 寄存器到异常堆栈里的上下文保存区
    ; */
    EXC_COPY_VOLATILE

    ;/*
    ; * 保存 non volatile 寄存器到异常堆栈里
    ; */
    EXC_SAVE_NON_VOLATILE

    MOV     SP , X0                                                     ;/*  使用异常堆栈                */
    B       2b
    FUNC_END()
    

和archEL1SyncExcEntry 有区别的是调用了bspIntHandle函数。 这个函数是bsp函数,需要在板级支持包中实现。

VOID  bspIntHandle (VOID)
{
    REGISTER UINT32  uiAck       = armGicIrqReadAck();
    REGISTER UINT32  uiSourceCpu = (uiAck >> 10) & 0x7;
    REGISTER UINT32  uiVector    = uiAck & 0x1FF;

    (VOID)uiSourceCpu;

    archIntHandle((ULONG)uiVector, LW_FALSE);

    armGicIrqWriteDone(uiAck);
}

上面是H6的 bspIntHandle函数。这里主要是调用archIntHandle函数,不同的芯片需要在这里获取中断向量号uiVectror传递给archIntHandle函数。

 irqret = API_InterVectorIsr(ulVector);                              /*  调用中断服务程序            */
    
    KN_INT_DISABLE();                                                   /*  禁能中断                    */

在archIntHandle主要是上面两个函数,一个调用中断服务程序,一个是禁能中断。API_InterVectorIsr开始查找中断号绑定的函数,然后执行。

最后

以上就是怕孤独樱桃为你收集整理的SylixOS arm64 异常向量表的全部内容,希望文章能够帮你解决SylixOS arm64 异常向量表所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(35)

评论列表共有 0 条评论

立即
投稿
返回
顶部