diff --git a/Kernel/Devices/Device.h b/Kernel/Devices/Device.h index fbe899b55c5..467a81e5ad4 100644 --- a/Kernel/Devices/Device.h +++ b/Kernel/Devices/Device.h @@ -25,6 +25,7 @@ public: uid_t gid() const { return m_gid; } virtual bool is_device() const override { return true; } + virtual bool is_disk_device() const { return false; } protected: Device(unsigned major, unsigned minor); diff --git a/Kernel/Devices/DiskDevice.cpp b/Kernel/Devices/DiskDevice.cpp index 7541e5f01e8..9fc78514973 100644 --- a/Kernel/Devices/DiskDevice.cpp +++ b/Kernel/Devices/DiskDevice.cpp @@ -1,6 +1,7 @@ #include -DiskDevice::DiskDevice() +DiskDevice::DiskDevice(int major, int minor) + : BlockDevice(major, minor) { } diff --git a/Kernel/Devices/DiskDevice.h b/Kernel/Devices/DiskDevice.h index 9912d80b895..873a91c5d71 100644 --- a/Kernel/Devices/DiskDevice.h +++ b/Kernel/Devices/DiskDevice.h @@ -2,11 +2,12 @@ #include #include +#include // FIXME: Support 64-bit DiskOffset typedef u32 DiskOffset; -class DiskDevice : public RefCounted { +class DiskDevice : public BlockDevice { public: virtual ~DiskDevice(); @@ -20,6 +21,8 @@ public: virtual bool read_blocks(unsigned index, u16 count, u8*) = 0; virtual bool write_blocks(unsigned index, u16 count, const u8*) = 0; + virtual bool is_disk_device() const override { return true; }; + protected: - DiskDevice(); + DiskDevice(int major, int minor); }; diff --git a/Kernel/Devices/DiskPartition.cpp b/Kernel/Devices/DiskPartition.cpp index 94921c84079..562ca39e6ec 100644 --- a/Kernel/Devices/DiskPartition.cpp +++ b/Kernel/Devices/DiskPartition.cpp @@ -8,7 +8,8 @@ NonnullRefPtr DiskPartition::create(NonnullRefPtr dev } DiskPartition::DiskPartition(NonnullRefPtr device, unsigned block_offset) - : m_device(move(device)) + : DiskDevice(100, 0) + , m_device(move(device)) , m_block_offset(block_offset) { } diff --git a/Kernel/Devices/DiskPartition.h b/Kernel/Devices/DiskPartition.h index f4e83697c50..dfdeab4c747 100644 --- a/Kernel/Devices/DiskPartition.h +++ b/Kernel/Devices/DiskPartition.h @@ -14,6 +14,12 @@ public: virtual bool read_blocks(unsigned index, u16 count, u8*) override; virtual bool write_blocks(unsigned index, u16 count, const u8*) override; + // ^BlockDevice + virtual ssize_t read(FileDescription&, u8*, ssize_t) override { return 0; } + virtual bool can_read(FileDescription&) const override { return true; } + virtual ssize_t write(FileDescription&, const u8*, ssize_t) override { return 0; } + virtual bool can_write(FileDescription&) const override { return true; } + private: virtual const char* class_name() const override; diff --git a/Kernel/Devices/FloppyDiskDevice.cpp b/Kernel/Devices/FloppyDiskDevice.cpp index a8953599507..de8f03ab877 100644 --- a/Kernel/Devices/FloppyDiskDevice.cpp +++ b/Kernel/Devices/FloppyDiskDevice.cpp @@ -84,6 +84,7 @@ const char* FloppyDiskDevice::class_name() const FloppyDiskDevice::FloppyDiskDevice(FloppyDiskDevice::DriveType type) : IRQHandler(IRQ_FLOPPY_DRIVE) + , DiskDevice(89, (type == FloppyDiskDevice::DriveType::Master) ? 0 : 1) , m_io_base_addr((type == FloppyDiskDevice::DriveType::Master) ? 0x3F0 : 0x370) { initialize(); diff --git a/Kernel/Devices/FloppyDiskDevice.h b/Kernel/Devices/FloppyDiskDevice.h index 8120415d68c..441bf3a5bee 100644 --- a/Kernel/Devices/FloppyDiskDevice.h +++ b/Kernel/Devices/FloppyDiskDevice.h @@ -132,7 +132,7 @@ private: }; public: - static NonnullRefPtr create(DriveType type); + static NonnullRefPtr create(DriveType); virtual ~FloppyDiskDevice() override; // ^DiskDevice @@ -142,6 +142,12 @@ public: virtual bool read_blocks(unsigned index, u16 count, u8*) override; virtual bool write_blocks(unsigned index, u16 count, const u8*) override; + // ^BlockDevice + virtual ssize_t read(FileDescription&, u8*, ssize_t) override { return 0; } + virtual bool can_read(FileDescription&) const override { return true; } + virtual ssize_t write(FileDescription&, const u8*, ssize_t) override { return 0; } + virtual bool can_write(FileDescription&) const override { return true; } + protected: explicit FloppyDiskDevice(DriveType); diff --git a/Kernel/Devices/PATAChannel.cpp b/Kernel/Devices/PATAChannel.cpp index 8847505636f..ece7e0619ad 100644 --- a/Kernel/Devices/PATAChannel.cpp +++ b/Kernel/Devices/PATAChannel.cpp @@ -236,11 +236,12 @@ void PATAChannel::detect_disks() heads, spt); + int major = (m_channel_number == 0) ? 3 : 4; if (i == 0) { - m_master = PATADiskDevice::create(*this, PATADiskDevice::DriveType::Master); + m_master = PATADiskDevice::create(*this, PATADiskDevice::DriveType::Master, major, 0); m_master->set_drive_geometry(cyls, heads, spt); } else { - m_slave = PATADiskDevice::create(*this, PATADiskDevice::DriveType::Slave); + m_slave = PATADiskDevice::create(*this, PATADiskDevice::DriveType::Slave, major, 1); m_slave->set_drive_geometry(cyls, heads, spt); } } diff --git a/Kernel/Devices/PATADiskDevice.cpp b/Kernel/Devices/PATADiskDevice.cpp index 69b50e08c27..627b952180c 100644 --- a/Kernel/Devices/PATADiskDevice.cpp +++ b/Kernel/Devices/PATADiskDevice.cpp @@ -78,13 +78,14 @@ #define ATA_REG_ALTSTATUS 0x0C #define ATA_REG_DEVADDRESS 0x0D -NonnullRefPtr PATADiskDevice::create(PATAChannel& channel, DriveType type) +NonnullRefPtr PATADiskDevice::create(PATAChannel& channel, DriveType type, int major, int minor) { - return adopt(*new PATADiskDevice(channel, type)); + return adopt(*new PATADiskDevice(channel, type, major, minor)); } -PATADiskDevice::PATADiskDevice(PATAChannel& channel, DriveType type) - : m_drive_type(type) +PATADiskDevice::PATADiskDevice(PATAChannel& channel, DriveType type, int major, int minor) + : DiskDevice(major, minor) + , m_drive_type(type) , m_channel(channel) { } diff --git a/Kernel/Devices/PATADiskDevice.h b/Kernel/Devices/PATADiskDevice.h index 3d3c4928d4b..cd23f705e15 100644 --- a/Kernel/Devices/PATADiskDevice.h +++ b/Kernel/Devices/PATADiskDevice.h @@ -26,7 +26,7 @@ public: }; public: - static NonnullRefPtr create(PATAChannel&, DriveType); + static NonnullRefPtr create(PATAChannel&, DriveType, int major, int minor); virtual ~PATADiskDevice() override; // ^DiskDevice @@ -38,8 +38,14 @@ public: void set_drive_geometry(u16, u16, u16); + // ^BlockDevice + virtual ssize_t read(FileDescription&, u8*, ssize_t) override { return 0; } + virtual bool can_read(FileDescription&) const override { return true; } + virtual ssize_t write(FileDescription&, const u8*, ssize_t) override { return 0; } + virtual bool can_write(FileDescription&) const override { return true; } + protected: - explicit PATADiskDevice(PATAChannel&, DriveType); + explicit PATADiskDevice(PATAChannel&, DriveType, int, int); private: // ^DiskDevice diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index f0d58004cb0..bbbe442013d 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -1900,7 +1901,7 @@ int Process::sys$poll(pollfd* fds, int nfds, int timeout) dbgprintf("%s<%u> polling on (read:%u, write:%u), timeout=%d\n", name().characters(), pid(), rfds.size(), wfds.size(), timeout); #endif - if (has_timeout|| timeout < 0) { + if (has_timeout || timeout < 0) { if (current->block(actual_timeout, has_timeout, rfds, wfds, Thread::SelectBlocker::FDVector()) == Thread::BlockResult::InterruptedBySignal) return -EINTR; } @@ -2726,6 +2727,47 @@ int Process::sys$reboot() return ESUCCESS; } +int Process::sys$mount(const char* device, const char* mountpoint) +{ + dbgprintf("mount: device = %s mountpoint = %s\n", device, mountpoint); + if (!validate_read_str(device) || !validate_read_str(mountpoint)) + return -EFAULT; + + // Let's do a stat to get some information about the device.. + // Let's use lstat so we can convert devname into a major/minor device pair! + struct stat st; + int rc = sys$stat(device, &st); + if (rc < 0) { + dbgprintf("mount: call to sys$stat failed!\n"); + return -ENODEV; + } + + int major = (st.st_rdev & 0xfff00u) >> 8u; + int minor = (st.st_rdev & 0xffu) | ((st.st_rdev >> 12u) & 0xfff00u); + + auto* dev = VFS::the().get_device(major, minor); + auto* disk_device = static_cast(dev); + + dbgprintf("mount: attempting to mount %d,%d to %s...\n", major, minor, mountpoint); + + // Do a quick check to make sure we're not passing nullptr to Ext2FS::create! + if (dev == nullptr) + return -ENODEV; + + // We currently only support ext2. Sorry :^) + auto ext2fs = Ext2FS::create(*disk_device); + if (!ext2fs->initialize()) { + dbgprintf("mount: failed to create ext2fs!\n"); + return -ENODEV; // Hmmm, this doesn't seem quite right.... + } + + // Let's mount the volume now + VFS::the().mount(ext2fs, mountpoint); + dbgprintf("mount: successfully mounted ext2 volume on %s to %s!\n", device, mountpoint); + + return ESUCCESS; +} + ProcessTracer& Process::ensure_tracer() { if (!m_tracer) diff --git a/Kernel/Process.h b/Kernel/Process.h index e114bc0cbf8..dfbbfc4771c 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -183,6 +183,7 @@ public: int sys$unlink(const char* pathname); int sys$symlink(const char* target, const char* linkpath); int sys$rmdir(const char* pathname); + int sys$mount(const char* device, const char* mountpoint); int sys$read_tsc(u32* lsw, u32* msw); int sys$chmod(const char* pathname, mode_t); int sys$fchmod(int fd, mode_t); diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 432a593bbaa..b378367ea28 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -292,6 +292,8 @@ static u32 handle(RegisterDump& regs, u32 function, u32 arg1, u32 arg2, u32 arg3 return current->process().sys$halt(); break; } + case Syscall::SC_mount: + return current->process().sys$mount((const char*)arg1, (const char*)arg2); case Syscall::SC_reboot: { return current->process().sys$reboot(); } diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index 44ba85cd88a..0451c415da0 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -116,6 +116,7 @@ struct timeval; __ENUMERATE_SYSCALL(fchown) \ __ENUMERATE_SYSCALL(halt) \ __ENUMERATE_SYSCALL(reboot) \ + __ENUMERATE_SYSCALL(mount) \ __ENUMERATE_SYSCALL(dump_backtrace) \ __ENUMERATE_SYSCALL(dbgputch) \ __ENUMERATE_SYSCALL(dbgputstr) \ diff --git a/Libraries/LibC/unistd.cpp b/Libraries/LibC/unistd.cpp index 922039c09f6..5d9e9bb97d6 100644 --- a/Libraries/LibC/unistd.cpp +++ b/Libraries/LibC/unistd.cpp @@ -546,6 +546,12 @@ int reboot() __RETURN_WITH_ERRNO(rc, rc, -1); } +int mount(const char* device, const char* mountpoint) +{ + int rc = syscall(SC_mount, device, mountpoint); + __RETURN_WITH_ERRNO(rc, rc, -1); +} + void dump_backtrace() { syscall(SC_dump_backtrace); diff --git a/Libraries/LibC/unistd.h b/Libraries/LibC/unistd.h index b4b8928e9c8..567f098c82e 100644 --- a/Libraries/LibC/unistd.h +++ b/Libraries/LibC/unistd.h @@ -98,6 +98,7 @@ int fchown(int fd, uid_t, gid_t); int ftruncate(int fd, off_t length); int halt(); int reboot(); +int mount(const char* device, const char* mountpoint); enum { _PC_NAME_MAX, diff --git a/Userland/mount.cpp b/Userland/mount.cpp new file mode 100644 index 00000000000..751063799e3 --- /dev/null +++ b/Userland/mount.cpp @@ -0,0 +1,29 @@ +#include +#include +#include + +// This version of 'mount' must have the following arguments +// 'mount +// It can currently only mount _physical_ devices found in /dev +// +// Currently, it is only possible to mount ext2 devices. Sorry! :^) +int main(int argc, char** argv) +{ + CArgsParser args_parser("mount"); + args_parser.add_arg("devname", "device path"); + args_parser.add_arg("mountpoint", "mount point"); + CArgsParserResult args = args_parser.parse(argc, argv); + + if (argc == 3) { + // Let's use lstat so we can convert devname into a major/minor device pair! + if (mount(argv[1], argv[2]) < 0) { + perror("mount"); + return 1; + } + } else { + args_parser.print_usage(); + return 0; + } + + return 0; +}