Serenity Operating System
at master 165 lines 5.3 kB view raw
1/* 2 * Copyright (c) 2020, the SerenityOS developers. 3 * Copyright (c) 2021, Andreas Kling <kling@serenityos.org> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#pragma once 9 10#include <AK/Types.h> 11#include <AK/Userspace.h> 12#include <Kernel/API/POSIX/errno.h> 13#include <Kernel/Memory/MemoryManager.h> 14#include <Kernel/StdLib.h> 15#include <Kernel/UnixTypes.h> 16 17namespace Kernel { 18 19class [[nodiscard]] UserOrKernelBuffer { 20public: 21 UserOrKernelBuffer() = delete; 22 23 static UserOrKernelBuffer for_kernel_buffer(u8* kernel_buffer) 24 { 25 VERIFY(!kernel_buffer || !Memory::is_user_address(VirtualAddress(kernel_buffer))); 26 return UserOrKernelBuffer(kernel_buffer); 27 } 28 29 static ErrorOr<UserOrKernelBuffer> for_user_buffer(u8* user_buffer, size_t size) 30 { 31 if (user_buffer && !Memory::is_user_range(VirtualAddress(user_buffer), size)) 32 return Error::from_errno(EFAULT); 33 return UserOrKernelBuffer(user_buffer); 34 } 35 36 template<typename UserspaceType> 37 static ErrorOr<UserOrKernelBuffer> for_user_buffer(UserspaceType userspace, size_t size) 38 { 39 if (!Memory::is_user_range(VirtualAddress(userspace.unsafe_userspace_ptr()), size)) 40 return Error::from_errno(EFAULT); 41 return UserOrKernelBuffer(const_cast<u8*>((u8 const*)userspace.unsafe_userspace_ptr())); 42 } 43 44 [[nodiscard]] bool is_kernel_buffer() const; 45 [[nodiscard]] void const* user_or_kernel_ptr() const { return m_buffer; } 46 47 [[nodiscard]] UserOrKernelBuffer offset(size_t offset) const 48 { 49 if (!m_buffer) 50 return *this; 51 UserOrKernelBuffer offset_buffer = *this; 52 offset_buffer.m_buffer += offset; 53 VERIFY(offset_buffer.is_kernel_buffer() == is_kernel_buffer()); 54 return offset_buffer; 55 } 56 57 ErrorOr<NonnullOwnPtr<KString>> try_copy_into_kstring(size_t) const; 58 ErrorOr<void> write(void const* src, size_t offset, size_t len); 59 ErrorOr<void> write(void const* src, size_t len) 60 { 61 return write(src, 0, len); 62 } 63 ErrorOr<void> write(ReadonlyBytes bytes) 64 { 65 return write(bytes.data(), bytes.size()); 66 } 67 68 ErrorOr<void> read(void* dest, size_t offset, size_t len) const; 69 ErrorOr<void> read(void* dest, size_t len) const 70 { 71 return read(dest, 0, len); 72 } 73 74 ErrorOr<void> read(Bytes bytes) const 75 { 76 return read(bytes.data(), bytes.size()); 77 } 78 79 ErrorOr<void> memset(int value, size_t offset, size_t len); 80 ErrorOr<void> memset(int value, size_t len) 81 { 82 return memset(value, 0, len); 83 } 84 85 template<size_t BUFFER_BYTES, typename F> 86 ErrorOr<size_t> write_buffered(size_t offset, size_t len, F f) 87 { 88 if (!m_buffer) 89 return EFAULT; 90 if (is_kernel_buffer()) { 91 // We're transferring directly to a kernel buffer, bypass 92 Bytes bytes { m_buffer + offset, len }; 93 return f(bytes); 94 } 95 96 // The purpose of using a buffer on the stack is that we can 97 // avoid a bunch of small (e.g. 1-byte) copy_to_user calls 98 u8 buffer[BUFFER_BYTES]; 99 size_t nwritten = 0; 100 while (nwritten < len) { 101 auto to_copy = min(sizeof(buffer), len - nwritten); 102 Bytes bytes { buffer, to_copy }; 103 ErrorOr<size_t> copied_or_error = f(bytes); 104 if (copied_or_error.is_error()) 105 return copied_or_error.release_error(); 106 auto copied = copied_or_error.release_value(); 107 VERIFY(copied <= to_copy); 108 TRY(write(buffer, nwritten, copied)); 109 nwritten += copied; 110 if (copied < to_copy) 111 break; 112 } 113 return nwritten; 114 } 115 template<size_t BUFFER_BYTES, typename F> 116 ErrorOr<size_t> write_buffered(size_t len, F f) 117 { 118 return write_buffered<BUFFER_BYTES, F>(0, len, f); 119 } 120 121 template<size_t BUFFER_BYTES, typename F> 122 ErrorOr<size_t> read_buffered(size_t offset, size_t len, F f) const 123 { 124 if (!m_buffer) 125 return EFAULT; 126 if (is_kernel_buffer()) { 127 // We're transferring directly from a kernel buffer, bypass 128 return f({ m_buffer + offset, len }); 129 } 130 131 // The purpose of using a buffer on the stack is that we can 132 // avoid a bunch of small (e.g. 1-byte) copy_from_user calls 133 u8 buffer[BUFFER_BYTES]; 134 size_t nread = 0; 135 while (nread < len) { 136 auto to_copy = min(sizeof(buffer), len - nread); 137 TRY(read(buffer, nread, to_copy)); 138 ReadonlyBytes read_only_bytes { buffer, to_copy }; 139 ErrorOr<size_t> copied_or_error = f(read_only_bytes); 140 if (copied_or_error.is_error()) 141 return copied_or_error.release_error(); 142 auto copied = copied_or_error.release_value(); 143 VERIFY(copied <= to_copy); 144 nread += copied; 145 if (copied < to_copy) 146 break; 147 } 148 return nread; 149 } 150 template<size_t BUFFER_BYTES, typename F> 151 ErrorOr<size_t> read_buffered(size_t len, F f) const 152 { 153 return read_buffered<BUFFER_BYTES, F>(0, len, f); 154 } 155 156private: 157 explicit UserOrKernelBuffer(u8* buffer) 158 : m_buffer(buffer) 159 { 160 } 161 162 u8* m_buffer; 163}; 164 165}