mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-22 13:45:20 +00:00
pci: Introduce and use PciBar struct
This simplies some of the handling for PCI BARs particularly with respect to snapshot and restore. No attempt has been made to handle the 64-bit bar handling in a different manner to that which was used before. Fixes: #1153 Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
parent
cbb1f4cc2d
commit
dc55e45977
@ -277,14 +277,19 @@ fn decode_64_bits_bar_size(bar_size_hi: u32, bar_size_lo: u32) -> Option<u64> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Default, Clone, Copy)]
|
||||||
|
struct PciBar {
|
||||||
|
addr: u32,
|
||||||
|
size: u32,
|
||||||
|
used: bool,
|
||||||
|
r#type: Option<PciBarRegionType>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct PciConfigurationState {
|
struct PciConfigurationState {
|
||||||
registers: Vec<u32>,
|
registers: Vec<u32>,
|
||||||
writable_bits: Vec<u32>,
|
writable_bits: Vec<u32>,
|
||||||
bar_addr: Vec<u32>,
|
bars: Vec<PciBar>,
|
||||||
bar_size: Vec<u32>,
|
|
||||||
bar_used: Vec<bool>,
|
|
||||||
bar_type: Vec<Option<PciBarRegionType>>,
|
|
||||||
rom_bar_addr: u32,
|
rom_bar_addr: u32,
|
||||||
rom_bar_size: u32,
|
rom_bar_size: u32,
|
||||||
rom_bar_used: bool,
|
rom_bar_used: bool,
|
||||||
@ -298,10 +303,7 @@ struct PciConfigurationState {
|
|||||||
pub struct PciConfiguration {
|
pub struct PciConfiguration {
|
||||||
registers: [u32; NUM_CONFIGURATION_REGISTERS],
|
registers: [u32; NUM_CONFIGURATION_REGISTERS],
|
||||||
writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register.
|
writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register.
|
||||||
bar_addr: [u32; NUM_BAR_REGS],
|
bars: [PciBar; NUM_BAR_REGS],
|
||||||
bar_size: [u32; NUM_BAR_REGS],
|
|
||||||
bar_used: [bool; NUM_BAR_REGS],
|
|
||||||
bar_type: [Option<PciBarRegionType>; NUM_BAR_REGS],
|
|
||||||
rom_bar_addr: u32,
|
rom_bar_addr: u32,
|
||||||
rom_bar_size: u32,
|
rom_bar_size: u32,
|
||||||
rom_bar_used: bool,
|
rom_bar_used: bool,
|
||||||
@ -404,8 +406,6 @@ impl PciConfiguration {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
|
let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
|
||||||
let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
|
let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
|
||||||
let bar_addr = [0u32; NUM_BAR_REGS];
|
|
||||||
let bar_size = [0u32; NUM_BAR_REGS];
|
|
||||||
registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id);
|
registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id);
|
||||||
// TODO(dverkamp): Status should be write-1-to-clear
|
// TODO(dverkamp): Status should be write-1-to-clear
|
||||||
writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w)
|
writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w)
|
||||||
@ -432,13 +432,12 @@ impl PciConfiguration {
|
|||||||
};
|
};
|
||||||
registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id);
|
registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id);
|
||||||
|
|
||||||
|
let bars = [PciBar::default(); NUM_BAR_REGS];
|
||||||
|
|
||||||
PciConfiguration {
|
PciConfiguration {
|
||||||
registers,
|
registers,
|
||||||
writable_bits,
|
writable_bits,
|
||||||
bar_addr,
|
bars,
|
||||||
bar_size,
|
|
||||||
bar_used: [false; NUM_BAR_REGS],
|
|
||||||
bar_type: [None; NUM_BAR_REGS],
|
|
||||||
rom_bar_addr: 0,
|
rom_bar_addr: 0,
|
||||||
rom_bar_size: 0,
|
rom_bar_size: 0,
|
||||||
rom_bar_used: false,
|
rom_bar_used: false,
|
||||||
@ -452,10 +451,7 @@ impl PciConfiguration {
|
|||||||
PciConfigurationState {
|
PciConfigurationState {
|
||||||
registers: self.registers.to_vec(),
|
registers: self.registers.to_vec(),
|
||||||
writable_bits: self.writable_bits.to_vec(),
|
writable_bits: self.writable_bits.to_vec(),
|
||||||
bar_addr: self.bar_addr.to_vec(),
|
bars: self.bars.to_vec(),
|
||||||
bar_size: self.bar_size.to_vec(),
|
|
||||||
bar_used: self.bar_used.to_vec(),
|
|
||||||
bar_type: self.bar_type.to_vec(),
|
|
||||||
rom_bar_addr: self.rom_bar_addr,
|
rom_bar_addr: self.rom_bar_addr,
|
||||||
rom_bar_size: self.rom_bar_size,
|
rom_bar_size: self.rom_bar_size,
|
||||||
rom_bar_used: self.rom_bar_used,
|
rom_bar_used: self.rom_bar_used,
|
||||||
@ -468,10 +464,7 @@ impl PciConfiguration {
|
|||||||
self.registers.clone_from_slice(state.registers.as_slice());
|
self.registers.clone_from_slice(state.registers.as_slice());
|
||||||
self.writable_bits
|
self.writable_bits
|
||||||
.clone_from_slice(state.writable_bits.as_slice());
|
.clone_from_slice(state.writable_bits.as_slice());
|
||||||
self.bar_addr.clone_from_slice(state.bar_addr.as_slice());
|
self.bars.clone_from_slice(state.bars.as_slice());
|
||||||
self.bar_size.clone_from_slice(state.bar_size.as_slice());
|
|
||||||
self.bar_used.clone_from_slice(state.bar_used.as_slice());
|
|
||||||
self.bar_type.clone_from_slice(state.bar_type.as_slice());
|
|
||||||
self.rom_bar_addr = state.rom_bar_addr;
|
self.rom_bar_addr = state.rom_bar_addr;
|
||||||
self.rom_bar_size = state.rom_bar_size;
|
self.rom_bar_size = state.rom_bar_size;
|
||||||
self.rom_bar_used = state.rom_bar_used;
|
self.rom_bar_used = state.rom_bar_used;
|
||||||
@ -492,7 +485,7 @@ impl PciConfiguration {
|
|||||||
// Handle very specific case where the BAR is being written with
|
// Handle very specific case where the BAR is being written with
|
||||||
// all 1's to retrieve the BAR size during next BAR reading.
|
// all 1's to retrieve the BAR size during next BAR reading.
|
||||||
if value == 0xffff_ffff {
|
if value == 0xffff_ffff {
|
||||||
mask &= self.bar_size[reg_idx - 4];
|
mask &= self.bars[reg_idx - 4].size;
|
||||||
}
|
}
|
||||||
} else if reg_idx == ROM_BAR_REG {
|
} else if reg_idx == ROM_BAR_REG {
|
||||||
// Handle very specific case where the BAR is being written with
|
// Handle very specific case where the BAR is being written with
|
||||||
@ -561,7 +554,7 @@ impl PciConfiguration {
|
|||||||
/// (i.e, region size must be power of two, register not already used). Returns 'None' on
|
/// (i.e, region size must be power of two, register not already used). Returns 'None' on
|
||||||
/// failure all, `Some(BarIndex)` on success.
|
/// failure all, `Some(BarIndex)` on success.
|
||||||
pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Result<usize> {
|
pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Result<usize> {
|
||||||
if self.bar_used[config.reg_idx] {
|
if self.bars[config.reg_idx].used {
|
||||||
return Err(Error::BarInUse(config.reg_idx));
|
return Err(Error::BarInUse(config.reg_idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -586,7 +579,7 @@ impl PciConfiguration {
|
|||||||
|
|
||||||
// Encode the BAR size as expected by the software running in
|
// Encode the BAR size as expected by the software running in
|
||||||
// the guest.
|
// the guest.
|
||||||
self.bar_size[config.reg_idx] =
|
self.bars[config.reg_idx].size =
|
||||||
encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
|
encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
|
||||||
}
|
}
|
||||||
PciBarRegionType::Memory64BitRegion => {
|
PciBarRegionType::Memory64BitRegion => {
|
||||||
@ -598,7 +591,7 @@ impl PciConfiguration {
|
|||||||
return Err(Error::BarAddressInvalid(config.addr, config.size));
|
return Err(Error::BarAddressInvalid(config.addr, config.size));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.bar_used[config.reg_idx + 1] {
|
if self.bars[config.reg_idx + 1].used {
|
||||||
return Err(Error::BarInUse64(config.reg_idx));
|
return Err(Error::BarInUse64(config.reg_idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -609,10 +602,10 @@ impl PciConfiguration {
|
|||||||
|
|
||||||
self.registers[bar_idx + 1] = (config.addr >> 32) as u32;
|
self.registers[bar_idx + 1] = (config.addr >> 32) as u32;
|
||||||
self.writable_bits[bar_idx + 1] = 0xffff_ffff;
|
self.writable_bits[bar_idx + 1] = 0xffff_ffff;
|
||||||
self.bar_addr[config.reg_idx + 1] = self.registers[bar_idx + 1];
|
self.bars[config.reg_idx + 1].addr = self.registers[bar_idx + 1];
|
||||||
self.bar_size[config.reg_idx] = bar_size_lo;
|
self.bars[config.reg_idx].size = bar_size_lo;
|
||||||
self.bar_size[config.reg_idx + 1] = bar_size_hi;
|
self.bars[config.reg_idx + 1].size = bar_size_hi;
|
||||||
self.bar_used[config.reg_idx + 1] = true;
|
self.bars[config.reg_idx + 1].used = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -626,9 +619,9 @@ impl PciConfiguration {
|
|||||||
|
|
||||||
self.registers[bar_idx] = ((config.addr as u32) & mask) | lower_bits;
|
self.registers[bar_idx] = ((config.addr as u32) & mask) | lower_bits;
|
||||||
self.writable_bits[bar_idx] = mask;
|
self.writable_bits[bar_idx] = mask;
|
||||||
self.bar_addr[config.reg_idx] = self.registers[bar_idx];
|
self.bars[config.reg_idx].addr = self.registers[bar_idx];
|
||||||
self.bar_used[config.reg_idx] = true;
|
self.bars[config.reg_idx].used = true;
|
||||||
self.bar_type[config.reg_idx] = Some(config.region_type);
|
self.bars[config.reg_idx].r#type = Some(config.region_type);
|
||||||
Ok(config.reg_idx)
|
Ok(config.reg_idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -668,11 +661,11 @@ impl PciConfiguration {
|
|||||||
pub fn get_bar_addr(&self, bar_num: usize) -> u64 {
|
pub fn get_bar_addr(&self, bar_num: usize) -> u64 {
|
||||||
let bar_idx = BAR0_REG + bar_num;
|
let bar_idx = BAR0_REG + bar_num;
|
||||||
|
|
||||||
let mut addr = u64::from(self.bar_addr[bar_num] & self.writable_bits[bar_idx]);
|
let mut addr = u64::from(self.bars[bar_num].addr & self.writable_bits[bar_idx]);
|
||||||
|
|
||||||
if let Some(bar_type) = self.bar_type[bar_num] {
|
if let Some(bar_type) = self.bars[bar_num].r#type {
|
||||||
if bar_type == PciBarRegionType::Memory64BitRegion {
|
if bar_type == PciBarRegionType::Memory64BitRegion {
|
||||||
addr |= u64::from(self.bar_addr[bar_num + 1]) << 32;
|
addr |= u64::from(self.bars[bar_num + 1].addr) << 32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -777,11 +770,11 @@ impl PciConfiguration {
|
|||||||
let mask = self.writable_bits[reg_idx];
|
let mask = self.writable_bits[reg_idx];
|
||||||
if reg_idx >= BAR0_REG && reg_idx < BAR0_REG + NUM_BAR_REGS {
|
if reg_idx >= BAR0_REG && reg_idx < BAR0_REG + NUM_BAR_REGS {
|
||||||
let bar_idx = reg_idx - 4;
|
let bar_idx = reg_idx - 4;
|
||||||
if (value & mask) != (self.bar_addr[bar_idx] & mask) {
|
if (value & mask) != (self.bars[bar_idx].addr & mask) {
|
||||||
// Handle special case where the address being written is
|
// Handle special case where the address being written is
|
||||||
// different from the address initially provided. This is a
|
// different from the address initially provided. This is a
|
||||||
// BAR reprogramming case which needs to be properly caught.
|
// BAR reprogramming case which needs to be properly caught.
|
||||||
if let Some(bar_type) = self.bar_type[bar_idx] {
|
if let Some(bar_type) = self.bars[bar_idx].r#type {
|
||||||
match bar_type {
|
match bar_type {
|
||||||
PciBarRegionType::Memory64BitRegion => {}
|
PciBarRegionType::Memory64BitRegion => {}
|
||||||
_ => {
|
_ => {
|
||||||
@ -795,16 +788,16 @@ impl PciConfiguration {
|
|||||||
"DETECT BAR REPROG: current 0x{:x}, new 0x{:x}",
|
"DETECT BAR REPROG: current 0x{:x}, new 0x{:x}",
|
||||||
self.registers[reg_idx], value
|
self.registers[reg_idx], value
|
||||||
);
|
);
|
||||||
let old_base = u64::from(self.bar_addr[bar_idx] & mask);
|
let old_base = u64::from(self.bars[bar_idx].addr & mask);
|
||||||
let new_base = u64::from(value & mask);
|
let new_base = u64::from(value & mask);
|
||||||
let len = u64::from(
|
let len = u64::from(
|
||||||
decode_32_bits_bar_size(self.bar_size[bar_idx])
|
decode_32_bits_bar_size(self.bars[bar_idx].size)
|
||||||
.ok_or(Error::Decode32BarSize)
|
.ok_or(Error::Decode32BarSize)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
let region_type = bar_type;
|
let region_type = bar_type;
|
||||||
|
|
||||||
self.bar_addr[bar_idx] = value;
|
self.bars[bar_idx].addr = value;
|
||||||
|
|
||||||
return Some(BarReprogrammingParams {
|
return Some(BarReprogrammingParams {
|
||||||
old_base,
|
old_base,
|
||||||
@ -816,7 +809,7 @@ impl PciConfiguration {
|
|||||||
}
|
}
|
||||||
} else if (reg_idx > BAR0_REG)
|
} else if (reg_idx > BAR0_REG)
|
||||||
&& (self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1])
|
&& (self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1])
|
||||||
!= (self.bar_addr[bar_idx - 1] & self.writable_bits[reg_idx - 1])
|
!= (self.bars[bar_idx - 1].addr & self.writable_bits[reg_idx - 1])
|
||||||
{
|
{
|
||||||
// Ignore the case where the BAR size is being asked for.
|
// Ignore the case where the BAR size is being asked for.
|
||||||
// Because we are in the 64bits case here, we have to check
|
// Because we are in the 64bits case here, we have to check
|
||||||
@ -824,7 +817,7 @@ impl PciConfiguration {
|
|||||||
// asked for the BAR size too.
|
// asked for the BAR size too.
|
||||||
if value == 0xffff_ffff
|
if value == 0xffff_ffff
|
||||||
&& self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1]
|
&& self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1]
|
||||||
== self.bar_size[bar_idx - 1] & self.writable_bits[reg_idx - 1]
|
== self.bars[bar_idx - 1].size & self.writable_bits[reg_idx - 1]
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -833,18 +826,20 @@ impl PciConfiguration {
|
|||||||
"DETECT BAR REPROG: current 0x{:x}, new 0x{:x}",
|
"DETECT BAR REPROG: current 0x{:x}, new 0x{:x}",
|
||||||
self.registers[reg_idx], value
|
self.registers[reg_idx], value
|
||||||
);
|
);
|
||||||
let old_base = u64::from(self.bar_addr[bar_idx] & mask) << 32
|
let old_base = u64::from(self.bars[bar_idx].addr & mask) << 32
|
||||||
| u64::from(self.bar_addr[bar_idx - 1] & self.writable_bits[reg_idx - 1]);
|
| u64::from(self.bars[bar_idx - 1].addr & self.writable_bits[reg_idx - 1]);
|
||||||
let new_base = u64::from(value & mask) << 32
|
let new_base = u64::from(value & mask) << 32
|
||||||
| u64::from(self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1]);
|
| u64::from(self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1]);
|
||||||
let len =
|
let len = decode_64_bits_bar_size(
|
||||||
decode_64_bits_bar_size(self.bar_size[bar_idx], self.bar_size[bar_idx - 1])
|
self.bars[bar_idx].size,
|
||||||
.ok_or(Error::Decode64BarSize)
|
self.bars[bar_idx - 1].size,
|
||||||
.unwrap();
|
)
|
||||||
|
.ok_or(Error::Decode64BarSize)
|
||||||
|
.unwrap();
|
||||||
let region_type = PciBarRegionType::Memory64BitRegion;
|
let region_type = PciBarRegionType::Memory64BitRegion;
|
||||||
|
|
||||||
self.bar_addr[bar_idx] = value;
|
self.bars[bar_idx].addr = value;
|
||||||
self.bar_addr[bar_idx - 1] = self.registers[reg_idx - 1];
|
self.bars[bar_idx - 1].addr = self.registers[reg_idx - 1];
|
||||||
|
|
||||||
return Some(BarReprogrammingParams {
|
return Some(BarReprogrammingParams {
|
||||||
old_base,
|
old_base,
|
||||||
|
Loading…
Reference in New Issue
Block a user