From e616af3b896578806a410a1311dae0d33487ce19 Mon Sep 17 00:00:00 2001 From: apio Date: Sat, 13 May 2023 14:11:09 +0200 Subject: [PATCH] kernel/ATA: Start reading/writing registers and detecting drives --- kernel/src/arch/x86_64/disk/ATA.cpp | 78 +++++++++++++++++++++++++---- kernel/src/arch/x86_64/disk/ATA.h | 53 ++++++++++++++++++-- kernel/src/lib/KMutex.h | 3 +- 3 files changed, 118 insertions(+), 16 deletions(-) diff --git a/kernel/src/arch/x86_64/disk/ATA.cpp b/kernel/src/arch/x86_64/disk/ATA.cpp index 0336ed0d..680bf4a8 100644 --- a/kernel/src/arch/x86_64/disk/ATA.cpp +++ b/kernel/src/arch/x86_64/disk/ATA.cpp @@ -45,30 +45,88 @@ namespace ATA { } + u8 Channel::read_register(Register reg) + { + return IO::inb(m_io_base + (u16)reg); + } + + void Channel::write_register(Register reg, u8 value) + { + IO::outb(m_io_base + (u16)reg, value); + } + + u8 Channel::read_control(ControlRegister reg) + { + return IO::inb(m_control_base + (u16)reg); + } + + void Channel::write_control(ControlRegister reg, u8 value) + { + IO::outb(m_control_base + (u16)reg, value); + } + + void Channel::delay_400ns() + { + read_control(ControlRegister::AltStatus); + read_control(ControlRegister::AltStatus); + read_control(ControlRegister::AltStatus); + read_control(ControlRegister::AltStatus); + } + + void Channel::select(u8 drive) + { + if (drive == m_current_drive) return; + + u8 value = (drive << 4) | 0xa0; + write_register(Register::DriveSelect, value); + + delay_400ns(); + + m_current_drive = drive; + } + bool Channel::initialize() { int offset = m_channel_index ? 2 : 0; m_is_pci_native_mode = m_controller->device().type.prog_if & (1 << offset); - kinfoln("ata: Channel %d is %sin PCI native mode", m_channel_index, m_is_pci_native_mode ? "" : "not "); + + u32 control_port_base_address; + u32 io_base_address; if (m_is_pci_native_mode) { - m_base_address = PCI::read32(m_controller->device().address, m_channel_index ? PCI::BAR2 : PCI::BAR0); - m_control_port_base_address = + // 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); } else { - m_base_address = m_channel_index ? 0x170 : 0x1f0; - m_control_port_base_address = m_channel_index ? 0x376 : 0x3f6; + io_base_address = m_channel_index ? 0x170 : 0x1f0; + control_port_base_address = m_channel_index ? 0x376 : 0x3f6; } - u8 interrupt_line; - if (m_is_pci_native_mode) interrupt_line = PCI::read8(m_controller->device().address, PCI::InterruptLine); - else - interrupt_line = m_channel_index ? 15 : 14; + m_io_base = (u16)io_base_address; + m_control_base = (u16)control_port_base_address + 2; - kinfoln("ata: Channel %d uses IRQ %hhu", m_channel_index, interrupt_line); + if (m_is_pci_native_mode) m_interrupt_line = PCI::read8(m_controller->device().address, PCI::InterruptLine); + else + m_interrupt_line = m_channel_index ? 15 : 14; + + for (u8 drive = 0; drive < 2; drive++) + { + ScopedKMutexLock<100> lock(m_lock); + + select(drive); + + if (read_register(Register::Status) == 0) + { + // No drive on this slot. + continue; + } + + kinfoln("ata: Channel %d has a drive on slot %d!", m_channel_index, drive); + } return true; } diff --git a/kernel/src/arch/x86_64/disk/ATA.h b/kernel/src/arch/x86_64/disk/ATA.h index 03d7cbd7..39ab2d21 100644 --- a/kernel/src/arch/x86_64/disk/ATA.h +++ b/kernel/src/arch/x86_64/disk/ATA.h @@ -7,12 +7,53 @@ namespace ATA { + enum class Register : u16 + { + Data = 0, + Error = 1, + Features = 1, + SectorCount = 2, + SectorNumber = 3, + LBALow = 3, + CylinderLow = 4, + LBAMiddle = 4, + CylinderHigh = 5, + LBAHigh = 5, + DriveSelect = 6, + Status = 7, + Command = 8, + }; + + enum class ControlRegister : u16 + { + AltStatus = 0, + DeviceControl = 0, + DriveAddress = 1, + }; + class Controller; + class Channel; + + class Drive + { + private: + Channel* m_channel; + }; + class Channel { public: Channel(Controller* controller, u8 channel_index, Badge); + u8 read_register(Register reg); + void write_register(Register reg, u8 value); + u8 read_control(ControlRegister reg); + void write_control(ControlRegister reg, u8 value); + + void delay_400ns(); + + void select(u8 drive); + bool initialize(); private: @@ -20,8 +61,14 @@ namespace ATA u8 m_channel_index; bool m_is_pci_native_mode; - u32 m_base_address; - u32 m_control_port_base_address; + u8 m_interrupt_line; + + KMutex<100> m_lock {}; + + u16 m_io_base; + u16 m_control_base; + + u8 m_current_drive = (u8)-1; }; class Controller @@ -41,8 +88,6 @@ namespace ATA PCI::Device m_device; Channel m_primary_channel; Channel m_secondary_channel; - - KMutex<100> m_lock; }; } diff --git a/kernel/src/lib/KMutex.h b/kernel/src/lib/KMutex.h index d55a947e..8929de06 100644 --- a/kernel/src/lib/KMutex.h +++ b/kernel/src/lib/KMutex.h @@ -52,9 +52,8 @@ template class KMutex template class ScopedKMutexLock { public: - ScopedKMutexLock(KMutex& lock) + ScopedKMutexLock(KMutex& lock) : m_lock(lock) { - m_lock = lock; m_lock.lock(); }