kernel/x86_64: Add basic ATA controller and channel identification
This commit is contained in:
parent
beeafb73e6
commit
7efc6dc985
@ -65,6 +65,7 @@ if("${LUNA_ARCH}" MATCHES "x86_64")
|
|||||||
src/arch/x86_64/Thread.cpp
|
src/arch/x86_64/Thread.cpp
|
||||||
src/arch/x86_64/PCI.cpp
|
src/arch/x86_64/PCI.cpp
|
||||||
src/arch/x86_64/Keyboard.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/GDT.cpp
|
||||||
src/arch/x86_64/init/IDT.cpp
|
src/arch/x86_64/init/IDT.cpp
|
||||||
src/arch/x86_64/init/PIC.cpp
|
src/arch/x86_64/init/PIC.cpp
|
||||||
|
73
kernel/src/arch/x86_64/disk/ATA.cpp
Normal file
73
kernel/src/arch/x86_64/disk/ATA.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#include "arch/x86_64/disk/ATA.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#include "arch/x86_64/IO.h"
|
||||||
|
#include <luna/Vector.h>
|
||||||
|
|
||||||
|
SharedPtr<ATA::Controller> g_controller;
|
||||||
|
|
||||||
|
namespace ATA
|
||||||
|
{
|
||||||
|
Result<void> 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<Controller>)
|
||||||
|
: 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;
|
||||||
|
}
|
||||||
|
}
|
72
kernel/src/arch/x86_64/disk/ATA.h
Normal file
72
kernel/src/arch/x86_64/disk/ATA.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "arch/PCI.h"
|
||||||
|
#include "fs/devices/DeviceRegistry.h"
|
||||||
|
#include <luna/Atomic.h>
|
||||||
|
#include <luna/SharedPtr.h>
|
||||||
|
|
||||||
|
namespace ATA
|
||||||
|
{
|
||||||
|
class Controller;
|
||||||
|
class Channel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Channel(Controller* controller, u8 channel_index, Badge<Controller>);
|
||||||
|
|
||||||
|
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<void> 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<int> m_hwlock = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ATADevice : public Device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Initializer for DeviceRegistry.
|
||||||
|
static Result<void> create(SharedPtr<ATA::Controller> controller, int channel, int drive);
|
||||||
|
|
||||||
|
Result<usize> read(u8*, usize, usize) const override;
|
||||||
|
|
||||||
|
Result<usize> write(const u8*, usize, usize) override;
|
||||||
|
|
||||||
|
bool blocking() const override;
|
||||||
|
|
||||||
|
Result<u64> ioctl(int request, void* arg) override;
|
||||||
|
|
||||||
|
usize size() const override;
|
||||||
|
|
||||||
|
virtual ~ATADevice() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ATADevice(SharedPtr<ATA::Controller> controller);
|
||||||
|
SharedPtr<ATA::Controller> m_controller;
|
||||||
|
int m_channel;
|
||||||
|
int m_drive;
|
||||||
|
};
|
@ -1,6 +1,5 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "arch/CPU.h"
|
#include "arch/CPU.h"
|
||||||
#include "arch/PCI.h"
|
|
||||||
#include "arch/Timer.h"
|
#include "arch/Timer.h"
|
||||||
#include "boot/Init.h"
|
#include "boot/Init.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -11,6 +10,10 @@
|
|||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include <luna/Units.h>
|
#include <luna/Units.h>
|
||||||
|
|
||||||
|
#ifdef ARCH_X86_64
|
||||||
|
#include "arch/x86_64/disk/ATA.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
extern void set_host_name(StringView);
|
extern void set_host_name(StringView);
|
||||||
|
|
||||||
void reap_thread()
|
void reap_thread()
|
||||||
@ -53,12 +56,9 @@ Result<void> init()
|
|||||||
auto reap = Scheduler::new_kernel_thread(reap_thread, "[reap]").release_value();
|
auto reap = Scheduler::new_kernel_thread(reap_thread, "[reap]").release_value();
|
||||||
Scheduler::set_reap_thread(reap);
|
Scheduler::set_reap_thread(reap);
|
||||||
|
|
||||||
PCI::scan(
|
#ifdef ARCH_X86_64
|
||||||
[](const PCI::Device& device) {
|
ATA::Controller::scan();
|
||||||
kinfoln("Found PCI mass storage device %.4x:%.4x, at address %u:%u:%u", device.id.vendor, device.id.device,
|
#endif
|
||||||
device.address.bus, device.address.slot, device.address.function);
|
|
||||||
},
|
|
||||||
{ .klass = 1 });
|
|
||||||
|
|
||||||
// Disable console logging before transferring control to userspace.
|
// Disable console logging before transferring control to userspace.
|
||||||
setup_log(log_debug_enabled(), log_serial_enabled(), false);
|
setup_log(log_debug_enabled(), log_serial_enabled(), false);
|
||||||
|
Loading…
Reference in New Issue
Block a user