diff --git a/kernel/Makefile b/kernel/Makefile index 7ca2ef10..4087db1a 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 ac731204..00000000 --- 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 cb19af8a..0931b9bc 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 027cc54d..6725b45a 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 00000000..34c64a16 --- /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 00000000..0f9309b3 --- /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 e8eadbf5..f333d21c 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 a8362851..00000000 --- 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 f7f11654..4036c739 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 1e4f6efa..47b4c31a 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 00000000..f7aa74b6 --- /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 10845720..40f1dd5d 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 1a31df79..bae10ec6 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());