From 7efc6dc985f197de61992f4d1c411807ea2e9e8e Mon Sep 17 00:00:00 2001 From: apio Date: Wed, 10 May 2023 19:15:47 +0200 Subject: [PATCH] kernel/x86_64: Add basic ATA controller and channel identification --- kernel/CMakeLists.txt | 1 + kernel/src/arch/x86_64/disk/ATA.cpp | 73 +++++++++++++++++++++++++++++ kernel/src/arch/x86_64/disk/ATA.h | 72 ++++++++++++++++++++++++++++ kernel/src/main.cpp | 14 +++--- 4 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 kernel/src/arch/x86_64/disk/ATA.cpp create mode 100644 kernel/src/arch/x86_64/disk/ATA.h diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 2e2e40d2..8c266e6d 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -65,6 +65,7 @@ if("${LUNA_ARCH}" MATCHES "x86_64") src/arch/x86_64/Thread.cpp src/arch/x86_64/PCI.cpp src/arch/x86_64/Keyboard.cpp + src/arch/x86_64/disk/ATA.cpp src/arch/x86_64/init/GDT.cpp src/arch/x86_64/init/IDT.cpp src/arch/x86_64/init/PIC.cpp diff --git a/kernel/src/arch/x86_64/disk/ATA.cpp b/kernel/src/arch/x86_64/disk/ATA.cpp new file mode 100644 index 00000000..0c371d4d --- /dev/null +++ b/kernel/src/arch/x86_64/disk/ATA.cpp @@ -0,0 +1,73 @@ +#include "arch/x86_64/disk/ATA.h" +#include "Log.h" +#include "arch/x86_64/IO.h" +#include + +SharedPtr g_controller; + +namespace ATA +{ + Result Controller::scan() + { + // FIXME: Propagate errors. + PCI::scan( + [](const PCI::Device& device) { + if (!g_controller) + { + auto controller = adopt_shared_if_nonnull(new (std::nothrow) Controller(device)).release_value(); + kinfoln("ata: Found ATA controller on PCI bus (%x:%x:%x)", device.address.bus, + device.address.function, device.address.slot); + + if (controller->initialize()) g_controller = controller; + } + }, + { .klass = 1, .subclass = 1 }); + + return {}; + } + + bool Controller::initialize() + { + if (!m_primary_channel.initialize()) return false; + + return m_secondary_channel.initialize(); + } + + Controller::Controller(const PCI::Device& device) + : m_device(device), m_primary_channel(this, 0, {}), m_secondary_channel(this, 1, {}) + { + } + + Channel::Channel(Controller* controller, u8 channel_index, Badge) + : m_controller(controller), m_channel_index(channel_index) + { + } + + 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 "); + + 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 = + 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; + } + + 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; + + kinfoln("ata: Channel %d uses IRQ %hhu", m_channel_index, interrupt_line); + + return true; + } +} diff --git a/kernel/src/arch/x86_64/disk/ATA.h b/kernel/src/arch/x86_64/disk/ATA.h new file mode 100644 index 00000000..ad46feef --- /dev/null +++ b/kernel/src/arch/x86_64/disk/ATA.h @@ -0,0 +1,72 @@ +#pragma once +#include "arch/PCI.h" +#include "fs/devices/DeviceRegistry.h" +#include +#include + +namespace ATA +{ + class Controller; + class Channel + { + public: + Channel(Controller* controller, u8 channel_index, Badge); + + bool initialize(); + + private: + Controller* m_controller; + u8 m_channel_index; + bool m_is_pci_native_mode; + + u32 m_base_address; + u32 m_control_port_base_address; + }; + + class Controller + { + public: + static Result scan(); + + const PCI::Device& device() const + { + return m_device; + } + + bool initialize(); + + private: + Controller(const PCI::Device& device); + PCI::Device m_device; + Channel m_primary_channel; + Channel m_secondary_channel; + + Atomic m_hwlock = 0; + }; + +} + +class ATADevice : public Device +{ + public: + // Initializer for DeviceRegistry. + static Result create(SharedPtr controller, int channel, int drive); + + Result read(u8*, usize, usize) const override; + + Result write(const u8*, usize, usize) override; + + bool blocking() const override; + + Result ioctl(int request, void* arg) override; + + usize size() const override; + + virtual ~ATADevice() = default; + + private: + ATADevice(SharedPtr controller); + SharedPtr m_controller; + int m_channel; + int m_drive; +}; diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index 31dc8137..fc56ed17 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -1,6 +1,5 @@ #include "Log.h" #include "arch/CPU.h" -#include "arch/PCI.h" #include "arch/Timer.h" #include "boot/Init.h" #include "config.h" @@ -11,6 +10,10 @@ #include "thread/Scheduler.h" #include +#ifdef ARCH_X86_64 +#include "arch/x86_64/disk/ATA.h" +#endif + extern void set_host_name(StringView); void reap_thread() @@ -53,12 +56,9 @@ Result init() auto reap = Scheduler::new_kernel_thread(reap_thread, "[reap]").release_value(); Scheduler::set_reap_thread(reap); - PCI::scan( - [](const PCI::Device& device) { - kinfoln("Found PCI mass storage device %.4x:%.4x, at address %u:%u:%u", device.id.vendor, device.id.device, - device.address.bus, device.address.slot, device.address.function); - }, - { .klass = 1 }); +#ifdef ARCH_X86_64 + ATA::Controller::scan(); +#endif // Disable console logging before transferring control to userspace. setup_log(log_debug_enabled(), log_serial_enabled(), false);