diff --git a/src/kernel/ahci.cpp b/src/kernel/ahci.cpp index 26d92bc..03b94f2 100644 --- a/src/kernel/ahci.cpp +++ b/src/kernel/ahci.cpp @@ -47,6 +47,98 @@ enum class ata_cmd : uint8_t identify = 0xEC }; +struct ahci_port_data +{ + uint64_t command_base; + uint64_t fis_base; + uint32_t interrupt_status; + uint32_t interrupt_enable; + uint32_t command; + uint32_t reserved; + uint32_t task_file; + uint32_t signature; + uint32_t serial_status; + uint32_t serial_control; + uint32_t serial_error; +} __attribute__ ((packed)); + + +ahci_port::ahci_port(ahci_port_data *data, bool impl) : + m_data(data), + m_state(state::unimpl) +{ + if (impl) { + m_state = state::inactive; + update(); + } +} + +void +ahci_port::update() +{ + if (m_state == state::unimpl) return; + + uint32_t detected = m_data->serial_status & 0x0f; + uint32_t power = (m_data->serial_status >> 8) & 0x0f; + + if (detected == 0x3 && power == 0x1) + m_state = state::active; + else + m_state = state::inactive; + +} + + +enum class ahci_hba::cap : uint32_t +{ + cccs = 0x00000080, // Command completion coalescing + sam = 0x00040000, // ACHI-only mode + sclo = 0x01000000, // Command list override + ssntf = 0x40000000, // SNotification register + sncq = 0x40000000, // Native command queuing + s64a = 0x80000000 // 64bit addressing +}; +IS_BITFIELD(ahci_hba::cap); + +enum class ahci_hba::cap2 : uint32_t +{ + boh = 0x00000001 // BIOS OS hand-off +}; +IS_BITFIELD(ahci_hba::cap2); + + + +ahci_hba::ahci_hba(pci_device *device) +{ + page_manager *pm = page_manager::get(); + + uint32_t bar5 = device->get_bar(5); + m_bara = reinterpret_cast(bar5 & ~0xfffull); + pm->map_offset_pointer(reinterpret_cast(&m_bara), 0x2000); + + ahci_port_data *port_data = reinterpret_cast( + kutil::offset_pointer(m_bara, 0x100)); + + uint32_t cap_reg = m_bara[0]; + m_cap = static_cast(cap_reg); + m_cap2 = static_cast(m_bara[6]); + + uint32_t ports = (cap_reg & 0xf) + 1; + uint32_t slots = ((cap_reg >> 8) & 0x1f) + 1; + + log::info(logs::driver, " %d ports", ports); + log::info(logs::driver, " %d command slots", slots); + + m_ports.ensure_capacity(ports); + + uint32_t pi = m_bara[3]; + for (int i = 0; i < ports; ++i) { + bool impl = ((pi & (1 << i)) != 0); + m_ports.emplace(&port_data[i], impl); + } +} + + ahci_driver::ahci_driver() { } @@ -57,32 +149,5 @@ ahci_driver::register_device(pci_device *device) log::info(logs::driver, "AHCI registering device %d:%d:%d:", device->bus(), device->device(), device->function()); - uint32_t bar5 = device->get_bar(5); - uint32_t *bara = reinterpret_cast(bar5 & ~0xfffull); - - page_manager *pm = page_manager::get(); - pm->map_offset_pointer(reinterpret_cast(&bara), 0x2000); - - uint32_t cap = bara[0]; - - log::info(logs::driver, " %d ports", (cap & 0xf) + 1); - log::info(logs::driver, " %d command slots", ((cap >> 8) & 0x1f) + 1); - log::info(logs::driver, " Supports:"); - if (cap & 0x80000000) log::info(logs::driver, " - 64 bit addressing"); - if (cap & 0x40000000) log::info(logs::driver, " - native command queuing"); - if (cap & 0x20000000) log::info(logs::driver, " - SNotification register"); - if (cap & 0x10000000) log::info(logs::driver, " - mechanical presence switches"); - if (cap & 0x08000000) log::info(logs::driver, " - staggered spin up"); - if (cap & 0x04000000) log::info(logs::driver, " - agressive link power management"); - if (cap & 0x02000000) log::info(logs::driver, " - activity LED"); - if (cap & 0x01000000) log::info(logs::driver, " - command list override"); - if (cap & 0x00040000) log::info(logs::driver, " - AHCI only"); - if (cap & 0x00020000) log::info(logs::driver, " - port multiplier"); - if (cap & 0x00010000) log::info(logs::driver, " - FIS switching"); - if (cap & 0x00008000) log::info(logs::driver, " - PIO multiple DRQ"); - if (cap & 0x00004000) log::info(logs::driver, " - slumber state"); - if (cap & 0x00002000) log::info(logs::driver, " - partial state"); - if (cap & 0x00000080) log::info(logs::driver, " - command completion coalescing"); - if (cap & 0x00000040) log::info(logs::driver, " - enclosure management"); - if (cap & 0x00000020) log::info(logs::driver, " - external SATA"); + ahci_hba &hba = m_devices.emplace(device); } diff --git a/src/kernel/ahci.h b/src/kernel/ahci.h index 9f0e053..566163f 100644 --- a/src/kernel/ahci.h +++ b/src/kernel/ahci.h @@ -4,6 +4,52 @@ #include "kutil/vector.h" class pci_device; +struct ahci_port_data; + + +/// A port on an AHCI HBA +class ahci_port +{ +public: + /// Constructor. + /// \arg data Pointer to the device's registers for this port + /// \arg impl Whether this port is marked as implemented in the HBA + ahci_port(ahci_port_data *data, bool impl); + + enum class state { unimpl, inactive, active }; + + /// Get the current state of this device + /// \returns An enum representing the state + state get_state() const { return m_state; } + + /// Update the state of this object from the register data + void update(); + +private: + ahci_port_data *m_data; + state m_state; +}; + + +/// An AHCI host bus adapter +class ahci_hba +{ +public: + /// Constructor. + /// \arg device The PCI device for this HBA + ahci_hba(pci_device *device); + +private: + enum class cap : uint32_t; + enum class cap2 : uint32_t; + + pci_device *m_device; + uint32_t *m_bara; + kutil::vector m_ports; + + cap m_cap; + cap2 m_cap2; +}; /// Basic AHCI driver @@ -22,5 +68,5 @@ public: void unregister_device(pci_device *device); private: - kutil::vector m_devices; + kutil::vector m_devices; };