From 3998c5f95595a8efe21f350febc28fd238b5081e Mon Sep 17 00:00:00 2001 From: Bananymous Date: Sun, 2 Apr 2023 23:56:01 +0300 Subject: [PATCH] Kernel: ATA now uses irqs instead of polling Reading is now much slower at ~500 kB/s it was around 3 MB/s. This is probably mostly due semaphore blocking taking atleast until next reschedule (1 ms itervals). This will be a problem as long as we are using only single processor. I could try to use {READ/WRITE}_MULTIPLE commands, but since most of the disk reads are 2 sectors (inode block size) this will at most double the speed. Most efficient speed up would of course be caching disk access data and inodes overall. --- kernel/CMakeLists.txt | 1 + kernel/include/kernel/Semaphore.h | 2 - kernel/include/kernel/Storage/ATABus.h | 68 ++++ kernel/include/kernel/Storage/ATAController.h | 14 +- kernel/include/kernel/Storage/ATADevice.h | 42 +-- .../kernel/Storage/StorageController.h | 13 +- kernel/kernel/DeviceManager.cpp | 9 +- kernel/kernel/Storage/ATABus.cpp | 318 ++++++++++++++++++ kernel/kernel/Storage/ATAController.cpp | 97 +----- kernel/kernel/Storage/ATADevice.cpp | 181 ++-------- 10 files changed, 449 insertions(+), 296 deletions(-) create mode 100644 kernel/include/kernel/Storage/ATABus.h create mode 100644 kernel/kernel/Storage/ATABus.cpp diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index e0fa0998..4de18186 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -38,6 +38,7 @@ set(KERNEL_SOURCES kernel/Shell.cpp kernel/SpinLock.cpp kernel/SSP.cpp + kernel/Storage/ATABus.cpp kernel/Storage/ATAController.cpp kernel/Storage/ATADevice.cpp kernel/Storage/StorageDevice.cpp diff --git a/kernel/include/kernel/Semaphore.h b/kernel/include/kernel/Semaphore.h index 4b85f31c..6ad21e66 100644 --- a/kernel/include/kernel/Semaphore.h +++ b/kernel/include/kernel/Semaphore.h @@ -1,7 +1,5 @@ #pragma once -#include - namespace Kernel { diff --git a/kernel/include/kernel/Storage/ATABus.h b/kernel/include/kernel/Storage/ATABus.h new file mode 100644 index 00000000..c9c2db0c --- /dev/null +++ b/kernel/include/kernel/Storage/ATABus.h @@ -0,0 +1,68 @@ +#pragma once + +#include +#include +#include +#include + +namespace Kernel +{ + + class ATADevice; + + class ATABus + { + public: + enum class DeviceType + { + None, + ATA, + ATAPI, + }; + + public: + static ATABus* create(ATAController*, uint16_t base, uint16_t ctrl, uint8_t irq); + + BAN::ErrorOr read(ATADevice*, uint64_t, uint8_t, uint8_t*); + BAN::ErrorOr write(ATADevice*, uint64_t, uint8_t, const uint8_t*); + + ATAController* controller() { return m_controller; } + + void on_irq(); + + private: + ATABus(ATAController* controller, uint16_t base, uint16_t ctrl) + : m_controller(controller) + , m_base(base) + , m_ctrl(ctrl) + {} + void initialize(uint8_t irq); + + void select_device(const ATADevice*); + DeviceType identify(const ATADevice*, uint16_t*); + + void block_until_irq(); + uint8_t device_index(const ATADevice*) const; + + uint8_t io_read(uint16_t); + void io_write(uint16_t, uint8_t); + void read_buffer(uint16_t, uint16_t*, size_t); + void write_buffer(uint16_t, const uint16_t*, size_t); + BAN::ErrorOr wait(bool); + BAN::Error error(); + + private: + ATAController* m_controller; + const uint16_t m_base; + const uint16_t m_ctrl; + SpinLock m_lock; + Semaphore m_semaphore; + + bool m_has_got_irq { false }; + + ATADevice* m_devices[2] { nullptr, nullptr }; + + friend class ATAController; + }; + +} \ No newline at end of file diff --git a/kernel/include/kernel/Storage/ATAController.h b/kernel/include/kernel/Storage/ATAController.h index c747b3a0..76e7f164 100644 --- a/kernel/include/kernel/Storage/ATAController.h +++ b/kernel/include/kernel/Storage/ATAController.h @@ -8,24 +8,24 @@ namespace Kernel { - class ATADevice; + class ATABus; class ATAController final : public StorageController { public: static BAN::ErrorOr create(const PCIDevice&); + virtual BAN::Vector devices() override; + + uint8_t next_device_index() const; + private: ATAController() = default; BAN::ErrorOr initialize(const PCIDevice& device); - BAN::ErrorOr read(ATADevice*, uint64_t, uint8_t, uint8_t*); - BAN::ErrorOr write(ATADevice*, uint64_t, uint8_t, const uint8_t*); - private: - SpinLock m_lock; - - friend class ATADevice; + ATABus* m_buses[2] { nullptr, nullptr }; + friend class ATABus; public: virtual ino_t ino() const override { return 0; } diff --git a/kernel/include/kernel/Storage/ATADevice.h b/kernel/include/kernel/Storage/ATADevice.h index e90913d4..bf22820f 100644 --- a/kernel/include/kernel/Storage/ATADevice.h +++ b/kernel/include/kernel/Storage/ATADevice.h @@ -1,16 +1,16 @@ #pragma once +#include #include namespace Kernel { - class ATAController; - class ATADevice final : public StorageDevice { public: - static BAN::ErrorOr create(ATAController*, uint16_t, uint16_t, uint8_t); + ATADevice(ATABus* bus) : m_bus(bus) { } + BAN::ErrorOr initialize(ATABus::DeviceType, const uint16_t*); virtual BAN::ErrorOr read_sectors(uint64_t, uint8_t, uint8_t*) override; virtual BAN::ErrorOr write_sectors(uint64_t, uint8_t, const uint8_t*) override; @@ -20,36 +20,10 @@ namespace Kernel BAN::StringView model() const { return m_model; } private: - ATADevice(ATAController* controller, uint16_t base, uint16_t ctrl, uint8_t index) - : m_controller(controller) - , m_base(base) - , m_ctrl(ctrl) - , m_index(index) - , m_slave_bit((index & 0x01) << 4) - { } - BAN::ErrorOr initialize(); + ATABus* m_bus; + uint8_t m_index; - uint8_t io_read(uint16_t); - void io_write(uint16_t, uint8_t); - void read_buffer(uint16_t, uint16_t*, size_t); - void write_buffer(uint16_t, const uint16_t*, size_t); - BAN::ErrorOr wait(bool); - BAN::Error error(); - - private: - enum class DeviceType - { - ATA, - ATAPI, - }; - - ATAController* m_controller; - const uint16_t m_base; - const uint16_t m_ctrl; - const uint8_t m_index; - const uint8_t m_slave_bit; - - DeviceType m_type; + ATABus::DeviceType m_type; uint16_t m_signature; uint16_t m_capabilities; uint32_t m_command_set; @@ -57,7 +31,7 @@ namespace Kernel uint64_t m_lba_count; char m_model[41]; - friend class ATAController; + friend class ATABus; public: virtual ino_t ino() const override { return m_index; } @@ -68,7 +42,7 @@ namespace Kernel virtual off_t size() const override { return 0; } virtual blksize_t blksize() const override { return sector_size(); } virtual blkcnt_t blocks() const override { return 0; } - virtual dev_t dev() const override; + virtual dev_t dev() const override { return m_bus->controller()->dev(); } virtual dev_t rdev() const override { return 0x5429; } virtual BAN::StringView name() const override { return BAN::StringView(m_device_name, sizeof(m_device_name) - 1); } diff --git a/kernel/include/kernel/Storage/StorageController.h b/kernel/include/kernel/Storage/StorageController.h index 321c4f91..ce46c161 100644 --- a/kernel/include/kernel/Storage/StorageController.h +++ b/kernel/include/kernel/Storage/StorageController.h @@ -8,18 +8,7 @@ namespace Kernel class StorageController : public CharacterDevice { public: - BAN::Vector& devices() { return m_devices; } - const BAN::Vector& devices() const { return m_devices; } - - protected: - void add_device(StorageDevice* device) - { - ASSERT(device); - MUST(m_devices.push_back(device)); - } - - private: - BAN::Vector m_devices; + virtual BAN::Vector devices() = 0; }; } \ No newline at end of file diff --git a/kernel/kernel/DeviceManager.cpp b/kernel/kernel/DeviceManager.cpp index fe8fdaf3..451a79d4 100644 --- a/kernel/kernel/DeviceManager.cpp +++ b/kernel/kernel/DeviceManager.cpp @@ -42,8 +42,13 @@ namespace Kernel for (auto* device : controller->devices()) { s_instance->add_device(device); - for (auto* partition : device->partitions()) - s_instance->add_device(partition); + if (auto res = device->initialize_partitions(); res.is_error()) + dprintln("{}: {}", device->name(), res.error()); + else + { + for (auto* partition : device->partitions()) + s_instance->add_device(partition); + } } } break; diff --git a/kernel/kernel/Storage/ATABus.cpp b/kernel/kernel/Storage/ATABus.cpp new file mode 100644 index 00000000..268069b5 --- /dev/null +++ b/kernel/kernel/Storage/ATABus.cpp @@ -0,0 +1,318 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace Kernel +{ + + static void bus_irq_handler0(); + static void bus_irq_handler1(); + + struct BusIRQ + { + ATABus* bus { nullptr }; + void (*handler)() { nullptr }; + uint8_t irq { 0 }; + }; + static BusIRQ s_bus_irqs[] { + { nullptr, bus_irq_handler0, 0 }, + { nullptr, bus_irq_handler1, 0 }, + }; + + static void bus_irq_handler0() { ASSERT(s_bus_irqs[0].bus); s_bus_irqs[0].bus->on_irq(); } + static void bus_irq_handler1() { ASSERT(s_bus_irqs[1].bus); s_bus_irqs[1].bus->on_irq(); } + + static void register_bus_irq_handler(ATABus* bus, uint8_t irq) + { + for (uint8_t i = 0; i < sizeof(s_bus_irqs) / sizeof(BusIRQ); i++) + { + if (s_bus_irqs[i].bus == nullptr) + { + s_bus_irqs[i].bus = bus; + s_bus_irqs[i].irq = irq; + + IDT::register_irq_handler(irq, s_bus_irqs[i].handler); + InterruptController::get().enable_irq(irq); + return; + } + } + ASSERT_NOT_REACHED(); + } + + ATABus* ATABus::create(ATAController* controller, uint16_t base, uint16_t ctrl, uint8_t irq) + { + ATABus* bus = new ATABus(controller, base, ctrl); + ASSERT(bus); + bus->initialize(irq); + return bus; + } + + void ATABus::initialize(uint8_t irq) + { + register_bus_irq_handler(this, irq); + + for (uint8_t i = 0; i < 2; i++) + { + m_devices[i] = new ATADevice(this); + ATADevice* device = m_devices[i]; + ASSERT(device); + + BAN::ScopeGuard guard([this, i] { m_devices[i]->unref(); m_devices[i] = nullptr; }); + + uint16_t identify_buffer[256]; + auto type = identify(device, identify_buffer); + if (type == DeviceType::None) + continue; + + auto res = device->initialize(type, identify_buffer); + if (res.is_error()) + { + dprintln("{}", res.error()); + continue; + } + + guard.disable(); + } + + // Enable disk interrupts + for (int i = 0; i < 2; i++) + { + if (!m_devices[i]) + continue; + select_device(m_devices[i]); + io_write(ATA_PORT_CONTROL, 0); + } + } + + void ATABus::select_device(const ATADevice* device) + { + uint8_t device_index = this->device_index(device); + io_write(ATA_PORT_DRIVE_SELECT, 0xA0 | (device_index << 4)); + PIT::sleep(1); + } + + ATABus::DeviceType ATABus::identify(const ATADevice* device, uint16_t* buffer) + { + select_device(device); + + // Disable interrupts + io_write(ATA_PORT_CONTROL, ATA_CONTROL_nIEN); + + io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY); + PIT::sleep(1); + + // No device on port + if (io_read(ATA_PORT_STATUS) == 0) + return DeviceType::None; + + DeviceType type = DeviceType::ATA; + + if (wait(true).is_error()) + { + uint8_t lba1 = io_read(ATA_PORT_LBA1); + uint8_t lba2 = io_read(ATA_PORT_LBA2); + + if (lba1 == 0x14 && lba2 == 0xEB) + type = DeviceType::ATAPI; + else if (lba1 == 0x69 && lba2 == 0x96) + type = DeviceType::ATAPI; + else + { + dprintln("Unsupported device type"); + return DeviceType::None; + } + + io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY_PACKET); + PIT::sleep(1); + + if (auto res = wait(true); res.is_error()) + { + dprintln("Fatal error: {}", res.error()); + return DeviceType::None; + } + } + + read_buffer(ATA_PORT_DATA, buffer, 256); + + return type; + } + + void ATABus::on_irq() + { + ASSERT(!m_has_got_irq); + if (io_read(ATA_PORT_STATUS) & ATA_STATUS_ERR) + dprintln("ATA Error: {}", error()); + m_has_got_irq = true; + m_semaphore.unblock(); + } + + void ATABus::block_until_irq() + { + if (!m_has_got_irq) + m_semaphore.block(); + m_has_got_irq = false; + } + + uint8_t ATABus::io_read(uint16_t port) + { + if (port <= 0x07) + return IO::inb(m_base + port); + if (0x10 <= port && port <= 0x11) + return IO::inb(m_ctrl + port - 0x10); + ASSERT_NOT_REACHED(); + } + + void ATABus::read_buffer(uint16_t port, uint16_t* buffer, size_t words) + { + if (port <= 0x07) + return IO::insw(m_base + port - 0x00, buffer, words); + if (0x10 <= port && port <= 0x11) + return IO::insw(m_ctrl + port - 0x10, buffer, words); + ASSERT_NOT_REACHED(); + } + + void ATABus::io_write(uint16_t port, uint8_t data) + { + if (port <= 0x07) + return IO::outb(m_base + port, data); + if (0x10 <= port && port <= 0x11) + return IO::outb(m_ctrl + port - 0x10, data); + ASSERT_NOT_REACHED(); + } + + void ATABus::write_buffer(uint16_t port, const uint16_t* buffer, size_t words) + { + uint16_t io_port = 0; + if (port <= 0x07) + io_port = m_base + port; + if (0x10 <= port && port <= 0x11) + io_port = m_ctrl + port - 0x10; + ASSERT(io_port); + for (size_t i = 0; i < words; i++) + IO::outw(io_port, buffer[i]); + } + + BAN::ErrorOr ATABus::wait(bool wait_drq) + { + for (uint32_t i = 0; i < 4; i++) + io_read(ATA_PORT_ALT_STATUS); + + uint8_t status = ATA_STATUS_BSY; + while (status & ATA_STATUS_BSY) + status = io_read(ATA_PORT_STATUS); + + while (wait_drq && !(status & ATA_STATUS_DRQ)) + { + if (status & ATA_STATUS_ERR) + return error(); + if (status & ATA_STATUS_DF) + return BAN::Error::from_errno(EIO); + status = io_read(ATA_PORT_STATUS); + } + + return {}; + } + + BAN::Error ATABus::error() + { + uint8_t err = io_read(ATA_PORT_ERROR); + if (err & ATA_ERROR_AMNF) + return BAN::Error::from_c_string("Address mark not found."); + if (err & ATA_ERROR_TKZNF) + return BAN::Error::from_c_string("Track zero not found."); + if (err & ATA_ERROR_ABRT) + return BAN::Error::from_c_string("Aborted command."); + if (err & ATA_ERROR_MCR) + return BAN::Error::from_c_string("Media change request."); + if (err & ATA_ERROR_IDNF) + return BAN::Error::from_c_string("ID not found."); + if (err & ATA_ERROR_MC) + return BAN::Error::from_c_string("Media changed."); + if (err & ATA_ERROR_UNC) + return BAN::Error::from_c_string("Uncorrectable data error."); + if (err & ATA_ERROR_BBK) + return BAN::Error::from_c_string("Bad Block detected."); + return BAN::Error::from_c_string("No error"); + } + + uint8_t ATABus::device_index(const ATADevice* device) const + { + ASSERT(device == m_devices[0] || device == m_devices[1]); + return (device == m_devices[0]) ? 0 : 1; + } + + BAN::ErrorOr ATABus::read(ATADevice* device, uint64_t lba, uint8_t sector_count, uint8_t* buffer) + { + if (lba + sector_count > device->m_lba_count) + return BAN::Error::from_c_string("Attempted to read outside of the device boundaries"); + + LockGuard _(m_lock); + + if (lba < (1 << 28)) + { + // LBA28 + io_write(ATA_PORT_DRIVE_SELECT, 0xE0 | (device_index(device) << 4) | ((lba >> 24) & 0x0F)); + io_write(ATA_PORT_SECTOR_COUNT, sector_count); + io_write(ATA_PORT_LBA0, (uint8_t)(lba >> 0)); + io_write(ATA_PORT_LBA1, (uint8_t)(lba >> 8)); + io_write(ATA_PORT_LBA2, (uint8_t)(lba >> 16)); + io_write(ATA_PORT_COMMAND, ATA_COMMAND_READ_SECTORS); + + for (uint32_t sector = 0; sector < sector_count; sector++) + { + block_until_irq(); + read_buffer(ATA_PORT_DATA, (uint16_t*)buffer + sector * device->m_sector_words, device->m_sector_words); + } + } + else + { + // LBA48 + ASSERT(false); + } + + return {}; + } + + BAN::ErrorOr ATABus::write(ATADevice* device, uint64_t lba, uint8_t sector_count, const uint8_t* buffer) + { + if (lba + sector_count > device->m_lba_count) + return BAN::Error::from_c_string("Attempted to write outside of the device boundaries"); + + LockGuard _(m_lock); + + if (lba < (1 << 28)) + { + // LBA28 + io_write(ATA_PORT_DRIVE_SELECT, 0xE0 | (device_index(device) << 4) | ((lba >> 24) & 0x0F)); + io_write(ATA_PORT_SECTOR_COUNT, sector_count); + io_write(ATA_PORT_LBA0, (uint8_t)(lba >> 0)); + io_write(ATA_PORT_LBA1, (uint8_t)(lba >> 8)); + io_write(ATA_PORT_LBA2, (uint8_t)(lba >> 16)); + io_write(ATA_PORT_COMMAND, ATA_COMMAND_WRITE_SECTORS); + + for (uint32_t sector = 0; sector < sector_count; sector++) + { + write_buffer(ATA_PORT_DATA, (uint16_t*)buffer + sector * device->m_sector_words, device->m_sector_words); + block_until_irq(); + } + } + else + { + // LBA48 + ASSERT(false); + } + + io_write(ATA_PORT_COMMAND, ATA_COMMAND_CACHE_FLUSH); + block_until_irq(); + + return {}; + } + +} \ No newline at end of file diff --git a/kernel/kernel/Storage/ATAController.cpp b/kernel/kernel/Storage/ATAController.cpp index 2a6bfd3d..70fae90f 100644 --- a/kernel/kernel/Storage/ATAController.cpp +++ b/kernel/kernel/Storage/ATAController.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -45,94 +46,30 @@ namespace Kernel buses[1].ctrl = pci_device.read_dword(0x1C) & 0xFFFFFFFC; } - for (uint8_t drive = 0; drive < 4; drive++) - { - auto device = ATADevice::create(this, buses[drive / 2].base, buses[drive / 2].ctrl, drive); - if (device.is_error()) - { - if (strlen(device.error().get_message()) > 0) - dprintln("{}", device.error()); - continue; - } - add_device(device.value()); - } - - for (StorageDevice* device_ : devices()) - { - ATADevice& device = *(ATADevice*)device_; - dprintln("Initialized drive {} ({} MiB) model {}", device.name(), device.total_size() / (1024 * 1024), device.model()); - } + m_buses[0] = ATABus::create(this, buses[0].base, buses[0].ctrl, 14); + m_buses[1] = ATABus::create(this, buses[1].base, buses[1].ctrl, 15); return {}; } - BAN::ErrorOr ATAController::read(ATADevice* device, uint64_t lba, uint8_t sector_count, uint8_t* buffer) + uint8_t ATAController::next_device_index() const { - if (lba + sector_count > device->m_lba_count) - return BAN::Error::from_c_string("Attempted to read outside of the device boundaries"); - - LockGuard _(m_lock); - - if (lba < (1 << 28)) - { - // LBA28 - TRY(device->wait(false)); - device->io_write(ATA_PORT_DRIVE_SELECT, 0xE0 | device->m_slave_bit | ((lba >> 24) & 0x0F)); - device->io_write(ATA_PORT_SECTOR_COUNT, sector_count); - device->io_write(ATA_PORT_LBA0, (uint8_t)(lba >> 0)); - device->io_write(ATA_PORT_LBA1, (uint8_t)(lba >> 8)); - device->io_write(ATA_PORT_LBA2, (uint8_t)(lba >> 16)); - device->io_write(ATA_PORT_COMMAND, ATA_COMMAND_READ_SECTORS); - - for (uint32_t sector = 0; sector < sector_count; sector++) - { - TRY(device->wait(true)); - device->read_buffer(ATA_PORT_DATA, (uint16_t*)buffer + sector * device->m_sector_words, device->m_sector_words); - } - } - else - { - // LBA48 - ASSERT(false); - } - - return {}; + static uint8_t index = 0; + return index++; } - BAN::ErrorOr ATAController::write(ATADevice* device, uint64_t lba, uint8_t sector_count, const uint8_t* buffer) + BAN::Vector ATAController::devices() { - if (lba + sector_count > device->m_lba_count) - return BAN::Error::from_c_string("Attempted to write outside of the device boundaries"); - - LockGuard _(m_lock); - - if (lba < (1 << 28)) - { - // LBA28 - TRY(device->wait(false)); - device->io_write(ATA_PORT_DRIVE_SELECT, 0xE0 | device->m_slave_bit | ((lba >> 24) & 0x0F)); - device->io_write(ATA_PORT_SECTOR_COUNT, sector_count); - device->io_write(ATA_PORT_LBA0, (uint8_t)(lba >> 0)); - device->io_write(ATA_PORT_LBA1, (uint8_t)(lba >> 8)); - device->io_write(ATA_PORT_LBA2, (uint8_t)(lba >> 16)); - device->io_write(ATA_PORT_COMMAND, ATA_COMMAND_WRITE_SECTORS); - - for (uint32_t sector = 0; sector < sector_count; sector++) - { - TRY(device->wait(false)); - device->write_buffer(ATA_PORT_DATA, (uint16_t*)buffer + sector * device->m_sector_words, device->m_sector_words); - } - } - else - { - // LBA48 - ASSERT(false); - } - - TRY(device->wait(false)); - device->io_write(ATA_PORT_COMMAND, ATA_COMMAND_CACHE_FLUSH); - - return {}; + BAN::Vector devices; + if (m_buses[0]->m_devices[0]) + MUST(devices.push_back(m_buses[0]->m_devices[0])); + if (m_buses[0]->m_devices[1]) + MUST(devices.push_back(m_buses[0]->m_devices[1])); + if (m_buses[1]->m_devices[0]) + MUST(devices.push_back(m_buses[1]->m_devices[0])); + if (m_buses[1]->m_devices[1]) + MUST(devices.push_back(m_buses[1]->m_devices[1])); + return devices; } } \ No newline at end of file diff --git a/kernel/kernel/Storage/ATADevice.cpp b/kernel/kernel/Storage/ATADevice.cpp index 6bc88977..b4cde8f0 100644 --- a/kernel/kernel/Storage/ATADevice.cpp +++ b/kernel/kernel/Storage/ATADevice.cpp @@ -1,81 +1,30 @@ -#include #include -#include +#include #include #include namespace Kernel { - BAN::ErrorOr ATADevice::create(ATAController* controller, uint16_t base, uint16_t ctrl, uint8_t index) + BAN::ErrorOr ATADevice::initialize(ATABus::DeviceType type, const uint16_t* identify_buffer) { - ATADevice* device = new ATADevice(controller, base, ctrl, index); - if (device == nullptr) - return BAN::Error::from_errno(ENOMEM); - BAN::ScopeGuard guard([device] { device->unref(); }); - TRY(device->initialize()); - guard.disable(); - return device; - } + m_type = type; - BAN::ErrorOr ATADevice::initialize() - { - io_write(ATA_PORT_CONTROL, ATA_CONTROL_nIEN); + m_signature = identify_buffer[ATA_IDENTIFY_SIGNATURE]; + m_capabilities = identify_buffer[ATA_IDENTIFY_CAPABILITIES]; - io_write(ATA_PORT_DRIVE_SELECT, 0xA0 | m_slave_bit); - PIT::sleep(1); - - io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY); - PIT::sleep(1); - - if (io_read(ATA_PORT_STATUS) == 0) - return BAN::Error::from_c_string(""); - - uint8_t status = 0; - while (true) - { - status = io_read(ATA_PORT_STATUS); - if (status & ATA_STATUS_ERR) - break; - if (!(status & ATA_STATUS_BSY) && (status && ATA_STATUS_DRQ)) - break; - } - - if (status & ATA_STATUS_ERR) - { - uint8_t lba1 = io_read(ATA_PORT_LBA1); - uint8_t lba2 = io_read(ATA_PORT_LBA2); - - if (lba1 == 0x14 && lba2 == 0xEB) - m_type = ATADevice::DeviceType::ATAPI; - else if (lba1 == 0x69 && lba2 == 0x96) - m_type = ATADevice::DeviceType::ATAPI; - else - return BAN::Error::from_c_string("Not ATA/ATAPI device"); - - io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY_PACKET); - PIT::sleep(1); - } - else - { - m_type = ATADevice::DeviceType::ATA; - } - - uint16_t buffer[256] {}; - read_buffer(ATA_PORT_DATA, buffer, 256); - - m_signature = *(uint16_t*)(buffer + ATA_IDENTIFY_SIGNATURE); - m_capabilities = *(uint16_t*)(buffer + ATA_IDENTIFY_CAPABILITIES); - m_command_set = *(uint32_t*)(buffer + ATA_IDENTIFY_COMMAND_SET); + m_command_set = 0; + m_command_set |= (uint32_t)(identify_buffer[ATA_IDENTIFY_COMMAND_SET + 0] << 0); + m_command_set |= (uint32_t)(identify_buffer[ATA_IDENTIFY_COMMAND_SET + 1] << 16); if (!(m_capabilities & ATA_CAPABILITIES_LBA)) return BAN::Error::from_c_string("Device does not support LBA addressing"); - - if ((buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 15)) == 0 && - (buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 14)) != 0 && - (buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 12)) != 0) + + if ((identify_buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 15)) == 0 && + (identify_buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 14)) != 0 && + (identify_buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 12)) != 0) { - m_sector_words = *(uint32_t*)(buffer + ATA_IDENTIFY_SECTOR_WORDS); + m_sector_words = *(uint32_t*)(identify_buffer + ATA_IDENTIFY_SECTOR_WORDS); } else { @@ -84,127 +33,41 @@ namespace Kernel m_lba_count = 0; if (m_command_set & ATA_COMMANDSET_LBA48_SUPPORTED) - m_lba_count = *(uint64_t*)(buffer + ATA_IDENTIFY_LBA_COUNT_EXT); + m_lba_count = *(uint64_t*)(identify_buffer + ATA_IDENTIFY_LBA_COUNT_EXT); if (m_lba_count < (1 << 28)) - m_lba_count = *(uint32_t*)(buffer + ATA_IDENTIFY_LBA_COUNT); + m_lba_count = *(uint32_t*)(identify_buffer + ATA_IDENTIFY_LBA_COUNT); for (int i = 0; i < 20; i++) { - uint16_t word = buffer[ATA_IDENTIFY_MODEL + i]; + uint16_t word = identify_buffer[ATA_IDENTIFY_MODEL + i]; m_model[2 * i + 0] = word >> 8; m_model[2 * i + 1] = word & 0xFF; } m_model[40] = 0; - + + m_index = m_bus->controller()->next_device_index(); m_device_name[0] = 'h'; m_device_name[1] = 'd'; m_device_name[2] = 'a' + m_index; m_device_name[3] = '\0'; - TRY(initialize_partitions()); + dprintln("{} {} MB", m_device_name, total_size() / 1024 / 1024); + return {}; } BAN::ErrorOr ATADevice::read_sectors(uint64_t lba, uint8_t sector_count, uint8_t* buffer) { - TRY(m_controller->read(this, lba, sector_count, buffer)); + TRY(m_bus->read(this, lba, sector_count, buffer)); return {}; } BAN::ErrorOr ATADevice::write_sectors(uint64_t lba, uint8_t sector_count, const uint8_t* buffer) { - TRY(m_controller->write(this, lba, sector_count, buffer)); + TRY(m_bus->write(this, lba, sector_count, buffer)); return {}; } - uint8_t ATADevice::io_read(uint16_t port) - { - if (port <= 0x07) - return IO::inb(m_base + port); - if (0x10 <= port && port <= 0x11) - return IO::inb(m_ctrl + port - 0x10); - ASSERT_NOT_REACHED(); - } - - void ATADevice::read_buffer(uint16_t port, uint16_t* buffer, size_t words) - { - if (port <= 0x07) - return IO::insw(m_base + port - 0x00, buffer, words); - if (0x10 <= port && port <= 0x11) - return IO::insw(m_ctrl + port - 0x10, buffer, words); - ASSERT_NOT_REACHED(); - } - - void ATADevice::io_write(uint16_t port, uint8_t data) - { - if (port <= 0x07) - return IO::outb(m_base + port, data); - if (0x10 <= port && port <= 0x11) - return IO::outb(m_ctrl + port - 0x10, data); - ASSERT_NOT_REACHED(); - } - - void ATADevice::write_buffer(uint16_t port, const uint16_t* buffer, size_t words) - { - uint16_t io_port = 0; - if (port <= 0x07) - io_port = m_base + port; - if (0x10 <= port && port <= 0x11) - io_port = m_ctrl + port - 0x10; - ASSERT(io_port); - for (size_t i = 0; i < words; i++) - IO::outw(io_port, buffer[i]); - } - - BAN::ErrorOr ATADevice::wait(bool wait_drq) - { - for (uint32_t i = 0; i < 4; i++) - io_read(ATA_PORT_ALT_STATUS); - - uint8_t status = ATA_STATUS_BSY; - while (status & ATA_STATUS_BSY) - status = io_read(ATA_PORT_STATUS); - - while (wait_drq && !(status & ATA_STATUS_DRQ)) - { - if (status & ATA_STATUS_ERR) - return error(); - if (status & ATA_STATUS_DF) - return BAN::Error::from_errno(EIO); - status = io_read(ATA_PORT_STATUS); - } - - return {}; - } - - BAN::Error ATADevice::error() - { - uint8_t err = io_read(ATA_PORT_ERROR); - if (err & ATA_ERROR_AMNF) - return BAN::Error::from_c_string("Address mark not found."); - if (err & ATA_ERROR_TKZNF) - return BAN::Error::from_c_string("Track zero not found."); - if (err & ATA_ERROR_ABRT) - return BAN::Error::from_c_string("Aborted command."); - if (err & ATA_ERROR_MCR) - return BAN::Error::from_c_string("Media change request."); - if (err & ATA_ERROR_IDNF) - return BAN::Error::from_c_string("ID not found."); - if (err & ATA_ERROR_MC) - return BAN::Error::from_c_string("Media changed."); - if (err & ATA_ERROR_UNC) - return BAN::Error::from_c_string("Uncorrectable data error."); - if (err & ATA_ERROR_BBK) - return BAN::Error::from_c_string("Bad Block detected."); - ASSERT_NOT_REACHED(); - } - - dev_t ATADevice::dev() const - { - ASSERT(m_controller); - return m_controller->dev(); - } - BAN::ErrorOr ATADevice::read(size_t offset, void* buffer, size_t bytes) { if (offset % sector_size() || bytes % sector_size())