Skip to content

Commit

Permalink
hvisor loongarch part docs merge 20240716 (#14)
Browse files Browse the repository at this point in the history
* update loongarch docs

* loongarch finish cpu virt and io docs

* polish

* add loongarch_irq.png
  • Loading branch information
enkerewpo authored Jul 20, 2024
1 parent 8fec6d6 commit c2776f4
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@

- [RISC-V 处理器虚拟化](./chap04/subchap01/RISCVirtualization.md)

- [LoongArch处理器虚拟化](./chap04/subchap01/LoongArchVirtualization.md)
- [LoongArch 处理器虚拟化](./chap04/subchap01/LoongArchVirtualization.md)
- [内存虚拟化](./chap04/MemVirtualization.md)
- [中断虚拟化](./chap04/subchap02/InterruptVirtualization.md)

Expand All @@ -61,7 +61,7 @@

- [RISC-V 中断控制 AIA](./chap04/subchap02/RISC-AIA.md)

- [LoongArch 中断控制](./chap04/subchap02/LoonArch-Controller.md)
- [LoongArch 中断控制](./chap04/subchap02/LoongArch-Controller.md)
- [I/O 虚拟化](./chap04/subchap03/IO-Virtualization.md)

- [IOMMU](./chap04/subchap03/IOMMU/IOMMU-Define.md)
Expand Down
Binary file added src/chap04/img/loongarch_7a_intc.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/chap04/img/loongarch_irq.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/chap04/img/loongarch_legacy_int.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
161 changes: 161 additions & 0 deletions src/chap04/subchap01/LoongArchVirtualization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# LoongArch 处理器虚拟化

LoongArch指令集是中国龙芯中科公司于2020年发布的自主RISC指令集,包括基础指令集、二进制翻译拓展(LBT)、向量拓展(LSX)、高级向量扩展(LASX)和虚拟化拓展(LVZ)五个模块。

本文将主要对LoongArch指令集的CPU虚拟化设计进行简要介绍。

## LoongArch寄存器简介

### 通用寄存器使用约定[1]

| 名称 | 别名 | 用途 | 在调用中是否保留 |
| ------------- | ----------- | ------------------------ | ---------------- |
| `$r0` | `$zero` | 常数 0 | (常数) |
| `$r1` | `$ra` | 返回地址 ||
| `$r2` | `$tp` | 线程指针 | (不可分配) |
| `$r3` | `$sp` | 栈指针 ||
| `$r4 - $r5` | `$a0 - $a1` | 传参寄存器、返回值寄存器 ||
| `$r6 - $r11` | `$a2 - $a7` | 传参寄存器 ||
| `$r12 - $r20` | `$t0 - $t8` | 临时寄存器 ||
| `$r21` | 保留 | (不可分配) | |
| `$r22` | `$fp / $s9` | 栈帧指针 / 静态寄存器 ||
| `$r23 - $r31` | `$s0 - $s8` | 静态寄存器 ||

### 浮点寄存器使用约定[1]

| 名称 | 别名 | 用途 | 在调用中是否保留 |
| ------------- | -------------- | ------------------------ | ---------------- |
| `$f0 - $f1` | `$fa0 - $fa1` | 传参寄存器、返回值寄存器 ||
| `$f2 - $f7` | `$fa2 - $fa7` | 传参寄存器 ||
| `$f8 - $f23` | `$ft0 - $ft15` | 临时寄存器 ||
| `$f24 - $f31` | `$fs0 - $fs7` | 静态寄存器 ||

临时寄存器也被称为调用者保存寄存器。 静态寄存器也被称为被调用者保存寄存器。

### CSR寄存器

**控制状态寄存器(Control and Status Register, CSR)** 是LoongArch架构中一类特殊的寄存器,用于控制处理器的运行状态。
控制状态寄存器一览表(不包括LVZ虚拟化拓展中新的CSR):

| 编号 | 名称 | 编号 | 名称 | 编号 | 名称 |
| ----------------- | ------------------------------------- | ----------------- | ------------------------------------- | ---------------- | ------------------------------------- |
| 0x0 | 当前模式信息 `CRMD` | 0x1 | 例外前模式信息 `PRMD` | 0x2 | 扩展部件使能 `EUEN` |
| 0x3 | 杂项控制 `MISC` | 0x4 | 例外配置 `ECFG` | 0x5 | 例外状态 `ESTAT` |
| 0x6 | 例外返回地址 `ERA` | 0x7 | 出错虚地址 `BADV` | 0x8 | 出错指令 `BADI` |
| 0xc | 例外入口地址 `EENTRY` | 0x10 | TLB 索引 `TLBIDX` | 0x11 | TLB 表项高位 `TLBEHI` |
| 0x12 | TLB 表项低位 0 `TLBELO0` | 0x13 | TLB 表项低位 1 `TLBELO1` | 0x18 | 地址空间标识符 `ASID` |
| 0x19 | 低半地址空间全局目录基址 `PGDL` | 0x1A | 高半地址空间全局目录基址 `PGDH` | 0x1B | 全局目录基址 `PGD` |
| 0x1C | 页表遍历控制低半部分 `PWCL` | 0x1D | 页表遍历控制高半部分 `PWCH` | 0x1E | STLB 页大小 `STLBPS` |
| 0x1F | 缩减虚地址配置 `RVACFG` | 0x20 | 处理器编号 `CPUID` | 0x21 | 特权资源配置信息 1 `PRCFG1` |
| 0x22 | 特权资源配置信息 2 `PRCFG2` | 0x23 | 特权资源配置信息 3 `PRCFG3` | 0x30+n (0≤n≤15) | 数据保存 `SAVEn` |
| 0x40 | 定时器编号 `TID` | 0x41 | 定时器配置 `TCFG` | 0x42 | 定时器值 `TVAL` |
| 0x43 | 计时器补偿 `CNTC` | 0x44 | 定时中断清除 `TICLR` | 0x60 | LLBit 控制 `LLBCTL` |
| 0x80 | 实现相关控制 1 `IMPCTL1` | 0x81 | 实现相关控制 2 `IMPCTL2` | 0x88 | TLB 重填例外入口地址 `TLBRENTRY` |
| 0x89 | TLB 重填例外出错虚地址 `TLBRBADV` | 0x8A | TLB 重填例外返回地址 `TLBRERA` | 0x8B | TLB 重填例外数据保存 `TLBRSAVE` |
| 0x8C | TLB 重填例外表项低位 0 `TLBRELO0` | 0x8D | TLB 重填例外表项低位 1 `TLBRELO1` | 0x8E | TLB 重填例外表项高位 `TLBREHI` |
| 0x8F | TLB 重填例外前模式信息 `TLBRPRMD` | 0x90 | 机器错误控制 `MERRCTL` | 0x91 | 机器错误信息 1 `MERRINFO1` |
| 0x92 | 机器错误信息 2 `MERRINFO2` | 0x93 | 机器错误例外入口地址 `MERRENTRY` | 0x94 | 机器错误例外返回地址 `MERRERA` |
| 0x95 | 机器错误例外数据保存 `MERRSAVE` | 0x98 | 高速缓存标签 `CTAG` | 0x180+n (0≤n≤3) | 直接映射配置窗口 n `DMWn` |
| 0x200+2n (0≤n≤31) | 性能监测配置 n `PMCFGn` | 0x201+2n (0≤n≤31) | 性能监测计数器 n `PMCNTn` | 0x300 | load/store 监视点整体控制 `MWPC` |
| 0x301 | load/store 监视点整体状态 `MWPS` | 0x310+8n (0≤n≤7) | load/store 监视点 n 配置 1 `MWPnCFG1` | 0x311+8n (0≤n≤7) | load/store 监视点 n 配置 2 `MWPnCFG2` |
| 0x312+8n (0≤n≤7) | load/store 监视点 n 配置 3 `MWPnCFG3` | 0x313+8n (0≤n≤7) | load/store 监视点 n 配置 4 `MWPnCFG4` | 0x380 | 取指监视点整体控制 `FWPC` |
| 0x381 | 取指监视点整体状态 `FWPS` | 0x390+8n (0≤n≤7) | 取指监视点 n 配置 1 `FWPnCFG1` | 0x391+8n (0≤n≤7) | 取指监视点 n 配置 2 `FWPnCFG2` |
| 0x392+8n (0≤n≤7) | 取指监视点 n 配置 3 `FWPnCFG3` | 0x393+8n (0≤n≤7) | 取指监视点 n 配置 4 `FWPnCFG4` | 0x500 | 调试寄存器 `DBG` |
| 0x501 | 调试例外返回地址 `DERA` | 0x502 | 调试数据保存 `DSAVE` | | |

对于实现了LVZ虚拟化拓展的处理器,还有一组用于控制虚拟化的CSR寄存器[3]

| 编号 | 名称 |
| ---- | ------------------------ |
| 0x15 | 客户机TLB控制 `GTLBC` |
| 0x16 | TLBRD读Guest项 `TRGP` |
| 0x50 | 客户机状态 `GSTAT` |
| 0x51 | 客户机控制 `GCTL` |
| 0x52 | 客户机中断控制 `GINTC` |
| 0x53 | 客户机计数器补偿 `GCNTC` |

## CPU模式

实现了LVZ虚拟化拓展的CPU(即龙芯3系处理器)支持两个运行模式—— **Host模式和Guest模式** [3],其中每个模式各自有四个特权级(PLV0-PLV3)。处理器核当前处于哪个特权等级由`CSR.CRMD``PLV`域的值唯一确定[2]
对于无虚拟化的场景如在Host模式下启动一个Linux内核,其Linux内核态位于PLV0,用户态通常位于PLV3。
对于虚拟化场景,Host模式由Hypervisor使用,Guest模式则是Hypervisor所启动的虚拟机的运行模式。Guest模式在诸多方面受到Host模式下Hypervisor的控制,并且Guest模式下可以通过
Hypercall超级调用指令(hvcl)强制陷入Host模式下的Hypervisor。

下图是在loongarch架构下Hypervisor处理guest模式的异常的一种流程:

![LoongArch-Exception-Guest](../img/loongarch_guest_exception_handle.png)

### GCSR寄存器组

在实现虚拟化的LoongArch处理器中会额外有一组 **GCSR(Guest Control and Status Register)** 寄存器,供Guest模式下的虚拟机内操作系统使用,这里需要和Host模式下的CSR寄存器区分开。
通过这一套GCSR寄存器可以让虚拟机有自己的特权资源和对应管理,同时避免和Hypervisor的特权资源冲突并减少虚拟机陷入Hypervisor的次数。需要注意的是虚拟机对GCSR寄存器的操作、对特权指令(`cpucfg``cacop`等)的执行等仍然可以被Hypervisor监控和控制,LVZ拓展允许Hypervisor自由选择是否对这些操作进行拦截。


### 进入Guest模式的流程(KVM)[4]


1.`switch_to_guest`】:

2. 清空`CSR.ECFG.VS`字段(设置为0,即所有异常共用一个入口地址)
3. 读取Hypervisor中保存的guest eentry(客户OS中断向量地址)-> GEENTRY
1. 然后将GEENTRY写入`CSR.EENTRY`
4. 读取Hypervisor中保存的guest era(客户OS异常返回地址)-> GPC
1. 然后将GPC写入`CSR.ERA`
5. 读取`CSR.PGDL`全局页表地址,存到Hypervisor中
6. 从Hypervisor中加载guest pgdl到`CSR.PGDL`
7. 读出`CSR.GSTAT.GID``CSR.GTLBC.TGID`,写入`CSR.GTLBC`
8.`CSR.PRMD.PIE`置1,打开Hypervisor级的全局中断
9.`CSR.GSTAT.PGM`置1,其目的是使ertn指令进入guest mode
10. Hypervisor将自己保存的该guest的通用寄存器(GPRS)恢复到硬件寄存器上(恢复现场)
11. **执行`ertn`指令,进入guest模式**


## 虚拟化相关的异常[2][3]

| code | subcode | 缩写 | 介绍 |
| ------ | ------- | ---- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| 22 | - | GSPR | 客户机敏感特权资源异常,由`cpucfg``idle``cacop`指令触发,以及在虚拟机访问了不存在的GCSR和IOCSR时触发,强制陷入Hypervisor进行处理(如软件模拟) |
| 23 | - | HVC | hvcl超级调用指令触发的异常 |
| 24 | 0 | GCM | 客户机GCSR软件修改异常 |
| 24 | 1 | GCHC | 客户机GCSR硬件修改异常 |


### 处理Guest模式下异常的流程(KVM)[4]



1.`kvm_exc_entry`】:

2. Hypervisor首先保存好guest的通用寄存器(GPRS),保护现场。
3. Hypervisor保存`CSR.ESTAT` -> host ESTAT
4. Hypervisor保存`CSR.ERA` -> GPC
5. Hypervisor保存`CSR.BADV` -> host BADV,即触发地址错误例外时,记录出错的虚拟地址
6. Hypervisor保存`CSR.BADI` -> host BADI,该寄存器用于记录触发同步类例外的指令的指令码,所谓同步类例外是指除了中断(INT)、客户机CSR硬件修改例外(GCHC)、机器错误例外(MERR)之外的所有例外。
7. 读取Hypervisor保存好的host ECFG,写入`CSR.ECFG`(即切换到host下的异常配置)
8. 读取Hypervisor保存好的host EENTRY,写入`CSR.EENTRY`
9. 读取Hypervisor保存好的host PGD,写入`CSR.PGDL`(恢复host页表全局目录基址,低半空间)
10. 设置`CSR.GSTAT.PGM`关闭
11. 清空`GTLBC.TGID`
12. 恢复kvm per cpu寄存器
1. kvm汇编里涉及到KVM_ARCH_HTP, KVM_ARCH_HSP, KVM_ARCH_HPERCPU
13. **跳转到KVM_ARCH_HANDLE_EXIT位置处理异常**
14. 判断刚才的函数ret是否<=0
1. 若<=0,则继续运行host
2. 否则继续运行guest,保存percpu寄存器,因为可能会切换到不同的CPU继续运行guest。保存host percpu寄存器到`CSR.KSAVE`寄存器

15. 跳转到`switch_to_guest`

## vCPU上下文需要保存的寄存器

由LoongArch函数调用规范可知如果需要手动切换CPU函数运行上下文,需要保存的寄存器如下(不考虑浮点寄存器):`$s0`-`$s9``$sp``$ra`

## 参考资料

[1] 龙芯中科技术股份有限公司.龙芯架构ELF psABI规范.Version 2.01.

[2] 龙芯中科技术股份有限公司.龙芯架构参考手册.卷一:基础架构.

[3] 龙芯中科技术股份有限公司.龙芯架构参考手册.卷三.

<!-- [4] https://github.com/torvalds/linux/blob/master/arch/loongarch/kvm/switch.S -->
[4] [https://github.com/torvalds/linux/blob/master/arch/loongarch/kvm/switch.S](https://github.com/torvalds/linux/blob/master/arch/loongarch/kvm/switch.S).
Empty file.
48 changes: 48 additions & 0 deletions src/chap04/subchap02/LoongArch-Controller.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# LoongArch 中断控制

由于龙芯不同处理器/开发板的中断控制器各自设计不同(嵌入式处理器如2K1000有自己的中断控制器设计,3系处理器则有7A1000和7A2000桥片负责外部中断控制),本文IO中断部分主要对最新的**龙芯7A2000桥片**内的中断控制器进行介绍[1]

## CPU中断

LoongArch的中断配置由`CSR.ECFG`控制,龙芯架构下的中断采用线中断的形式,每个处理器核内部可以记录 13 个线中断。这些中断包括:1 个核间中断(IPI),1 个定时器中断(TI),1 个性能监测计数溢出中断(PMI),8 个硬中断(HWI0~HWI7),以及 2 个软中断(SWI0~SWI1)。所有线中断均为电平中断,并且都是高电平有效[3]

![LoongArch-Irq](../img/loongarch_irq.png)

- **核间中断**:来自核外的中断控制器,被记录在 `CSR.ESTAT.IS[12]` 位。
- **定时器中断**:源自核内的恒定频率定时器,当计时至全 0 值时触发,并被记录在 `CSR.ESTAT.IS[11]` 位。清除方法是通过软件向 `CSR.TICLR` 寄存器的 `TI` 位写 1。
- **性能计数器溢出中断**:源自核内的性能计数器,当任一开启中断使能的性能计数器的第 63 位为 1 时触发,并记录在 `CSR.ESTAT.IS[10]` 位。清除方法是将引起中断的性能计数器的第 63 位清 0 或关闭该性能计数器的中断使能。
- **硬中断**:来自处理器核外部的中断控制器,8 个硬中断 `HWI[7:0]` 被记录在 `CSR.ESTAT.IS[9:2]` 位。
- **软中断**:来自处理器核内部,通过软件指令对 `CSR.ESTAT.IS[1:0]` 写 1 置起,写 0 清除。

中断在 `CSR.ESTAT.IS` 域中记录的位置的索引值也被称为中断号(Int Number)。例如,`SWI0` 的中断号为 0,`SWI1` 的中断号为 1,依此类推,`IPI` 的中断号为 12。


## 传统IO中断

![LoongArch-Controller](../img/loongarch_7a_intc.png)

上图是3A系列处理器+7A系列桥片的中断系统示意图。图中表示了两种中断方式的过程,上部表示的是通过中断线`INTn0`来中断,下部表示的是通过HT消息包来中断。

设备(除了工作在MSI模式的PCIe设备)发出的中断`intX`送给7A内部中断控制器,经过中断路由后送到桥片引脚或者转换成HT消息包发给3A的HT控制器,3A的中断控制器通过外部中断引脚或者HT控制器中断接收到该中断,并经过中断路由中断某个处理器核[1]


龙芯3A5000芯片的**传统 IO 中断**支持32个中断源,以统一方式进行管理,如下图所示。
任意一个IO中断源可以被配置为是否使能、触发的方式、以及被路由的目标处理器核中断脚。传统中断*不支持*中断的跨片分发,只能中断同一个处理器片内的处理器核[2]

![LoongArch-Controller](../img/loongarch_legacy_int.png)

## 拓展IO中断

除了兼容原有的传统 IO 中断方式,3A5000 开始支持**扩展 I/O 中断**,用于将 HT 总线上的 256 位中断直接分发给各个处理器核,而不再通过 HT 的中断线进行转发,提升 IO 中断使用的灵活性[2]

## 中断虚拟化

在LVZ拓展新增的CSR寄存器中,`CSR.GINTC`(客户机中断控制寄存器)用于虚拟机**硬件中断**的控制,其能够让Hypervisor手动控制客户机各HW中断的使能,以及配置外部HW中断直通虚拟机等功能。

## 参考资料

[1] 龙芯中科技术股份有限公司.龙芯7A2000桥片用户手册.V1.0.第5章.

[2] 龙芯中科技术股份有限公司.龙芯3A5000/3B5000处理器寄存器使用手册-多核处理器架构、寄存器描述与系统软件编程指南.V1.3.第11章.

[3] 龙芯中科技术股份有限公司.龙芯架构参考手册.卷一:基础架构.

0 comments on commit c2776f4

Please sign in to comment.