pci: configuration: Use correct algorithm for BAR size reporting

When reporting the BAR size it is necessary to return a value that is
encoded such that all the bits are set that represent the mask of the
natural alignment of the field.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2020-04-17 09:27:26 +01:00 committed by Sebastien Boeuf
parent 9bd5ec8967
commit b8cfdab8b6

View File

@ -244,6 +244,38 @@ pub trait PciCapability {
fn id(&self) -> PciCapabilityID; fn id(&self) -> PciCapabilityID;
} }
fn encode_32_bits_bar_size(bar_size: u32) -> Option<u32> {
if bar_size > 0 {
return Some(!(bar_size - 1));
}
None
}
fn decode_32_bits_bar_size(bar_size: u32) -> Option<u32> {
if bar_size > 0 {
return Some(!bar_size + 1);
}
None
}
fn encode_64_bits_bar_size(bar_size: u64) -> Option<(u32, u32)> {
if bar_size > 0 {
let result = !(bar_size - 1);
let result_hi = (result >> 32) as u32;
let result_lo = (result & 0xffff_ffff) as u32;
return Some((result_hi, result_lo));
}
None
}
fn decode_64_bits_bar_size(bar_size_hi: u32, bar_size_lo: u32) -> Option<u64> {
let bar_size: u64 = ((bar_size_hi as u64) << 32) | (bar_size_lo as u64);
if bar_size > 0 {
return Some(!bar_size + 1);
}
None
}
/// Contains the configuration space of a PCI node. /// Contains the configuration space of a PCI node.
/// See the [specification](https://en.wikipedia.org/wiki/PCI_configuration_space). /// See the [specification](https://en.wikipedia.org/wiki/PCI_configuration_space).
/// The configuration space is accessed with DWORD reads and writes from the guest. /// The configuration space is accessed with DWORD reads and writes from the guest.
@ -297,6 +329,10 @@ pub enum Error {
CapabilityEmpty, CapabilityEmpty,
CapabilityLengthInvalid(usize), CapabilityLengthInvalid(usize),
CapabilitySpaceFull(usize), CapabilitySpaceFull(usize),
Decode32BarSize,
Decode64BarSize,
Encode32BarSize,
Encode64BarSize,
RomBarAddressInvalid(u64, u64), RomBarAddressInvalid(u64, u64),
RomBarInUse(usize), RomBarInUse(usize),
RomBarInvalid(usize), RomBarInvalid(usize),
@ -324,6 +360,10 @@ impl Display for Error {
CapabilityEmpty => write!(f, "empty capabilities are invalid"), CapabilityEmpty => write!(f, "empty capabilities are invalid"),
CapabilityLengthInvalid(l) => write!(f, "Invalid capability length {}", l), CapabilityLengthInvalid(l) => write!(f, "Invalid capability length {}", l),
CapabilitySpaceFull(s) => write!(f, "capability of size {} doesn't fit", s), CapabilitySpaceFull(s) => write!(f, "capability of size {} doesn't fit", s),
Decode32BarSize => write!(f, "failed to decode 32 bits BAR size"),
Decode64BarSize => write!(f, "failed to decode 64 bits BAR size"),
Encode32BarSize => write!(f, "failed to encode 32 bits BAR size"),
Encode64BarSize => write!(f, "failed to encode 64 bits BAR size"),
RomBarAddressInvalid(a, s) => write!(f, "address {} size {} too big", a, s), RomBarAddressInvalid(a, s) => write!(f, "address {} size {} too big", a, s),
RomBarInUse(b) => write!(f, "rom bar {} already used", b), RomBarInUse(b) => write!(f, "rom bar {} already used", b),
RomBarInvalid(b) => write!(f, "rom bar {} invalid, max {}", b, NUM_BAR_REGS - 1), RomBarInvalid(b) => write!(f, "rom bar {} invalid, max {}", b, NUM_BAR_REGS - 1),
@ -405,14 +445,14 @@ 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.bar_size[reg_idx - 4];
} }
} 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
// all 1's on bits 31-11 to retrieve the BAR size during next BAR // all 1's on bits 31-11 to retrieve the BAR size during next BAR
// reading. // reading.
if value & ROM_BAR_ADDR_MASK == ROM_BAR_ADDR_MASK { if value & ROM_BAR_ADDR_MASK == ROM_BAR_ADDR_MASK {
mask = self.rom_bar_size; mask &= self.rom_bar_size;
} }
} }
@ -496,6 +536,11 @@ impl PciConfiguration {
if end_addr > u64::from(u32::max_value()) { if end_addr > u64::from(u32::max_value()) {
return Err(Error::BarAddressInvalid(config.addr, config.size)); return Err(Error::BarAddressInvalid(config.addr, config.size));
} }
// Encode the BAR size as expected by the software running in
// the guest.
self.bar_size[config.reg_idx] =
encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
} }
PciBarRegionType::Memory64BitRegion => { PciBarRegionType::Memory64BitRegion => {
if config.reg_idx + 1 >= NUM_BAR_REGS { if config.reg_idx + 1 >= NUM_BAR_REGS {
@ -510,10 +555,16 @@ impl PciConfiguration {
return Err(Error::BarInUse64(config.reg_idx)); return Err(Error::BarInUse64(config.reg_idx));
} }
// Encode the BAR size as expected by the software running in
// the guest.
let (bar_size_hi, bar_size_lo) =
encode_64_bits_bar_size(config.size).ok_or(Error::Encode64BarSize)?;
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.bar_addr[config.reg_idx + 1] = self.registers[bar_idx + 1];
self.bar_size[config.reg_idx + 1] = (config.size >> 32) as u32; self.bar_size[config.reg_idx] = bar_size_lo;
self.bar_size[config.reg_idx + 1] = bar_size_hi;
self.bar_used[config.reg_idx + 1] = true; self.bar_used[config.reg_idx + 1] = true;
} }
} }
@ -529,7 +580,6 @@ 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.bar_addr[config.reg_idx] = self.registers[bar_idx];
self.bar_size[config.reg_idx] = config.size as u32;
self.bar_used[config.reg_idx] = true; self.bar_used[config.reg_idx] = true;
self.bar_type[config.reg_idx] = Some(config.region_type); self.bar_type[config.reg_idx] = Some(config.region_type);
Ok(config.reg_idx) Ok(config.reg_idx)
@ -561,7 +611,8 @@ impl PciConfiguration {
self.registers[config.reg_idx] = (config.addr as u32) | active; self.registers[config.reg_idx] = (config.addr as u32) | active;
self.writable_bits[config.reg_idx] = ROM_BAR_ADDR_MASK; self.writable_bits[config.reg_idx] = ROM_BAR_ADDR_MASK;
self.rom_bar_addr = self.registers[config.reg_idx]; self.rom_bar_addr = self.registers[config.reg_idx];
self.rom_bar_size = config.size as u32; self.rom_bar_size =
encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
self.rom_bar_used = true; self.rom_bar_used = true;
Ok(config.reg_idx) Ok(config.reg_idx)
} }
@ -699,7 +750,11 @@ impl PciConfiguration {
); );
let old_base = u64::from(self.bar_addr[bar_idx] & mask); let old_base = u64::from(self.bar_addr[bar_idx] & mask);
let new_base = u64::from(value & mask); let new_base = u64::from(value & mask);
let len = u64::from(self.bar_size[bar_idx]); let len = u64::from(
decode_32_bits_bar_size(self.bar_size[bar_idx])
.ok_or(Error::Decode32BarSize)
.unwrap(),
);
let region_type = bar_type; let region_type = bar_type;
self.bar_addr[bar_idx] = value; self.bar_addr[bar_idx] = value;
@ -735,8 +790,10 @@ impl PciConfiguration {
| u64::from(self.bar_addr[bar_idx - 1] & self.writable_bits[reg_idx - 1]); | u64::from(self.bar_addr[bar_idx - 1] & 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 = u64::from(self.bar_size[bar_idx]) << 32 let len =
| u64::from(self.bar_size[bar_idx - 1]); decode_64_bits_bar_size(self.bar_size[bar_idx], self.bar_size[bar_idx - 1])
.ok_or(Error::Decode64BarSize)
.unwrap();
let region_type = PciBarRegionType::Memory64BitRegion; let region_type = PciBarRegionType::Memory64BitRegion;
self.bar_addr[bar_idx] = value; self.bar_addr[bar_idx] = value;
@ -762,7 +819,11 @@ impl PciConfiguration {
); );
let old_base = u64::from(self.rom_bar_addr & mask); let old_base = u64::from(self.rom_bar_addr & mask);
let new_base = u64::from(value & mask); let new_base = u64::from(value & mask);
let len = u64::from(self.rom_bar_size); let len = u64::from(
decode_32_bits_bar_size(self.rom_bar_size)
.ok_or(Error::Decode32BarSize)
.unwrap(),
);
let region_type = PciBarRegionType::Memory32BitRegion; let region_type = PciBarRegionType::Memory32BitRegion;
self.rom_bar_addr = value; self.rom_bar_addr = value;