Merge pull request #12484 from Amulyam24/runtime-rs-ppc64le

runtime-rs: add QEMU support for ppc64le
This commit is contained in:
Steve Horsman
2026-04-01 12:54:40 +01:00
committed by GitHub
6 changed files with 153 additions and 14 deletions

View File

@@ -41,6 +41,7 @@ sysctl = "0.7.1"
tempfile = "3.19.1"
test-utils = { path = "../test-utils" }
nix = "0.26.4"
rstest = "0.18"
[features]
default = []

View File

@@ -1077,6 +1077,81 @@ impl MemoryInfo {
if self.default_maxmemory == 0 || u64::from(self.default_maxmemory) > host_memory {
self.default_maxmemory = host_memory as u32;
}
// Apply PowerPC64 memory alignment
#[cfg(all(target_arch = "powerpc64", target_endian = "little"))]
self.adjust_ppc64_memory_alignment()?;
Ok(())
}
/// Adjusts memory values for PowerPC64 little-endian systems to meet
/// QEMU's 256MB block size alignment requirement.
///
/// Ensures default_memory is at least 1024MB and both default_memory
/// and default_maxmemory are aligned to 256MB boundaries.
/// Returns an error if aligned values would be equal.
#[cfg(all(target_arch = "powerpc64", target_endian = "little"))]
fn adjust_ppc64_memory_alignment(&mut self) -> Result<()> {
const PPC64_MEM_BLOCK_SIZE: u64 = 256;
const MIN_MEMORY_MB: u64 = 1024;
fn align_memory(value: u64) -> u64 {
(value / PPC64_MEM_BLOCK_SIZE) * PPC64_MEM_BLOCK_SIZE
}
let mut mem_size = u64::from(self.default_memory);
let max_mem_size = u64::from(self.default_maxmemory);
// Ensure minimum memory size
if mem_size < MIN_MEMORY_MB {
info!(
sl!(),
"PowerPC: Increasing default_memory from {}MB to minimum {}MB",
mem_size,
MIN_MEMORY_MB
);
mem_size = MIN_MEMORY_MB;
}
// Align both values to 256MB boundaries
let aligned_mem = align_memory(mem_size);
let aligned_max_mem = align_memory(max_mem_size);
if aligned_mem != mem_size {
info!(
sl!(),
"PowerPC: Aligned default_memory from {}MB to {}MB", mem_size, aligned_mem
);
}
if aligned_max_mem != max_mem_size {
info!(
sl!(),
"PowerPC: Aligned default_maxmemory from {}MB to {}MB",
max_mem_size,
aligned_max_mem
);
}
// Check if aligned values are equal
if aligned_max_mem != 0 && aligned_max_mem <= aligned_mem {
return Err(std::io::Error::other(format!(
"PowerPC: default_maxmemory ({}MB) <= default_memory ({}MB) after alignment. \
Requires maxmemory > memory. Please increase default_maxmemory.",
aligned_max_mem, aligned_mem
)));
}
info!(
sl!(),
"PowerPC: Memory alignment applied - memory: {}MB, max_memory: {}MB",
aligned_mem,
aligned_max_mem
);
self.default_memory = aligned_mem as u32;
self.default_maxmemory = aligned_max_mem as u32;
Ok(())
}
@@ -1948,4 +2023,72 @@ mod tests {
);
}
}
#[cfg(all(target_arch = "powerpc64", target_endian = "little"))]
use rstest::rstest;
#[rstest]
#[case::memory_below_minimum(512, 2048, 1024, 2048)]
#[case::already_aligned(1024, 2048, 1024, 2048)]
#[case::unaligned_rounds_down(1100, 2100, 1024, 2048)]
#[cfg(all(target_arch = "powerpc64", target_endian = "little"))]
fn test_adjust_ppc64_memory_alignment_success(
#[case] input_memory: u32,
#[case] input_maxmemory: u32,
#[case] expected_memory: u32,
#[case] expected_maxmemory: u32,
) {
let mut mem = MemoryInfo {
default_memory: input_memory,
default_maxmemory: input_maxmemory,
..Default::default()
};
let result = mem.adjust_ppc64_memory_alignment();
assert!(
result.is_ok(),
"Expected success but got error: {:?}",
result.err()
);
assert_eq!(
mem.default_memory, expected_memory,
"Memory not aligned correctly"
);
assert_eq!(
mem.default_maxmemory, expected_maxmemory,
"Max memory not aligned correctly"
);
}
#[rstest]
#[case::equal_after_alignment(1024, 1100, "Requires maxmemory > memory")]
#[case::maxmemory_less_than_memory(2048, 1500, "Requires maxmemory > memory")]
#[cfg(all(target_arch = "powerpc64", target_endian = "little"))]
fn test_adjust_ppc64_memory_alignment_errors(
#[case] input_memory: u32,
#[case] input_maxmemory: u32,
#[case] expected_error_msg: &str,
) {
let mut mem = MemoryInfo {
default_memory: input_memory,
default_maxmemory: input_maxmemory,
..Default::default()
};
let result = mem.adjust_ppc64_memory_alignment();
assert!(
result.is_err(),
"Expected error but got success for memory={}, maxmemory={}",
input_memory,
input_maxmemory
);
let error_msg = result.unwrap_err().to_string();
assert!(
error_msg.contains(expected_error_msg),
"Error message '{}' does not contain expected text '{}'",
error_msg,
expected_error_msg
);
}
}

View File

@@ -33,15 +33,11 @@ test:
exit 0
install: install-runtime install-configs
else ifeq ($(ARCH), powerpc64le)
default:
@echo "PowerPC 64 LE is not currently supported"
exit 0
default: runtime show-header
test:
@echo "PowerPC 64 LE is not currently supported"
exit 0
install:
@echo "PowerPC 64 LE is not currently supported"
@echo "powerpc64le is not currently supported"
exit 0
install: install-runtime install-configs
else ifeq ($(ARCH), riscv64gc)
default: runtime show-header
test:

View File

@@ -7,9 +7,6 @@
MACHINETYPE := pseries
KERNELPARAMS := cgroup_no_v1=all systemd.unified_cgroup_hierarchy=1
MACHINEACCELERATORS := "cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken,cap-large-decr=off,cap-ccf-assist=off"
CPUFEATURES := pmu=off
CPUFEATURES :=
QEMUCMD := qemu-system-ppc64
# dragonball binary name
DBCMD := dragonball

View File

@@ -147,7 +147,7 @@ impl Tap {
// ioctl is safe since we call it with a valid tap fd and check the return
// value.
let ret = unsafe { ioctl_with_mut_ref(&tuntap, TUNSETIFF(), ifr) };
let ret = unsafe { ioctl_with_mut_ref(&tuntap, libc::TUNSETIFF as libc::c_ulong, ifr) };
if ret < 0 {
return Err(Error::CreateTap(IoError::last_os_error()));
}

View File

@@ -617,8 +617,10 @@ impl QemuInner {
todo!()
}
pub(crate) fn set_capabilities(&mut self, _flag: CapabilityBits) {
todo!()
pub(crate) fn set_capabilities(&mut self, flag: CapabilityBits) {
let mut caps = Capabilities::default();
caps.set(flag)
}
pub(crate) fn set_guest_memory_block_size(&mut self, size: u32) {