From 3743a448cf8b585053767dcd1beb5e17b89ed1fb Mon Sep 17 00:00:00 2001 From: sts Date: Thu, 12 Sep 2024 09:30:29 +0800 Subject: [PATCH 1/9] Add articles/20240911-stratovirt-riscv-part4 --- articles/20240911-stratovirt-riscv-part4.md | 259 ++++++++++++++++++ .../images/stratovirt-riscv/memory_layout.jpg | Bin 0 -> 18049 bytes 2 files changed, 259 insertions(+) create mode 100644 articles/20240911-stratovirt-riscv-part4.md create mode 100644 articles/images/stratovirt-riscv/memory_layout.jpg diff --git a/articles/20240911-stratovirt-riscv-part4.md b/articles/20240911-stratovirt-riscv-part4.md new file mode 100644 index 0000000..7b1295c --- /dev/null +++ b/articles/20240911-stratovirt-riscv-part4.md @@ -0,0 +1,259 @@ +> Author: Sunts
+> Date: 2024/09/11
+> Revisor: Falcon
+> Project: [RISC-V Linux 内核剖析](https://gitee.com/tinylab/riscv-linux)
+> Sponsor: PLCT Lab, ISCAS + +# Stratovirt 的 RISC-V 支持(四):内存模型和 CPU 模型 + +## 前言 +前文介绍了基本的 KVM 模型,本文将通过增加 memory 子模块和 cpu 子模块来增强内存空间管理和 cpu 控制的灵活性。 + +## 内存模型 +在前文中我们仅申请固定大小的空间用于虚拟机的 ram 部分并存放汇编指令代码。但这远远不能满足中断控制器、PCI 设备等的要求。memory 子模块包含地址资源管理和虚拟机内存管理以及内存读写功能。 + +### 地址空间分布 +在 risc-v 的stratovirt中,对地址空间布局如下图所示。 + +![Image Description](images/stratovirt-riscv/memory_layout.jpg) + +在初始 edu 分支中并不会用到类似 PCI 的地址空间,edu 后面会使用到 IRQCHIP 作为 PLIC 的内存映射区域。 +考虑到 edu 的全部内容,我们使用三种 edu 分支中会用到的内存区域,IRQCHIP 用于 PLIC 空间, MMIO 用于串口空间,RAM 用于内存,内存的最大边界已在图中指定,真正内存的大小由 stratovirt 中调用内存子模块接口时指定,一般较小,例如:128M,256M 等。最大不超过内存空间的最大边界。 +```rust +// src/memory/mod.rs + +pub enum LayoutEntryType { + IrqChip = 0_usize, + Mmio, + MemRam +} + +pub const MEM_LAYOUT: &[(u64, u64)] = &[ + (0x08000000, 0x08000000), + (0x10000000, 0x20000000), + (0x80000000, ((1 << 40) - 0x80000000)) +]; +``` +### 内存地址映射管理 + +定义 HostMemMapping 结构体通过 mmap 系统调用来分配宿主机虚拟内存,映射关系通过结构体成员来保存。在 HostMemMapping 的析构函数中,会通过 unmap 系统调用来释放宿主机的虚拟内存资源。 +内存子模块的对外接口为 GuestMemory,其成员保存所有的映射关系。例如,当拥有 PLIC 时,IrqChip 部分空间可能会使用作为 PLIC 的 MMIO 空间,同时还存在虚拟机运行必须的 RAM。这两部分分别保存在两个 HostMemMapping 中。 + +```rust +// src/memory/guest_memory.rs + +impl GuestMemory { + pub fn new(vm_fd: &Arc, mem_size: u64) -> Result { + let range = Self::arch_ram_ranges(mem_size); + + let mut host_mmaps = Vec::new(); + for (index, range) in ranges.iter().enumerate() { + let host_mmap = Arc::new(HostMemMapping::new(range.0, range.1)); + host_mmaps.push(host_mmap.clone()); + + let kvm_region = kvm_userspace_memory_region { + slot: index as u32, + guest_phys_addr: host_mmap.guest_address(), + memory_size: host_mmap.size(), + userspace_addr: host_mmap.host_address(), + flags: 0 + }; + unsafe { + vm_fd + .set_user_memory_region(kvm_region) + .map_err(Error::KvmSetMR); + } + } + Ok(GuestMemory{ host_mmaps }) + } +} +``` + +### 内存访问接口 +其他模块需要通过 GuestMemory 对象的成员方法来访问内存,完成读写。读和写自然作为两个最基本最重要的接口必须实现。 + +```rust +// src/memory/guest_memory.rs + +impl GuestMemory { + pub fn read(&self, dst: &mut [u8], addr: u64) -> Result<()> { + let count = dst.len() as u64; + let host_mmap = self.find_host_mmap(addr, count); + let offset = addr - host_mmap.guest_address(); + let host_addr = host_mmap.host_address(); + let slice = unsafe { + std::slice::from_raw_parts((host_addr + offset) as * const u8, count as usize) + }; + dst.write_all(slice).map_err(Error::IoError); + Ok(()) + } + pub fn read(&self, src: &[u8], addr: u64) -> Result<()> { + let count = src.len() as u64; + let host_mmap = self.find_host_mmap(addr, count); + let offset = addr - host_mmap.guest_address(); + let host_addr = host_mmap.host_address(); + let slice = unsafe { + std::slice::from_raw_parts_mut((host_addr + offset) as * const u8, count as usize) + }; + slice.write_all(src).map_err(Error::IoError); + Ok(()) + } +} +``` +### 错误处理 +错误处理不可缺少,对于在内存申请映射,读写过程中可能出现的错误,通过 Error 枚举类型做不同的处理。为它实现 `std::fmt::Display` 这个 trait,方便自定义每种错误发生时的输出信息。 + +```rust +// src/memory/mod.rs + +pub enum Error { + Overflow(u64, u64, u64), + HostMmapNotFound(u64), + Mmap(std::io::Error), + IoError(std::io::Error), + KvmSetMR(kvm_ioctls::Error) +} +impl std::fmt::Display for Error { + ... +} + +// 通过 type 定义已经存在的数据类型别名 +pub type Result = std::result::Result; +``` + +## CPU 模型 +CPU 子模块需要处理寄存器数据的读写,并完成对部分计算机指令的模拟。常规用户级指令会在 KVM 内核模块中处理,CPU 模块中主要负责对 VM-Exit 退出事件的处理。 + +CPU 结构体需要记录 vCPU 相关信息,与 KVM 模块进行交互,包括但不限于读写寄存器的信息,开始执行 vCPU 等。 + +```rust +// src/cpu/mod.rs + +pub struct CPU { + // 虚拟 VCPU 的 id + pub id: u8; + // 调用 KVM 模块中的 VCPU 接口所用句柄 + fd: Arc; + // 该 VCPU 所在的虚拟机的地址空间 + sys_mem: Arc; +} +``` +构造函数对 CPU 结构体初始化。 + +```rust +// src/cpu/mod.rs + +impl CPU { + pub fn new(vm_fd: &VmFd, sys_mem: Arc, vcpu_id: u8) -> Self { + let vcpu_fd = vm_fd + .create_vcpu(vcpu_id as u8) + .expect("Failed to create VCPU"); + Self { + id: vcpu_id, + fd: Arc::new(vcpu_fd), + sys_mem: sys_mem.clone(), + } + } +} +``` +读写寄存器是非常重要的和 KVM 交互的功能。结合前文中通过 id 来写 PC 寄存器,在 CPU 模块实现对寄存器的访问。目前只考虑通用寄存器。由于每个寄存器的 id 都是一个无符号 64 位整数表示的唯一值,故为通用寄存器枚举类型 Riscv64CoreRegs 实现 std::convert::Into 这个 trait 来为每个寄存器返回其 id。 + +```rust +// src/cpu/mod.rs + +use std::convert::Into; +pub enum Riscv64CoreRegs{ + PC, + RA, + ... + T6, + MODE, +} +impl Into for Riscv64CoreRegs{ + fn into(self) -> u64 { + let reg_offset = match self { + Riscv64CoreRegs::PC => { + offset_of!(kvm_riscv_core, regs, user_regs_struct, pc) + } + ... + Riscv64CoreRegs::T6 => { + offset_of!(kvm_riscv_core, regs, user_regs_struct, t6) + } + Riscv64CoreRegs::MODE => { + offset_of!(kvm_riscv_core, mode) + } + }; + KVM_REG_RISCV as u64 + | KVM_REG_SIZE_U64 as u64 + | u64::from(KVM_REG_RISCV_CORE) + | (reg_offset / mem::size_of::()) as u64 + } +} + +impl CPU { + pub fn set_core_reg(&self, reg: Riscv64CoreRegs, val: u64) -> Result<()>{ + self.fd.set_one_reg(reg.into(), val).expect("Failed to set register"); + Ok(()) + } + pub fn get_core_reg(&self, reg: Riscv64CoreRegs) -> Result{ + let res = self.fd.get_one_reg(reg.into()).unwrap(); + Ok(res) + } +} +``` +最后正式运行抽象出的 CPU,运行中最重要的部分为 vCPU 的指令模拟和对陷出事件的处理。 +```rust +// src/cpu/mod.rs + +impl CPU { + pub fn kvm_vcpu_exec(&self) { + match self.fd.run().unwrap() { + VcpuExit::IoIn(addr, data) => { + println!("VCPU{} VmExit IO in: addr 0x{:x}, data is {}", + self.id, addr, data[0]) + } + VcpuExit::IoOut(addr, data) => { + println!("VCPU{} VmExit IO out: addr 0x{:x}, data is {}", + self.id, addr, data[0]) + } + VcpuExit::MmioRead(addr, _data) => { + println!("VCPU{} VmExit MMIO read: addr 0x{:x}", + self.id, addr) + } + VcpuExit::MmioWrite(addr, _data) => { + println!("VCPU{} VmExit MMIO write: addr 0x{:x}", + self.id, addr) + } + r => panic!("Unexpected exit reason: {:?}", r) + } + true + } +} +``` +### CPU 并发运行多个任务 + +多个 vCPU 可以同时运行通过并行计算加快程序运行速度,可通过 start 接口返回线程的 handle,实现对同一个虚拟机多线程运行多个不同的 vCPU。 +```rust +// src/cpu/mod.rs + +impl CPU { + pub fn start(arc_cpu: Arc) -> std::thread::JoinHandle<()>{ + let cpu_id = arc_cpu.id; + thread::Builder::new() + .name(format!("CPU {}/KVM", cpu_id)) + .spawn(move || { + loop { + if !arc_cpu.kvm_vcpu_exec() { break; } + } + }).expect(&format!("thread CPU {}/KVM Failed", cpu_id)) + } +} +``` + +## 小结 + +CPU 模型和内存模型解决了灵活控制地址空间和 KVM 交互的问题。后面会实现加载内核文件、PLIC 中断控制等。 + +## 参考资料 + +- [RUST thread 官方文档](https://doc.rust-lang.org/std/thread/) \ No newline at end of file diff --git a/articles/images/stratovirt-riscv/memory_layout.jpg b/articles/images/stratovirt-riscv/memory_layout.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8c76a6091ebd347211d98a90c567a4a8ff03daa2 GIT binary patch literal 18049 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 Date: Thu, 12 Sep 2024 09:31:40 +0800 Subject: [PATCH 2/9] stratovirt-riscv-part4.md: commit correct result of tinycorrect-spaces Signed-off-by: sts --- articles/20240911-stratovirt-riscv-part4.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/articles/20240911-stratovirt-riscv-part4.md b/articles/20240911-stratovirt-riscv-part4.md index 7b1295c..efe0d2f 100644 --- a/articles/20240911-stratovirt-riscv-part4.md +++ b/articles/20240911-stratovirt-riscv-part4.md @@ -1,3 +1,4 @@ +> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [spaces]
> Author: Sunts
> Date: 2024/09/11
> Revisor: Falcon
@@ -18,7 +19,7 @@ ![Image Description](images/stratovirt-riscv/memory_layout.jpg) 在初始 edu 分支中并不会用到类似 PCI 的地址空间,edu 后面会使用到 IRQCHIP 作为 PLIC 的内存映射区域。 -考虑到 edu 的全部内容,我们使用三种 edu 分支中会用到的内存区域,IRQCHIP 用于 PLIC 空间, MMIO 用于串口空间,RAM 用于内存,内存的最大边界已在图中指定,真正内存的大小由 stratovirt 中调用内存子模块接口时指定,一般较小,例如:128M,256M 等。最大不超过内存空间的最大边界。 +考虑到 edu 的全部内容,我们使用三种 edu 分支中会用到的内存区域,IRQCHIP 用于 PLIC 空间,MMIO 用于串口空间,RAM 用于内存,内存的最大边界已在图中指定,真正内存的大小由 stratovirt 中调用内存子模块接口时指定,一般较小,例如:128M,256M 等。最大不超过内存空间的最大边界。 ```rust // src/memory/mod.rs @@ -184,9 +185,9 @@ impl Into for Riscv64CoreRegs{ } }; KVM_REG_RISCV as u64 - | KVM_REG_SIZE_U64 as u64 - | u64::from(KVM_REG_RISCV_CORE) - | (reg_offset / mem::size_of::()) as u64 + | KVM_REG_SIZE_U64 as u64 + | u64::from(KVM_REG_RISCV_CORE) + | (reg_offset / mem::size_of::()) as u64 } } @@ -256,4 +257,4 @@ CPU 模型和内存模型解决了灵活控制地址空间和 KVM 交互的问 ## 参考资料 -- [RUST thread 官方文档](https://doc.rust-lang.org/std/thread/) \ No newline at end of file +- [RUST thread 官方文档](https://doc.rust-lang.org/std/thread/) -- Gitee From 1d815a061a73a386527a029d7d0e85478c67f996 Mon Sep 17 00:00:00 2001 From: sts Date: Thu, 12 Sep 2024 09:31:49 +0800 Subject: [PATCH 3/9] stratovirt-riscv-part4.md: commit correct result of tinycorrect-toc Signed-off-by: sts --- articles/20240911-stratovirt-riscv-part4.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/articles/20240911-stratovirt-riscv-part4.md b/articles/20240911-stratovirt-riscv-part4.md index efe0d2f..2e4c6a4 100644 --- a/articles/20240911-stratovirt-riscv-part4.md +++ b/articles/20240911-stratovirt-riscv-part4.md @@ -1,4 +1,4 @@ -> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [spaces]
+> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [spaces toc]
> Author: Sunts
> Date: 2024/09/11
> Revisor: Falcon
@@ -8,12 +8,15 @@ # Stratovirt 的 RISC-V 支持(四):内存模型和 CPU 模型 ## 前言 + 前文介绍了基本的 KVM 模型,本文将通过增加 memory 子模块和 cpu 子模块来增强内存空间管理和 cpu 控制的灵活性。 ## 内存模型 + 在前文中我们仅申请固定大小的空间用于虚拟机的 ram 部分并存放汇编指令代码。但这远远不能满足中断控制器、PCI 设备等的要求。memory 子模块包含地址资源管理和虚拟机内存管理以及内存读写功能。 ### 地址空间分布 + 在 risc-v 的stratovirt中,对地址空间布局如下图所示。 ![Image Description](images/stratovirt-riscv/memory_layout.jpg) @@ -35,6 +38,7 @@ pub const MEM_LAYOUT: &[(u64, u64)] = &[ (0x80000000, ((1 << 40) - 0x80000000)) ]; ``` + ### 内存地址映射管理 定义 HostMemMapping 结构体通过 mmap 系统调用来分配宿主机虚拟内存,映射关系通过结构体成员来保存。在 HostMemMapping 的析构函数中,会通过 unmap 系统调用来释放宿主机的虚拟内存资源。 @@ -71,6 +75,7 @@ impl GuestMemory { ``` ### 内存访问接口 + 其他模块需要通过 GuestMemory 对象的成员方法来访问内存,完成读写。读和写自然作为两个最基本最重要的接口必须实现。 ```rust @@ -101,7 +106,9 @@ impl GuestMemory { } } ``` + ### 错误处理 + 错误处理不可缺少,对于在内存申请映射,读写过程中可能出现的错误,通过 Error 枚举类型做不同的处理。为它实现 `std::fmt::Display` 这个 trait,方便自定义每种错误发生时的输出信息。 ```rust @@ -123,6 +130,7 @@ pub type Result = std::result::Result; ``` ## CPU 模型 + CPU 子模块需要处理寄存器数据的读写,并完成对部分计算机指令的模拟。常规用户级指令会在 KVM 内核模块中处理,CPU 模块中主要负责对 VM-Exit 退出事件的处理。 CPU 结构体需要记录 vCPU 相关信息,与 KVM 模块进行交互,包括但不限于读写寄存器的信息,开始执行 vCPU 等。 @@ -231,6 +239,7 @@ impl CPU { } } ``` + ### CPU 并发运行多个任务 多个 vCPU 可以同时运行通过并行计算加快程序运行速度,可通过 start 接口返回线程的 handle,实现对同一个虚拟机多线程运行多个不同的 vCPU。 -- Gitee From b917c2131e6b42ff1878e2b2ba795d2984aff861 Mon Sep 17 00:00:00 2001 From: sts Date: Thu, 12 Sep 2024 09:31:59 +0800 Subject: [PATCH 4/9] stratovirt-riscv-part4.md: commit correct result of tinycorrect-codeblock Signed-off-by: sts --- articles/20240911-stratovirt-riscv-part4.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/articles/20240911-stratovirt-riscv-part4.md b/articles/20240911-stratovirt-riscv-part4.md index 2e4c6a4..240627a 100644 --- a/articles/20240911-stratovirt-riscv-part4.md +++ b/articles/20240911-stratovirt-riscv-part4.md @@ -1,4 +1,4 @@ -> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [spaces toc]
+> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [spaces toc codeblock]
> Author: Sunts
> Date: 2024/09/11
> Revisor: Falcon
@@ -23,6 +23,7 @@ 在初始 edu 分支中并不会用到类似 PCI 的地址空间,edu 后面会使用到 IRQCHIP 作为 PLIC 的内存映射区域。 考虑到 edu 的全部内容,我们使用三种 edu 分支中会用到的内存区域,IRQCHIP 用于 PLIC 空间,MMIO 用于串口空间,RAM 用于内存,内存的最大边界已在图中指定,真正内存的大小由 stratovirt 中调用内存子模块接口时指定,一般较小,例如:128M,256M 等。最大不超过内存空间的最大边界。 + ```rust // src/memory/mod.rs @@ -147,6 +148,7 @@ pub struct CPU { sys_mem: Arc; } ``` + 构造函数对 CPU 结构体初始化。 ```rust @@ -165,6 +167,7 @@ impl CPU { } } ``` + 读写寄存器是非常重要的和 KVM 交互的功能。结合前文中通过 id 来写 PC 寄存器,在 CPU 模块实现对寄存器的访问。目前只考虑通用寄存器。由于每个寄存器的 id 都是一个无符号 64 位整数表示的唯一值,故为通用寄存器枚举类型 Riscv64CoreRegs 实现 std::convert::Into 这个 trait 来为每个寄存器返回其 id。 ```rust @@ -210,7 +213,9 @@ impl CPU { } } ``` + 最后正式运行抽象出的 CPU,运行中最重要的部分为 vCPU 的指令模拟和对陷出事件的处理。 + ```rust // src/cpu/mod.rs @@ -243,6 +248,7 @@ impl CPU { ### CPU 并发运行多个任务 多个 vCPU 可以同时运行通过并行计算加快程序运行速度,可通过 start 接口返回线程的 handle,实现对同一个虚拟机多线程运行多个不同的 vCPU。 + ```rust // src/cpu/mod.rs -- Gitee From e77f24ff724cf26d6723f6023eb81c997d5b411f Mon Sep 17 00:00:00 2001 From: sts Date: Thu, 12 Sep 2024 09:32:12 +0800 Subject: [PATCH 5/9] stratovirt-riscv-part4.md: commit correct result of tinycorrect-urls Signed-off-by: sts --- articles/20240911-stratovirt-riscv-part4.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/articles/20240911-stratovirt-riscv-part4.md b/articles/20240911-stratovirt-riscv-part4.md index 240627a..9fa0760 100644 --- a/articles/20240911-stratovirt-riscv-part4.md +++ b/articles/20240911-stratovirt-riscv-part4.md @@ -1,4 +1,4 @@ -> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [spaces toc codeblock]
+> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [spaces toc codeblock urls]
> Author: Sunts
> Date: 2024/09/11
> Revisor: Falcon
@@ -272,4 +272,6 @@ CPU 模型和内存模型解决了灵活控制地址空间和 KVM 交互的问 ## 参考资料 -- [RUST thread 官方文档](https://doc.rust-lang.org/std/thread/) +- [RUST thread 官方文档][001] + +[001]: https://doc.rust-lang.org/std/thread/ -- Gitee From dc5aed7a91b075f150a532e3cbe46462284638d4 Mon Sep 17 00:00:00 2001 From: sts Date: Thu, 12 Sep 2024 09:32:26 +0800 Subject: [PATCH 6/9] stratovirt-riscv-part4.md: commit correct result of tinycorrect-pangu Signed-off-by: sts --- articles/20240911-stratovirt-riscv-part4.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/articles/20240911-stratovirt-riscv-part4.md b/articles/20240911-stratovirt-riscv-part4.md index 9fa0760..734eaea 100644 --- a/articles/20240911-stratovirt-riscv-part4.md +++ b/articles/20240911-stratovirt-riscv-part4.md @@ -1,4 +1,4 @@ -> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [spaces toc codeblock urls]
+> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [spaces toc codeblock urls pangu]
> Author: Sunts
> Date: 2024/09/11
> Revisor: Falcon
@@ -17,7 +17,7 @@ ### 地址空间分布 -在 risc-v 的stratovirt中,对地址空间布局如下图所示。 +在 risc-v 的 stratovirt 中,对地址空间布局如下图所示。 ![Image Description](images/stratovirt-riscv/memory_layout.jpg) -- Gitee From 3df43d1c557cb7edc56d39f4d07297a33e81111e Mon Sep 17 00:00:00 2001 From: sts Date: Mon, 28 Oct 2024 19:28:19 +0800 Subject: [PATCH 7/9] Fix articles/20240911-stratovirt-riscv-part4 --- articles/20240911-stratovirt-riscv-part4.md | 47 ++++++++++++++++++--- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/articles/20240911-stratovirt-riscv-part4.md b/articles/20240911-stratovirt-riscv-part4.md index 734eaea..5ebc020 100644 --- a/articles/20240911-stratovirt-riscv-part4.md +++ b/articles/20240911-stratovirt-riscv-part4.md @@ -9,7 +9,7 @@ ## 前言 -前文介绍了基本的 KVM 模型,本文将通过增加 memory 子模块和 cpu 子模块来增强内存空间管理和 cpu 控制的灵活性。 +前文介绍了基本的 KVM 模型,本文将通过增加 memory 子模块和 cpu 子模块来进一步完善虚拟机功能。 ## 内存模型 @@ -42,8 +42,45 @@ pub const MEM_LAYOUT: &[(u64, u64)] = &[ ### 内存地址映射管理 -定义 HostMemMapping 结构体通过 mmap 系统调用来分配宿主机虚拟内存,映射关系通过结构体成员来保存。在 HostMemMapping 的析构函数中,会通过 unmap 系统调用来释放宿主机的虚拟内存资源。 -内存子模块的对外接口为 GuestMemory,其成员保存所有的映射关系。例如,当拥有 PLIC 时,IrqChip 部分空间可能会使用作为 PLIC 的 MMIO 空间,同时还存在虚拟机运行必须的 RAM。这两部分分别保存在两个 HostMemMapping 中。 +前文中我们直接在主函数中为虚拟机的运行分配 RAM 空间。本文中我们定义 HostMemMapping 结构体记录宿主机虚拟内存和客户机物理内存的一个连续区域的映射关系。其结构体定义如下所示: +```rust +pub struct HostMemMapping { + // 客户机物理地址起始地址 + guest_addr: u64, + // 映射区域大小 + size: u64, + // 宿主机虚拟地址起始地址 + host_addr: u64, +} +``` + +假如一个区域需要真实物理内存,则通过 HostMemMapping 的 new 函数实现。其通过 mmap 系统调用来分配宿主机虚拟内存,映射关系通过结构体成员来保存。在 HostMemMapping 的析构函数中,会通过 unmap 系统调用来释放宿主机的虚拟内存资源。具体 new 函数实现如下: +```rust +pub fn new(guest_addr: u64, size: u64) -> Result { + let flags = libc::MAP_ANONYMOUS | libc::MAP_PRIVATE; + let host_addr = unsafe { + let hva = libc::mmap( + std::ptr::null_mut() as *mut libc::c_void, + size as libc::size_t, + libc::PROT_READ | libc::PROT_WRITE, + flags, + -1, + 0 + ); + if hva == libc::MAP_FAILED { + return Err(Error::Mmap(std::io::Error::last_os_error())); + } + hva + }; + Ok(HostMemMapping { + guest_addr, + size, + host_addr: host_addr as u64, + }) +} +``` + +内存子模块的对外接口为 GuestMemory,其成员保存所有的内存区域映射关系。例如,当拥有 PLIC 时,IrqChip 部分空间可能会使用作为 PLIC 的 MMIO 空间,同时还存在虚拟机运行必须的 RAM。这两部分分别保存在两个 HostMemMapping 中。 ```rust // src/memory/guest_memory.rs @@ -77,7 +114,7 @@ impl GuestMemory { ### 内存访问接口 -其他模块需要通过 GuestMemory 对象的成员方法来访问内存,完成读写。读和写自然作为两个最基本最重要的接口必须实现。 +在 edu 分支中,其他模块需要通过 GuestMemory 对象的成员方法来访问内存,完成读写。读和写自然作为两个最基本最重要的接口必须实现。 ```rust // src/memory/guest_memory.rs @@ -268,7 +305,7 @@ impl CPU { ## 小结 -CPU 模型和内存模型解决了灵活控制地址空间和 KVM 交互的问题。后面会实现加载内核文件、PLIC 中断控制等。 +CPU 模型和内存模型进一步完善了 RISC-V 下内存和 CPU 虚拟化功能。后面会实现加载内核文件、PLIC 中断控制等。 ## 参考资料 -- Gitee From de9e448e6866cf8e0889bb2640be464e29321d91 Mon Sep 17 00:00:00 2001 From: sts Date: Mon, 28 Oct 2024 19:30:29 +0800 Subject: [PATCH 8/9] stratovirt-riscv-part4.md: commit correct result of tinycorrect-spaces Signed-off-by: sts --- articles/20240911-stratovirt-riscv-part4.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/articles/20240911-stratovirt-riscv-part4.md b/articles/20240911-stratovirt-riscv-part4.md index 5ebc020..6104a22 100644 --- a/articles/20240911-stratovirt-riscv-part4.md +++ b/articles/20240911-stratovirt-riscv-part4.md @@ -1,4 +1,4 @@ -> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [spaces toc codeblock urls pangu]
+> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [spaces]
> Author: Sunts
> Date: 2024/09/11
> Revisor: Falcon
@@ -44,7 +44,7 @@ pub const MEM_LAYOUT: &[(u64, u64)] = &[ 前文中我们直接在主函数中为虚拟机的运行分配 RAM 空间。本文中我们定义 HostMemMapping 结构体记录宿主机虚拟内存和客户机物理内存的一个连续区域的映射关系。其结构体定义如下所示: ```rust -pub struct HostMemMapping { +pub struct HostMemMapping { // 客户机物理地址起始地址 guest_addr: u64, // 映射区域大小 @@ -56,10 +56,10 @@ pub struct HostMemMapping { 假如一个区域需要真实物理内存,则通过 HostMemMapping 的 new 函数实现。其通过 mmap 系统调用来分配宿主机虚拟内存,映射关系通过结构体成员来保存。在 HostMemMapping 的析构函数中,会通过 unmap 系统调用来释放宿主机的虚拟内存资源。具体 new 函数实现如下: ```rust -pub fn new(guest_addr: u64, size: u64) -> Result { +pub fn new(guest_addr: u64, size: u64) -> Result { let flags = libc::MAP_ANONYMOUS | libc::MAP_PRIVATE; - let host_addr = unsafe { - let hva = libc::mmap( + let host_addr = unsafe { + let hva = libc::mmap( std::ptr::null_mut() as *mut libc::c_void, size as libc::size_t, libc::PROT_READ | libc::PROT_WRITE, @@ -67,13 +67,13 @@ pub fn new(guest_addr: u64, size: u64) -> Result { -1, 0 ); - if hva == libc::MAP_FAILED { + if hva == libc::MAP_FAILED { return Err(Error::Mmap(std::io::Error::last_os_error())); } hva }; - Ok(HostMemMapping { - guest_addr, + Ok(HostMemMapping { + guest_addr, size, host_addr: host_addr as u64, }) -- Gitee From d739c47a9f1e15b7afb9206f3e1f11ec51b653db Mon Sep 17 00:00:00 2001 From: sts Date: Mon, 28 Oct 2024 19:30:38 +0800 Subject: [PATCH 9/9] stratovirt-riscv-part4.md: commit correct result of tinycorrect-codeblock Signed-off-by: sts --- articles/20240911-stratovirt-riscv-part4.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/articles/20240911-stratovirt-riscv-part4.md b/articles/20240911-stratovirt-riscv-part4.md index 6104a22..0d24fe8 100644 --- a/articles/20240911-stratovirt-riscv-part4.md +++ b/articles/20240911-stratovirt-riscv-part4.md @@ -1,4 +1,4 @@ -> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [spaces]
+> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [spaces codeblock]
> Author: Sunts
> Date: 2024/09/11
> Revisor: Falcon
@@ -43,6 +43,7 @@ pub const MEM_LAYOUT: &[(u64, u64)] = &[ ### 内存地址映射管理 前文中我们直接在主函数中为虚拟机的运行分配 RAM 空间。本文中我们定义 HostMemMapping 结构体记录宿主机虚拟内存和客户机物理内存的一个连续区域的映射关系。其结构体定义如下所示: + ```rust pub struct HostMemMapping { // 客户机物理地址起始地址 @@ -55,6 +56,7 @@ pub struct HostMemMapping { ``` 假如一个区域需要真实物理内存,则通过 HostMemMapping 的 new 函数实现。其通过 mmap 系统调用来分配宿主机虚拟内存,映射关系通过结构体成员来保存。在 HostMemMapping 的析构函数中,会通过 unmap 系统调用来释放宿主机的虚拟内存资源。具体 new 函数实现如下: + ```rust pub fn new(guest_addr: u64, size: u64) -> Result { let flags = libc::MAP_ANONYMOUS | libc::MAP_PRIVATE; -- Gitee