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
Notes:
sideshowbarker
2024-07-19 02:42:35 +09:00
Author: https://github.com/tomuta Commit: https://github.com/SerenityOS/serenity/commit/c8d9f1b9c92 Pull-request: https://github.com/SerenityOS/serenity/pull/3467 Reviewed-by: https://github.com/awesomekling
149 changed files with 1585 additions and 1244 deletions
|
@ -930,7 +930,7 @@ int Emulator::virt$execve(FlatPtr params_addr)
|
||||||
auto copy_string_list = [this](auto& output_vector, auto& string_list) {
|
auto copy_string_list = [this](auto& output_vector, auto& string_list) {
|
||||||
for (size_t i = 0; i < string_list.length; ++i) {
|
for (size_t i = 0; i < string_list.length; ++i) {
|
||||||
Syscall::StringArgument string;
|
Syscall::StringArgument string;
|
||||||
mmu().copy_from_vm(&string, (FlatPtr)&string_list.strings.ptr()[i], sizeof(string));
|
mmu().copy_from_vm(&string, (FlatPtr)&string_list.strings[i], sizeof(string));
|
||||||
output_vector.append(String::copy(mmu().copy_buffer_from_vm((FlatPtr)string.characters, string.length)));
|
output_vector.append(String::copy(mmu().copy_buffer_from_vm((FlatPtr)string.characters, string.length)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1307,7 +1307,7 @@ int Emulator::virt$waitid(FlatPtr params_addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.infop)
|
if (params.infop)
|
||||||
mmu().copy_to_vm(params.infop, &info, sizeof(info));
|
mmu().copy_to_vm((FlatPtr)params.infop, &info, sizeof(info));
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,7 +222,7 @@ inline constexpr const char* to_string(Function function)
|
||||||
|
|
||||||
#ifdef __serenity__
|
#ifdef __serenity__
|
||||||
struct StringArgument {
|
struct StringArgument {
|
||||||
Userspace<const char*> characters;
|
const char* characters;
|
||||||
size_t length { 0 };
|
size_t length { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -239,7 +239,7 @@ struct ImmutableBufferArgument {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StringListArgument {
|
struct StringListArgument {
|
||||||
Userspace<StringArgument*> strings {};
|
StringArgument* strings {};
|
||||||
size_t length { 0 };
|
size_t length { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -273,22 +273,22 @@ struct SC_select_params {
|
||||||
struct SC_poll_params {
|
struct SC_poll_params {
|
||||||
struct pollfd* fds;
|
struct pollfd* fds;
|
||||||
unsigned nfds;
|
unsigned nfds;
|
||||||
Userspace<const struct timespec*> timeout;
|
const struct timespec* timeout;
|
||||||
Userspace<const u32*> sigmask;
|
const u32* sigmask;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SC_clock_nanosleep_params {
|
struct SC_clock_nanosleep_params {
|
||||||
int clock_id;
|
int clock_id;
|
||||||
int flags;
|
int flags;
|
||||||
Userspace<const struct timespec*> requested_sleep;
|
const struct timespec* requested_sleep;
|
||||||
Userspace<struct timespec*> remaining_sleep;
|
struct timespec* remaining_sleep;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SC_sendto_params {
|
struct SC_sendto_params {
|
||||||
int sockfd;
|
int sockfd;
|
||||||
ImmutableBufferArgument<void, size_t> data;
|
ImmutableBufferArgument<void, size_t> data;
|
||||||
int flags;
|
int flags;
|
||||||
Userspace<const sockaddr*> addr;
|
const sockaddr* addr;
|
||||||
socklen_t addr_length;
|
socklen_t addr_length;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -296,50 +296,50 @@ struct SC_recvfrom_params {
|
||||||
int sockfd;
|
int sockfd;
|
||||||
MutableBufferArgument<void, size_t> buffer;
|
MutableBufferArgument<void, size_t> buffer;
|
||||||
int flags;
|
int flags;
|
||||||
Userspace<sockaddr*> addr;
|
sockaddr* addr;
|
||||||
Userspace<socklen_t*> addr_length;
|
socklen_t* addr_length;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SC_getsockopt_params {
|
struct SC_getsockopt_params {
|
||||||
int sockfd;
|
int sockfd;
|
||||||
int level;
|
int level;
|
||||||
int option;
|
int option;
|
||||||
Userspace<void*> value;
|
void* value;
|
||||||
Userspace<socklen_t*> value_size;
|
socklen_t* value_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SC_setsockopt_params {
|
struct SC_setsockopt_params {
|
||||||
int sockfd;
|
int sockfd;
|
||||||
int level;
|
int level;
|
||||||
int option;
|
int option;
|
||||||
Userspace<const void*> value;
|
const void* value;
|
||||||
socklen_t value_size;
|
socklen_t value_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SC_getsockname_params {
|
struct SC_getsockname_params {
|
||||||
int sockfd;
|
int sockfd;
|
||||||
Userspace<sockaddr*> addr;
|
sockaddr* addr;
|
||||||
Userspace<socklen_t*> addrlen;
|
socklen_t* addrlen;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SC_getpeername_params {
|
struct SC_getpeername_params {
|
||||||
int sockfd;
|
int sockfd;
|
||||||
Userspace<sockaddr*> addr;
|
sockaddr* addr;
|
||||||
Userspace<socklen_t*> addrlen;
|
socklen_t* addrlen;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SC_futex_params {
|
struct SC_futex_params {
|
||||||
Userspace<const i32*> userspace_address;
|
const i32* userspace_address;
|
||||||
int futex_op;
|
int futex_op;
|
||||||
i32 val;
|
i32 val;
|
||||||
Userspace<const timespec*> timeout;
|
const timespec* timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SC_setkeymap_params {
|
struct SC_setkeymap_params {
|
||||||
Userspace<const u32*> map;
|
const u32* map;
|
||||||
Userspace<const u32*> shift_map;
|
const u32* shift_map;
|
||||||
Userspace<const u32*> alt_map;
|
const u32* alt_map;
|
||||||
Userspace<const u32*> altgr_map;
|
const u32* altgr_map;
|
||||||
StringArgument map_name;
|
StringArgument map_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -354,7 +354,7 @@ struct SC_create_thread_params {
|
||||||
unsigned int m_guard_page_size = 0; // Rounded up to PAGE_SIZE
|
unsigned int m_guard_page_size = 0; // Rounded up to PAGE_SIZE
|
||||||
unsigned int m_reported_guard_page_size = 0; // The lie we tell callers
|
unsigned int m_reported_guard_page_size = 0; // The lie we tell callers
|
||||||
unsigned int m_stack_size = 4 * MiB; // Default PTHREAD_STACK_MIN
|
unsigned int m_stack_size = 4 * MiB; // Default PTHREAD_STACK_MIN
|
||||||
Userspace<void*> m_stack_location; // nullptr means any, o.w. process virtual address
|
void* m_stack_location; // nullptr means any, o.w. process virtual address
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SC_realpath_params {
|
struct SC_realpath_params {
|
||||||
|
@ -426,26 +426,26 @@ struct SC_unveil_params {
|
||||||
struct SC_waitid_params {
|
struct SC_waitid_params {
|
||||||
int idtype;
|
int idtype;
|
||||||
int id;
|
int id;
|
||||||
Userspace<struct siginfo*> infop;
|
struct siginfo* infop;
|
||||||
int options;
|
int options;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SC_stat_params {
|
struct SC_stat_params {
|
||||||
StringArgument path;
|
StringArgument path;
|
||||||
Userspace<struct stat*> statbuf;
|
struct stat* statbuf;
|
||||||
bool follow_symlinks;
|
bool follow_symlinks;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SC_ptrace_params {
|
struct SC_ptrace_params {
|
||||||
int request;
|
int request;
|
||||||
pid_t tid;
|
pid_t tid;
|
||||||
Userspace<u8*> addr;
|
u8* addr;
|
||||||
int data;
|
int data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SC_ptrace_peek_params {
|
struct SC_ptrace_peek_params {
|
||||||
Userspace<const u32*> address;
|
const u32* address;
|
||||||
Userspace<u32*> out_data;
|
u32* out_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
|
|
|
@ -226,6 +226,7 @@ extern "C" u8* safe_memset_2_faulted;
|
||||||
|
|
||||||
bool safe_memcpy(void* dest_ptr, const void* src_ptr, size_t n, void*& fault_at)
|
bool safe_memcpy(void* dest_ptr, const void* src_ptr, size_t n, void*& fault_at)
|
||||||
{
|
{
|
||||||
|
fault_at = nullptr;
|
||||||
size_t dest = (size_t)dest_ptr;
|
size_t dest = (size_t)dest_ptr;
|
||||||
size_t src = (size_t)src_ptr;
|
size_t src = (size_t)src_ptr;
|
||||||
size_t remainder;
|
size_t remainder;
|
||||||
|
@ -233,7 +234,6 @@ bool safe_memcpy(void* dest_ptr, const void* src_ptr, size_t n, void*& fault_at)
|
||||||
if (!(dest & 0x3) && !(src & 0x3) && n >= 12) {
|
if (!(dest & 0x3) && !(src & 0x3) && n >= 12) {
|
||||||
size_t size_ts = n / sizeof(size_t);
|
size_t size_ts = n / sizeof(size_t);
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"xor %[fault_at], %[fault_at] \n"
|
|
||||||
".global safe_memcpy_ins_1 \n"
|
".global safe_memcpy_ins_1 \n"
|
||||||
"safe_memcpy_ins_1: \n"
|
"safe_memcpy_ins_1: \n"
|
||||||
"rep movsl \n"
|
"rep movsl \n"
|
||||||
|
@ -256,7 +256,6 @@ bool safe_memcpy(void* dest_ptr, const void* src_ptr, size_t n, void*& fault_at)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"xor %[fault_at], %[fault_at] \n"
|
|
||||||
".global safe_memcpy_ins_2 \n"
|
".global safe_memcpy_ins_2 \n"
|
||||||
"safe_memcpy_ins_2: \n"
|
"safe_memcpy_ins_2: \n"
|
||||||
"rep movsb \n"
|
"rep movsb \n"
|
||||||
|
@ -277,8 +276,8 @@ bool safe_memcpy(void* dest_ptr, const void* src_ptr, size_t n, void*& fault_at)
|
||||||
ssize_t safe_strnlen(const char* str, size_t max_n, void*& fault_at)
|
ssize_t safe_strnlen(const char* str, size_t max_n, void*& fault_at)
|
||||||
{
|
{
|
||||||
ssize_t count = 0;
|
ssize_t count = 0;
|
||||||
|
fault_at = nullptr;
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"xor %[fault_at], %[fault_at] \n"
|
|
||||||
"1: \n"
|
"1: \n"
|
||||||
"test %[max_n], %[max_n] \n"
|
"test %[max_n], %[max_n] \n"
|
||||||
"je 2f \n"
|
"je 2f \n"
|
||||||
|
@ -307,6 +306,7 @@ ssize_t safe_strnlen(const char* str, size_t max_n, void*& fault_at)
|
||||||
|
|
||||||
bool safe_memset(void* dest_ptr, int c, size_t n, void*& fault_at)
|
bool safe_memset(void* dest_ptr, int c, size_t n, void*& fault_at)
|
||||||
{
|
{
|
||||||
|
fault_at = nullptr;
|
||||||
size_t dest = (size_t)dest_ptr;
|
size_t dest = (size_t)dest_ptr;
|
||||||
size_t remainder;
|
size_t remainder;
|
||||||
// FIXME: Support starting at an unaligned address.
|
// FIXME: Support starting at an unaligned address.
|
||||||
|
@ -316,7 +316,6 @@ bool safe_memset(void* dest_ptr, int c, size_t n, void*& fault_at)
|
||||||
expanded_c |= expanded_c << 8;
|
expanded_c |= expanded_c << 8;
|
||||||
expanded_c |= expanded_c << 16;
|
expanded_c |= expanded_c << 16;
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"xor %[fault_at], %[fault_at] \n"
|
|
||||||
".global safe_memset_ins_1 \n"
|
".global safe_memset_ins_1 \n"
|
||||||
"safe_memset_ins_1: \n"
|
"safe_memset_ins_1: \n"
|
||||||
"rep stosl \n"
|
"rep stosl \n"
|
||||||
|
@ -338,7 +337,6 @@ bool safe_memset(void* dest_ptr, int c, size_t n, void*& fault_at)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"xor %[fault_at], %[fault_at] \n"
|
|
||||||
".global safe_memset_ins_2 \n"
|
".global safe_memset_ins_2 \n"
|
||||||
"safe_memset_ins_2: \n"
|
"safe_memset_ins_2: \n"
|
||||||
"rep stosb \n"
|
"rep stosb \n"
|
||||||
|
|
|
@ -176,6 +176,7 @@ set(KERNEL_SOURCES
|
||||||
Time/RTC.cpp
|
Time/RTC.cpp
|
||||||
Time/TimeManagement.cpp
|
Time/TimeManagement.cpp
|
||||||
TimerQueue.cpp
|
TimerQueue.cpp
|
||||||
|
UserOrKernelBuffer.cpp
|
||||||
VM/AnonymousVMObject.cpp
|
VM/AnonymousVMObject.cpp
|
||||||
VM/ContiguousVMObject.cpp
|
VM/ContiguousVMObject.cpp
|
||||||
VM/InodeVMObject.cpp
|
VM/InodeVMObject.cpp
|
||||||
|
|
|
@ -65,20 +65,26 @@ bool Console::can_read(const Kernel::FileDescription&, size_t) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::KResultOr<size_t> Console::read(Kernel::FileDescription&, size_t, u8*, size_t)
|
Kernel::KResultOr<size_t> Console::read(Kernel::FileDescription&, size_t, Kernel::UserOrKernelBuffer&, size_t)
|
||||||
{
|
{
|
||||||
// FIXME: Implement reading from the console.
|
// FIXME: Implement reading from the console.
|
||||||
// Maybe we could use a ring buffer for this device?
|
// Maybe we could use a ring buffer for this device?
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::KResultOr<size_t> Console::write(Kernel::FileDescription&, size_t, const u8* data, size_t size)
|
Kernel::KResultOr<size_t> Console::write(Kernel::FileDescription&, size_t, const Kernel::UserOrKernelBuffer& data, size_t size)
|
||||||
{
|
{
|
||||||
if (!size)
|
if (!size)
|
||||||
return 0;
|
return 0;
|
||||||
for (size_t i = 0; i < size; ++i)
|
|
||||||
put_char(data[i]);
|
ssize_t nread = data.read_buffered<256>(size, [&](const u8* bytes, size_t bytes_count) {
|
||||||
return size;
|
for (size_t i = 0; i < bytes_count; i++)
|
||||||
|
put_char((char)bytes[i]);
|
||||||
|
return (ssize_t)bytes_count;
|
||||||
|
});
|
||||||
|
if (nread < 0)
|
||||||
|
return Kernel::KResult(nread);
|
||||||
|
return (size_t)nread;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::put_char(char ch)
|
void Console::put_char(char ch)
|
||||||
|
|
|
@ -43,8 +43,8 @@ public:
|
||||||
// ^CharacterDevice
|
// ^CharacterDevice
|
||||||
virtual bool can_read(const Kernel::FileDescription&, size_t) const override;
|
virtual bool can_read(const Kernel::FileDescription&, size_t) const override;
|
||||||
virtual bool can_write(const Kernel::FileDescription&, size_t) const override { return true; }
|
virtual bool can_write(const Kernel::FileDescription&, size_t) const override { return true; }
|
||||||
virtual Kernel::KResultOr<size_t> read(Kernel::FileDescription&, size_t, u8*, size_t) override;
|
virtual Kernel::KResultOr<size_t> read(Kernel::FileDescription&, size_t, Kernel::UserOrKernelBuffer&, size_t) override;
|
||||||
virtual Kernel::KResultOr<size_t> write(Kernel::FileDescription&, size_t, const u8*, size_t) override;
|
virtual Kernel::KResultOr<size_t> write(Kernel::FileDescription&, size_t, const Kernel::UserOrKernelBuffer&, size_t) override;
|
||||||
virtual const char* class_name() const override { return "Console"; }
|
virtual const char* class_name() const override { return "Console"; }
|
||||||
|
|
||||||
void put_char(char);
|
void put_char(char);
|
||||||
|
|
|
@ -203,18 +203,16 @@ int BXVGADevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
|
||||||
switch (request) {
|
switch (request) {
|
||||||
case FB_IOCTL_GET_SIZE_IN_BYTES: {
|
case FB_IOCTL_GET_SIZE_IN_BYTES: {
|
||||||
auto* out = (size_t*)arg;
|
auto* out = (size_t*)arg;
|
||||||
if (!Process::current()->validate_write_typed(out))
|
|
||||||
return -EFAULT;
|
|
||||||
size_t value = framebuffer_size_in_bytes();
|
size_t value = framebuffer_size_in_bytes();
|
||||||
copy_to_user(out, &value);
|
if (!copy_to_user(out, &value))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case FB_IOCTL_GET_BUFFER: {
|
case FB_IOCTL_GET_BUFFER: {
|
||||||
auto* index = (int*)arg;
|
auto* index = (int*)arg;
|
||||||
if (!Process::current()->validate_write_typed(index))
|
|
||||||
return -EFAULT;
|
|
||||||
int value = m_y_offset == 0 ? 0 : 1;
|
int value = m_y_offset == 0 ? 0 : 1;
|
||||||
copy_to_user(index, &value);
|
if (!copy_to_user(index, &value))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case FB_IOCTL_SET_BUFFER: {
|
case FB_IOCTL_SET_BUFFER: {
|
||||||
|
@ -225,21 +223,18 @@ int BXVGADevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
|
||||||
}
|
}
|
||||||
case FB_IOCTL_GET_RESOLUTION: {
|
case FB_IOCTL_GET_RESOLUTION: {
|
||||||
auto* user_resolution = (FBResolution*)arg;
|
auto* user_resolution = (FBResolution*)arg;
|
||||||
if (!Process::current()->validate_write_typed(user_resolution))
|
|
||||||
return -EFAULT;
|
|
||||||
FBResolution resolution;
|
FBResolution resolution;
|
||||||
resolution.pitch = m_framebuffer_pitch;
|
resolution.pitch = m_framebuffer_pitch;
|
||||||
resolution.width = m_framebuffer_width;
|
resolution.width = m_framebuffer_width;
|
||||||
resolution.height = m_framebuffer_height;
|
resolution.height = m_framebuffer_height;
|
||||||
copy_to_user(user_resolution, &resolution);
|
if (!copy_to_user(user_resolution, &resolution))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case FB_IOCTL_SET_RESOLUTION: {
|
case FB_IOCTL_SET_RESOLUTION: {
|
||||||
auto* user_resolution = (FBResolution*)arg;
|
auto* user_resolution = (FBResolution*)arg;
|
||||||
if (!Process::current()->validate_write_typed(user_resolution))
|
|
||||||
return -EFAULT;
|
|
||||||
FBResolution resolution;
|
FBResolution resolution;
|
||||||
if (!Process::current()->validate_read_and_copy_typed(&resolution, user_resolution))
|
if (!copy_from_user(&resolution, user_resolution))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (resolution.width > MAX_RESOLUTION_WIDTH || resolution.height > MAX_RESOLUTION_HEIGHT)
|
if (resolution.width > MAX_RESOLUTION_WIDTH || resolution.height > MAX_RESOLUTION_HEIGHT)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -250,7 +245,8 @@ int BXVGADevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
|
||||||
resolution.pitch = m_framebuffer_pitch;
|
resolution.pitch = m_framebuffer_pitch;
|
||||||
resolution.width = m_framebuffer_width;
|
resolution.width = m_framebuffer_width;
|
||||||
resolution.height = m_framebuffer_height;
|
resolution.height = m_framebuffer_height;
|
||||||
copy_to_user(user_resolution, &resolution);
|
if (!copy_to_user(user_resolution, &resolution))
|
||||||
|
return -EFAULT;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
#ifdef BXVGA_DEBUG
|
#ifdef BXVGA_DEBUG
|
||||||
|
@ -259,7 +255,8 @@ int BXVGADevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
|
||||||
resolution.pitch = m_framebuffer_pitch;
|
resolution.pitch = m_framebuffer_pitch;
|
||||||
resolution.width = m_framebuffer_width;
|
resolution.width = m_framebuffer_width;
|
||||||
resolution.height = m_framebuffer_height;
|
resolution.height = m_framebuffer_height;
|
||||||
copy_to_user(user_resolution, &resolution);
|
if (!copy_to_user(user_resolution, &resolution))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -48,10 +48,10 @@ private:
|
||||||
virtual const char* class_name() const override { return "BXVGA"; }
|
virtual const char* class_name() const override { return "BXVGA"; }
|
||||||
virtual bool can_read(const FileDescription&, size_t) const override { return true; }
|
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 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> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override { return -EINVAL; }
|
||||||
virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, 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, u8*) override { return false; }
|
virtual bool read_blocks(unsigned, u16, UserOrKernelBuffer&) override { return false; }
|
||||||
virtual bool write_blocks(unsigned, u16, const u8*) override { return false; }
|
virtual bool write_blocks(unsigned, u16, const UserOrKernelBuffer&) override { return false; }
|
||||||
|
|
||||||
void set_safe_resolution();
|
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);
|
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);
|
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((offset % block_size()) == 0);
|
||||||
ASSERT((length % 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);
|
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((offset % block_size()) == 0);
|
||||||
ASSERT((length % block_size()) == 0);
|
ASSERT((length % block_size()) == 0);
|
||||||
|
|
|
@ -37,13 +37,13 @@ public:
|
||||||
size_t block_size() const { return m_block_size; }
|
size_t block_size() const { return m_block_size; }
|
||||||
virtual bool is_seekable() const override { return true; }
|
virtual bool is_seekable() const override { return true; }
|
||||||
|
|
||||||
bool read_block(unsigned index, u8*) const;
|
bool read_block(unsigned index, UserOrKernelBuffer&) const;
|
||||||
bool write_block(unsigned index, const u8*);
|
bool write_block(unsigned index, const UserOrKernelBuffer&);
|
||||||
bool read_raw(u32 offset, unsigned length, u8*) const;
|
bool read_raw(u32 offset, unsigned length, UserOrKernelBuffer&) const;
|
||||||
bool write_raw(u32 offset, unsigned length, const u8*);
|
bool write_raw(u32 offset, unsigned length, const UserOrKernelBuffer&);
|
||||||
|
|
||||||
virtual bool read_blocks(unsigned index, u16 count, u8*) = 0;
|
virtual bool read_blocks(unsigned index, u16 count, UserOrKernelBuffer&) = 0;
|
||||||
virtual bool write_blocks(unsigned index, u16 count, const u8*) = 0;
|
virtual bool write_blocks(unsigned index, u16 count, const UserOrKernelBuffer&) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BlockDevice(unsigned major, unsigned minor, size_t block_size = PAGE_SIZE)
|
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();
|
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);
|
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();
|
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);
|
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
|
#ifdef OFFD_DEBUG
|
||||||
klog() << "DiskPartition::read_blocks " << index << " (really: " << (m_block_offset + index) << ") count=" << count;
|
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);
|
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
|
#ifdef OFFD_DEBUG
|
||||||
klog() << "DiskPartition::write_blocks " << index << " (really: " << (m_block_offset + index) << ") count=" << count;
|
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);
|
static NonnullRefPtr<DiskPartition> create(BlockDevice&, unsigned block_offset, unsigned block_limit);
|
||||||
virtual ~DiskPartition();
|
virtual ~DiskPartition();
|
||||||
|
|
||||||
virtual bool read_blocks(unsigned index, u16 count, u8*) override;
|
virtual bool read_blocks(unsigned index, u16 count, UserOrKernelBuffer&) override;
|
||||||
virtual bool write_blocks(unsigned index, u16 count, const u8*) override;
|
virtual bool write_blocks(unsigned index, u16 count, const UserOrKernelBuffer&) override;
|
||||||
|
|
||||||
// ^BlockDevice
|
// ^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 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;
|
virtual bool can_write(const FileDescription&, size_t) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -63,7 +63,8 @@ int EBRPartitionTable::index_of_ebr_container() const
|
||||||
|
|
||||||
bool EBRPartitionTable::initialize()
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
auto& header = this->header();
|
auto& header = this->header();
|
||||||
|
@ -80,7 +81,8 @@ bool EBRPartitionTable::initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& ebr_entry = header.entry[m_ebr_container_id - 1];
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
size_t index = 1;
|
size_t index = 1;
|
||||||
|
@ -89,7 +91,7 @@ bool EBRPartitionTable::initialize()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
index++;
|
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;
|
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);
|
klog() << "EBRPartitionTable::partition: Extended partition, offset 0x" << String::format("%x", ebr_entry.offset) << ", type " << String::format("%x", ebr_entry.type);
|
||||||
#endif
|
#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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
@ -154,7 +157,7 @@ RefPtr<DiskPartition> EBRPartitionTable::get_extended_partition(unsigned index)
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,14 +46,15 @@ bool FullDevice::can_read(const FileDescription&, size_t) const
|
||||||
return true;
|
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);
|
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;
|
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)
|
if (size == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -38,8 +38,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// ^CharacterDevice
|
// ^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 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_read(const FileDescription&, size_t) const override;
|
virtual bool can_read(const FileDescription&, size_t) const override;
|
||||||
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
|
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
|
||||||
virtual const char* class_name() const override { return "FullDevice"; }
|
virtual const char* class_name() const override { return "FullDevice"; }
|
||||||
|
|
|
@ -49,7 +49,8 @@ const GPTPartitionHeader& GPTPartitionTable::header() const
|
||||||
|
|
||||||
bool GPTPartitionTable::initialize()
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +83,8 @@ RefPtr<DiskPartition> GPTPartitionTable::partition(unsigned index)
|
||||||
u8 entries_per_sector = BytesPerSector / header.partition_entry_size;
|
u8 entries_per_sector = BytesPerSector / header.partition_entry_size;
|
||||||
|
|
||||||
GPTPartitionEntry entries[entries_per_sector];
|
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)];
|
GPTPartitionEntry& entry = entries[((index - 1) % entries_per_sector)];
|
||||||
|
|
||||||
#ifdef GPT_DEBUG
|
#ifdef GPT_DEBUG
|
||||||
|
|
|
@ -369,7 +369,7 @@ bool KeyboardDevice::can_read(const FileDescription&, size_t) const
|
||||||
return !m_queue.is_empty();
|
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;
|
size_t nread = 0;
|
||||||
while (nread < size) {
|
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))
|
if ((size - nread) < (ssize_t)sizeof(Event))
|
||||||
break;
|
break;
|
||||||
auto event = m_queue.dequeue();
|
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);
|
nread += sizeof(Event);
|
||||||
}
|
}
|
||||||
return nread;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,9 +57,9 @@ public:
|
||||||
const String keymap_name() { return m_character_map.character_map_name(); }
|
const String keymap_name() { return m_character_map.character_map_name(); }
|
||||||
|
|
||||||
// ^CharacterDevice
|
// ^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 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 bool can_write(const FileDescription&, size_t) const override { return true; }
|
||||||
|
|
||||||
virtual const char* purpose() const override { return class_name(); }
|
virtual const char* purpose() const override { return class_name(); }
|
||||||
|
|
|
@ -49,7 +49,8 @@ const MBRPartitionHeader& MBRPartitionTable::header() const
|
||||||
|
|
||||||
bool MBRPartitionTable::initialize()
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,40 +79,36 @@ int MBVGADevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
|
||||||
switch (request) {
|
switch (request) {
|
||||||
case FB_IOCTL_GET_SIZE_IN_BYTES: {
|
case FB_IOCTL_GET_SIZE_IN_BYTES: {
|
||||||
auto* out = (size_t*)arg;
|
auto* out = (size_t*)arg;
|
||||||
if (!Process::current()->validate_write_typed(out))
|
|
||||||
return -EFAULT;
|
|
||||||
size_t value = framebuffer_size_in_bytes();
|
size_t value = framebuffer_size_in_bytes();
|
||||||
copy_to_user(out, &value);
|
if (!copy_to_user(out, &value))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case FB_IOCTL_GET_BUFFER: {
|
case FB_IOCTL_GET_BUFFER: {
|
||||||
auto* index = (int*)arg;
|
auto* index = (int*)arg;
|
||||||
if (!Process::current()->validate_write_typed(index))
|
|
||||||
return -EFAULT;
|
|
||||||
int value = 0;
|
int value = 0;
|
||||||
copy_to_user(index, &value);
|
if (!copy_to_user(index, &value))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case FB_IOCTL_GET_RESOLUTION: {
|
case FB_IOCTL_GET_RESOLUTION: {
|
||||||
auto* user_resolution = (FBResolution*)arg;
|
auto* user_resolution = (FBResolution*)arg;
|
||||||
if (!Process::current()->validate_write_typed(user_resolution))
|
|
||||||
return -EFAULT;
|
|
||||||
FBResolution resolution;
|
FBResolution resolution;
|
||||||
resolution.pitch = m_framebuffer_pitch;
|
resolution.pitch = m_framebuffer_pitch;
|
||||||
resolution.width = m_framebuffer_width;
|
resolution.width = m_framebuffer_width;
|
||||||
resolution.height = m_framebuffer_height;
|
resolution.height = m_framebuffer_height;
|
||||||
copy_to_user(user_resolution, &resolution);
|
if (!copy_to_user(user_resolution, &resolution))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case FB_IOCTL_SET_RESOLUTION: {
|
case FB_IOCTL_SET_RESOLUTION: {
|
||||||
auto* user_resolution = (FBResolution*)arg;
|
auto* user_resolution = (FBResolution*)arg;
|
||||||
if (!Process::current()->validate_read_typed(user_resolution) || !Process::current()->validate_write_typed(user_resolution))
|
|
||||||
return -EFAULT;
|
|
||||||
FBResolution resolution;
|
FBResolution resolution;
|
||||||
resolution.pitch = m_framebuffer_pitch;
|
resolution.pitch = m_framebuffer_pitch;
|
||||||
resolution.width = m_framebuffer_width;
|
resolution.width = m_framebuffer_width;
|
||||||
resolution.height = m_framebuffer_height;
|
resolution.height = m_framebuffer_height;
|
||||||
copy_to_user(user_resolution, &resolution);
|
if (!copy_to_user(user_resolution, &resolution))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -47,10 +47,10 @@ private:
|
||||||
virtual const char* class_name() const override { return "MBVGA"; }
|
virtual const char* class_name() const override { return "MBVGA"; }
|
||||||
virtual bool can_read(const FileDescription&, size_t) const override { return true; }
|
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 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> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override { return -EINVAL; }
|
||||||
virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, 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, u8*) override { return false; }
|
virtual bool read_blocks(unsigned, u16, UserOrKernelBuffer&) override { return false; }
|
||||||
virtual bool write_blocks(unsigned, u16, const u8*) 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; }
|
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;
|
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;
|
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);
|
return min(static_cast<size_t>(PAGE_SIZE), buffer_size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,8 +41,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// ^CharacterDevice
|
// ^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 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 bool can_write(const FileDescription&, size_t) const override { return true; }
|
||||||
virtual bool can_read(const FileDescription&, size_t) const override;
|
virtual bool can_read(const FileDescription&, size_t) const override;
|
||||||
virtual const char* class_name() const override { return "NullDevice"; }
|
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());
|
LOCKER(s_lock());
|
||||||
#ifdef PATA_DEBUG
|
#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
|
#endif
|
||||||
|
|
||||||
prdt().offset = m_dma_buffer_page->paddr();
|
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)
|
if (m_device_error)
|
||||||
return false;
|
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.
|
// 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);
|
m_bus_master_base.offset(2).out<u8>(m_bus_master_base.offset(2).in<u8>() | 0x6);
|
||||||
return true;
|
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());
|
LOCKER(s_lock());
|
||||||
#ifdef PATA_DEBUG
|
#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
|
#endif
|
||||||
|
|
||||||
prdt().offset = m_dma_buffer_page->paddr();
|
prdt().offset = m_dma_buffer_page->paddr();
|
||||||
prdt().size = 512 * count;
|
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);
|
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;
|
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);
|
ASSERT(count <= 256);
|
||||||
LOCKER(s_lock());
|
LOCKER(s_lock());
|
||||||
#ifdef PATA_DEBUG
|
#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
|
#endif
|
||||||
|
|
||||||
while (m_io_base.offset(ATA_REG_STATUS).in<u8>() & ATA_SR_BSY)
|
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>();
|
u8 status = m_control_base.offset(ATA_CTL_ALTSTATUS).in<u8>();
|
||||||
ASSERT(!(status & ATA_SR_BSY));
|
ASSERT(!(status & ATA_SR_BSY));
|
||||||
|
|
||||||
auto* buffer = (u16*)(outbuf + i * 512);
|
auto out = outbuf.offset(i * 512);
|
||||||
#ifdef PATA_DEBUG
|
#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
|
#endif
|
||||||
prepare_for_irq();
|
prepare_for_irq();
|
||||||
|
|
||||||
for (int i = 0; i < 256; i++) {
|
ssize_t nwritten = out.write_buffered<512>(512, [&](u8* buffer, size_t buffer_bytes) {
|
||||||
buffer[i] = IO::in16(m_io_base.offset(ATA_REG_DATA).get());
|
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;
|
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);
|
ASSERT(count <= 256);
|
||||||
LOCKER(s_lock());
|
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>();
|
u8 status = m_io_base.offset(ATA_REG_STATUS).in<u8>();
|
||||||
ASSERT(status & ATA_SR_DRQ);
|
ASSERT(status & ATA_SR_DRQ);
|
||||||
|
|
||||||
|
auto in = inbuf.offset(i * 512);
|
||||||
#ifdef PATA_DEBUG
|
#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
|
#endif
|
||||||
prepare_for_irq();
|
prepare_for_irq();
|
||||||
auto* buffer = (u16*)(const_cast<u8*>(inbuf) + i * 512);
|
ssize_t nread = in.read_buffered<512>(512, [&](const u8* buffer, size_t buffer_bytes) {
|
||||||
for (int i = 0; i < 256; i++) {
|
for (size_t i = 0; i < buffer_bytes; i += sizeof(u16))
|
||||||
IO::out16(m_io_base.offset(ATA_REG_DATA).get(), buffer[i]);
|
IO::out16(m_io_base.offset(ATA_REG_DATA).get(), *(const u16*)&buffer[i]);
|
||||||
}
|
return (ssize_t)buffer_bytes;
|
||||||
|
});
|
||||||
wait_for_irq();
|
wait_for_irq();
|
||||||
status = m_io_base.offset(ATA_REG_STATUS).in<u8>();
|
status = m_io_base.offset(ATA_REG_STATUS).in<u8>();
|
||||||
ASSERT(!(status & ATA_SR_BSY));
|
ASSERT(!(status & ATA_SR_BSY));
|
||||||
|
if (nread < 0)
|
||||||
|
return false; // TODO: -EFAULT
|
||||||
}
|
}
|
||||||
prepare_for_irq();
|
prepare_for_irq();
|
||||||
m_io_base.offset(ATA_REG_COMMAND).out<u8>(ATA_CMD_CACHE_FLUSH);
|
m_io_base.offset(ATA_REG_COMMAND).out<u8>(ATA_CMD_CACHE_FLUSH);
|
||||||
|
|
|
@ -84,10 +84,10 @@ private:
|
||||||
void detect_disks();
|
void detect_disks();
|
||||||
|
|
||||||
void wait_for_irq();
|
void wait_for_irq();
|
||||||
bool ata_read_sectors_with_dma(u32, u16, u8*, bool);
|
bool ata_read_sectors_with_dma(u32, u16, UserOrKernelBuffer&, bool);
|
||||||
bool ata_write_sectors_with_dma(u32, u16, const u8*, bool);
|
bool ata_write_sectors_with_dma(u32, u16, const UserOrKernelBuffer&, bool);
|
||||||
bool ata_read_sectors(u32, u16, u8*, bool);
|
bool ata_read_sectors(u32, u16, UserOrKernelBuffer&, bool);
|
||||||
bool ata_write_sectors(u32, u16, const u8*, bool);
|
bool ata_write_sectors(u32, u16, const UserOrKernelBuffer&, bool);
|
||||||
|
|
||||||
inline void prepare_for_irq();
|
inline void prepare_for_irq();
|
||||||
|
|
||||||
|
|
|
@ -55,19 +55,19 @@ const char* PATADiskDevice::class_name() const
|
||||||
return "PATADiskDevice";
|
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())
|
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_with_dma(index, count, out);
|
||||||
return read_sectors(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())
|
if (!m_channel.m_bus_master_base.is_null() && m_channel.m_dma_enabled.resource())
|
||||||
return write_sectors_with_dma(index, count, data);
|
return write_sectors_with_dma(index, count, data);
|
||||||
for (unsigned i = 0; i < count; ++i) {
|
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 false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -80,7 +80,7 @@ void PATADiskDevice::set_drive_geometry(u16 cyls, u16 heads, u16 spt)
|
||||||
m_sectors_per_track = 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();
|
unsigned index = offset / block_size();
|
||||||
u16 whole_blocks = len / 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();
|
off_t pos = whole_blocks * block_size();
|
||||||
|
|
||||||
if (remaining > 0) {
|
if (remaining > 0) {
|
||||||
auto buf = ByteBuffer::create_uninitialized(block_size());
|
auto data = ByteBuffer::create_uninitialized(block_size());
|
||||||
if (!read_blocks(index + whole_blocks, 1, buf.data()))
|
auto data_buffer = UserOrKernelBuffer::for_kernel_buffer(data.data());
|
||||||
|
if (!read_blocks(index + whole_blocks, 1, data_buffer))
|
||||||
return pos;
|
return pos;
|
||||||
memcpy(&outbuf[pos], buf.data(), remaining);
|
if (!outbuf.write(data.data(), pos, remaining))
|
||||||
|
return KResult(-EFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pos + remaining;
|
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());
|
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();
|
unsigned index = offset / block_size();
|
||||||
u16 whole_blocks = len / 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,
|
// partial write, we have to read the block's content first, modify it,
|
||||||
// then write the whole block back to the disk.
|
// then write the whole block back to the disk.
|
||||||
if (remaining > 0) {
|
if (remaining > 0) {
|
||||||
auto buf = ByteBuffer::create_zeroed(block_size());
|
auto data = ByteBuffer::create_zeroed(block_size());
|
||||||
if (!read_blocks(index + whole_blocks, 1, buf.data()))
|
auto data_buffer = UserOrKernelBuffer::for_kernel_buffer(data.data());
|
||||||
|
if (!read_blocks(index + whole_blocks, 1, data_buffer))
|
||||||
return pos;
|
return pos;
|
||||||
memcpy(buf.data(), &inbuf[pos], remaining);
|
if (!inbuf.read(data.data(), pos, remaining))
|
||||||
if (!write_blocks(index + whole_blocks, 1, buf.data()))
|
return KResult(-EFAULT);
|
||||||
|
if (!write_blocks(index + whole_blocks, 1, data_buffer))
|
||||||
return pos;
|
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());
|
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());
|
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());
|
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());
|
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());
|
return m_channel.ata_write_sectors(start_sector, count, inbuf, is_slave());
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,15 +55,15 @@ public:
|
||||||
virtual ~PATADiskDevice() override;
|
virtual ~PATADiskDevice() override;
|
||||||
|
|
||||||
// ^DiskDevice
|
// ^DiskDevice
|
||||||
virtual bool read_blocks(unsigned index, u16 count, u8*) override;
|
virtual bool read_blocks(unsigned index, u16 count, UserOrKernelBuffer&) override;
|
||||||
virtual bool write_blocks(unsigned index, u16 count, const u8*) override;
|
virtual bool write_blocks(unsigned index, u16 count, const UserOrKernelBuffer&) override;
|
||||||
|
|
||||||
void set_drive_geometry(u16, u16, u16);
|
void set_drive_geometry(u16, u16, u16);
|
||||||
|
|
||||||
// ^BlockDevice
|
// ^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 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;
|
virtual bool can_write(const FileDescription&, size_t) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -74,10 +74,10 @@ private:
|
||||||
virtual const char* class_name() const override;
|
virtual const char* class_name() const override;
|
||||||
|
|
||||||
bool wait_for_irq();
|
bool wait_for_irq();
|
||||||
bool read_sectors_with_dma(u32 lba, u16 count, u8*);
|
bool read_sectors_with_dma(u32 lba, u16 count, UserOrKernelBuffer&);
|
||||||
bool write_sectors_with_dma(u32 lba, u16 count, const u8*);
|
bool write_sectors_with_dma(u32 lba, u16 count, const UserOrKernelBuffer&);
|
||||||
bool read_sectors(u32 lba, u16 count, u8* buffer);
|
bool read_sectors(u32 lba, u16 count, UserOrKernelBuffer& buffer);
|
||||||
bool write_sectors(u32 lba, u16 count, const u8* data);
|
bool write_sectors(u32 lba, u16 count, const UserOrKernelBuffer& data);
|
||||||
bool is_slave() const;
|
bool is_slave() const;
|
||||||
|
|
||||||
Lock m_lock { "IDEDiskDevice" };
|
Lock m_lock { "IDEDiskDevice" };
|
||||||
|
|
|
@ -336,7 +336,7 @@ bool PS2MouseDevice::can_read(const FileDescription&, size_t) const
|
||||||
return !m_queue.is_empty();
|
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);
|
ASSERT(size > 0);
|
||||||
size_t nread = 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";
|
dbg() << "PS2 Mouse Read: Filter packets";
|
||||||
#endif
|
#endif
|
||||||
size_t bytes_read_from_packet = min(remaining_space_in_buffer, sizeof(MousePacket));
|
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;
|
nread += bytes_read_from_packet;
|
||||||
remaining_space_in_buffer -= bytes_read_from_packet;
|
remaining_space_in_buffer -= bytes_read_from_packet;
|
||||||
}
|
}
|
||||||
return nread;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,8 +45,8 @@ public:
|
||||||
|
|
||||||
// ^CharacterDevice
|
// ^CharacterDevice
|
||||||
virtual bool can_read(const FileDescription&, size_t) const override;
|
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 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 bool can_write(const FileDescription&, size_t) const override { return true; }
|
||||||
|
|
||||||
virtual const char* purpose() const override { return class_name(); }
|
virtual const char* purpose() const override { return class_name(); }
|
||||||
|
|
|
@ -43,13 +43,18 @@ bool RandomDevice::can_read(const FileDescription&, size_t) const
|
||||||
return true;
|
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;
|
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?
|
// FIXME: Use input for entropy? I guess that could be a neat feature?
|
||||||
return min(static_cast<size_t>(PAGE_SIZE), size);
|
return min(static_cast<size_t>(PAGE_SIZE), size);
|
||||||
|
|
|
@ -38,8 +38,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// ^CharacterDevice
|
// ^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 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_read(const FileDescription&, size_t) const override;
|
virtual bool can_read(const FileDescription&, size_t) const override;
|
||||||
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
|
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
|
||||||
virtual const char* class_name() const override { return "RandomDevice"; }
|
virtual const char* class_name() const override { return "RandomDevice"; }
|
||||||
|
|
|
@ -177,7 +177,7 @@ bool SB16::can_read(const FileDescription&, size_t) const
|
||||||
return false;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -231,7 +231,7 @@ void SB16::wait_for_irq()
|
||||||
disable_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) {
|
if (!m_dma_region) {
|
||||||
auto page = MM.allocate_supervisor_physical_page();
|
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;
|
const int sample_rate = 44100;
|
||||||
set_sample_rate(sample_rate);
|
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);
|
dma_start(length);
|
||||||
|
|
||||||
// 16-bit single-cycle output.
|
// 16-bit single-cycle output.
|
||||||
|
|
|
@ -47,8 +47,8 @@ public:
|
||||||
|
|
||||||
// ^CharacterDevice
|
// ^CharacterDevice
|
||||||
virtual bool can_read(const FileDescription&, size_t) const override;
|
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 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 bool can_write(const FileDescription&, size_t) const override { return true; }
|
||||||
|
|
||||||
virtual const char* purpose() const override { return class_name(); }
|
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;
|
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)
|
if (!size)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -53,9 +53,15 @@ KResultOr<size_t> SerialDevice::read(FileDescription&, size_t, u8* buffer, size_
|
||||||
if (!(get_line_status() & DataReady))
|
if (!(get_line_status() & DataReady))
|
||||||
return 0;
|
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
|
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;
|
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)
|
if (!size)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -71,9 +77,14 @@ KResultOr<size_t> SerialDevice::write(FileDescription&, size_t, const u8* buffer
|
||||||
if (!(get_line_status() & EmptyTransmitterHoldingRegister))
|
if (!(get_line_status() & EmptyTransmitterHoldingRegister))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
IO::out8(m_base_addr, buffer[0]);
|
ssize_t nread = buffer.read_buffered<128>(size, [&](const u8* data, size_t data_size) {
|
||||||
|
for (size_t i = 0; i < data_size; i++)
|
||||||
return 1;
|
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()
|
void SerialDevice::initialize()
|
||||||
|
|
|
@ -43,9 +43,9 @@ public:
|
||||||
|
|
||||||
// ^CharacterDevice
|
// ^CharacterDevice
|
||||||
virtual bool can_read(const FileDescription&, size_t) const override;
|
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 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 {
|
enum InterruptEnable {
|
||||||
LowPowerMode = 0x01 << 5,
|
LowPowerMode = 0x01 << 5,
|
||||||
|
|
|
@ -44,14 +44,15 @@ bool ZeroDevice::can_read(const FileDescription&, size_t) const
|
||||||
return true;
|
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);
|
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;
|
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);
|
return min(static_cast<size_t>(PAGE_SIZE), size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,8 +38,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// ^CharacterDevice
|
// ^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 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_read(const FileDescription&, size_t) const override;
|
virtual bool can_read(const FileDescription&, size_t) const override;
|
||||||
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
|
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
|
||||||
virtual const char* class_name() const override { return "ZeroDevice"; }
|
virtual const char* class_name() const override { return "ZeroDevice"; }
|
||||||
|
|
|
@ -58,7 +58,7 @@ void DoubleBuffer::flip()
|
||||||
compute_lockfree_metadata();
|
compute_lockfree_metadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t DoubleBuffer::write(const u8* data, size_t size)
|
ssize_t DoubleBuffer::write(const UserOrKernelBuffer& data, size_t size)
|
||||||
{
|
{
|
||||||
if (!size)
|
if (!size)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -68,11 +68,12 @@ size_t DoubleBuffer::write(const u8* data, size_t size)
|
||||||
u8* write_ptr = m_write_buffer->data + m_write_buffer->size;
|
u8* write_ptr = m_write_buffer->data + m_write_buffer->size;
|
||||||
m_write_buffer->size += bytes_to_write;
|
m_write_buffer->size += bytes_to_write;
|
||||||
compute_lockfree_metadata();
|
compute_lockfree_metadata();
|
||||||
memcpy(write_ptr, data, bytes_to_write);
|
if (!data.read(write_ptr, bytes_to_write))
|
||||||
return bytes_to_write;
|
return -EFAULT;
|
||||||
|
return (ssize_t)bytes_to_write;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t DoubleBuffer::read(u8* data, size_t size)
|
ssize_t DoubleBuffer::read(UserOrKernelBuffer& data, size_t size)
|
||||||
{
|
{
|
||||||
if (!size)
|
if (!size)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -83,10 +84,11 @@ size_t DoubleBuffer::read(u8* data, size_t size)
|
||||||
if (m_read_buffer_index >= m_read_buffer->size)
|
if (m_read_buffer_index >= m_read_buffer->size)
|
||||||
return 0;
|
return 0;
|
||||||
size_t nread = min(m_read_buffer->size - m_read_buffer_index, size);
|
size_t nread = min(m_read_buffer->size - m_read_buffer_index, size);
|
||||||
memcpy(data, m_read_buffer->data + m_read_buffer_index, nread);
|
if (!data.write(m_read_buffer->data + m_read_buffer_index, nread))
|
||||||
|
return -EFAULT;
|
||||||
m_read_buffer_index += nread;
|
m_read_buffer_index += nread;
|
||||||
compute_lockfree_metadata();
|
compute_lockfree_metadata();
|
||||||
return nread;
|
return (ssize_t)nread;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <Kernel/KBuffer.h>
|
#include <Kernel/KBuffer.h>
|
||||||
#include <Kernel/Lock.h>
|
#include <Kernel/Lock.h>
|
||||||
|
#include <Kernel/UserOrKernelBuffer.h>
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
@ -36,8 +37,17 @@ class DoubleBuffer {
|
||||||
public:
|
public:
|
||||||
explicit DoubleBuffer(size_t capacity = 65536);
|
explicit DoubleBuffer(size_t capacity = 65536);
|
||||||
|
|
||||||
size_t write(const u8*, size_t);
|
[[nodiscard]] ssize_t write(const UserOrKernelBuffer&, size_t);
|
||||||
size_t read(u8*, size_t);
|
[[nodiscard]] ssize_t write(const u8* data, size_t size)
|
||||||
|
{
|
||||||
|
return write(UserOrKernelBuffer::for_kernel_buffer(const_cast<u8*>(data)), size);
|
||||||
|
}
|
||||||
|
[[nodiscard]] ssize_t read(UserOrKernelBuffer&, size_t);
|
||||||
|
[[nodiscard]] ssize_t read(u8* data, size_t size)
|
||||||
|
{
|
||||||
|
auto buffer = UserOrKernelBuffer::for_kernel_buffer(data);
|
||||||
|
return read(buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
bool is_empty() const { return m_empty; }
|
bool is_empty() const { return m_empty; }
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,7 @@ BlockBasedFS::~BlockBasedFS()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BlockBasedFS::write_block(unsigned index, const u8* data, size_t count, size_t offset, bool allow_cache)
|
int BlockBasedFS::write_block(unsigned index, const UserOrKernelBuffer& data, size_t count, size_t offset, bool allow_cache)
|
||||||
{
|
{
|
||||||
ASSERT(m_logical_block_size);
|
ASSERT(m_logical_block_size);
|
||||||
ASSERT(offset + count <= block_size());
|
ASSERT(offset + count <= block_size());
|
||||||
|
@ -133,9 +133,9 @@ bool BlockBasedFS::write_block(unsigned index, const u8* data, size_t count, siz
|
||||||
file_description().seek(base_offset, SEEK_SET);
|
file_description().seek(base_offset, SEEK_SET);
|
||||||
auto nwritten = file_description().write(data, count);
|
auto nwritten = file_description().write(data, count);
|
||||||
if (nwritten.is_error())
|
if (nwritten.is_error())
|
||||||
return false;
|
return -EIO; // TODO: Return error code as-is, could be -EFAULT!
|
||||||
ASSERT(nwritten.value() == count);
|
ASSERT(nwritten.value() == count);
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& entry = cache().get(index);
|
auto& entry = cache().get(index);
|
||||||
|
@ -143,15 +143,16 @@ bool BlockBasedFS::write_block(unsigned index, const u8* data, size_t count, siz
|
||||||
// Fill the cache first.
|
// Fill the cache first.
|
||||||
read_block(index, nullptr, block_size());
|
read_block(index, nullptr, block_size());
|
||||||
}
|
}
|
||||||
memcpy(entry.data + offset, data, count);
|
if (!data.read(entry.data + offset, count))
|
||||||
|
return -EFAULT;
|
||||||
entry.is_dirty = true;
|
entry.is_dirty = true;
|
||||||
entry.has_data = true;
|
entry.has_data = true;
|
||||||
|
|
||||||
cache().set_dirty(true);
|
cache().set_dirty(true);
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BlockBasedFS::raw_read(unsigned index, u8* buffer)
|
bool BlockBasedFS::raw_read(unsigned index, UserOrKernelBuffer& buffer)
|
||||||
{
|
{
|
||||||
u32 base_offset = static_cast<u32>(index) * static_cast<u32>(m_logical_block_size);
|
u32 base_offset = static_cast<u32>(index) * static_cast<u32>(m_logical_block_size);
|
||||||
file_description().seek(base_offset, SEEK_SET);
|
file_description().seek(base_offset, SEEK_SET);
|
||||||
|
@ -160,7 +161,7 @@ bool BlockBasedFS::raw_read(unsigned index, u8* buffer)
|
||||||
ASSERT(nread.value() == m_logical_block_size);
|
ASSERT(nread.value() == m_logical_block_size);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool BlockBasedFS::raw_write(unsigned index, const u8* buffer)
|
bool BlockBasedFS::raw_write(unsigned index, const UserOrKernelBuffer& buffer)
|
||||||
{
|
{
|
||||||
u32 base_offset = static_cast<u32>(index) * static_cast<u32>(m_logical_block_size);
|
u32 base_offset = static_cast<u32>(index) * static_cast<u32>(m_logical_block_size);
|
||||||
file_description().seek(base_offset, SEEK_SET);
|
file_description().seek(base_offset, SEEK_SET);
|
||||||
|
@ -170,37 +171,39 @@ bool BlockBasedFS::raw_write(unsigned index, const u8* buffer)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BlockBasedFS::raw_read_blocks(unsigned index, size_t count, u8* buffer)
|
bool BlockBasedFS::raw_read_blocks(unsigned index, size_t count, UserOrKernelBuffer& buffer)
|
||||||
{
|
{
|
||||||
|
auto current = buffer;
|
||||||
for (unsigned block = index; block < (index + count); block++) {
|
for (unsigned block = index; block < (index + count); block++) {
|
||||||
if (!raw_read(block, buffer))
|
if (!raw_read(block, current))
|
||||||
return false;
|
return false;
|
||||||
buffer += logical_block_size();
|
current = current.offset(logical_block_size());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool BlockBasedFS::raw_write_blocks(unsigned index, size_t count, const u8* buffer)
|
bool BlockBasedFS::raw_write_blocks(unsigned index, size_t count, const UserOrKernelBuffer& buffer)
|
||||||
{
|
{
|
||||||
|
auto current = buffer;
|
||||||
for (unsigned block = index; block < (index + count); block++) {
|
for (unsigned block = index; block < (index + count); block++) {
|
||||||
if (!raw_write(block, buffer))
|
if (!raw_write(block, current))
|
||||||
return false;
|
return false;
|
||||||
buffer += logical_block_size();
|
current = current.offset(logical_block_size());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BlockBasedFS::write_blocks(unsigned index, unsigned count, const u8* data, bool allow_cache)
|
int BlockBasedFS::write_blocks(unsigned index, unsigned count, const UserOrKernelBuffer& data, bool allow_cache)
|
||||||
{
|
{
|
||||||
ASSERT(m_logical_block_size);
|
ASSERT(m_logical_block_size);
|
||||||
#ifdef BBFS_DEBUG
|
#ifdef BBFS_DEBUG
|
||||||
klog() << "BlockBasedFileSystem::write_blocks " << index << " x" << count;
|
klog() << "BlockBasedFileSystem::write_blocks " << index << " x" << count;
|
||||||
#endif
|
#endif
|
||||||
for (unsigned i = 0; i < count; ++i)
|
for (unsigned i = 0; i < count; ++i)
|
||||||
write_block(index + i, data + i * block_size(), block_size(), 0, allow_cache);
|
write_block(index + i, data.offset(i * block_size()), block_size(), 0, allow_cache);
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BlockBasedFS::read_block(unsigned index, u8* buffer, size_t count, size_t offset, bool allow_cache) const
|
int BlockBasedFS::read_block(unsigned index, UserOrKernelBuffer* buffer, size_t count, size_t offset, bool allow_cache) const
|
||||||
{
|
{
|
||||||
ASSERT(m_logical_block_size);
|
ASSERT(m_logical_block_size);
|
||||||
ASSERT(offset + count <= block_size());
|
ASSERT(offset + count <= block_size());
|
||||||
|
@ -212,44 +215,45 @@ bool BlockBasedFS::read_block(unsigned index, u8* buffer, size_t count, size_t o
|
||||||
const_cast<BlockBasedFS*>(this)->flush_specific_block_if_needed(index);
|
const_cast<BlockBasedFS*>(this)->flush_specific_block_if_needed(index);
|
||||||
u32 base_offset = static_cast<u32>(index) * static_cast<u32>(block_size()) + static_cast<u32>(offset);
|
u32 base_offset = static_cast<u32>(index) * static_cast<u32>(block_size()) + static_cast<u32>(offset);
|
||||||
file_description().seek(base_offset, SEEK_SET);
|
file_description().seek(base_offset, SEEK_SET);
|
||||||
auto nread = file_description().read(buffer, count);
|
auto nread = file_description().read(*buffer, count);
|
||||||
if (nread.is_error())
|
if (nread.is_error())
|
||||||
return false;
|
return -EIO;
|
||||||
ASSERT(nread.value() == count);
|
ASSERT(nread.value() == count);
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& entry = cache().get(index);
|
auto& entry = cache().get(index);
|
||||||
if (!entry.has_data) {
|
if (!entry.has_data) {
|
||||||
u32 base_offset = static_cast<u32>(index) * static_cast<u32>(block_size());
|
u32 base_offset = static_cast<u32>(index) * static_cast<u32>(block_size());
|
||||||
file_description().seek(base_offset, SEEK_SET);
|
file_description().seek(base_offset, SEEK_SET);
|
||||||
auto nread = file_description().read(entry.data, block_size());
|
auto entry_data_buffer = UserOrKernelBuffer::for_kernel_buffer(entry.data);
|
||||||
|
auto nread = file_description().read(entry_data_buffer, block_size());
|
||||||
if (nread.is_error())
|
if (nread.is_error())
|
||||||
return false;
|
return -EIO;
|
||||||
ASSERT(nread.value() == block_size());
|
ASSERT(nread.value() == block_size());
|
||||||
entry.has_data = true;
|
entry.has_data = true;
|
||||||
}
|
}
|
||||||
if (buffer)
|
if (buffer && !buffer->write(entry.data + offset, count))
|
||||||
memcpy(buffer, entry.data + offset, count);
|
return -EFAULT;
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BlockBasedFS::read_blocks(unsigned index, unsigned count, u8* buffer, bool allow_cache) const
|
int BlockBasedFS::read_blocks(unsigned index, unsigned count, UserOrKernelBuffer& buffer, bool allow_cache) const
|
||||||
{
|
{
|
||||||
ASSERT(m_logical_block_size);
|
ASSERT(m_logical_block_size);
|
||||||
if (!count)
|
if (!count)
|
||||||
return false;
|
return false;
|
||||||
if (count == 1)
|
if (count == 1)
|
||||||
return read_block(index, buffer, block_size(), 0, allow_cache);
|
return read_block(index, &buffer, block_size(), 0, allow_cache);
|
||||||
u8* out = buffer;
|
auto out = buffer;
|
||||||
|
|
||||||
for (unsigned i = 0; i < count; ++i) {
|
for (unsigned i = 0; i < count; ++i) {
|
||||||
if (!read_block(index + i, out, block_size(), 0, allow_cache))
|
auto err = read_block(index + i, &out, block_size(), 0, allow_cache);
|
||||||
return false;
|
if (err < 0)
|
||||||
out += block_size();
|
return err;
|
||||||
|
out = out.offset(block_size());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockBasedFS::flush_specific_block_if_needed(unsigned index)
|
void BlockBasedFS::flush_specific_block_if_needed(unsigned index)
|
||||||
|
@ -262,7 +266,8 @@ void BlockBasedFS::flush_specific_block_if_needed(unsigned index)
|
||||||
u32 base_offset = static_cast<u32>(entry.block_index) * static_cast<u32>(block_size());
|
u32 base_offset = static_cast<u32>(entry.block_index) * static_cast<u32>(block_size());
|
||||||
file_description().seek(base_offset, SEEK_SET);
|
file_description().seek(base_offset, SEEK_SET);
|
||||||
// FIXME: Should this error path be surfaced somehow?
|
// FIXME: Should this error path be surfaced somehow?
|
||||||
(void)file_description().write(entry.data, block_size());
|
auto entry_data_buffer = UserOrKernelBuffer::for_kernel_buffer(entry.data);
|
||||||
|
(void)file_description().write(entry_data_buffer, block_size());
|
||||||
entry.is_dirty = false;
|
entry.is_dirty = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -280,7 +285,8 @@ void BlockBasedFS::flush_writes_impl()
|
||||||
u32 base_offset = static_cast<u32>(entry.block_index) * static_cast<u32>(block_size());
|
u32 base_offset = static_cast<u32>(entry.block_index) * static_cast<u32>(block_size());
|
||||||
file_description().seek(base_offset, SEEK_SET);
|
file_description().seek(base_offset, SEEK_SET);
|
||||||
// FIXME: Should this error path be surfaced somehow?
|
// FIXME: Should this error path be surfaced somehow?
|
||||||
(void)file_description().write(entry.data, block_size());
|
auto entry_data_buffer = UserOrKernelBuffer::for_kernel_buffer(entry.data);
|
||||||
|
(void)file_description().write(entry_data_buffer, block_size());
|
||||||
++count;
|
++count;
|
||||||
entry.is_dirty = false;
|
entry.is_dirty = false;
|
||||||
});
|
});
|
||||||
|
|
|
@ -42,17 +42,17 @@ public:
|
||||||
protected:
|
protected:
|
||||||
explicit BlockBasedFS(FileDescription&);
|
explicit BlockBasedFS(FileDescription&);
|
||||||
|
|
||||||
bool read_block(unsigned index, u8* buffer, size_t count, size_t offset = 0, bool allow_cache = true) const;
|
int read_block(unsigned index, UserOrKernelBuffer* buffer, size_t count, size_t offset = 0, bool allow_cache = true) const;
|
||||||
bool read_blocks(unsigned index, unsigned count, u8* buffer, bool allow_cache = true) const;
|
int read_blocks(unsigned index, unsigned count, UserOrKernelBuffer& buffer, bool allow_cache = true) const;
|
||||||
|
|
||||||
bool raw_read(unsigned index, u8* buffer);
|
bool raw_read(unsigned index, UserOrKernelBuffer& buffer);
|
||||||
bool raw_write(unsigned index, const u8* buffer);
|
bool raw_write(unsigned index, const UserOrKernelBuffer& buffer);
|
||||||
|
|
||||||
bool raw_read_blocks(unsigned index, size_t count, u8* buffer);
|
bool raw_read_blocks(unsigned index, size_t count, UserOrKernelBuffer& buffer);
|
||||||
bool raw_write_blocks(unsigned index, size_t count, const u8* buffer);
|
bool raw_write_blocks(unsigned index, size_t count, const UserOrKernelBuffer& buffer);
|
||||||
|
|
||||||
bool write_block(unsigned index, const u8* buffer, size_t count, size_t offset = 0, bool allow_cache = true);
|
int write_block(unsigned index, const UserOrKernelBuffer& buffer, size_t count, size_t offset = 0, bool allow_cache = true);
|
||||||
bool write_blocks(unsigned index, unsigned count, const u8*, bool allow_cache = true);
|
int write_blocks(unsigned index, unsigned count, const UserOrKernelBuffer&, bool allow_cache = true);
|
||||||
|
|
||||||
size_t m_logical_block_size { 512 };
|
size_t m_logical_block_size { 512 };
|
||||||
|
|
||||||
|
|
|
@ -120,12 +120,12 @@ DevPtsFSInode::~DevPtsFSInode()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t DevPtsFSInode::read_bytes(off_t, ssize_t, u8*, FileDescription*) const
|
ssize_t DevPtsFSInode::read_bytes(off_t, ssize_t, UserOrKernelBuffer&, FileDescription*) const
|
||||||
{
|
{
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t DevPtsFSInode::write_bytes(off_t, ssize_t, const u8*, FileDescription*)
|
ssize_t DevPtsFSInode::write_bytes(off_t, ssize_t, const UserOrKernelBuffer&, FileDescription*)
|
||||||
{
|
{
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,12 +67,12 @@ private:
|
||||||
DevPtsFSInode(DevPtsFS&, unsigned index, SlavePTY*);
|
DevPtsFSInode(DevPtsFS&, unsigned index, SlavePTY*);
|
||||||
|
|
||||||
// ^Inode
|
// ^Inode
|
||||||
virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override;
|
virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override;
|
||||||
virtual InodeMetadata metadata() const override;
|
virtual InodeMetadata metadata() const override;
|
||||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
|
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
|
||||||
virtual RefPtr<Inode> lookup(StringView name) override;
|
virtual RefPtr<Inode> lookup(StringView name) override;
|
||||||
virtual void flush_metadata() override;
|
virtual void flush_metadata() override;
|
||||||
virtual ssize_t write_bytes(off_t, ssize_t, const u8* buffer, FileDescription*) override;
|
virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& buffer, FileDescription*) override;
|
||||||
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
|
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
|
||||||
virtual KResult add_child(Inode&, const StringView& name, mode_t) override;
|
virtual KResult add_child(Inode&, const StringView& name, mode_t) override;
|
||||||
virtual KResult remove_child(const StringView& name) override;
|
virtual KResult remove_child(const StringView& name) override;
|
||||||
|
|
|
@ -88,7 +88,8 @@ bool Ext2FS::flush_super_block()
|
||||||
{
|
{
|
||||||
LOCKER(m_lock);
|
LOCKER(m_lock);
|
||||||
ASSERT((sizeof(ext2_super_block) % logical_block_size()) == 0);
|
ASSERT((sizeof(ext2_super_block) % logical_block_size()) == 0);
|
||||||
bool success = raw_write_blocks(2, (sizeof(ext2_super_block) / logical_block_size()), (const u8*)&m_super_block);
|
auto super_block_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&m_super_block);
|
||||||
|
bool success = raw_write_blocks(2, (sizeof(ext2_super_block) / logical_block_size()), super_block_buffer);
|
||||||
ASSERT(success);
|
ASSERT(success);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -104,7 +105,8 @@ bool Ext2FS::initialize()
|
||||||
{
|
{
|
||||||
LOCKER(m_lock);
|
LOCKER(m_lock);
|
||||||
ASSERT((sizeof(ext2_super_block) % logical_block_size()) == 0);
|
ASSERT((sizeof(ext2_super_block) % logical_block_size()) == 0);
|
||||||
bool success = raw_read_blocks(2, (sizeof(ext2_super_block) / logical_block_size()), (u8*)&m_super_block);
|
auto super_block_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&m_super_block);
|
||||||
|
bool success = raw_read_blocks(2, (sizeof(ext2_super_block) / logical_block_size()), super_block_buffer);
|
||||||
ASSERT(success);
|
ASSERT(success);
|
||||||
|
|
||||||
auto& super_block = this->super_block();
|
auto& super_block = this->super_block();
|
||||||
|
@ -139,7 +141,8 @@ bool Ext2FS::initialize()
|
||||||
unsigned blocks_to_read = ceil_div(m_block_group_count * sizeof(ext2_group_desc), block_size());
|
unsigned blocks_to_read = ceil_div(m_block_group_count * sizeof(ext2_group_desc), block_size());
|
||||||
BlockIndex first_block_of_bgdt = block_size() == 1024 ? 2 : 1;
|
BlockIndex first_block_of_bgdt = block_size() == 1024 ? 2 : 1;
|
||||||
m_cached_group_descriptor_table = KBuffer::create_with_size(block_size() * blocks_to_read, Region::Access::Read | Region::Access::Write, "Ext2FS: Block group descriptors");
|
m_cached_group_descriptor_table = KBuffer::create_with_size(block_size() * blocks_to_read, Region::Access::Read | Region::Access::Write, "Ext2FS: Block group descriptors");
|
||||||
read_blocks(first_block_of_bgdt, blocks_to_read, m_cached_group_descriptor_table.value().data());
|
auto buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_group_descriptor_table.value().data());
|
||||||
|
read_blocks(first_block_of_bgdt, blocks_to_read, buffer);
|
||||||
|
|
||||||
#ifdef EXT2_DEBUG
|
#ifdef EXT2_DEBUG
|
||||||
for (unsigned i = 1; i <= m_block_group_count; ++i) {
|
for (unsigned i = 1; i <= m_block_group_count; ++i) {
|
||||||
|
@ -291,8 +294,9 @@ bool Ext2FS::write_block_list_for_inode(InodeIndex inode_index, ext2_inode& e2in
|
||||||
--remaining_blocks;
|
--remaining_blocks;
|
||||||
}
|
}
|
||||||
stream.fill_to_end(0);
|
stream.fill_to_end(0);
|
||||||
bool success = write_block(e2inode.i_block[EXT2_IND_BLOCK], block_contents.data(), block_size());
|
auto buffer = UserOrKernelBuffer::for_kernel_buffer(block_contents.data());
|
||||||
ASSERT(success);
|
int err = write_block(e2inode.i_block[EXT2_IND_BLOCK], buffer, block_size());
|
||||||
|
ASSERT(err >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!remaining_blocks)
|
if (!remaining_blocks)
|
||||||
|
@ -329,7 +333,8 @@ bool Ext2FS::write_block_list_for_inode(InodeIndex inode_index, ext2_inode& e2in
|
||||||
memset(dind_block_contents.data(), 0, dind_block_contents.size());
|
memset(dind_block_contents.data(), 0, dind_block_contents.size());
|
||||||
dind_block_dirty = true;
|
dind_block_dirty = true;
|
||||||
} else {
|
} else {
|
||||||
read_block(e2inode.i_block[EXT2_DIND_BLOCK], dind_block_contents.data(), block_size());
|
auto buffer = UserOrKernelBuffer::for_kernel_buffer(dind_block_contents.data());
|
||||||
|
read_block(e2inode.i_block[EXT2_DIND_BLOCK], &buffer, block_size());
|
||||||
}
|
}
|
||||||
auto* dind_block_as_pointers = (unsigned*)dind_block_contents.data();
|
auto* dind_block_as_pointers = (unsigned*)dind_block_contents.data();
|
||||||
|
|
||||||
|
@ -351,7 +356,8 @@ bool Ext2FS::write_block_list_for_inode(InodeIndex inode_index, ext2_inode& e2in
|
||||||
memset(ind_block_contents.data(), 0, dind_block_contents.size());
|
memset(ind_block_contents.data(), 0, dind_block_contents.size());
|
||||||
ind_block_dirty = true;
|
ind_block_dirty = true;
|
||||||
} else {
|
} else {
|
||||||
read_block(indirect_block_index, ind_block_contents.data(), block_size());
|
auto buffer = UserOrKernelBuffer::for_kernel_buffer(ind_block_contents.data());
|
||||||
|
read_block(indirect_block_index, &buffer, block_size());
|
||||||
}
|
}
|
||||||
auto* ind_block_as_pointers = (unsigned*)ind_block_contents.data();
|
auto* ind_block_as_pointers = (unsigned*)ind_block_contents.data();
|
||||||
|
|
||||||
|
@ -376,8 +382,9 @@ bool Ext2FS::write_block_list_for_inode(InodeIndex inode_index, ext2_inode& e2in
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ind_block_dirty) {
|
if (ind_block_dirty) {
|
||||||
bool success = write_block(indirect_block_index, ind_block_contents.data(), block_size());
|
auto buffer = UserOrKernelBuffer::for_kernel_buffer(ind_block_contents.data());
|
||||||
ASSERT(success);
|
int err = write_block(indirect_block_index, buffer, block_size());
|
||||||
|
ASSERT(err >= 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (unsigned i = indirect_block_count; i < entries_per_block; ++i) {
|
for (unsigned i = indirect_block_count; i < entries_per_block; ++i) {
|
||||||
|
@ -388,8 +395,9 @@ bool Ext2FS::write_block_list_for_inode(InodeIndex inode_index, ext2_inode& e2in
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dind_block_dirty) {
|
if (dind_block_dirty) {
|
||||||
bool success = write_block(e2inode.i_block[EXT2_DIND_BLOCK], dind_block_contents.data(), block_size());
|
auto buffer = UserOrKernelBuffer::for_kernel_buffer(dind_block_contents.data());
|
||||||
ASSERT(success);
|
int err = write_block(e2inode.i_block[EXT2_DIND_BLOCK], buffer, block_size());
|
||||||
|
ASSERT(err >= 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,7 +470,8 @@ Vector<Ext2FS::BlockIndex> Ext2FS::block_list_for_inode_impl(const ext2_inode& e
|
||||||
unsigned count = min(blocks_remaining, entries_per_block);
|
unsigned count = min(blocks_remaining, entries_per_block);
|
||||||
size_t read_size = count * sizeof(__u32);
|
size_t read_size = count * sizeof(__u32);
|
||||||
auto array_block = ByteBuffer::create_uninitialized(read_size);
|
auto array_block = ByteBuffer::create_uninitialized(read_size);
|
||||||
read_block(array_block_index, array_block.data(), read_size, 0);
|
auto buffer = UserOrKernelBuffer::for_kernel_buffer(array_block.data());
|
||||||
|
read_block(array_block_index, &buffer, read_size, 0);
|
||||||
ASSERT(array_block);
|
ASSERT(array_block);
|
||||||
auto* array = reinterpret_cast<const __u32*>(array_block.data());
|
auto* array = reinterpret_cast<const __u32*>(array_block.data());
|
||||||
for (BlockIndex i = 0; i < count; ++i)
|
for (BlockIndex i = 0; i < count; ++i)
|
||||||
|
@ -532,7 +541,8 @@ void Ext2FS::flush_block_group_descriptor_table()
|
||||||
LOCKER(m_lock);
|
LOCKER(m_lock);
|
||||||
unsigned blocks_to_write = ceil_div(m_block_group_count * sizeof(ext2_group_desc), block_size());
|
unsigned blocks_to_write = ceil_div(m_block_group_count * sizeof(ext2_group_desc), block_size());
|
||||||
unsigned first_block_of_bgdt = block_size() == 1024 ? 2 : 1;
|
unsigned first_block_of_bgdt = block_size() == 1024 ? 2 : 1;
|
||||||
write_blocks(first_block_of_bgdt, blocks_to_write, (const u8*)block_group_descriptors());
|
auto buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)block_group_descriptors());
|
||||||
|
write_blocks(first_block_of_bgdt, blocks_to_write, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ext2FS::flush_writes()
|
void Ext2FS::flush_writes()
|
||||||
|
@ -548,7 +558,8 @@ void Ext2FS::flush_writes()
|
||||||
}
|
}
|
||||||
for (auto& cached_bitmap : m_cached_bitmaps) {
|
for (auto& cached_bitmap : m_cached_bitmaps) {
|
||||||
if (cached_bitmap->dirty) {
|
if (cached_bitmap->dirty) {
|
||||||
write_block(cached_bitmap->bitmap_block_index, cached_bitmap->buffer.data(), block_size());
|
auto buffer = UserOrKernelBuffer::for_kernel_buffer(cached_bitmap->buffer.data());
|
||||||
|
write_block(cached_bitmap->bitmap_block_index, buffer, block_size());
|
||||||
cached_bitmap->dirty = false;
|
cached_bitmap->dirty = false;
|
||||||
#ifdef EXT2_DEBUG
|
#ifdef EXT2_DEBUG
|
||||||
dbg() << "Flushed bitmap block " << cached_bitmap->bitmap_block_index;
|
dbg() << "Flushed bitmap block " << cached_bitmap->bitmap_block_index;
|
||||||
|
@ -653,12 +664,13 @@ RefPtr<Inode> Ext2FS::get_inode(InodeIdentifier inode) const
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto new_inode = adopt(*new Ext2FSInode(const_cast<Ext2FS&>(*this), inode.index()));
|
auto new_inode = adopt(*new Ext2FSInode(const_cast<Ext2FS&>(*this), inode.index()));
|
||||||
read_block(block_index, reinterpret_cast<u8*>(&new_inode->m_raw_inode), sizeof(ext2_inode), offset);
|
auto buffer = UserOrKernelBuffer::for_kernel_buffer(reinterpret_cast<u8*>(&new_inode->m_raw_inode));
|
||||||
|
read_block(block_index, &buffer, sizeof(ext2_inode), offset);
|
||||||
m_inode_cache.set(inode.index(), new_inode);
|
m_inode_cache.set(inode.index(), new_inode);
|
||||||
return new_inode;
|
return new_inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t Ext2FSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDescription* description) const
|
ssize_t Ext2FSInode::read_bytes(off_t offset, ssize_t count, UserOrKernelBuffer& buffer, FileDescription* description) const
|
||||||
{
|
{
|
||||||
Locker inode_locker(m_lock);
|
Locker inode_locker(m_lock);
|
||||||
ASSERT(offset >= 0);
|
ASSERT(offset >= 0);
|
||||||
|
@ -670,7 +682,8 @@ ssize_t Ext2FSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDes
|
||||||
if (is_symlink() && size() < max_inline_symlink_length) {
|
if (is_symlink() && size() < max_inline_symlink_length) {
|
||||||
ASSERT(offset == 0);
|
ASSERT(offset == 0);
|
||||||
ssize_t nread = min((off_t)size() - offset, static_cast<off_t>(count));
|
ssize_t nread = min((off_t)size() - offset, static_cast<off_t>(count));
|
||||||
memcpy(buffer, ((const u8*)m_raw_inode.i_block) + offset, (size_t)nread);
|
if (!buffer.write(((const u8*)m_raw_inode.i_block) + offset, (size_t)nread))
|
||||||
|
return -EFAULT;
|
||||||
return nread;
|
return nread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -697,10 +710,9 @@ ssize_t Ext2FSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDes
|
||||||
|
|
||||||
ssize_t nread = 0;
|
ssize_t nread = 0;
|
||||||
size_t remaining_count = min((off_t)count, (off_t)size() - offset);
|
size_t remaining_count = min((off_t)count, (off_t)size() - offset);
|
||||||
u8* out = buffer;
|
|
||||||
|
|
||||||
#ifdef EXT2_DEBUG
|
#ifdef EXT2_DEBUG
|
||||||
dbg() << "Ext2FS: Reading up to " << count << " bytes " << offset << " bytes into inode " << identifier() << " to " << (const void*)buffer;
|
dbg() << "Ext2FS: Reading up to " << count << " bytes " << offset << " bytes into inode " << identifier() << " to " << buffer.user_or_kernel_ptr();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (size_t bi = first_block_logical_index; remaining_count && bi <= last_block_logical_index; ++bi) {
|
for (size_t bi = first_block_logical_index; remaining_count && bi <= last_block_logical_index; ++bi) {
|
||||||
|
@ -708,14 +720,14 @@ ssize_t Ext2FSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDes
|
||||||
ASSERT(block_index);
|
ASSERT(block_index);
|
||||||
size_t offset_into_block = (bi == first_block_logical_index) ? offset_into_first_block : 0;
|
size_t offset_into_block = (bi == first_block_logical_index) ? offset_into_first_block : 0;
|
||||||
size_t num_bytes_to_copy = min(block_size - offset_into_block, remaining_count);
|
size_t num_bytes_to_copy = min(block_size - offset_into_block, remaining_count);
|
||||||
bool success = fs().read_block(block_index, out, num_bytes_to_copy, offset_into_block, allow_cache);
|
auto buffer_offset = buffer.offset(nread);
|
||||||
if (!success) {
|
int err = fs().read_block(block_index, &buffer_offset, num_bytes_to_copy, offset_into_block, allow_cache);
|
||||||
|
if (err < 0) {
|
||||||
klog() << "ext2fs: read_bytes: read_block(" << block_index << ") failed (lbi: " << bi << ")";
|
klog() << "ext2fs: read_bytes: read_block(" << block_index << ") failed (lbi: " << bi << ")";
|
||||||
return -EIO;
|
return err;
|
||||||
}
|
}
|
||||||
remaining_count -= num_bytes_to_copy;
|
remaining_count -= num_bytes_to_copy;
|
||||||
nread += num_bytes_to_copy;
|
nread += num_bytes_to_copy;
|
||||||
out += num_bytes_to_copy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nread;
|
return nread;
|
||||||
|
@ -760,9 +772,9 @@ KResult Ext2FSInode::resize(u64 new_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success = fs().write_block_list_for_inode(index(), m_raw_inode, block_list);
|
int err = fs().write_block_list_for_inode(index(), m_raw_inode, block_list);
|
||||||
if (!success)
|
if (err < 0)
|
||||||
return KResult(-EIO);
|
return KResult(err);
|
||||||
|
|
||||||
m_raw_inode.i_size = new_size;
|
m_raw_inode.i_size = new_size;
|
||||||
set_metadata_dirty(true);
|
set_metadata_dirty(true);
|
||||||
|
@ -771,7 +783,7 @@ KResult Ext2FSInode::resize(u64 new_size)
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const u8* data, FileDescription* description)
|
ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const UserOrKernelBuffer& data, FileDescription* description)
|
||||||
{
|
{
|
||||||
ASSERT(offset >= 0);
|
ASSERT(offset >= 0);
|
||||||
ASSERT(count >= 0);
|
ASSERT(count >= 0);
|
||||||
|
@ -787,9 +799,10 @@ ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const u8* data, Fi
|
||||||
ASSERT(offset == 0);
|
ASSERT(offset == 0);
|
||||||
if (max((size_t)(offset + count), (size_t)m_raw_inode.i_size) < max_inline_symlink_length) {
|
if (max((size_t)(offset + count), (size_t)m_raw_inode.i_size) < max_inline_symlink_length) {
|
||||||
#ifdef EXT2_DEBUG
|
#ifdef EXT2_DEBUG
|
||||||
dbg() << "Ext2FS: write_bytes poking into i_block array for inline symlink '" << StringView(data, count) << " ' (" << count << " bytes)";
|
dbg() << "Ext2FS: write_bytes poking into i_block array for inline symlink '" << data.copy_into_string(count) << " ' (" << count << " bytes)";
|
||||||
#endif
|
#endif
|
||||||
memcpy(((u8*)m_raw_inode.i_block) + offset, data, (size_t)count);
|
if (!data.read(((u8*)m_raw_inode.i_block) + offset, (size_t)count))
|
||||||
|
return -EFAULT;
|
||||||
if ((size_t)(offset + count) > (size_t)m_raw_inode.i_size)
|
if ((size_t)(offset + count) > (size_t)m_raw_inode.i_size)
|
||||||
m_raw_inode.i_size = offset + count;
|
m_raw_inode.i_size = offset + count;
|
||||||
set_metadata_dirty(true);
|
set_metadata_dirty(true);
|
||||||
|
@ -824,10 +837,9 @@ ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const u8* data, Fi
|
||||||
|
|
||||||
ssize_t nwritten = 0;
|
ssize_t nwritten = 0;
|
||||||
size_t remaining_count = min((off_t)count, (off_t)new_size - offset);
|
size_t remaining_count = min((off_t)count, (off_t)new_size - offset);
|
||||||
const u8* in = data;
|
|
||||||
|
|
||||||
#ifdef EXT2_DEBUG
|
#ifdef EXT2_DEBUG
|
||||||
dbg() << "Ext2FS: Writing " << count << " bytes " << offset << " bytes into inode " << identifier() << " from " << (const void*)data;
|
dbg() << "Ext2FS: Writing " << count << " bytes " << offset << " bytes into inode " << identifier() << " from " << data.user_or_kernel_ptr();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (size_t bi = first_block_logical_index; remaining_count && bi <= last_block_logical_index; ++bi) {
|
for (size_t bi = first_block_logical_index; remaining_count && bi <= last_block_logical_index; ++bi) {
|
||||||
|
@ -836,15 +848,14 @@ ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const u8* data, Fi
|
||||||
#ifdef EXT2_DEBUG
|
#ifdef EXT2_DEBUG
|
||||||
dbg() << "Ext2FS: Writing block " << m_block_list[bi] << " (offset_into_block: " << offset_into_block << ")";
|
dbg() << "Ext2FS: Writing block " << m_block_list[bi] << " (offset_into_block: " << offset_into_block << ")";
|
||||||
#endif
|
#endif
|
||||||
bool success = fs().write_block(m_block_list[bi], in, num_bytes_to_copy, offset_into_block, allow_cache);
|
int err = fs().write_block(m_block_list[bi], data.offset(nwritten), num_bytes_to_copy, offset_into_block, allow_cache);
|
||||||
if (!success) {
|
if (err < 0) {
|
||||||
dbg() << "Ext2FS: write_block(" << m_block_list[bi] << ") failed (bi: " << bi << ")";
|
dbg() << "Ext2FS: write_block(" << m_block_list[bi] << ") failed (bi: " << bi << ")";
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
return -EIO;
|
return err;
|
||||||
}
|
}
|
||||||
remaining_count -= num_bytes_to_copy;
|
remaining_count -= num_bytes_to_copy;
|
||||||
nwritten += num_bytes_to_copy;
|
nwritten += num_bytes_to_copy;
|
||||||
in += num_bytes_to_copy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EXT2_DEBUG
|
#ifdef EXT2_DEBUG
|
||||||
|
@ -958,7 +969,8 @@ bool Ext2FSInode::write_directory(const Vector<Ext2FSDirectoryEntry>& entries)
|
||||||
|
|
||||||
stream.fill_to_end(0);
|
stream.fill_to_end(0);
|
||||||
|
|
||||||
ssize_t nwritten = write_bytes(0, directory_data.size(), directory_data.data(), nullptr);
|
auto buffer = UserOrKernelBuffer::for_kernel_buffer(directory_data.data());
|
||||||
|
ssize_t nwritten = write_bytes(0, directory_data.size(), buffer, nullptr);
|
||||||
if (nwritten < 0)
|
if (nwritten < 0)
|
||||||
return false;
|
return false;
|
||||||
set_metadata_dirty(true);
|
set_metadata_dirty(true);
|
||||||
|
@ -1087,7 +1099,8 @@ bool Ext2FS::write_ext2_inode(unsigned inode, const ext2_inode& e2inode)
|
||||||
unsigned offset;
|
unsigned offset;
|
||||||
if (!find_block_containing_inode(inode, block_index, offset))
|
if (!find_block_containing_inode(inode, block_index, offset))
|
||||||
return false;
|
return false;
|
||||||
return write_block(block_index, reinterpret_cast<const u8*>(&e2inode), inode_size(), offset);
|
auto buffer = UserOrKernelBuffer::for_kernel_buffer(const_cast<u8*>((const u8*)&e2inode));
|
||||||
|
return write_block(block_index, buffer, inode_size(), offset) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<Ext2FS::BlockIndex> Ext2FS::allocate_blocks(GroupIndex preferred_group_index, size_t count)
|
Vector<Ext2FS::BlockIndex> Ext2FS::allocate_blocks(GroupIndex preferred_group_index, size_t count)
|
||||||
|
@ -1314,8 +1327,9 @@ Ext2FS::CachedBitmap& Ext2FS::get_bitmap_block(BlockIndex bitmap_block_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto block = KBuffer::create_with_size(block_size(), Region::Access::Read | Region::Access::Write, "Ext2FS: Cached bitmap block");
|
auto block = KBuffer::create_with_size(block_size(), Region::Access::Read | Region::Access::Write, "Ext2FS: Cached bitmap block");
|
||||||
bool success = read_block(bitmap_block_index, block.data(), block_size());
|
auto buffer = UserOrKernelBuffer::for_kernel_buffer(block.data());
|
||||||
ASSERT(success);
|
int err = read_block(bitmap_block_index, &buffer, block_size());
|
||||||
|
ASSERT(err >= 0);
|
||||||
m_cached_bitmaps.append(make<CachedBitmap>(bitmap_block_index, move(block)));
|
m_cached_bitmaps.append(make<CachedBitmap>(bitmap_block_index, move(block)));
|
||||||
return *m_cached_bitmaps.last();
|
return *m_cached_bitmaps.last();
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,12 +58,12 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// ^Inode
|
// ^Inode
|
||||||
virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override;
|
virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override;
|
||||||
virtual InodeMetadata metadata() const override;
|
virtual InodeMetadata metadata() const override;
|
||||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
|
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
|
||||||
virtual RefPtr<Inode> lookup(StringView name) override;
|
virtual RefPtr<Inode> lookup(StringView name) override;
|
||||||
virtual void flush_metadata() override;
|
virtual void flush_metadata() override;
|
||||||
virtual ssize_t write_bytes(off_t, ssize_t, const u8* data, FileDescription*) override;
|
virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& data, FileDescription*) override;
|
||||||
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
|
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
|
||||||
virtual KResult add_child(Inode& child, const StringView& name, mode_t) override;
|
virtual KResult add_child(Inode& child, const StringView& name, mode_t) override;
|
||||||
virtual KResult remove_child(const StringView& name) override;
|
virtual KResult remove_child(const StringView& name) override;
|
||||||
|
|
|
@ -145,14 +145,14 @@ bool FIFO::can_write(const FileDescription&, size_t) const
|
||||||
return m_buffer.space_for_writing() || !m_readers;
|
return m_buffer.space_for_writing() || !m_readers;
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> FIFO::read(FileDescription&, size_t, u8* buffer, size_t size)
|
KResultOr<size_t> FIFO::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t size)
|
||||||
{
|
{
|
||||||
if (!m_writers && m_buffer.is_empty())
|
if (!m_writers && m_buffer.is_empty())
|
||||||
return 0;
|
return 0;
|
||||||
return m_buffer.read(buffer, size);
|
return m_buffer.read(buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> FIFO::write(FileDescription&, size_t, const u8* buffer, size_t size)
|
KResultOr<size_t> FIFO::write(FileDescription&, size_t, const UserOrKernelBuffer& buffer, size_t size)
|
||||||
{
|
{
|
||||||
if (!m_readers) {
|
if (!m_readers) {
|
||||||
Thread::current()->send_signal(SIGPIPE, Process::current());
|
Thread::current()->send_signal(SIGPIPE, Process::current());
|
||||||
|
|
|
@ -57,8 +57,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// ^File
|
// ^File
|
||||||
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 KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
|
virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
|
||||||
virtual KResult stat(::stat&) const override;
|
virtual KResult stat(::stat&) const override;
|
||||||
virtual bool can_read(const FileDescription&, size_t) const override;
|
virtual bool can_read(const FileDescription&, size_t) const override;
|
||||||
virtual bool can_write(const FileDescription&, size_t) const override;
|
virtual bool can_write(const FileDescription&, size_t) const override;
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include <Kernel/Forward.h>
|
#include <Kernel/Forward.h>
|
||||||
#include <Kernel/KResult.h>
|
#include <Kernel/KResult.h>
|
||||||
#include <Kernel/UnixTypes.h>
|
#include <Kernel/UnixTypes.h>
|
||||||
|
#include <Kernel/UserOrKernelBuffer.h>
|
||||||
#include <Kernel/VirtualAddress.h>
|
#include <Kernel/VirtualAddress.h>
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
@ -77,8 +78,8 @@ public:
|
||||||
virtual bool can_read(const FileDescription&, size_t) const = 0;
|
virtual bool can_read(const FileDescription&, size_t) const = 0;
|
||||||
virtual bool can_write(const FileDescription&, size_t) const = 0;
|
virtual bool can_write(const FileDescription&, size_t) const = 0;
|
||||||
|
|
||||||
virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) = 0;
|
virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) = 0;
|
||||||
virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) = 0;
|
virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) = 0;
|
||||||
virtual int ioctl(FileDescription&, unsigned request, FlatPtr arg);
|
virtual int ioctl(FileDescription&, unsigned request, FlatPtr arg);
|
||||||
virtual KResultOr<Region*> mmap(Process&, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot, bool shared);
|
virtual KResultOr<Region*> mmap(Process&, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot, bool shared);
|
||||||
virtual KResult stat(::stat&) const { return KResult(-EBADF); }
|
virtual KResult stat(::stat&) const { return KResult(-EBADF); }
|
||||||
|
|
|
@ -116,7 +116,7 @@ off_t FileDescription::seek(off_t offset, int whence)
|
||||||
return m_current_offset;
|
return m_current_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> FileDescription::read(u8* buffer, size_t count)
|
KResultOr<size_t> FileDescription::read(UserOrKernelBuffer& buffer, size_t count)
|
||||||
{
|
{
|
||||||
LOCKER(m_lock);
|
LOCKER(m_lock);
|
||||||
Checked<size_t> new_offset = m_current_offset;
|
Checked<size_t> new_offset = m_current_offset;
|
||||||
|
@ -130,7 +130,7 @@ KResultOr<size_t> FileDescription::read(u8* buffer, size_t count)
|
||||||
return nread_or_error;
|
return nread_or_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> FileDescription::write(const u8* data, size_t size)
|
KResultOr<size_t> FileDescription::write(const UserOrKernelBuffer& data, size_t size)
|
||||||
{
|
{
|
||||||
LOCKER(m_lock);
|
LOCKER(m_lock);
|
||||||
Checked<size_t> new_offset = m_current_offset;
|
Checked<size_t> new_offset = m_current_offset;
|
||||||
|
@ -162,7 +162,7 @@ KResultOr<KBuffer> FileDescription::read_entire_file()
|
||||||
return m_inode->read_entire(this);
|
return m_inode->read_entire(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t FileDescription::get_dir_entries(u8* buffer, ssize_t size)
|
ssize_t FileDescription::get_dir_entries(UserOrKernelBuffer& buffer, ssize_t size)
|
||||||
{
|
{
|
||||||
LOCKER(m_lock, Lock::Mode::Shared);
|
LOCKER(m_lock, Lock::Mode::Shared);
|
||||||
if (!is_directory())
|
if (!is_directory())
|
||||||
|
@ -195,7 +195,8 @@ ssize_t FileDescription::get_dir_entries(u8* buffer, ssize_t size)
|
||||||
if (static_cast<size_t>(size) < temp_buffer.size())
|
if (static_cast<size_t>(size) < temp_buffer.size())
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
copy_to_user(buffer, temp_buffer.data(), temp_buffer.size());
|
if (!buffer.write(temp_buffer.data(), temp_buffer.size()))
|
||||||
|
return -EFAULT;
|
||||||
return stream.offset();
|
return stream.offset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,8 +60,8 @@ public:
|
||||||
KResult close();
|
KResult close();
|
||||||
|
|
||||||
off_t seek(off_t, int whence);
|
off_t seek(off_t, int whence);
|
||||||
KResultOr<size_t> read(u8*, size_t);
|
KResultOr<size_t> read(UserOrKernelBuffer&, size_t);
|
||||||
KResultOr<size_t> write(const u8* data, size_t);
|
KResultOr<size_t> write(const UserOrKernelBuffer& data, size_t);
|
||||||
KResult stat(::stat&);
|
KResult stat(::stat&);
|
||||||
|
|
||||||
KResult chmod(mode_t);
|
KResult chmod(mode_t);
|
||||||
|
@ -69,7 +69,7 @@ public:
|
||||||
bool can_read() const;
|
bool can_read() const;
|
||||||
bool can_write() const;
|
bool can_write() const;
|
||||||
|
|
||||||
ssize_t get_dir_entries(u8* buffer, ssize_t);
|
ssize_t get_dir_entries(UserOrKernelBuffer& buffer, ssize_t);
|
||||||
|
|
||||||
KResultOr<KBuffer> read_entire_file();
|
KResultOr<KBuffer> read_entire_file();
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include <Kernel/KResult.h>
|
#include <Kernel/KResult.h>
|
||||||
#include <Kernel/Lock.h>
|
#include <Kernel/Lock.h>
|
||||||
#include <Kernel/UnixTypes.h>
|
#include <Kernel/UnixTypes.h>
|
||||||
|
#include <Kernel/UserOrKernelBuffer.h>
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,10 @@ KResultOr<KBuffer> Inode::read_entire(FileDescription* descriptor) const
|
||||||
u8 buffer[4096];
|
u8 buffer[4096];
|
||||||
off_t offset = 0;
|
off_t offset = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
nread = read_bytes(offset, sizeof(buffer), buffer, descriptor);
|
auto buf = UserOrKernelBuffer::for_kernel_buffer(buffer);
|
||||||
|
nread = read_bytes(offset, sizeof(buffer), buf, descriptor);
|
||||||
|
if (nread < 0)
|
||||||
|
return KResult(nread);
|
||||||
ASSERT(nread <= (ssize_t)sizeof(buffer));
|
ASSERT(nread <= (ssize_t)sizeof(buffer));
|
||||||
if (nread <= 0)
|
if (nread <= 0)
|
||||||
break;
|
break;
|
||||||
|
@ -124,7 +127,7 @@ void Inode::will_be_destroyed()
|
||||||
flush_metadata();
|
flush_metadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Inode::inode_contents_changed(off_t offset, ssize_t size, const u8* data)
|
void Inode::inode_contents_changed(off_t offset, ssize_t size, const UserOrKernelBuffer& data)
|
||||||
{
|
{
|
||||||
if (m_shared_vmobject)
|
if (m_shared_vmobject)
|
||||||
m_shared_vmobject->inode_contents_changed({}, offset, size, data);
|
m_shared_vmobject->inode_contents_changed({}, offset, size, data);
|
||||||
|
|
|
@ -69,10 +69,10 @@ public:
|
||||||
|
|
||||||
KResultOr<KBuffer> read_entire(FileDescription* = nullptr) const;
|
KResultOr<KBuffer> read_entire(FileDescription* = nullptr) const;
|
||||||
|
|
||||||
virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const = 0;
|
virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const = 0;
|
||||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const = 0;
|
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const = 0;
|
||||||
virtual RefPtr<Inode> lookup(StringView name) = 0;
|
virtual RefPtr<Inode> lookup(StringView name) = 0;
|
||||||
virtual ssize_t write_bytes(off_t, ssize_t, const u8* data, FileDescription*) = 0;
|
virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& data, FileDescription*) = 0;
|
||||||
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) = 0;
|
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) = 0;
|
||||||
virtual KResult add_child(Inode&, const StringView& name, mode_t) = 0;
|
virtual KResult add_child(Inode&, const StringView& name, mode_t) = 0;
|
||||||
virtual KResult remove_child(const StringView& name) = 0;
|
virtual KResult remove_child(const StringView& name) = 0;
|
||||||
|
@ -122,7 +122,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
Inode(FS& fs, unsigned index);
|
Inode(FS& fs, unsigned index);
|
||||||
void set_metadata_dirty(bool);
|
void set_metadata_dirty(bool);
|
||||||
void inode_contents_changed(off_t, ssize_t, const u8*);
|
void inode_contents_changed(off_t, ssize_t, const UserOrKernelBuffer&);
|
||||||
void inode_size_changed(size_t old_size, size_t new_size);
|
void inode_size_changed(size_t old_size, size_t new_size);
|
||||||
KResult prepare_to_write_data();
|
KResult prepare_to_write_data();
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ InodeFile::~InodeFile()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> InodeFile::read(FileDescription& description, size_t offset, u8* buffer, size_t count)
|
KResultOr<size_t> InodeFile::read(FileDescription& description, size_t offset, UserOrKernelBuffer& buffer, size_t count)
|
||||||
{
|
{
|
||||||
ssize_t nread = m_inode->read_bytes(offset, count, buffer, &description);
|
ssize_t nread = m_inode->read_bytes(offset, count, buffer, &description);
|
||||||
if (nread > 0)
|
if (nread > 0)
|
||||||
|
@ -54,7 +54,7 @@ KResultOr<size_t> InodeFile::read(FileDescription& description, size_t offset, u
|
||||||
return nread;
|
return nread;
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> InodeFile::write(FileDescription& description, size_t offset, const u8* data, size_t count)
|
KResultOr<size_t> InodeFile::write(FileDescription& description, size_t offset, const UserOrKernelBuffer& data, size_t count)
|
||||||
{
|
{
|
||||||
ssize_t nwritten = m_inode->write_bytes(offset, count, data, &description);
|
ssize_t nwritten = m_inode->write_bytes(offset, count, data, &description);
|
||||||
if (nwritten > 0) {
|
if (nwritten > 0) {
|
||||||
|
|
|
@ -47,8 +47,8 @@ public:
|
||||||
virtual bool can_read(const FileDescription&, size_t) const override { return true; }
|
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 bool can_write(const FileDescription&, size_t) const override { return true; }
|
||||||
|
|
||||||
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 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 KResultOr<Region*> mmap(Process&, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot, bool shared) override;
|
virtual KResultOr<Region*> mmap(Process&, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot, bool shared) override;
|
||||||
|
|
||||||
virtual String absolute_path(const FileDescription&) const override;
|
virtual String absolute_path(const FileDescription&) const override;
|
||||||
|
|
|
@ -57,7 +57,7 @@ bool InodeWatcher::can_write(const FileDescription&, size_t) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> InodeWatcher::read(FileDescription&, size_t, u8* buffer, size_t buffer_size)
|
KResultOr<size_t> InodeWatcher::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t buffer_size)
|
||||||
{
|
{
|
||||||
LOCKER(m_lock);
|
LOCKER(m_lock);
|
||||||
ASSERT(!m_queue.is_empty() || !m_inode);
|
ASSERT(!m_queue.is_empty() || !m_inode);
|
||||||
|
@ -68,11 +68,17 @@ KResultOr<size_t> InodeWatcher::read(FileDescription&, size_t, u8* buffer, size_
|
||||||
// FIXME: What should we do if the output buffer is too small?
|
// FIXME: What should we do if the output buffer is too small?
|
||||||
ASSERT(buffer_size >= (int)sizeof(Event));
|
ASSERT(buffer_size >= (int)sizeof(Event));
|
||||||
auto event = m_queue.dequeue();
|
auto event = m_queue.dequeue();
|
||||||
memcpy(buffer, &event, sizeof(event));
|
ssize_t nwritten = buffer.write_buffered<sizeof(event)>(sizeof(event), [&](u8* data, size_t data_bytes) {
|
||||||
|
memcpy(data, &event, sizeof(event));
|
||||||
|
return (ssize_t)data_bytes;
|
||||||
|
});
|
||||||
|
if (nwritten < 0)
|
||||||
|
return KResult(nwritten);
|
||||||
|
ASSERT((size_t)nwritten == sizeof(event));
|
||||||
return sizeof(event);
|
return sizeof(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> InodeWatcher::write(FileDescription&, size_t, const u8*, size_t)
|
KResultOr<size_t> InodeWatcher::write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t)
|
||||||
{
|
{
|
||||||
return KResult(-EIO);
|
return KResult(-EIO);
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,8 +55,8 @@ public:
|
||||||
|
|
||||||
virtual bool can_read(const FileDescription&, size_t) const override;
|
virtual bool can_read(const FileDescription&, size_t) const override;
|
||||||
virtual bool can_write(const FileDescription&, size_t) const override;
|
virtual bool can_write(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 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 String absolute_path(const FileDescription&) const override;
|
virtual String absolute_path(const FileDescription&) const override;
|
||||||
virtual const char* class_name() const override { return "InodeWatcher"; };
|
virtual const char* class_name() const override { return "InodeWatcher"; };
|
||||||
|
|
||||||
|
|
|
@ -426,7 +426,8 @@ KResult Plan9FS::post_message(Message& message)
|
||||||
if (Thread::current()->block<Thread::WriteBlocker>(nullptr, description).was_interrupted())
|
if (Thread::current()->block<Thread::WriteBlocker>(nullptr, description).was_interrupted())
|
||||||
return KResult(-EINTR);
|
return KResult(-EINTR);
|
||||||
}
|
}
|
||||||
auto nwritten_or_error = description.write(data, size);
|
auto data_buffer = UserOrKernelBuffer::for_kernel_buffer(const_cast<u8*>(data));
|
||||||
|
auto nwritten_or_error = description.write(data_buffer, size);
|
||||||
if (nwritten_or_error.is_error())
|
if (nwritten_or_error.is_error())
|
||||||
return nwritten_or_error.error();
|
return nwritten_or_error.error();
|
||||||
auto nwritten = nwritten_or_error.value();
|
auto nwritten = nwritten_or_error.value();
|
||||||
|
@ -445,7 +446,8 @@ KResult Plan9FS::do_read(u8* data, size_t size)
|
||||||
if (Thread::current()->block<Thread::ReadBlocker>(nullptr, description).was_interrupted())
|
if (Thread::current()->block<Thread::ReadBlocker>(nullptr, description).was_interrupted())
|
||||||
return KResult(-EINTR);
|
return KResult(-EINTR);
|
||||||
}
|
}
|
||||||
auto nread_or_error = description.read(data, size);
|
auto data_buffer = UserOrKernelBuffer::for_kernel_buffer(data);
|
||||||
|
auto nread_or_error = description.read(data_buffer, size);
|
||||||
if (nread_or_error.is_error())
|
if (nread_or_error.is_error())
|
||||||
return nread_or_error.error();
|
return nread_or_error.error();
|
||||||
auto nread = nread_or_error.value();
|
auto nread = nread_or_error.value();
|
||||||
|
@ -677,7 +679,7 @@ KResult Plan9FSInode::ensure_open_for_mode(int mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t Plan9FSInode::read_bytes(off_t offset, ssize_t size, u8* buffer, FileDescription*) const
|
ssize_t Plan9FSInode::read_bytes(off_t offset, ssize_t size, UserOrKernelBuffer& buffer, FileDescription*) const
|
||||||
{
|
{
|
||||||
auto result = const_cast<Plan9FSInode&>(*this).ensure_open_for_mode(O_RDONLY);
|
auto result = const_cast<Plan9FSInode&>(*this).ensure_open_for_mode(O_RDONLY);
|
||||||
if (result.is_error())
|
if (result.is_error())
|
||||||
|
@ -710,12 +712,13 @@ ssize_t Plan9FSInode::read_bytes(off_t offset, ssize_t size, u8* buffer, FileDes
|
||||||
|
|
||||||
// Guard against the server returning more data than requested.
|
// Guard against the server returning more data than requested.
|
||||||
size_t nread = min(data.length(), (size_t)size);
|
size_t nread = min(data.length(), (size_t)size);
|
||||||
memcpy(buffer, data.characters_without_null_termination(), nread);
|
if (!buffer.write(data.characters_without_null_termination(), nread))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
return nread;
|
return nread;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t Plan9FSInode::write_bytes(off_t offset, ssize_t size, const u8* data, FileDescription*)
|
ssize_t Plan9FSInode::write_bytes(off_t offset, ssize_t size, const UserOrKernelBuffer& data, FileDescription*)
|
||||||
{
|
{
|
||||||
auto result = ensure_open_for_mode(O_WRONLY);
|
auto result = ensure_open_for_mode(O_WRONLY);
|
||||||
if (result.is_error())
|
if (result.is_error())
|
||||||
|
@ -723,9 +726,13 @@ ssize_t Plan9FSInode::write_bytes(off_t offset, ssize_t size, const u8* data, Fi
|
||||||
|
|
||||||
size = fs().adjust_buffer_size(size);
|
size = fs().adjust_buffer_size(size);
|
||||||
|
|
||||||
|
auto data_copy = data.copy_into_string(size); // FIXME: this seems ugly
|
||||||
|
if (data_copy.is_null())
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
Plan9FS::Message message { fs(), Plan9FS::Message::Type::Twrite };
|
Plan9FS::Message message { fs(), Plan9FS::Message::Type::Twrite };
|
||||||
message << fid() << (u64)offset;
|
message << fid() << (u64)offset;
|
||||||
message.append_data({ data, (size_t)size });
|
message.append_data(data_copy);
|
||||||
result = fs().post_message_and_wait_for_a_reply(message);
|
result = fs().post_message_and_wait_for_a_reply(message);
|
||||||
if (result.is_error())
|
if (result.is_error())
|
||||||
return result.error();
|
return result.error();
|
||||||
|
|
|
@ -124,8 +124,8 @@ public:
|
||||||
// ^Inode
|
// ^Inode
|
||||||
virtual InodeMetadata metadata() const override;
|
virtual InodeMetadata metadata() const override;
|
||||||
virtual void flush_metadata() override;
|
virtual void flush_metadata() override;
|
||||||
virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override;
|
virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override;
|
||||||
virtual ssize_t write_bytes(off_t, ssize_t, const u8* data, FileDescription*) override;
|
virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& data, FileDescription*) override;
|
||||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
|
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
|
||||||
virtual RefPtr<Inode> lookup(StringView name) override;
|
virtual RefPtr<Inode> lookup(StringView name) override;
|
||||||
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
|
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
|
||||||
|
|
|
@ -976,21 +976,33 @@ static ByteBuffer read_sys_bool(InodeIdentifier inode_id)
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t write_sys_bool(InodeIdentifier inode_id, const ByteBuffer& data)
|
static ssize_t write_sys_bool(InodeIdentifier inode_id, const UserOrKernelBuffer& buffer, size_t size)
|
||||||
{
|
{
|
||||||
auto& variable = SysVariable::for_inode(inode_id);
|
auto& variable = SysVariable::for_inode(inode_id);
|
||||||
ASSERT(variable.type == SysVariable::Type::Boolean);
|
ASSERT(variable.type == SysVariable::Type::Boolean);
|
||||||
|
|
||||||
if (data.is_empty() || !(data[0] == '0' || data[0] == '1'))
|
char value = 0;
|
||||||
return data.size();
|
bool did_read = false;
|
||||||
|
ssize_t nread = buffer.read_buffered<1>(1, [&](const u8* data, size_t) {
|
||||||
|
if (did_read)
|
||||||
|
return 0;
|
||||||
|
value = (char)data[0];
|
||||||
|
did_read = true;
|
||||||
|
return 1;
|
||||||
|
});
|
||||||
|
if (nread < 0)
|
||||||
|
return nread;
|
||||||
|
ASSERT(nread == 0 || (nread == 1 && did_read));
|
||||||
|
if (nread == 0 || !(value == '0' || value == '1'))
|
||||||
|
return (ssize_t)size;
|
||||||
|
|
||||||
auto* lockable_bool = reinterpret_cast<Lockable<bool>*>(variable.address);
|
auto* lockable_bool = reinterpret_cast<Lockable<bool>*>(variable.address);
|
||||||
{
|
{
|
||||||
LOCKER(lockable_bool->lock());
|
LOCKER(lockable_bool->lock());
|
||||||
lockable_bool->resource() = data[0] == '1';
|
lockable_bool->resource() = value == '1';
|
||||||
}
|
}
|
||||||
variable.notify();
|
variable.notify();
|
||||||
return data.size();
|
return (ssize_t)size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ByteBuffer read_sys_string(InodeIdentifier inode_id)
|
static ByteBuffer read_sys_string(InodeIdentifier inode_id)
|
||||||
|
@ -1003,18 +1015,22 @@ static ByteBuffer read_sys_string(InodeIdentifier inode_id)
|
||||||
return lockable_string->resource().to_byte_buffer();
|
return lockable_string->resource().to_byte_buffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t write_sys_string(InodeIdentifier inode_id, const ByteBuffer& data)
|
static ssize_t write_sys_string(InodeIdentifier inode_id, const UserOrKernelBuffer& buffer, size_t size)
|
||||||
{
|
{
|
||||||
auto& variable = SysVariable::for_inode(inode_id);
|
auto& variable = SysVariable::for_inode(inode_id);
|
||||||
ASSERT(variable.type == SysVariable::Type::String);
|
ASSERT(variable.type == SysVariable::Type::String);
|
||||||
|
|
||||||
|
auto string_copy = buffer.copy_into_string(size);
|
||||||
|
if (string_copy.is_null())
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
{
|
{
|
||||||
auto* lockable_string = reinterpret_cast<Lockable<String>*>(variable.address);
|
auto* lockable_string = reinterpret_cast<Lockable<String>*>(variable.address);
|
||||||
LOCKER(lockable_string->lock());
|
LOCKER(lockable_string->lock());
|
||||||
lockable_string->resource() = String((const char*)data.data(), data.size());
|
lockable_string->resource() = move(string_copy);
|
||||||
}
|
}
|
||||||
variable.notify();
|
variable.notify();
|
||||||
return data.size();
|
return (ssize_t)size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcFS::add_sys_bool(String&& name, Lockable<bool>& var, Function<void()>&& notify_callback)
|
void ProcFS::add_sys_bool(String&& name, Lockable<bool>& var, Function<void()>&& notify_callback)
|
||||||
|
@ -1180,13 +1196,13 @@ InodeMetadata ProcFSInode::metadata() const
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t ProcFSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDescription* description) const
|
ssize_t ProcFSInode::read_bytes(off_t offset, ssize_t count, UserOrKernelBuffer& buffer, FileDescription* description) const
|
||||||
{
|
{
|
||||||
#ifdef PROCFS_DEBUG
|
#ifdef PROCFS_DEBUG
|
||||||
dbg() << "ProcFS: read_bytes " << index();
|
dbg() << "ProcFS: read_bytes " << index();
|
||||||
#endif
|
#endif
|
||||||
ASSERT(offset >= 0);
|
ASSERT(offset >= 0);
|
||||||
ASSERT(buffer);
|
ASSERT(buffer.user_or_kernel_ptr());
|
||||||
|
|
||||||
auto* directory_entry = fs().get_directory_entry(identifier());
|
auto* directory_entry = fs().get_directory_entry(identifier());
|
||||||
|
|
||||||
|
@ -1240,7 +1256,8 @@ ssize_t ProcFSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDes
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ssize_t nread = min(static_cast<off_t>(data.value().size() - offset), static_cast<off_t>(count));
|
ssize_t nread = min(static_cast<off_t>(data.value().size() - offset), static_cast<off_t>(count));
|
||||||
memcpy(buffer, data.value().data() + offset, nread);
|
if (!buffer.write(data.value().data() + offset, nread))
|
||||||
|
return -EFAULT;
|
||||||
if (nread == 0 && description && description->generator_cache().has_value())
|
if (nread == 0 && description && description->generator_cache().has_value())
|
||||||
description->generator_cache().clear();
|
description->generator_cache().clear();
|
||||||
|
|
||||||
|
@ -1461,7 +1478,7 @@ void ProcFSInode::flush_metadata()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t ProcFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, FileDescription*)
|
ssize_t ProcFSInode::write_bytes(off_t offset, ssize_t size, const UserOrKernelBuffer& buffer, FileDescription*)
|
||||||
{
|
{
|
||||||
auto result = prepare_to_write_data();
|
auto result = prepare_to_write_data();
|
||||||
if (result.is_error())
|
if (result.is_error())
|
||||||
|
@ -1469,8 +1486,8 @@ ssize_t ProcFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, F
|
||||||
|
|
||||||
auto* directory_entry = fs().get_directory_entry(identifier());
|
auto* directory_entry = fs().get_directory_entry(identifier());
|
||||||
|
|
||||||
Function<ssize_t(InodeIdentifier, const ByteBuffer&)> callback_tmp;
|
Function<ssize_t(InodeIdentifier, const UserOrKernelBuffer&, size_t)> callback_tmp;
|
||||||
Function<ssize_t(InodeIdentifier, const ByteBuffer&)>* write_callback { nullptr };
|
Function<ssize_t(InodeIdentifier, const UserOrKernelBuffer&, size_t)>* write_callback { nullptr };
|
||||||
|
|
||||||
if (directory_entry == nullptr) {
|
if (directory_entry == nullptr) {
|
||||||
if (to_proc_parent_directory(identifier()) == PDI_Root_sys) {
|
if (to_proc_parent_directory(identifier()) == PDI_Root_sys) {
|
||||||
|
@ -1496,9 +1513,10 @@ ssize_t ProcFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, F
|
||||||
ASSERT(is_persistent_inode(identifier()));
|
ASSERT(is_persistent_inode(identifier()));
|
||||||
// FIXME: Being able to write into ProcFS at a non-zero offset seems like something we should maybe support..
|
// FIXME: Being able to write into ProcFS at a non-zero offset seems like something we should maybe support..
|
||||||
ASSERT(offset == 0);
|
ASSERT(offset == 0);
|
||||||
bool success = (*write_callback)(identifier(), ByteBuffer::wrap(const_cast<u8*>(buffer), size));
|
ssize_t nwritten = (*write_callback)(identifier(), buffer, (size_t)size);
|
||||||
ASSERT(success);
|
if (nwritten < 0)
|
||||||
return 0;
|
klog() << "ProcFS: Writing " << size << " bytes failed: " << nwritten;
|
||||||
|
return nwritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<NonnullRefPtr<Custody>> ProcFSInode::resolve_as_link(Custody& base, RefPtr<Custody>* out_parent, int options, int symlink_recursion_level) const
|
KResultOr<NonnullRefPtr<Custody>> ProcFSInode::resolve_as_link(Custody& base, RefPtr<Custody>* out_parent, int options, int symlink_recursion_level) const
|
||||||
|
|
|
@ -59,7 +59,7 @@ private:
|
||||||
|
|
||||||
struct ProcFSDirectoryEntry {
|
struct ProcFSDirectoryEntry {
|
||||||
ProcFSDirectoryEntry() { }
|
ProcFSDirectoryEntry() { }
|
||||||
ProcFSDirectoryEntry(const char* a_name, unsigned a_proc_file_type, bool a_supervisor_only, Function<Optional<KBuffer>(InodeIdentifier)>&& a_read_callback = nullptr, Function<ssize_t(InodeIdentifier, const ByteBuffer&)>&& a_write_callback = nullptr, RefPtr<ProcFSInode>&& a_inode = nullptr)
|
ProcFSDirectoryEntry(const char* a_name, unsigned a_proc_file_type, bool a_supervisor_only, Function<Optional<KBuffer>(InodeIdentifier)>&& a_read_callback = nullptr, Function<ssize_t(InodeIdentifier, const UserOrKernelBuffer&, size_t)>&& a_write_callback = nullptr, RefPtr<ProcFSInode>&& a_inode = nullptr)
|
||||||
: name(a_name)
|
: name(a_name)
|
||||||
, proc_file_type(a_proc_file_type)
|
, proc_file_type(a_proc_file_type)
|
||||||
, supervisor_only(a_supervisor_only)
|
, supervisor_only(a_supervisor_only)
|
||||||
|
@ -73,7 +73,7 @@ private:
|
||||||
unsigned proc_file_type { 0 };
|
unsigned proc_file_type { 0 };
|
||||||
bool supervisor_only { false };
|
bool supervisor_only { false };
|
||||||
Function<Optional<KBuffer>(InodeIdentifier)> read_callback;
|
Function<Optional<KBuffer>(InodeIdentifier)> read_callback;
|
||||||
Function<ssize_t(InodeIdentifier, const ByteBuffer&)> write_callback;
|
Function<ssize_t(InodeIdentifier, const UserOrKernelBuffer&, size_t)> write_callback;
|
||||||
RefPtr<ProcFSInode> inode;
|
RefPtr<ProcFSInode> inode;
|
||||||
InodeIdentifier identifier(unsigned fsid) const;
|
InodeIdentifier identifier(unsigned fsid) const;
|
||||||
};
|
};
|
||||||
|
@ -96,12 +96,12 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// ^Inode
|
// ^Inode
|
||||||
virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override;
|
virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override;
|
||||||
virtual InodeMetadata metadata() const override;
|
virtual InodeMetadata metadata() const override;
|
||||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
|
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
|
||||||
virtual RefPtr<Inode> lookup(StringView name) override;
|
virtual RefPtr<Inode> lookup(StringView name) override;
|
||||||
virtual void flush_metadata() override;
|
virtual void flush_metadata() override;
|
||||||
virtual ssize_t write_bytes(off_t, ssize_t, const u8* buffer, FileDescription*) override;
|
virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& buffer, FileDescription*) override;
|
||||||
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
|
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
|
||||||
virtual KResult add_child(Inode&, const StringView& name, mode_t) override;
|
virtual KResult add_child(Inode&, const StringView& name, mode_t) override;
|
||||||
virtual KResult remove_child(const StringView& name) override;
|
virtual KResult remove_child(const StringView& name) override;
|
||||||
|
@ -123,12 +123,12 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// ^Inode
|
// ^Inode
|
||||||
virtual ssize_t read_bytes(off_t, ssize_t, u8*, FileDescription*) const override { ASSERT_NOT_REACHED(); }
|
virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer&, FileDescription*) const override { ASSERT_NOT_REACHED(); }
|
||||||
virtual InodeMetadata metadata() const override;
|
virtual InodeMetadata metadata() const override;
|
||||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override { ASSERT_NOT_REACHED(); }
|
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override { ASSERT_NOT_REACHED(); }
|
||||||
virtual RefPtr<Inode> lookup(StringView name) override;
|
virtual RefPtr<Inode> lookup(StringView name) override;
|
||||||
virtual void flush_metadata() override {};
|
virtual void flush_metadata() override {};
|
||||||
virtual ssize_t write_bytes(off_t, ssize_t, const u8*, FileDescription*) override { ASSERT_NOT_REACHED(); }
|
virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer&, FileDescription*) override { ASSERT_NOT_REACHED(); }
|
||||||
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
|
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
|
||||||
virtual KResult add_child(Inode&, const StringView& name, mode_t) override;
|
virtual KResult add_child(Inode&, const StringView& name, mode_t) override;
|
||||||
virtual KResult remove_child(const StringView& name) override;
|
virtual KResult remove_child(const StringView& name) override;
|
||||||
|
|
|
@ -141,7 +141,7 @@ KResult TmpFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntry
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t TmpFSInode::read_bytes(off_t offset, ssize_t size, u8* buffer, FileDescription*) const
|
ssize_t TmpFSInode::read_bytes(off_t offset, ssize_t size, UserOrKernelBuffer& buffer, FileDescription*) const
|
||||||
{
|
{
|
||||||
LOCKER(m_lock, Lock::Mode::Shared);
|
LOCKER(m_lock, Lock::Mode::Shared);
|
||||||
ASSERT(!is_directory());
|
ASSERT(!is_directory());
|
||||||
|
@ -157,11 +157,12 @@ ssize_t TmpFSInode::read_bytes(off_t offset, ssize_t size, u8* buffer, FileDescr
|
||||||
if (static_cast<off_t>(size) > m_metadata.size - offset)
|
if (static_cast<off_t>(size) > m_metadata.size - offset)
|
||||||
size = m_metadata.size - offset;
|
size = m_metadata.size - offset;
|
||||||
|
|
||||||
memcpy(buffer, m_content.value().data() + offset, size);
|
if (!buffer.write(m_content.value().data() + offset, size))
|
||||||
|
return -EFAULT;
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t TmpFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, FileDescription*)
|
ssize_t TmpFSInode::write_bytes(off_t offset, ssize_t size, const UserOrKernelBuffer& buffer, FileDescription*)
|
||||||
{
|
{
|
||||||
LOCKER(m_lock);
|
LOCKER(m_lock);
|
||||||
ASSERT(!is_directory());
|
ASSERT(!is_directory());
|
||||||
|
@ -199,7 +200,8 @@ ssize_t TmpFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, Fi
|
||||||
inode_size_changed(old_size, new_size);
|
inode_size_changed(old_size, new_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(m_content.value().data() + offset, buffer, size);
|
if (!buffer.read(m_content.value().data() + offset, size)) // TODO: partial reads?
|
||||||
|
return -EFAULT;
|
||||||
inode_contents_changed(offset, size, buffer);
|
inode_contents_changed(offset, size, buffer);
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
|
@ -343,8 +345,10 @@ KResult TmpFSInode::truncate(u64 size)
|
||||||
|
|
||||||
if (old_size != (size_t)size) {
|
if (old_size != (size_t)size) {
|
||||||
inode_size_changed(old_size, size);
|
inode_size_changed(old_size, size);
|
||||||
if (m_content.has_value())
|
if (m_content.has_value()) {
|
||||||
inode_contents_changed(0, size, m_content.value().data());
|
auto buffer = UserOrKernelBuffer::for_kernel_buffer(m_content.value().data());
|
||||||
|
inode_contents_changed(0, size, buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
|
|
|
@ -74,12 +74,12 @@ public:
|
||||||
const TmpFS& fs() const { return static_cast<const TmpFS&>(Inode::fs()); }
|
const TmpFS& fs() const { return static_cast<const TmpFS&>(Inode::fs()); }
|
||||||
|
|
||||||
// ^Inode
|
// ^Inode
|
||||||
virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override;
|
virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override;
|
||||||
virtual InodeMetadata metadata() const override;
|
virtual InodeMetadata metadata() const override;
|
||||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
|
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
|
||||||
virtual RefPtr<Inode> lookup(StringView name) override;
|
virtual RefPtr<Inode> lookup(StringView name) override;
|
||||||
virtual void flush_metadata() override;
|
virtual void flush_metadata() override;
|
||||||
virtual ssize_t write_bytes(off_t, ssize_t, const u8* buffer, FileDescription*) override;
|
virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& buffer, FileDescription*) override;
|
||||||
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
|
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
|
||||||
virtual KResult add_child(Inode&, const StringView& name, mode_t) override;
|
virtual KResult add_child(Inode&, const StringView& name, mode_t) override;
|
||||||
virtual KResult remove_child(const StringView& name) override;
|
virtual KResult remove_child(const StringView& name) override;
|
||||||
|
|
|
@ -707,7 +707,8 @@ KResult VFS::symlink(StringView target, StringView linkpath, Custody& base)
|
||||||
if (inode_or_error.is_error())
|
if (inode_or_error.is_error())
|
||||||
return inode_or_error.error();
|
return inode_or_error.error();
|
||||||
auto& inode = inode_or_error.value();
|
auto& inode = inode_or_error.value();
|
||||||
ssize_t nwritten = inode->write_bytes(0, target.length(), (const u8*)target.characters_without_null_termination(), nullptr);
|
auto target_buffer = UserOrKernelBuffer::for_kernel_buffer(const_cast<u8*>((const u8*)target.characters_without_null_termination()));
|
||||||
|
ssize_t nwritten = inode->write_bytes(0, target.length(), target_buffer, nullptr);
|
||||||
if (nwritten < 0)
|
if (nwritten < 0)
|
||||||
return KResult(nwritten);
|
return KResult(nwritten);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
|
|
|
@ -68,6 +68,7 @@ class TCPSocket;
|
||||||
class TTY;
|
class TTY;
|
||||||
class Thread;
|
class Thread;
|
||||||
class UDPSocket;
|
class UDPSocket;
|
||||||
|
class UserOrKernelBuffer;
|
||||||
class VFS;
|
class VFS;
|
||||||
class VMObject;
|
class VMObject;
|
||||||
class WaitQueue;
|
class WaitQueue;
|
||||||
|
|
|
@ -142,16 +142,22 @@ NEVER_INLINE static void dump_backtrace_impl(FlatPtr base_pointer, bool use_ksym
|
||||||
RecognizedSymbol recognized_symbols[max_recognized_symbol_count];
|
RecognizedSymbol recognized_symbols[max_recognized_symbol_count];
|
||||||
size_t recognized_symbol_count = 0;
|
size_t recognized_symbol_count = 0;
|
||||||
if (use_ksyms) {
|
if (use_ksyms) {
|
||||||
for (FlatPtr* stack_ptr = (FlatPtr*)base_pointer;
|
FlatPtr copied_stack_ptr[2];
|
||||||
(current_process ? current_process->validate_read_from_kernel(VirtualAddress(stack_ptr), sizeof(void*) * 2) : 1) && recognized_symbol_count < max_recognized_symbol_count; stack_ptr = (FlatPtr*)*stack_ptr) {
|
for (FlatPtr* stack_ptr = (FlatPtr*)base_pointer; stack_ptr && recognized_symbol_count < max_recognized_symbol_count; stack_ptr = (FlatPtr*)copied_stack_ptr[0]) {
|
||||||
FlatPtr retaddr = stack_ptr[1];
|
void* fault_at;
|
||||||
|
if (!safe_memcpy(copied_stack_ptr, stack_ptr, sizeof(copied_stack_ptr), fault_at))
|
||||||
|
break;
|
||||||
|
FlatPtr retaddr = copied_stack_ptr[1];
|
||||||
recognized_symbols[recognized_symbol_count++] = { retaddr, symbolicate_kernel_address(retaddr) };
|
recognized_symbols[recognized_symbol_count++] = { retaddr, symbolicate_kernel_address(retaddr) };
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (FlatPtr* stack_ptr = (FlatPtr*)base_pointer;
|
void* fault_at;
|
||||||
(current_process ? current_process->validate_read_from_kernel(VirtualAddress(stack_ptr), sizeof(void*) * 2) : 1); stack_ptr = (FlatPtr*)*stack_ptr) {
|
FlatPtr copied_stack_ptr[2];
|
||||||
FlatPtr retaddr = stack_ptr[1];
|
FlatPtr* stack_ptr = (FlatPtr*)base_pointer;
|
||||||
dbg() << String::format("%x", retaddr) << " (next: " << String::format("%x", (stack_ptr ? (u32*)*stack_ptr : 0)) << ")";
|
while (stack_ptr && safe_memcpy(copied_stack_ptr, stack_ptr, sizeof(copied_stack_ptr), fault_at)) {
|
||||||
|
FlatPtr retaddr = copied_stack_ptr[1];
|
||||||
|
dbg() << String::format("%x", retaddr) << " (next: " << String::format("%x", (stack_ptr ? (u32*)copied_stack_ptr[0] : 0)) << ")";
|
||||||
|
stack_ptr = (FlatPtr*)copied_stack_ptr[0];
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,8 @@ KResult IPv4Socket::bind(Userspace<const sockaddr*> user_address, socklen_t addr
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
|
|
||||||
sockaddr_in address;
|
sockaddr_in address;
|
||||||
copy_from_user(&address, user_address, sizeof(sockaddr_in));
|
if (!copy_from_user(&address, user_address, sizeof(sockaddr_in)))
|
||||||
|
return KResult(-EFAULT);
|
||||||
|
|
||||||
if (address.sin_family != AF_INET)
|
if (address.sin_family != AF_INET)
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
|
@ -144,18 +145,25 @@ KResult IPv4Socket::listen(size_t backlog)
|
||||||
return protocol_listen();
|
return protocol_listen();
|
||||||
}
|
}
|
||||||
|
|
||||||
KResult IPv4Socket::connect(FileDescription& description, const sockaddr* address, socklen_t address_size, ShouldBlock should_block)
|
KResult IPv4Socket::connect(FileDescription& description, Userspace<const sockaddr*> address, socklen_t address_size, ShouldBlock should_block)
|
||||||
{
|
{
|
||||||
if (address_size != sizeof(sockaddr_in))
|
if (address_size != sizeof(sockaddr_in))
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
if (address->sa_family != AF_INET)
|
u16 sa_family_copy;
|
||||||
|
auto* user_address = reinterpret_cast<const sockaddr*>(address.unsafe_userspace_ptr());
|
||||||
|
if (!copy_from_user(&sa_family_copy, &user_address->sa_family, sizeof(u16)))
|
||||||
|
return KResult(-EFAULT);
|
||||||
|
if (sa_family_copy != AF_INET)
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
if (m_role == Role::Connected)
|
if (m_role == Role::Connected)
|
||||||
return KResult(-EISCONN);
|
return KResult(-EISCONN);
|
||||||
|
|
||||||
auto& ia = *(const sockaddr_in*)address;
|
sockaddr_in safe_address;
|
||||||
m_peer_address = IPv4Address((const u8*)&ia.sin_addr.s_addr);
|
if (!copy_from_user(&safe_address, (const sockaddr_in*)user_address, sizeof(sockaddr_in)))
|
||||||
m_peer_port = ntohs(ia.sin_port);
|
return KResult(-EFAULT);
|
||||||
|
|
||||||
|
m_peer_address = IPv4Address((const u8*)&safe_address.sin_addr.s_addr);
|
||||||
|
m_peer_port = ntohs(safe_address.sin_port);
|
||||||
|
|
||||||
return protocol_connect(description, should_block);
|
return protocol_connect(description, should_block);
|
||||||
}
|
}
|
||||||
|
@ -193,7 +201,7 @@ int IPv4Socket::allocate_local_port_if_needed()
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> IPv4Socket::sendto(FileDescription&, const void* data, size_t data_length, int flags, Userspace<const sockaddr*> addr, socklen_t addr_length)
|
KResultOr<size_t> IPv4Socket::sendto(FileDescription&, const UserOrKernelBuffer& data, size_t data_length, int flags, Userspace<const sockaddr*> addr, socklen_t addr_length)
|
||||||
{
|
{
|
||||||
(void)flags;
|
(void)flags;
|
||||||
if (addr && addr_length != sizeof(sockaddr_in))
|
if (addr && addr_length != sizeof(sockaddr_in))
|
||||||
|
@ -201,7 +209,7 @@ KResultOr<size_t> IPv4Socket::sendto(FileDescription&, const void* data, size_t
|
||||||
|
|
||||||
if (addr) {
|
if (addr) {
|
||||||
sockaddr_in ia;
|
sockaddr_in ia;
|
||||||
if (!Process::current()->validate_read_and_copy_typed(&ia, Userspace<const sockaddr_in*>(addr.ptr())))
|
if (!copy_from_user(&ia, Userspace<const sockaddr_in*>(addr.ptr())))
|
||||||
return KResult(-EFAULT);
|
return KResult(-EFAULT);
|
||||||
|
|
||||||
if (ia.sin_family != AF_INET) {
|
if (ia.sin_family != AF_INET) {
|
||||||
|
@ -229,7 +237,9 @@ KResultOr<size_t> IPv4Socket::sendto(FileDescription&, const void* data, size_t
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (type() == SOCK_RAW) {
|
if (type() == SOCK_RAW) {
|
||||||
routing_decision.adapter->send_ipv4(routing_decision.next_hop, m_peer_address, (IPv4Protocol)protocol(), { (const u8*)data, data_length }, m_ttl);
|
int err = routing_decision.adapter->send_ipv4(routing_decision.next_hop, m_peer_address, (IPv4Protocol)protocol(), data, data_length, m_ttl);
|
||||||
|
if (err < 0)
|
||||||
|
return KResult(err);
|
||||||
return data_length;
|
return data_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,7 +249,7 @@ KResultOr<size_t> IPv4Socket::sendto(FileDescription&, const void* data, size_t
|
||||||
return nsent_or_error;
|
return nsent_or_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> IPv4Socket::receive_byte_buffered(FileDescription& description, void* buffer, size_t buffer_length, int, Userspace<sockaddr*>, Userspace<socklen_t*>)
|
KResultOr<size_t> IPv4Socket::receive_byte_buffered(FileDescription& description, UserOrKernelBuffer& buffer, size_t buffer_length, int, Userspace<sockaddr*>, Userspace<socklen_t*>)
|
||||||
{
|
{
|
||||||
Locker locker(lock());
|
Locker locker(lock());
|
||||||
if (m_receive_buffer.is_empty()) {
|
if (m_receive_buffer.is_empty()) {
|
||||||
|
@ -262,7 +272,7 @@ KResultOr<size_t> IPv4Socket::receive_byte_buffered(FileDescription& description
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(!m_receive_buffer.is_empty());
|
ASSERT(!m_receive_buffer.is_empty());
|
||||||
int nreceived = m_receive_buffer.read((u8*)buffer, buffer_length);
|
int nreceived = m_receive_buffer.read(buffer, buffer_length);
|
||||||
if (nreceived > 0)
|
if (nreceived > 0)
|
||||||
Thread::current()->did_ipv4_socket_read((size_t)nreceived);
|
Thread::current()->did_ipv4_socket_read((size_t)nreceived);
|
||||||
|
|
||||||
|
@ -270,7 +280,7 @@ KResultOr<size_t> IPv4Socket::receive_byte_buffered(FileDescription& description
|
||||||
return nreceived;
|
return nreceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> IPv4Socket::receive_packet_buffered(FileDescription& description, void* buffer, size_t buffer_length, int flags, Userspace<sockaddr*> addr, Userspace<socklen_t*> addr_length)
|
KResultOr<size_t> IPv4Socket::receive_packet_buffered(FileDescription& description, UserOrKernelBuffer& buffer, size_t buffer_length, int flags, Userspace<sockaddr*> addr, Userspace<socklen_t*> addr_length)
|
||||||
{
|
{
|
||||||
Locker locker(lock());
|
Locker locker(lock());
|
||||||
ReceivedPacket packet;
|
ReceivedPacket packet;
|
||||||
|
@ -330,27 +340,30 @@ KResultOr<size_t> IPv4Socket::receive_packet_buffered(FileDescription& descripti
|
||||||
out_addr.sin_port = htons(packet.peer_port);
|
out_addr.sin_port = htons(packet.peer_port);
|
||||||
out_addr.sin_family = AF_INET;
|
out_addr.sin_family = AF_INET;
|
||||||
Userspace<sockaddr_in*> dest_addr = addr.ptr();
|
Userspace<sockaddr_in*> dest_addr = addr.ptr();
|
||||||
copy_to_user(dest_addr, &out_addr);
|
if (!copy_to_user(dest_addr, &out_addr))
|
||||||
|
return KResult(-EFAULT);
|
||||||
|
|
||||||
socklen_t out_length = sizeof(sockaddr_in);
|
socklen_t out_length = sizeof(sockaddr_in);
|
||||||
ASSERT(addr_length);
|
ASSERT(addr_length);
|
||||||
copy_to_user(addr_length, &out_length);
|
if (!copy_to_user(addr_length, &out_length))
|
||||||
|
return KResult(-EFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type() == SOCK_RAW) {
|
if (type() == SOCK_RAW) {
|
||||||
size_t bytes_written = min((size_t) ipv4_packet.payload_size(), buffer_length);
|
size_t bytes_written = min((size_t) ipv4_packet.payload_size(), buffer_length);
|
||||||
memcpy(buffer, ipv4_packet.payload(), bytes_written);
|
if (!buffer.write(ipv4_packet.payload(), bytes_written))
|
||||||
|
return KResult(-EFAULT);
|
||||||
return bytes_written;
|
return bytes_written;
|
||||||
}
|
}
|
||||||
|
|
||||||
return protocol_receive(packet.data.value(), buffer, buffer_length, flags);
|
return protocol_receive(packet.data.value(), buffer, buffer_length, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> IPv4Socket::recvfrom(FileDescription& description, void* buffer, size_t buffer_length, int flags, Userspace<sockaddr*> user_addr, Userspace<socklen_t*> user_addr_length)
|
KResultOr<size_t> IPv4Socket::recvfrom(FileDescription& description, UserOrKernelBuffer& buffer, size_t buffer_length, int flags, Userspace<sockaddr*> user_addr, Userspace<socklen_t*> user_addr_length)
|
||||||
{
|
{
|
||||||
if (user_addr_length) {
|
if (user_addr_length) {
|
||||||
socklen_t addr_length;
|
socklen_t addr_length;
|
||||||
if (!Process::current()->validate_read_and_copy_typed(&addr_length, user_addr_length))
|
if (!copy_from_user(&addr_length, user_addr_length.unsafe_userspace_ptr()))
|
||||||
return KResult(-EFAULT);
|
return KResult(-EFAULT);
|
||||||
if (addr_length < sizeof(sockaddr_in))
|
if (addr_length < sizeof(sockaddr_in))
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
|
@ -387,10 +400,13 @@ bool IPv4Socket::did_receive(const IPv4Address& source_address, u16 source_port,
|
||||||
ASSERT(m_can_read);
|
ASSERT(m_can_read);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto nreceived_or_error = protocol_receive(packet, m_scratch_buffer.value().data(), m_scratch_buffer.value().size(), 0);
|
auto scratch_buffer = UserOrKernelBuffer::for_kernel_buffer(m_scratch_buffer.value().data());
|
||||||
|
auto nreceived_or_error = protocol_receive(packet, scratch_buffer, m_scratch_buffer.value().size(), 0);
|
||||||
if (nreceived_or_error.is_error())
|
if (nreceived_or_error.is_error())
|
||||||
return false;
|
return false;
|
||||||
m_receive_buffer.write(m_scratch_buffer.value().data(), nreceived_or_error.value());
|
ssize_t nwritten = m_receive_buffer.write(scratch_buffer, nreceived_or_error.value());
|
||||||
|
if (nwritten < 0)
|
||||||
|
return false;
|
||||||
m_can_read = !m_receive_buffer.is_empty();
|
m_can_read = !m_receive_buffer.is_empty();
|
||||||
} else {
|
} else {
|
||||||
if (m_receive_queue.size() > 2000) {
|
if (m_receive_queue.size() > 2000) {
|
||||||
|
@ -452,7 +468,7 @@ KResult IPv4Socket::setsockopt(int level, int option, Userspace<const void*> use
|
||||||
if (user_value_size < sizeof(int))
|
if (user_value_size < sizeof(int))
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
int value;
|
int value;
|
||||||
if (!Process::current()->validate_read_and_copy_typed(&value, static_ptr_cast<const int*>(user_value)))
|
if (!copy_from_user(&value, static_ptr_cast<const int*>(user_value)))
|
||||||
return KResult(-EFAULT);
|
return KResult(-EFAULT);
|
||||||
if (value < 0 || value > 255)
|
if (value < 0 || value > 255)
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
|
@ -470,16 +486,18 @@ KResult IPv4Socket::getsockopt(FileDescription& description, int level, int opti
|
||||||
return Socket::getsockopt(description, level, option, value, value_size);
|
return Socket::getsockopt(description, level, option, value, value_size);
|
||||||
|
|
||||||
socklen_t size;
|
socklen_t size;
|
||||||
if (!Process::current()->validate_read_and_copy_typed(&size, value_size))
|
if (!copy_from_user(&size, value_size.unsafe_userspace_ptr()))
|
||||||
return KResult(-EFAULT);
|
return KResult(-EFAULT);
|
||||||
|
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case IP_TTL:
|
case IP_TTL:
|
||||||
if (size < sizeof(int))
|
if (size < sizeof(int))
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
copy_to_user(static_ptr_cast<int*>(value), (int*)&m_ttl);
|
if (!copy_to_user(static_ptr_cast<int*>(value), (int*)&m_ttl))
|
||||||
|
return KResult(-EFAULT);
|
||||||
size = sizeof(int);
|
size = sizeof(int);
|
||||||
copy_to_user(value_size, &size);
|
if (!copy_to_user(value_size, &size))
|
||||||
|
return KResult(-EFAULT);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
default:
|
default:
|
||||||
return KResult(-ENOPROTOOPT);
|
return KResult(-ENOPROTOOPT);
|
||||||
|
@ -493,15 +511,15 @@ int IPv4Socket::ioctl(FileDescription&, unsigned request, FlatPtr arg)
|
||||||
SmapDisabler disabler;
|
SmapDisabler disabler;
|
||||||
|
|
||||||
auto ioctl_route = [request, arg]() {
|
auto ioctl_route = [request, arg]() {
|
||||||
auto* route = (rtentry*)arg;
|
rtentry route;
|
||||||
if (!Process::current()->validate_read_typed(route))
|
if (!copy_from_user(&route, (rtentry*)arg))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
char namebuf[IFNAMSIZ + 1];
|
auto copied_ifname = copy_string_from_user(route.rt_dev, IFNAMSIZ);
|
||||||
memcpy(namebuf, route->rt_dev, IFNAMSIZ);
|
if (copied_ifname.is_null())
|
||||||
namebuf[sizeof(namebuf) - 1] = '\0';
|
return -EFAULT;
|
||||||
|
|
||||||
auto adapter = NetworkAdapter::lookup_by_name(namebuf);
|
auto adapter = NetworkAdapter::lookup_by_name(copied_ifname);
|
||||||
if (!adapter)
|
if (!adapter)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
@ -509,11 +527,11 @@ int IPv4Socket::ioctl(FileDescription&, unsigned request, FlatPtr arg)
|
||||||
case SIOCADDRT:
|
case SIOCADDRT:
|
||||||
if (!Process::current()->is_superuser())
|
if (!Process::current()->is_superuser())
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
if (route->rt_gateway.sa_family != AF_INET)
|
if (route.rt_gateway.sa_family != AF_INET)
|
||||||
return -EAFNOSUPPORT;
|
return -EAFNOSUPPORT;
|
||||||
if ((route->rt_flags & (RTF_UP | RTF_GATEWAY)) != (RTF_UP | RTF_GATEWAY))
|
if ((route.rt_flags & (RTF_UP | RTF_GATEWAY)) != (RTF_UP | RTF_GATEWAY))
|
||||||
return -EINVAL; // FIXME: Find the correct value to return
|
return -EINVAL; // FIXME: Find the correct value to return
|
||||||
adapter->set_ipv4_gateway(IPv4Address(((sockaddr_in&)route->rt_gateway).sin_addr.s_addr));
|
adapter->set_ipv4_gateway(IPv4Address(((sockaddr_in&)route.rt_gateway).sin_addr.s_addr));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case SIOCDELRT:
|
case SIOCDELRT:
|
||||||
|
@ -525,12 +543,13 @@ int IPv4Socket::ioctl(FileDescription&, unsigned request, FlatPtr arg)
|
||||||
};
|
};
|
||||||
|
|
||||||
auto ioctl_interface = [request, arg]() {
|
auto ioctl_interface = [request, arg]() {
|
||||||
auto* ifr = (ifreq*)arg;
|
ifreq* user_ifr = (ifreq*)arg;
|
||||||
if (!Process::current()->validate_read_typed(ifr))
|
ifreq ifr;
|
||||||
|
if (!copy_from_user(&ifr, user_ifr))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
char namebuf[IFNAMSIZ + 1];
|
char namebuf[IFNAMSIZ + 1];
|
||||||
memcpy(namebuf, ifr->ifr_name, IFNAMSIZ);
|
memcpy(namebuf, ifr.ifr_name, IFNAMSIZ);
|
||||||
namebuf[sizeof(namebuf) - 1] = '\0';
|
namebuf[sizeof(namebuf) - 1] = '\0';
|
||||||
|
|
||||||
auto adapter = NetworkAdapter::lookup_by_name(namebuf);
|
auto adapter = NetworkAdapter::lookup_by_name(namebuf);
|
||||||
|
@ -541,36 +560,39 @@ int IPv4Socket::ioctl(FileDescription&, unsigned request, FlatPtr arg)
|
||||||
case SIOCSIFADDR:
|
case SIOCSIFADDR:
|
||||||
if (!Process::current()->is_superuser())
|
if (!Process::current()->is_superuser())
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
if (ifr->ifr_addr.sa_family != AF_INET)
|
if (ifr.ifr_addr.sa_family != AF_INET)
|
||||||
return -EAFNOSUPPORT;
|
return -EAFNOSUPPORT;
|
||||||
adapter->set_ipv4_address(IPv4Address(((sockaddr_in&)ifr->ifr_addr).sin_addr.s_addr));
|
adapter->set_ipv4_address(IPv4Address(((sockaddr_in&)ifr.ifr_addr).sin_addr.s_addr));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case SIOCSIFNETMASK:
|
case SIOCSIFNETMASK:
|
||||||
if (!Process::current()->is_superuser())
|
if (!Process::current()->is_superuser())
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
if (ifr->ifr_addr.sa_family != AF_INET)
|
if (ifr.ifr_addr.sa_family != AF_INET)
|
||||||
return -EAFNOSUPPORT;
|
return -EAFNOSUPPORT;
|
||||||
adapter->set_ipv4_netmask(IPv4Address(((sockaddr_in&)ifr->ifr_netmask).sin_addr.s_addr));
|
adapter->set_ipv4_netmask(IPv4Address(((sockaddr_in&)ifr.ifr_netmask).sin_addr.s_addr));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case SIOCGIFADDR:
|
case SIOCGIFADDR: {
|
||||||
if (!Process::current()->validate_write_typed(ifr))
|
u16 sa_family = AF_INET;
|
||||||
|
if (!copy_to_user(&user_ifr->ifr_addr.sa_family, &sa_family))
|
||||||
|
return -EFAULT;
|
||||||
|
auto ip4_addr = adapter->ipv4_address().to_u32();
|
||||||
|
if (!copy_to_user(&((sockaddr_in&)user_ifr->ifr_addr).sin_addr.s_addr, &ip4_addr, sizeof(ip4_addr)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
ifr->ifr_addr.sa_family = AF_INET;
|
|
||||||
((sockaddr_in&)ifr->ifr_addr).sin_addr.s_addr = adapter->ipv4_address().to_u32();
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
case SIOCGIFHWADDR:
|
case SIOCGIFHWADDR: {
|
||||||
if (!Process::current()->validate_write_typed(ifr))
|
u16 sa_family = AF_INET;
|
||||||
|
if (!copy_to_user(&user_ifr->ifr_hwaddr.sa_family, &sa_family))
|
||||||
|
return -EFAULT;
|
||||||
|
auto mac_address = adapter->mac_address();
|
||||||
|
if (!copy_to_user(ifr.ifr_hwaddr.sa_data, &mac_address, sizeof(MACAddress)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
ifr->ifr_hwaddr.sa_family = AF_INET;
|
|
||||||
{
|
|
||||||
auto mac_address = adapter->mac_address();
|
|
||||||
memcpy(ifr->ifr_hwaddr.sa_data, &mac_address, sizeof(MACAddress));
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
};
|
};
|
||||||
|
|
|
@ -50,7 +50,7 @@ public:
|
||||||
|
|
||||||
virtual KResult close() override;
|
virtual KResult close() override;
|
||||||
virtual KResult bind(Userspace<const sockaddr*>, socklen_t) override;
|
virtual KResult bind(Userspace<const sockaddr*>, socklen_t) override;
|
||||||
virtual KResult connect(FileDescription&, const sockaddr*, socklen_t, ShouldBlock = ShouldBlock::Yes) override;
|
virtual KResult connect(FileDescription&, Userspace<const sockaddr*>, socklen_t, ShouldBlock = ShouldBlock::Yes) override;
|
||||||
virtual KResult listen(size_t) override;
|
virtual KResult listen(size_t) override;
|
||||||
virtual void get_local_address(sockaddr*, socklen_t*) override;
|
virtual void get_local_address(sockaddr*, socklen_t*) override;
|
||||||
virtual void get_peer_address(sockaddr*, socklen_t*) override;
|
virtual void get_peer_address(sockaddr*, socklen_t*) override;
|
||||||
|
@ -58,8 +58,8 @@ public:
|
||||||
virtual void detach(FileDescription&) override;
|
virtual void detach(FileDescription&) override;
|
||||||
virtual bool can_read(const FileDescription&, size_t) const override;
|
virtual bool can_read(const FileDescription&, size_t) const override;
|
||||||
virtual bool can_write(const FileDescription&, size_t) const override;
|
virtual bool can_write(const FileDescription&, size_t) const override;
|
||||||
virtual KResultOr<size_t> sendto(FileDescription&, const void*, size_t, int, Userspace<const sockaddr*>, socklen_t) override;
|
virtual KResultOr<size_t> sendto(FileDescription&, const UserOrKernelBuffer&, size_t, int, Userspace<const sockaddr*>, socklen_t) override;
|
||||||
virtual KResultOr<size_t> recvfrom(FileDescription&, void*, size_t, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>) override;
|
virtual KResultOr<size_t> recvfrom(FileDescription&, UserOrKernelBuffer&, size_t, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>) override;
|
||||||
virtual KResult setsockopt(int level, int option, Userspace<const void*>, socklen_t) override;
|
virtual KResult setsockopt(int level, int option, Userspace<const void*>, socklen_t) override;
|
||||||
virtual KResult getsockopt(FileDescription&, int level, int option, Userspace<void*>, Userspace<socklen_t*>) override;
|
virtual KResult getsockopt(FileDescription&, int level, int option, Userspace<void*>, Userspace<socklen_t*>) override;
|
||||||
|
|
||||||
|
@ -96,8 +96,8 @@ protected:
|
||||||
|
|
||||||
virtual KResult protocol_bind() { return KSuccess; }
|
virtual KResult protocol_bind() { return KSuccess; }
|
||||||
virtual KResult protocol_listen() { return KSuccess; }
|
virtual KResult protocol_listen() { return KSuccess; }
|
||||||
virtual KResultOr<size_t> protocol_receive(const KBuffer&, void*, size_t, int) { return -ENOTIMPL; }
|
virtual KResultOr<size_t> protocol_receive(const KBuffer&, UserOrKernelBuffer&, size_t, int) { return -ENOTIMPL; }
|
||||||
virtual KResultOr<size_t> protocol_send(const void*, size_t) { return -ENOTIMPL; }
|
virtual KResultOr<size_t> protocol_send(const UserOrKernelBuffer&, size_t) { return -ENOTIMPL; }
|
||||||
virtual KResult protocol_connect(FileDescription&, ShouldBlock) { return KSuccess; }
|
virtual KResult protocol_connect(FileDescription&, ShouldBlock) { return KSuccess; }
|
||||||
virtual int protocol_allocate_local_port() { return 0; }
|
virtual int protocol_allocate_local_port() { return 0; }
|
||||||
virtual bool protocol_is_disconnected() const { return false; }
|
virtual bool protocol_is_disconnected() const { return false; }
|
||||||
|
@ -110,8 +110,8 @@ protected:
|
||||||
private:
|
private:
|
||||||
virtual bool is_ipv4() const override { return true; }
|
virtual bool is_ipv4() const override { return true; }
|
||||||
|
|
||||||
KResultOr<size_t> receive_byte_buffered(FileDescription&, void* buffer, size_t buffer_length, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>);
|
KResultOr<size_t> receive_byte_buffered(FileDescription&, UserOrKernelBuffer& buffer, size_t buffer_length, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>);
|
||||||
KResultOr<size_t> receive_packet_buffered(FileDescription&, void* buffer, size_t buffer_length, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>);
|
KResultOr<size_t> receive_packet_buffered(FileDescription&, UserOrKernelBuffer& buffer, size_t buffer_length, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>);
|
||||||
|
|
||||||
IPv4Address m_local_address;
|
IPv4Address m_local_address;
|
||||||
IPv4Address m_peer_address;
|
IPv4Address m_peer_address;
|
||||||
|
|
|
@ -98,7 +98,8 @@ KResult LocalSocket::bind(Userspace<const sockaddr*> user_address, socklen_t add
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
|
|
||||||
sockaddr_un address;
|
sockaddr_un address;
|
||||||
copy_from_user(&address, user_address, sizeof(sockaddr_un));
|
if (!copy_from_user(&address, user_address, sizeof(sockaddr_un)))
|
||||||
|
return KResult(-EFAULT);
|
||||||
|
|
||||||
if (address.sun_family != AF_LOCAL)
|
if (address.sun_family != AF_LOCAL)
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
|
@ -131,19 +132,25 @@ KResult LocalSocket::bind(Userspace<const sockaddr*> user_address, socklen_t add
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
KResult LocalSocket::connect(FileDescription& description, const sockaddr* address, socklen_t address_size, ShouldBlock)
|
KResult LocalSocket::connect(FileDescription& description, Userspace<const sockaddr*> address, socklen_t address_size, ShouldBlock)
|
||||||
{
|
{
|
||||||
ASSERT(!m_bound);
|
ASSERT(!m_bound);
|
||||||
if (address_size != sizeof(sockaddr_un))
|
if (address_size != sizeof(sockaddr_un))
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
if (address->sa_family != AF_LOCAL)
|
u16 sa_family_copy;
|
||||||
|
auto* user_address = reinterpret_cast<const sockaddr*>(address.unsafe_userspace_ptr());
|
||||||
|
if (!copy_from_user(&sa_family_copy, &user_address->sa_family, sizeof(u16)))
|
||||||
|
return KResult(-EFAULT);
|
||||||
|
if (sa_family_copy != AF_LOCAL)
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
if (is_connected())
|
if (is_connected())
|
||||||
return KResult(-EISCONN);
|
return KResult(-EISCONN);
|
||||||
|
|
||||||
const sockaddr_un& local_address = *reinterpret_cast<const sockaddr_un*>(address);
|
const auto& local_address = *reinterpret_cast<const sockaddr_un*>(user_address);
|
||||||
char safe_address[sizeof(local_address.sun_path) + 1] = { 0 };
|
char safe_address[sizeof(local_address.sun_path) + 1] = { 0 };
|
||||||
memcpy(safe_address, local_address.sun_path, sizeof(local_address.sun_path));
|
if (!copy_from_user(&safe_address[0], &local_address.sun_path[0], sizeof(safe_address) - 1))
|
||||||
|
return KResult(-EFAULT);
|
||||||
|
safe_address[sizeof(safe_address) - 1] = '\0';
|
||||||
|
|
||||||
#ifdef DEBUG_LOCAL_SOCKET
|
#ifdef DEBUG_LOCAL_SOCKET
|
||||||
dbg() << "LocalSocket{" << this << "} connect(" << safe_address << ")";
|
dbg() << "LocalSocket{" << this << "} connect(" << safe_address << ")";
|
||||||
|
@ -159,7 +166,8 @@ KResult LocalSocket::connect(FileDescription& description, const sockaddr* addre
|
||||||
if (!m_file->inode()->socket())
|
if (!m_file->inode()->socket())
|
||||||
return KResult(-ECONNREFUSED);
|
return KResult(-ECONNREFUSED);
|
||||||
|
|
||||||
m_address = local_address;
|
m_address.sun_family = sa_family_copy;
|
||||||
|
memcpy(m_address.sun_path, safe_address, sizeof(m_address.sun_path));
|
||||||
|
|
||||||
ASSERT(m_connect_side_fd == &description);
|
ASSERT(m_connect_side_fd == &description);
|
||||||
m_connect_side_role = Role::Connecting;
|
m_connect_side_role = Role::Connecting;
|
||||||
|
@ -260,11 +268,11 @@ bool LocalSocket::can_write(const FileDescription& description, size_t) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> LocalSocket::sendto(FileDescription& description, const void* data, size_t data_size, int, Userspace<const sockaddr*>, socklen_t)
|
KResultOr<size_t> LocalSocket::sendto(FileDescription& description, const UserOrKernelBuffer& data, size_t data_size, int, Userspace<const sockaddr*>, socklen_t)
|
||||||
{
|
{
|
||||||
if (!has_attached_peer(description))
|
if (!has_attached_peer(description))
|
||||||
return KResult(-EPIPE);
|
return KResult(-EPIPE);
|
||||||
ssize_t nwritten = send_buffer_for(description).write((const u8*)data, data_size);
|
ssize_t nwritten = send_buffer_for(description).write(data, data_size);
|
||||||
if (nwritten > 0)
|
if (nwritten > 0)
|
||||||
Thread::current()->did_unix_socket_write(nwritten);
|
Thread::current()->did_unix_socket_write(nwritten);
|
||||||
return nwritten;
|
return nwritten;
|
||||||
|
@ -290,7 +298,7 @@ DoubleBuffer& LocalSocket::send_buffer_for(FileDescription& description)
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> LocalSocket::recvfrom(FileDescription& description, void* buffer, size_t buffer_size, int, Userspace<sockaddr*>, Userspace<socklen_t*>)
|
KResultOr<size_t> LocalSocket::recvfrom(FileDescription& description, UserOrKernelBuffer& buffer, size_t buffer_size, int, Userspace<sockaddr*>, Userspace<socklen_t*>)
|
||||||
{
|
{
|
||||||
auto& buffer_for_me = receive_buffer_for(description);
|
auto& buffer_for_me = receive_buffer_for(description);
|
||||||
if (!description.is_blocking()) {
|
if (!description.is_blocking()) {
|
||||||
|
@ -306,7 +314,7 @@ KResultOr<size_t> LocalSocket::recvfrom(FileDescription& description, void* buff
|
||||||
if (!has_attached_peer(description) && buffer_for_me.is_empty())
|
if (!has_attached_peer(description) && buffer_for_me.is_empty())
|
||||||
return 0;
|
return 0;
|
||||||
ASSERT(!buffer_for_me.is_empty());
|
ASSERT(!buffer_for_me.is_empty());
|
||||||
int nread = buffer_for_me.read((u8*)buffer, buffer_size);
|
int nread = buffer_for_me.read(buffer, buffer_size);
|
||||||
if (nread > 0)
|
if (nread > 0)
|
||||||
Thread::current()->did_unix_socket_read(nread);
|
Thread::current()->did_unix_socket_read(nread);
|
||||||
return nread;
|
return nread;
|
||||||
|
@ -350,7 +358,7 @@ KResult LocalSocket::getsockopt(FileDescription& description, int level, int opt
|
||||||
return Socket::getsockopt(description, level, option, value, value_size);
|
return Socket::getsockopt(description, level, option, value, value_size);
|
||||||
|
|
||||||
socklen_t size;
|
socklen_t size;
|
||||||
if (!Process::current()->validate_read_and_copy_typed(&size, value_size))
|
if (!copy_from_user(&size, value_size.unsafe_userspace_ptr()))
|
||||||
return KResult(-EFAULT);
|
return KResult(-EFAULT);
|
||||||
|
|
||||||
switch (option) {
|
switch (option) {
|
||||||
|
@ -359,14 +367,18 @@ KResult LocalSocket::getsockopt(FileDescription& description, int level, int opt
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
switch (role(description)) {
|
switch (role(description)) {
|
||||||
case Role::Accepted:
|
case Role::Accepted:
|
||||||
copy_to_user(static_ptr_cast<ucred*>(value), &m_origin);
|
if (!copy_to_user(static_ptr_cast<ucred*>(value), &m_origin))
|
||||||
|
return KResult(-EFAULT);
|
||||||
size = sizeof(ucred);
|
size = sizeof(ucred);
|
||||||
copy_to_user(value_size, &size);
|
if (!copy_to_user(value_size, &size))
|
||||||
|
return KResult(-EFAULT);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
case Role::Connected:
|
case Role::Connected:
|
||||||
copy_to_user(static_ptr_cast<ucred*>(value), &m_acceptor);
|
if (!copy_to_user(static_ptr_cast<ucred*>(value), &m_acceptor))
|
||||||
|
return KResult(-EFAULT);
|
||||||
size = sizeof(ucred);
|
size = sizeof(ucred);
|
||||||
copy_to_user(value_size, &size);
|
if (!copy_to_user(value_size, &size))
|
||||||
|
return KResult(-EFAULT);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
case Role::Connecting:
|
case Role::Connecting:
|
||||||
return KResult(-ENOTCONN);
|
return KResult(-ENOTCONN);
|
||||||
|
|
|
@ -52,7 +52,7 @@ public:
|
||||||
|
|
||||||
// ^Socket
|
// ^Socket
|
||||||
virtual KResult bind(Userspace<const sockaddr*>, socklen_t) override;
|
virtual KResult bind(Userspace<const sockaddr*>, socklen_t) override;
|
||||||
virtual KResult connect(FileDescription&, const sockaddr*, socklen_t, ShouldBlock = ShouldBlock::Yes) override;
|
virtual KResult connect(FileDescription&, Userspace<const sockaddr*>, socklen_t, ShouldBlock = ShouldBlock::Yes) override;
|
||||||
virtual KResult listen(size_t) override;
|
virtual KResult listen(size_t) override;
|
||||||
virtual void get_local_address(sockaddr*, socklen_t*) override;
|
virtual void get_local_address(sockaddr*, socklen_t*) override;
|
||||||
virtual void get_peer_address(sockaddr*, socklen_t*) override;
|
virtual void get_peer_address(sockaddr*, socklen_t*) override;
|
||||||
|
@ -60,8 +60,8 @@ public:
|
||||||
virtual void detach(FileDescription&) override;
|
virtual void detach(FileDescription&) override;
|
||||||
virtual bool can_read(const FileDescription&, size_t) const override;
|
virtual bool can_read(const FileDescription&, size_t) const override;
|
||||||
virtual bool can_write(const FileDescription&, size_t) const override;
|
virtual bool can_write(const FileDescription&, size_t) const override;
|
||||||
virtual KResultOr<size_t> sendto(FileDescription&, const void*, size_t, int, Userspace<const sockaddr*>, socklen_t) override;
|
virtual KResultOr<size_t> sendto(FileDescription&, const UserOrKernelBuffer&, size_t, int, Userspace<const sockaddr*>, socklen_t) override;
|
||||||
virtual KResultOr<size_t> recvfrom(FileDescription&, void*, size_t, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>) override;
|
virtual KResultOr<size_t> recvfrom(FileDescription&, UserOrKernelBuffer&, size_t, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>) override;
|
||||||
virtual KResult getsockopt(FileDescription&, int level, int option, Userspace<void*>, Userspace<socklen_t*>) override;
|
virtual KResult getsockopt(FileDescription&, int level, int option, Userspace<void*>, Userspace<socklen_t*>) override;
|
||||||
virtual KResult chown(FileDescription&, uid_t, gid_t) override;
|
virtual KResult chown(FileDescription&, uid_t, gid_t) override;
|
||||||
virtual KResult chmod(FileDescription&, mode_t) override;
|
virtual KResult chmod(FileDescription&, mode_t) override;
|
||||||
|
|
|
@ -100,15 +100,13 @@ void NetworkAdapter::send(const MACAddress& destination, const ARPPacket& packet
|
||||||
send_raw({ (const u8*)eth, size_in_bytes });
|
send_raw({ (const u8*)eth, size_in_bytes });
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkAdapter::send_ipv4(const MACAddress& destination_mac, const IPv4Address& destination_ipv4, IPv4Protocol protocol, ReadonlyBytes payload, u8 ttl)
|
int NetworkAdapter::send_ipv4(const MACAddress& destination_mac, const IPv4Address& destination_ipv4, IPv4Protocol protocol, const UserOrKernelBuffer& payload, size_t payload_size, u8 ttl)
|
||||||
{
|
{
|
||||||
size_t ipv4_packet_size = sizeof(IPv4Packet) + payload.size();
|
size_t ipv4_packet_size = sizeof(IPv4Packet) + payload_size;
|
||||||
if (ipv4_packet_size > mtu()) {
|
if (ipv4_packet_size > mtu())
|
||||||
send_ipv4_fragmented(destination_mac, destination_ipv4, protocol, payload, ttl);
|
return send_ipv4_fragmented(destination_mac, destination_ipv4, protocol, payload, payload_size, ttl);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ethernet_frame_size = sizeof(EthernetFrameHeader) + sizeof(IPv4Packet) + payload.size();
|
size_t ethernet_frame_size = sizeof(EthernetFrameHeader) + sizeof(IPv4Packet) + payload_size;
|
||||||
auto buffer = ByteBuffer::create_zeroed(ethernet_frame_size);
|
auto buffer = ByteBuffer::create_zeroed(ethernet_frame_size);
|
||||||
auto& eth = *(EthernetFrameHeader*)buffer.data();
|
auto& eth = *(EthernetFrameHeader*)buffer.data();
|
||||||
eth.set_source(mac_address());
|
eth.set_source(mac_address());
|
||||||
|
@ -120,22 +118,25 @@ void NetworkAdapter::send_ipv4(const MACAddress& destination_mac, const IPv4Addr
|
||||||
ipv4.set_source(ipv4_address());
|
ipv4.set_source(ipv4_address());
|
||||||
ipv4.set_destination(destination_ipv4);
|
ipv4.set_destination(destination_ipv4);
|
||||||
ipv4.set_protocol((u8)protocol);
|
ipv4.set_protocol((u8)protocol);
|
||||||
ipv4.set_length(sizeof(IPv4Packet) + payload.size());
|
ipv4.set_length(sizeof(IPv4Packet) + payload_size);
|
||||||
ipv4.set_ident(1);
|
ipv4.set_ident(1);
|
||||||
ipv4.set_ttl(ttl);
|
ipv4.set_ttl(ttl);
|
||||||
ipv4.set_checksum(ipv4.compute_checksum());
|
ipv4.set_checksum(ipv4.compute_checksum());
|
||||||
m_packets_out++;
|
m_packets_out++;
|
||||||
m_bytes_out += ethernet_frame_size;
|
m_bytes_out += ethernet_frame_size;
|
||||||
memcpy(ipv4.payload(), payload.data(), payload.size());
|
|
||||||
|
if (!payload.read(ipv4.payload(), payload_size))
|
||||||
|
return -EFAULT;
|
||||||
send_raw({ (const u8*)ð, ethernet_frame_size });
|
send_raw({ (const u8*)ð, ethernet_frame_size });
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkAdapter::send_ipv4_fragmented(const MACAddress& destination_mac, const IPv4Address& destination_ipv4, IPv4Protocol protocol, ReadonlyBytes payload, u8 ttl)
|
int NetworkAdapter::send_ipv4_fragmented(const MACAddress& destination_mac, const IPv4Address& destination_ipv4, IPv4Protocol protocol, const UserOrKernelBuffer& payload, size_t payload_size, u8 ttl)
|
||||||
{
|
{
|
||||||
// packets must be split on the 64-bit boundary
|
// packets must be split on the 64-bit boundary
|
||||||
auto packet_boundary_size = (mtu() - sizeof(IPv4Packet) - sizeof(EthernetFrameHeader)) & 0xfffffff8;
|
auto packet_boundary_size = (mtu() - sizeof(IPv4Packet) - sizeof(EthernetFrameHeader)) & 0xfffffff8;
|
||||||
auto fragment_block_count = (payload.size() + packet_boundary_size) / packet_boundary_size;
|
auto fragment_block_count = (payload_size + packet_boundary_size) / packet_boundary_size;
|
||||||
auto last_block_size = payload.size() - packet_boundary_size * (fragment_block_count - 1);
|
auto last_block_size = payload_size - packet_boundary_size * (fragment_block_count - 1);
|
||||||
auto number_of_blocks_in_fragment = packet_boundary_size / 8;
|
auto number_of_blocks_in_fragment = packet_boundary_size / 8;
|
||||||
|
|
||||||
auto identification = get_good_random<u16>();
|
auto identification = get_good_random<u16>();
|
||||||
|
@ -163,9 +164,11 @@ void NetworkAdapter::send_ipv4_fragmented(const MACAddress& destination_mac, con
|
||||||
ipv4.set_checksum(ipv4.compute_checksum());
|
ipv4.set_checksum(ipv4.compute_checksum());
|
||||||
m_packets_out++;
|
m_packets_out++;
|
||||||
m_bytes_out += ethernet_frame_size;
|
m_bytes_out += ethernet_frame_size;
|
||||||
memcpy(ipv4.payload(), payload.data() + packet_index * packet_boundary_size, packet_payload_size);
|
if (!payload.read(ipv4.payload(), packet_index * packet_boundary_size, packet_payload_size))
|
||||||
|
return -EFAULT;
|
||||||
send_raw({ (const u8*)ð, ethernet_frame_size });
|
send_raw({ (const u8*)ð, ethernet_frame_size });
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkAdapter::did_receive(ReadonlyBytes payload)
|
void NetworkAdapter::did_receive(ReadonlyBytes payload)
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include <Kernel/Net/ARP.h>
|
#include <Kernel/Net/ARP.h>
|
||||||
#include <Kernel/Net/ICMP.h>
|
#include <Kernel/Net/ICMP.h>
|
||||||
#include <Kernel/Net/IPv4.h>
|
#include <Kernel/Net/IPv4.h>
|
||||||
|
#include <Kernel/UserOrKernelBuffer.h>
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
@ -63,8 +64,8 @@ public:
|
||||||
void set_ipv4_gateway(const IPv4Address&);
|
void set_ipv4_gateway(const IPv4Address&);
|
||||||
|
|
||||||
void send(const MACAddress&, const ARPPacket&);
|
void send(const MACAddress&, const ARPPacket&);
|
||||||
void send_ipv4(const MACAddress&, const IPv4Address&, IPv4Protocol, ReadonlyBytes payload, u8 ttl);
|
int send_ipv4(const MACAddress&, const IPv4Address&, IPv4Protocol, const UserOrKernelBuffer& payload, size_t payload_size, u8 ttl);
|
||||||
void send_ipv4_fragmented(const MACAddress&, const IPv4Address&, IPv4Protocol, ReadonlyBytes payload, u8 ttl);
|
int send_ipv4_fragmented(const MACAddress&, const IPv4Address&, IPv4Protocol, const UserOrKernelBuffer& payload, size_t payload_size, u8 ttl);
|
||||||
|
|
||||||
size_t dequeue_packet(u8* buffer, size_t buffer_size);
|
size_t dequeue_packet(u8* buffer, size_t buffer_size);
|
||||||
|
|
||||||
|
|
|
@ -285,7 +285,8 @@ void handle_icmp(const EthernetFrameHeader& eth, const IPv4Packet& ipv4_packet)
|
||||||
memcpy(response.payload(), request.payload(), icmp_payload_size);
|
memcpy(response.payload(), request.payload(), icmp_payload_size);
|
||||||
response.header.set_checksum(internet_checksum(&response, icmp_packet_size));
|
response.header.set_checksum(internet_checksum(&response, icmp_packet_size));
|
||||||
// FIXME: What is the right TTL value here? Is 64 ok? Should we use the same TTL as the echo request?
|
// FIXME: What is the right TTL value here? Is 64 ok? Should we use the same TTL as the echo request?
|
||||||
adapter->send_ipv4(eth.source(), ipv4_packet.source(), IPv4Protocol::ICMP, buffer, 64);
|
auto response_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&response);
|
||||||
|
adapter->send_ipv4(eth.source(), ipv4_packet.source(), IPv4Protocol::ICMP, response_buffer, buffer.size(), 64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,7 +380,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
|
||||||
return;
|
return;
|
||||||
case TCPSocket::State::TimeWait:
|
case TCPSocket::State::TimeWait:
|
||||||
klog() << "handle_tcp: unexpected flags in TimeWait state";
|
klog() << "handle_tcp: unexpected flags in TimeWait state";
|
||||||
socket->send_tcp_packet(TCPFlags::RST);
|
(void)socket->send_tcp_packet(TCPFlags::RST);
|
||||||
socket->set_state(TCPSocket::State::Closed);
|
socket->set_state(TCPSocket::State::Closed);
|
||||||
return;
|
return;
|
||||||
case TCPSocket::State::Listen:
|
case TCPSocket::State::Listen:
|
||||||
|
@ -400,46 +401,46 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
|
||||||
#endif
|
#endif
|
||||||
client->set_sequence_number(1000);
|
client->set_sequence_number(1000);
|
||||||
client->set_ack_number(tcp_packet.sequence_number() + payload_size + 1);
|
client->set_ack_number(tcp_packet.sequence_number() + payload_size + 1);
|
||||||
client->send_tcp_packet(TCPFlags::SYN | TCPFlags::ACK);
|
(void)client->send_tcp_packet(TCPFlags::SYN | TCPFlags::ACK);
|
||||||
client->set_state(TCPSocket::State::SynReceived);
|
client->set_state(TCPSocket::State::SynReceived);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
klog() << "handle_tcp: unexpected flags in Listen state";
|
klog() << "handle_tcp: unexpected flags in Listen state";
|
||||||
// socket->send_tcp_packet(TCPFlags::RST);
|
// (void)socket->send_tcp_packet(TCPFlags::RST);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case TCPSocket::State::SynSent:
|
case TCPSocket::State::SynSent:
|
||||||
switch (tcp_packet.flags()) {
|
switch (tcp_packet.flags()) {
|
||||||
case TCPFlags::SYN:
|
case TCPFlags::SYN:
|
||||||
socket->set_ack_number(tcp_packet.sequence_number() + payload_size + 1);
|
socket->set_ack_number(tcp_packet.sequence_number() + payload_size + 1);
|
||||||
socket->send_tcp_packet(TCPFlags::ACK);
|
(void)socket->send_tcp_packet(TCPFlags::ACK);
|
||||||
socket->set_state(TCPSocket::State::SynReceived);
|
socket->set_state(TCPSocket::State::SynReceived);
|
||||||
return;
|
return;
|
||||||
case TCPFlags::ACK | TCPFlags::SYN:
|
case TCPFlags::ACK | TCPFlags::SYN:
|
||||||
socket->set_ack_number(tcp_packet.sequence_number() + payload_size + 1);
|
socket->set_ack_number(tcp_packet.sequence_number() + payload_size + 1);
|
||||||
socket->send_tcp_packet(TCPFlags::ACK);
|
(void)socket->send_tcp_packet(TCPFlags::ACK);
|
||||||
socket->set_state(TCPSocket::State::Established);
|
socket->set_state(TCPSocket::State::Established);
|
||||||
socket->set_setup_state(Socket::SetupState::Completed);
|
socket->set_setup_state(Socket::SetupState::Completed);
|
||||||
socket->set_connected(true);
|
socket->set_connected(true);
|
||||||
return;
|
return;
|
||||||
case TCPFlags::ACK | TCPFlags::FIN:
|
case TCPFlags::ACK | TCPFlags::FIN:
|
||||||
socket->set_ack_number(tcp_packet.sequence_number() + payload_size + 1);
|
socket->set_ack_number(tcp_packet.sequence_number() + payload_size + 1);
|
||||||
socket->send_tcp_packet(TCPFlags::ACK);
|
(void)socket->send_tcp_packet(TCPFlags::ACK);
|
||||||
socket->set_state(TCPSocket::State::Closed);
|
socket->set_state(TCPSocket::State::Closed);
|
||||||
socket->set_error(TCPSocket::Error::FINDuringConnect);
|
socket->set_error(TCPSocket::Error::FINDuringConnect);
|
||||||
socket->set_setup_state(Socket::SetupState::Completed);
|
socket->set_setup_state(Socket::SetupState::Completed);
|
||||||
return;
|
return;
|
||||||
case TCPFlags::ACK | TCPFlags::RST:
|
case TCPFlags::ACK | TCPFlags::RST:
|
||||||
socket->set_ack_number(tcp_packet.sequence_number() + payload_size);
|
socket->set_ack_number(tcp_packet.sequence_number() + payload_size);
|
||||||
socket->send_tcp_packet(TCPFlags::ACK);
|
(void)socket->send_tcp_packet(TCPFlags::ACK);
|
||||||
socket->set_state(TCPSocket::State::Closed);
|
socket->set_state(TCPSocket::State::Closed);
|
||||||
socket->set_error(TCPSocket::Error::RSTDuringConnect);
|
socket->set_error(TCPSocket::Error::RSTDuringConnect);
|
||||||
socket->set_setup_state(Socket::SetupState::Completed);
|
socket->set_setup_state(Socket::SetupState::Completed);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
klog() << "handle_tcp: unexpected flags in SynSent state";
|
klog() << "handle_tcp: unexpected flags in SynSent state";
|
||||||
socket->send_tcp_packet(TCPFlags::RST);
|
(void)socket->send_tcp_packet(TCPFlags::RST);
|
||||||
socket->set_state(TCPSocket::State::Closed);
|
socket->set_state(TCPSocket::State::Closed);
|
||||||
socket->set_error(TCPSocket::Error::UnexpectedFlagsDuringConnect);
|
socket->set_error(TCPSocket::Error::UnexpectedFlagsDuringConnect);
|
||||||
socket->set_setup_state(Socket::SetupState::Completed);
|
socket->set_setup_state(Socket::SetupState::Completed);
|
||||||
|
@ -454,7 +455,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
|
||||||
case TCPSocket::Direction::Incoming:
|
case TCPSocket::Direction::Incoming:
|
||||||
if (!socket->has_originator()) {
|
if (!socket->has_originator()) {
|
||||||
klog() << "handle_tcp: connection doesn't have an originating socket; maybe it went away?";
|
klog() << "handle_tcp: connection doesn't have an originating socket; maybe it went away?";
|
||||||
socket->send_tcp_packet(TCPFlags::RST);
|
(void)socket->send_tcp_packet(TCPFlags::RST);
|
||||||
socket->set_state(TCPSocket::State::Closed);
|
socket->set_state(TCPSocket::State::Closed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -470,7 +471,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
klog() << "handle_tcp: got ACK in SynReceived state but direction is invalid (" << TCPSocket::to_string(socket->direction()) << ")";
|
klog() << "handle_tcp: got ACK in SynReceived state but direction is invalid (" << TCPSocket::to_string(socket->direction()) << ")";
|
||||||
socket->send_tcp_packet(TCPFlags::RST);
|
(void)socket->send_tcp_packet(TCPFlags::RST);
|
||||||
socket->set_state(TCPSocket::State::Closed);
|
socket->set_state(TCPSocket::State::Closed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -478,7 +479,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
klog() << "handle_tcp: unexpected flags in SynReceived state";
|
klog() << "handle_tcp: unexpected flags in SynReceived state";
|
||||||
socket->send_tcp_packet(TCPFlags::RST);
|
(void)socket->send_tcp_packet(TCPFlags::RST);
|
||||||
socket->set_state(TCPSocket::State::Closed);
|
socket->set_state(TCPSocket::State::Closed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -486,7 +487,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
|
||||||
switch (tcp_packet.flags()) {
|
switch (tcp_packet.flags()) {
|
||||||
default:
|
default:
|
||||||
klog() << "handle_tcp: unexpected flags in CloseWait state";
|
klog() << "handle_tcp: unexpected flags in CloseWait state";
|
||||||
socket->send_tcp_packet(TCPFlags::RST);
|
(void)socket->send_tcp_packet(TCPFlags::RST);
|
||||||
socket->set_state(TCPSocket::State::Closed);
|
socket->set_state(TCPSocket::State::Closed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -498,7 +499,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
klog() << "handle_tcp: unexpected flags in LastAck state";
|
klog() << "handle_tcp: unexpected flags in LastAck state";
|
||||||
socket->send_tcp_packet(TCPFlags::RST);
|
(void)socket->send_tcp_packet(TCPFlags::RST);
|
||||||
socket->set_state(TCPSocket::State::Closed);
|
socket->set_state(TCPSocket::State::Closed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -514,7 +515,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
klog() << "handle_tcp: unexpected flags in FinWait1 state";
|
klog() << "handle_tcp: unexpected flags in FinWait1 state";
|
||||||
socket->send_tcp_packet(TCPFlags::RST);
|
(void)socket->send_tcp_packet(TCPFlags::RST);
|
||||||
socket->set_state(TCPSocket::State::Closed);
|
socket->set_state(TCPSocket::State::Closed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -529,7 +530,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
klog() << "handle_tcp: unexpected flags in FinWait2 state";
|
klog() << "handle_tcp: unexpected flags in FinWait2 state";
|
||||||
socket->send_tcp_packet(TCPFlags::RST);
|
(void)socket->send_tcp_packet(TCPFlags::RST);
|
||||||
socket->set_state(TCPSocket::State::Closed);
|
socket->set_state(TCPSocket::State::Closed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -541,7 +542,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
klog() << "handle_tcp: unexpected flags in Closing state";
|
klog() << "handle_tcp: unexpected flags in Closing state";
|
||||||
socket->send_tcp_packet(TCPFlags::RST);
|
(void)socket->send_tcp_packet(TCPFlags::RST);
|
||||||
socket->set_state(TCPSocket::State::Closed);
|
socket->set_state(TCPSocket::State::Closed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -551,7 +552,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
|
||||||
socket->did_receive(ipv4_packet.source(), tcp_packet.source_port(), KBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size()));
|
socket->did_receive(ipv4_packet.source(), tcp_packet.source_port(), KBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size()));
|
||||||
|
|
||||||
socket->set_ack_number(tcp_packet.sequence_number() + payload_size + 1);
|
socket->set_ack_number(tcp_packet.sequence_number() + payload_size + 1);
|
||||||
socket->send_tcp_packet(TCPFlags::ACK);
|
(void)socket->send_tcp_packet(TCPFlags::ACK);
|
||||||
socket->set_state(TCPSocket::State::CloseWait);
|
socket->set_state(TCPSocket::State::CloseWait);
|
||||||
socket->set_connected(false);
|
socket->set_connected(false);
|
||||||
return;
|
return;
|
||||||
|
@ -565,7 +566,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
|
||||||
|
|
||||||
if (payload_size) {
|
if (payload_size) {
|
||||||
if (socket->did_receive(ipv4_packet.source(), tcp_packet.source_port(), KBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size())))
|
if (socket->did_receive(ipv4_packet.source(), tcp_packet.source_port(), KBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size())))
|
||||||
socket->send_tcp_packet(TCPFlags::ACK);
|
(void)socket->send_tcp_packet(TCPFlags::ACK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,18 +108,20 @@ KResult Socket::setsockopt(int level, int option, Userspace<const void*> user_va
|
||||||
case SO_SNDTIMEO:
|
case SO_SNDTIMEO:
|
||||||
if (user_value_size != sizeof(timeval))
|
if (user_value_size != sizeof(timeval))
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
copy_from_user(&m_send_timeout, static_ptr_cast<const timeval*>(user_value));
|
if (!copy_from_user(&m_send_timeout, static_ptr_cast<const timeval*>(user_value)))
|
||||||
|
return KResult(-EFAULT);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
case SO_RCVTIMEO:
|
case SO_RCVTIMEO:
|
||||||
if (user_value_size != sizeof(timeval))
|
if (user_value_size != sizeof(timeval))
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
copy_from_user(&m_receive_timeout, static_ptr_cast<const timeval*>(user_value));
|
if (!copy_from_user(&m_receive_timeout, static_ptr_cast<const timeval*>(user_value)))
|
||||||
|
return KResult(-EFAULT);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
case SO_BINDTODEVICE: {
|
case SO_BINDTODEVICE: {
|
||||||
if (user_value_size != IFNAMSIZ)
|
if (user_value_size != IFNAMSIZ)
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
auto user_string = static_ptr_cast<const char*>(user_value);
|
auto user_string = static_ptr_cast<const char*>(user_value);
|
||||||
auto ifname = Process::current()->validate_and_copy_string_from_user(user_string, user_value_size);
|
auto ifname = copy_string_from_user(user_string, user_value_size);
|
||||||
if (ifname.is_null())
|
if (ifname.is_null())
|
||||||
return KResult(-EFAULT);
|
return KResult(-EFAULT);
|
||||||
auto device = NetworkAdapter::lookup_by_name(ifname);
|
auto device = NetworkAdapter::lookup_by_name(ifname);
|
||||||
|
@ -140,7 +142,7 @@ KResult Socket::setsockopt(int level, int option, Userspace<const void*> user_va
|
||||||
KResult Socket::getsockopt(FileDescription&, int level, int option, Userspace<void*> value, Userspace<socklen_t*> value_size)
|
KResult Socket::getsockopt(FileDescription&, int level, int option, Userspace<void*> value, Userspace<socklen_t*> value_size)
|
||||||
{
|
{
|
||||||
socklen_t size;
|
socklen_t size;
|
||||||
if (!Process::current()->validate_read_and_copy_typed(&size, value_size))
|
if (!copy_from_user(&size, value_size.unsafe_userspace_ptr()))
|
||||||
return KResult(-EFAULT);
|
return KResult(-EFAULT);
|
||||||
|
|
||||||
ASSERT(level == SOL_SOCKET);
|
ASSERT(level == SOL_SOCKET);
|
||||||
|
@ -148,25 +150,31 @@ KResult Socket::getsockopt(FileDescription&, int level, int option, Userspace<vo
|
||||||
case SO_SNDTIMEO:
|
case SO_SNDTIMEO:
|
||||||
if (size < sizeof(timeval))
|
if (size < sizeof(timeval))
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
copy_to_user(static_ptr_cast<timeval*>(value), &m_send_timeout);
|
if (!copy_to_user(static_ptr_cast<timeval*>(value), &m_send_timeout))
|
||||||
|
return KResult(-EFAULT);
|
||||||
size = sizeof(timeval);
|
size = sizeof(timeval);
|
||||||
copy_to_user(value_size, &size);
|
if (!copy_to_user(value_size, &size))
|
||||||
|
return KResult(-EFAULT);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
case SO_RCVTIMEO:
|
case SO_RCVTIMEO:
|
||||||
if (size < sizeof(timeval))
|
if (size < sizeof(timeval))
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
copy_to_user(static_ptr_cast<timeval*>(value), &m_receive_timeout);
|
if (!copy_to_user(static_ptr_cast<timeval*>(value), &m_receive_timeout))
|
||||||
|
return KResult(-EFAULT);
|
||||||
size = sizeof(timeval);
|
size = sizeof(timeval);
|
||||||
copy_to_user(value_size, &size);
|
if (!copy_to_user(value_size, &size))
|
||||||
|
return KResult(-EFAULT);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
case SO_ERROR: {
|
case SO_ERROR: {
|
||||||
if (size < sizeof(int))
|
if (size < sizeof(int))
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
dbg() << "getsockopt(SO_ERROR): FIXME!";
|
dbg() << "getsockopt(SO_ERROR): FIXME!";
|
||||||
int errno = 0;
|
int errno = 0;
|
||||||
copy_to_user(static_ptr_cast<int*>(value), &errno);
|
if (!copy_to_user(static_ptr_cast<int*>(value), &errno))
|
||||||
|
return KResult(-EFAULT);
|
||||||
size = sizeof(int);
|
size = sizeof(int);
|
||||||
copy_to_user(value_size, &size);
|
if (!copy_to_user(value_size, &size))
|
||||||
|
return KResult(-EFAULT);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
}
|
}
|
||||||
case SO_BINDTODEVICE:
|
case SO_BINDTODEVICE:
|
||||||
|
@ -175,13 +183,16 @@ KResult Socket::getsockopt(FileDescription&, int level, int option, Userspace<vo
|
||||||
if (m_bound_interface) {
|
if (m_bound_interface) {
|
||||||
const auto& name = m_bound_interface->name();
|
const auto& name = m_bound_interface->name();
|
||||||
auto length = name.length() + 1;
|
auto length = name.length() + 1;
|
||||||
copy_to_user(static_ptr_cast<char*>(value), name.characters(), length);
|
if (!copy_to_user(static_ptr_cast<char*>(value), name.characters(), length))
|
||||||
|
return KResult(-EFAULT);
|
||||||
size = length;
|
size = length;
|
||||||
copy_to_user(value_size, &size);
|
if (!copy_to_user(value_size, &size))
|
||||||
|
return KResult(-EFAULT);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
} else {
|
} else {
|
||||||
size = 0;
|
size = 0;
|
||||||
copy_to_user(value_size, &size);
|
if (!copy_to_user(value_size, &size))
|
||||||
|
return KResult(-EFAULT);
|
||||||
|
|
||||||
return KResult(-EFAULT);
|
return KResult(-EFAULT);
|
||||||
}
|
}
|
||||||
|
@ -191,14 +202,14 @@ KResult Socket::getsockopt(FileDescription&, int level, int option, Userspace<vo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> Socket::read(FileDescription& description, size_t, u8* buffer, size_t size)
|
KResultOr<size_t> Socket::read(FileDescription& description, size_t, UserOrKernelBuffer& buffer, size_t size)
|
||||||
{
|
{
|
||||||
if (is_shut_down_for_reading())
|
if (is_shut_down_for_reading())
|
||||||
return 0;
|
return 0;
|
||||||
return recvfrom(description, buffer, size, 0, {}, 0);
|
return recvfrom(description, buffer, size, 0, {}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> Socket::write(FileDescription& description, size_t, const u8* data, size_t size)
|
KResultOr<size_t> Socket::write(FileDescription& description, size_t, const UserOrKernelBuffer& data, size_t size)
|
||||||
{
|
{
|
||||||
if (is_shut_down_for_writing())
|
if (is_shut_down_for_writing())
|
||||||
return -EPIPE;
|
return -EPIPE;
|
||||||
|
|
|
@ -99,7 +99,7 @@ public:
|
||||||
KResult shutdown(int how);
|
KResult shutdown(int how);
|
||||||
|
|
||||||
virtual KResult bind(Userspace<const sockaddr*>, socklen_t) = 0;
|
virtual KResult bind(Userspace<const sockaddr*>, socklen_t) = 0;
|
||||||
virtual KResult connect(FileDescription&, const sockaddr*, socklen_t, ShouldBlock) = 0;
|
virtual KResult connect(FileDescription&, Userspace<const sockaddr*>, socklen_t, ShouldBlock) = 0;
|
||||||
virtual KResult listen(size_t) = 0;
|
virtual KResult listen(size_t) = 0;
|
||||||
virtual void get_local_address(sockaddr*, socklen_t*) = 0;
|
virtual void get_local_address(sockaddr*, socklen_t*) = 0;
|
||||||
virtual void get_peer_address(sockaddr*, socklen_t*) = 0;
|
virtual void get_peer_address(sockaddr*, socklen_t*) = 0;
|
||||||
|
@ -107,8 +107,8 @@ public:
|
||||||
virtual bool is_ipv4() const { return false; }
|
virtual bool is_ipv4() const { return false; }
|
||||||
virtual void attach(FileDescription&) = 0;
|
virtual void attach(FileDescription&) = 0;
|
||||||
virtual void detach(FileDescription&) = 0;
|
virtual void detach(FileDescription&) = 0;
|
||||||
virtual KResultOr<size_t> sendto(FileDescription&, const void*, size_t, int flags, Userspace<const sockaddr*>, socklen_t) = 0;
|
virtual KResultOr<size_t> sendto(FileDescription&, const UserOrKernelBuffer&, size_t, int flags, Userspace<const sockaddr*>, socklen_t) = 0;
|
||||||
virtual KResultOr<size_t> recvfrom(FileDescription&, void*, size_t, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>) = 0;
|
virtual KResultOr<size_t> recvfrom(FileDescription&, UserOrKernelBuffer&, size_t, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>) = 0;
|
||||||
|
|
||||||
virtual KResult setsockopt(int level, int option, Userspace<const void*>, socklen_t);
|
virtual KResult setsockopt(int level, int option, Userspace<const void*>, socklen_t);
|
||||||
virtual KResult getsockopt(FileDescription&, int level, int option, Userspace<void*>, Userspace<socklen_t*>);
|
virtual KResult getsockopt(FileDescription&, int level, int option, Userspace<void*>, Userspace<socklen_t*>);
|
||||||
|
@ -124,8 +124,8 @@ public:
|
||||||
Lock& lock() { return m_lock; }
|
Lock& lock() { return m_lock; }
|
||||||
|
|
||||||
// ^File
|
// ^File
|
||||||
virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override final;
|
virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override final;
|
||||||
virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override final;
|
virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override final;
|
||||||
virtual KResult stat(::stat&) const override;
|
virtual KResult stat(::stat&) const override;
|
||||||
virtual String absolute_path(const FileDescription&) const override = 0;
|
virtual String absolute_path(const FileDescription&) const override = 0;
|
||||||
|
|
||||||
|
|
|
@ -161,7 +161,7 @@ NonnullRefPtr<TCPSocket> TCPSocket::create(int protocol)
|
||||||
return adopt(*new TCPSocket(protocol));
|
return adopt(*new TCPSocket(protocol));
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> TCPSocket::protocol_receive(const KBuffer& packet_buffer, void* buffer, size_t buffer_size, int flags)
|
KResultOr<size_t> TCPSocket::protocol_receive(const KBuffer& packet_buffer, UserOrKernelBuffer& buffer, size_t buffer_size, int flags)
|
||||||
{
|
{
|
||||||
(void)flags;
|
(void)flags;
|
||||||
auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.data());
|
auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.data());
|
||||||
|
@ -171,17 +171,20 @@ KResultOr<size_t> TCPSocket::protocol_receive(const KBuffer& packet_buffer, void
|
||||||
klog() << "payload_size " << payload_size << ", will it fit in " << buffer_size << "?";
|
klog() << "payload_size " << payload_size << ", will it fit in " << buffer_size << "?";
|
||||||
#endif
|
#endif
|
||||||
ASSERT(buffer_size >= payload_size);
|
ASSERT(buffer_size >= payload_size);
|
||||||
memcpy(buffer, tcp_packet.payload(), payload_size);
|
if (!buffer.write(tcp_packet.payload(), payload_size))
|
||||||
|
return KResult(-EFAULT);
|
||||||
return payload_size;
|
return payload_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> TCPSocket::protocol_send(const void* data, size_t data_length)
|
KResultOr<size_t> TCPSocket::protocol_send(const UserOrKernelBuffer& data, size_t data_length)
|
||||||
{
|
{
|
||||||
send_tcp_packet(TCPFlags::PUSH | TCPFlags::ACK, data, data_length);
|
int err = send_tcp_packet(TCPFlags::PUSH | TCPFlags::ACK, &data, data_length);
|
||||||
|
if (err < 0)
|
||||||
|
return KResult(err);
|
||||||
return data_length;
|
return data_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCPSocket::send_tcp_packet(u16 flags, const void* payload, size_t payload_size)
|
int TCPSocket::send_tcp_packet(u16 flags, const UserOrKernelBuffer* payload, size_t payload_size)
|
||||||
{
|
{
|
||||||
auto buffer = ByteBuffer::create_zeroed(sizeof(TCPPacket) + payload_size);
|
auto buffer = ByteBuffer::create_zeroed(sizeof(TCPPacket) + payload_size);
|
||||||
auto& tcp_packet = *(TCPPacket*)(buffer.data());
|
auto& tcp_packet = *(TCPPacket*)(buffer.data());
|
||||||
|
@ -196,31 +199,37 @@ void TCPSocket::send_tcp_packet(u16 flags, const void* payload, size_t payload_s
|
||||||
if (flags & TCPFlags::ACK)
|
if (flags & TCPFlags::ACK)
|
||||||
tcp_packet.set_ack_number(m_ack_number);
|
tcp_packet.set_ack_number(m_ack_number);
|
||||||
|
|
||||||
|
if (payload && !payload->read(tcp_packet.payload(), payload_size))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
if (flags & TCPFlags::SYN) {
|
if (flags & TCPFlags::SYN) {
|
||||||
++m_sequence_number;
|
++m_sequence_number;
|
||||||
} else {
|
} else {
|
||||||
m_sequence_number += payload_size;
|
m_sequence_number += payload_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(tcp_packet.payload(), payload, payload_size);
|
|
||||||
tcp_packet.set_checksum(compute_tcp_checksum(local_address(), peer_address(), tcp_packet, payload_size));
|
tcp_packet.set_checksum(compute_tcp_checksum(local_address(), peer_address(), tcp_packet, payload_size));
|
||||||
|
|
||||||
if (tcp_packet.has_syn() || payload_size > 0) {
|
if (tcp_packet.has_syn() || payload_size > 0) {
|
||||||
LOCKER(m_not_acked_lock);
|
LOCKER(m_not_acked_lock);
|
||||||
m_not_acked.append({ m_sequence_number, move(buffer) });
|
m_not_acked.append({ m_sequence_number, move(buffer) });
|
||||||
send_outgoing_packets();
|
send_outgoing_packets();
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto routing_decision = route_to(peer_address(), local_address(), bound_interface());
|
auto routing_decision = route_to(peer_address(), local_address(), bound_interface());
|
||||||
ASSERT(!routing_decision.is_zero());
|
ASSERT(!routing_decision.is_zero());
|
||||||
|
|
||||||
routing_decision.adapter->send_ipv4(
|
auto packet_buffer = UserOrKernelBuffer::for_kernel_buffer(buffer.data());
|
||||||
|
int err = routing_decision.adapter->send_ipv4(
|
||||||
routing_decision.next_hop, peer_address(), IPv4Protocol::TCP,
|
routing_decision.next_hop, peer_address(), IPv4Protocol::TCP,
|
||||||
buffer, ttl());
|
packet_buffer, buffer.size(), ttl());
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
m_packets_out++;
|
m_packets_out++;
|
||||||
m_bytes_out += buffer.size();
|
m_bytes_out += buffer.size();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCPSocket::send_outgoing_packets()
|
void TCPSocket::send_outgoing_packets()
|
||||||
|
@ -243,12 +252,17 @@ void TCPSocket::send_outgoing_packets()
|
||||||
auto& tcp_packet = *(TCPPacket*)(packet.buffer.data());
|
auto& tcp_packet = *(TCPPacket*)(packet.buffer.data());
|
||||||
klog() << "sending tcp packet from " << local_address().to_string().characters() << ":" << local_port() << " to " << peer_address().to_string().characters() << ":" << peer_port() << " with (" << (tcp_packet.has_syn() ? "SYN " : "") << (tcp_packet.has_ack() ? "ACK " : "") << (tcp_packet.has_fin() ? "FIN " : "") << (tcp_packet.has_rst() ? "RST " : "") << ") seq_no=" << tcp_packet.sequence_number() << ", ack_no=" << tcp_packet.ack_number() << ", tx_counter=" << packet.tx_counter;
|
klog() << "sending tcp packet from " << local_address().to_string().characters() << ":" << local_port() << " to " << peer_address().to_string().characters() << ":" << peer_port() << " with (" << (tcp_packet.has_syn() ? "SYN " : "") << (tcp_packet.has_ack() ? "ACK " : "") << (tcp_packet.has_fin() ? "FIN " : "") << (tcp_packet.has_rst() ? "RST " : "") << ") seq_no=" << tcp_packet.sequence_number() << ", ack_no=" << tcp_packet.ack_number() << ", tx_counter=" << packet.tx_counter;
|
||||||
#endif
|
#endif
|
||||||
routing_decision.adapter->send_ipv4(
|
auto packet_buffer = UserOrKernelBuffer::for_kernel_buffer(packet.buffer.data());
|
||||||
|
int err = routing_decision.adapter->send_ipv4(
|
||||||
routing_decision.next_hop, peer_address(), IPv4Protocol::TCP,
|
routing_decision.next_hop, peer_address(), IPv4Protocol::TCP,
|
||||||
packet.buffer, ttl());
|
packet_buffer, packet.buffer.size(), ttl());
|
||||||
|
if (err < 0) {
|
||||||
m_packets_out++;
|
auto& tcp_packet = *(TCPPacket*)(packet.buffer.data());
|
||||||
m_bytes_out += packet.buffer.size();
|
klog() << "Error (" << err << ") sending tcp packet from " << local_address().to_string().characters() << ":" << local_port() << " to " << peer_address().to_string().characters() << ":" << peer_port() << " with (" << (tcp_packet.has_syn() ? "SYN " : "") << (tcp_packet.has_ack() ? "ACK " : "") << (tcp_packet.has_fin() ? "FIN " : "") << (tcp_packet.has_rst() ? "RST " : "") << ") seq_no=" << tcp_packet.sequence_number() << ", ack_no=" << tcp_packet.ack_number() << ", tx_counter=" << packet.tx_counter;
|
||||||
|
} else {
|
||||||
|
m_packets_out++;
|
||||||
|
m_bytes_out += packet.buffer.size();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,7 +380,9 @@ KResult TCPSocket::protocol_connect(FileDescription& description, ShouldBlock sh
|
||||||
m_ack_number = 0;
|
m_ack_number = 0;
|
||||||
|
|
||||||
set_setup_state(SetupState::InProgress);
|
set_setup_state(SetupState::InProgress);
|
||||||
send_tcp_packet(TCPFlags::SYN);
|
int err = send_tcp_packet(TCPFlags::SYN);
|
||||||
|
if (err < 0)
|
||||||
|
return KResult(err);
|
||||||
m_state = State::SynSent;
|
m_state = State::SynSent;
|
||||||
m_role = Role::Connecting;
|
m_role = Role::Connecting;
|
||||||
m_direction = Direction::Outgoing;
|
m_direction = Direction::Outgoing;
|
||||||
|
@ -433,7 +449,7 @@ void TCPSocket::shut_down_for_writing()
|
||||||
#ifdef TCP_SOCKET_DEBUG
|
#ifdef TCP_SOCKET_DEBUG
|
||||||
dbg() << " Sending FIN/ACK from Established and moving into FinWait1";
|
dbg() << " Sending FIN/ACK from Established and moving into FinWait1";
|
||||||
#endif
|
#endif
|
||||||
send_tcp_packet(TCPFlags::FIN | TCPFlags::ACK);
|
(void)send_tcp_packet(TCPFlags::FIN | TCPFlags::ACK);
|
||||||
set_state(State::FinWait1);
|
set_state(State::FinWait1);
|
||||||
} else {
|
} else {
|
||||||
dbg() << " Shutting down TCPSocket for writing but not moving to FinWait1 since state is " << to_string(state());
|
dbg() << " Shutting down TCPSocket for writing but not moving to FinWait1 since state is " << to_string(state());
|
||||||
|
@ -447,7 +463,7 @@ KResult TCPSocket::close()
|
||||||
#ifdef TCP_SOCKET_DEBUG
|
#ifdef TCP_SOCKET_DEBUG
|
||||||
dbg() << " Sending FIN from CloseWait and moving into LastAck";
|
dbg() << " Sending FIN from CloseWait and moving into LastAck";
|
||||||
#endif
|
#endif
|
||||||
send_tcp_packet(TCPFlags::FIN | TCPFlags::ACK);
|
(void)send_tcp_packet(TCPFlags::FIN | TCPFlags::ACK);
|
||||||
set_state(State::LastAck);
|
set_state(State::LastAck);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,7 @@ public:
|
||||||
u32 packets_out() const { return m_packets_out; }
|
u32 packets_out() const { return m_packets_out; }
|
||||||
u32 bytes_out() const { return m_bytes_out; }
|
u32 bytes_out() const { return m_bytes_out; }
|
||||||
|
|
||||||
void send_tcp_packet(u16 flags, const void* = nullptr, size_t = 0);
|
[[nodiscard]] int send_tcp_packet(u16 flags, const UserOrKernelBuffer* = nullptr, size_t = 0);
|
||||||
void send_outgoing_packets();
|
void send_outgoing_packets();
|
||||||
void receive_tcp_packet(const TCPPacket&, u16 size);
|
void receive_tcp_packet(const TCPPacket&, u16 size);
|
||||||
|
|
||||||
|
@ -177,8 +177,8 @@ private:
|
||||||
|
|
||||||
virtual void shut_down_for_writing() override;
|
virtual void shut_down_for_writing() override;
|
||||||
|
|
||||||
virtual KResultOr<size_t> protocol_receive(const KBuffer&, void* buffer, size_t buffer_size, int flags) override;
|
virtual KResultOr<size_t> protocol_receive(const KBuffer&, UserOrKernelBuffer& buffer, size_t buffer_size, int flags) override;
|
||||||
virtual KResultOr<size_t> protocol_send(const void*, size_t) override;
|
virtual KResultOr<size_t> protocol_send(const UserOrKernelBuffer&, size_t) override;
|
||||||
virtual KResult protocol_connect(FileDescription&, ShouldBlock) override;
|
virtual KResult protocol_connect(FileDescription&, ShouldBlock) override;
|
||||||
virtual int protocol_allocate_local_port() override;
|
virtual int protocol_allocate_local_port() override;
|
||||||
virtual bool protocol_is_disconnected() const override;
|
virtual bool protocol_is_disconnected() const override;
|
||||||
|
|
|
@ -79,18 +79,19 @@ NonnullRefPtr<UDPSocket> UDPSocket::create(int protocol)
|
||||||
return adopt(*new UDPSocket(protocol));
|
return adopt(*new UDPSocket(protocol));
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> UDPSocket::protocol_receive(const KBuffer& packet_buffer, void* buffer, size_t buffer_size, int flags)
|
KResultOr<size_t> UDPSocket::protocol_receive(const KBuffer& packet_buffer, UserOrKernelBuffer& buffer, size_t buffer_size, int flags)
|
||||||
{
|
{
|
||||||
(void)flags;
|
(void)flags;
|
||||||
auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.data());
|
auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.data());
|
||||||
auto& udp_packet = *static_cast<const UDPPacket*>(ipv4_packet.payload());
|
auto& udp_packet = *static_cast<const UDPPacket*>(ipv4_packet.payload());
|
||||||
ASSERT(udp_packet.length() >= sizeof(UDPPacket)); // FIXME: This should be rejected earlier.
|
ASSERT(udp_packet.length() >= sizeof(UDPPacket)); // FIXME: This should be rejected earlier.
|
||||||
ASSERT(buffer_size >= (udp_packet.length() - sizeof(UDPPacket)));
|
ASSERT(buffer_size >= (udp_packet.length() - sizeof(UDPPacket)));
|
||||||
memcpy(buffer, udp_packet.payload(), udp_packet.length() - sizeof(UDPPacket));
|
if (!buffer.write(udp_packet.payload(), udp_packet.length() - sizeof(UDPPacket)))
|
||||||
|
return KResult(-EFAULT);
|
||||||
return udp_packet.length() - sizeof(UDPPacket);
|
return udp_packet.length() - sizeof(UDPPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<size_t> UDPSocket::protocol_send(const void* data, size_t data_length)
|
KResultOr<size_t> UDPSocket::protocol_send(const UserOrKernelBuffer& data, size_t data_length)
|
||||||
{
|
{
|
||||||
auto routing_decision = route_to(peer_address(), local_address(), bound_interface());
|
auto routing_decision = route_to(peer_address(), local_address(), bound_interface());
|
||||||
if (routing_decision.is_zero())
|
if (routing_decision.is_zero())
|
||||||
|
@ -100,9 +101,11 @@ KResultOr<size_t> UDPSocket::protocol_send(const void* data, size_t data_length)
|
||||||
udp_packet.set_source_port(local_port());
|
udp_packet.set_source_port(local_port());
|
||||||
udp_packet.set_destination_port(peer_port());
|
udp_packet.set_destination_port(peer_port());
|
||||||
udp_packet.set_length(sizeof(UDPPacket) + data_length);
|
udp_packet.set_length(sizeof(UDPPacket) + data_length);
|
||||||
memcpy(udp_packet.payload(), data, data_length);
|
if (!data.read(udp_packet.payload(), data_length))
|
||||||
|
return KResult(-EFAULT);
|
||||||
klog() << "sending as udp packet from " << routing_decision.adapter->ipv4_address().to_string().characters() << ":" << local_port() << " to " << peer_address().to_string().characters() << ":" << peer_port() << "!";
|
klog() << "sending as udp packet from " << routing_decision.adapter->ipv4_address().to_string().characters() << ":" << local_port() << " to " << peer_address().to_string().characters() << ":" << peer_port() << "!";
|
||||||
routing_decision.adapter->send_ipv4(routing_decision.next_hop, peer_address(), IPv4Protocol::UDP, buffer, ttl());
|
auto udp_packet_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&udp_packet);
|
||||||
|
routing_decision.adapter->send_ipv4(routing_decision.next_hop, peer_address(), IPv4Protocol::UDP, udp_packet_buffer, buffer.size(), ttl());
|
||||||
return data_length;
|
return data_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,8 +43,8 @@ private:
|
||||||
virtual const char* class_name() const override { return "UDPSocket"; }
|
virtual const char* class_name() const override { return "UDPSocket"; }
|
||||||
static Lockable<HashMap<u16, UDPSocket*>>& sockets_by_port();
|
static Lockable<HashMap<u16, UDPSocket*>>& sockets_by_port();
|
||||||
|
|
||||||
virtual KResultOr<size_t> protocol_receive(const KBuffer&, void* buffer, size_t buffer_size, int flags) override;
|
virtual KResultOr<size_t> protocol_receive(const KBuffer&, UserOrKernelBuffer& buffer, size_t buffer_size, int flags) override;
|
||||||
virtual KResultOr<size_t> protocol_send(const void*, size_t) override;
|
virtual KResultOr<size_t> protocol_send(const UserOrKernelBuffer&, size_t) override;
|
||||||
virtual KResult protocol_connect(FileDescription&, ShouldBlock) override;
|
virtual KResult protocol_connect(FileDescription&, ShouldBlock) override;
|
||||||
virtual int protocol_allocate_local_port() override;
|
virtual int protocol_allocate_local_port() override;
|
||||||
virtual KResult protocol_bind() override;
|
virtual KResult protocol_bind() override;
|
||||||
|
|
|
@ -520,24 +520,6 @@ int Process::fd_flags(int fd) const
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
String Process::validate_and_copy_string_from_user(const char* user_characters, size_t user_length) const
|
|
||||||
{
|
|
||||||
if (user_length == 0)
|
|
||||||
return String::empty();
|
|
||||||
if (!user_characters)
|
|
||||||
return {};
|
|
||||||
if (!validate_read(user_characters, user_length))
|
|
||||||
return {};
|
|
||||||
SmapDisabler disabler;
|
|
||||||
size_t measured_length = strnlen(user_characters, user_length);
|
|
||||||
return String(user_characters, measured_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
String Process::validate_and_copy_string_from_user(const Syscall::StringArgument& string) const
|
|
||||||
{
|
|
||||||
return validate_and_copy_string_from_user(string.characters, string.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Process::number_of_open_file_descriptors() const
|
int Process::number_of_open_file_descriptors() const
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
@ -602,27 +584,6 @@ siginfo_t Process::reap(Process& process)
|
||||||
return siginfo;
|
return siginfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Process::validate_read_from_kernel(VirtualAddress vaddr, size_t size) const
|
|
||||||
{
|
|
||||||
if (vaddr.is_null())
|
|
||||||
return false;
|
|
||||||
return MM.validate_kernel_read(*this, vaddr, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Process::validate_read(const void* address, size_t size) const
|
|
||||||
{
|
|
||||||
if (!size)
|
|
||||||
return false;
|
|
||||||
return MM.validate_user_read(*this, VirtualAddress(address), size);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Process::validate_write(void* address, size_t size) const
|
|
||||||
{
|
|
||||||
if (!size)
|
|
||||||
return false;
|
|
||||||
return MM.validate_user_write(*this, VirtualAddress(address), size);
|
|
||||||
}
|
|
||||||
|
|
||||||
Custody& Process::current_directory()
|
Custody& Process::current_directory()
|
||||||
{
|
{
|
||||||
if (!m_cwd)
|
if (!m_cwd)
|
||||||
|
@ -636,9 +597,10 @@ KResultOr<String> Process::get_syscall_path_argument(const char* user_path, size
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
if (path_length > PATH_MAX)
|
if (path_length > PATH_MAX)
|
||||||
return KResult(-ENAMETOOLONG);
|
return KResult(-ENAMETOOLONG);
|
||||||
if (!validate_read(user_path, path_length))
|
auto copied_string = copy_string_from_user(user_path, path_length);
|
||||||
|
if (copied_string.is_null())
|
||||||
return KResult(-EFAULT);
|
return KResult(-EFAULT);
|
||||||
return copy_string_from_user(user_path, path_length);
|
return copied_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<String> Process::get_syscall_path_argument(const Syscall::StringArgument& path) const
|
KResultOr<String> Process::get_syscall_path_argument(const Syscall::StringArgument& path) const
|
||||||
|
@ -659,7 +621,8 @@ void Process::finalize()
|
||||||
auto& description = description_or_error.value();
|
auto& description = description_or_error.value();
|
||||||
auto json = m_perf_event_buffer->to_json(m_pid, m_executable ? m_executable->absolute_path() : "");
|
auto json = m_perf_event_buffer->to_json(m_pid, m_executable ? m_executable->absolute_path() : "");
|
||||||
// FIXME: Should this error path be surfaced somehow?
|
// FIXME: Should this error path be surfaced somehow?
|
||||||
(void)description->write(json.data(), json.size());
|
auto json_buffer = UserOrKernelBuffer::for_kernel_buffer(json.data());
|
||||||
|
(void)description->write(json_buffer, json.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
112
Kernel/Process.h
112
Kernel/Process.h
|
@ -362,111 +362,6 @@ public:
|
||||||
u32 m_ticks_in_user_for_dead_children { 0 };
|
u32 m_ticks_in_user_for_dead_children { 0 };
|
||||||
u32 m_ticks_in_kernel_for_dead_children { 0 };
|
u32 m_ticks_in_kernel_for_dead_children { 0 };
|
||||||
|
|
||||||
[[nodiscard]] bool validate_read_from_kernel(VirtualAddress, size_t) const;
|
|
||||||
|
|
||||||
[[nodiscard]] bool validate_read(const void*, size_t) const;
|
|
||||||
[[nodiscard]] bool validate_write(void*, size_t) const;
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
[[nodiscard]] bool validate_read(Userspace<T*> ptr, size_t size) const
|
|
||||||
{
|
|
||||||
return validate_read(ptr.unsafe_userspace_ptr(), size);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
[[nodiscard]] bool validate_write(Userspace<T*> ptr, size_t size) const
|
|
||||||
{
|
|
||||||
return validate_write(ptr.unsafe_userspace_ptr(), size);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
[[nodiscard]] bool validate_read_typed(T* value, size_t count = 1)
|
|
||||||
{
|
|
||||||
Checked size = sizeof(T);
|
|
||||||
size *= count;
|
|
||||||
if (size.has_overflow())
|
|
||||||
return false;
|
|
||||||
return validate_read(value, size.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
[[nodiscard]] bool validate_read_typed(Userspace<T*> value, size_t count = 1)
|
|
||||||
{
|
|
||||||
Checked size = sizeof(T);
|
|
||||||
size *= count;
|
|
||||||
if (size.has_overflow())
|
|
||||||
return false;
|
|
||||||
return validate_read(value, size.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
[[nodiscard]] bool validate_read_and_copy_typed(T* dest, const T* src)
|
|
||||||
{
|
|
||||||
bool validated = validate_read_typed(src);
|
|
||||||
if (validated) {
|
|
||||||
copy_from_user(dest, src);
|
|
||||||
}
|
|
||||||
return validated;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
[[nodiscard]] bool validate_read_and_copy_typed(T* dest, Userspace<const T*> src)
|
|
||||||
{
|
|
||||||
bool validated = validate_read_typed(src);
|
|
||||||
if (validated) {
|
|
||||||
copy_from_user(dest, src);
|
|
||||||
}
|
|
||||||
return validated;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
[[nodiscard]] bool validate_read_and_copy_typed(T* dest, Userspace<T*> src)
|
|
||||||
{
|
|
||||||
Userspace<const T*> const_src { src.ptr() };
|
|
||||||
return validate_read_and_copy_typed(dest, const_src);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
[[nodiscard]] bool validate_write_typed(T* value, size_t count = 1)
|
|
||||||
{
|
|
||||||
Checked size = sizeof(T);
|
|
||||||
size *= count;
|
|
||||||
if (size.has_overflow())
|
|
||||||
return false;
|
|
||||||
return validate_write(value, size.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
[[nodiscard]] bool validate_write_typed(Userspace<T*> value, size_t count = 1)
|
|
||||||
{
|
|
||||||
Checked size = sizeof(T);
|
|
||||||
size *= count;
|
|
||||||
if (size.has_overflow())
|
|
||||||
return false;
|
|
||||||
return validate_write(value, size.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename DataType, typename SizeType>
|
|
||||||
[[nodiscard]] bool validate(const Syscall::MutableBufferArgument<DataType, SizeType>& buffer)
|
|
||||||
{
|
|
||||||
return validate_write(buffer.data, buffer.size);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename DataType, typename SizeType>
|
|
||||||
[[nodiscard]] bool validate(const Syscall::ImmutableBufferArgument<DataType, SizeType>& buffer)
|
|
||||||
{
|
|
||||||
return validate_read(buffer.data, buffer.size);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] String validate_and_copy_string_from_user(const char*, size_t) const;
|
|
||||||
|
|
||||||
[[nodiscard]] String validate_and_copy_string_from_user(Userspace<const char*> user_characters, size_t size) const
|
|
||||||
{
|
|
||||||
return validate_and_copy_string_from_user(user_characters.unsafe_userspace_ptr(), size);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] String validate_and_copy_string_from_user(const Syscall::StringArgument&) const;
|
|
||||||
|
|
||||||
Custody& current_directory();
|
Custody& current_directory();
|
||||||
Custody* executable()
|
Custody* executable()
|
||||||
{
|
{
|
||||||
|
@ -582,7 +477,7 @@ private:
|
||||||
void kill_all_threads();
|
void kill_all_threads();
|
||||||
|
|
||||||
int do_exec(NonnullRefPtr<FileDescription> main_program_description, Vector<String> arguments, Vector<String> environment, RefPtr<FileDescription> interpreter_description, Thread*& new_main_thread, u32& prev_flags);
|
int do_exec(NonnullRefPtr<FileDescription> main_program_description, Vector<String> arguments, Vector<String> environment, RefPtr<FileDescription> interpreter_description, Thread*& new_main_thread, u32& prev_flags);
|
||||||
ssize_t do_write(FileDescription&, const u8*, int data_size);
|
ssize_t do_write(FileDescription&, const UserOrKernelBuffer&, size_t);
|
||||||
|
|
||||||
KResultOr<NonnullRefPtr<FileDescription>> find_elf_interpreter_for_executable(const String& path, char (&first_page)[PAGE_SIZE], int nread, size_t file_size);
|
KResultOr<NonnullRefPtr<FileDescription>> find_elf_interpreter_for_executable(const String& path, char (&first_page)[PAGE_SIZE], int nread, size_t file_size);
|
||||||
Vector<AuxiliaryValue> generate_auxiliary_vector() const;
|
Vector<AuxiliaryValue> generate_auxiliary_vector() const;
|
||||||
|
@ -834,3 +729,8 @@ inline u32 Thread::effective_priority() const
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline static String copy_string_from_user(const Kernel::Syscall::StringArgument& string)
|
||||||
|
{
|
||||||
|
return copy_string_from_user(string.characters, string.length);
|
||||||
|
}
|
||||||
|
|
|
@ -105,10 +105,9 @@ KResultOr<u32> handle_syscall(const Kernel::Syscall::SC_ptrace_params& params, P
|
||||||
if (!tracer->has_regs())
|
if (!tracer->has_regs())
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
|
|
||||||
auto* regs = reinterpret_cast<PtraceRegisters*>(params.addr.unsafe_userspace_ptr());
|
auto* regs = reinterpret_cast<PtraceRegisters*>(params.addr);
|
||||||
if (!caller.validate_write_typed(regs))
|
if (!copy_to_user(regs, &tracer->regs()))
|
||||||
return KResult(-EFAULT);
|
return KResult(-EFAULT);
|
||||||
copy_to_user(regs, &tracer->regs());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +116,7 @@ KResultOr<u32> handle_syscall(const Kernel::Syscall::SC_ptrace_params& params, P
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
|
|
||||||
PtraceRegisters regs;
|
PtraceRegisters regs;
|
||||||
if (!caller.validate_read_and_copy_typed(®s, (const PtraceRegisters*)params.addr.unsafe_userspace_ptr()))
|
if (!copy_from_user(®s, (const PtraceRegisters*)params.addr))
|
||||||
return KResult(-EFAULT);
|
return KResult(-EFAULT);
|
||||||
|
|
||||||
auto& peer_saved_registers = peer->get_register_dump_from_stack();
|
auto& peer_saved_registers = peer->get_register_dump_from_stack();
|
||||||
|
@ -132,21 +131,20 @@ KResultOr<u32> handle_syscall(const Kernel::Syscall::SC_ptrace_params& params, P
|
||||||
|
|
||||||
case PT_PEEK: {
|
case PT_PEEK: {
|
||||||
Kernel::Syscall::SC_ptrace_peek_params peek_params;
|
Kernel::Syscall::SC_ptrace_peek_params peek_params;
|
||||||
if (!caller.validate_read_and_copy_typed(&peek_params, reinterpret_cast<Kernel::Syscall::SC_ptrace_peek_params*>(params.addr.unsafe_userspace_ptr())))
|
if (!copy_from_user(&peek_params, reinterpret_cast<Kernel::Syscall::SC_ptrace_peek_params*>(params.addr)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
// read validation is done inside 'peek_user_data'
|
// read validation is done inside 'peek_user_data'
|
||||||
auto result = peer->process().peek_user_data(peek_params.address);
|
auto result = peer->process().peek_user_data((FlatPtr)peek_params.address);
|
||||||
if (result.is_error())
|
if (result.is_error())
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (!caller.validate_write(peek_params.out_data, sizeof(u32)))
|
if (!copy_to_user(peek_params.out_data, &result.value()))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
copy_to_user(peek_params.out_data, &result.value());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PT_POKE: {
|
case PT_POKE: {
|
||||||
Userspace<u32*> addr = reinterpret_cast<FlatPtr>(params.addr.ptr());
|
Userspace<u32*> addr = reinterpret_cast<FlatPtr>(params.addr);
|
||||||
// write validation is done inside 'poke_user_data'
|
// write validation is done inside 'poke_user_data'
|
||||||
return peer->process().poke_user_data(addr, params.data);
|
return peer->process().poke_user_data(addr, params.data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -651,7 +651,7 @@ void Scheduler::initialize()
|
||||||
ASSERT(s_colonel_process);
|
ASSERT(s_colonel_process);
|
||||||
ASSERT(idle_thread);
|
ASSERT(idle_thread);
|
||||||
idle_thread->set_priority(THREAD_PRIORITY_MIN);
|
idle_thread->set_priority(THREAD_PRIORITY_MIN);
|
||||||
idle_thread->set_name("idle thread #0");
|
idle_thread->set_name(StringView("idle thread #0"));
|
||||||
|
|
||||||
set_idle_thread(idle_thread);
|
set_idle_thread(idle_thread);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,27 +35,68 @@
|
||||||
|
|
||||||
String copy_string_from_user(const char* user_str, size_t user_str_size)
|
String copy_string_from_user(const char* user_str, size_t user_str_size)
|
||||||
{
|
{
|
||||||
|
bool is_user = Kernel::is_user_range(VirtualAddress(user_str), user_str_size);
|
||||||
|
ASSERT(is_user); // For now assert to catch bugs, but technically not an error
|
||||||
|
if (!is_user)
|
||||||
|
return {};
|
||||||
Kernel::SmapDisabler disabler;
|
Kernel::SmapDisabler disabler;
|
||||||
size_t length = strnlen(user_str, user_str_size);
|
void* fault_at;
|
||||||
return String(user_str, length);
|
ssize_t length = Kernel::safe_strnlen(user_str, user_str_size, fault_at);
|
||||||
|
if (length < 0) {
|
||||||
|
klog() << "copy_string_from_user(" << user_str << ", " << user_str_size << ") failed at " << VirtualAddress(fault_at) << " (strnlen)";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (length == 0)
|
||||||
|
return String::empty();
|
||||||
|
|
||||||
|
char* buffer;
|
||||||
|
auto copied_string = StringImpl::create_uninitialized((size_t)length, buffer);
|
||||||
|
if (!Kernel::safe_memcpy(buffer, user_str, (size_t)length, fault_at)) {
|
||||||
|
klog() << "copy_string_from_user(" << user_str << ", " << user_str_size << ") failed at " << VirtualAddress(fault_at) << " (memcpy)";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return copied_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
String copy_string_from_user(Userspace<const char*> user_str, size_t user_str_size)
|
||||||
|
{
|
||||||
|
return copy_string_from_user(user_str.unsafe_userspace_ptr(), user_str_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
void copy_to_user(void* dest_ptr, const void* src_ptr, size_t n)
|
bool copy_to_user(void* dest_ptr, const void* src_ptr, size_t n)
|
||||||
{
|
{
|
||||||
ASSERT(Kernel::is_user_range(VirtualAddress(dest_ptr), n));
|
bool is_user = Kernel::is_user_range(VirtualAddress(dest_ptr), n);
|
||||||
|
ASSERT(is_user); // For now assert to catch bugs, but technically not an error
|
||||||
|
if (!is_user)
|
||||||
|
return false;
|
||||||
ASSERT(!Kernel::is_user_range(VirtualAddress(src_ptr), n));
|
ASSERT(!Kernel::is_user_range(VirtualAddress(src_ptr), n));
|
||||||
Kernel::SmapDisabler disabler;
|
Kernel::SmapDisabler disabler;
|
||||||
memcpy(dest_ptr, src_ptr, n);
|
void* fault_at;
|
||||||
|
if (!Kernel::safe_memcpy(dest_ptr, src_ptr, n, fault_at)) {
|
||||||
|
ASSERT(VirtualAddress(fault_at) >= VirtualAddress(dest_ptr) && VirtualAddress(fault_at) <= VirtualAddress((FlatPtr)dest_ptr + n));
|
||||||
|
klog() << "copy_to_user(" << dest_ptr << ", " << src_ptr << ", " << n << ") failed at " << VirtualAddress(fault_at);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void copy_from_user(void* dest_ptr, const void* src_ptr, size_t n)
|
bool copy_from_user(void* dest_ptr, const void* src_ptr, size_t n)
|
||||||
{
|
{
|
||||||
ASSERT(Kernel::is_user_range(VirtualAddress(src_ptr), n));
|
bool is_user = Kernel::is_user_range(VirtualAddress(src_ptr), n);
|
||||||
|
ASSERT(is_user); // For now assert to catch bugs, but technically not an error
|
||||||
|
if (!is_user)
|
||||||
|
return false;
|
||||||
ASSERT(!Kernel::is_user_range(VirtualAddress(dest_ptr), n));
|
ASSERT(!Kernel::is_user_range(VirtualAddress(dest_ptr), n));
|
||||||
Kernel::SmapDisabler disabler;
|
Kernel::SmapDisabler disabler;
|
||||||
memcpy(dest_ptr, src_ptr, n);
|
void* fault_at;
|
||||||
|
if (!Kernel::safe_memcpy(dest_ptr, src_ptr, n, fault_at)) {
|
||||||
|
ASSERT(VirtualAddress(fault_at) >= VirtualAddress(src_ptr) && VirtualAddress(fault_at) <= VirtualAddress((FlatPtr)src_ptr + n));
|
||||||
|
klog() << "copy_from_user(" << dest_ptr << ", " << src_ptr << ", " << n << ") failed at " << VirtualAddress(fault_at);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* memcpy(void* dest_ptr, const void* src_ptr, size_t n)
|
void* memcpy(void* dest_ptr, const void* src_ptr, size_t n)
|
||||||
|
@ -97,11 +138,19 @@ const void* memmem(const void* haystack, size_t haystack_length, const void* nee
|
||||||
return AK::memmem(haystack, haystack_length, needle, needle_length);
|
return AK::memmem(haystack, haystack_length, needle, needle_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void memset_user(void* dest_ptr, int c, size_t n)
|
[[nodiscard]] bool memset_user(void* dest_ptr, int c, size_t n)
|
||||||
{
|
{
|
||||||
ASSERT(Kernel::is_user_range(VirtualAddress(dest_ptr), n));
|
bool is_user = Kernel::is_user_range(VirtualAddress(dest_ptr), n);
|
||||||
|
ASSERT(is_user); // For now assert to catch bugs, but technically not an error
|
||||||
|
if (!is_user)
|
||||||
|
return false;
|
||||||
Kernel::SmapDisabler disabler;
|
Kernel::SmapDisabler disabler;
|
||||||
memset(dest_ptr, c, n);
|
void* fault_at;
|
||||||
|
if (!Kernel::safe_memset(dest_ptr, c, n, fault_at)) {
|
||||||
|
klog() << "memset(" << dest_ptr << ", " << n << ") failed at " << VirtualAddress(fault_at);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* memset(void* dest_ptr, int c, size_t n)
|
void* memset(void* dest_ptr, int c, size_t n)
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Checked.h>
|
||||||
#include <AK/Forward.h>
|
#include <AK/Forward.h>
|
||||||
#include <AK/Userspace.h>
|
#include <AK/Userspace.h>
|
||||||
|
|
||||||
|
@ -34,12 +35,13 @@ struct StringArgument;
|
||||||
}
|
}
|
||||||
|
|
||||||
String copy_string_from_user(const char*, size_t);
|
String copy_string_from_user(const char*, size_t);
|
||||||
|
String copy_string_from_user(Userspace<const char*>, size_t);
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
void copy_to_user(void*, const void*, size_t);
|
[[nodiscard]] bool copy_to_user(void*, const void*, size_t);
|
||||||
void copy_from_user(void*, const void*, size_t);
|
[[nodiscard]] bool copy_from_user(void*, const void*, size_t);
|
||||||
void memset_user(void*, int, size_t);
|
[[nodiscard]] bool memset_user(void*, int, size_t);
|
||||||
|
|
||||||
void* memcpy(void*, const void*, size_t);
|
void* memcpy(void*, const void*, size_t);
|
||||||
int strncmp(const char* s1, const char* s2, size_t n);
|
int strncmp(const char* s1, const char* s2, size_t n);
|
||||||
|
@ -57,37 +59,77 @@ inline u16 htons(u16 w) { return (w & 0xff) << 8 | ((w >> 8) & 0xff); }
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void copy_from_user(T* dest, const T* src)
|
[[nodiscard]] inline bool copy_from_user(T* dest, const T* src)
|
||||||
{
|
{
|
||||||
copy_from_user(dest, src, sizeof(T));
|
return copy_from_user(dest, src, sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void copy_to_user(T* dest, const T* src)
|
[[nodiscard]] inline bool copy_to_user(T* dest, const T* src)
|
||||||
{
|
{
|
||||||
copy_to_user(dest, src, sizeof(T));
|
return copy_to_user(dest, src, sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void copy_from_user(T* dest, Userspace<const T*> src)
|
[[nodiscard]] inline bool copy_from_user(T* dest, Userspace<const T*> src)
|
||||||
{
|
{
|
||||||
copy_from_user(dest, src.unsafe_userspace_ptr(), sizeof(T));
|
return copy_from_user(dest, src.unsafe_userspace_ptr(), sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void copy_to_user(Userspace<T*> dest, const T* src)
|
[[nodiscard]] inline bool copy_to_user(Userspace<T*> dest, const T* src)
|
||||||
{
|
{
|
||||||
copy_to_user(dest.unsafe_userspace_ptr(), src, sizeof(T));
|
return copy_to_user(dest.unsafe_userspace_ptr(), src, sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void copy_to_user(Userspace<T*> dest, const void* src, size_t size)
|
[[nodiscard]] inline bool copy_to_user(Userspace<T*> dest, const void* src, size_t size)
|
||||||
{
|
{
|
||||||
copy_to_user(dest.unsafe_userspace_ptr(), src, size);
|
return copy_to_user(dest.unsafe_userspace_ptr(), src, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void copy_from_user(void* dest, Userspace<const T*> src, size_t size)
|
[[nodiscard]] inline bool copy_from_user(void* dest, Userspace<const T*> src, size_t size)
|
||||||
{
|
{
|
||||||
copy_from_user(dest, src.unsafe_userspace_ptr(), size);
|
return copy_from_user(dest, src.unsafe_userspace_ptr(), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
[[nodiscard]] inline bool copy_n_from_user(T* dest, const T* src, size_t count)
|
||||||
|
{
|
||||||
|
Checked size = sizeof(T);
|
||||||
|
size *= count;
|
||||||
|
if (size.has_overflow())
|
||||||
|
return false;
|
||||||
|
return copy_from_user(dest, src, sizeof(T) * count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
[[nodiscard]] inline bool copy_n_to_user(T* dest, const T* src, size_t count)
|
||||||
|
{
|
||||||
|
Checked size = sizeof(T);
|
||||||
|
size *= count;
|
||||||
|
if (size.has_overflow())
|
||||||
|
return false;
|
||||||
|
return copy_to_user(dest, src, sizeof(T) * count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
[[nodiscard]] inline bool copy_n_from_user(T* dest, Userspace<const T*> src, size_t count)
|
||||||
|
{
|
||||||
|
Checked size = sizeof(T);
|
||||||
|
size *= count;
|
||||||
|
if (size.has_overflow())
|
||||||
|
return false;
|
||||||
|
return copy_from_user(dest, src.unsafe_userspace_ptr(), sizeof(T) * count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
[[nodiscard]] inline bool copy_n_to_user(Userspace<T*> dest, const T* src, size_t count)
|
||||||
|
{
|
||||||
|
Checked size = sizeof(T);
|
||||||
|
size *= count;
|
||||||
|
if (size.has_overflow())
|
||||||
|
return false;
|
||||||
|
return copy_to_user(dest.unsafe_userspace_ptr(), src, sizeof(T) * count);
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,12 +66,11 @@ int Process::sys$getcwd(Userspace<char*> buffer, ssize_t size)
|
||||||
REQUIRE_PROMISE(rpath);
|
REQUIRE_PROMISE(rpath);
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!validate_write(buffer, size))
|
|
||||||
return -EFAULT;
|
|
||||||
auto path = current_directory().absolute_path();
|
auto path = current_directory().absolute_path();
|
||||||
if ((size_t)size < path.length() + 1)
|
if ((size_t)size < path.length() + 1)
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
copy_to_user(buffer, path.characters(), path.length() + 1);
|
if (!copy_to_user(buffer, path.characters(), path.length() + 1))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ int Process::sys$chown(Userspace<const Syscall::SC_chown_params*> user_params)
|
||||||
{
|
{
|
||||||
REQUIRE_PROMISE(chown);
|
REQUIRE_PROMISE(chown);
|
||||||
Syscall::SC_chown_params params;
|
Syscall::SC_chown_params params;
|
||||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
if (!copy_from_user(¶ms, user_params))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
auto path = get_syscall_path_argument(params.path);
|
auto path = get_syscall_path_argument(params.path);
|
||||||
if (path.is_error())
|
if (path.is_error())
|
||||||
|
|
|
@ -32,8 +32,6 @@ namespace Kernel {
|
||||||
int Process::sys$clock_gettime(clockid_t clock_id, Userspace<timespec*> user_ts)
|
int Process::sys$clock_gettime(clockid_t clock_id, Userspace<timespec*> user_ts)
|
||||||
{
|
{
|
||||||
REQUIRE_PROMISE(stdio);
|
REQUIRE_PROMISE(stdio);
|
||||||
if (!validate_write_typed(user_ts))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
timespec ts = {};
|
timespec ts = {};
|
||||||
|
|
||||||
|
@ -49,7 +47,8 @@ int Process::sys$clock_gettime(clockid_t clock_id, Userspace<timespec*> user_ts)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
copy_to_user(user_ts, &ts);
|
if (!copy_to_user(user_ts, &ts))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +60,7 @@ int Process::sys$clock_settime(clockid_t clock_id, Userspace<const timespec*> us
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
timespec ts;
|
timespec ts;
|
||||||
if (!validate_read_and_copy_typed(&ts, user_ts))
|
if (!copy_from_user(&ts, user_ts))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
switch (clock_id) {
|
switch (clock_id) {
|
||||||
|
@ -79,16 +78,11 @@ int Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_par
|
||||||
REQUIRE_PROMISE(stdio);
|
REQUIRE_PROMISE(stdio);
|
||||||
|
|
||||||
Syscall::SC_clock_nanosleep_params params;
|
Syscall::SC_clock_nanosleep_params params;
|
||||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
if (!copy_from_user(¶ms, user_params))
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
if (params.requested_sleep && !validate_read_typed(params.requested_sleep))
|
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
timespec requested_sleep;
|
timespec requested_sleep;
|
||||||
copy_from_user(&requested_sleep, params.requested_sleep);
|
if (!copy_from_user(&requested_sleep, params.requested_sleep))
|
||||||
|
|
||||||
if (params.remaining_sleep && !validate_write_typed(params.remaining_sleep))
|
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
bool is_absolute = params.flags & TIMER_ABSTIME;
|
bool is_absolute = params.flags & TIMER_ABSTIME;
|
||||||
|
@ -109,18 +103,12 @@ int Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_par
|
||||||
if (wakeup_time > g_uptime) {
|
if (wakeup_time > g_uptime) {
|
||||||
u64 ticks_left = wakeup_time - g_uptime;
|
u64 ticks_left = wakeup_time - g_uptime;
|
||||||
if (!is_absolute && params.remaining_sleep) {
|
if (!is_absolute && params.remaining_sleep) {
|
||||||
if (!validate_write_typed(params.remaining_sleep)) {
|
|
||||||
// This can happen because the lock is dropped while
|
|
||||||
// sleeping, thus giving other threads the opportunity
|
|
||||||
// to make the region unwritable.
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
timespec remaining_sleep = {};
|
timespec remaining_sleep = {};
|
||||||
remaining_sleep.tv_sec = ticks_left / TimeManagement::the().ticks_per_second();
|
remaining_sleep.tv_sec = ticks_left / TimeManagement::the().ticks_per_second();
|
||||||
ticks_left -= remaining_sleep.tv_sec * TimeManagement::the().ticks_per_second();
|
ticks_left -= remaining_sleep.tv_sec * TimeManagement::the().ticks_per_second();
|
||||||
remaining_sleep.tv_nsec = ticks_left * 1000000000 / TimeManagement::the().ticks_per_second();
|
remaining_sleep.tv_nsec = ticks_left * 1000000000 / TimeManagement::the().ticks_per_second();
|
||||||
copy_to_user(params.remaining_sleep, &remaining_sleep);
|
if (!copy_to_user(params.remaining_sleep, &remaining_sleep))
|
||||||
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
return -EINTR;
|
return -EINTR;
|
||||||
}
|
}
|
||||||
|
@ -134,10 +122,9 @@ int Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_par
|
||||||
int Process::sys$gettimeofday(Userspace<timeval*> user_tv)
|
int Process::sys$gettimeofday(Userspace<timeval*> user_tv)
|
||||||
{
|
{
|
||||||
REQUIRE_PROMISE(stdio);
|
REQUIRE_PROMISE(stdio);
|
||||||
if (!validate_write_typed(user_tv))
|
|
||||||
return -EFAULT;
|
|
||||||
auto tv = kgettimeofday();
|
auto tv = kgettimeofday();
|
||||||
copy_to_user(user_tv, &tv);
|
if (!copy_to_user(user_tv, &tv))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <Kernel/IO.h>
|
#include <Kernel/IO.h>
|
||||||
#include <Kernel/KSyms.h>
|
#include <Kernel/KSyms.h>
|
||||||
#include <Kernel/Process.h>
|
#include <Kernel/Process.h>
|
||||||
|
#include <Kernel/UserOrKernelBuffer.h>
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
@ -44,13 +45,20 @@ int Process::sys$dbgputch(u8 ch)
|
||||||
|
|
||||||
int Process::sys$dbgputstr(Userspace<const u8*> characters, int length)
|
int Process::sys$dbgputstr(Userspace<const u8*> characters, int length)
|
||||||
{
|
{
|
||||||
if (!length)
|
if (length <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (!validate_read(characters, length))
|
|
||||||
return -EFAULT;
|
|
||||||
SmapDisabler disabler;
|
SmapDisabler disabler;
|
||||||
for (int i = 0; i < length; ++i)
|
auto buffer = UserOrKernelBuffer::for_user_buffer(characters, length);
|
||||||
IO::out8(0xe9, characters.unsafe_userspace_ptr()[i]);
|
if (!buffer.has_value())
|
||||||
|
return -EFAULT;
|
||||||
|
ssize_t nread = buffer.value().read_buffered<1024>(length, [&](const u8* buffer, size_t buffer_size) {
|
||||||
|
for (size_t i = 0; i < buffer_size; ++i)
|
||||||
|
IO::out8(0xe9, buffer[i]);
|
||||||
|
return (ssize_t)buffer_size;
|
||||||
|
});
|
||||||
|
if (nread < 0)
|
||||||
|
return (int)nread;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -423,7 +423,8 @@ KResultOr<NonnullRefPtr<FileDescription>> Process::find_elf_interpreter_for_exec
|
||||||
return KResult(-ENOEXEC);
|
return KResult(-ENOEXEC);
|
||||||
|
|
||||||
memset(first_page, 0, sizeof(first_page));
|
memset(first_page, 0, sizeof(first_page));
|
||||||
auto nread_or_error = interpreter_description->read((u8*)&first_page, sizeof(first_page));
|
auto first_page_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&first_page);
|
||||||
|
auto nread_or_error = interpreter_description->read(first_page_buffer, sizeof(first_page));
|
||||||
if (nread_or_error.is_error())
|
if (nread_or_error.is_error())
|
||||||
return KResult(-ENOEXEC);
|
return KResult(-ENOEXEC);
|
||||||
nread = nread_or_error.value();
|
nread = nread_or_error.value();
|
||||||
|
@ -490,7 +491,8 @@ int Process::exec(String path, Vector<String> arguments, Vector<String> environm
|
||||||
|
|
||||||
// Read the first page of the program into memory so we can validate the binfmt of it
|
// Read the first page of the program into memory so we can validate the binfmt of it
|
||||||
char first_page[PAGE_SIZE];
|
char first_page[PAGE_SIZE];
|
||||||
auto nread_or_error = description->read((u8*)&first_page, sizeof(first_page));
|
auto first_page_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&first_page);
|
||||||
|
auto nread_or_error = description->read(first_page_buffer, sizeof(first_page));
|
||||||
if (nread_or_error.is_error())
|
if (nread_or_error.is_error())
|
||||||
return -ENOEXEC;
|
return -ENOEXEC;
|
||||||
|
|
||||||
|
@ -554,7 +556,7 @@ int Process::sys$execve(Userspace<const Syscall::SC_execve_params*> user_params)
|
||||||
// NOTE: Be extremely careful with allocating any kernel memory in exec().
|
// NOTE: Be extremely careful with allocating any kernel memory in exec().
|
||||||
// On success, the kernel stack will be lost.
|
// On success, the kernel stack will be lost.
|
||||||
Syscall::SC_execve_params params;
|
Syscall::SC_execve_params params;
|
||||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
if (!copy_from_user(¶ms, user_params))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
if (params.arguments.length > ARG_MAX || params.environment.length > ARG_MAX)
|
if (params.arguments.length > ARG_MAX || params.environment.length > ARG_MAX)
|
||||||
|
@ -574,13 +576,16 @@ int Process::sys$execve(Userspace<const Syscall::SC_execve_params*> user_params)
|
||||||
auto copy_user_strings = [this](const auto& list, auto& output) {
|
auto copy_user_strings = [this](const auto& list, auto& output) {
|
||||||
if (!list.length)
|
if (!list.length)
|
||||||
return true;
|
return true;
|
||||||
if (!validate_read_typed(list.strings, list.length))
|
Checked size = sizeof(list.length);
|
||||||
|
size *= list.length;
|
||||||
|
if (size.has_overflow())
|
||||||
return false;
|
return false;
|
||||||
Vector<Syscall::StringArgument, 32> strings;
|
Vector<Syscall::StringArgument, 32> strings;
|
||||||
strings.resize(list.length);
|
strings.resize(list.length);
|
||||||
copy_from_user(strings.data(), list.strings.unsafe_userspace_ptr(), list.length * sizeof(Syscall::StringArgument));
|
if (!copy_from_user(strings.data(), list.strings, list.length * sizeof(Syscall::StringArgument)))
|
||||||
|
return false;
|
||||||
for (size_t i = 0; i < list.length; ++i) {
|
for (size_t i = 0; i < list.length; ++i) {
|
||||||
auto string = validate_and_copy_string_from_user(strings[i]);
|
auto string = copy_string_from_user(strings[i]);
|
||||||
if (string.is_null())
|
if (string.is_null())
|
||||||
return false;
|
return false;
|
||||||
output.append(move(string));
|
output.append(move(string));
|
||||||
|
|
|
@ -55,21 +55,19 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
|
||||||
REQUIRE_PROMISE(thread);
|
REQUIRE_PROMISE(thread);
|
||||||
|
|
||||||
Syscall::SC_futex_params params;
|
Syscall::SC_futex_params params;
|
||||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
if (!copy_from_user(¶ms, user_params))
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
if (!validate_read_typed(params.userspace_address))
|
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
switch (params.futex_op) {
|
switch (params.futex_op) {
|
||||||
case FUTEX_WAIT: {
|
case FUTEX_WAIT: {
|
||||||
i32 user_value;
|
i32 user_value;
|
||||||
copy_from_user(&user_value, params.userspace_address);
|
if (!copy_from_user(&user_value, params.userspace_address))
|
||||||
|
return -EFAULT;
|
||||||
if (user_value != params.val)
|
if (user_value != params.val)
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
timespec ts_abstimeout { 0, 0 };
|
timespec ts_abstimeout { 0, 0 };
|
||||||
if (params.timeout && !validate_read_and_copy_typed(&ts_abstimeout, params.timeout))
|
if (params.timeout && !copy_from_user(&ts_abstimeout, params.timeout))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
timeval* optional_timeout = nullptr;
|
timeval* optional_timeout = nullptr;
|
||||||
|
@ -80,7 +78,7 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This is supposed to be interruptible by a signal, but right now WaitQueue cannot be interrupted.
|
// FIXME: This is supposed to be interruptible by a signal, but right now WaitQueue cannot be interrupted.
|
||||||
WaitQueue& wait_queue = futex_queue(params.userspace_address);
|
WaitQueue& wait_queue = futex_queue((FlatPtr)params.userspace_address);
|
||||||
Thread::BlockResult result = Thread::current()->wait_on(wait_queue, "Futex", optional_timeout);
|
Thread::BlockResult result = Thread::current()->wait_on(wait_queue, "Futex", optional_timeout);
|
||||||
if (result == Thread::BlockResult::InterruptedByTimeout) {
|
if (result == Thread::BlockResult::InterruptedByTimeout) {
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
|
@ -92,9 +90,9 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
|
||||||
if (params.val == 0)
|
if (params.val == 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (params.val == 1) {
|
if (params.val == 1) {
|
||||||
futex_queue(params.userspace_address).wake_one();
|
futex_queue((FlatPtr)params.userspace_address).wake_one();
|
||||||
} else {
|
} else {
|
||||||
futex_queue(params.userspace_address).wake_n(params.val);
|
futex_queue((FlatPtr)params.userspace_address).wake_n(params.val);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,12 +34,13 @@ ssize_t Process::sys$get_dir_entries(int fd, void* buffer, ssize_t size)
|
||||||
REQUIRE_PROMISE(stdio);
|
REQUIRE_PROMISE(stdio);
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!validate_write(buffer, size))
|
|
||||||
return -EFAULT;
|
|
||||||
auto description = file_description(fd);
|
auto description = file_description(fd);
|
||||||
if (!description)
|
if (!description)
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
return description->get_dir_entries((u8*)buffer, size);
|
auto user_buffer = UserOrKernelBuffer::for_user_buffer((u8*)buffer, size);
|
||||||
|
if (!user_buffer.has_value())
|
||||||
|
return -EFAULT;
|
||||||
|
return description->get_dir_entries(user_buffer.value(), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,11 +31,6 @@ namespace Kernel {
|
||||||
|
|
||||||
int Process::sys$get_stack_bounds(FlatPtr* user_stack_base, size_t* user_stack_size)
|
int Process::sys$get_stack_bounds(FlatPtr* user_stack_base, size_t* user_stack_size)
|
||||||
{
|
{
|
||||||
if (!validate_write_typed(user_stack_base))
|
|
||||||
return -EFAULT;
|
|
||||||
if (!validate_write_typed(user_stack_size))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
FlatPtr stack_pointer = Thread::current()->get_register_dump_from_stack().userspace_esp;
|
FlatPtr stack_pointer = Thread::current()->get_register_dump_from_stack().userspace_esp;
|
||||||
auto* stack_region = MM.find_region_from_vaddr(*this, VirtualAddress(stack_pointer));
|
auto* stack_region = MM.find_region_from_vaddr(*this, VirtualAddress(stack_pointer));
|
||||||
if (!stack_region) {
|
if (!stack_region) {
|
||||||
|
@ -45,8 +40,10 @@ int Process::sys$get_stack_bounds(FlatPtr* user_stack_base, size_t* user_stack_s
|
||||||
|
|
||||||
FlatPtr stack_base = stack_region->range().base().get();
|
FlatPtr stack_base = stack_region->range().base().get();
|
||||||
size_t stack_size = stack_region->size();
|
size_t stack_size = stack_region->size();
|
||||||
copy_to_user(user_stack_base, &stack_base);
|
if (!copy_to_user(user_stack_base, &stack_base))
|
||||||
copy_to_user(user_stack_size, &stack_size);
|
return -EFAULT;
|
||||||
|
if (!copy_to_user(user_stack_size, &stack_size))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include <Kernel/Process.h>
|
#include <Kernel/Process.h>
|
||||||
#include <Kernel/Random.h>
|
#include <Kernel/Random.h>
|
||||||
|
#include <Kernel/UserOrKernelBuffer.h>
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
@ -38,13 +39,15 @@ ssize_t Process::sys$getrandom(Userspace<void*> buffer, size_t buffer_size, [[ma
|
||||||
if (buffer_size <= 0)
|
if (buffer_size <= 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!validate_write(buffer, buffer_size))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
SmapDisabler disabler;
|
SmapDisabler disabler;
|
||||||
// FIXME: We should really push Userspace<T> down through the interface.
|
auto data_buffer = UserOrKernelBuffer::for_user_buffer(buffer, buffer_size);
|
||||||
get_good_random_bytes((u8*)buffer.ptr(), buffer_size);
|
if (!data_buffer.has_value())
|
||||||
return 0;
|
return -EFAULT;
|
||||||
|
ssize_t nwritten = data_buffer.value().write_buffered<1024>(buffer_size, [&](u8* buffer, size_t buffer_bytes) {
|
||||||
|
get_good_random_bytes(buffer, buffer_bytes);
|
||||||
|
return (ssize_t)buffer_bytes;
|
||||||
|
});
|
||||||
|
return nwritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,22 +55,16 @@ gid_t Process::sys$getegid()
|
||||||
int Process::sys$getresuid(Userspace<uid_t*> ruid, Userspace<uid_t*> euid, Userspace<uid_t*> suid)
|
int Process::sys$getresuid(Userspace<uid_t*> ruid, Userspace<uid_t*> euid, Userspace<uid_t*> suid)
|
||||||
{
|
{
|
||||||
REQUIRE_PROMISE(stdio);
|
REQUIRE_PROMISE(stdio);
|
||||||
if (!validate_write_typed(ruid) || !validate_write_typed(euid) || !validate_write_typed(suid))
|
if (!copy_to_user(ruid, &m_uid) || !copy_to_user(euid, &m_euid) || !copy_to_user(suid, &m_suid))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
copy_to_user(ruid, &m_uid);
|
|
||||||
copy_to_user(euid, &m_euid);
|
|
||||||
copy_to_user(suid, &m_suid);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Process::sys$getresgid(Userspace<gid_t*> rgid, Userspace<gid_t*> egid, Userspace<gid_t*> sgid)
|
int Process::sys$getresgid(Userspace<gid_t*> rgid, Userspace<gid_t*> egid, Userspace<gid_t*> sgid)
|
||||||
{
|
{
|
||||||
REQUIRE_PROMISE(stdio);
|
REQUIRE_PROMISE(stdio);
|
||||||
if (!validate_write_typed(rgid) || !validate_write_typed(egid) || !validate_write_typed(sgid))
|
if (!copy_to_user(rgid, &m_gid) || !copy_to_user(egid, &m_egid) || !copy_to_user(sgid, &m_sgid))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
copy_to_user(rgid, &m_gid);
|
|
||||||
copy_to_user(egid, &m_egid);
|
|
||||||
copy_to_user(sgid, &m_sgid);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,10 +77,9 @@ int Process::sys$getgroups(ssize_t count, Userspace<gid_t*> user_gids)
|
||||||
return m_extra_gids.size();
|
return m_extra_gids.size();
|
||||||
if (count != (int)m_extra_gids.size())
|
if (count != (int)m_extra_gids.size())
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!validate_write_typed(user_gids, m_extra_gids.size()))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
copy_to_user(user_gids, m_extra_gids.data(), sizeof(gid_t) * count);
|
if (!copy_to_user(user_gids, m_extra_gids.data(), sizeof(gid_t) * count))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,12 +36,11 @@ int Process::sys$gethostname(Userspace<char*> buffer, ssize_t size)
|
||||||
REQUIRE_PROMISE(stdio);
|
REQUIRE_PROMISE(stdio);
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!validate_write(buffer, size))
|
|
||||||
return -EFAULT;
|
|
||||||
LOCKER(*g_hostname_lock, Lock::Mode::Shared);
|
LOCKER(*g_hostname_lock, Lock::Mode::Shared);
|
||||||
if ((size_t)size < (g_hostname->length() + 1))
|
if ((size_t)size < (g_hostname->length() + 1))
|
||||||
return -ENAMETOOLONG;
|
return -ENAMETOOLONG;
|
||||||
copy_to_user(buffer, g_hostname->characters(), g_hostname->length() + 1);
|
if (!copy_to_user(buffer, g_hostname->characters(), g_hostname->length() + 1))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +54,10 @@ int Process::sys$sethostname(Userspace<const char*> hostname, ssize_t length)
|
||||||
LOCKER(*g_hostname_lock, Lock::Mode::Exclusive);
|
LOCKER(*g_hostname_lock, Lock::Mode::Exclusive);
|
||||||
if (length > 64)
|
if (length > 64)
|
||||||
return -ENAMETOOLONG;
|
return -ENAMETOOLONG;
|
||||||
*g_hostname = validate_and_copy_string_from_user(hostname, length);
|
auto copied_hostname = copy_string_from_user(hostname, length);
|
||||||
|
if (copied_hostname.is_null())
|
||||||
|
return -EFAULT;
|
||||||
|
*g_hostname = move(copied_hostname);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,11 +34,13 @@ int Process::sys$link(Userspace<const Syscall::SC_link_params*> user_params)
|
||||||
{
|
{
|
||||||
REQUIRE_PROMISE(cpath);
|
REQUIRE_PROMISE(cpath);
|
||||||
Syscall::SC_link_params params;
|
Syscall::SC_link_params params;
|
||||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
if (!copy_from_user(¶ms, user_params))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
auto old_path = validate_and_copy_string_from_user(params.old_path);
|
auto old_path = copy_string_from_user(params.old_path);
|
||||||
auto new_path = validate_and_copy_string_from_user(params.new_path);
|
if (old_path.is_null())
|
||||||
if (old_path.is_null() || new_path.is_null())
|
return -EFAULT;
|
||||||
|
auto new_path = copy_string_from_user(params.new_path);
|
||||||
|
if (new_path.is_null())
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
return VFS::the().link(old_path, new_path, current_directory());
|
return VFS::the().link(old_path, new_path, current_directory());
|
||||||
}
|
}
|
||||||
|
@ -47,7 +49,7 @@ int Process::sys$symlink(Userspace<const Syscall::SC_symlink_params*> user_param
|
||||||
{
|
{
|
||||||
REQUIRE_PROMISE(cpath);
|
REQUIRE_PROMISE(cpath);
|
||||||
Syscall::SC_symlink_params params;
|
Syscall::SC_symlink_params params;
|
||||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
if (!copy_from_user(¶ms, user_params))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
auto target = get_syscall_path_argument(params.target);
|
auto target = get_syscall_path_argument(params.target);
|
||||||
if (target.is_error())
|
if (target.is_error())
|
||||||
|
|
|
@ -34,7 +34,7 @@ int Process::sys$mknod(Userspace<const Syscall::SC_mknod_params*> user_params)
|
||||||
{
|
{
|
||||||
REQUIRE_PROMISE(dpath);
|
REQUIRE_PROMISE(dpath);
|
||||||
Syscall::SC_mknod_params params;
|
Syscall::SC_mknod_params params;
|
||||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
if (!copy_from_user(¶ms, user_params))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (!is_superuser() && !is_regular_file(params.mode) && !is_fifo(params.mode) && !is_socket(params.mode))
|
if (!is_superuser() && !is_regular_file(params.mode) && !is_fifo(params.mode) && !is_socket(params.mode))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
|
@ -81,7 +81,7 @@ void* Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> user_params)
|
||||||
REQUIRE_PROMISE(stdio);
|
REQUIRE_PROMISE(stdio);
|
||||||
|
|
||||||
Syscall::SC_mmap_params params;
|
Syscall::SC_mmap_params params;
|
||||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
if (!copy_from_user(¶ms, user_params))
|
||||||
return (void*)-EFAULT;
|
return (void*)-EFAULT;
|
||||||
|
|
||||||
void* addr = (void*)params.addr;
|
void* addr = (void*)params.addr;
|
||||||
|
@ -102,7 +102,7 @@ void* Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> user_params)
|
||||||
if (params.name.characters) {
|
if (params.name.characters) {
|
||||||
if (params.name.length > PATH_MAX)
|
if (params.name.length > PATH_MAX)
|
||||||
return (void*)-ENAMETOOLONG;
|
return (void*)-ENAMETOOLONG;
|
||||||
name = validate_and_copy_string_from_user(params.name);
|
name = copy_string_from_user(params.name);
|
||||||
if (name.is_null())
|
if (name.is_null())
|
||||||
return (void*)-EFAULT;
|
return (void*)-EFAULT;
|
||||||
}
|
}
|
||||||
|
@ -336,13 +336,13 @@ int Process::sys$set_mmap_name(Userspace<const Syscall::SC_set_mmap_name_params*
|
||||||
REQUIRE_PROMISE(stdio);
|
REQUIRE_PROMISE(stdio);
|
||||||
|
|
||||||
Syscall::SC_set_mmap_name_params params;
|
Syscall::SC_set_mmap_name_params params;
|
||||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
if (!copy_from_user(¶ms, user_params))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
if (params.name.length > PATH_MAX)
|
if (params.name.length > PATH_MAX)
|
||||||
return -ENAMETOOLONG;
|
return -ENAMETOOLONG;
|
||||||
|
|
||||||
auto name = validate_and_copy_string_from_user(params.name);
|
auto name = copy_string_from_user(params.name);
|
||||||
if (name.is_null())
|
if (name.is_null())
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
|
@ -351,7 +351,7 @@ int Process::sys$set_mmap_name(Userspace<const Syscall::SC_set_mmap_name_params*
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!region->is_mmap())
|
if (!region->is_mmap())
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
region->set_name(name);
|
region->set_name(move(name));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -169,7 +169,7 @@ int Process::sys$module_unload(Userspace<const char*> user_name, size_t name_len
|
||||||
|
|
||||||
REQUIRE_NO_PROMISES;
|
REQUIRE_NO_PROMISES;
|
||||||
|
|
||||||
auto module_name = validate_and_copy_string_from_user(user_name, name_length);
|
auto module_name = copy_string_from_user(user_name, name_length);
|
||||||
if (module_name.is_null())
|
if (module_name.is_null())
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue