飞腾CPU虚拟化相关代码分析(一)—— 函数el2_setup

函数el2_setup是ARM64体系结构下Linux内核运行的第一个和虚拟化相关的函数。

相关概念

ARM64支持两种虚拟方式:Hyp和VHE两种方式。

  1. 传统分裂模式Hyp:

宿主OS内核处于EL1状态,客户OS内核也处于EL1状态,CPU需要两次陷入和四次上下文切换才能完成一次对客户OS的服务。

  1. 虚拟主机扩展模式VHE(当前飞腾CPU还没有支持VHE模式):

宿主OS内核处于EL2状态,客户OS内核处于EL1状态,CPU只需要一次陷入和两次上下文切换就可以完成一次对客户OS的服务。

函数输入输出描述

  1. 输入
  1. MMU关闭,数据cache关闭。
  2. x21保存了设备树起始地址,在启动阶段不能被占用。
  3. u64 __cacheline_aligned boot_args[4]保存了寄存器x0/1/2/3
    1)boot_args[0]保存了设备树起始地址。
    2)boot_args[1]-[3]如果非零,表示固件不是符合标准的UEFI,很可能就是uboot。
  1. 输出
  1. 寄存器w0返回,刚刚进入内核时,CPU的权限级
    1) BOOT_CPU_MODE_EL1:表示当前CPU跳入内核时处于权限级EL1;函数正常返回,无权限级切换。
    2)BOOT_CPU_MODE_EL2:表示当前CPU跳入内核时处于权限级EL2。此次内核启动可以支持KVM虚拟机,Hyp模式下函数异常返回,需要将CPU切换回EL1权限级;如果VHE模式,函数正常返回,CPU保持EL2权限级。

函数分析

  1. 堆栈寄存器的选择

msr SPsel, #1

  1. 判断当前CPU权限级

mrs x0, CurrentEL
cmp x0, #CurrentEL_EL2
b.eq 1f
/*不跳转,说明当前为EL1,内核后续不能支持虚拟化*/
1: /*跳转,说明当前为EL2,el2_setup函数为后续虚拟化做好铺垫*/

  1. 如果当前CPU权限级已经是EL1,通过设置sctlr_el1,将CPU的EL0/1设置为小端模式,就直接调用ret指令返回,返回地址为lr寄存器所包含的地址(因此el2_setup函数需要用bl调用)。

mov_q x0, (SCTLR_EL1_RES1 | ENDIAN_SET_EL1)
msr sctlr_el1, x0
mov w0, #BOOT_CPU_MODE_EL1
isb
ret

  1. 我们现在在权限级EL2级。
  1. 通过设置sctlr_el2,将CPU的EL2设置为小端模式。
  2. 通过读取id_aa64mmfr1_el1,判断CPU是支持虚拟主机扩展VHE模式,还是传统的分离Hyp模式。
    mrs x2, id_aa64mmfr1_el1
    ubfx x2, x2, #8, #4
  1. 设置Hypervisor配置寄存器hcr_el2。
  1. Hyp模式
    #define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK)
    mov_q x0, HCR_HOST_NVHE_FLAGS
    msr hcr_el2, x0
  2. VHE模式
    #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)
    mov_q x0, HCR_HOST_VHE_FLAGS
    msr hcr_el2, x0

这以后,寄存器x2,零表示Hyp模式;非零表示VHE模式

  1. 设置定时器相关寄存器

将定时器虚拟偏移量清零

  1. Hyp模式
    /*启动计数器事件流*/
    mrs x0, cnthctl_el2
    orr x0, x0, #3
    msr cnthctl_el2, x0
    /*虚拟偏移量清零*/
    msr cntvoff_el2, xzr
  2. VHE模式
    msr cntvoff_el2, xzr
  1. GICv3中断控制器相关设置
  1. 中断控制器类型判断
    mrs x1, id_aa64pfr0_el1
    ubfx x0, x0, #24, #4
    cbz x0, 3f
    /*当中断控制是GICv3时,不发生跳转*/
    ......
    3: /*如果直接跳转到这里,说明CPU不支持GICv3*/
  2. 如果是GICv3,设置SYS_ICC_SRE_EL2、SYS_ICH_HCR_EL2寄存器,这两个寄存器是GICv3的CPU接口寄存器。
    /*不允许内核访问ICC_SRE_EL1;设置采用MSR/MRS方式访问ICC_*相关寄存器*/
    mrs_s x0, SYS_ICC_SRE_EL2
    orr x0, x0, #ICC_SRE_EL2_SRE
    orr x0, x0, #ICC_SRE_EL2_ENABLE
    msr_s SYS_ICC_SRE_EL2, x0
    isb
    mrs_s x0, SYS_ICC_SRE_EL2/*写之后再读,确认是否真正设置成功*/
    tbz x0, #0, 3f
    /*如果SYS_ICC_SRE_EL2寄存器的SRE位不为0,表示设置成功*/
    msr_s SYS_ICH_HCR_EL2, xzr
    3: /*如果设置不成功,就跳转到此处运行*/
    msr_s SYS_ICH_HCR_EL2, xzr /*关闭所有虚拟中断和维护中断*/
  1. 根据物理CPU的ID寄存器和亲合属性寄存器,来设置虚拟CPU对应的寄存器。

/*ID寄存器*/
mrs x0, midr_el1
msr vpidr_el1, x0
/*亲合属性寄存器*/
mrs x1, mpidr_el1
msr vmpidr_el2, x1

  1. 将Hypervisor系统陷入寄存器HSTR_EL2清零。一般情况下,当客户虚拟机是AArch32位,会有Thumb和协处理器方式,不希望在访问相关寄存器陷入到EL2中。

msr hstr_el2, xzr

  1. 获取事件计数器数量。通过AArch64调试特征寄存器0,id_aa64dfr0_el1,判断CPU是否可以访问PMU寄存器,如果可以就获取事件计数器数量,否则直接为零。

mrs x1, id_aa64dfr0_el1
sbfx x0, x1, #8, #4
cmp x0, #1
b.lt 4f
/*id_aa64dfr0_el1的11:8位小于0b0001,不跳转表示,支持性能监控扩展系统寄存器*/
/*当支持PMU时,这里会获取事件计数器数量*/
mrs x0, pmcr_el0
ubfx x0, x0, #11, #5
4:/*跳转,表示支持*/
csel x3, xze, x0, lt /*这条指令的直接含义是:当前面cmp x0, #1和b.lt 跳转成功时,x3直接赋值为零,否则赋值为x0 */

此时,寄存器x3的低5位记录了事件计数器的数量,如果该数量为零,表示不支持PMU

  1. 也是通过AArch64调试特征寄存器0,id_aa64dfr0_el1,判断CPU是否可以访问SPE寄存器。

ubfx x0, x1, #32, #4
cbz x0, 7f
/*不跳转,表示支持PMS*/
/*飞腾还没有支持,这一段我们先不分析(?)*/
7: /*直接跳转到这里,表示不支持SPE*/

  1. 根据前面的第10和第11步,已经完成对寄存器x3的初始化,然后直接赋值给寄存器mdcr_el2。

msr mdcr_el2, x3

  1. 内存模式特征寄存器id_aa64mmfr1_el1,这个寄存器手册上还没有说明。

mrs x1, id_aa64mmfr1_el1
ubfx x0, x1, #ID_AA64MMFR1_LOR_SHIFT, 4
cbz x0, 1f
msr_s SYS_LORC_EL1, zxr
1:

  1. 将非安全态EL0/EL1的stage2阶段的虚拟页表基址寄存器清零,即将寄存器vttbr_el2清零。

msr vttbr_el2, xzr

  1. 从下面代码开始,VHE模式和Hyp模式走向不同的分支。

