From 0d1c01fd623c69fd4ec14e62843ad93a71070eff Mon Sep 17 00:00:00 2001 From: apio Date: Wed, 17 May 2023 18:15:01 +0200 Subject: [PATCH] kernel+init: Create a device node in /dev to access the CDROM from userspace! Still using PIO, though. --- kernel/src/arch/x86_64/disk/ATA.cpp | 84 ++++++++++++++++++++++++++ kernel/src/arch/x86_64/disk/ATA.h | 42 ++++++++++--- kernel/src/fs/devices/DeviceRegistry.h | 1 + 3 files changed, 117 insertions(+), 10 deletions(-) diff --git a/kernel/src/arch/x86_64/disk/ATA.cpp b/kernel/src/arch/x86_64/disk/ATA.cpp index 0e891734..e28ec535 100644 --- a/kernel/src/arch/x86_64/disk/ATA.cpp +++ b/kernel/src/arch/x86_64/disk/ATA.cpp @@ -4,6 +4,7 @@ #include "arch/Timer.h" #include "arch/x86_64/IO.h" #include "memory/MemoryManager.h" +#include #include #include #include @@ -329,6 +330,12 @@ namespace ATA m_drives[drive] = {}; return false; } + + if (ATADevice::create(m_drives[drive]).has_error()) + { + kwarnln("ata: Failed to register ATA drive %d:%d in DeviceRegistry", m_channel_index, drive); + continue; + } } } @@ -675,6 +682,25 @@ namespace ATA return send_packet_atapi_pio(&read_packet, out, (u16)size); } + Result Drive::read_lba(u64 lba, void* out, usize nblocks) + { + const usize blocks_per_page = ARCH_PAGE_SIZE / m_block_size; + if (m_is_atapi) + { + kdbgln("ata: Reading %zu blocks from ATAPI drive using PIO, at LBA %ld", nblocks, lba); + while (nblocks > blocks_per_page) + { + TRY(atapi_read_pio(lba, out, ARCH_PAGE_SIZE)); + lba += blocks_per_page; + nblocks -= blocks_per_page; + out = offset_ptr(out, ARCH_PAGE_SIZE); + } + return atapi_read_pio(lba, out, nblocks * m_block_size); + } + else + todo(); + } + void Drive::irq_handler() { // Clear the IRQ flag. @@ -694,3 +720,61 @@ namespace ATA } } } + +static u32 next_minor = 0; + +Result ATADevice::create(SharedPtr drive) +{ + auto device = TRY(adopt_shared_if_nonnull(new (std::nothrow) ATADevice())); + device->m_drive = drive; + return DeviceRegistry::register_special_device(DeviceRegistry::Disk, next_minor++, device); +} + +Result ATADevice::read(u8* buf, usize offset, usize size) const +{ + if (size == 0) return 0; + + if (offset > m_drive->capacity()) return 0; + if (offset + size > m_drive->capacity()) size = m_drive->capacity() - offset; + + usize length = size; + + auto block_size = m_drive->block_size(); + + auto* temp = TRY(make_array(block_size)); + auto guard = make_scope_guard([temp] { delete[] temp; }); + + if (offset % block_size) + { + usize extra_size = block_size - (offset % block_size); + TRY(m_drive->read_lba(offset / block_size, temp, 1)); + memcpy(buf, temp + (offset % block_size), extra_size); + offset += extra_size; + size -= extra_size; + buf += extra_size; + } + + while (size >= ARCH_PAGE_SIZE) + { + TRY(m_drive->read_lba(offset / block_size, buf, ARCH_PAGE_SIZE / block_size)); + offset += ARCH_PAGE_SIZE; + size -= ARCH_PAGE_SIZE; + buf += ARCH_PAGE_SIZE; + } + + while (size >= block_size) + { + TRY(m_drive->read_lba(offset / block_size, buf, 1)); + offset += block_size; + size -= block_size; + buf += block_size; + } + + if (size) + { + TRY(m_drive->read_lba(offset / block_size, temp, 1)); + memcpy(buf, temp, size); + } + + return length; +} diff --git a/kernel/src/arch/x86_64/disk/ATA.h b/kernel/src/arch/x86_64/disk/ATA.h index a6ad2147..fbcd3ff3 100644 --- a/kernel/src/arch/x86_64/disk/ATA.h +++ b/kernel/src/arch/x86_64/disk/ATA.h @@ -142,6 +142,23 @@ namespace ATA void irq_handler(); + usize block_size() const + { + return m_block_size; + } + + usize block_count() const + { + return m_block_count; + } + + usize capacity() const + { + return m_block_count * m_block_size; + } + + Result read_lba(u64 lba, void* out, usize nblocks); + private: bool identify_ata(); @@ -265,23 +282,28 @@ class ATADevice : public Device { public: // Initializer for DeviceRegistry. - static Result create(SharedPtr controller, int channel, int drive); + static Result create(SharedPtr drive); Result read(u8*, usize, usize) const override; - Result write(const u8*, usize, usize) override; + Result write(const u8*, usize, usize) override + { + return err(ENOTSUP); + } - bool blocking() const override; + bool blocking() const override + { + return false; + } - Result ioctl(int request, void* arg) override; - - usize size() const override; + usize size() const override + { + return m_drive->capacity(); + } virtual ~ATADevice() = default; private: - ATADevice(SharedPtr controller); - SharedPtr m_controller; - int m_channel; - int m_drive; + ATADevice() = default; + SharedPtr m_drive; }; diff --git a/kernel/src/fs/devices/DeviceRegistry.h b/kernel/src/fs/devices/DeviceRegistry.h index a68c4039..074e5d05 100644 --- a/kernel/src/fs/devices/DeviceRegistry.h +++ b/kernel/src/fs/devices/DeviceRegistry.h @@ -12,6 +12,7 @@ namespace DeviceRegistry Console = 1, Memory = 2, Framebuffer = 3, + Disk = 4, }; Result> fetch_special_device(u32 major, u32 minor);