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:
parent
7d1b8417bd
commit
c8d9f1b9c9
149 changed files with 1585 additions and 1244 deletions
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"; }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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"; }
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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" };
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"; }
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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"; }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue