mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
memory_manager: Fix address range calculation in MemorySlot
The MCRS method returns a 64-bit memory range descriptor. The
calculation is supposed to be done as follows:
max = min + len - 1
However, every operand is represented not as a QWORD but as combination
of two DWORDs for high and low part. Till now, the calculation was done
this way, please see also inline comments:
max.lo = min.lo + len.lo //this may overflow, need to carry over to high
max.hi = min.hi + len.hi
max.hi = max.hi - 1 // subtraction needs to happen on the low part
This calculation has been corrected the following way:
max.lo = min.lo + len.lo
max.hi = min.hi + len.hi + (max.lo < min.lo) // check for overflow
max.lo = max.lo - 1 // subtract from low part
The relevant part from the generated ASL for the MCRS method:
```
Method (MCRS, 1, Serialized)
{
Acquire (MLCK, 0xFFFF)
\_SB.MHPC.MSEL = Arg0
Name (MR64, ResourceTemplate ()
{
QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
0x0000000000000000, // Granularity
0x0000000000000000, // Range Minimum
0xFFFFFFFFFFFFFFFE, // Range Maximum
0x0000000000000000, // Translation Offset
0xFFFFFFFFFFFFFFFF, // Length
,, _Y00, AddressRangeMemory, TypeStatic)
})
CreateQWordField (MR64, \_SB.MHPC.MCRS._Y00._MIN, MINL) // _MIN: Minimum Base Address
CreateDWordField (MR64, 0x12, MINH)
CreateQWordField (MR64, \_SB.MHPC.MCRS._Y00._MAX, MAXL) // _MAX: Maximum Base Address
CreateDWordField (MR64, 0x1A, MAXH)
CreateQWordField (MR64, \_SB.MHPC.MCRS._Y00._LEN, LENL) // _LEN: Length
CreateDWordField (MR64, 0x2A, LENH)
MINL = \_SB.MHPC.MHBL
MINH = \_SB.MHPC.MHBH
LENL = \_SB.MHPC.MHLL
LENH = \_SB.MHPC.MHLH
MAXL = (MINL + LENL) /* \_SB_.MHPC.MCRS.LENL */
MAXH = (MINH + LENH) /* \_SB_.MHPC.MCRS.LENH */
If ((MAXL < MINL))
{
MAXH += One /* \_SB_.MHPC.MCRS.MAXH */
}
MAXL -= One
Release (MLCK)
Return (MR64) /* \_SB_.MHPC.MCRS.MR64 */
}
```
Fixes #1800.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
committed by
Samuel Ortiz
parent
37e2784299
commit
e1cc702327
@@ -5574,6 +5574,20 @@ mod tests {
|
||||
.unwrap_or(0);
|
||||
}
|
||||
|
||||
fn get_ram_size_windows(auth: &PasswordAuth) -> usize {
|
||||
return ssh_command_ip_with_auth(
|
||||
"powershell -Command \"(Get-CimInstance win32_computersystem).TotalPhysicalMemory\"",
|
||||
&auth,
|
||||
"192.168.249.2",
|
||||
DEFAULT_SSH_RETRIES,
|
||||
DEFAULT_SSH_TIMEOUT,
|
||||
)
|
||||
.unwrap()
|
||||
.trim()
|
||||
.parse::<usize>()
|
||||
.unwrap_or(0);
|
||||
}
|
||||
|
||||
fn get_vcpu_threads_count(pid: u32) -> u8 {
|
||||
// ps -T -p 12345 | grep vcpu | wc -l
|
||||
let out = Command::new("ps")
|
||||
@@ -5821,6 +5835,96 @@ mod tests {
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_windows_guest_ram_hotplug() {
|
||||
let mut windows = WindowsDiskConfig::new(WINDOWS_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(&mut windows);
|
||||
|
||||
let tmp_dir = TempDir::new_with_prefix("/tmp/ch").unwrap();
|
||||
let mut workload_path = dirs::home_dir().unwrap();
|
||||
workload_path.push("workloads");
|
||||
|
||||
let mut ovmf_path = workload_path.clone();
|
||||
ovmf_path.push(OVMF_NAME);
|
||||
|
||||
let mut osdisk_path = workload_path;
|
||||
osdisk_path.push(WINDOWS_IMAGE_NAME.to_string());
|
||||
|
||||
let api_socket = temp_api_path(&tmp_dir);
|
||||
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(&["--api-socket", &api_socket])
|
||||
.args(&["--cpus", "boot=2,kvm_hyperv=on"])
|
||||
.args(&["--memory", "size=2G,hotplug_size=5G"])
|
||||
.args(&["--kernel", ovmf_path.to_str().unwrap()])
|
||||
.default_disks()
|
||||
.args(&["--serial", "tty"])
|
||||
.args(&["--console", "off"])
|
||||
.args(&["--net", "tap="])
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
// Wait to make sure Windows boots up
|
||||
thread::sleep(std::time::Duration::new(60, 0));
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
let auth = windows_auth();
|
||||
|
||||
let ram_size = 2 * 1024 * 1024 * 1024;
|
||||
// Check the initial number of RAM the guest sees
|
||||
let current_ram_size = get_ram_size_windows(&auth);
|
||||
// This size seems to be reserved by the system and thus the
|
||||
// reported amount differs by this constant value.
|
||||
let reserved_ram_size = ram_size - current_ram_size;
|
||||
// Verify that there's not more than 4mb constant diff wasted
|
||||
// by the reserved ram.
|
||||
assert!(reserved_ram_size < 4 * 1024 * 1024);
|
||||
|
||||
let ram_size = 4 * 1024 * 1024 * 1024;
|
||||
// Hotplug some RAM
|
||||
resize_command(&api_socket, None, Some(ram_size), None);
|
||||
// Wait to make sure RAM has been added
|
||||
thread::sleep(std::time::Duration::new(10, 0));
|
||||
// Check the guest sees the correct number
|
||||
assert_eq!(get_ram_size_windows(&auth), ram_size - reserved_ram_size);
|
||||
|
||||
let ram_size = 3 * 1024 * 1024 * 1024;
|
||||
// Unplug some RAM. Note that hot-remove most likely won't work.
|
||||
resize_command(&api_socket, None, Some(ram_size), None);
|
||||
// Wait to make sure RAM has been added
|
||||
thread::sleep(std::time::Duration::new(10, 0));
|
||||
// Reboot to let Windows catch up
|
||||
ssh_command_ip_with_auth(
|
||||
"shutdown /r /t 0",
|
||||
&auth,
|
||||
"192.168.249.2",
|
||||
DEFAULT_SSH_RETRIES,
|
||||
DEFAULT_SSH_TIMEOUT,
|
||||
)
|
||||
.unwrap();
|
||||
// Wait to make sure guest completely rebooted
|
||||
thread::sleep(std::time::Duration::new(60, 0));
|
||||
// Check the guest sees the correct number
|
||||
assert_eq!(get_ram_size_windows(&auth), ram_size - reserved_ram_size);
|
||||
|
||||
ssh_command_ip_with_auth(
|
||||
"shutdown /s",
|
||||
&auth,
|
||||
"192.168.249.2",
|
||||
DEFAULT_SSH_RETRIES,
|
||||
DEFAULT_SSH_TIMEOUT,
|
||||
)
|
||||
.unwrap();
|
||||
});
|
||||
|
||||
let _ = child.wait_timeout(std::time::Duration::from_secs(60));
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
|
||||
Reference in New Issue
Block a user