From ee5d02aa70d2c1b51a8dd47a1a9550061ac3a2bc Mon Sep 17 00:00:00 2001 From: Bananymous Date: Sun, 26 Feb 2023 03:00:29 +0200 Subject: [PATCH] Kernel: Rewrite basically all current disk io stuff This is a big commit that was kinda hard to split to smaller ones. Essentially we now look at all the mass storage devices from PCI and initialize (P)ATA devices. This doesn't provide any more functionality but better abstractions and everything doesn't have to be on its old default port that might be different for modern computers. --- kernel/Makefile | 5 +- kernel/include/kernel/ATA.h | 61 ---- kernel/include/kernel/FS/Ext2.h | 8 +- kernel/include/kernel/FS/VirtualFileSystem.h | 10 +- kernel/include/kernel/Storage/ATAController.h | 67 ++++ .../kernel/Storage/StorageController.h | 19 ++ .../{DiskIO.h => Storage/StorageDevice.h} | 34 +-- kernel/kernel/ATA.cpp | 245 --------------- kernel/kernel/FS/Ext2.cpp | 14 +- kernel/kernel/FS/VirtualFileSystem.cpp | 93 +++++- kernel/kernel/Storage/ATAController.cpp | 287 ++++++++++++++++++ .../{DiskIO.cpp => Storage/StorageDevice.cpp} | 181 ++++------- kernel/kernel/kernel.cpp | 21 +- 13 files changed, 570 insertions(+), 475 deletions(-) delete mode 100644 kernel/include/kernel/ATA.h create mode 100644 kernel/include/kernel/Storage/ATAController.h create mode 100644 kernel/include/kernel/Storage/StorageController.h rename kernel/include/kernel/{DiskIO.h => Storage/StorageDevice.h} (57%) delete mode 100644 kernel/kernel/ATA.cpp create mode 100644 kernel/kernel/Storage/ATAController.cpp rename kernel/kernel/{DiskIO.cpp => Storage/StorageDevice.cpp} (61%) diff --git a/kernel/Makefile b/kernel/Makefile index 7ca2ef1082..4087db1a4d 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -33,11 +33,9 @@ KERNEL_OBJS= \ $(KERNEL_ARCH_OBJS) \ font/prefs.o \ kernel/APIC.o \ -kernel/ATA.o \ kernel/build_libc.o \ kernel/CPUID.o \ kernel/Debug.o \ -kernel/DiskIO.o \ kernel/Font.o \ kernel/FS/Ext2.o \ kernel/FS/VirtualFileSystem.o \ @@ -54,6 +52,8 @@ kernel/Serial.o \ kernel/Shell.o \ kernel/SpinLock.o \ kernel/SSP.o \ +kernel/Storage/ATAController.o \ +kernel/Storage/StorageDevice.o \ kernel/Thread.o \ kernel/TTY.o \ kernel/VesaTerminalDriver.o \ @@ -103,6 +103,7 @@ always: mkdir -p $(BUILDDIR)/$(ARCHDIR) mkdir -p $(BUILDDIR)/kernel mkdir -p $(BUILDDIR)/kernel/FS + mkdir -p $(BUILDDIR)/kernel/Storage mkdir -p $(BUILDDIR)/font clean: diff --git a/kernel/include/kernel/ATA.h b/kernel/include/kernel/ATA.h deleted file mode 100644 index ac731204d1..0000000000 --- a/kernel/include/kernel/ATA.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include -#include - -namespace Kernel -{ - - class ATADevice : public DiskDevice - { - public: - static ATADevice* create(uint16_t io_base, uint16_t ctl_base, uint8_t slave_bit); - - virtual ~ATADevice() {} - - uint16_t io_base() const { return m_io_base; } - uint16_t ctl_base() const { return m_ctl_base; } - uint8_t slave_bit() const { return m_slave_bit; } - virtual const char* type() const = 0; - - protected: - ATADevice(uint16_t io_base, uint16_t ctl_base, uint8_t slave_bit) - : m_io_base(io_base) - , m_ctl_base(ctl_base) - , m_slave_bit(slave_bit) - {} - - private: - const uint16_t m_io_base; - const uint16_t m_ctl_base; - const uint8_t m_slave_bit; - }; - - class PATADevice final : public ATADevice - { - public: - PATADevice(uint16_t io_base, uint16_t ctl_base, uint8_t slave_bit) - : ATADevice(io_base, ctl_base, slave_bit) - {} - - virtual uint32_t sector_size() const override { return m_sector_words * 2; } - virtual const char* type() const override { return "PATA"; } - - virtual bool read_sectors(uint32_t lba, uint32_t sector_count, uint8_t* buffer) override; - - protected: - virtual bool initialize() override; - - private: - bool read_lba28(uint32_t lba, uint8_t sector_count, uint8_t* buffer); - bool wait_while_buzy(); - bool wait_for_transfer(); - void flush(); - - private: - bool m_lba_48 = false; - uint32_t m_sector_words = 256; - }; - - -} diff --git a/kernel/include/kernel/FS/Ext2.h b/kernel/include/kernel/FS/Ext2.h index cb19af8a1c..0931b9bc7f 100644 --- a/kernel/include/kernel/FS/Ext2.h +++ b/kernel/include/kernel/FS/Ext2.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include namespace Kernel @@ -156,12 +156,12 @@ namespace Kernel class Ext2FS : public FileSystem { public: - static BAN::ErrorOr create(DiskDevice::Partition&); + static BAN::ErrorOr create(StorageDevice::Partition&); virtual const BAN::RefCounted root_inode() const override { return m_root_inode; } private: - Ext2FS(DiskDevice::Partition& partition) + Ext2FS(StorageDevice::Partition& partition) : m_partition(partition) {} @@ -177,7 +177,7 @@ namespace Kernel const Ext2::Inode& ext2_root_inode() const; private: - DiskDevice::Partition& m_partition; + StorageDevice::Partition& m_partition; BAN::RefCounted m_root_inode; diff --git a/kernel/include/kernel/FS/VirtualFileSystem.h b/kernel/include/kernel/FS/VirtualFileSystem.h index 027cc54d7e..6725b45aab 100644 --- a/kernel/include/kernel/FS/VirtualFileSystem.h +++ b/kernel/include/kernel/FS/VirtualFileSystem.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace Kernel { @@ -8,7 +9,7 @@ namespace Kernel class VirtualFileSystem : public FileSystem { public: - static void initialize(BAN::RefCounted root_inode); + static BAN::ErrorOr initialize(); static VirtualFileSystem& get(); static bool is_initialized(); @@ -17,12 +18,13 @@ namespace Kernel BAN::ErrorOr> from_absolute_path(BAN::StringView); private: - VirtualFileSystem(BAN::RefCounted root_inode) - : m_root_inode(root_inode) - {} + VirtualFileSystem() = default; + BAN::ErrorOr initialize_impl(); private: BAN::RefCounted m_root_inode; + + BAN::Vector m_storage_controllers; }; } \ No newline at end of file diff --git a/kernel/include/kernel/Storage/ATAController.h b/kernel/include/kernel/Storage/ATAController.h new file mode 100644 index 0000000000..34c64a16a9 --- /dev/null +++ b/kernel/include/kernel/Storage/ATAController.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include + +namespace Kernel +{ + + struct ATABus; + + class ATADevice : public StorageDevice + { + public: + virtual BAN::ErrorOr read_sectors(uint64_t, uint8_t, uint8_t*) override; + virtual uint32_t sector_size() const override { return sector_words * 2; } + virtual uint64_t total_size() const override { return lba_count * sector_size(); } + + private: + enum class Type + { + Unknown, + ATA, + ATAPI, + }; + + Type type; + uint8_t slave_bit; // 0x00 for master, 0x10 for slave + uint16_t signature; + uint16_t capabilities; + uint32_t command_set; + uint32_t sector_words; + uint64_t lba_count; + char model[41]; + + ATABus* bus; + + friend class ATAController; + }; + + struct ATABus + { + uint16_t base; + uint16_t ctrl; + ATADevice devices[2]; + + uint8_t read(uint16_t); + void read_buffer(uint16_t, uint16_t*, size_t); + void write(uint16_t, uint8_t); + BAN::ErrorOr wait(bool); + BAN::Error error(); + }; + + class ATAController : public StorageController + { + public: + static BAN::ErrorOr create(const PCIDevice&); + + private: + ATAController(const PCIDevice& device) : m_pci_device(device) {} + BAN::ErrorOr initialize(); + + private: + ATABus m_buses[2]; + const PCIDevice& m_pci_device; + }; + +} \ No newline at end of file diff --git a/kernel/include/kernel/Storage/StorageController.h b/kernel/include/kernel/Storage/StorageController.h new file mode 100644 index 0000000000..0f9309b319 --- /dev/null +++ b/kernel/include/kernel/Storage/StorageController.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +namespace Kernel +{ + + class StorageController + { + public: + BAN::Vector& devices() { return m_devices; } + const BAN::Vector& devices() const { return m_devices; } + + protected: + BAN::Vector m_devices; + }; + +} \ No newline at end of file diff --git a/kernel/include/kernel/DiskIO.h b/kernel/include/kernel/Storage/StorageDevice.h similarity index 57% rename from kernel/include/kernel/DiskIO.h rename to kernel/include/kernel/Storage/StorageDevice.h index e8eadbf585..f333d21c94 100644 --- a/kernel/include/kernel/DiskIO.h +++ b/kernel/include/kernel/Storage/StorageDevice.h @@ -13,12 +13,12 @@ namespace Kernel uint8_t data4[8]; }; - class DiskDevice + class StorageDevice { public: struct Partition { - Partition(DiskDevice&, const GUID&, const GUID&, uint64_t, uint64_t, uint64_t, const char*); + Partition(StorageDevice&, const GUID&, const GUID&, uint64_t, uint64_t, uint64_t, const char*); const GUID& type() const { return m_type; } const GUID& guid() const { return m_guid; } @@ -26,29 +26,29 @@ namespace Kernel uint64_t lba_end() const { return m_lba_end; } uint64_t attributes() const { return m_attributes; } const char* name() const { return m_name; } - const DiskDevice& device() const { return m_device; } + const StorageDevice& device() const { return m_device; } - bool read_sectors(uint32_t lba, uint32_t sector_count, uint8_t* buffer); + BAN::ErrorOr read_sectors(uint64_t lba, uint8_t sector_count, uint8_t* buffer); bool is_used() const { uint8_t zero[16] {}; return memcmp(&m_type, zero, 16); } private: - DiskDevice& m_device; + StorageDevice& m_device; const GUID m_type; const GUID m_guid; const uint64_t m_lba_start; const uint64_t m_lba_end; const uint64_t m_attributes; - char m_name[72]; + char m_name[36 * 3 + 1]; }; public: - virtual ~DiskDevice() {} + virtual ~StorageDevice() {} - virtual bool initialize() = 0; - bool initialize_partitions(); + BAN::ErrorOr initialize_partitions(); - virtual bool read_sectors(uint32_t lba, uint32_t sector_count, uint8_t* buffer) = 0; + virtual BAN::ErrorOr read_sectors(uint64_t lba, uint8_t sector_count, uint8_t* buffer) = 0; virtual uint32_t sector_size() const = 0; + virtual uint64_t total_size() const = 0; BAN::Vector& partitions() { return m_partitions; } @@ -56,18 +56,4 @@ namespace Kernel BAN::Vector m_partitions; }; - class DiskIO - { - public: - static bool initialize(); - static DiskIO& get(); - - private: - DiskIO(); - void try_add_device(DiskDevice*); - - private: - BAN::Vector m_devices; - }; - } \ No newline at end of file diff --git a/kernel/kernel/ATA.cpp b/kernel/kernel/ATA.cpp deleted file mode 100644 index a83628518e..0000000000 --- a/kernel/kernel/ATA.cpp +++ /dev/null @@ -1,245 +0,0 @@ -#include -#include -#include -#include - -#include -#include - -#define ATA_IO_PORT_DATA 0 -#define ATA_IO_PORT_ERROR 1 -#define ATA_IO_PORT_FEATURES 1 -#define ATA_IO_PORT_SECTOR_COUNT 2 -#define ATA_IO_PORT_LBA_LOW 3 -#define ATA_IO_PORT_LBA_MID 4 -#define ATA_IO_PORT_LBA_HIGH 5 -#define ATA_IO_PORT_DRIVE_SELECT 6 -#define ATA_IO_PORT_STATUS 7 -#define ATA_IO_PORT_COMMAND 7 - -#define ATA_CTL_PORT_STATUS 0 -#define ATA_CTL_PORT_CONTROL 0 -#define ATA_CTL_PORT_ADDRESS 1 - -#define ATA_COMMAND_READ_SECTORS 0x20 -#define ATA_COMMAND_IDENTIFY 0xEC -#define ATA_COMMAND_FLUSH 0xE7 - -#define ATA_STATUS_ERR (1 << 0) -#define ATA_STATUS_DRQ (1 << 3) -#define ATA_STATUS_DF (1 << 3) -#define ATA_STATUS_BSY (1 << 7) - -#define ATA_DEBUG_PRINT 0 - -namespace Kernel -{ - - enum class ATADeviceType - { - UNKNOWN, - PATA, - PATAPI, - SATA, - SATAPI, - }; - - static void soft_reset(uint16_t ctl_base) - { - IO::outb(ctl_base + ATA_CTL_PORT_CONTROL, 0b00000110); - PIT::sleep(2); - IO::outb(ctl_base + ATA_CTL_PORT_CONTROL, 0b00000010); - PIT::sleep(2); - } - - static ATADeviceType detect_device_type(uint16_t io_base, uint16_t ctl_base, uint8_t slave_bit) - { - soft_reset(ctl_base); - - IO::outb(io_base + ATA_IO_PORT_DRIVE_SELECT, 0xA0 | slave_bit); - PIT::sleep(2); - - uint8_t lba_mid = IO::inb(io_base + ATA_IO_PORT_LBA_MID); - uint8_t lba_high = IO::inb(io_base + ATA_IO_PORT_LBA_HIGH); - if (lba_mid == 0x00 && lba_high == 0x00) - return ATADeviceType::PATA; - if (lba_mid == 0x14 && lba_high == 0xEB) - return ATADeviceType::PATAPI; - if (lba_mid == 0x3C && lba_high == 0xC3) - return ATADeviceType::SATA; - if (lba_mid == 0x69 && lba_high == 0x96) - return ATADeviceType::SATAPI; - return ATADeviceType::UNKNOWN; - } - - ATADevice* ATADevice::create(uint16_t io_base, uint16_t ctl_base, uint8_t slave_bit) - { - uint8_t status = IO::inb(io_base + ATA_IO_PORT_STATUS); - if (status == 0xFF) - return nullptr; - - ATADeviceType type = detect_device_type(io_base, ctl_base, slave_bit); - if (type == ATADeviceType::UNKNOWN) - return nullptr; - - ATADevice* ata_device = nullptr; - switch (type) - { - case ATADeviceType::PATA: - ata_device = new PATADevice(io_base, ctl_base, slave_bit); - break; - case ATADeviceType::PATAPI: -#if ATA_DEBUG_PRINT - dwarnln("Unsupported PATAPI device"); -#endif - break; - case ATADeviceType::SATA: -#if ATA_DEBUG_PRINT - dwarnln("Unsupported SATA device"); -#endif - break; - case ATADeviceType::SATAPI: -#if ATA_DEBUG_PRINT - dwarnln("Unsupported SATAPI device"); -#endif - break; - case ATADeviceType::UNKNOWN: - break; - } - - if (ata_device && !ata_device->initialize()) - { - delete ata_device; - ata_device = nullptr; - } - - return ata_device; - } - - bool PATADevice::initialize() - { - IO::outb(io_base() + ATA_IO_PORT_COMMAND, ATA_COMMAND_IDENTIFY); - if (!wait_while_buzy() || !wait_for_transfer()) - return false; - - uint16_t response[256]; - for (int i = 0; i < 256; i++) - response[i] = IO::inw(io_base() + ATA_IO_PORT_DATA); - - m_lba_48 = response[83] & (1 << 10); - - if (!(response[106] & (1 << 15)) - && (response[106] & (1 << 14)) - && (response[106] & (1 << 12))) - { - m_sector_words = ((uint32_t)response[117] << 16) | response[118]; - dprintln("using {} sector size", m_sector_words * 2); - } - - return true; - } - - bool PATADevice::read_sectors(uint32_t lba, uint32_t sector_count, uint8_t* buffer) - { - return read_lba28(lba, sector_count, buffer); - } - - bool PATADevice::read_lba28(uint32_t lba, uint8_t sector_count, uint8_t* buffer) - { - // 1. Send 0xE0 for the "master" or 0xF0 for the "slave", ORed with the highest 4 bits of the LBA to port 0x1F6: - // outb(0x1F6, 0xE0 | (slavebit << 4) | ((LBA >> 24) & 0x0F)) - IO::outb(io_base() + ATA_IO_PORT_DRIVE_SELECT, 0xE0 | slave_bit() | ((lba >> 24) & 0xF)); - - // 2. Send a NULL byte to port 0x1F1, if you like (it is ignored and wastes lots of CPU time): outb(0x1F1, 0x00) - - // 3. Send the sectorcount to port 0x1F2: outb(0x1F2, (unsigned char) count) - IO::outb(io_base() + ATA_IO_PORT_SECTOR_COUNT, sector_count); - - // 4. Send the low 8 bits of the LBA to port 0x1F3: outb(0x1F3, (unsigned char) LBA)) - IO::outb(io_base() + ATA_IO_PORT_LBA_LOW, lba & 0xFF); - - // 5. Send the next 8 bits of the LBA to port 0x1F4: outb(0x1F4, (unsigned char)(LBA >> 8)) - IO::outb(io_base() + ATA_IO_PORT_LBA_MID, (lba >> 8) & 0xFF); - - // 6. Send the next 8 bits of the LBA to port 0x1F5: outb(0x1F5, (unsigned char)(LBA >> 16)) - IO::outb(io_base() + ATA_IO_PORT_LBA_HIGH, (lba >> 16) & 0xFF); - - // 7. Send the "READ SECTORS" command (0x20) to port 0x1F7: outb(0x1F7, 0x20) - IO::outb(io_base() + ATA_IO_PORT_COMMAND, ATA_COMMAND_READ_SECTORS); - - memset(buffer, 0, sector_count * m_sector_words * sizeof(uint16_t)); - for (int i = 0; i < sector_count; i++) - { - // 8. Wait for an IRQ or poll. - if (!wait_while_buzy() || !wait_for_transfer()) - return false; - - // 9. Transfer 256 16-bit values, a uint16_t at a time, into your buffer from I/O port 0x1F0. - // (In assembler, REP INSW works well for this.) - for (size_t j = 0; j < m_sector_words; j++) - { - uint16_t word = IO::inw(io_base() + ATA_IO_PORT_DATA); - buffer[(i * m_sector_words + j) * 2 + 0] = word & 0xFF; - buffer[(i * m_sector_words + j) * 2 + 1] = word >> 8; - } - - // 10. Then loop back to waiting for the next IRQ (or poll again -- see next note) for each successive sector. - } - - return true; - } - - bool PATADevice::wait_while_buzy() - { - uint64_t timeout = PIT::ms_since_boot() + 1000; - while (IO::inb(ctl_base() + ATA_CTL_PORT_STATUS) & ATA_STATUS_BSY) - { - if (PIT::ms_since_boot() > timeout) - { -#if ATA_DEBUG_PRINT - dwarnln("timeout on device 0x{3H} slave: {}", io_base(), !!slave_bit()); -#endif - return false; - } - } - return true; - } - - bool PATADevice::wait_for_transfer() - { - uint8_t status; - uint64_t timeout = PIT::ms_since_boot() + 1000; - while (!((status = IO::inb(ctl_base() + ATA_CTL_PORT_STATUS)) & ATA_STATUS_DRQ)) - { - if (status & ATA_STATUS_ERR) - { -#if ATA_DEBUG_PRINT - dwarnln("error on device 0x{3H} slave: {}", io_base(), !!slave_bit()); -#endif - return false; - } - if (status & ATA_STATUS_DF) - { -#if ATA_DEBUG_PRINT - dwarnln("drive fault on device 0x{3H} slave: {}", io_base(), !!slave_bit()); -#endif - return false; - } - if (PIT::ms_since_boot() > timeout) - { -#if ATA_DEBUG_PRINT - dwarnln("timeout on device 0x{3H} slave: {}", io_base(), !!slave_bit()); -#endif - return false; - } - } - return true; - } - - void PATADevice::flush() - { - IO::outb(io_base() + ATA_IO_PORT_COMMAND, ATA_COMMAND_FLUSH); - wait_while_buzy(); - } - -} diff --git a/kernel/kernel/FS/Ext2.cpp b/kernel/kernel/FS/Ext2.cpp index f7f1165405..4036c73976 100644 --- a/kernel/kernel/FS/Ext2.cpp +++ b/kernel/kernel/FS/Ext2.cpp @@ -318,7 +318,7 @@ namespace Kernel return inodes; } - BAN::ErrorOr Ext2FS::create(DiskDevice::Partition& partition) + BAN::ErrorOr Ext2FS::create(StorageDevice::Partition& partition) { Ext2FS* ext2fs = new Ext2FS(partition); if (ext2fs == nullptr) @@ -344,8 +344,7 @@ namespace Kernel uint32_t lba = 1024 / sector_size; uint32_t sector_count = 1024 / sector_size; - if (!m_partition.read_sectors(lba, sector_count, superblock_buffer)) - return BAN::Error::from_string("Could not read from partition"); + TRY(m_partition.read_sectors(lba, sector_count, superblock_buffer)); memcpy(&m_superblock, superblock_buffer, sizeof(Ext2::Superblock)); } @@ -398,13 +397,11 @@ namespace Kernel return BAN::Error::from_string("Could not allocate memory for block group descriptor table"); BAN::ScopeGuard _([block_group_descriptor_table_buffer] { kfree(block_group_descriptor_table_buffer); }); - if (!m_partition.read_sectors( + TRY(m_partition.read_sectors( block_group_descriptor_table_block * sectors_per_block, block_group_descriptor_table_sector_count, block_group_descriptor_table_buffer - )) - return BAN::Error::from_string("Could not read from partition"); - + )); TRY(m_block_group_descriptors.resize(number_of_block_groups)); for (uint32_t i = 0; i < number_of_block_groups; i++) @@ -464,8 +461,7 @@ namespace Kernel BAN::Vector block_buffer; TRY(block_buffer.resize(block_size)); - if (!m_partition.read_sectors(block * sectors_per_block, sectors_per_block, block_buffer.data())) - return BAN::Error::from_string("Could not read from partition"); + TRY(m_partition.read_sectors(block * sectors_per_block, sectors_per_block, block_buffer.data())); return block_buffer; } diff --git a/kernel/kernel/FS/VirtualFileSystem.cpp b/kernel/kernel/FS/VirtualFileSystem.cpp index 1e4f6efa87..47b4c31aa7 100644 --- a/kernel/kernel/FS/VirtualFileSystem.cpp +++ b/kernel/kernel/FS/VirtualFileSystem.cpp @@ -1,17 +1,22 @@ #include #include +#include #include +#include +#include namespace Kernel { static VirtualFileSystem* s_instance = nullptr; - void VirtualFileSystem::initialize(BAN::RefCounted root_inode) + BAN::ErrorOr VirtualFileSystem::initialize() { ASSERT(s_instance == nullptr); - s_instance = new VirtualFileSystem(root_inode); - ASSERT(s_instance); + s_instance = new VirtualFileSystem(); + if (s_instance == nullptr) + return BAN::Error::from_string("Could not allocate the Virtual File System"); + return s_instance->initialize_impl(); } VirtualFileSystem& VirtualFileSystem::get() @@ -25,6 +30,88 @@ namespace Kernel return s_instance != nullptr; } + BAN::ErrorOr VirtualFileSystem::initialize_impl() + { + // Initialize all storage controllers + for (auto& device : PCI::get().devices()) + { + if (device.class_code != 0x01) + continue; + + switch (device.subclass) + { + case 0x0: + dwarnln("unsupported SCSI Bus Controller"); + break; + case 0x1: + case 0x5: + TRY(m_storage_controllers.push_back(TRY(ATAController::create(device)))); + break; + case 0x2: + dwarnln("unsupported Floppy Disk Controller"); + break; + case 0x3: + dwarnln("unsupported IPI Bus Controller"); + break; + case 0x4: + dwarnln("unsupported RAID Controller"); + break; + case 0x6: + dwarnln("unsupported Serial ATA Controller"); + break; + case 0x7: + dwarnln("unsupported Serial Attached SCSI Controller"); + break; + case 0x8: + dwarnln("unsupported Non-Volatile Memory Controller"); + break; + case 0x80: + dwarnln("unsupported Unknown Storage Controller"); + break; + } + } + + // Initialize partitions on all devices on found controllers + for (auto controller : m_storage_controllers) + { + for (auto device : controller->devices()) + { + if (device->total_size() == 0) + continue; + + auto result = device->initialize_partitions(); + if (result.is_error()) + { + dwarnln("{}", result.error()); + continue; + } + + for (auto& partition : device->partitions()) + { + if (partition.name() == "banan-root"_sv) + { + if (m_root_inode) + dwarnln("multiple root partitions found"); + else + { + auto ext2fs_or_error = Ext2FS::create(partition); + if (ext2fs_or_error.is_error()) + dwarnln("{}", ext2fs_or_error.error()); + else + // FIXME: We leave a dangling pointer to ext2fs. This might be okay since + // root fs sould probably be always mounted + m_root_inode = ext2fs_or_error.release_value()->root_inode(); + } + } + } + } + } + + if (m_root_inode) + return {}; + return BAN::Error::from_string("Could not locate root partition"); + } + BAN::ErrorOr> VirtualFileSystem::from_absolute_path(BAN::StringView path) { if (path.front() != '/') diff --git a/kernel/kernel/Storage/ATAController.cpp b/kernel/kernel/Storage/ATAController.cpp new file mode 100644 index 0000000000..f7aa74b6ea --- /dev/null +++ b/kernel/kernel/Storage/ATAController.cpp @@ -0,0 +1,287 @@ +#include +#include + +#include + +#define ATA_PRIMARY 0 +#define ATA_SECONDARY 1 + +#define ATA_PORT_DATA 0x00 +#define ATA_PORT_ERROR 0x00 +#define ATA_PORT_SECTOR_COUNT 0x02 +#define ATA_PORT_LBA0 0x03 +#define ATA_PORT_LBA1 0x04 +#define ATA_PORT_LBA2 0x05 +#define ATA_PORT_DRIVE_SELECT 0x06 +#define ATA_PORT_COMMAND 0x07 +#define ATA_PORT_STATUS 0x07 + +#define ATA_PORT_CONTROL 0x10 +#define ATA_PORT_ALT_STATUS 0x10 + +#define ATA_ERROR_AMNF 0x01 +#define ATA_ERROR_TKZNF 0x02 +#define ATA_ERROR_ABRT 0x04 +#define ATA_ERROR_MCR 0x08 +#define ATA_ERROR_IDNF 0x10 +#define ATA_ERROR_MC 0x20 +#define ATA_ERROR_UNC 0x40 +#define ATA_ERROR_BBK 0x80 + +#define ATA_STATUS_ERR 0x01 +#define ATA_STATUS_DF 0x02 +#define ATA_STATUS_DRQ 0x08 +#define ATA_STATUS_BSY 0x80 + +#define ATA_COMMAND_READ_SECTORS 0x20 +#define ATA_COMMAND_IDENTIFY 0xEC +#define ATA_COMMAND_IDENTIFY_PACKET 0xA1 + +#define ATA_IDENTIFY_SIGNATURE 0 +#define ATA_IDENTIFY_MODEL 27 +#define ATA_IDENTIFY_CAPABILITIES 49 +#define ATA_IDENTIFY_LBA_COUNT 60 +#define ATA_IDENTIFY_COMMAND_SET 82 +#define ATA_IDENTIFY_LBA_COUNT_EXT 100 +#define ATA_IDENTIFY_SECTOR_INFO 106 +#define ATA_IDENTIFY_SECTOR_WORDS 117 + +#define ATA_COMMANDSET_LBA48_SUPPORTED (1 << 26) + +namespace Kernel +{ + + BAN::ErrorOr ATAController::create(const PCIDevice& device) + { + ATAController* controller = new ATAController(device); + if (controller == nullptr) + return BAN::Error::from_string("Could not allocate memory for ATAController"); + TRY(controller->initialize()); + return controller; + } + + BAN::ErrorOr ATAController::initialize() + { + m_buses[ATA_PRIMARY].base = 0x1F0; + m_buses[ATA_PRIMARY].ctrl = 0x3F6; + m_buses[ATA_PRIMARY].write(ATA_PORT_CONTROL, 2); + + m_buses[ATA_SECONDARY].base = 0x170; + m_buses[ATA_SECONDARY].ctrl = 0x376; + m_buses[ATA_SECONDARY].write(ATA_PORT_CONTROL, 2); + + uint8_t prog_if = m_pci_device.read_byte(0x09); + if (prog_if & 0x01) + { + m_buses[ATA_PRIMARY].base = m_pci_device.read_dword(0x10) & 0xFFFFFFFC; + m_buses[ATA_PRIMARY].ctrl = m_pci_device.read_dword(0x14) & 0xFFFFFFFC; + } + if (prog_if & 0x04) + { + m_buses[ATA_SECONDARY].base = m_pci_device.read_dword(0x18) & 0xFFFFFFFC; + m_buses[ATA_SECONDARY].ctrl = m_pci_device.read_dword(0x1C) & 0xFFFFFFFC; + } + + for (uint8_t bus_index = 0; bus_index < 2; bus_index++) + { + for (uint8_t device_index = 0; device_index < 2; device_index++) + { + ATABus& bus = m_buses[bus_index]; + ATADevice& device = bus.devices[device_index]; + + device.type = ATADevice::Type::Unknown; + device.slave_bit = device_index << 4; + device.bus = &bus; + + bus.write(ATA_PORT_DRIVE_SELECT, 0xA0 | device.slave_bit); + PIT::sleep(1); + + bus.write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY); + PIT::sleep(1); + + if (bus.read(ATA_PORT_STATUS) == 0) + continue; + + uint8_t status = 0; + while (true) + { + status = bus.read(ATA_PORT_STATUS); + if (status & ATA_STATUS_ERR) + break; + if (!(status & ATA_STATUS_BSY) && (status && ATA_STATUS_DRQ)) + break; + } + + auto type = ATADevice::Type::ATA; + + // Not a ATA device, maybe ATAPI + if (status & ATA_STATUS_ERR) + { + uint8_t lba1 = bus.read(ATA_PORT_LBA1); + uint8_t lba2 = bus.read(ATA_PORT_LBA2); + + if (lba1 == 0x14 && lba2 == 0xEB) + type = ATADevice::Type::ATAPI; + else if (lba1 == 0x69 && lba2 == 0x96) + type = ATADevice::Type::ATAPI; + else + continue; + + bus.write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY_PACKET); + PIT::sleep(1); + } + + uint16_t buffer[256] {}; + bus.read_buffer(ATA_PORT_DATA, buffer, 256); + + device.type = type; + device.signature = *(uint16_t*)(buffer + ATA_IDENTIFY_SIGNATURE); + device.capabilities = *(uint16_t*)(buffer + ATA_IDENTIFY_CAPABILITIES); + device.command_set = *(uint32_t*)(buffer + ATA_IDENTIFY_COMMAND_SET); + + device.sector_words = 256; + 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) + { + device.sector_words = *(uint32_t*)(buffer + ATA_IDENTIFY_SECTOR_WORDS); + } + + device.lba_count = 0; + if (device.command_set & ATA_COMMANDSET_LBA48_SUPPORTED) + device.lba_count = *(uint64_t*)(buffer + ATA_IDENTIFY_LBA_COUNT_EXT); + if (device.lba_count < (1 << 28)) + device.lba_count = *(uint32_t*)(buffer + ATA_IDENTIFY_LBA_COUNT); + + for (int i = 0; i < 20; i++) + { + uint16_t word = buffer[ATA_IDENTIFY_MODEL + i]; + device.model[2 * i + 0] = word >> 8; + device.model[2 * i + 1] = word & 0xFF; + } + device.model[40] = 0; + + TRY(m_devices.push_back(&device)); + } + } + + for (uint32_t i = 0; i < 2; i++) + { + for (uint32_t j = 0; j < 2; j++) + { + ATADevice& device = m_buses[i].devices[j]; + if (device.type == ATADevice::Type::Unknown) + continue; + constexpr uint32_t words_per_mib = 1024 * 1024 / 2; + const char* device_type = + device.type == ATADevice::Type::ATA ? "ATA" : + device.type == ATADevice::Type::ATAPI ? "ATAPI" : + "Unknown"; + dprintln("Found {} Drive ({} MiB) model {}", device_type, device.lba_count * device.sector_words / words_per_mib, device.model); + } + } + + return {}; + } + + BAN::ErrorOr ATADevice::read_sectors(uint64_t lba, uint8_t sector_count, uint8_t* buffer) + { + if (lba + sector_count > lba_count) + return BAN::Error::from_string("Attempted to read outside of the device boundaries"); + + if (lba < (1 << 28)) + { + // LBA28 + bus->write(ATA_PORT_DRIVE_SELECT, 0xE0 | slave_bit | ((lba >> 24) & 0x0F)); + bus->write(ATA_PORT_SECTOR_COUNT, sector_count); + bus->write(ATA_PORT_LBA0, (uint8_t)(lba >> 0)); + bus->write(ATA_PORT_LBA1, (uint8_t)(lba >> 8)); + bus->write(ATA_PORT_LBA2, (uint8_t)(lba >> 16)); + bus->write(ATA_PORT_COMMAND, ATA_COMMAND_READ_SECTORS); + + for (uint32_t sector = 0; sector < sector_count; sector++) + { + TRY(bus->wait(true)); + bus->read_buffer(ATA_PORT_DATA, (uint16_t*)buffer + sector * sector_words, sector_words); + } + } + else + { + // LBA48 + ASSERT(false); + } + + return {}; + } + + uint8_t ATABus::read(uint16_t port) + { + if (port <= 0x07) + return IO::inb(base + port); + if (0x10 <= port && port <= 0x11) + return IO::inb(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(base + port - 0x00, buffer, words); + if (0x10 <= port && port <= 0x11) + return IO::insw(ctrl + port - 0x10, buffer, words); + ASSERT_NOT_REACHED(); + } + + void ATABus::write(uint16_t port, uint8_t data) + { + if (port <= 0x07) + return IO::outb(base + port, data); + if (0x10 <= port && port <= 0x11) + return IO::outb(ctrl + port - 0x10, data); + ASSERT_NOT_REACHED(); + } + + BAN::ErrorOr ATABus::wait(bool wait_drq) + { + for (uint32_t i = 0; i < 4; i++) + read(ATA_PORT_ALT_STATUS); + + uint8_t status = ATA_STATUS_BSY; + while (status & ATA_STATUS_BSY) + status = 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_string("Device fault"); + status = read(ATA_PORT_STATUS); + } + + return {}; + } + + BAN::Error ATABus::error() + { + uint8_t err = read(ATA_PORT_ERROR); + if (err & ATA_ERROR_AMNF) + return BAN::Error::from_string("Address mark not found."); + if (err & ATA_ERROR_TKZNF) + return BAN::Error::from_string("Track zero not found."); + if (err & ATA_ERROR_ABRT) + return BAN::Error::from_string("Aborted command."); + if (err & ATA_ERROR_MCR) + return BAN::Error::from_string("Media change request."); + if (err & ATA_ERROR_IDNF) + return BAN::Error::from_string("ID not found."); + if (err & ATA_ERROR_MC) + return BAN::Error::from_string("Media changed."); + if (err & ATA_ERROR_UNC) + return BAN::Error::from_string("Uncorrectable data error."); + if (err & ATA_ERROR_BBK) + return BAN::Error::from_string("Bad Block detected."); + ASSERT_NOT_REACHED(); + } + +} \ No newline at end of file diff --git a/kernel/kernel/DiskIO.cpp b/kernel/kernel/Storage/StorageDevice.cpp similarity index 61% rename from kernel/kernel/DiskIO.cpp rename to kernel/kernel/Storage/StorageDevice.cpp index 108457204a..40f1dd5da5 100644 --- a/kernel/kernel/DiskIO.cpp +++ b/kernel/kernel/Storage/StorageDevice.cpp @@ -1,11 +1,9 @@ #include #include -#include #include #include -#include - -#include +#include +#include #define ATA_DEVICE_PRIMARY 0x1F0 #define ATA_DEVICE_SECONDARY 0x170 @@ -95,7 +93,7 @@ namespace Kernel 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, - 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, }; static uint32_t crc32_checksum(const uint8_t* data, size_t count) @@ -109,30 +107,12 @@ namespace Kernel return crc32 ^ 0xFFFFFFFF; } - template - static T little_endian_to_host(const uint8_t* data) - { - T result = 0; - for (size_t i = 0; i < sizeof(T); i++) - result |= data[i] << (8 * i); - return result; - } - - template - static T big_endian_to_host(const uint8_t* data) - { - T result = 0; - for (size_t i = 0; i < sizeof(T); i++) - result |= data[i] << (8 * (sizeof(T) - i - 1)); - return result; - } - static GUID parse_guid(const uint8_t* guid) { GUID result; - result.data1 = big_endian_to_host(guid + 0); - result.data2 = big_endian_to_host(guid + 4); - result.data3 = big_endian_to_host(guid + 6); + result.data1 = BAN::Math::big_endian_to_host(guid + 0); + result.data2 = BAN::Math::big_endian_to_host(guid + 4); + result.data3 = BAN::Math::big_endian_to_host(guid + 6); memcpy(result.data4, guid + 8, 8); return result; } @@ -166,124 +146,87 @@ namespace Kernel memset(&header, 0, sizeof(header)); memcpy(header.signature, lba1.data(), 8); - header.revision = little_endian_to_host(lba1.data() + 8); - header.size = little_endian_to_host(lba1.data() + 12); - header.crc32 = little_endian_to_host(lba1.data() + 16); - header.my_lba = little_endian_to_host(lba1.data() + 24); - header.first_lba = little_endian_to_host(lba1.data() + 40); - header.last_lba = little_endian_to_host(lba1.data() + 48); + header.revision = BAN::Math::little_endian_to_host(lba1.data() + 8); + header.size = BAN::Math::little_endian_to_host(lba1.data() + 12); + header.crc32 = BAN::Math::little_endian_to_host(lba1.data() + 16); + header.my_lba = BAN::Math::little_endian_to_host(lba1.data() + 24); + header.first_lba = BAN::Math::little_endian_to_host(lba1.data() + 40); + header.last_lba = BAN::Math::little_endian_to_host(lba1.data() + 48); header.guid = parse_guid(lba1.data() + 56); - header.partition_entry_lba = little_endian_to_host(lba1.data() + 72); - header.partition_entry_count = little_endian_to_host(lba1.data() + 80); - header.partition_entry_size = little_endian_to_host(lba1.data() + 84); - header.partition_entry_array_crc32 = little_endian_to_host(lba1.data() + 88); + header.partition_entry_lba = BAN::Math::little_endian_to_host(lba1.data() + 72); + header.partition_entry_count = BAN::Math::little_endian_to_host(lba1.data() + 80); + header.partition_entry_size = BAN::Math::little_endian_to_host(lba1.data() + 84); + header.partition_entry_array_crc32 = BAN::Math::little_endian_to_host(lba1.data() + 88); return header; } - bool DiskDevice::initialize_partitions() + static void utf8_encode(const uint16_t* codepoints, size_t count, char* out) + { + uint32_t len = 0; + while (*codepoints && count--) + { + uint16_t cp = *codepoints; + if (cp < 128) + { + out[len++] = cp & 0x7F; + } + else if (cp < 2048) + { + out[len++] = 0xC0 | ((cp >> 0x6) & 0x1F); + out[len++] = 0x80 | (cp & 0x3F); + } + else + { + out[len++] = 0xE0 | ((cp >> 0xC) & 0x0F); + out[len++] = 0x80 | ((cp >> 0x6) & 0x3F); + out[len++] = 0x80 | (cp & 0x3F); + } + codepoints++; + } + out[len] = 0; + } + + BAN::ErrorOr StorageDevice::initialize_partitions() { BAN::Vector lba1(sector_size()); - if (!read_sectors(1, 1, lba1.data())) - return false; + TRY(read_sectors(1, 1, lba1.data())); GPTHeader header = parse_gpt_header(lba1); if (!is_valid_gpt_header(header, sector_size())) - { - dprintln("invalid gpt header"); - return false; - } + return BAN::Error::from_string("Invalid GPT header"); uint32_t size = header.partition_entry_count * header.partition_entry_size; if (uint32_t remainder = size % sector_size()) size += sector_size() - remainder; BAN::Vector entry_array(size); - if (!read_sectors(header.partition_entry_lba, size / sector_size(), entry_array.data())) - return false; + TRY(read_sectors(header.partition_entry_lba, size / sector_size(), entry_array.data())); if (!is_valid_gpt_crc32(header, lba1, entry_array)) - { - dprintln("invalid crc3 in gpt header"); - return false; - } + return BAN::Error::from_string("Invalid crc3 in the GPT header"); for (uint32_t i = 0; i < header.partition_entry_count; i++) { uint8_t* partition_data = entry_array.data() + header.partition_entry_size * i; + + char utf8_name[36 * 3 + 1]; // 36 16-bit codepoints + nullbyte + utf8_encode((uint16_t*)(partition_data + 56), header.partition_entry_size - 56, utf8_name); + MUST(m_partitions.emplace_back( *this, parse_guid(partition_data + 0), parse_guid(partition_data + 16), - little_endian_to_host(partition_data + 32), - little_endian_to_host(partition_data + 40), - little_endian_to_host(partition_data + 48), - (const char*)(partition_data + 56) + BAN::Math::little_endian_to_host(partition_data + 32), + BAN::Math::little_endian_to_host(partition_data + 40), + BAN::Math::little_endian_to_host(partition_data + 48), + utf8_name )); } - return true; + return {}; } - static DiskIO* s_instance = nullptr; - - bool DiskIO::initialize() - { - ASSERT(s_instance == nullptr); - s_instance = new DiskIO(); - -#if 1 - for (DiskDevice* device : s_instance->m_devices) - { - for (auto& partition : device->partitions()) - { - if (!partition.is_used()) - continue; - - if (memcmp(&partition.type(), "\x0F\xC6\x3D\xAF\x84\x83\x47\x72\x8E\x79\x3D\x69\xD8\x47\x7D\xE4", 16) == 0) - { - auto ext2fs = MUST(Ext2FS::create(partition)); - VirtualFileSystem::initialize(ext2fs->root_inode()); - } - } - } -#endif - - return true; - } - - DiskIO& DiskIO::get() - { - ASSERT(s_instance); - return *s_instance; - } - - DiskIO::DiskIO() - { - try_add_device(ATADevice::create(ATA_DEVICE_PRIMARY, ATA_DEVICE_PRIMARY + 0x206, 0)); - try_add_device(ATADevice::create(ATA_DEVICE_PRIMARY, ATA_DEVICE_PRIMARY + 0x206, ATA_DEVICE_SLAVE_BIT)); - try_add_device(ATADevice::create(ATA_DEVICE_SECONDARY, ATA_DEVICE_SECONDARY + 0x206, 0)); - try_add_device(ATADevice::create(ATA_DEVICE_SECONDARY, ATA_DEVICE_SECONDARY + 0x206, ATA_DEVICE_SLAVE_BIT)); - } - - void DiskIO::try_add_device(DiskDevice* device) - { - if (!device) - return; - if (!device->initialize()) - { - delete device; - return; - } - if (!device->initialize_partitions()) - { - delete device; - return; - } - MUST(m_devices.push_back(device)); - } - - - DiskDevice::Partition::Partition(DiskDevice& device, const GUID& type, const GUID& guid, uint64_t start, uint64_t end, uint64_t attr, const char* name) + StorageDevice::Partition::Partition(StorageDevice& device, const GUID& type, const GUID& guid, uint64_t start, uint64_t end, uint64_t attr, const char* name) : m_device(device) , m_type(type) , m_guid(guid) @@ -291,14 +234,16 @@ namespace Kernel , m_lba_end(end) , m_attributes(attr) { - memcpy(m_name, name, sizeof(m_name)); + memcpy(m_name, name, sizeof(m_name)); } - bool DiskDevice::Partition::read_sectors(uint32_t lba, uint32_t sector_count, uint8_t* buffer) + BAN::ErrorOr StorageDevice::Partition::read_sectors(uint64_t lba, uint8_t sector_count, uint8_t* buffer) { const uint32_t sectors_in_partition = m_lba_end - m_lba_start; - ASSERT(lba + sector_count < sectors_in_partition); - return m_device.read_sectors(m_lba_start + lba, sector_count, buffer); + if (lba + sector_count > sectors_in_partition) + return BAN::Error::from_string("Attempted to read outside of the partition boundaries"); + TRY(m_device.read_sectors(m_lba_start + lba, sector_count, buffer)); + return {}; } } \ No newline at end of file diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index 1a31df79ae..bae10ec64c 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -92,18 +93,28 @@ extern "C" void kernel_main() PIT::initialize(); dprintln("PIT initialized"); + if (!PCI::initialize()) + Kernel::panic("Could not initialize PCI"); + dprintln("PCI initialized"); + if (!Input::initialize()) - return; - dprintln("8042 initialized"); + dprintln("Could not initialize input drivers"); + dprintln("Input initialized"); Scheduler::initialize(); Scheduler& scheduler = Scheduler::get(); MUST(scheduler.add_thread(BAN::Function( [terminal_driver] { - DiskIO::initialize(); - dprintln("Disk IO initialized"); + //PCI::get().initialize_controllers(); + //StorageDeviceManager::initialize(); + if (auto error = VirtualFileSystem::initialize(); error.is_error()) + { + derrorln("{}", error.error()); + return; + } + auto font_or_error = Font::load("/usr/share/fonts/zap-ext-vga16.psf"); if (font_or_error.is_error()) dprintln("{}", font_or_error.error());