From 738b218a49e3e63e9a6a23d638284bc595fec5b8 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 16 Jun 2023 21:30:50 +0200 Subject: [PATCH] kernel/ATA+MBR: Dynamically generate device names + create devices for MBR partitions --- kernel/src/arch/x86_64/disk/ATA.cpp | 12 +++++- kernel/src/arch/x86_64/disk/ATA.h | 15 ++++++- kernel/src/fs/MBR.cpp | 51 ++++++++++++++++++++++- kernel/src/fs/MBR.h | 48 +++++++++++++++++++++ kernel/src/fs/devices/ConsoleDevice.h | 5 +++ kernel/src/fs/devices/Device.h | 12 ++++++ kernel/src/fs/devices/DeviceRegistry.h | 1 + kernel/src/fs/devices/FramebufferDevice.h | 5 +++ kernel/src/fs/devices/FullDevice.h | 5 +++ kernel/src/fs/devices/NullDevice.h | 5 +++ kernel/src/fs/devices/ZeroDevice.h | 5 +++ 11 files changed, 161 insertions(+), 3 deletions(-) diff --git a/kernel/src/arch/x86_64/disk/ATA.cpp b/kernel/src/arch/x86_64/disk/ATA.cpp index 4a6a6690..6c476f70 100644 --- a/kernel/src/arch/x86_64/disk/ATA.cpp +++ b/kernel/src/arch/x86_64/disk/ATA.cpp @@ -729,11 +729,21 @@ namespace ATA static u32 next_minor = 0; +Result ATA::Drive::create_drive_name(SharedPtr drive) +{ + static u32 cd_index = 0; + static u32 sd_index = 0; + + return String::format("%s%d"_sv, drive->m_is_atapi ? "cd" : "sd", drive->m_is_atapi ? cd_index++ : sd_index++); +} + Result> ATADevice::create(SharedPtr drive) { auto device = TRY(adopt_shared_if_nonnull(new (std::nothrow) ATADevice())); device->m_drive = drive; - TRY(DeviceRegistry::register_special_device(DeviceRegistry::Disk, next_minor++, device, "cdrom", 0400)); + device->m_device_path = TRY(ATA::Drive::create_drive_name(drive)); + TRY(DeviceRegistry::register_special_device(DeviceRegistry::Disk, next_minor++, device, + device->m_device_path.chars(), 0400)); return (SharedPtr)device; } diff --git a/kernel/src/arch/x86_64/disk/ATA.h b/kernel/src/arch/x86_64/disk/ATA.h index 9ceabcf5..53207b0a 100644 --- a/kernel/src/arch/x86_64/disk/ATA.h +++ b/kernel/src/arch/x86_64/disk/ATA.h @@ -159,6 +159,8 @@ namespace ATA Result read_lba(u64 lba, void* out, usize nblocks); + static Result create_drive_name(SharedPtr drive); + private: bool identify_ata(); @@ -289,7 +291,7 @@ class ATADevice : public Device { public: // Initializer for DeviceRegistry. - static Result create(SharedPtr drive); + static Result> create(SharedPtr drive); Result read(u8*, usize, usize) const override; @@ -313,9 +315,20 @@ class ATADevice : public Device return m_drive->capacity(); } + Result block_size() const override + { + return m_drive->block_size(); + } + + StringView device_path() const override + { + return m_device_path.view(); + } + virtual ~ATADevice() = default; private: ATADevice() = default; SharedPtr m_drive; + String m_device_path; }; diff --git a/kernel/src/fs/MBR.cpp b/kernel/src/fs/MBR.cpp index c3d5da52..0a585abe 100644 --- a/kernel/src/fs/MBR.cpp +++ b/kernel/src/fs/MBR.cpp @@ -1,19 +1,66 @@ #include "fs/MBR.h" #include "Log.h" +#include + +static Result create_partition_name(SharedPtr host_device, u32 partition_index) +{ + auto host_path = host_device->device_path(); + + char last = host_path[host_path.length() - 1]; + + if (_isdigit(last)) return String::format("%sp%d"_sv, host_path.chars(), partition_index); + + return String::format("%s%d"_sv, host_path.chars(), partition_index); +} namespace MBR { + Result PartitionDevice::create(SharedPtr host_device, usize start_block, usize num_blocks, + u32 partition_index) + { + static u32 next_minor = 0; + auto device = TRY(adopt_shared_if_nonnull(new (std::nothrow) PartitionDevice())); + device->m_host_device = host_device; + device->m_start_offset = start_block * device->m_block_size; + device->m_num_blocks = num_blocks; + device->m_device_path = TRY(create_partition_name(host_device, partition_index)); + return DeviceRegistry::register_special_device(DeviceRegistry::DiskPartition, next_minor++, device, + device->m_device_path.chars(), 0400); + } + + Result PartitionDevice::read(u8* buf, usize offset, usize length) const + { + if (length == 0) return 0; + + if (offset > size()) return 0; + if (offset + length > size()) length = size() - offset; + + return m_host_device->read(buf, m_start_offset + offset, length); + } + + Result PartitionDevice::write(const u8* buf, usize offset, usize length) + { + if (length == 0) return 0; + + if (offset > size()) return 0; + if (offset + length > size()) length = size() - offset; + + return m_host_device->write(buf, m_start_offset + offset, length); + } + Result identify(SharedPtr device) { // Cannot read a partition table from a character device! Who is even coming up with this silliness? if (!device->is_block_device()) return false; DiskHeader hdr; - usize nread = TRY(device->read((u8*)&hdr, 0, sizeof(hdr))); + const usize nread = TRY(device->read((u8*)&hdr, 0, sizeof(hdr))); check(nread == 512); if (hdr.signature[0] != MBR_SIGNATURE_1 || hdr.signature[1] != MBR_SIGNATURE_2) return false; + u32 partition_index = 0; + for (int i = 0; i < 4; i++) { const auto& part = hdr.partitions[i]; @@ -22,6 +69,8 @@ namespace MBR bool bootable = part.attributes & MBR_BOOTABLE; kinfoln("mbr: Partition #%d is active: bootable=%d, type=%x, start=%d, sectors=%d", i, bootable, part.partition_type, part.start_lba, part.num_sectors); + + TRY(PartitionDevice::create(device, part.start_lba, part.num_sectors, partition_index++)); } return true; diff --git a/kernel/src/fs/MBR.h b/kernel/src/fs/MBR.h index b361ea78..7203febb 100644 --- a/kernel/src/fs/MBR.h +++ b/kernel/src/fs/MBR.h @@ -1,6 +1,7 @@ #pragma once #include "fs/devices/DeviceRegistry.h" +#include #include #define MBR_BOOTABLE 0x80 @@ -29,6 +30,53 @@ namespace MBR u8 signature[2]; }; + class PartitionDevice : public Device + { + public: + // Initializer for DeviceRegistry. + static Result create(SharedPtr host_device, usize start_block, usize num_blocks, + u32 partition_index); + + Result read(u8*, usize, usize) const override; + + Result write(const u8* buf, usize offset, usize length) override; + + bool blocking() const override + { + return false; + } + + bool is_block_device() const override + { + return true; + } + + usize size() const override + { + return m_num_blocks * m_block_size; + } + + Result block_size() const override + { + return m_block_size; + } + + StringView device_path() const override + { + return m_device_path.view(); + } + + virtual ~PartitionDevice() = default; + + private: + PartitionDevice() = default; + SharedPtr m_host_device; + usize m_block_size { 512ul }; + usize m_start_offset; + usize m_num_blocks; + String m_device_path; + }; + static_assert(sizeof(DiskHeader) == 512ul); Result identify(SharedPtr device); diff --git a/kernel/src/fs/devices/ConsoleDevice.h b/kernel/src/fs/devices/ConsoleDevice.h index 4a17f832..cf428ef2 100644 --- a/kernel/src/fs/devices/ConsoleDevice.h +++ b/kernel/src/fs/devices/ConsoleDevice.h @@ -17,5 +17,10 @@ class ConsoleDevice : public Device Result ioctl(int request, void* arg) override; + StringView device_path() const override + { + return "console"; + } + virtual ~ConsoleDevice() = default; }; diff --git a/kernel/src/fs/devices/Device.h b/kernel/src/fs/devices/Device.h index e2bb95db..e7e44f27 100644 --- a/kernel/src/fs/devices/Device.h +++ b/kernel/src/fs/devices/Device.h @@ -1,4 +1,5 @@ #pragma once +#include "Log.h" #include class Device @@ -23,6 +24,17 @@ class Device return false; } + virtual Result block_size() const + { + // Block devices should override this function. + kwarnln("Device::block_size() was called on a character device or block device without block size"); + + return err(ENOTSUP); + } + + // Path in devfs. + virtual StringView device_path() const = 0; + virtual bool blocking() const = 0; virtual ~Device() = default; diff --git a/kernel/src/fs/devices/DeviceRegistry.h b/kernel/src/fs/devices/DeviceRegistry.h index b8c01dfe..8ee64e9f 100644 --- a/kernel/src/fs/devices/DeviceRegistry.h +++ b/kernel/src/fs/devices/DeviceRegistry.h @@ -14,6 +14,7 @@ namespace DeviceRegistry Memory = 2, Framebuffer = 3, Disk = 4, + DiskPartition = 5, }; Result> fetch_special_device(u32 major, u32 minor); diff --git a/kernel/src/fs/devices/FramebufferDevice.h b/kernel/src/fs/devices/FramebufferDevice.h index ade9a913..4bf2928c 100644 --- a/kernel/src/fs/devices/FramebufferDevice.h +++ b/kernel/src/fs/devices/FramebufferDevice.h @@ -22,5 +22,10 @@ class FramebufferDevice : public Device usize size() const override; + StringView device_path() const override + { + return "fb0"; + } + virtual ~FramebufferDevice() = default; }; diff --git a/kernel/src/fs/devices/FullDevice.h b/kernel/src/fs/devices/FullDevice.h index 85830003..9102db20 100644 --- a/kernel/src/fs/devices/FullDevice.h +++ b/kernel/src/fs/devices/FullDevice.h @@ -24,5 +24,10 @@ class FullDevice : public Device return false; } + StringView device_path() const override + { + return "full"; + } + virtual ~FullDevice() = default; }; diff --git a/kernel/src/fs/devices/NullDevice.h b/kernel/src/fs/devices/NullDevice.h index 319aeb7e..9f434718 100644 --- a/kernel/src/fs/devices/NullDevice.h +++ b/kernel/src/fs/devices/NullDevice.h @@ -22,5 +22,10 @@ class NullDevice : public Device return false; } + StringView device_path() const override + { + return "null"; + } + virtual ~NullDevice() = default; }; diff --git a/kernel/src/fs/devices/ZeroDevice.h b/kernel/src/fs/devices/ZeroDevice.h index a2aa7b88..8b2fed80 100644 --- a/kernel/src/fs/devices/ZeroDevice.h +++ b/kernel/src/fs/devices/ZeroDevice.h @@ -24,5 +24,10 @@ class ZeroDevice : public Device return false; } + StringView device_path() const override + { + return "zero"; + } + virtual ~ZeroDevice() = default; };