1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 08:24:58 +00:00

Kernel+LibC: Pass 64-bit integers in syscalls by value

Now that support for 32-bit x86 has been removed, we don't have to worry
about the top half of `off_t`/`u64` values being chopped off when we try
to pass them in registers. Therefore, we no longer need the workaround
of pointers to stack-allocated values to syscalls.

Note that this changes the system call ABI, so statically linked
programs will have to be re-linked.
This commit is contained in:
Daniel Bertalan 2023-08-11 10:47:31 +02:00
parent 87f4b0f1c2
commit 286984750e
12 changed files with 22 additions and 37 deletions

View file

@ -13,16 +13,14 @@
namespace Kernel { namespace Kernel {
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fallocate.html // https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fallocate.html
ErrorOr<FlatPtr> Process::sys$posix_fallocate(int fd, Userspace<off_t const*> userspace_offset, Userspace<off_t const*> userspace_length) ErrorOr<FlatPtr> Process::sys$posix_fallocate(int fd, off_t offset, off_t length)
{ {
VERIFY_NO_PROCESS_BIG_LOCK(this); VERIFY_NO_PROCESS_BIG_LOCK(this);
TRY(require_promise(Pledge::stdio)); TRY(require_promise(Pledge::stdio));
// [EINVAL] The len argument is less than zero, or the offset argument is less than zero, or the underlying file system does not support this operation. // [EINVAL] The len argument is less than zero, or the offset argument is less than zero, or the underlying file system does not support this operation.
auto offset = TRY(copy_typed_from_user(userspace_offset));
if (offset < 0) if (offset < 0)
return EINVAL; return EINVAL;
auto length = TRY(copy_typed_from_user(userspace_length));
if (length <= 0) if (length <= 0)
return EINVAL; return EINVAL;

View file

@ -9,13 +9,10 @@
namespace Kernel { namespace Kernel {
// NOTE: The length is passed by pointer because off_t is 64bit, ErrorOr<FlatPtr> Process::sys$ftruncate(int fd, off_t length)
// hence it can't be passed by register on 32bit platforms.
ErrorOr<FlatPtr> Process::sys$ftruncate(int fd, Userspace<off_t const*> userspace_length)
{ {
VERIFY_NO_PROCESS_BIG_LOCK(this); VERIFY_NO_PROCESS_BIG_LOCK(this);
TRY(require_promise(Pledge::stdio)); TRY(require_promise(Pledge::stdio));
auto length = TRY(copy_typed_from_user(userspace_length));
if (length < 0) if (length < 0)
return EINVAL; return EINVAL;
auto description = TRY(open_file_description(fd)); auto description = TRY(open_file_description(fd));

View file

@ -16,14 +16,11 @@ bool g_profiling_all_threads;
PerformanceEventBuffer* g_global_perf_events; PerformanceEventBuffer* g_global_perf_events;
u64 g_profiling_event_mask; u64 g_profiling_event_mask;
// NOTE: event_mask needs to be passed as a pointer as u64 ErrorOr<FlatPtr> Process::sys$profiling_enable(pid_t pid, u64 event_mask)
// does not fit into a register on 32bit architectures.
ErrorOr<FlatPtr> Process::sys$profiling_enable(pid_t pid, Userspace<u64 const*> userspace_event_mask)
{ {
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
TRY(require_no_promises()); TRY(require_no_promises());
auto const event_mask = TRY(copy_typed_from_user(userspace_event_mask));
return profiling_enable(pid, event_mask); return profiling_enable(pid, event_mask);
} }

View file

@ -101,9 +101,7 @@ ErrorOr<FlatPtr> Process::read_impl(int fd, Userspace<u8*> buffer, size_t size)
return TRY(description->read(user_buffer, size)); return TRY(description->read(user_buffer, size));
} }
// NOTE: The offset is passed by pointer because off_t is 64bit, ErrorOr<FlatPtr> Process::sys$pread(int fd, Userspace<u8*> buffer, size_t size, off_t offset)
// hence it can't be passed by register on 32bit platforms.
ErrorOr<FlatPtr> Process::sys$pread(int fd, Userspace<u8*> buffer, size_t size, Userspace<off_t const*> userspace_offset)
{ {
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
TRY(require_promise(Pledge::stdio)); TRY(require_promise(Pledge::stdio));
@ -111,7 +109,6 @@ ErrorOr<FlatPtr> Process::sys$pread(int fd, Userspace<u8*> buffer, size_t size,
return 0; return 0;
if (size > NumericLimits<ssize_t>::max()) if (size > NumericLimits<ssize_t>::max())
return EINVAL; return EINVAL;
auto offset = TRY(copy_typed_from_user(userspace_offset));
if (offset < 0) if (offset < 0)
return EINVAL; return EINVAL;
dbgln_if(IO_DEBUG, "sys$pread({}, {}, {}, {})", fd, buffer.ptr(), size, offset); dbgln_if(IO_DEBUG, "sys$pread({}, {}, {}, {})", fd, buffer.ptr(), size, offset);

View file

@ -11,9 +11,7 @@
namespace Kernel { namespace Kernel {
// NOTE: The offset is passed by pointer because off_t is 64bit, ErrorOr<FlatPtr> Process::sys$pwritev(int fd, Userspace<const struct iovec*> iov, int iov_count, off_t base_offset)
// hence it can't be passed by register on 32bit platforms.
ErrorOr<FlatPtr> Process::sys$pwritev(int fd, Userspace<const struct iovec*> iov, int iov_count, Userspace<off_t const*> userspace_offset)
{ {
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
TRY(require_promise(Pledge::stdio)); TRY(require_promise(Pledge::stdio));
@ -33,11 +31,10 @@ ErrorOr<FlatPtr> Process::sys$pwritev(int fd, Userspace<const struct iovec*> iov
return EINVAL; return EINVAL;
} }
// NOTE: Negative offset means "operate like writev" which seeks the file.
auto base_offset = TRY(copy_typed_from_user(userspace_offset));
auto description = TRY(open_file_description(fd)); auto description = TRY(open_file_description(fd));
if (!description->is_writable()) if (!description->is_writable())
return EBADF; return EBADF;
// NOTE: Negative offset means "operate like writev" which seeks the file.
if (base_offset >= 0 && !description->file().is_seekable()) if (base_offset >= 0 && !description->file().is_seekable())
return EINVAL; return EINVAL;

View file

@ -337,17 +337,17 @@ public:
ErrorOr<FlatPtr> sys$open(Userspace<Syscall::SC_open_params const*>); ErrorOr<FlatPtr> sys$open(Userspace<Syscall::SC_open_params const*>);
ErrorOr<FlatPtr> sys$close(int fd); ErrorOr<FlatPtr> sys$close(int fd);
ErrorOr<FlatPtr> sys$read(int fd, Userspace<u8*>, size_t); ErrorOr<FlatPtr> sys$read(int fd, Userspace<u8*>, size_t);
ErrorOr<FlatPtr> sys$pread(int fd, Userspace<u8*>, size_t, Userspace<off_t const*>); ErrorOr<FlatPtr> sys$pread(int fd, Userspace<u8*>, size_t, off_t);
ErrorOr<FlatPtr> sys$readv(int fd, Userspace<const struct iovec*> iov, int iov_count); ErrorOr<FlatPtr> sys$readv(int fd, Userspace<const struct iovec*> iov, int iov_count);
ErrorOr<FlatPtr> sys$write(int fd, Userspace<u8 const*>, size_t); ErrorOr<FlatPtr> sys$write(int fd, Userspace<u8 const*>, size_t);
ErrorOr<FlatPtr> sys$pwritev(int fd, Userspace<const struct iovec*> iov, int iov_count, Userspace<off_t const*>); ErrorOr<FlatPtr> sys$pwritev(int fd, Userspace<const struct iovec*> iov, int iov_count, off_t);
ErrorOr<FlatPtr> sys$fstat(int fd, Userspace<stat*>); ErrorOr<FlatPtr> sys$fstat(int fd, Userspace<stat*>);
ErrorOr<FlatPtr> sys$stat(Userspace<Syscall::SC_stat_params const*>); ErrorOr<FlatPtr> sys$stat(Userspace<Syscall::SC_stat_params const*>);
ErrorOr<FlatPtr> sys$annotate_mapping(Userspace<void*>, int flags); ErrorOr<FlatPtr> sys$annotate_mapping(Userspace<void*>, int flags);
ErrorOr<FlatPtr> sys$lseek(int fd, Userspace<off_t*>, int whence); ErrorOr<FlatPtr> sys$lseek(int fd, Userspace<off_t*>, int whence);
ErrorOr<FlatPtr> sys$ftruncate(int fd, Userspace<off_t const*>); ErrorOr<FlatPtr> sys$ftruncate(int fd, off_t);
ErrorOr<FlatPtr> sys$futimens(Userspace<Syscall::SC_futimens_params const*>); ErrorOr<FlatPtr> sys$futimens(Userspace<Syscall::SC_futimens_params const*>);
ErrorOr<FlatPtr> sys$posix_fallocate(int fd, Userspace<off_t const*>, Userspace<off_t const*>); ErrorOr<FlatPtr> sys$posix_fallocate(int fd, off_t, off_t);
ErrorOr<FlatPtr> sys$kill(pid_t pid_or_pgid, int sig); ErrorOr<FlatPtr> sys$kill(pid_t pid_or_pgid, int sig);
[[noreturn]] void sys$exit(int status); [[noreturn]] void sys$exit(int status);
ErrorOr<FlatPtr> sys$sigreturn(RegisterState& registers); ErrorOr<FlatPtr> sys$sigreturn(RegisterState& registers);
@ -443,7 +443,7 @@ public:
ErrorOr<FlatPtr> sys$getrandom(Userspace<void*>, size_t, unsigned int); ErrorOr<FlatPtr> sys$getrandom(Userspace<void*>, size_t, unsigned int);
ErrorOr<FlatPtr> sys$getkeymap(Userspace<Syscall::SC_getkeymap_params const*>); ErrorOr<FlatPtr> sys$getkeymap(Userspace<Syscall::SC_getkeymap_params const*>);
ErrorOr<FlatPtr> sys$setkeymap(Userspace<Syscall::SC_setkeymap_params const*>); ErrorOr<FlatPtr> sys$setkeymap(Userspace<Syscall::SC_setkeymap_params const*>);
ErrorOr<FlatPtr> sys$profiling_enable(pid_t, Userspace<u64 const*>); ErrorOr<FlatPtr> sys$profiling_enable(pid_t, u64);
ErrorOr<FlatPtr> profiling_enable(pid_t, u64 event_mask); ErrorOr<FlatPtr> profiling_enable(pid_t, u64 event_mask);
ErrorOr<FlatPtr> sys$profiling_disable(pid_t); ErrorOr<FlatPtr> sys$profiling_disable(pid_t);
ErrorOr<FlatPtr> sys$profiling_free_buffer(pid_t); ErrorOr<FlatPtr> sys$profiling_free_buffer(pid_t);

View file

@ -213,7 +213,7 @@ private:
u32 virt$pledge(u32); u32 virt$pledge(u32);
int virt$poll(FlatPtr); int virt$poll(FlatPtr);
int virt$profiling_disable(pid_t); int virt$profiling_disable(pid_t);
int virt$profiling_enable(pid_t); int virt$profiling_enable(pid_t, u64);
int virt$purge(int mode); int virt$purge(int mode);
u32 virt$read(int, FlatPtr, ssize_t); u32 virt$read(int, FlatPtr, ssize_t);
int virt$readlink(FlatPtr); int virt$readlink(FlatPtr);

View file

@ -185,7 +185,7 @@ u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3)
case SC_profiling_disable: case SC_profiling_disable:
return virt$profiling_disable(arg1); return virt$profiling_disable(arg1);
case SC_profiling_enable: case SC_profiling_enable:
return virt$profiling_enable(arg1); return virt$profiling_enable(arg1, arg2);
case SC_purge: case SC_purge:
return virt$purge(arg1); return virt$purge(arg1);
case SC_read: case SC_read:
@ -281,9 +281,9 @@ int Emulator::virt$recvfd(int socket, int options)
return syscall(SC_recvfd, socket, options); return syscall(SC_recvfd, socket, options);
} }
int Emulator::virt$profiling_enable(pid_t pid) int Emulator::virt$profiling_enable(pid_t pid, u64 mask)
{ {
return syscall(SC_profiling_enable, pid); return syscall(SC_profiling_enable, pid, mask);
} }
int Emulator::virt$profiling_disable(pid_t pid) int Emulator::virt$profiling_disable(pid_t pid)
@ -474,11 +474,10 @@ int Emulator::virt$get_stack_bounds(FlatPtr base, FlatPtr size)
return 0; return 0;
} }
int Emulator::virt$ftruncate(int fd, FlatPtr length_addr) int Emulator::virt$ftruncate(int fd, off_t length)
{ {
off_t length; off_t length;
mmu().copy_from_vm(&length, length_addr, sizeof(off_t)); return syscall(SC_ftruncate, fd, length);
return syscall(SC_ftruncate, fd, &length);
} }
int Emulator::virt$uname(FlatPtr params_addr) int Emulator::virt$uname(FlatPtr params_addr)

View file

@ -118,7 +118,7 @@ int posix_fadvise(int fd, off_t offset, off_t len, int advice)
int posix_fallocate(int fd, off_t offset, off_t len) int posix_fallocate(int fd, off_t offset, off_t len)
{ {
// posix_fallocate does not set errno. // posix_fallocate does not set errno.
return -static_cast<int>(syscall(SC_posix_fallocate, fd, &offset, &len)); return -static_cast<int>(syscall(SC_posix_fallocate, fd, offset, len));
} }
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimensat.html // https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimensat.html

View file

@ -22,7 +22,7 @@ int disown(pid_t pid)
int profiling_enable(pid_t pid, uint64_t event_mask) int profiling_enable(pid_t pid, uint64_t event_mask)
{ {
int rc = syscall(SC_profiling_enable, pid, &event_mask); int rc = syscall(SC_profiling_enable, pid, event_mask);
__RETURN_WITH_ERRNO(rc, rc, -1); __RETURN_WITH_ERRNO(rc, rc, -1);
} }

View file

@ -28,7 +28,7 @@ ssize_t pwritev(int fd, struct iovec const* iov, int iov_count, off_t offset)
{ {
__pthread_maybe_cancel(); __pthread_maybe_cancel();
int rc = syscall(SC_pwritev, fd, iov, iov_count, &offset); int rc = syscall(SC_pwritev, fd, iov, iov_count, offset);
__RETURN_WITH_ERRNO(rc, rc, -1); __RETURN_WITH_ERRNO(rc, rc, -1);
} }
} }

View file

@ -392,7 +392,7 @@ ssize_t pread(int fd, void* buf, size_t count, off_t offset)
{ {
__pthread_maybe_cancel(); __pthread_maybe_cancel();
int rc = syscall(SC_pread, fd, buf, count, &offset); int rc = syscall(SC_pread, fd, buf, count, offset);
__RETURN_WITH_ERRNO(rc, rc, -1); __RETURN_WITH_ERRNO(rc, rc, -1);
} }
@ -897,7 +897,7 @@ char* getlogin()
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html // https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html
int ftruncate(int fd, off_t length) int ftruncate(int fd, off_t length)
{ {
int rc = syscall(SC_ftruncate, fd, &length); int rc = syscall(SC_ftruncate, fd, length);
__RETURN_WITH_ERRNO(rc, rc, -1); __RETURN_WITH_ERRNO(rc, rc, -1);
} }