mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4eb4dee9cf | ||
|
|
aa850b5c3d | ||
|
|
c84d43d85d | ||
|
|
4eac4dfb0f | ||
|
|
475d1879f2 | ||
|
|
42ad38d28c | ||
|
|
8a8fe39c99 | ||
|
|
7da34333f5 | ||
|
|
1da2abf4b5 | ||
|
|
e5835fdc75 | ||
|
|
c10de48f08 | ||
|
|
5b0478d12a | ||
|
|
d1504e5654 | ||
|
|
d86905b92a | ||
|
|
f0de3e5b55 | ||
|
|
81a4274738 | ||
|
|
ea1a05f846 | ||
|
|
378eadbc1a |
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -179,7 +179,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cloud-hypervisor"
|
name = "cloud-hypervisor"
|
||||||
version = "32.0.0"
|
version = "32.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"api_client",
|
"api_client",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cloud-hypervisor"
|
name = "cloud-hypervisor"
|
||||||
version = "32.0.0"
|
version = "32.1.0"
|
||||||
authors = ["The Cloud Hypervisor Authors"]
|
authors = ["The Cloud Hypervisor Authors"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
default-run = "cloud-hypervisor"
|
default-run = "cloud-hypervisor"
|
||||||
|
|||||||
@@ -260,32 +260,86 @@ fn create_memory_node(
|
|||||||
fdt.end_node(memory_node)?;
|
fdt.end_node(memory_node)?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let last_addr = guest_mem.last_addr().raw_value();
|
// Note: memory regions from "GuestMemory" are sorted and non-zero sized.
|
||||||
if last_addr < super::layout::MEM_32BIT_RESERVED_START.raw_value() {
|
let ram_regions = {
|
||||||
// Case 1: all RAM is under the hole
|
let mut ram_regions = Vec::new();
|
||||||
let mem_size = last_addr - super::layout::RAM_START.raw_value() + 1;
|
let mut current_start = guest_mem
|
||||||
let mem_reg_prop = [super::layout::RAM_START.raw_value(), mem_size];
|
.iter()
|
||||||
let memory_node = fdt.begin_node("memory")?;
|
.next()
|
||||||
fdt.property_string("device_type", "memory")?;
|
.map(GuestMemoryRegion::start_addr)
|
||||||
fdt.property_array_u64("reg", &mem_reg_prop)?;
|
.expect("GuestMemory must have one memory region at least")
|
||||||
fdt.end_node(memory_node)?;
|
.raw_value();
|
||||||
} else {
|
let mut current_end = current_start;
|
||||||
// Case 2: RAM is split by the hole
|
|
||||||
// Region 1: RAM before the hole
|
for (start, size) in guest_mem
|
||||||
let mem_size = super::layout::MEM_32BIT_RESERVED_START.raw_value()
|
.iter()
|
||||||
- super::layout::RAM_START.raw_value();
|
.map(|m| (m.start_addr().raw_value(), m.len()))
|
||||||
let mem_reg_prop = [super::layout::RAM_START.raw_value(), mem_size];
|
{
|
||||||
let memory_node_name = format!("memory@{:x}", super::layout::RAM_START.raw_value());
|
if current_end == start {
|
||||||
|
// This zone is continuous with the previous one.
|
||||||
|
current_end += size;
|
||||||
|
} else {
|
||||||
|
ram_regions.push((current_start, current_end));
|
||||||
|
|
||||||
|
current_start = start;
|
||||||
|
current_end = start + size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ram_regions.push((current_start, current_end));
|
||||||
|
|
||||||
|
ram_regions
|
||||||
|
};
|
||||||
|
|
||||||
|
if ram_regions.len() > 2 {
|
||||||
|
panic!(
|
||||||
|
"There should be up to two non-continuous regions, devidided by the
|
||||||
|
gap at the end of 32bit address space."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the memory node for memory region before the gap
|
||||||
|
{
|
||||||
|
let (first_region_start, first_region_end) = ram_regions
|
||||||
|
.first()
|
||||||
|
.expect("There should be at last one memory region");
|
||||||
|
let ram_start = super::layout::RAM_START.raw_value();
|
||||||
|
let mem_32bit_reserved_start = super::layout::MEM_32BIT_RESERVED_START.raw_value();
|
||||||
|
|
||||||
|
if !((first_region_start <= &ram_start)
|
||||||
|
&& (first_region_end > &ram_start)
|
||||||
|
&& (first_region_end <= &mem_32bit_reserved_start))
|
||||||
|
{
|
||||||
|
panic!(
|
||||||
|
"Unexpected first memory region layout: (start: 0x{:08x}, end: 0x{:08x}).
|
||||||
|
ram_start: 0x{:08x}, mem_32bit_reserved_start: 0x{:08x}",
|
||||||
|
first_region_start, first_region_end, ram_start, mem_32bit_reserved_start
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mem_size = first_region_end - ram_start;
|
||||||
|
let mem_reg_prop = [ram_start, mem_size];
|
||||||
|
let memory_node_name = format!("memory@{:x}", ram_start);
|
||||||
let memory_node = fdt.begin_node(&memory_node_name)?;
|
let memory_node = fdt.begin_node(&memory_node_name)?;
|
||||||
fdt.property_string("device_type", "memory")?;
|
fdt.property_string("device_type", "memory")?;
|
||||||
fdt.property_array_u64("reg", &mem_reg_prop)?;
|
fdt.property_array_u64("reg", &mem_reg_prop)?;
|
||||||
fdt.end_node(memory_node)?;
|
fdt.end_node(memory_node)?;
|
||||||
|
}
|
||||||
|
|
||||||
// Region 2: RAM after the hole
|
// Create the memory map entry for memory region after the gap if any
|
||||||
let mem_size = last_addr - super::layout::RAM_64BIT_START.raw_value() + 1;
|
if let Some((second_region_start, second_region_end)) = ram_regions.get(1) {
|
||||||
let mem_reg_prop = [super::layout::RAM_64BIT_START.raw_value(), mem_size];
|
let ram_64bit_start = super::layout::RAM_64BIT_START.raw_value();
|
||||||
let memory_node_name =
|
|
||||||
format!("memory@{:x}", super::layout::RAM_64BIT_START.raw_value());
|
if second_region_start != &ram_64bit_start {
|
||||||
|
panic!(
|
||||||
|
"Unexpected second memory region layout: start: 0x{:08x}, ram_64bit_start: 0x{:08x}",
|
||||||
|
second_region_start, ram_64bit_start
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mem_size = second_region_end - ram_64bit_start;
|
||||||
|
let mem_reg_prop = [ram_64bit_start, mem_size];
|
||||||
|
let memory_node_name = format!("memory@{:x}", ram_64bit_start);
|
||||||
let memory_node = fdt.begin_node(&memory_node_name)?;
|
let memory_node = fdt.begin_node(&memory_node_name)?;
|
||||||
fdt.property_string("device_type", "memory")?;
|
fdt.property_string("device_type", "memory")?;
|
||||||
fdt.property_array_u64("reg", &mem_reg_prop)?;
|
fdt.property_array_u64("reg", &mem_reg_prop)?;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ use std::collections::HashMap;
|
|||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic, GuestUsize};
|
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic};
|
||||||
|
|
||||||
pub const _NSIG: i32 = 65;
|
pub const _NSIG: i32 = 65;
|
||||||
|
|
||||||
@@ -83,8 +83,8 @@ pub fn configure_vcpu(
|
|||||||
Ok(mpidr)
|
Ok(mpidr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> {
|
pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> {
|
||||||
let mut regions = vec![
|
vec![
|
||||||
// 0 MiB ~ 256 MiB: UEFI, GIC and legacy devices
|
// 0 MiB ~ 256 MiB: UEFI, GIC and legacy devices
|
||||||
(
|
(
|
||||||
GuestAddress(0),
|
GuestAddress(0),
|
||||||
@@ -103,39 +103,21 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region
|
|||||||
layout::PCI_MMCONFIG_SIZE as usize,
|
layout::PCI_MMCONFIG_SIZE as usize,
|
||||||
RegionType::Reserved,
|
RegionType::Reserved,
|
||||||
),
|
),
|
||||||
];
|
// 1GiB ~ 4032 MiB: RAM before the gap
|
||||||
|
(
|
||||||
let ram_32bit_space_size =
|
|
||||||
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START);
|
|
||||||
|
|
||||||
// RAM space
|
|
||||||
// Case1: guest memory fits before the gap
|
|
||||||
if size <= ram_32bit_space_size {
|
|
||||||
regions.push((layout::RAM_START, size as usize, RegionType::Ram));
|
|
||||||
// Case2: guest memory extends beyond the gap
|
|
||||||
} else {
|
|
||||||
// Push memory before the gap
|
|
||||||
regions.push((
|
|
||||||
layout::RAM_START,
|
layout::RAM_START,
|
||||||
ram_32bit_space_size as usize,
|
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START) as usize,
|
||||||
RegionType::Ram,
|
RegionType::Ram,
|
||||||
));
|
),
|
||||||
// Other memory is placed after 4GiB
|
// 4GiB ~ inf: RAM after the gap
|
||||||
regions.push((
|
(layout::RAM_64BIT_START, usize::MAX, RegionType::Ram),
|
||||||
layout::RAM_64BIT_START,
|
// Add the 32-bit reserved memory hole as a reserved region
|
||||||
(size - ram_32bit_space_size) as usize,
|
(
|
||||||
RegionType::Ram,
|
layout::MEM_32BIT_RESERVED_START,
|
||||||
));
|
layout::MEM_32BIT_RESERVED_SIZE as usize,
|
||||||
}
|
RegionType::Reserved,
|
||||||
|
),
|
||||||
// Add the 32-bit reserved memory hole as a reserved region
|
]
|
||||||
regions.push((
|
|
||||||
layout::MEM_32BIT_RESERVED_START,
|
|
||||||
layout::MEM_32BIT_RESERVED_SIZE as usize,
|
|
||||||
RegionType::Reserved,
|
|
||||||
));
|
|
||||||
|
|
||||||
regions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configures the system and should be called once per vm before starting vcpu threads.
|
/// Configures the system and should be called once per vm before starting vcpu threads.
|
||||||
@@ -217,26 +199,12 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_arch_memory_regions_dram_2gb() {
|
fn test_arch_memory_regions_dram() {
|
||||||
let regions = arch_memory_regions((1usize << 31) as u64); //2GB
|
let regions = arch_memory_regions();
|
||||||
assert_eq!(5, regions.len());
|
|
||||||
assert_eq!(layout::RAM_START, regions[3].0);
|
|
||||||
assert_eq!((1usize << 31), regions[3].1);
|
|
||||||
assert_eq!(RegionType::Ram, regions[3].2);
|
|
||||||
assert_eq!(RegionType::Reserved, regions[4].2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_arch_memory_regions_dram_4gb() {
|
|
||||||
let regions = arch_memory_regions((1usize << 32) as u64); //4GB
|
|
||||||
let ram_32bit_space_size =
|
|
||||||
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START) as usize;
|
|
||||||
assert_eq!(6, regions.len());
|
assert_eq!(6, regions.len());
|
||||||
assert_eq!(layout::RAM_START, regions[3].0);
|
assert_eq!(layout::RAM_START, regions[3].0);
|
||||||
assert_eq!(ram_32bit_space_size, regions[3].1);
|
|
||||||
assert_eq!(RegionType::Ram, regions[3].2);
|
assert_eq!(RegionType::Ram, regions[3].2);
|
||||||
assert_eq!(RegionType::Reserved, regions[5].2);
|
assert_eq!(RegionType::Reserved, regions[5].2);
|
||||||
assert_eq!(RegionType::Ram, regions[4].2);
|
assert_eq!(RegionType::Ram, regions[4].2);
|
||||||
assert_eq!(((1usize << 32) - ram_32bit_space_size), regions[4].1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -775,6 +775,13 @@ pub fn configure_vcpu(
|
|||||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, u32::from(id));
|
CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, u32::from(id));
|
||||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, u32::from(id));
|
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, u32::from(id));
|
||||||
|
|
||||||
|
// Set ApicId in cpuid for each vcpu
|
||||||
|
// SAFETY: get host cpuid when eax=1
|
||||||
|
let mut cpu_ebx = unsafe { core::arch::x86_64::__cpuid(1) }.ebx;
|
||||||
|
cpu_ebx &= 0xffffff;
|
||||||
|
cpu_ebx |= (id as u32) << 24;
|
||||||
|
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1, None, CpuidReg::EBX, cpu_ebx);
|
||||||
|
|
||||||
// The TSC frequency CPUID leaf should not be included when running with HyperV emulation
|
// The TSC frequency CPUID leaf should not be included when running with HyperV emulation
|
||||||
if !kvm_hyperv {
|
if !kvm_hyperv {
|
||||||
if let Some(tsc_khz) = vcpu.tsc_khz().map_err(Error::GetTscFrequency)? {
|
if let Some(tsc_khz) = vcpu.tsc_khz().map_err(Error::GetTscFrequency)? {
|
||||||
@@ -827,47 +834,29 @@ pub fn configure_vcpu(
|
|||||||
/// These should be used to configure the GuestMemory structure for the platform.
|
/// These should be used to configure the GuestMemory structure for the platform.
|
||||||
/// For x86_64 all addresses are valid from the start of the kernel except a
|
/// For x86_64 all addresses are valid from the start of the kernel except a
|
||||||
/// carve out at the end of 32bit address space.
|
/// carve out at the end of 32bit address space.
|
||||||
pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> {
|
pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> {
|
||||||
let reserved_memory_gap_start = layout::MEM_32BIT_RESERVED_START
|
vec![
|
||||||
.checked_add(layout::MEM_32BIT_DEVICES_SIZE)
|
// 0 GiB ~ 3GiB: memory before the gap
|
||||||
.expect("32-bit reserved region is too large");
|
(
|
||||||
|
|
||||||
let requested_memory_size = GuestAddress(size);
|
|
||||||
let mut regions = Vec::new();
|
|
||||||
|
|
||||||
// case1: guest memory fits before the gap
|
|
||||||
if size <= layout::MEM_32BIT_RESERVED_START.raw_value() {
|
|
||||||
regions.push((GuestAddress(0), size as usize, RegionType::Ram));
|
|
||||||
// case2: guest memory extends beyond the gap
|
|
||||||
} else {
|
|
||||||
// push memory before the gap
|
|
||||||
regions.push((
|
|
||||||
GuestAddress(0),
|
GuestAddress(0),
|
||||||
layout::MEM_32BIT_RESERVED_START.raw_value() as usize,
|
layout::MEM_32BIT_RESERVED_START.raw_value() as usize,
|
||||||
RegionType::Ram,
|
RegionType::Ram,
|
||||||
));
|
),
|
||||||
regions.push((
|
// 4 GiB ~ inf: memory after the gap
|
||||||
layout::RAM_64BIT_START,
|
(layout::RAM_64BIT_START, usize::MAX, RegionType::Ram),
|
||||||
requested_memory_size.unchecked_offset_from(layout::MEM_32BIT_RESERVED_START) as usize,
|
// 3 GiB ~ 3712 MiB: 32-bit device memory hole
|
||||||
RegionType::Ram,
|
(
|
||||||
));
|
layout::MEM_32BIT_RESERVED_START,
|
||||||
}
|
layout::MEM_32BIT_DEVICES_SIZE as usize,
|
||||||
|
RegionType::SubRegion,
|
||||||
// Add the 32-bit device memory hole as a sub region.
|
),
|
||||||
regions.push((
|
// 3712 MiB ~ 3968 MiB: 32-bit reserved memory hole
|
||||||
layout::MEM_32BIT_RESERVED_START,
|
(
|
||||||
layout::MEM_32BIT_DEVICES_SIZE as usize,
|
layout::MEM_32BIT_RESERVED_START.unchecked_add(layout::MEM_32BIT_DEVICES_SIZE),
|
||||||
RegionType::SubRegion,
|
(layout::MEM_32BIT_RESERVED_SIZE - layout::MEM_32BIT_DEVICES_SIZE) as usize,
|
||||||
));
|
RegionType::Reserved,
|
||||||
|
),
|
||||||
// Add the 32-bit reserved memory hole as a sub region.
|
]
|
||||||
regions.push((
|
|
||||||
reserved_memory_gap_start,
|
|
||||||
(layout::MEM_32BIT_RESERVED_SIZE - layout::MEM_32BIT_DEVICES_SIZE) as usize,
|
|
||||||
RegionType::Reserved,
|
|
||||||
));
|
|
||||||
|
|
||||||
regions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configures the system and should be called once per vm before starting vcpu threads.
|
/// Configures the system and should be called once per vm before starting vcpu threads.
|
||||||
@@ -965,30 +954,102 @@ fn configure_pvh(
|
|||||||
// Create the memory map entries.
|
// Create the memory map entries.
|
||||||
add_memmap_entry(&mut memmap, 0, layout::EBDA_START.raw_value(), E820_RAM);
|
add_memmap_entry(&mut memmap, 0, layout::EBDA_START.raw_value(), E820_RAM);
|
||||||
|
|
||||||
let mem_end = guest_mem.last_addr();
|
// Merge continuous memory regions into one region.
|
||||||
|
// Note: memory regions from "GuestMemory" are sorted and non-zero sized.
|
||||||
|
let ram_regions = {
|
||||||
|
let mut ram_regions = Vec::new();
|
||||||
|
let mut current_start = guest_mem
|
||||||
|
.iter()
|
||||||
|
.next()
|
||||||
|
.map(GuestMemoryRegion::start_addr)
|
||||||
|
.expect("GuestMemory must have one memory region at least")
|
||||||
|
.raw_value();
|
||||||
|
let mut current_end = current_start;
|
||||||
|
|
||||||
if mem_end < layout::MEM_32BIT_RESERVED_START {
|
for (start, size) in guest_mem
|
||||||
add_memmap_entry(
|
.iter()
|
||||||
&mut memmap,
|
.map(|m| (m.start_addr().raw_value(), m.len()))
|
||||||
layout::HIGH_RAM_START.raw_value(),
|
{
|
||||||
mem_end.unchecked_offset_from(layout::HIGH_RAM_START) + 1,
|
if current_end == start {
|
||||||
E820_RAM,
|
// This zone is continuous with the previous one.
|
||||||
);
|
current_end += size;
|
||||||
} else {
|
} else {
|
||||||
add_memmap_entry(
|
ram_regions.push((current_start, current_end));
|
||||||
&mut memmap,
|
|
||||||
layout::HIGH_RAM_START.raw_value(),
|
current_start = start;
|
||||||
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::HIGH_RAM_START),
|
current_end = start + size;
|
||||||
E820_RAM,
|
}
|
||||||
);
|
|
||||||
if mem_end > layout::RAM_64BIT_START {
|
|
||||||
add_memmap_entry(
|
|
||||||
&mut memmap,
|
|
||||||
layout::RAM_64BIT_START.raw_value(),
|
|
||||||
mem_end.unchecked_offset_from(layout::RAM_64BIT_START) + 1,
|
|
||||||
E820_RAM,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ram_regions.push((current_start, current_end));
|
||||||
|
|
||||||
|
ram_regions
|
||||||
|
};
|
||||||
|
|
||||||
|
if ram_regions.len() > 2 {
|
||||||
|
error!(
|
||||||
|
"There should be up to two non-continuous regions, devidided by the
|
||||||
|
gap at the end of 32bit address space (e.g. between 3G and 4G)."
|
||||||
|
);
|
||||||
|
return Err(super::Error::MemmapTableSetup);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the memory map entry for memory region before the gap
|
||||||
|
{
|
||||||
|
let (first_region_start, first_region_end) =
|
||||||
|
ram_regions.first().ok_or(super::Error::MemmapTableSetup)?;
|
||||||
|
let high_ram_start = layout::HIGH_RAM_START.raw_value();
|
||||||
|
let mem_32bit_reserved_start = layout::MEM_32BIT_RESERVED_START.raw_value();
|
||||||
|
|
||||||
|
if !((first_region_start <= &high_ram_start)
|
||||||
|
&& (first_region_end > &high_ram_start)
|
||||||
|
&& (first_region_end <= &mem_32bit_reserved_start))
|
||||||
|
{
|
||||||
|
error!(
|
||||||
|
"Unexpected first memory region layout: (start: 0x{:08x}, end: 0x{:08x}).
|
||||||
|
high_ram_start: 0x{:08x}, mem_32bit_reserved_start: 0x{:08x}",
|
||||||
|
first_region_start, first_region_end, high_ram_start, mem_32bit_reserved_start
|
||||||
|
);
|
||||||
|
|
||||||
|
return Err(super::Error::MemmapTableSetup);
|
||||||
|
}
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x})",
|
||||||
|
high_ram_start, first_region_end
|
||||||
|
);
|
||||||
|
|
||||||
|
add_memmap_entry(
|
||||||
|
&mut memmap,
|
||||||
|
high_ram_start,
|
||||||
|
first_region_end - high_ram_start,
|
||||||
|
E820_RAM,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the memory map entry for memory region after the gap if any
|
||||||
|
if let Some((second_region_start, second_region_end)) = ram_regions.get(1) {
|
||||||
|
let ram_64bit_start = layout::RAM_64BIT_START.raw_value();
|
||||||
|
|
||||||
|
if second_region_start != &ram_64bit_start {
|
||||||
|
error!(
|
||||||
|
"Unexpected second memory region layout: start: 0x{:08x}, ram_64bit_start: 0x{:08x}",
|
||||||
|
second_region_start, ram_64bit_start
|
||||||
|
);
|
||||||
|
|
||||||
|
return Err(super::Error::MemmapTableSetup);
|
||||||
|
}
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x})",
|
||||||
|
ram_64bit_start, second_region_end
|
||||||
|
);
|
||||||
|
add_memmap_entry(
|
||||||
|
&mut memmap,
|
||||||
|
ram_64bit_start,
|
||||||
|
second_region_end - ram_64bit_start,
|
||||||
|
E820_RAM,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
add_memmap_entry(
|
add_memmap_entry(
|
||||||
@@ -1224,16 +1285,8 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn regions_lt_4gb() {
|
fn regions_base_addr() {
|
||||||
let regions = arch_memory_regions(1 << 29);
|
let regions = arch_memory_regions();
|
||||||
assert_eq!(3, regions.len());
|
|
||||||
assert_eq!(GuestAddress(0), regions[0].0);
|
|
||||||
assert_eq!(1usize << 29, regions[0].1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn regions_gt_4gb() {
|
|
||||||
let regions = arch_memory_regions((1 << 32) + 0x8000);
|
|
||||||
assert_eq!(4, regions.len());
|
assert_eq!(4, regions.len());
|
||||||
assert_eq!(GuestAddress(0), regions[0].0);
|
assert_eq!(GuestAddress(0), regions[0].0);
|
||||||
assert_eq!(GuestAddress(1 << 32), regions[1].0);
|
assert_eq!(GuestAddress(1 << 32), regions[1].0);
|
||||||
@@ -1257,11 +1310,10 @@ mod tests {
|
|||||||
assert!(config_err.is_err());
|
assert!(config_err.is_err());
|
||||||
|
|
||||||
// Now assigning some memory that falls before the 32bit memory hole.
|
// Now assigning some memory that falls before the 32bit memory hole.
|
||||||
let mem_size = 128 << 20;
|
let arch_mem_regions = arch_memory_regions();
|
||||||
let arch_mem_regions = arch_memory_regions(mem_size);
|
|
||||||
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
|
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|r| r.2 == RegionType::Ram)
|
.filter(|r| r.2 == RegionType::Ram && r.1 != usize::MAX)
|
||||||
.map(|r| (r.0, r.1))
|
.map(|r| (r.0, r.1))
|
||||||
.collect();
|
.collect();
|
||||||
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
||||||
@@ -1279,48 +1331,18 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Now assigning some memory that is equal to the start of the 32bit memory hole.
|
|
||||||
let mem_size = 3328 << 20;
|
|
||||||
let arch_mem_regions = arch_memory_regions(mem_size);
|
|
||||||
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
|
|
||||||
.iter()
|
|
||||||
.filter(|r| r.2 == RegionType::Ram)
|
|
||||||
.map(|r| (r.0, r.1))
|
|
||||||
.collect();
|
|
||||||
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
|
||||||
configure_system(
|
|
||||||
&gm,
|
|
||||||
GuestAddress(0),
|
|
||||||
&None,
|
|
||||||
no_vcpus,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
configure_system(
|
|
||||||
&gm,
|
|
||||||
GuestAddress(0),
|
|
||||||
&None,
|
|
||||||
no_vcpus,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Now assigning some memory that falls after the 32bit memory hole.
|
// Now assigning some memory that falls after the 32bit memory hole.
|
||||||
let mem_size = 3330 << 20;
|
let arch_mem_regions = arch_memory_regions();
|
||||||
let arch_mem_regions = arch_memory_regions(mem_size);
|
|
||||||
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
|
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|r| r.2 == RegionType::Ram)
|
.filter(|r| r.2 == RegionType::Ram)
|
||||||
.map(|r| (r.0, r.1))
|
.map(|r| {
|
||||||
|
if r.1 == usize::MAX {
|
||||||
|
(r.0, 128 << 20)
|
||||||
|
} else {
|
||||||
|
(r.0, r.1)
|
||||||
|
}
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
||||||
configure_system(
|
configure_system(
|
||||||
|
|||||||
@@ -511,6 +511,16 @@ impl MsixCap {
|
|||||||
self.pba & 0xffff_fff8
|
self.pba & 0xffff_fff8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn table_set_offset(&mut self, addr: u32) {
|
||||||
|
self.table &= 0x7;
|
||||||
|
self.table += addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pba_set_offset(&mut self, addr: u32) {
|
||||||
|
self.pba &= 0x7;
|
||||||
|
self.pba += addr;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn table_bir(&self) -> u32 {
|
pub fn table_bir(&self) -> u32 {
|
||||||
self.table & 0x7
|
self.table & 0x7
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use crate::{
|
|||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
use hypervisor::HypervisorVmError;
|
use hypervisor::HypervisorVmError;
|
||||||
|
use libc::{sysconf, _SC_PAGESIZE};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -27,6 +28,9 @@ use vfio_bindings::bindings::vfio::*;
|
|||||||
use vfio_ioctls::{
|
use vfio_ioctls::{
|
||||||
VfioContainer, VfioDevice, VfioIrq, VfioRegionInfoCap, VfioRegionSparseMmapArea,
|
VfioContainer, VfioDevice, VfioIrq, VfioRegionInfoCap, VfioRegionSparseMmapArea,
|
||||||
};
|
};
|
||||||
|
use vm_allocator::page_size::{
|
||||||
|
align_page_size_down, align_page_size_up, is_4k_aligned, is_4k_multiple, is_page_size_aligned,
|
||||||
|
};
|
||||||
use vm_allocator::{AddressAllocator, SystemAllocator};
|
use vm_allocator::{AddressAllocator, SystemAllocator};
|
||||||
use vm_device::interrupt::{
|
use vm_device::interrupt::{
|
||||||
InterruptIndex, InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig,
|
InterruptIndex, InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig,
|
||||||
@@ -498,6 +502,29 @@ impl VfioCommon {
|
|||||||
Ok(vfio_common)
|
Ok(vfio_common)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// In case msix table offset is not page size aligned, we need do some fixup to achive it.
|
||||||
|
/// Becuse we don't want the MMIO RW region and trap region overlap each other.
|
||||||
|
fn fixup_msix_region(&mut self, bar_id: u32, region_size: u64) -> u64 {
|
||||||
|
let msix = self.interrupt.msix.as_mut().unwrap();
|
||||||
|
let msix_cap = &mut msix.cap;
|
||||||
|
|
||||||
|
// Suppose table_bir equals to pba_bir here. Am I right?
|
||||||
|
let (table_offset, table_size) = msix_cap.table_range();
|
||||||
|
if is_page_size_aligned(table_offset) || msix_cap.table_bir() != bar_id {
|
||||||
|
return region_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (pba_offset, pba_size) = msix_cap.pba_range();
|
||||||
|
let msix_sz = align_page_size_up(table_size + pba_size);
|
||||||
|
// Expand region to hold RW and trap region which both page size aligned
|
||||||
|
let size = std::cmp::max(region_size * 2, msix_sz * 2);
|
||||||
|
// let table starts from the middle of the region
|
||||||
|
msix_cap.table_set_offset((size / 2) as u32);
|
||||||
|
msix_cap.pba_set_offset((size / 2 + pba_offset - table_offset) as u32);
|
||||||
|
|
||||||
|
size
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn allocate_bars(
|
pub(crate) fn allocate_bars(
|
||||||
&mut self,
|
&mut self,
|
||||||
allocator: &Arc<Mutex<SystemAllocator>>,
|
allocator: &Arc<Mutex<SystemAllocator>>,
|
||||||
@@ -661,9 +688,16 @@ impl VfioCommon {
|
|||||||
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?
|
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?
|
||||||
}
|
}
|
||||||
PciBarRegionType::Memory64BitRegion => {
|
PciBarRegionType::Memory64BitRegion => {
|
||||||
// BAR allocation must be naturally aligned
|
// We need do some fixup to keep MMIO RW region and msix cap region page size
|
||||||
|
// aligned.
|
||||||
|
region_size = self.fixup_msix_region(bar_id, region_size);
|
||||||
mmio_allocator
|
mmio_allocator
|
||||||
.allocate(restored_bar_addr, region_size, Some(region_size))
|
.allocate(
|
||||||
|
restored_bar_addr,
|
||||||
|
region_size,
|
||||||
|
// SAFETY: FFI call. Trivially safe.
|
||||||
|
Some(unsafe { sysconf(_SC_PAGESIZE) as GuestUsize }),
|
||||||
|
)
|
||||||
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?
|
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -800,6 +834,23 @@ impl VfioCommon {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_msix_cap_idx(&self) -> Option<usize> {
|
||||||
|
let mut cap_next = self
|
||||||
|
.vfio_wrapper
|
||||||
|
.read_config_byte(PCI_CONFIG_CAPABILITY_OFFSET);
|
||||||
|
|
||||||
|
while cap_next != 0 {
|
||||||
|
let cap_id = self.vfio_wrapper.read_config_byte(cap_next.into());
|
||||||
|
if PciCapabilityId::from(cap_id) == PciCapabilityId::MsiX {
|
||||||
|
return Some(cap_next as usize);
|
||||||
|
} else {
|
||||||
|
cap_next = self.vfio_wrapper.read_config_byte((cap_next + 1).into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_capabilities(&mut self, bdf: PciBdf) {
|
pub(crate) fn parse_capabilities(&mut self, bdf: PciBdf) {
|
||||||
let mut cap_next = self
|
let mut cap_next = self
|
||||||
.vfio_wrapper
|
.vfio_wrapper
|
||||||
@@ -1154,6 +1205,15 @@ impl VfioCommon {
|
|||||||
return self.configuration.read_reg(reg_idx);
|
return self.configuration.read_reg(reg_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(id) = self.get_msix_cap_idx() {
|
||||||
|
let msix = self.interrupt.msix.as_mut().unwrap();
|
||||||
|
if reg_idx * 4 == id + 4 {
|
||||||
|
return msix.cap.table;
|
||||||
|
} else if reg_idx * 4 == id + 8 {
|
||||||
|
return msix.cap.pba;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Since we don't support passing multi-functions devices, we should
|
// Since we don't support passing multi-functions devices, we should
|
||||||
// mask the multi-function bit, bit 7 of the Header Type byte on the
|
// mask the multi-function bit, bit 7 of the Header Type byte on the
|
||||||
// register 3.
|
// register 3.
|
||||||
@@ -1316,18 +1376,6 @@ impl VfioPciDevice {
|
|||||||
self.iommu_attached
|
self.iommu_attached
|
||||||
}
|
}
|
||||||
|
|
||||||
fn align_4k(address: u64) -> u64 {
|
|
||||||
(address + 0xfff) & 0xffff_ffff_ffff_f000
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_4k_aligned(address: u64) -> bool {
|
|
||||||
(address & 0xfff) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_4k_multiple(size: u64) -> bool {
|
|
||||||
(size & 0xfff) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_sparse_areas(
|
fn generate_sparse_areas(
|
||||||
caps: &[VfioRegionInfoCap],
|
caps: &[VfioRegionInfoCap],
|
||||||
region_index: u32,
|
region_index: u32,
|
||||||
@@ -1339,14 +1387,14 @@ impl VfioPciDevice {
|
|||||||
match cap {
|
match cap {
|
||||||
VfioRegionInfoCap::SparseMmap(sparse_mmap) => return Ok(sparse_mmap.areas.clone()),
|
VfioRegionInfoCap::SparseMmap(sparse_mmap) => return Ok(sparse_mmap.areas.clone()),
|
||||||
VfioRegionInfoCap::MsixMappable => {
|
VfioRegionInfoCap::MsixMappable => {
|
||||||
if !Self::is_4k_aligned(region_start) {
|
if !is_4k_aligned(region_start) {
|
||||||
error!(
|
error!(
|
||||||
"Region start address 0x{:x} must be at least aligned on 4KiB",
|
"Region start address 0x{:x} must be at least aligned on 4KiB",
|
||||||
region_start
|
region_start
|
||||||
);
|
);
|
||||||
return Err(VfioPciError::RegionAlignment);
|
return Err(VfioPciError::RegionAlignment);
|
||||||
}
|
}
|
||||||
if !Self::is_4k_multiple(region_size) {
|
if !is_4k_multiple(region_size) {
|
||||||
error!(
|
error!(
|
||||||
"Region size 0x{:x} must be at least a multiple of 4KiB",
|
"Region size 0x{:x} must be at least a multiple of 4KiB",
|
||||||
region_size
|
region_size
|
||||||
@@ -1358,7 +1406,8 @@ impl VfioPciDevice {
|
|||||||
// the MSI-X PBA table, we must calculate the subregions
|
// the MSI-X PBA table, we must calculate the subregions
|
||||||
// around them, leading to a list of sparse areas.
|
// around them, leading to a list of sparse areas.
|
||||||
// We want to make sure we will still trap MMIO accesses
|
// We want to make sure we will still trap MMIO accesses
|
||||||
// to these MSI-X specific ranges.
|
// to these MSI-X specific ranges. If these region don't align
|
||||||
|
// with pagesize, we can achive it by enlarging its range.
|
||||||
//
|
//
|
||||||
// Using a BtreeMap as the list provided through the iterator is sorted
|
// Using a BtreeMap as the list provided through the iterator is sorted
|
||||||
// by key. This ensures proper split of the whole region.
|
// by key. This ensures proper split of the whole region.
|
||||||
@@ -1366,10 +1415,14 @@ impl VfioPciDevice {
|
|||||||
if let Some(msix) = vfio_msix {
|
if let Some(msix) = vfio_msix {
|
||||||
if region_index == msix.cap.table_bir() {
|
if region_index == msix.cap.table_bir() {
|
||||||
let (offset, size) = msix.cap.table_range();
|
let (offset, size) = msix.cap.table_range();
|
||||||
|
let offset = align_page_size_down(offset);
|
||||||
|
let size = align_page_size_up(size);
|
||||||
inter_ranges.insert(offset, size);
|
inter_ranges.insert(offset, size);
|
||||||
}
|
}
|
||||||
if region_index == msix.cap.pba_bir() {
|
if region_index == msix.cap.pba_bir() {
|
||||||
let (offset, size) = msix.cap.pba_range();
|
let (offset, size) = msix.cap.pba_range();
|
||||||
|
let offset = align_page_size_down(offset);
|
||||||
|
let size = align_page_size_up(size);
|
||||||
inter_ranges.insert(offset, size);
|
inter_ranges.insert(offset, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1383,8 +1436,7 @@ impl VfioPciDevice {
|
|||||||
size: range_offset - current_offset,
|
size: range_offset - current_offset,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
current_offset = align_page_size_down(range_offset + range_size);
|
||||||
current_offset = Self::align_4k(range_offset + range_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if region_size > current_offset {
|
if region_size > current_offset {
|
||||||
@@ -1482,6 +1534,15 @@ impl VfioPciDevice {
|
|||||||
return Err(VfioPciError::MmapArea);
|
return Err(VfioPciError::MmapArea);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !is_page_size_aligned(area.size) || !is_page_size_aligned(area.offset) {
|
||||||
|
warn!(
|
||||||
|
"Could not mmap sparse area that is not page size aligned (offset = 0x{:x}, size = 0x{:x})",
|
||||||
|
area.offset,
|
||||||
|
area.size,
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let user_memory_region = UserMemoryRegion {
|
let user_memory_region = UserMemoryRegion {
|
||||||
slot: (self.memory_slot)(),
|
slot: (self.memory_slot)(),
|
||||||
start: region.start.0 + area.offset,
|
start: region.start.0 + area.offset,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
- [v32.1](#v321)
|
||||||
- [v32.0](#v320)
|
- [v32.0](#v320)
|
||||||
- [Increased PCI Segment Limit](#increased-pci-segment-limit)
|
- [Increased PCI Segment Limit](#increased-pci-segment-limit)
|
||||||
- [API Changes](#api-changes)
|
- [API Changes](#api-changes)
|
||||||
@@ -282,6 +283,19 @@
|
|||||||
- [Unit testing](#unit-testing)
|
- [Unit testing](#unit-testing)
|
||||||
- [Integration tests parallelization](#integration-tests-parallelization)
|
- [Integration tests parallelization](#integration-tests-parallelization)
|
||||||
|
|
||||||
|
# v32.1
|
||||||
|
|
||||||
|
This is a bug fix release. The following issues have been addressed:
|
||||||
|
|
||||||
|
* Report errors explicitly to users when VM failed to boot (#5453)
|
||||||
|
* Fix VFIO on platforms with non-4k page size (#5450, #5469)
|
||||||
|
* Fix TDX initialization (#5454)
|
||||||
|
* Ensure all guest memory regions are page-size aligned (#5496)
|
||||||
|
* Fix seccomp filter lists related to virtio-console, serial and pty
|
||||||
|
(#5506, #5524)
|
||||||
|
* Populate APIC ID properly (#5512)
|
||||||
|
* Ignore and warn TAP FDs in more situations (#5522)
|
||||||
|
|
||||||
# v32.0
|
# v32.0
|
||||||
|
|
||||||
This release has been tracked in our [roadmap
|
This release has been tracked in our [roadmap
|
||||||
|
|||||||
10
src/main.rs
10
src/main.rs
@@ -92,9 +92,9 @@ impl log::Log for Logger {
|
|||||||
let duration = now.duration_since(self.start);
|
let duration = now.duration_since(self.start);
|
||||||
|
|
||||||
if record.file().is_some() && record.line().is_some() {
|
if record.file().is_some() && record.line().is_some() {
|
||||||
writeln!(
|
write!(
|
||||||
*(*(self.output.lock().unwrap())),
|
*(*(self.output.lock().unwrap())),
|
||||||
"cloud-hypervisor: {:.6?}: <{}> {}:{}:{} -- {}",
|
"cloud-hypervisor: {:.6?}: <{}> {}:{}:{} -- {}\r\n",
|
||||||
duration,
|
duration,
|
||||||
std::thread::current().name().unwrap_or("anonymous"),
|
std::thread::current().name().unwrap_or("anonymous"),
|
||||||
record.level(),
|
record.level(),
|
||||||
@@ -103,9 +103,9 @@ impl log::Log for Logger {
|
|||||||
record.args()
|
record.args()
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
writeln!(
|
write!(
|
||||||
*(*(self.output.lock().unwrap())),
|
*(*(self.output.lock().unwrap())),
|
||||||
"cloud-hypervisor: {:.6?}: <{}> {}:{} -- {}",
|
"cloud-hypervisor: {:.6?}: <{}> {}:{} -- {}\r\n",
|
||||||
duration,
|
duration,
|
||||||
std::thread::current().name().unwrap_or("anonymous"),
|
std::thread::current().name().unwrap_or("anonymous"),
|
||||||
record.level(),
|
record.level(),
|
||||||
@@ -573,7 +573,7 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
|
|||||||
.map_err(Error::ThreadJoin)?
|
.map_err(Error::ThreadJoin)?
|
||||||
.map_err(Error::VmmThread)?;
|
.map_err(Error::VmmThread)?;
|
||||||
|
|
||||||
Ok(api_socket_path)
|
r.map(|_| api_socket_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|||||||
@@ -309,11 +309,7 @@ impl Emulator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.established_flag_cached = true;
|
self.established_flag_cached = true;
|
||||||
if est.resp.bit != 0 {
|
self.established_flag = est.resp.bit == 0;
|
||||||
self.established_flag = false;
|
|
||||||
} else {
|
|
||||||
self.established_flag = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.established_flag
|
self.established_flag
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,11 +145,7 @@ impl DiskSpec {
|
|||||||
let bits = f
|
let bits = f
|
||||||
.read_u32::<LittleEndian>()
|
.read_u32::<LittleEndian>()
|
||||||
.map_err(VhdxMetadataError::ReadMetadata)?;
|
.map_err(VhdxMetadataError::ReadMetadata)?;
|
||||||
if bits & BLOCK_HAS_PARENT != 0 {
|
disk_spec.has_parent = bits & BLOCK_HAS_PARENT != 0;
|
||||||
disk_spec.has_parent = true;
|
|
||||||
} else {
|
|
||||||
disk_spec.has_parent = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata_presence |= METADATA_FILE_PARAMETER_PRESENT;
|
metadata_presence |= METADATA_FILE_PARAMETER_PRESENT;
|
||||||
} else if metadata_entry.item_id
|
} else if metadata_entry.item_id
|
||||||
|
|||||||
@@ -259,6 +259,7 @@ fn virtio_thread_common() -> Vec<(i64, Vec<SeccompRule>)> {
|
|||||||
(libc::SYS_madvise, vec![]),
|
(libc::SYS_madvise, vec![]),
|
||||||
(libc::SYS_mmap, vec![]),
|
(libc::SYS_mmap, vec![]),
|
||||||
(libc::SYS_mprotect, vec![]),
|
(libc::SYS_mprotect, vec![]),
|
||||||
|
(libc::SYS_mremap, vec![]),
|
||||||
(libc::SYS_munmap, vec![]),
|
(libc::SYS_munmap, vec![]),
|
||||||
(libc::SYS_openat, vec![]),
|
(libc::SYS_openat, vec![]),
|
||||||
(libc::SYS_read, vec![]),
|
(libc::SYS_read, vec![]),
|
||||||
|
|||||||
@@ -605,7 +605,7 @@ impl VirtioDevice for Fs {
|
|||||||
&mut self,
|
&mut self,
|
||||||
shm_regions: VirtioSharedMemoryList,
|
shm_regions: VirtioSharedMemoryList,
|
||||||
) -> std::result::Result<(), crate::Error> {
|
) -> std::result::Result<(), crate::Error> {
|
||||||
if let Some(mut cache) = self.cache.as_mut() {
|
if let Some(cache) = self.cache.as_mut() {
|
||||||
cache.0 = shm_regions;
|
cache.0 = shm_regions;
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
mod address;
|
mod address;
|
||||||
mod gsi;
|
mod gsi;
|
||||||
|
/// page size related utility funtions
|
||||||
|
pub mod page_size;
|
||||||
mod system;
|
mod system;
|
||||||
|
|
||||||
pub use crate::address::AddressAllocator;
|
pub use crate::address::AddressAllocator;
|
||||||
|
|||||||
38
vm-allocator/src/page_size.rs
Normal file
38
vm-allocator/src/page_size.rs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2023 Arm Limited (or its affiliates). All rights reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use libc::{sysconf, _SC_PAGESIZE};
|
||||||
|
|
||||||
|
/// get host page size
|
||||||
|
pub fn get_page_size() -> u64 {
|
||||||
|
// SAFETY: FFI call. Trivially safe.
|
||||||
|
unsafe { sysconf(_SC_PAGESIZE) as u64 }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// round up address to let it align page size
|
||||||
|
pub fn align_page_size_up(address: u64) -> u64 {
|
||||||
|
let page_size = get_page_size();
|
||||||
|
(address + page_size - 1) & !(page_size - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// round down address to let it align page size
|
||||||
|
pub fn align_page_size_down(address: u64) -> u64 {
|
||||||
|
let page_size = get_page_size();
|
||||||
|
address & !(page_size - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test if address is 4k aligned
|
||||||
|
pub fn is_4k_aligned(address: u64) -> bool {
|
||||||
|
(address & 0xfff) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test if size is 4k aligned
|
||||||
|
pub fn is_4k_multiple(size: u64) -> bool {
|
||||||
|
(size & 0xfff) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test if address is page size aligned
|
||||||
|
pub fn is_page_size_aligned(address: u64) -> bool {
|
||||||
|
let page_size = get_page_size();
|
||||||
|
address & (page_size - 1) == 0
|
||||||
|
}
|
||||||
@@ -14,14 +14,7 @@ use crate::gsi::GsiAllocator;
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use crate::gsi::GsiApic;
|
use crate::gsi::GsiApic;
|
||||||
|
|
||||||
use libc::{sysconf, _SC_PAGESIZE};
|
use crate::page_size::get_page_size;
|
||||||
|
|
||||||
/// Safe wrapper for `sysconf(_SC_PAGESIZE)`.
|
|
||||||
#[inline(always)]
|
|
||||||
fn pagesize() -> usize {
|
|
||||||
// SAFETY: FFI call. Trivially safe.
|
|
||||||
unsafe { sysconf(_SC_PAGESIZE) as usize }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Manages allocating system resources such as address space and interrupt numbers.
|
/// Manages allocating system resources such as address space and interrupt numbers.
|
||||||
///
|
///
|
||||||
@@ -126,7 +119,7 @@ impl SystemAllocator {
|
|||||||
self.platform_mmio_address_space.allocate(
|
self.platform_mmio_address_space.allocate(
|
||||||
address,
|
address,
|
||||||
size,
|
size,
|
||||||
Some(align_size.unwrap_or(pagesize() as u64)),
|
Some(align_size.unwrap_or(get_page_size())),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +133,7 @@ impl SystemAllocator {
|
|||||||
self.mmio_hole_address_space.allocate(
|
self.mmio_hole_address_space.allocate(
|
||||||
address,
|
address,
|
||||||
size,
|
size,
|
||||||
Some(align_size.unwrap_or(pagesize() as u64)),
|
Some(align_size.unwrap_or(get_page_size())),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,8 +110,7 @@ impl Bus {
|
|||||||
let devices = self.devices.read().unwrap();
|
let devices = self.devices.read().unwrap();
|
||||||
let (range, dev) = devices
|
let (range, dev) = devices
|
||||||
.range(..=BusRange { base: addr, len: 1 })
|
.range(..=BusRange { base: addr, len: 1 })
|
||||||
.rev()
|
.next_back()?;
|
||||||
.next()?;
|
|
||||||
dev.upgrade().map(|d| (*range, d.clone()))
|
dev.upgrade().map(|d| (*range, d.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ pub mod protocol;
|
|||||||
|
|
||||||
/// Global VMM version for versioning
|
/// Global VMM version for versioning
|
||||||
const MAJOR_VERSION: u16 = 32;
|
const MAJOR_VERSION: u16 = 32;
|
||||||
const MINOR_VERSION: u16 = 0;
|
const MINOR_VERSION: u16 = 1;
|
||||||
const VMM_VERSION: u16 = MAJOR_VERSION << 12 | MINOR_VERSION & 0b1111;
|
const VMM_VERSION: u16 = MAJOR_VERSION << 12 | MINOR_VERSION & 0b1111;
|
||||||
|
|
||||||
pub trait VersionMapped {
|
pub trait VersionMapped {
|
||||||
|
|||||||
@@ -36,13 +36,22 @@ impl EndpointHandler for VmCreate {
|
|||||||
match &req.body {
|
match &req.body {
|
||||||
Some(body) => {
|
Some(body) => {
|
||||||
// Deserialize into a VmConfig
|
// Deserialize into a VmConfig
|
||||||
let vm_config: VmConfig = match serde_json::from_slice(body.raw())
|
let mut vm_config: VmConfig = match serde_json::from_slice(body.raw())
|
||||||
.map_err(HttpError::SerdeJsonDeserialize)
|
.map_err(HttpError::SerdeJsonDeserialize)
|
||||||
{
|
{
|
||||||
Ok(config) => config,
|
Ok(config) => config,
|
||||||
Err(e) => return error_response(e, StatusCode::BadRequest),
|
Err(e) => return error_response(e, StatusCode::BadRequest),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Some(ref mut nets) = vm_config.net {
|
||||||
|
if nets.iter().any(|net| net.fds.is_some()) {
|
||||||
|
warn!("Ignoring FDs sent via the HTTP request body");
|
||||||
|
}
|
||||||
|
for net in nets {
|
||||||
|
net.fds = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Call vm_create()
|
// Call vm_create()
|
||||||
match vm_create(api_notifier, api_sender, Arc::new(Mutex::new(vm_config)))
|
match vm_create(api_notifier, api_sender, Arc::new(Mutex::new(vm_config)))
|
||||||
.map_err(HttpError::ApiError)
|
.map_err(HttpError::ApiError)
|
||||||
|
|||||||
@@ -1131,7 +1131,7 @@ impl CpuManager {
|
|||||||
|
|
||||||
fn remove_vcpu(&mut self, cpu_id: u8) -> Result<()> {
|
fn remove_vcpu(&mut self, cpu_id: u8) -> Result<()> {
|
||||||
info!("Removing vCPU: cpu_id = {}", cpu_id);
|
info!("Removing vCPU: cpu_id = {}", cpu_id);
|
||||||
let mut state = &mut self.vcpu_states[usize::from(cpu_id)];
|
let state = &mut self.vcpu_states[usize::from(cpu_id)];
|
||||||
state.kill.store(true, Ordering::SeqCst);
|
state.kill.store(true, Ordering::SeqCst);
|
||||||
state.signal_thread();
|
state.signal_thread();
|
||||||
state.join_thread()?;
|
state.join_thread()?;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ use std::convert::TryInto;
|
|||||||
use std::ffi;
|
use std::ffi;
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
use std::ops::Deref;
|
use std::ops::{BitAnd, Deref, Not, Sub};
|
||||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::result;
|
use std::result;
|
||||||
@@ -330,6 +330,12 @@ pub enum Error {
|
|||||||
|
|
||||||
/// Using a directory as a backing file for memory is not supported
|
/// Using a directory as a backing file for memory is not supported
|
||||||
DirectoryAsBackingFileForMemory,
|
DirectoryAsBackingFileForMemory,
|
||||||
|
|
||||||
|
/// Failed to stat filesystem
|
||||||
|
GetFileSystemBlockSize(io::Error),
|
||||||
|
|
||||||
|
/// Memory size is misaligned with default page size or its hugepage size
|
||||||
|
MisalignedMemorySize,
|
||||||
}
|
}
|
||||||
|
|
||||||
const ENABLE_FLAG: usize = 0;
|
const ENABLE_FLAG: usize = 0;
|
||||||
@@ -353,6 +359,77 @@ fn mmio_address_space_size(phys_bits: u8) -> u64 {
|
|||||||
(1 << phys_bits) - (1 << 16)
|
(1 << phys_bits) - (1 << 16)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The `statfs` function can get information of hugetlbfs, and the hugepage size is in the
|
||||||
|
// `f_bsize` field.
|
||||||
|
//
|
||||||
|
// See: https://github.com/torvalds/linux/blob/v6.3/fs/hugetlbfs/inode.c#L1169
|
||||||
|
fn statfs_get_bsize(path: &str) -> Result<u64, Error> {
|
||||||
|
let path = std::ffi::CString::new(path).map_err(|_| Error::InvalidMemoryParameters)?;
|
||||||
|
let mut buf = std::mem::MaybeUninit::<libc::statfs>::uninit();
|
||||||
|
|
||||||
|
// SAFETY: FFI call with a valid path and buffer
|
||||||
|
let ret = unsafe { libc::statfs(path.as_ptr(), buf.as_mut_ptr()) };
|
||||||
|
if ret != 0 {
|
||||||
|
return Err(Error::GetFileSystemBlockSize(
|
||||||
|
std::io::Error::last_os_error(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAFETY: `buf` is valid at this point
|
||||||
|
// Because this value is always positive, just convert it directly.
|
||||||
|
// Note that the `f_bsize` is `i64` in glibc and `u64` in musl, using `as u64` will be warned
|
||||||
|
// by `clippy` on musl target. To avoid the warning, there should be `as _` instead of
|
||||||
|
// `as u64`.
|
||||||
|
let bsize = unsafe { (*buf.as_ptr()).f_bsize } as _;
|
||||||
|
Ok(bsize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn memory_zone_get_align_size(zone: &MemoryZoneConfig) -> Result<u64, Error> {
|
||||||
|
// SAFETY: FFI call. Trivially safe.
|
||||||
|
let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as u64 };
|
||||||
|
|
||||||
|
// There is no backend file and the `hugepages` is disabled, just use system page size.
|
||||||
|
if zone.file.is_none() && !zone.hugepages {
|
||||||
|
return Ok(page_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The `hugepages` is enabled and the `hugepage_size` is specified, just use it directly.
|
||||||
|
if zone.hugepages && zone.hugepage_size.is_some() {
|
||||||
|
return Ok(zone.hugepage_size.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
// There are two scenarios here:
|
||||||
|
// - `hugepages` is enabled but `hugepage_size` is not specified:
|
||||||
|
// Call `statfs` for `/dev/hugepages` for getting the default size of hugepage
|
||||||
|
// - The backing file is specified:
|
||||||
|
// Call `statfs` for the file and get its `f_bsize`. If the value is larger than the page
|
||||||
|
// size of normal page, just use the `f_bsize` because the file is in a hugetlbfs. If the
|
||||||
|
// value is less than or equal to the page size, just use the page size.
|
||||||
|
let path = zone.file.as_ref().map_or(Ok("/dev/hugepages"), |pathbuf| {
|
||||||
|
pathbuf.to_str().ok_or(Error::InvalidMemoryParameters)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let align_size = std::cmp::max(page_size, statfs_get_bsize(path)?);
|
||||||
|
|
||||||
|
Ok(align_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn align_down<T>(val: T, align: T) -> T
|
||||||
|
where
|
||||||
|
T: BitAnd<Output = T> + Not<Output = T> + Sub<Output = T> + From<u8>,
|
||||||
|
{
|
||||||
|
val & !(align - 1u8.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_aligned<T>(val: T, align: T) -> bool
|
||||||
|
where
|
||||||
|
T: BitAnd<Output = T> + Sub<Output = T> + From<u8> + PartialEq,
|
||||||
|
{
|
||||||
|
(val & (align - 1u8.into())) == 0u8.into()
|
||||||
|
}
|
||||||
|
|
||||||
impl BusDevice for MemoryManager {
|
impl BusDevice for MemoryManager {
|
||||||
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
|
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
|
||||||
if self.selected_slot < self.hotplug_slots.len() {
|
if self.selected_slot < self.hotplug_slots.len() {
|
||||||
@@ -442,6 +519,9 @@ impl MemoryManager {
|
|||||||
/// - First one mapping entirely the first memory zone on 0-1G range
|
/// - First one mapping entirely the first memory zone on 0-1G range
|
||||||
/// - Second one mapping partially the second memory zone on 1G-3G range
|
/// - Second one mapping partially the second memory zone on 1G-3G range
|
||||||
/// - Third one mapping partially the second memory zone on 4G-6G range
|
/// - Third one mapping partially the second memory zone on 4G-6G range
|
||||||
|
/// Also, all memory regions are page-size aligned (e.g. their sizes must
|
||||||
|
/// be multiple of page-size), which may leave an additional hole in the
|
||||||
|
/// address space when hugepage is used.
|
||||||
fn create_memory_regions_from_zones(
|
fn create_memory_regions_from_zones(
|
||||||
ram_regions: &[(GuestAddress, usize)],
|
ram_regions: &[(GuestAddress, usize)],
|
||||||
zones: &[MemoryZoneConfig],
|
zones: &[MemoryZoneConfig],
|
||||||
@@ -451,9 +531,14 @@ impl MemoryManager {
|
|||||||
let mut zones = zones.to_owned();
|
let mut zones = zones.to_owned();
|
||||||
let mut mem_regions = Vec::new();
|
let mut mem_regions = Vec::new();
|
||||||
let mut zone = zones.remove(0);
|
let mut zone = zones.remove(0);
|
||||||
let mut zone_offset = 0;
|
let mut zone_align_size = memory_zone_get_align_size(&zone)?;
|
||||||
|
let mut zone_offset = 0u64;
|
||||||
let mut memory_zones = HashMap::new();
|
let mut memory_zones = HashMap::new();
|
||||||
|
|
||||||
|
if !is_aligned(zone.size, zone_align_size) {
|
||||||
|
return Err(Error::MisalignedMemorySize);
|
||||||
|
}
|
||||||
|
|
||||||
// Add zone id to the list of memory zones.
|
// Add zone id to the list of memory zones.
|
||||||
memory_zones.insert(zone.id.clone(), MemoryZone::default());
|
memory_zones.insert(zone.id.clone(), MemoryZone::default());
|
||||||
|
|
||||||
@@ -465,16 +550,20 @@ impl MemoryManager {
|
|||||||
let mut ram_region_consumed = false;
|
let mut ram_region_consumed = false;
|
||||||
let mut pull_next_zone = false;
|
let mut pull_next_zone = false;
|
||||||
|
|
||||||
let ram_region_sub_size = ram_region.1 - ram_region_offset;
|
let ram_region_available_size =
|
||||||
let zone_sub_size = zone.size as usize - zone_offset;
|
align_down(ram_region.1 as u64 - ram_region_offset, zone_align_size);
|
||||||
|
if ram_region_available_size == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let zone_sub_size = zone.size - zone_offset;
|
||||||
|
|
||||||
let file_offset = zone_offset as u64;
|
let file_offset = zone_offset;
|
||||||
let region_start = ram_region
|
let region_start = ram_region
|
||||||
.0
|
.0
|
||||||
.checked_add(ram_region_offset as u64)
|
.checked_add(ram_region_offset)
|
||||||
.ok_or(Error::GuestAddressOverFlow)?;
|
.ok_or(Error::GuestAddressOverFlow)?;
|
||||||
let region_size = if zone_sub_size <= ram_region_sub_size {
|
let region_size = if zone_sub_size <= ram_region_available_size {
|
||||||
if zone_sub_size == ram_region_sub_size {
|
if zone_sub_size == ram_region_available_size {
|
||||||
ram_region_consumed = true;
|
ram_region_consumed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -483,21 +572,24 @@ impl MemoryManager {
|
|||||||
|
|
||||||
zone_sub_size
|
zone_sub_size
|
||||||
} else {
|
} else {
|
||||||
zone_offset += ram_region_sub_size;
|
zone_offset += ram_region_available_size;
|
||||||
ram_region_consumed = true;
|
ram_region_consumed = true;
|
||||||
|
|
||||||
ram_region_sub_size
|
ram_region_available_size
|
||||||
};
|
};
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"create ram region for zone {}, region_start: {:#x}, region_size: {:#x}",
|
||||||
|
zone.id,
|
||||||
|
region_start.raw_value(),
|
||||||
|
region_size
|
||||||
|
);
|
||||||
let region = MemoryManager::create_ram_region(
|
let region = MemoryManager::create_ram_region(
|
||||||
&zone.file,
|
&zone.file,
|
||||||
file_offset,
|
file_offset,
|
||||||
region_start,
|
region_start,
|
||||||
region_size,
|
region_size as usize,
|
||||||
match prefault {
|
prefault.unwrap_or(zone.prefault),
|
||||||
Some(pf) => pf,
|
|
||||||
None => zone.prefault,
|
|
||||||
},
|
|
||||||
zone.shared,
|
zone.shared,
|
||||||
zone.hugepages,
|
zone.hugepages,
|
||||||
zone.hugepage_size,
|
zone.hugepage_size,
|
||||||
@@ -522,6 +614,10 @@ impl MemoryManager {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
zone = zones.remove(0);
|
zone = zones.remove(0);
|
||||||
|
zone_align_size = memory_zone_get_align_size(&zone)?;
|
||||||
|
if !is_aligned(zone.size, zone_align_size) {
|
||||||
|
return Err(Error::MisalignedMemorySize);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if zone id already exist. In case it does, throw
|
// Check if zone id already exist. In case it does, throw
|
||||||
// an error as we need unique identifiers. Otherwise, add
|
// an error as we need unique identifiers. Otherwise, add
|
||||||
@@ -573,10 +669,7 @@ impl MemoryManager {
|
|||||||
guest_ram_mapping.file_offset,
|
guest_ram_mapping.file_offset,
|
||||||
GuestAddress(guest_ram_mapping.gpa),
|
GuestAddress(guest_ram_mapping.gpa),
|
||||||
guest_ram_mapping.size as usize,
|
guest_ram_mapping.size as usize,
|
||||||
match prefault {
|
prefault.unwrap_or(zone_config.prefault),
|
||||||
Some(pf) => pf,
|
|
||||||
None => zone_config.prefault,
|
|
||||||
},
|
|
||||||
zone_config.shared,
|
zone_config.shared,
|
||||||
zone_config.hugepages,
|
zone_config.hugepages,
|
||||||
zone_config.hugepage_size,
|
zone_config.hugepage_size,
|
||||||
@@ -939,7 +1032,7 @@ impl MemoryManager {
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// Init guest memory
|
// Init guest memory
|
||||||
let arch_mem_regions = arch::arch_memory_regions(ram_size);
|
let arch_mem_regions = arch::arch_memory_regions();
|
||||||
|
|
||||||
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
|
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
|
||||||
.iter()
|
.iter()
|
||||||
@@ -997,10 +1090,7 @@ impl MemoryManager {
|
|||||||
0,
|
0,
|
||||||
start_addr,
|
start_addr,
|
||||||
hotplug_size as usize,
|
hotplug_size as usize,
|
||||||
match prefault {
|
prefault.unwrap_or(zone.prefault),
|
||||||
Some(pf) => pf,
|
|
||||||
None => zone.prefault,
|
|
||||||
},
|
|
||||||
zone.shared,
|
zone.shared,
|
||||||
zone.hugepages,
|
zone.hugepages,
|
||||||
zone.hugepage_size,
|
zone.hugepage_size,
|
||||||
@@ -1501,7 +1591,7 @@ impl MemoryManager {
|
|||||||
.ok_or(Error::MemoryRangeAllocation)?;
|
.ok_or(Error::MemoryRangeAllocation)?;
|
||||||
|
|
||||||
// Update the slot so that it can be queried via the I/O port
|
// Update the slot so that it can be queried via the I/O port
|
||||||
let mut slot = &mut self.hotplug_slots[self.next_hotplug_slot];
|
let slot = &mut self.hotplug_slots[self.next_hotplug_slot];
|
||||||
slot.active = true;
|
slot.active = true;
|
||||||
slot.inserting = true;
|
slot.inserting = true;
|
||||||
slot.base = region.start_addr().0;
|
slot.base = region.start_addr().0;
|
||||||
|
|||||||
@@ -484,6 +484,7 @@ fn pty_foreground_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, Backend
|
|||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
(libc::SYS_ppoll, vec![]),
|
(libc::SYS_ppoll, vec![]),
|
||||||
(libc::SYS_read, vec![]),
|
(libc::SYS_read, vec![]),
|
||||||
|
(libc::SYS_restart_syscall, vec![]),
|
||||||
(libc::SYS_rt_sigaction, vec![]),
|
(libc::SYS_rt_sigaction, vec![]),
|
||||||
(libc::SYS_rt_sigreturn, vec![]),
|
(libc::SYS_rt_sigreturn, vec![]),
|
||||||
(libc::SYS_setsid, vec![]),
|
(libc::SYS_setsid, vec![]),
|
||||||
@@ -609,6 +610,7 @@ fn vmm_thread_rules(
|
|||||||
(libc::SYS_socketpair, vec![]),
|
(libc::SYS_socketpair, vec![]),
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
(libc::SYS_stat, vec![]),
|
(libc::SYS_stat, vec![]),
|
||||||
|
(libc::SYS_statfs, vec![]),
|
||||||
(libc::SYS_statx, vec![]),
|
(libc::SYS_statx, vec![]),
|
||||||
(libc::SYS_tgkill, vec![]),
|
(libc::SYS_tgkill, vec![]),
|
||||||
(libc::SYS_timerfd_create, vec![]),
|
(libc::SYS_timerfd_create, vec![]),
|
||||||
@@ -715,6 +717,7 @@ fn vcpu_thread_rules(
|
|||||||
(libc::SYS_madvise, vec![]),
|
(libc::SYS_madvise, vec![]),
|
||||||
(libc::SYS_mmap, vec![]),
|
(libc::SYS_mmap, vec![]),
|
||||||
(libc::SYS_mprotect, vec![]),
|
(libc::SYS_mprotect, vec![]),
|
||||||
|
(libc::SYS_mremap, vec![]),
|
||||||
(libc::SYS_munmap, vec![]),
|
(libc::SYS_munmap, vec![]),
|
||||||
(libc::SYS_nanosleep, vec![]),
|
(libc::SYS_nanosleep, vec![]),
|
||||||
(libc::SYS_newfstatat, vec![]),
|
(libc::SYS_newfstatat, vec![]),
|
||||||
|
|||||||
@@ -1258,7 +1258,7 @@ impl Vm {
|
|||||||
.resize(desired_memory)
|
.resize(desired_memory)
|
||||||
.map_err(Error::MemoryManager)?;
|
.map_err(Error::MemoryManager)?;
|
||||||
|
|
||||||
let mut memory_config = &mut self.config.lock().unwrap().memory;
|
let memory_config = &mut self.config.lock().unwrap().memory;
|
||||||
|
|
||||||
if let Some(new_region) = &new_region {
|
if let Some(new_region) = &new_region {
|
||||||
self.device_manager
|
self.device_manager
|
||||||
@@ -2004,6 +2004,18 @@ impl Vm {
|
|||||||
})
|
})
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
// Note: For x86, always call this function before invoking start boot vcpus.
|
||||||
|
// Otherwise guest would fail to boot because we haven't created the
|
||||||
|
// userspace mappings to update the hypervisor about the memory mappings.
|
||||||
|
// These mappings must be created before we start the vCPU threads for
|
||||||
|
// the very first time.
|
||||||
|
self.memory_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.allocate_address_space()
|
||||||
|
.map_err(Error::MemoryManager)?;
|
||||||
|
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
if let Some(hob_address) = hob_address {
|
if let Some(hob_address) = hob_address {
|
||||||
// With the HOB address extracted the vCPUs can have
|
// With the HOB address extracted the vCPUs can have
|
||||||
@@ -2021,18 +2033,6 @@ impl Vm {
|
|||||||
self.vm.tdx_finalize().map_err(Error::FinalizeTdx)?;
|
self.vm.tdx_finalize().map_err(Error::FinalizeTdx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
// Note: For x86, always call this function before invoking start boot vcpus.
|
|
||||||
// Otherwise guest would fail to boot because we haven't created the
|
|
||||||
// userspace mappings to update the hypervisor about the memory mappings.
|
|
||||||
// These mappings must be created before we start the vCPU threads for
|
|
||||||
// the very first time.
|
|
||||||
self.memory_manager
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.allocate_address_space()
|
|
||||||
.map_err(Error::MemoryManager)?;
|
|
||||||
|
|
||||||
self.cpu_manager
|
self.cpu_manager
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|||||||
Reference in New Issue
Block a user