diff --git a/kernel/src/arch/PCI.cpp b/kernel/src/arch/PCI.cpp index 25c0cc3b..3a7bb6a9 100644 --- a/kernel/src/arch/PCI.cpp +++ b/kernel/src/arch/PCI.cpp @@ -9,6 +9,10 @@ struct ScanInfo namespace PCI { + BAR::BAR(u32 raw) : m_raw(raw) + { + } + Device::ID read_id(const Device::Address& address) { const u16 vendor = read16(address, Field::VendorID); @@ -108,4 +112,13 @@ namespace PCI } } } + + BAR Device::getBAR(u8 index) const + { + check(index < 6); + + u32 raw = read32(address, 0x10 + (index * 4)); + + return { raw }; + } } diff --git a/kernel/src/arch/PCI.h b/kernel/src/arch/PCI.h index 5e457048..6e138f3a 100644 --- a/kernel/src/arch/PCI.h +++ b/kernel/src/arch/PCI.h @@ -27,6 +27,45 @@ namespace PCI InterruptLine = 0x3c, }; + struct BAR + { + public: + BAR(u32 raw); + + bool is_iospace() + { + return m_raw & 0x01; + } + + bool is_memory_space() + { + return !is_iospace(); + } + + u16 port() + { + return (u16)(m_raw & 0xfffffffc); + } + + u8 type() + { + return (m_raw >> 1) & 0x03; + } + + bool is_prefetchable() + { + return m_raw & (1 << 3); + } + + u32 address_32bit() + { + return m_raw & 0xFFFFFFF0; + } + + private: + u32 m_raw; + }; + struct Device { struct ID @@ -49,6 +88,8 @@ namespace PCI u32 function; }; + BAR getBAR(u8 index) const; + ID id; Type type; Address address; diff --git a/kernel/src/arch/x86_64/disk/ATA.cpp b/kernel/src/arch/x86_64/disk/ATA.cpp index 4229322c..1fb852cf 100644 --- a/kernel/src/arch/x86_64/disk/ATA.cpp +++ b/kernel/src/arch/x86_64/disk/ATA.cpp @@ -156,15 +156,27 @@ namespace ATA int offset = m_channel_index ? 2 : 0; m_is_pci_native_mode = m_controller->device().type.prog_if & (1 << offset); - u32 control_port_base_address; - u32 io_base_address; + u16 control_port_base_address; + u16 io_base_address; if (m_is_pci_native_mode) { - // FIXME: Properly decode BARs. - io_base_address = PCI::read32(m_controller->device().address, m_channel_index ? PCI::BAR2 : PCI::BAR0); - control_port_base_address = - PCI::read32(m_controller->device().address, m_channel_index ? PCI::BAR3 : PCI::BAR1); + auto io_base = m_controller->device().getBAR(m_channel_index ? 2 : 0); + if (!io_base.is_iospace()) + { + kwarnln("ata: Channel %d's IO base BAR is not in IO space", m_channel_index); + return false; + } + io_base_address = io_base.port(); + + auto io_control = m_controller->device().getBAR(m_channel_index ? 3 : 1); + if (!io_control.is_iospace()) + { + kwarnln("ata: Channel %d's control base BAR is not in IO space", m_channel_index); + return false; + } + + control_port_base_address = io_control.port(); } else { @@ -172,8 +184,8 @@ namespace ATA control_port_base_address = m_channel_index ? 0x376 : 0x3f6; } - m_io_base = (u16)io_base_address; - m_control_base = (u16)control_port_base_address + 2; + m_io_base = io_base_address; + m_control_base = control_port_base_address + 2; if (m_is_pci_native_mode) m_interrupt_line = PCI::read8(m_controller->device().address, PCI::InterruptLine); else