cbz x2, install_el2_stub
/*VHE模式返回代码*/
install_el2_stub:
/*Hyp模式设置和返回代码*/

  1. 如果是VHE模式,直接返回w0为BOOT_CPU_MODE_EL2。由于进入内核时,CPU处于EL2,所以直接调用ret指令返回,CPU仍然是EL2。

mov w0, #BOOT_CPU_MODE_EL2
isb
ret

  1. install_el2_stub是Hyp模式相关设置和返回代码。
  2. 通过设置sctlr_el1,将CPU的EL0/1设置为小端模式。

mov_q x0, (SCTLR_EL1_RES1 | ENDIAN_SET_EL1)
msr sctlr_el1, x0

  1. 设置寄存器cptr_el2,浮点和ASIMD相关寄存器的访问不陷入EL2

mov x0, #0x33ff
msr cptr_el2, x0

  1. 先判断是否支持SVE指令,如果支持设置相关寄存器访问不陷入EL2,而且设置在EL1可以进行全向量长度支持。
  1. SVE指令支持判断

mrs x1, id_aa64pfr0_el1
ubfx x1, x1, #ID_AA64PFR0_SVE_SHIFT, #4
cbz x1, 7f
/*支持SVE指令*/
7: /**/
2.支持设置相关寄存器访问不陷入EL2
bic x0, x0, #CPTR_EL2_TZ
msr cptr_el2, x0
isb

  1. 设置全向量长度支持

mov x1, #ZCR_ELx_LEN_MASK
msr_s SYS_ZCR_EL2, x1

  1. 设置EL2异常向量表基地址寄存器(参见《飞腾CPU虚拟化相关代码分析(二)之EL2异常向量表》)

adr_l x0, __hyp_stub_vectors /*装载64位地址*/
msr vbar_el2, x0
__hyp_stub_vectors是EL2异常向量表,寄存器vbar_el2是EL2级异常向量表基地址寄存器。

  1. Hyp模式的el2_setup函数返回

mov x0, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT | PSR_MODE_EL1h)
msr spsr_el2, x0
msr elr_el2, lr
mov w0, #BOOT_CPU_MODE_EL2
eret

  1. 设置寄存器spsr_el2是为了返回设置CPU返回后的EL1状态,el1h说明了返回EL1状态,EL1堆栈寄存器采用sp_el1,F/I/A/D表明各种异常都屏蔽。
  2. elr_el2异常链接地址寄存器,也设置为当前链接寄存器lr地址,即即使从EL2返回到EL1,返回地址不变。
  3. eret指令为异常返回指令。

