Adds a region specified by `config`. Configures the specified BAR(s) to report this region and size to the guest kernel. Enforces a few constraints (i.e, region size must be power of two, register not already used).
(&mut self, config: &PciBarConfiguration)
| 724 | /// report this region and size to the guest kernel. Enforces a few constraints |
| 725 | /// (i.e, region size must be power of two, register not already used). |
| 726 | pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Result<()> { |
| 727 | let bar_idx = config.idx; |
| 728 | let reg_idx = BAR0_REG + bar_idx; |
| 729 | |
| 730 | if self.bars[bar_idx].used { |
| 731 | return Err(Error::BarInUse(bar_idx)); |
| 732 | } |
| 733 | |
| 734 | if !config.size.is_power_of_two() { |
| 735 | return Err(Error::BarSizeInvalid(config.size)); |
| 736 | } |
| 737 | |
| 738 | if bar_idx >= NUM_BAR_REGS { |
| 739 | return Err(Error::BarInvalid(bar_idx)); |
| 740 | } |
| 741 | |
| 742 | let end_addr = config |
| 743 | .addr |
| 744 | .checked_add(config.size - 1) |
| 745 | .ok_or(Error::BarAddressInvalid(config.addr, config.size))?; |
| 746 | match config.region_type { |
| 747 | PciBarRegionType::Memory32BitRegion | PciBarRegionType::IoRegion => { |
| 748 | if end_addr > u64::from(u32::MAX) { |
| 749 | return Err(Error::BarAddressInvalid(config.addr, config.size)); |
| 750 | } |
| 751 | |
| 752 | // Encode the BAR size as expected by the software running in |
| 753 | // the guest. |
| 754 | self.bars[bar_idx].size = |
| 755 | encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?; |
| 756 | } |
| 757 | PciBarRegionType::Memory64BitRegion => { |
| 758 | if bar_idx + 1 >= NUM_BAR_REGS { |
| 759 | return Err(Error::BarInvalid64(bar_idx)); |
| 760 | } |
| 761 | |
| 762 | if self.bars[bar_idx + 1].used { |
| 763 | return Err(Error::BarInUse64(bar_idx)); |
| 764 | } |
| 765 | |
| 766 | // Encode the BAR size as expected by the software running in |
| 767 | // the guest. |
| 768 | let (bar_size_hi, bar_size_lo) = |
| 769 | encode_64_bits_bar_size(config.size).ok_or(Error::Encode64BarSize)?; |
| 770 | |
| 771 | self.registers[reg_idx + 1] = (config.addr >> 32) as u32; |
| 772 | self.writable_bits[reg_idx + 1] = 0xffff_ffff; |
| 773 | self.bars[bar_idx + 1].addr = self.registers[reg_idx + 1]; |
| 774 | self.bars[bar_idx].size = bar_size_lo; |
| 775 | self.bars[bar_idx + 1].size = bar_size_hi; |
| 776 | self.bars[bar_idx + 1].used = true; |
| 777 | } |
| 778 | } |
| 779 | |
| 780 | let (mask, lower_bits) = match config.region_type { |
| 781 | PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => ( |
| 782 | BAR_MEM_ADDR_MASK, |
| 783 | config.prefetchable as u32 | config.region_type as u32, |
no test coverage detected