Kernel: Safely fail allocating zero sized BAR regions
Our device discovery thinks vmware's audio device is AC97 and allocating one of the BARs leads to zero sized allocation -> panic from page table as it tries to allocate 0 pages. Now we gracefully handle these regions and fail to allocate the BAR
This commit is contained in:
+11
-5
@@ -912,10 +912,10 @@ namespace Kernel::PCI
|
||||
}
|
||||
|
||||
// disable io/mem space while reading bar
|
||||
uint16_t command = device.read_word(PCI_REG_COMMAND);
|
||||
const uint16_t command = device.read_word(PCI_REG_COMMAND);
|
||||
device.write_word(PCI_REG_COMMAND, command & ~(PCI_CMD_IO_SPACE | PCI_CMD_MEM_SPACE));
|
||||
|
||||
uint8_t offset = 0x10 + bar_num * 4;
|
||||
const uint8_t offset = 0x10 + bar_num * 4;
|
||||
|
||||
uint64_t addr = device.read_dword(offset);
|
||||
|
||||
@@ -924,6 +924,13 @@ namespace Kernel::PCI
|
||||
size = ~size + 1;
|
||||
device.write_dword(offset, addr);
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
device.write_word(PCI_REG_COMMAND, command);
|
||||
dwarnln("BAR{} has size 0", bar_num);
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
// determine bar type
|
||||
BarType type = BarType::INVALID;
|
||||
if (addr & 1)
|
||||
@@ -956,8 +963,7 @@ namespace Kernel::PCI
|
||||
TRY(region->initialize());
|
||||
|
||||
// restore old command register and enable correct IO/MEM space
|
||||
command |= (type == BarType::IO) ? PCI_CMD_IO_SPACE : PCI_CMD_MEM_SPACE;
|
||||
device.write_word(PCI_REG_COMMAND, command);
|
||||
device.write_word(PCI_REG_COMMAND, command | ((type == BarType::IO) ? PCI_CMD_IO_SPACE : PCI_CMD_MEM_SPACE));
|
||||
|
||||
#if DEBUG_PCI
|
||||
dprintln("created BAR region for PCI {2H}:{2H}.{2H}",
|
||||
@@ -997,7 +1003,7 @@ namespace Kernel::PCI
|
||||
if (m_type == BarType::IO)
|
||||
return {};
|
||||
|
||||
size_t needed_pages = BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE);
|
||||
const size_t needed_pages = BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE);
|
||||
m_vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET);
|
||||
if (m_vaddr == 0)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
|
||||
Reference in New Issue
Block a user