Signed-off-by: Ying Fang fangying1@huawei.com --- device_model/src/legacy/fw_cfg.rs | 238 +++++++++++++++++------------- device_model/src/legacy/mod.rs | 2 - device_model/src/micro_vm/mod.rs | 2 +- 3 files changed, 137 insertions(+), 105 deletions(-)
diff --git a/device_model/src/legacy/fw_cfg.rs b/device_model/src/legacy/fw_cfg.rs index 7422d4b..09396cc 100644 --- a/device_model/src/legacy/fw_cfg.rs +++ b/device_model/src/legacy/fw_cfg.rs @@ -10,18 +10,18 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details.
-use super::super::mmio::errors::{Result}; +use super::super::mmio::errors::Result; use super::super::mmio::{DeviceResource, DeviceType, MmioDeviceOps}; use super::super::DeviceOps; use address_space::{AddressSpace, GuestAddress}; -use byteorder::{ByteOrder, BigEndian, LittleEndian}; -use serde::{Deserialize, Serialize}; +use byteorder::{BigEndian, ByteOrder, LittleEndian}; use kvm_ioctls::VmFd; -use std::default::Default; use std::cmp::Ordering; -use std::sync::{Arc}; +use std::default::Default; +use std::sync::Arc; use util::byte_code::ByteCode;
+/// FWCfg ACPI Device ID const FW_CFG_ACPI_DEVICE_ID: &str = "QEMU0002"; /// QEMU CFG Signature const FW_CFG_DMA_SIGNATURE: u128 = 0x51454d5520434647; @@ -32,30 +32,30 @@ const FW_CFG_VERSION_DMA: u32 = 0x02; const FW_CFG_FILE_SLOTS_DFLT: u32 = 0x20;
enum FWCfgEntryType { - FW_CFG_SIGNATURE = 0x00, - FW_CFG_ID, - FW_CFG_UUID, - FW_CFG_RAM_SIZE, - FW_CFG_NOGRAPHIC, - FW_CFG_NB_CPUS, - FW_CFG_MACHINE_ID, - FW_CFG_KERNEL_ADDR, - FW_CFG_KERNEL_SIZE, - FW_CFG_KERNEL_CMDLINE, - FW_CFG_INITRD_ADDR, - FW_CFG_INITRD_SIZE, - FW_CFG_BOOT_DEVICE, - FW_CFG_NUMA, - FW_CFG_BOOT_MENU, - FW_CFG_MAX_CPUS, - FW_CFG_KERNEL_ENTRY, - FW_CFG_KERNEL_DATA, - FW_CFG_INITRD_DATA, - FW_CFG_CMDLINE_ADDR, - FW_CFG_CMDLINE_SIZE, - FW_CFG_SETUP_ADDR, - FW_CFG_SETUP_SIZE, - FW_CFG_FILE_DIR, + FWCfgSignature = 0x00, + FWCfgId, + FWCfgUUID, + FWCfgRamSize, + FWCfgNoGraphic, + FWCfgNbCpus, + FWCfgMachineId, + FWCfgKernelAddr, + FWCfgKernelSize, + FWCfgKernelCmdline, + FWCfgInitrdAddr, + FWCfgInitrdSize, + FWCfgBootDevice, + FWCfgNuma, + FWCfgBootMenu, + FWCfgMaxCpus, + FWCfgKernelEntry, + FWCfgKernelData, + FWCfgInitrdData, + FWCfgCmdlineAddr, + FWCfgCmdlineSize, + FWCfgSetupAddr, + FWCfgSetupSize, + FWCfgFileDir, }
const FW_CFG_FILE_FIRST: u16 = 0x20; @@ -72,9 +72,10 @@ const FW_CFG_SIG_SIZE: u32 = 4; type FWCfgCallbackType = Box<dyn FWCfgCallback + Send + Sync>; type FWCfgWriteCallbackType = Box<dyn FWCfgWriteCallback + Send + Sync>;
+#[derive(Default)] pub struct FWCfgEntry { data: Vec<u8>, - pub select_cb: Option<FWCfgCallbackType>, + select_cb: Option<FWCfgCallbackType>, write_cb: Option<FWCfgWriteCallbackType>, allow_write: bool, } @@ -229,13 +230,13 @@ pub fn dma_result_write( }
fn extract64(value: u64, start: i32, length: i32) -> u64 { - assert!(start >= 0 && length > 0 && length < 64 - start); + assert!(start >= 0 && length > 0 && length <= 64 - start);
(value >> start as u64) & (!(0 as u64) >> (64 - length) as u64) }
fn get_key_name(key: usize) -> &'static str { - static fw_cfg_keys: [&str; 25] = [ + static FW_CFG_KEYS: [&str; 25] = [ "signature", "id", "uuid", @@ -262,7 +263,7 @@ fn get_key_name(key: usize) -> &'static str { "setup_data", "file_dir", ]; - return fw_cfg_keys[key]; + return FW_CFG_KEYS[key]; }
pub struct FWCfgCommon { @@ -303,6 +304,7 @@ impl FWCfgCommon { fn fw_cfg_write(&self, _value: u8) {}
pub fn fw_cfg_get_entry(&mut self) -> Option<&mut FWCfgEntry> { + info!("fw_cfg_get_entry"); let is_local = (self.cur_entry & FW_CFG_ARCH_LOCAL as u16) > 0;
let mut entry = None; @@ -321,6 +323,7 @@ impl FWCfgCommon { }
pub fn fw_cfg_select(&mut self, key: u16) -> i32 { + info!("fw_cfg_select"); let mut ret = 0;
self.cur_offset = 0; @@ -336,11 +339,12 @@ impl FWCfgCommon { entry.select_cb.as_mut().unwrap().select_callback(); }
- debug!("fw_cfg_select key {} ret {}", key, ret); + info!("fw_cfg_select key {} ret {}", key, ret); ret }
fn fw_cfg_dma_transfer(&mut self) { + info!("fw_cfg_dma_transfer"); let dma_addr = self.dma_addr; let mem_space = self.mem_space.clone(); let mut cur_offset = self.cur_offset; @@ -356,6 +360,7 @@ impl FWCfgCommon { let size = std::mem::size_of::<FWCfgDmaAccess>() as u64; if let Err(_) = dma_memory_read(&self.mem_space, dma_addr, dma_buf, size) { dma_result_write(&self.mem_space, dma_addr, FW_CFG_DMA_CTL_ERROR); + return; }
// Build FWCfgDmaAccess object here @@ -385,7 +390,7 @@ impl FWCfgCommon {
while dma.length > 0 && (dma.control & FW_CFG_DMA_CTL_ERROR) != 0 { if cur_entry == FW_CFG_INVALID - || !entry.data.is_empty() + || entry.data.is_empty() || cur_offset >= entry.data.len() as u32 { len = dma.length; @@ -422,7 +427,7 @@ impl FWCfgCommon { let mut dma_read_error = false; let data = &mut entry.data[cur_offset as usize..]; if let Err(_) = - dma_memory_read(&mem_space, GuestAddress(dma.address), data, len as u64) + dma_memory_read(&mem_space, GuestAddress(dma.address), data, len as u64) { dma_read_error = true; } @@ -440,35 +445,46 @@ impl FWCfgCommon { dma.address += len as u64 } dma_result_write(&self.mem_space, dma_addr, dma.control); - debug!("fw_cfg dma tranfer"); + info!("fw_cfg dma tranfer"); }
pub fn fw_cfg_add_entry( &mut self, - key: u16, + mut key: u16, select_cb: Option<FWCfgCallbackType>, write_cb: Option<FWCfgWriteCallbackType>, data: Vec<u8>, allow_write: bool, ) { + info!("fw_cfg_add_entry {}", get_key_name(key as usize)); let is_local = key & FW_CFG_ARCH_LOCAL > 0;
assert!(key < self.fw_cfg_max_entry() && data.len() < std::u32::MAX as usize);
+ key &= FW_CFG_ENTRY_MASK; + let mut entry; if is_local { - entry = &mut self.local_entries[key as usize]; + entry = self.local_entries.get_mut(key as usize); } else { - entry = &mut self.entries[key as usize]; + entry = self.entries.get_mut(key as usize); }
- entry.data = data; - entry.select_cb = select_cb; - entry.write_cb = write_cb; - entry.allow_write = allow_write; + if let Some(ref mut e) = entry { + e.data = data; + e.select_cb = select_cb; + e.write_cb = write_cb; + e.allow_write = allow_write; + } else { + // *e = FWCfgEntry::new(data, select_cb, write_cb, allow_write); + } }
pub fn fw_cfg_update_entry_data(&mut self, key: u16, data: Vec<u8>) { + info!( + "fw_cfg_update_entry_data key {}", + get_key_name(key as usize) + ); let is_local = key & FW_CFG_ARCH_LOCAL > 0;
assert!(key < self.fw_cfg_max_entry() && data.len() < std::u32::MAX as usize); @@ -485,21 +501,25 @@ impl FWCfgCommon { }
pub fn fw_cfg_add_entry_data(&mut self, key: u16, data: Vec<u8>) { - debug!("fw_cfg_add_data key {} ", get_key_name(key as usize)); + info!("fw_cfg_add_data key {} ", get_key_name(key as usize));
- self.fw_cfg_add_entry(key, None, None, data, true); + self.fw_cfg_add_entry(key, None, None, data, false); }
pub fn fw_cfg_entry_add_string(&mut self, key: u16, value: &str) { - self.fw_cfg_update_entry_data(key, value.as_bytes().to_vec()); + info!("fw_cfg_entry_add_string {}", value); + self.fw_cfg_add_entry_data(key, value.as_bytes().to_vec()); }
- pub fn fw_cfg_add_file_callback(&mut self, - filename: &str, - data: Vec<u8>, - select_cb: Option<FWCfgCallbackType>, - write_cb: Option<FWCfgWriteCallbackType>, - allow_write: bool) -> Result<()> { + pub fn fw_cfg_add_file_callback( + &mut self, + filename: &str, + data: Vec<u8>, + select_cb: Option<FWCfgCallbackType>, + write_cb: Option<FWCfgWriteCallbackType>, + allow_write: bool, + ) -> Result<()> { + info!("fw_cfg_add_file_callback filename {}", filename); let len = self.files.len(); assert!(len < self.file_slots as usize); let mut index = len; @@ -521,10 +541,14 @@ impl FWCfgCommon { }
let entry = FWCfgEntry::new(data, select_cb, write_cb, allow_write); - self.local_entries.insert(index + FW_CFG_FILE_FIRST as usize, entry); - let file = FWCfgFile::new(BigEndian::read_u32((len as u32).as_bytes()), - BigEndian::read_u16(((index + FW_CFG_FILE_FIRST as usize) as u16).as_bytes()), - 0, filename.to_string()); + self.local_entries + .insert(index + FW_CFG_FILE_FIRST as usize, entry); + let file = FWCfgFile::new( + BigEndian::read_u32((len as u32).as_bytes()), + BigEndian::read_u16(((index + FW_CFG_FILE_FIRST as usize) as u16).as_bytes()), + 0, + filename.to_string(), + ); self.files.push(file); self.files.sort(); Ok(()) @@ -534,36 +558,41 @@ impl FWCfgCommon { self.fw_cfg_add_file_callback(filename, data, None, None, false); }
- pub fn fw_cfg_dma_mem_write(&mut self, addr: GuestAddress, value: u64, size: u32) { + pub fn fw_cfg_dma_mem_write(&mut self, addr: u64, value: u64, size: u32) { + info!( + "fw_cfg_dma_mem_write addr 0x{:x} value 0x{:x} size 0x{:x}", + addr, value, size + ); if size == 4 { - if addr == GuestAddress(0) { + if addr == 0 { self.dma_addr = GuestAddress(value << 32); - } else if addr == GuestAddress(4) { - self.dma_addr = GuestAddress(self.dma_addr.raw_value() | size as u64); + } else if addr == 4 { + self.dma_addr = GuestAddress(self.dma_addr.raw_value() | value as u64); self.fw_cfg_dma_transfer(); } - } else if size == 8 && addr == GuestAddress(0) { + } else if size == 8 && addr == 0 { self.dma_addr = GuestAddress(value); self.fw_cfg_dma_transfer(); } }
- pub fn fw_cfg_dma_mem_read(&self, addr: GuestAddress, size: u32) -> u64 { + pub fn fw_cfg_dma_mem_read(&self, addr: u64, size: u32) -> u64 { + info!("fw_cfg_dma_mem_read addr 0x{:x} size 0x{:x}", addr, size); extract64( FW_CFG_DMA_SIGNATURE as u64, - ((8 - addr.raw_value() - size as u64) * 8) as i32, + ((8 - addr - size as u64) * 8) as i32, (size * 8) as i32, ) }
- pub fn fw_cfg_data_read(&mut self, addr: GuestAddress, mut size: u32) -> u64 { + pub fn fw_cfg_data_read(&mut self, addr: u64, mut size: u32) -> u64 { let mut value: u64 = 0; let cur_entry = self.cur_entry; let cur_offset = self.cur_offset;
let entry = self.fw_cfg_get_entry().unwrap(); - let SIZE_U64 = std::mem::size_of::<u64>() as u32; - assert!(size > 0 && size < SIZE_U64); + let size_u64 = std::mem::size_of::<u64>() as u32; + assert!(size > 0 && size < size_u64); if cur_entry != FW_CFG_INVALID && !entry.data.is_empty() && cur_offset < entry.data.len() as u32 @@ -574,65 +603,54 @@ impl FWCfgCommon { offset += 1; size -= 1;
- if size < 0 || offset >= entry.data.len() as u32 { + if size <= 0 || offset >= entry.data.len() as u32 { break; } } value = 8 * size as u64; }
- debug!( + info!( "fw_cfg_data_read 0x{:x} size {} value 0x{:x}", - addr.raw_value(), - size, - value + addr, size, value ); value }
pub fn fw_cfg_common_realize(&mut self) { - self.local_entries = Vec::with_capacity(self.fw_cfg_max_entry() as usize); - self.entries = Vec::with_capacity(self.fw_cfg_max_entry() as usize);
self.fw_cfg_add_entry_data( - FWCfgEntryType::FW_CFG_SIGNATURE as u16, + FWCfgEntryType::FWCfgSignature as u16, "QEMU".as_bytes().to_vec(), );
// TODO add real uuid here self.fw_cfg_add_entry_data( - FWCfgEntryType::FW_CFG_UUID as u16, + FWCfgEntryType::FWCfgUUID as u16, "49c9bedd6459b52a".as_bytes().to_vec(), );
self.fw_cfg_add_entry_data( - FWCfgEntryType::FW_CFG_NOGRAPHIC as u16, + FWCfgEntryType::FWCfgNoGraphic as u16, (0 as u16).as_bytes().to_vec(), );
self.fw_cfg_add_entry_data( - FWCfgEntryType::FW_CFG_BOOT_MENU as u16, + FWCfgEntryType::FWCfgBootMenu as u16, (0 as u16).as_bytes().to_vec(), );
let version = FW_CFG_VERSION & FW_CFG_VERSION_DMA; - self.fw_cfg_add_entry_data( - FWCfgEntryType::FW_CFG_ID as u16, - version.as_bytes().to_vec(), - ); + self.fw_cfg_add_entry_data(FWCfgEntryType::FWCfgId as u16, version.as_bytes().to_vec()); } }
-#[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub struct FWCfgConfig {} - /// Emulate FWCfg MMIO Device pub struct FWCfgMem { fwcfg: FWCfgCommon, data_width: u32, }
- impl FWCfgMem { pub fn new(sys_mem: Arc<AddressSpace>) -> Self { FWCfgMem { @@ -641,7 +659,11 @@ impl FWCfgMem { } }
- pub fn fw_cfg_data_mem_write(&self, _addr: GuestAddress, value: u64, size: u32) { + pub fn fw_cfg_data_mem_write(&self, _addr: u64, value: u64, size: u32) { + info!( + "fw_cfg_data_mem_write addr 0x{:x} value 0x{:x} size 0x{:x}", + _addr, value, size + ); let mut i = size; loop { i -= 1; @@ -652,27 +674,35 @@ impl FWCfgMem { } }
- pub fn fw_cfg_ctl_mem_read(&self, _addr: GuestAddress, _size: u32) -> u64 { + pub fn fw_cfg_ctl_mem_read(&self, addr: u64, _size: u32) -> u64 { 0 }
- pub fn fw_cfg_ctl_mem_write(&mut self, _addr: GuestAddress, value: u64, _size: u32) { + pub fn fw_cfg_ctl_mem_write(&mut self, addr: u64, value: u64, _size: u32) { self.fwcfg.fw_cfg_select(value as u16); } }
impl DeviceOps for FWCfgMem { fn read(&mut self, data: &mut [u8], base: GuestAddress, offset: u64) -> bool { + info!( + "FWCfgMem read offset 0x{:x} size 0x{:x}", + offset, + data.len() + ); let mut value = 0; match offset { 0..=7 => { - value = self.fwcfg.fw_cfg_data_read(base, data.len() as u32); + value = self.fwcfg.fw_cfg_data_read(offset, data.len() as u32); } 8..=15 => { - value = self.fw_cfg_ctl_mem_read(base, data.len() as u32); + value = self.fw_cfg_ctl_mem_read(offset, data.len() as u32); + } + 16..=23 => { + self.fwcfg.fw_cfg_dma_mem_read(offset, data.len() as u32); } _ => { - self.fwcfg.fw_cfg_dma_mem_read(base, data.len() as u32); + error!("write overflow"); } }
@@ -681,18 +711,22 @@ impl DeviceOps for FWCfgMem { }
fn write(&mut self, data: &[u8], base: GuestAddress, offset: u64) -> bool { - let mut value = 0; let size = data.len() as u32; - value = BigEndian::read_u64(data); + let mut value = match size { + 2 => BigEndian::read_u16(data) as u64, + 4 => BigEndian::read_u32(data) as u64, + _ => 0, + }; + info!("FWCfgMem write value 0x{:x} size 0x{:x}", value, size); match offset { 0..=7 => { - self.fw_cfg_data_mem_write(base, value, size); + self.fw_cfg_data_mem_write(offset, value, size); } 8..=15 => { - self.fw_cfg_ctl_mem_write(base, value, size); + self.fw_cfg_ctl_mem_write(offset, value, size); } _ => { - self.fwcfg.fw_cfg_dma_mem_write(base, value, size); + self.fwcfg.fw_cfg_dma_mem_write(offset, value, size); } } true @@ -734,7 +768,7 @@ impl FWCfgIO { } }
- pub fn fw_cfg_comb_write(&mut self, _addr: GuestAddress, value: u64, size: u32) { + pub fn fw_cfg_comb_write(&mut self, _addr: u64, value: u64, size: u32) { match size { 1 => { self.fwcfg.fw_cfg_write(value as u8); @@ -752,10 +786,10 @@ impl DeviceOps for FWCfgIO { let mut value = 0; match offset { 1..=2 => { - value = self.fwcfg.fw_cfg_data_read(base, data.len() as u32); + value = self.fwcfg.fw_cfg_data_read(offset, data.len() as u32); } 15..=23 => { - value = self.fwcfg.fw_cfg_dma_mem_read(base, data.len() as u32); + value = self.fwcfg.fw_cfg_dma_mem_read(offset, data.len() as u32); } _ => error!("invalid read of set in FWCfgIO"), } @@ -769,10 +803,10 @@ impl DeviceOps for FWCfgIO { value = LittleEndian::read_u64(data); match offset { 1..=2 => { - self.fw_cfg_comb_write(base, value, size); + self.fw_cfg_comb_write(offset, value, size); } 15..=23 => { - self.fwcfg.fw_cfg_dma_mem_write(base, value, size); + self.fwcfg.fw_cfg_dma_mem_write(offset, value, size); } _ => {} } diff --git a/device_model/src/legacy/mod.rs b/device_model/src/legacy/mod.rs index 0df5ae3..0cb4ccd 100644 --- a/device_model/src/legacy/mod.rs +++ b/device_model/src/legacy/mod.rs @@ -39,8 +39,6 @@ mod fw_cfg;
#[cfg(target_arch = "aarch64")] pub use self::fw_cfg::FWCfgMem; -#[cfg(target_arch = "aarch64")] -pub use self::fw_cfg::FWCfgConfig;
mod pl011; #[cfg(target_arch = "aarch64")] diff --git a/device_model/src/micro_vm/mod.rs b/device_model/src/micro_vm/mod.rs index 4905513..19cebdc 100644 --- a/device_model/src/micro_vm/mod.rs +++ b/device_model/src/micro_vm/mod.rs @@ -470,7 +470,7 @@ impl LightMachine { pml4_start: layout.boot_pml4_addr, };
- for cpu_index in 0..self.cpu_topo.max_cpus { + for cpu_index in 0. .self.cpu_topo.max_cpus { self.cpus.lock().unwrap()[cpu_index as usize].realize(&boot_config)?; }