summaryrefslogtreecommitdiff
path: root/Kernel/Devices
diff options
context:
space:
mode:
authorTom <tomut@yahoo.com>2020-09-11 21:11:07 -0600
committerAndreas Kling <kling@serenityos.org>2020-09-13 21:19:15 +0200
commitc8d9f1b9c920e0314bb9ca67f183c8df743e845a (patch)
tree773e9fb30d26602598ba309291b8e6d2e80475e6 /Kernel/Devices
parent7d1b8417bdf5d2818d1c9d310786cdf59650b104 (diff)
downloadserenity-c8d9f1b9c920e0314bb9ca67f183c8df743e845a.zip
Kernel: Make copy_to/from_user safe and remove unnecessary checks
Since the CPU already does almost all necessary validation steps for us, we don't really need to attempt to do this. Doing it ourselves doesn't really work very reliably, because we'd have to account for other processors modifying virtual memory, and we'd have to account for e.g. pages not being able to be allocated due to insufficient resources. So change the copy_to/from_user (and associated helper functions) to use the new safe_memcpy, which will return whether it succeeded or not. The only manual validation step needed (which the CPU can't perform for us) is making sure the pointers provided by user mode aren't pointing to kernel mappings. To make it easier to read/write from/to either kernel or user mode data add the UserOrKernelBuffer helper class, which will internally either use copy_from/to_user or directly memcpy, or pass the data through directly using a temporary buffer on the stack. Last but not least we need to keep syscall params trivial as we need to copy them from/to user mode using copy_from/to_user.
Diffstat (limited to 'Kernel/Devices')
-rw-r--r--Kernel/Devices/BXVGADevice.cpp25
-rw-r--r--Kernel/Devices/BXVGADevice.h8
-rw-r--r--Kernel/Devices/BlockDevice.cpp8
-rw-r--r--Kernel/Devices/BlockDevice.h12
-rw-r--r--Kernel/Devices/DiskPartition.cpp8
-rw-r--r--Kernel/Devices/DiskPartition.h8
-rw-r--r--Kernel/Devices/EBRPartitionTable.cpp13
-rw-r--r--Kernel/Devices/FullDevice.cpp7
-rw-r--r--Kernel/Devices/FullDevice.h4
-rw-r--r--Kernel/Devices/GPTPartitionTable.cpp6
-rw-r--r--Kernel/Devices/KeyboardDevice.cpp12
-rw-r--r--Kernel/Devices/KeyboardDevice.h4
-rw-r--r--Kernel/Devices/MBRPartitionTable.cpp3
-rw-r--r--Kernel/Devices/MBVGADevice.cpp20
-rw-r--r--Kernel/Devices/MBVGADevice.h8
-rw-r--r--Kernel/Devices/NullDevice.cpp4
-rw-r--r--Kernel/Devices/NullDevice.h4
-rw-r--r--Kernel/Devices/PATAChannel.cpp49
-rw-r--r--Kernel/Devices/PATAChannel.h8
-rw-r--r--Kernel/Devices/PATADiskDevice.cpp36
-rw-r--r--Kernel/Devices/PATADiskDevice.h16
-rw-r--r--Kernel/Devices/PS2MouseDevice.cpp7
-rw-r--r--Kernel/Devices/PS2MouseDevice.h4
-rw-r--r--Kernel/Devices/RandomDevice.cpp11
-rw-r--r--Kernel/Devices/RandomDevice.h4
-rw-r--r--Kernel/Devices/SB16.cpp7
-rw-r--r--Kernel/Devices/SB16.h4
-rw-r--r--Kernel/Devices/SerialDevice.cpp25
-rw-r--r--Kernel/Devices/SerialDevice.h4
-rw-r--r--Kernel/Devices/ZeroDevice.cpp7
-rw-r--r--Kernel/Devices/ZeroDevice.h4
31 files changed, 191 insertions, 149 deletions
diff --git a/Kernel/Devices/BXVGADevice.cpp b/Kernel/Devices/BXVGADevice.cpp
index c9f1732260..85040ed747 100644
--- a/Kernel/Devices/BXVGADevice.cpp
+++ b/Kernel/Devices/BXVGADevice.cpp
@@ -203,18 +203,16 @@ int BXVGADevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
switch (request) {
case FB_IOCTL_GET_SIZE_IN_BYTES: {
auto* out = (size_t*)arg;
- if (!Process::current()->validate_write_typed(out))
- return -EFAULT;
size_t value = framebuffer_size_in_bytes();
- copy_to_user(out, &value);
+ if (!copy_to_user(out, &value))
+ return -EFAULT;
return 0;
}
case FB_IOCTL_GET_BUFFER: {
auto* index = (int*)arg;
- if (!Process::current()->validate_write_typed(index))
- return -EFAULT;
int value = m_y_offset == 0 ? 0 : 1;
- copy_to_user(index, &value);
+ if (!copy_to_user(index, &value))
+ return -EFAULT;
return 0;
}
case FB_IOCTL_SET_BUFFER: {
@@ -225,21 +223,18 @@ int BXVGADevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
}
case FB_IOCTL_GET_RESOLUTION: {
auto* user_resolution = (FBResolution*)arg;
- if (!Process::current()->validate_write_typed(user_resolution))
- return -EFAULT;
FBResolution resolution;
resolution.pitch = m_framebuffer_pitch;
resolution.width = m_framebuffer_width;
resolution.height = m_framebuffer_height;
- copy_to_user(user_resolution, &resolution);
+ if (!copy_to_user(user_resolution, &resolution))
+ return -EFAULT;
return 0;
}
case FB_IOCTL_SET_RESOLUTION: {
auto* user_resolution = (FBResolution*)arg;
- if (!Process::current()->validate_write_typed(user_resolution))
- return -EFAULT;
FBResolution resolution;
- if (!Process::current()->validate_read_and_copy_typed(&resolution, user_resolution))
+ if (!copy_from_user(&resolution, user_resolution))
return -EFAULT;
if (resolution.width > MAX_RESOLUTION_WIDTH || resolution.height > MAX_RESOLUTION_HEIGHT)
return -EINVAL;
@@ -250,7 +245,8 @@ int BXVGADevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
resolution.pitch = m_framebuffer_pitch;
resolution.width = m_framebuffer_width;
resolution.height = m_framebuffer_height;
- copy_to_user(user_resolution, &resolution);
+ if (!copy_to_user(user_resolution, &resolution))
+ return -EFAULT;
return -EINVAL;
}
#ifdef BXVGA_DEBUG
@@ -259,7 +255,8 @@ int BXVGADevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
resolution.pitch = m_framebuffer_pitch;
resolution.width = m_framebuffer_width;
resolution.height = m_framebuffer_height;
- copy_to_user(user_resolution, &resolution);
+ if (!copy_to_user(user_resolution, &resolution))
+ return -EFAULT;
return 0;
}
default:
diff --git a/Kernel/Devices/BXVGADevice.h b/Kernel/Devices/BXVGADevice.h
index 213fc1617c..6b98db525b 100644
--- a/Kernel/Devices/BXVGADevice.h
+++ b/Kernel/Devices/BXVGADevice.h
@@ -48,10 +48,10 @@ private:
virtual const char* class_name() const override { return "BXVGA"; }
virtual bool can_read(const FileDescription&, size_t) const override { return true; }
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override { return -EINVAL; }
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override { return -EINVAL; }
- virtual bool read_blocks(unsigned, u16, u8*) override { return false; }
- virtual bool write_blocks(unsigned, u16, const u8*) override { return false; }
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override { return -EINVAL; }
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override { return -EINVAL; }
+ virtual bool read_blocks(unsigned, u16, UserOrKernelBuffer&) override { return false; }
+ virtual bool write_blocks(unsigned, u16, const UserOrKernelBuffer&) override { return false; }
void set_safe_resolution();
diff --git a/Kernel/Devices/BlockDevice.cpp b/Kernel/Devices/BlockDevice.cpp
index 2120db0edc..d78388b610 100644
--- a/Kernel/Devices/BlockDevice.cpp
+++ b/Kernel/Devices/BlockDevice.cpp
@@ -32,17 +32,17 @@ BlockDevice::~BlockDevice()
{
}
-bool BlockDevice::read_block(unsigned index, u8* buffer) const
+bool BlockDevice::read_block(unsigned index, UserOrKernelBuffer& buffer) const
{
return const_cast<BlockDevice*>(this)->read_blocks(index, 1, buffer);
}
-bool BlockDevice::write_block(unsigned index, const u8* data)
+bool BlockDevice::write_block(unsigned index, const UserOrKernelBuffer& data)
{
return write_blocks(index, 1, data);
}
-bool BlockDevice::read_raw(u32 offset, unsigned length, u8* out) const
+bool BlockDevice::read_raw(u32 offset, unsigned length, UserOrKernelBuffer& out) const
{
ASSERT((offset % block_size()) == 0);
ASSERT((length % block_size()) == 0);
@@ -51,7 +51,7 @@ bool BlockDevice::read_raw(u32 offset, unsigned length, u8* out) const
return const_cast<BlockDevice*>(this)->read_blocks(first_block, end_block - first_block, out);
}
-bool BlockDevice::write_raw(u32 offset, unsigned length, const u8* in)
+bool BlockDevice::write_raw(u32 offset, unsigned length, const UserOrKernelBuffer& in)
{
ASSERT((offset % block_size()) == 0);
ASSERT((length % block_size()) == 0);
diff --git a/Kernel/Devices/BlockDevice.h b/Kernel/Devices/BlockDevice.h
index 042a2cfce1..69786df3f8 100644
--- a/Kernel/Devices/BlockDevice.h
+++ b/Kernel/Devices/BlockDevice.h
@@ -37,13 +37,13 @@ public:
size_t block_size() const { return m_block_size; }
virtual bool is_seekable() const override { return true; }
- bool read_block(unsigned index, u8*) const;
- bool write_block(unsigned index, const u8*);
- bool read_raw(u32 offset, unsigned length, u8*) const;
- bool write_raw(u32 offset, unsigned length, const u8*);
+ bool read_block(unsigned index, UserOrKernelBuffer&) const;
+ bool write_block(unsigned index, const UserOrKernelBuffer&);
+ bool read_raw(u32 offset, unsigned length, UserOrKernelBuffer&) const;
+ bool write_raw(u32 offset, unsigned length, const UserOrKernelBuffer&);
- virtual bool read_blocks(unsigned index, u16 count, u8*) = 0;
- virtual bool write_blocks(unsigned index, u16 count, const u8*) = 0;
+ virtual bool read_blocks(unsigned index, u16 count, UserOrKernelBuffer&) = 0;
+ virtual bool write_blocks(unsigned index, u16 count, const UserOrKernelBuffer&) = 0;
protected:
BlockDevice(unsigned major, unsigned minor, size_t block_size = PAGE_SIZE)
diff --git a/Kernel/Devices/DiskPartition.cpp b/Kernel/Devices/DiskPartition.cpp
index 75f83d3976..d1ccb90d1b 100644
--- a/Kernel/Devices/DiskPartition.cpp
+++ b/Kernel/Devices/DiskPartition.cpp
@@ -48,7 +48,7 @@ DiskPartition::~DiskPartition()
{
}
-KResultOr<size_t> DiskPartition::read(FileDescription& fd, size_t offset, u8* outbuf, size_t len)
+KResultOr<size_t> DiskPartition::read(FileDescription& fd, size_t offset, UserOrKernelBuffer& outbuf, size_t len)
{
unsigned adjust = m_block_offset * block_size();
@@ -70,7 +70,7 @@ bool DiskPartition::can_read(const FileDescription& fd, size_t offset) const
return m_device->can_read(fd, offset + adjust);
}
-KResultOr<size_t> DiskPartition::write(FileDescription& fd, size_t offset, const u8* inbuf, size_t len)
+KResultOr<size_t> DiskPartition::write(FileDescription& fd, size_t offset, const UserOrKernelBuffer& inbuf, size_t len)
{
unsigned adjust = m_block_offset * block_size();
@@ -92,7 +92,7 @@ bool DiskPartition::can_write(const FileDescription& fd, size_t offset) const
return m_device->can_write(fd, offset + adjust);
}
-bool DiskPartition::read_blocks(unsigned index, u16 count, u8* out)
+bool DiskPartition::read_blocks(unsigned index, u16 count, UserOrKernelBuffer& out)
{
#ifdef OFFD_DEBUG
klog() << "DiskPartition::read_blocks " << index << " (really: " << (m_block_offset + index) << ") count=" << count;
@@ -101,7 +101,7 @@ bool DiskPartition::read_blocks(unsigned index, u16 count, u8* out)
return m_device->read_blocks(m_block_offset + index, count, out);
}
-bool DiskPartition::write_blocks(unsigned index, u16 count, const u8* data)
+bool DiskPartition::write_blocks(unsigned index, u16 count, const UserOrKernelBuffer& data)
{
#ifdef OFFD_DEBUG
klog() << "DiskPartition::write_blocks " << index << " (really: " << (m_block_offset + index) << ") count=" << count;
diff --git a/Kernel/Devices/DiskPartition.h b/Kernel/Devices/DiskPartition.h
index 51d3342869..e9551b8097 100644
--- a/Kernel/Devices/DiskPartition.h
+++ b/Kernel/Devices/DiskPartition.h
@@ -36,13 +36,13 @@ public:
static NonnullRefPtr<DiskPartition> create(BlockDevice&, unsigned block_offset, unsigned block_limit);
virtual ~DiskPartition();
- virtual bool read_blocks(unsigned index, u16 count, u8*) override;
- virtual bool write_blocks(unsigned index, u16 count, const u8*) override;
+ virtual bool read_blocks(unsigned index, u16 count, UserOrKernelBuffer&) override;
+ virtual bool write_blocks(unsigned index, u16 count, const UserOrKernelBuffer&) override;
// ^BlockDevice
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
virtual bool can_read(const FileDescription&, size_t) const override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_write(const FileDescription&, size_t) const override;
private:
diff --git a/Kernel/Devices/EBRPartitionTable.cpp b/Kernel/Devices/EBRPartitionTable.cpp
index 095fc78ecd..48826636de 100644
--- a/Kernel/Devices/EBRPartitionTable.cpp
+++ b/Kernel/Devices/EBRPartitionTable.cpp
@@ -63,7 +63,8 @@ int EBRPartitionTable::index_of_ebr_container() const
bool EBRPartitionTable::initialize()
{
- if (!m_device->read_block(0, m_cached_mbr_header)) {
+ auto mbr_header_buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_mbr_header);
+ if (!m_device->read_block(0, mbr_header_buffer)) {
return false;
}
auto& header = this->header();
@@ -80,7 +81,8 @@ bool EBRPartitionTable::initialize()
}
auto& ebr_entry = header.entry[m_ebr_container_id - 1];
- if (!m_device->read_block(ebr_entry.offset, m_cached_ebr_header)) {
+ auto ebr_header_buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_ebr_header);
+ if (!m_device->read_block(ebr_entry.offset, ebr_header_buffer)) {
return false;
}
size_t index = 1;
@@ -89,7 +91,7 @@ bool EBRPartitionTable::initialize()
break;
}
index++;
- if (!m_device->read_block(ebr_extension().next_chained_ebr_extension.offset, m_cached_ebr_header)) {
+ if (!m_device->read_block(ebr_extension().next_chained_ebr_extension.offset, ebr_header_buffer)) {
return false;
}
}
@@ -140,7 +142,8 @@ RefPtr<DiskPartition> EBRPartitionTable::get_extended_partition(unsigned index)
klog() << "EBRPartitionTable::partition: Extended partition, offset 0x" << String::format("%x", ebr_entry.offset) << ", type " << String::format("%x", ebr_entry.type);
#endif
- if (!m_device->read_block(ebr_entry.offset, m_cached_ebr_header)) {
+ auto ebr_header_buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_ebr_header);
+ if (!m_device->read_block(ebr_entry.offset, ebr_header_buffer)) {
return nullptr;
}
size_t i = 0;
@@ -154,7 +157,7 @@ RefPtr<DiskPartition> EBRPartitionTable::get_extended_partition(unsigned index)
}
i++;
- if (!m_device->read_block(ebr_extension().next_chained_ebr_extension.offset, m_cached_ebr_header)) {
+ if (!m_device->read_block(ebr_extension().next_chained_ebr_extension.offset, ebr_header_buffer)) {
return nullptr;
}
}
diff --git a/Kernel/Devices/FullDevice.cpp b/Kernel/Devices/FullDevice.cpp
index bfd2c15a82..0d43d7a950 100644
--- a/Kernel/Devices/FullDevice.cpp
+++ b/Kernel/Devices/FullDevice.cpp
@@ -46,14 +46,15 @@ bool FullDevice::can_read(const FileDescription&, size_t) const
return true;
}
-KResultOr<size_t> FullDevice::read(FileDescription&, size_t, u8* buffer, size_t size)
+KResultOr<size_t> FullDevice::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t size)
{
ssize_t count = min(static_cast<size_t>(PAGE_SIZE), size);
- memset(buffer, 0, count);
+ if (!buffer.memset(0, count))
+ return KResult(-EFAULT);
return count;
}
-KResultOr<size_t> FullDevice::write(FileDescription&, size_t, const u8*, size_t size)
+KResultOr<size_t> FullDevice::write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t size)
{
if (size == 0)
return 0;
diff --git a/Kernel/Devices/FullDevice.h b/Kernel/Devices/FullDevice.h
index 3404ce22aa..43070686c1 100644
--- a/Kernel/Devices/FullDevice.h
+++ b/Kernel/Devices/FullDevice.h
@@ -38,8 +38,8 @@ public:
private:
// ^CharacterDevice
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_read(const FileDescription&, size_t) const override;
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
virtual const char* class_name() const override { return "FullDevice"; }
diff --git a/Kernel/Devices/GPTPartitionTable.cpp b/Kernel/Devices/GPTPartitionTable.cpp
index e5413a0336..f442952cd6 100644
--- a/Kernel/Devices/GPTPartitionTable.cpp
+++ b/Kernel/Devices/GPTPartitionTable.cpp
@@ -49,7 +49,8 @@ const GPTPartitionHeader& GPTPartitionTable::header() const
bool GPTPartitionTable::initialize()
{
- if (!m_device->read_block(1, m_cached_header)) {
+ auto header_buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_header);
+ if (!m_device->read_block(1, header_buffer)) {
return false;
}
@@ -82,7 +83,8 @@ RefPtr<DiskPartition> GPTPartitionTable::partition(unsigned index)
u8 entries_per_sector = BytesPerSector / header.partition_entry_size;
GPTPartitionEntry entries[entries_per_sector];
- this->m_device->read_blocks(lba, 1, (u8*)&entries);
+ auto entries_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&entries);
+ this->m_device->read_blocks(lba, 1, entries_buffer);
GPTPartitionEntry& entry = entries[((index - 1) % entries_per_sector)];
#ifdef GPT_DEBUG
diff --git a/Kernel/Devices/KeyboardDevice.cpp b/Kernel/Devices/KeyboardDevice.cpp
index 531c488a9f..9f60268986 100644
--- a/Kernel/Devices/KeyboardDevice.cpp
+++ b/Kernel/Devices/KeyboardDevice.cpp
@@ -369,7 +369,7 @@ bool KeyboardDevice::can_read(const FileDescription&, size_t) const
return !m_queue.is_empty();
}
-KResultOr<size_t> KeyboardDevice::read(FileDescription&, size_t, u8* buffer, size_t size)
+KResultOr<size_t> KeyboardDevice::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t size)
{
size_t nread = 0;
while (nread < size) {
@@ -379,13 +379,19 @@ KResultOr<size_t> KeyboardDevice::read(FileDescription&, size_t, u8* buffer, siz
if ((size - nread) < (ssize_t)sizeof(Event))
break;
auto event = m_queue.dequeue();
- memcpy(buffer, &event, sizeof(Event));
+ ssize_t n = buffer.write_buffered<sizeof(Event)>(sizeof(Event), [&](u8* data, size_t data_bytes) {
+ memcpy(data, &event, sizeof(Event));
+ return (ssize_t)data_bytes;
+ });
+ if (n < 0)
+ return KResult(n);
+ ASSERT((size_t)n == sizeof(Event));
nread += sizeof(Event);
}
return nread;
}
-KResultOr<size_t> KeyboardDevice::write(FileDescription&, size_t, const u8*, size_t)
+KResultOr<size_t> KeyboardDevice::write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t)
{
return 0;
}
diff --git a/Kernel/Devices/KeyboardDevice.h b/Kernel/Devices/KeyboardDevice.h
index 74a53a0da6..1d7f60ab7d 100644
--- a/Kernel/Devices/KeyboardDevice.h
+++ b/Kernel/Devices/KeyboardDevice.h
@@ -57,9 +57,9 @@ public:
const String keymap_name() { return m_character_map.character_map_name(); }
// ^CharacterDevice
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
virtual bool can_read(const FileDescription&, size_t) const override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
virtual const char* purpose() const override { return class_name(); }
diff --git a/Kernel/Devices/MBRPartitionTable.cpp b/Kernel/Devices/MBRPartitionTable.cpp
index b836a9b479..a57a5db310 100644
--- a/Kernel/Devices/MBRPartitionTable.cpp
+++ b/Kernel/Devices/MBRPartitionTable.cpp
@@ -49,7 +49,8 @@ const MBRPartitionHeader& MBRPartitionTable::header() const
bool MBRPartitionTable::initialize()
{
- if (!m_device->read_block(0, m_cached_header)) {
+ auto header_buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_header);
+ if (!m_device->read_block(0, header_buffer)) {
return false;
}
diff --git a/Kernel/Devices/MBVGADevice.cpp b/Kernel/Devices/MBVGADevice.cpp
index f19de93e41..84998f14c8 100644
--- a/Kernel/Devices/MBVGADevice.cpp
+++ b/Kernel/Devices/MBVGADevice.cpp
@@ -79,40 +79,36 @@ int MBVGADevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
switch (request) {
case FB_IOCTL_GET_SIZE_IN_BYTES: {
auto* out = (size_t*)arg;
- if (!Process::current()->validate_write_typed(out))
- return -EFAULT;
size_t value = framebuffer_size_in_bytes();
- copy_to_user(out, &value);
+ if (!copy_to_user(out, &value))
+ return -EFAULT;
return 0;
}
case FB_IOCTL_GET_BUFFER: {
auto* index = (int*)arg;
- if (!Process::current()->validate_write_typed(index))
- return -EFAULT;
int value = 0;
- copy_to_user(index, &value);
+ if (!copy_to_user(index, &value))
+ return -EFAULT;
return 0;
}
case FB_IOCTL_GET_RESOLUTION: {
auto* user_resolution = (FBResolution*)arg;
- if (!Process::current()->validate_write_typed(user_resolution))
- return -EFAULT;
FBResolution resolution;
resolution.pitch = m_framebuffer_pitch;
resolution.width = m_framebuffer_width;
resolution.height = m_framebuffer_height;
- copy_to_user(user_resolution, &resolution);
+ if (!copy_to_user(user_resolution, &resolution))
+ return -EFAULT;
return 0;
}
case FB_IOCTL_SET_RESOLUTION: {
auto* user_resolution = (FBResolution*)arg;
- if (!Process::current()->validate_read_typed(user_resolution) || !Process::current()->validate_write_typed(user_resolution))
- return -EFAULT;
FBResolution resolution;
resolution.pitch = m_framebuffer_pitch;
resolution.width = m_framebuffer_width;
resolution.height = m_framebuffer_height;
- copy_to_user(user_resolution, &resolution);
+ if (!copy_to_user(user_resolution, &resolution))
+ return -EFAULT;
return 0;
}
default:
diff --git a/Kernel/Devices/MBVGADevice.h b/Kernel/Devices/MBVGADevice.h
index 8a7d60e54c..09dda1f853 100644
--- a/Kernel/Devices/MBVGADevice.h
+++ b/Kernel/Devices/MBVGADevice.h
@@ -47,10 +47,10 @@ private:
virtual const char* class_name() const override { return "MBVGA"; }
virtual bool can_read(const FileDescription&, size_t) const override { return true; }
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override { return -EINVAL; }
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override { return -EINVAL; }
- virtual bool read_blocks(unsigned, u16, u8*) override { return false; }
- virtual bool write_blocks(unsigned, u16, const u8*) override { return false; }
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override { return -EINVAL; }
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override { return -EINVAL; }
+ virtual bool read_blocks(unsigned, u16, UserOrKernelBuffer&) override { return false; }
+ virtual bool write_blocks(unsigned, u16, const UserOrKernelBuffer&) override { return false; }
size_t framebuffer_size_in_bytes() const { return m_framebuffer_pitch * m_framebuffer_height; }
diff --git a/Kernel/Devices/NullDevice.cpp b/Kernel/Devices/NullDevice.cpp
index 5c6a5c59c5..260e8d9aa8 100644
--- a/Kernel/Devices/NullDevice.cpp
+++ b/Kernel/Devices/NullDevice.cpp
@@ -56,12 +56,12 @@ bool NullDevice::can_read(const FileDescription&, size_t) const
return true;
}
-KResultOr<size_t> NullDevice::read(FileDescription&, size_t, u8*, size_t)
+KResultOr<size_t> NullDevice::read(FileDescription&, size_t, UserOrKernelBuffer&, size_t)
{
return 0;
}
-KResultOr<size_t> NullDevice::write(FileDescription&, size_t, const u8*, size_t buffer_size)
+KResultOr<size_t> NullDevice::write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t buffer_size)
{
return min(static_cast<size_t>(PAGE_SIZE), buffer_size);
}
diff --git a/Kernel/Devices/NullDevice.h b/Kernel/Devices/NullDevice.h
index c7968258f7..4fcc9c0258 100644
--- a/Kernel/Devices/NullDevice.h
+++ b/Kernel/Devices/NullDevice.h
@@ -41,8 +41,8 @@ public:
private:
// ^CharacterDevice
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
virtual bool can_read(const FileDescription&, size_t) const override;
virtual const char* class_name() const override { return "NullDevice"; }
diff --git a/Kernel/Devices/PATAChannel.cpp b/Kernel/Devices/PATAChannel.cpp
index 172816ea1b..cc47ff532c 100644
--- a/Kernel/Devices/PATAChannel.cpp
+++ b/Kernel/Devices/PATAChannel.cpp
@@ -274,11 +274,11 @@ void PATAChannel::detect_disks()
}
}
-bool PATAChannel::ata_read_sectors_with_dma(u32 lba, u16 count, u8* outbuf, bool slave_request)
+bool PATAChannel::ata_read_sectors_with_dma(u32 lba, u16 count, UserOrKernelBuffer& outbuf, bool slave_request)
{
LOCKER(s_lock());
#ifdef PATA_DEBUG
- dbg() << "PATAChannel::ata_read_sectors_with_dma (" << lba << " x" << count << ") -> " << outbuf;
+ dbg() << "PATAChannel::ata_read_sectors_with_dma (" << lba << " x" << count << ") -> " << outbuf.user_or_kernel_ptr();
#endif
prdt().offset = m_dma_buffer_page->paddr();
@@ -335,24 +335,26 @@ bool PATAChannel::ata_read_sectors_with_dma(u32 lba, u16 count, u8* outbuf, bool
if (m_device_error)
return false;
- memcpy(outbuf, m_dma_buffer_page->paddr().offset(0xc0000000).as_ptr(), 512 * count);
+ if (!outbuf.write(m_dma_buffer_page->paddr().offset(0xc0000000).as_ptr(), 512 * count))
+ return false; // TODO: -EFAULT
// I read somewhere that this may trigger a cache flush so let's do it.
m_bus_master_base.offset(2).out<u8>(m_bus_master_base.offset(2).in<u8>() | 0x6);
return true;
}
-bool PATAChannel::ata_write_sectors_with_dma(u32 lba, u16 count, const u8* inbuf, bool slave_request)
+bool PATAChannel::ata_write_sectors_with_dma(u32 lba, u16 count, const UserOrKernelBuffer& inbuf, bool slave_request)
{
LOCKER(s_lock());
#ifdef PATA_DEBUG
- dbg() << "PATAChannel::ata_write_sectors_with_dma (" << lba << " x" << count << ") <- " << inbuf;
+ dbg() << "PATAChannel::ata_write_sectors_with_dma (" << lba << " x" << count << ") <- " << inbuf.user_or_kernel_ptr();
#endif
prdt().offset = m_dma_buffer_page->paddr();
prdt().size = 512 * count;
- memcpy(m_dma_buffer_page->paddr().offset(0xc0000000).as_ptr(), inbuf, 512 * count);
+ if (!inbuf.read(m_dma_buffer_page->paddr().offset(0xc0000000).as_ptr(), 512 * count))
+ return false; // TODO: -EFAULT
ASSERT(prdt().size <= PAGE_SIZE);
@@ -406,12 +408,12 @@ bool PATAChannel::ata_write_sectors_with_dma(u32 lba, u16 count, const u8* inbuf
return true;
}
-bool PATAChannel::ata_read_sectors(u32 lba, u16 count, u8* outbuf, bool slave_request)
+bool PATAChannel::ata_read_sectors(u32 lba, u16 count, UserOrKernelBuffer& outbuf, bool slave_request)
{
ASSERT(count <= 256);
LOCKER(s_lock());
#ifdef PATA_DEBUG
- dbg() << "PATAChannel::ata_read_sectors request (" << count << " sector(s) @ " << lba << " into " << outbuf << ")";
+ dbg() << "PATAChannel::ata_read_sectors request (" << count << " sector(s) @ " << lba << " into " << outbuf.user_or_kernel_ptr() << ")";
#endif
while (m_io_base.offset(ATA_REG_STATUS).in<u8>() & ATA_SR_BSY)
@@ -460,14 +462,21 @@ bool PATAChannel::ata_read_sectors(u32 lba, u16 count, u8* outbuf, bool slave_re
u8 status = m_control_base.offset(ATA_CTL_ALTSTATUS).in<u8>();
ASSERT(!(status & ATA_SR_BSY));
- auto* buffer = (u16*)(outbuf + i * 512);
+ auto out = outbuf.offset(i * 512);
#ifdef PATA_DEBUG
- dbg() << "PATAChannel: Retrieving 512 bytes (part " << i << ") (status=" << String::format("%b", status) << "), outbuf=(" << buffer << ")...";
+ dbg() << "PATAChannel: Retrieving 512 bytes (part " << i << ") (status=" << String::format("%b", status) << "), outbuf=(" << out.user_or_kernel_ptr() << ")...";
#endif
prepare_for_irq();
- for (int i = 0; i < 256; i++) {
- buffer[i] = IO::in16(m_io_base.offset(ATA_REG_DATA).get());
+ ssize_t nwritten = out.write_buffered<512>(512, [&](u8* buffer, size_t buffer_bytes) {
+ for (size_t i = 0; i < buffer_bytes; i += sizeof(u16))
+ *(u16*)&buffer[i] = IO::in16(m_io_base.offset(ATA_REG_DATA).get());
+ return (ssize_t)buffer_bytes;
+ });
+ if (nwritten < 0) {
+ sti();
+ disable_irq();
+ return false; // TODO: -EFAULT
}
}
@@ -476,7 +485,7 @@ bool PATAChannel::ata_read_sectors(u32 lba, u16 count, u8* outbuf, bool slave_re
return true;
}
-bool PATAChannel::ata_write_sectors(u32 start_sector, u16 count, const u8* inbuf, bool slave_request)
+bool PATAChannel::ata_write_sectors(u32 start_sector, u16 count, const UserOrKernelBuffer& inbuf, bool slave_request)
{
ASSERT(count <= 256);
LOCKER(s_lock());
@@ -515,17 +524,21 @@ bool PATAChannel::ata_write_sectors(u32 start_sector, u16 count, const u8* inbuf
u8 status = m_io_base.offset(ATA_REG_STATUS).in<u8>();
ASSERT(status & ATA_SR_DRQ);
+ auto in = inbuf.offset(i * 512);
#ifdef PATA_DEBUG
- dbg() << "PATAChannel: Writing 512 bytes (part " << i << ") (status=" << String::format("%b", status) << "), inbuf=(" << (inbuf + (512 * i)) << ")...";
+ dbg() << "PATAChannel: Writing 512 bytes (part " << i << ") (status=" << String::format("%b", status) << "), inbuf=(" << in.user_or_kernel_ptr() << ")...";
#endif
prepare_for_irq();
- auto* buffer = (u16*)(const_cast<u8*>(inbuf) + i * 512);
- for (int i = 0; i < 256; i++) {
- IO::out16(m_io_base.offset(ATA_REG_DATA).get(), buffer[i]);
- }
+ ssize_t nread = in.read_buffered<512>(512, [&](const u8* buffer, size_t buffer_bytes) {
+ for (size_t i = 0; i < buffer_bytes; i += sizeof(u16))
+ IO::out16(m_io_base.offset(ATA_REG_DATA).get(), *(const u16*)&buffer[i]);
+ return (ssize_t)buffer_bytes;
+ });
wait_for_irq();
status = m_io_base.offset(ATA_REG_STATUS).in<u8>();
ASSERT(!(status & ATA_SR_BSY));
+ if (nread < 0)
+ return false; // TODO: -EFAULT
}
prepare_for_irq();
m_io_base.offset(ATA_REG_COMMAND).out<u8>(ATA_CMD_CACHE_FLUSH);
diff --git a/Kernel/Devices/PATAChannel.h b/Kernel/Devices/PATAChannel.h
index 60ed95d6c1..40e331a4e8 100644
--- a/Kernel/Devices/PATAChannel.h
+++ b/Kernel/Devices/PATAChannel.h
@@ -84,10 +84,10 @@ private:
void detect_disks();
void wait_for_irq();
- bool ata_read_sectors_with_dma(u32, u16, u8*, bool);
- bool ata_write_sectors_with_dma(u32, u16, const u8*, bool);
- bool ata_read_sectors(u32, u16, u8*, bool);
- bool ata_write_sectors(u32, u16, const u8*, bool);
+ bool ata_read_sectors_with_dma(u32, u16, UserOrKernelBuffer&, bool);
+ bool ata_write_sectors_with_dma(u32, u16, const UserOrKernelBuffer&, bool);
+ bool ata_read_sectors(u32, u16, UserOrKernelBuffer&, bool);
+ bool ata_write_sectors(u32, u16, const UserOrKernelBuffer&, bool);
inline void prepare_for_irq();
diff --git a/Kernel/Devices/PATADiskDevice.cpp b/Kernel/Devices/PATADiskDevice.cpp
index 384c0c7bba..a81f7bb557 100644
--- a/Kernel/Devices/PATADiskDevice.cpp
+++ b/Kernel/Devices/PATADiskDevice.cpp
@@ -55,19 +55,19 @@ const char* PATADiskDevice::class_name() const
return "PATADiskDevice";
}
-bool PATADiskDevice::read_blocks(unsigned index, u16 count, u8* out)
+bool PATADiskDevice::read_blocks(unsigned index, u16 count, UserOrKernelBuffer& out)
{
if (!m_channel.m_bus_master_base.is_null() && m_channel.m_dma_enabled.resource())
return read_sectors_with_dma(index, count, out);
return read_sectors(index, count, out);
}
-bool PATADiskDevice::write_blocks(unsigned index, u16 count, const u8* data)
+bool PATADiskDevice::write_blocks(unsigned index, u16 count, const UserOrKernelBuffer& data)
{
if (!m_channel.m_bus_master_base.is_null() && m_channel.m_dma_enabled.resource())
return write_sectors_with_dma(index, count, data);
for (unsigned i = 0; i < count; ++i) {
- if (!write_sectors(index + i, 1, data + i * 512))
+ if (!write_sectors(index + i, 1, data.offset(i * 512)))
return false;
}
return true;
@@ -80,7 +80,7 @@ void PATADiskDevice::set_drive_geometry(u16 cyls, u16 heads, u16 spt)
m_sectors_per_track = spt;
}
-KResultOr<size_t> PATADiskDevice::read(FileDescription&, size_t offset, u8* outbuf, size_t len)
+KResultOr<size_t> PATADiskDevice::read(FileDescription&, size_t offset, UserOrKernelBuffer& outbuf, size_t len)
{
unsigned index = offset / block_size();
u16 whole_blocks = len / block_size();
@@ -107,10 +107,12 @@ KResultOr<size_t> PATADiskDevice::read(FileDescription&, size_t offset, u8* outb
off_t pos = whole_blocks * block_size();
if (remaining > 0) {
- auto buf = ByteBuffer::create_uninitialized(block_size());
- if (!read_blocks(index + whole_blocks, 1, buf.data()))
+ auto data = ByteBuffer::create_uninitialized(block_size());
+ auto data_buffer = UserOrKernelBuffer::for_kernel_buffer(data.data());
+ if (!read_blocks(index + whole_blocks, 1, data_buffer))
return pos;
- memcpy(&outbuf[pos], buf.data(), remaining);
+ if (!outbuf.write(data.data(), pos, remaining))
+ return KResult(-EFAULT);
}
return pos + remaining;
@@ -121,7 +123,7 @@ bool PATADiskDevice::can_read(const FileDescription&, size_t offset) const
return offset < (m_cylinders * m_heads * m_sectors_per_track * block_size());
}
-KResultOr<size_t> PATADiskDevice::write(FileDescription&, size_t offset, const u8* inbuf, size_t len)
+KResultOr<size_t> PATADiskDevice::write(FileDescription&, size_t offset, const UserOrKernelBuffer& inbuf, size_t len)
{
unsigned index = offset / block_size();
u16 whole_blocks = len / block_size();
@@ -151,11 +153,13 @@ KResultOr<size_t> PATADiskDevice::write(FileDescription&, size_t offset, const u
// partial write, we have to read the block's content first, modify it,
// then write the whole block back to the disk.
if (remaining > 0) {
- auto buf = ByteBuffer::create_zeroed(block_size());
- if (!read_blocks(index + whole_blocks, 1, buf.data()))
+ auto data = ByteBuffer::create_zeroed(block_size());
+ auto data_buffer = UserOrKernelBuffer::for_kernel_buffer(data.data());
+ if (!read_blocks(index + whole_blocks, 1, data_buffer))
return pos;
- memcpy(buf.data(), &inbuf[pos], remaining);
- if (!write_blocks(index + whole_blocks, 1, buf.data()))
+ if (!inbuf.read(data.data(), pos, remaining))
+ return KResult(-EFAULT);
+ if (!write_blocks(index + whole_blocks, 1, data_buffer))
return pos;
}
@@ -167,22 +171,22 @@ bool PATADiskDevice::can_write(const FileDescription&, size_t offset) const
return offset < (m_cylinders * m_heads * m_sectors_per_track * block_size());
}
-bool PATADiskDevice::read_sectors_with_dma(u32 lba, u16 count, u8* outbuf)
+bool PATADiskDevice::read_sectors_with_dma(u32 lba, u16 count, UserOrKernelBuffer& outbuf)
{
return m_channel.ata_read_sectors_with_dma(lba, count, outbuf, is_slave());
}
-bool PATADiskDevice::read_sectors(u32 start_sector, u16 count, u8* outbuf)
+bool PATADiskDevice::read_sectors(u32 start_sector, u16 count, UserOrKernelBuffer& outbuf)
{
return m_channel.ata_read_sectors(start_sector, count, outbuf, is_slave());
}
-bool PATADiskDevice::write_sectors_with_dma(u32 lba, u16 count, const u8* inbuf)
+bool PATADiskDevice::write_sectors_with_dma(u32 lba, u16 count, const UserOrKernelBuffer& inbuf)
{
return m_channel.ata_write_sectors_with_dma(lba, count, inbuf, is_slave());
}
-bool PATADiskDevice::write_sectors(u32 start_sector, u16 count, const u8* inbuf)
+bool PATADiskDevice::write_sectors(u32 start_sector, u16 count, const UserOrKernelBuffer& inbuf)
{
return m_channel.ata_write_sectors(start_sector, count, inbuf, is_slave());
}
diff --git a/Kernel/Devices/PATADiskDevice.h b/Kernel/Devices/PATADiskDevice.h
index d9b7fa9432..eb9377e1bf 100644
--- a/Kernel/Devices/PATADiskDevice.h
+++ b/Kernel/Devices/PATADiskDevice.h
@@ -55,15 +55,15 @@ public:
virtual ~PATADiskDevice() override;
// ^DiskDevice
- virtual bool read_blocks(unsigned index, u16 count, u8*) override;
- virtual bool write_blocks(unsigned index, u16 count, const u8*) override;
+ virtual bool read_blocks(unsigned index, u16 count, UserOrKernelBuffer&) override;
+ virtual bool write_blocks(unsigned index, u16 count, const UserOrKernelBuffer&) override;
void set_drive_geometry(u16, u16, u16);
// ^BlockDevice
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
virtual bool can_read(const FileDescription&, size_t) const override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_write(const FileDescription&, size_t) const override;
protected:
@@ -74,10 +74,10 @@ private:
virtual const char* class_name() const override;
bool wait_for_irq();
- bool read_sectors_with_dma(u32 lba, u16 count, u8*);
- bool write_sectors_with_dma(u32 lba, u16 count, const u8*);
- bool read_sectors(u32 lba, u16 count, u8* buffer);
- bool write_sectors(u32 lba, u16 count, const u8* data);
+ bool read_sectors_with_dma(u32 lba, u16 count, UserOrKernelBuffer&);
+ bool write_sectors_with_dma(u32 lba, u16 count, const UserOrKernelBuffer&);
+ bool read_sectors(u32 lba, u16 count, UserOrKernelBuffer& buffer);
+ bool write_sectors(u32 lba, u16 count, const UserOrKernelBuffer& data);
bool is_slave() const;
Lock m_lock { "IDEDiskDevice" };
diff --git a/Kernel/Devices/PS2MouseDevice.cpp b/Kernel/Devices/PS2MouseDevice.cpp
index 65fcc33264..75ae40524e 100644
--- a/Kernel/Devices/PS2MouseDevice.cpp
+++ b/Kernel/Devices/PS2MouseDevice.cpp
@@ -336,7 +336,7 @@ bool PS2MouseDevice::can_read(const FileDescription&, size_t) const
return !m_queue.is_empty();
}
-KResultOr<size_t> PS2MouseDevice::read(FileDescription&, size_t, u8* buffer, size_t size)
+KResultOr<size_t> PS2MouseDevice::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t size)
{
ASSERT(size > 0);
size_t nread = 0;
@@ -349,14 +349,15 @@ KResultOr<size_t> PS2MouseDevice::read(FileDescription&, size_t, u8* buffer, siz
dbg() << "PS2 Mouse Read: Filter packets";
#endif
size_t bytes_read_from_packet = min(remaining_space_in_buffer, sizeof(MousePacket));
- memcpy(buffer + nread, &packet, bytes_read_from_packet);
+ if (!buffer.write(&packet, nread, bytes_read_from_packet))
+ return KResult(-EFAULT);
nread += bytes_read_from_packet;
remaining_space_in_buffer -= bytes_read_from_packet;
}
return nread;
}
-KResultOr<size_t> PS2MouseDevice::write(FileDescription&, size_t, const u8*, size_t)
+KResultOr<size_t> PS2MouseDevice::write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t)
{
return 0;
}
diff --git a/Kernel/Devices/PS2MouseDevice.h b/Kernel/Devices/PS2MouseDevice.h
index 10f382f43d..07cfcc7a61 100644
--- a/Kernel/Devices/PS2MouseDevice.h
+++ b/Kernel/Devices/PS2MouseDevice.h
@@ -45,8 +45,8 @@ public:
// ^CharacterDevice
virtual bool can_read(const FileDescription&, size_t) const override;
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
virtual const char* purpose() const override { return class_name(); }
diff --git a/Kernel/Devices/RandomDevice.cpp b/Kernel/Devices/RandomDevice.cpp
index 5c6b7eb22b..fa625d0ecf 100644
--- a/Kernel/Devices/RandomDevice.cpp
+++ b/Kernel/Devices/RandomDevice.cpp
@@ -43,13 +43,18 @@ bool RandomDevice::can_read(const FileDescription&, size_t) const
return true;
}
-KResultOr<size_t> RandomDevice::read(FileDescription&, size_t, u8* buffer, size_t size)
+KResultOr<size_t> RandomDevice::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t size)
{
- get_good_random_bytes(buffer, size);
+ bool success = buffer.write_buffered<256>(size, [&](u8* data, size_t data_size) {
+ get_good_random_bytes(data, data_size);
+ return (ssize_t)data_size;
+ });
+ if (!success)
+ return KResult(-EFAULT);
return size;
}
-KResultOr<size_t> RandomDevice::write(FileDescription&, size_t, const u8*, size_t size)
+KResultOr<size_t> RandomDevice::write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t size)
{
// FIXME: Use input for entropy? I guess that could be a neat feature?
return min(static_cast<size_t>(PAGE_SIZE), size);
diff --git a/Kernel/Devices/RandomDevice.h b/Kernel/Devices/RandomDevice.h
index d8951297ab..c419934107 100644
--- a/Kernel/Devices/RandomDevice.h
+++ b/Kernel/Devices/RandomDevice.h
@@ -38,8 +38,8 @@ public:
private:
// ^CharacterDevice
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_read(const FileDescription&, size_t) const override;
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
virtual const char* class_name() const override { return "RandomDevice"; }
diff --git a/Kernel/Devices/SB16.cpp b/Kernel/Devices/SB16.cpp
index 8d7406f39b..eb6d15b993 100644
--- a/Kernel/Devices/SB16.cpp
+++ b/Kernel/Devices/SB16.cpp
@@ -177,7 +177,7 @@ bool SB16::can_read(const FileDescription&, size_t) const
return false;
}
-KResultOr<size_t> SB16::read(FileDescription&, size_t, u8*, size_t)
+KResultOr<size_t> SB16::read(FileDescription&, size_t, UserOrKernelBuffer&, size_t)
{
return 0;
}
@@ -231,7 +231,7 @@ void SB16::wait_for_irq()
disable_irq();
}
-KResultOr<size_t> SB16::write(FileDescription&, size_t, const u8* data, size_t length)
+KResultOr<size_t> SB16::write(FileDescription&, size_t, const UserOrKernelBuffer& data, size_t length)
{
if (!m_dma_region) {
auto page = MM.allocate_supervisor_physical_page();
@@ -252,7 +252,8 @@ KResultOr<size_t> SB16::write(FileDescription&, size_t, const u8* data, size_t l
const int sample_rate = 44100;
set_sample_rate(sample_rate);
- memcpy(m_dma_region->vaddr().as_ptr(), data, length);
+ if (!data.read(m_dma_region->vaddr().as_ptr(), length))
+ return KResult(-EFAULT);
dma_start(length);
// 16-bit single-cycle output.
diff --git a/Kernel/Devices/SB16.h b/Kernel/Devices/SB16.h
index e0d5ba7ca3..cc18fde5ef 100644
--- a/Kernel/Devices/SB16.h
+++ b/Kernel/Devices/SB16.h
@@ -47,8 +47,8 @@ public:
// ^CharacterDevice
virtual bool can_read(const FileDescription&, size_t) const override;
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
virtual const char* purpose() const override { return class_name(); }
diff --git a/Kernel/Devices/SerialDevice.cpp b/Kernel/Devices/SerialDevice.cpp
index e286afb7d4..a54a8bed3e 100644
--- a/Kernel/Devices/SerialDevice.cpp
+++ b/Kernel/Devices/SerialDevice.cpp
@@ -45,7 +45,7 @@ bool SerialDevice::can_read(const FileDescription&, size_t) const
return (get_line_status() & DataReady) != 0;
}
-KResultOr<size_t> SerialDevice::read(FileDescription&, size_t, u8* buffer, size_t size)
+KResultOr<size_t> SerialDevice::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t size)
{
if (!size)
return 0;
@@ -53,9 +53,15 @@ KResultOr<size_t> SerialDevice::read(FileDescription&, size_t, u8* buffer, size_
if (!(get_line_status() & DataReady))
return 0;
- buffer[0] = IO::in8(m_base_addr);
+ ssize_t nwritten = buffer.write_buffered<128>(size, [&](u8* data, size_t data_size) {
+ for (size_t i = 0; i < data_size; i++)
+ data[i] = IO::in8(m_base_addr);
+ return (ssize_t)data_size;
+ });
+ if (nwritten < 0)
+ return KResult(nwritten);
- return 1;
+ return size;
}
bool SerialDevice::can_write(const FileDescription&, size_t) const
@@ -63,7 +69,7 @@ bool SerialDevice::can_write(const FileDescription&, size_t) const
return (get_line_status() & EmptyTransmitterHoldingRegister) != 0;
}
-KResultOr<size_t> SerialDevice::write(FileDescription&, size_t, const u8* buffer, size_t size)
+KResultOr<size_t> SerialDevice::write(FileDescription&, size_t, const UserOrKernelBuffer& buffer, size_t size)
{
if (!size)
return 0;
@@ -71,9 +77,14 @@ KResultOr<size_t> SerialDevice::write(FileDescription&, size_t, const u8* buffer
if (!(get_line_status() & EmptyTransmitterHoldingRegister))
return 0;
- IO::out8(m_base_addr, buffer[0]);
-
- return 1;
+ ssize_t nread = buffer.read_buffered<128>(size, [&](const u8* data, size_t data_size) {
+ for (size_t i = 0; i < data_size; i++)
+ IO::out8(m_base_addr, data[i]);
+ return (ssize_t)data_size;
+ });
+ if (nread < 0)
+ return KResult(nread);
+ return (size_t)nread;
}
void SerialDevice::initialize()
diff --git a/Kernel/Devices/SerialDevice.h b/Kernel/Devices/SerialDevice.h
index bac77ce9b1..5c76f5abdf 100644
--- a/Kernel/Devices/SerialDevice.h
+++ b/Kernel/Devices/SerialDevice.h
@@ -43,9 +43,9 @@ public:
// ^CharacterDevice
virtual bool can_read(const FileDescription&, size_t) const override;
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
virtual bool can_write(const FileDescription&, size_t) const override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
enum InterruptEnable {
LowPowerMode = 0x01 << 5,
diff --git a/Kernel/Devices/ZeroDevice.cpp b/Kernel/Devices/ZeroDevice.cpp
index e568d9a215..ac326434d0 100644
--- a/Kernel/Devices/ZeroDevice.cpp
+++ b/Kernel/Devices/ZeroDevice.cpp
@@ -44,14 +44,15 @@ bool ZeroDevice::can_read(const FileDescription&, size_t) const
return true;
}
-KResultOr<size_t> ZeroDevice::read(FileDescription&, size_t, u8* buffer, size_t size)
+KResultOr<size_t> ZeroDevice::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t size)
{
ssize_t count = min(static_cast<size_t>(PAGE_SIZE), size);
- memset(buffer, 0, count);
+ if (!buffer.memset(0, count))
+ return KResult(-EFAULT);
return count;
}
-KResultOr<size_t> ZeroDevice::write(FileDescription&, size_t, const u8*, size_t size)
+KResultOr<size_t> ZeroDevice::write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t size)
{
return min(static_cast<size_t>(PAGE_SIZE), size);
}
diff --git a/Kernel/Devices/ZeroDevice.h b/Kernel/Devices/ZeroDevice.h
index 0f3e76e5d6..f307c6f645 100644
--- a/Kernel/Devices/ZeroDevice.h
+++ b/Kernel/Devices/ZeroDevice.h
@@ -38,8 +38,8 @@ public:
private:
// ^CharacterDevice
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_read(const FileDescription&, size_t) const override;
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
virtual const char* class_name() const override { return "ZeroDevice"; }