1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 18:17:44 +00:00

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.
This commit is contained in:
Tom 2020-09-11 21:11:07 -06:00 committed by Andreas Kling
parent 7d1b8417bd
commit c8d9f1b9c9
149 changed files with 1585 additions and 1244 deletions

View file

@ -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:

View file

@ -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();

View file

@ -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);

View file

@ -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)

View file

@ -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;

View file

@ -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:

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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"; }

View file

@ -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

View file

@ -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;
}

View file

@ -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(); }

View file

@ -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;
}

View file

@ -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:

View file

@ -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; }

View file

@ -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);
}

View file

@ -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"; }

View file

@ -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);

View file

@ -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();

View file

@ -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());
}

View file

@ -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" };

View file

@ -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;
}

View file

@ -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(); }

View file

@ -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);

View file

@ -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"; }

View file

@ -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.

View file

@ -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(); }

View file

@ -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()

View file

@ -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,

View file

@ -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);
}

View file

@ -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"; }