飞腾CPU虚拟化相关代码分析(二)

飞腾CPU虚拟化相关代码分析(二)——EL2异常向量表

  1. 飞腾CPU采用ARMv8体系结构,在非安全态有四个权限级EL0/1/2/3,其中EL2是Hypervisor权限级,虚拟机监控器VMM代码运行在EL2权限级上。
  2. ARMv8的早期版本只能支持Hyp模式的EL2,即EL2权限级的实现还不能完全支撑虚拟机内核和应用,需要运行在EL1的宿主OS协助完成。(备注:ARMv8的扩展版本支持VHE模式,即宿主OS可以直接运行在EL2模式下,此时VMM和宿主机内核可以共用一个EL2权限级上的异常向量表)
  3. 下面列出了Hyp分裂模式的EL2的异常向量表:
  1. ENTRY(__hyp_stub_vectors)
  1. ventry el2_sync_invalid // Synchronous EL2t
    ventry el2_irq_invalid // IRQ EL2t
    ventry el2_fiq_invalid // FIQ EL2t
    ventry el2_error_invalid // Error EL2t
  2. ventry el2_sync_invalid // Synchronous EL2h
    ventry el2_irq_invalid // IRQ EL2h
    ventry el2_fiq_invalid // FIQ EL2h
    ventry el2_error_invalid // Error EL2h
  3. ventry el1_sync // Synchronous 64-bit EL1
    ventry el1_irq_invalid // IRQ 64-bit EL1
    ventry el1_fiq_invalid // FIQ 64-bit EL1
    ventry el1_error_invalid // Error 64-bit EL1
  4. ventry el1_sync_invalid // Synchronous 32-bit EL1
    ventry el1_irq_invalid // IRQ 32-bit EL1
    ventry el1_fiq_invalid // FIQ 32-bit EL1
    ventry el1_error_invalid // Error 32-bit EL1
  1. ENDPROC(__hyp_stub_vectors)
  1. 根据触发异常的权限级和CPU状态,EL2异常向量表定义了四组:
  1. EL2t,当CPU在EL2且堆栈寄存器为SP_EL0时,触发了异常。
  2. EL2h,当CPU在EL2且堆栈寄存器为SP_EL2时,触发了异常。
  3. AArch64_EL1,当CPU在EL0/1且为AArch64模式,触发了异常。
  4. AArch32_EL1,当CPU在EL0/1且为AArch32模式,触发了异常。
    说明:

1~2,CPU权限级没有发生变化。
3~4,CPU权限级升高了。
这四组是按照位置顺序来定义的。

  1. 根据异常的类型,每一组又分为四个入口点
  1. 同步指令类型,例如系统调用指令、访存的缺页故障等
  2. IRQ中断类型,中断控制器GIC控制的一组外部设备中断
  3. FIQ中断类型,中断控制器GIC控制的另一组外部设备中断
  4. 系统错误类型,片上网络等相关部件故障中断(一般由具体CPU厂商定义的)
    说明:
    这四种类型是按照位置顺序来定义的。
  1. 根据上述EL2异常向量表,当前Hyp模式下虚拟机监控器VMM仅仅支持AArch64模式的虚拟机的同步指令触发的异常。

1.ventry el1_sync
2.*_invalid

  1. ventry代码分析,这是汇编宏。

.macro ventry label
.align 7/*必须按照0x80长度对齐*/
b \label/*虽然可以容纳0x80/4 =0x20条指令,但软件实现为直接跳转*/
.endm

  1. el1_sync代码分析,无返回无条件跳转到el1_sync中,返回采用异常返回eret指令,异常链接寄存器elr_el2已经保存了返回地址,即EL1中触发同步异常的下一条指令地址。

el1_sync:
...
ENDPROC(el1_sync)

cmp x0, #HVC_SET_VECTORS /*判断是否为HVC_SET_VECTORS调用*/
b.ne 2f
...
2: cmp x0, #HVC_SOFT_RESTART /*判断是否为HVC_SOFT_RESTART调用*/
b.ne 3f
...
3: cmp x0, #HVC_RESET_VECTORS/*判断是否为HVC_RESET_VECTORS调用*/
beq 9f
...
9:...

  1. 第一个参数x0是hcall的系统调用号,当前hcall的系统系统调用号为0/1/2

#define HVC_SET_VECTORS 0 设置新的异常向量表,参数x1为新表物理地址。
#define HVC_SOFT_RESTART 1 CPU软件启动
#define HVC_RESET_VECTORS 2 将异常向量表恢复到原始__hyp_stub_vectors
#define HVC_STUB_HCALL_NR 3
#define HVC_STUB_ERR 0xbadca11

  1. 如果调用号为HVC_SET_VECTORS(0), 设置新的异常向量表调用

msr vbar_el2, x1 设置寄存器vbar_el2
mov x0, xzr 正常返回零
eret

  1. 如果调用号为HVC_RESET_VECTORS(2),恢复异常向量表(其实什么也没有做,直接返回)

mov x0, xzr
eret

  1. 如果调用号为HVC_SOFT_RESTART,CPU软件启动
    执行下列代码之前,
    x1是CPU软件启动函数的首地址;
    x2/x3/x4是CPU软件启动函数的第一、二、三个参数

mov x0, x2
mov x2, x4
mov x4, x1
mov x1, x3
br x4 调用CPU软件启动函数之前,x0/x1/x2已经是第一、二、三个参数了。
mov x0, xzr
eret

  1. 出错返回

ldr x0, =HVC_STUB_ERR
eret

  1. 我们再看看虚拟机的内核如何实现HVC_SET/RESET_VECTORS
  1. ENTRY(__hyp_set_vectors)

mov x1, x0
mov x0, #HVC_SET_VECTORS
hvc #0
ret
ENDPROC(__hyp_set_vectors)

  1. ENTRY(__hyp_reset_vectors)

mov x0, #HVC_RESET_VECTORS
hvc #0
ret
ENDPROC(__hyp_reset_vectors)

  1. 最后我们看看虚拟机的内核如何实现HVC_SOFT_RESTART
  1. 主要是调用__cpu_soft_restart(el2_switch, entry, arg0, arg1, arg2)
  1. el2_switch表示CPU是否需要进入EL2权限级
  2. entry表示软件启动CPU的代码地址
  3. arg0/1/2软件启动CPU函数的参数
  1. __cpu_soft_restart代码分析
    ENTRY(__cpu_soft_restart)
    mrs x12, sctlr_el1
    ldr x13, =SCTLR_ELx_FLAGS
    bic x12, x12, x13
    pre_disable_mmu_workaround
    msr sctlr_el1, x12
    isb 上面代码主要是将寄存器sctlr_el1的SCTLR_ELx_FLAGS对应的位清零
    cbz x0, 1f // el2_switch?
    mov x0, #HVC_SOFT_RESTART
    hvc #0 // no return
    1:下面代码是因为不希望CPU陷入EL2来处理。
    mov x18, x1 // entry
    mov x0, x2 // arg0
    mov x1, x3 // arg1
    mov x2, x4 // arg2
    br x18
    ENDPROC(__cpu_soft_restart)
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值