(&mut self, size: usize)
| 2204 | } |
| 2205 | |
| 2206 | fn hotplug_ram_region(&mut self, size: usize) -> Result<Arc<GuestRegionMmap>, Error> { |
| 2207 | info!("Hotplugging new RAM: {size}"); |
| 2208 | |
| 2209 | // Check that there is a free slot |
| 2210 | if self.next_hotplug_slot >= HOTPLUG_COUNT { |
| 2211 | return Err(Error::NoSlotAvailable); |
| 2212 | } |
| 2213 | |
| 2214 | // "Inserted" DIMM must have a size that is a multiple of 128MiB |
| 2215 | if !size.is_multiple_of(128 << 20) { |
| 2216 | return Err(Error::InvalidSize); |
| 2217 | } |
| 2218 | |
| 2219 | let start_addr = MemoryManager::start_addr(self.guest_memory.memory().last_addr(), true)?; |
| 2220 | |
| 2221 | if start_addr |
| 2222 | .checked_add((size - 1).try_into().unwrap()) |
| 2223 | .unwrap() |
| 2224 | > self.end_of_ram_area |
| 2225 | { |
| 2226 | return Err(Error::InsufficientHotplugRam); |
| 2227 | } |
| 2228 | |
| 2229 | let region = self.add_ram_region(start_addr, size)?; |
| 2230 | |
| 2231 | // Add region to the list of regions associated with the default |
| 2232 | // memory zone. |
| 2233 | if let Some(memory_zone) = self.memory_zones.get_mut(DEFAULT_MEMORY_ZONE) { |
| 2234 | memory_zone.regions.push(Arc::clone(®ion)); |
| 2235 | } |
| 2236 | |
| 2237 | // Tell the allocator |
| 2238 | self.ram_allocator |
| 2239 | .allocate(Some(start_addr), size as GuestUsize, None) |
| 2240 | .ok_or(Error::MemoryRangeAllocation)?; |
| 2241 | |
| 2242 | // Update the slot so that it can be queried via the I/O port |
| 2243 | let slot = &mut self.hotplug_slots[self.next_hotplug_slot]; |
| 2244 | slot.active = true; |
| 2245 | slot.inserting = true; |
| 2246 | slot.base = region.start_addr().0; |
| 2247 | slot.length = region.len(); |
| 2248 | |
| 2249 | self.next_hotplug_slot += 1; |
| 2250 | |
| 2251 | Ok(region) |
| 2252 | } |
| 2253 | |
| 2254 | pub fn guest_memory(&self) -> GuestMemoryAtomic<GuestMemoryMmap> { |
| 2255 | self.guest_memory.clone() |
no test coverage detected