飞腾CPU虚拟化相关代码分析(一)相关推荐

  1. linux 锁屏 代码,Android锁屏与解屏相关代码分析

    我觉得对于普通人来说,最常见的是Android解屏的界面,然后应该是Home界面.今天就来分析一下解屏界面的相关代码(以索爱的解锁界面为例). 首先看解屏的界面,我把解屏的界面分为两个部分,最上部是s ...

  2. eMule 的使用场景及初始化任务描述级eMule相关代码分析(仅涉及ed2k)

    提前说明:从这页博客开始就会涉及eMule源代码的分析(或者说梳理更为合适),梳理源代码的目的在于让大家在看了一下原理后,想看下这些原理的具体实现(看eMule源代码)时轻松些,更有目标.所以在这里笔 ...

  3. 嵌入式Linux内核移植相关代码分析(转)

    本文通过整理之前研发的一个项目(ARM7TDMI +uCLinux),分析内核启动过程及需要修改的文件,以供内核移植者参考.整理过程中也同时参考了众多网友的帖子,在此谢过.由于整理过程匆忙,难免 错误 ...

  4. 1640_MIT 6.828 fork函数的功能以及相关代码分析

    全部学习汇总: GitHub - GreyZhang/g_unix: some basic learning about unix operating system. 继续分析之前看到的一段代码,先梳 ...

  5. 服务器虚拟化相关问题分析,服务器虚拟化后引入的问题分析

    将服务器物理资源抽象成逻辑资源,让一台服务器变成几台甚至上百台相互隔离的虚拟服务器,我们不再受限于物理上的界限,而是让CPU.内存.磁盘.I/O等硬件变成可以动态管理的"资源池", ...

  6. (二)nvidia jetson orin nvcsi tegra-capture-vi camera相关内容梳理 之 nvcsi,v4l2相关代码分析

    背景:对于nvidia 的jetson orin 的camera,其内部是如何实现的尼?硬件方面的pipeline是怎么关联的,其内部有哪些camera相关的modules?对于这些modules,软 ...

  7. (一) nvidia jetson orin nvcsi tegra-capture-vi camera相关内容梳理 之 vi相关代码分析

    背景:对于nvidia 的jetson orin 的camera,其内部是如何实现的尼?硬件方面的pipeline是怎么关联的,其内部有哪些camera相关的modules?对于这些modules,软 ...

  8. 服务器虚拟化相关问题分析,服务器虚拟化中遇到的存储问题分析

    服务器虚拟化可以降低IT开支并提高服务器利用率.但也因为虚拟化的特性,为承载环境中不断增长的虚拟机,需要扩容存储以满足性能与容量的使用需求.IT经理们已经发现,那些因服务器虚拟化所节省的资金都逐渐投入 ...

  9. 《数据结构(C语言版)》-01-绪论-相关代码分析

    例1:算法时间复杂度01-循环 void loveYou(int n){ //n为问题规模int i=1; //爱你的程度,初始值 while(i<=n){i++; //每次+1 printf( ...

最新文章

  1. 【联盛德W806上手笔记】三、MCU系统与时钟结构
  2. linux系统wget、curl终端命令行获取公网ip地址及其他网络信息
  3. mssql 批量导入mysql_mssql 数据库 批量导入指令
  4. linux系统无法读取硬盘,安装CentOS时读取硬盘错误解决办法
  5. 大润发java薪资,大润发edp员工面试:不说位置了,怕备查,哈哈 第一次去是因 - 职朋职业圈...
  6. 2的负x次幂图像_数学| NO.2,3函数 T51
  7. scala 类中的对象是类_Scala类和对象– Singleton对象,伴侣类
  8. ASP.NET MVC载入页面常用方法
  9. Java输出字符串中的叠词_java中正则表达式的简单运用 | iamxiarui
  10. php 单笔转账到支付宝账户,php之支付宝转账或发红包到指定账户(提现功能)
  11. matlab光斑中心,Matlab学习手记——二维高斯曲面拟合法定位光斑中心
  12. yii mysql gii_yii框架之gii的使用
  13. setInterval()的三种写法
  14. NEXTCHIP-图像优化师
  15. 远程控制软件:RemotelyAnywhere 安装使用指南
  16. 红旗桌面版本最新行使流动和结果解答100例-6
  17. im即时通讯聊天软件,完整的一套即时通讯IM源码
  18. 沟渠指什么_沟渠-什么什么照沟渠-什么明月什么沟渠
  19. c语言程序设计二级考试书,全国计算机等级考试用书(C语言程序设计[二级])(新考纲)...
  20. java基于springboot口腔牙科诊所管理系统

热门文章

  1. 计算机科学与技术论文中期检查,2018届计算机科学与技术专业 本科毕业论文(设计)中期检查工作安排...
  2. iGrimace IGevo 非ZNT V8 V3 IOSAPP一键新机 全息备份
  3. 中职计算机基础知识点笔记2
  4. Git 基础入门教程
  5. Rust crates源国内加速镜像配置说明
  6. vue经典面试题,帮你准备未来的面试《一》
  7. 美国调查半导体装置专利侵权事件;“元宇宙业务”未达到Meta预期;kakao回应韩国数据中心火灾事件 | 每日大事件...
  8. linux添加ax88772b驱动,佳能 USB 2.0 to Fast Ethernet AX88772B 驱动程序下载-更新佳能软件(以太网控制器)...
  9. 区块链技术服务于税收治理的深圳实践
  10. 为什么跑完步了膝盖会疼痛?