From 6ed965117643adcb6a6f28026a5b6cb7140fb855 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Thu, 23 Mar 2023 12:54:59 +0200 Subject: [PATCH] Kernel: StorageDevice and Ext2 "support" writing --- disk.sh | 1 + kernel/include/kernel/FS/Ext2.h | 1 + kernel/include/kernel/Storage/ATAController.h | 3 + kernel/include/kernel/Storage/StorageDevice.h | 2 + kernel/kernel/FS/Ext2.cpp | 19 ++++++- kernel/kernel/Storage/ATAController.cpp | 55 +++++++++++++++++++ kernel/kernel/Storage/StorageDevice.cpp | 10 ++++ 7 files changed, 88 insertions(+), 3 deletions(-) diff --git a/disk.sh b/disk.sh index b14645ad..22ca3b14 100755 --- a/disk.sh +++ b/disk.sh @@ -53,6 +53,7 @@ sudo mount $PARTITION2 $MOUNT_DIR sudo cp -r ${SYSROOT}/* ${MOUNT_DIR}/ sudo mkdir -p ${MOUNT_DIR}/usr/share/ sudo cp -r fonts ${MOUNT_DIR}/usr/share/ +sudo mkdir -p ${MOUNT_DIR}/mnt/ sudo grub-install --no-floppy --target=i386-pc --modules="normal ext2 multiboot" --boot-directory=${MOUNT_DIR}/boot $LOOP_DEV diff --git a/kernel/include/kernel/FS/Ext2.h b/kernel/include/kernel/FS/Ext2.h index 6fde635b..9ddc365e 100644 --- a/kernel/include/kernel/FS/Ext2.h +++ b/kernel/include/kernel/FS/Ext2.h @@ -182,6 +182,7 @@ namespace Kernel BAN::ErrorOr read_inode(uint32_t); BAN::ErrorOr> read_block(uint32_t); + BAN::ErrorOr write_block(uint32_t, BAN::Span); const Ext2::Superblock& superblock() const { return m_superblock; } diff --git a/kernel/include/kernel/Storage/ATAController.h b/kernel/include/kernel/Storage/ATAController.h index 0e3692d5..fc6c8e9c 100644 --- a/kernel/include/kernel/Storage/ATAController.h +++ b/kernel/include/kernel/Storage/ATAController.h @@ -14,6 +14,7 @@ namespace Kernel { public: 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; virtual uint32_t sector_size() const override { return sector_words * 2; } virtual uint64_t total_size() const override { return lba_count * sector_size(); } @@ -49,6 +50,7 @@ namespace Kernel uint8_t read(uint16_t); void read_buffer(uint16_t, uint16_t*, size_t); void write(uint16_t, uint8_t); + void write_buffer(uint16_t, const uint16_t*, size_t); BAN::ErrorOr wait(bool); BAN::Error error(); }; @@ -63,6 +65,7 @@ namespace Kernel BAN::ErrorOr initialize(); 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; diff --git a/kernel/include/kernel/Storage/StorageDevice.h b/kernel/include/kernel/Storage/StorageDevice.h index 769e0e43..e1b2f962 100644 --- a/kernel/include/kernel/Storage/StorageDevice.h +++ b/kernel/include/kernel/Storage/StorageDevice.h @@ -29,6 +29,7 @@ namespace Kernel const StorageDevice& device() const { return m_device; } BAN::ErrorOr read_sectors(uint64_t lba, uint8_t sector_count, uint8_t* buffer); + BAN::ErrorOr write_sectors(uint64_t lba, uint8_t sector_count, const uint8_t* buffer); bool is_used() const { uint8_t zero[16] {}; return memcmp(&m_type, zero, 16); } private: @@ -47,6 +48,7 @@ namespace Kernel BAN::ErrorOr initialize_partitions(); virtual BAN::ErrorOr read_sectors(uint64_t lba, uint8_t sector_count, uint8_t* buffer) = 0; + virtual BAN::ErrorOr write_sectors(uint64_t lba, uint8_t sector_count, const uint8_t* buffer) = 0; virtual uint32_t sector_size() const = 0; virtual uint64_t total_size() const = 0; diff --git a/kernel/kernel/FS/Ext2.cpp b/kernel/kernel/FS/Ext2.cpp index 012a2c10..e2ee4cf0 100644 --- a/kernel/kernel/FS/Ext2.cpp +++ b/kernel/kernel/FS/Ext2.cpp @@ -212,7 +212,7 @@ namespace Kernel return block; } - ASSERT(false); + ASSERT_NOT_REACHED(); } BAN::ErrorOr Ext2Inode::read(size_t offset, void* buffer, size_t count) @@ -458,9 +458,9 @@ namespace Kernel BAN::ErrorOr> Ext2FS::read_block(uint32_t block) { const uint32_t sector_size = m_partition.device().sector_size(); - uint32_t block_size = 1024 << m_superblock.log_block_size; + const uint32_t block_size = 1024 << m_superblock.log_block_size; ASSERT(block_size % sector_size == 0); - uint32_t sectors_per_block = block_size / sector_size; + const uint32_t sectors_per_block = block_size / sector_size; BAN::Vector block_buffer; TRY(block_buffer.resize(block_size)); @@ -470,4 +470,17 @@ namespace Kernel return block_buffer; } + BAN::ErrorOr Ext2FS::write_block(uint32_t block, BAN::Span data) + { + const uint32_t sector_size = m_partition.device().sector_size(); + const uint32_t block_size = 1024 << m_superblock.log_block_size; + ASSERT(block_size % sector_size == 0); + ASSERT(data.size() <= block_size); + const uint32_t sectors_per_block = block_size / sector_size; + + TRY(m_partition.write_sectors(block * sectors_per_block, sectors_per_block, data.data())); + + return {}; + } + } \ No newline at end of file diff --git a/kernel/kernel/Storage/ATAController.cpp b/kernel/kernel/Storage/ATAController.cpp index 3ffa3a95..06023e2f 100644 --- a/kernel/kernel/Storage/ATAController.cpp +++ b/kernel/kernel/Storage/ATAController.cpp @@ -33,6 +33,8 @@ #define ATA_STATUS_BSY 0x80 #define ATA_COMMAND_READ_SECTORS 0x20 +#define ATA_COMMAND_WRITE_SECTORS 0x30 +#define ATA_COMMAND_CACHE_FLUSH 0xE7 #define ATA_COMMAND_IDENTIFY 0xEC #define ATA_COMMAND_IDENTIFY_PACKET 0xA1 @@ -216,12 +218,53 @@ namespace Kernel return {}; } + BAN::ErrorOr ATAController::write(ATADevice* device, uint64_t lba, uint8_t sector_count, const uint8_t* buffer) + { + if (lba + sector_count > device->lba_count) + return BAN::Error::from_c_string("Attempted to read outside of the device boundaries"); + + LockGuard _(m_lock); + + if (lba < (1 << 28)) + { + // LBA28 + device->bus->write(ATA_PORT_DRIVE_SELECT, 0xE0 | device->slave_bit | ((lba >> 24) & 0x0F)); + device->bus->write(ATA_PORT_SECTOR_COUNT, sector_count); + device->bus->write(ATA_PORT_LBA0, (uint8_t)(lba >> 0)); + device->bus->write(ATA_PORT_LBA1, (uint8_t)(lba >> 8)); + device->bus->write(ATA_PORT_LBA2, (uint8_t)(lba >> 16)); + device->bus->write(ATA_PORT_COMMAND, ATA_COMMAND_WRITE_SECTORS); + + for (uint32_t sector = 0; sector < sector_count; sector++) + { + TRY(device->bus->wait(false)); + device->bus->write_buffer(ATA_PORT_DATA, (uint16_t*)buffer + sector * device->sector_words, device->sector_words); + } + } + else + { + // LBA48 + ASSERT(false); + } + + device->bus->write(ATA_PORT_COMMAND, ATA_COMMAND_CACHE_FLUSH); + TRY(device->bus->wait(false)); + + return {}; + } + BAN::ErrorOr ATADevice::read_sectors(uint64_t lba, uint8_t sector_count, uint8_t* buffer) { TRY(controller->read(this, lba, sector_count, buffer)); return {}; } + BAN::ErrorOr ATADevice::write_sectors(uint64_t lba, uint8_t sector_count, const uint8_t* buffer) + { + TRY(controller->write(this, lba, sector_count, buffer)); + return {}; + } + uint8_t ATABus::read(uint16_t port) { if (port <= 0x07) @@ -249,6 +292,18 @@ namespace Kernel 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 = base + port; + if (0x10 <= port && port <= 0x11) + io_port = 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++) diff --git a/kernel/kernel/Storage/StorageDevice.cpp b/kernel/kernel/Storage/StorageDevice.cpp index c63b6256..2d536adb 100644 --- a/kernel/kernel/Storage/StorageDevice.cpp +++ b/kernel/kernel/Storage/StorageDevice.cpp @@ -167,6 +167,7 @@ namespace Kernel for (uint32_t i = 0; i < header.partition_entry_count; i++) { const PartitionEntry& entry = *(const PartitionEntry*)(entry_array.data() + header.partition_entry_size * i); + ASSERT((uintptr_t)&entry % 2 == 0); char utf8_name[36 * 4 + 1]; BAN::UTF8::from_codepoints(entry.partition_name, 36, utf8_name); @@ -205,4 +206,13 @@ namespace Kernel return {}; } + BAN::ErrorOr StorageDevice::Partition::write_sectors(uint64_t lba, uint8_t sector_count, const uint8_t* buffer) + { + const uint32_t sectors_in_partition = m_lba_end - m_lba_start; + if (lba + sector_count > sectors_in_partition) + return BAN::Error::from_c_string("Attempted to read outside of the partition boundaries"); + TRY(m_device.write_sectors(m_lba_start + lba, sector_count, buffer)); + return {}; + } + } \ No newline at end of file