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 {
// 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);
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.
auto offset = TRY(copy_typed_from_user(userspace_offset));
if (offset < 0)
return EINVAL;
auto length = TRY(copy_typed_from_user(userspace_length));
if (length <= 0)
return EINVAL;

View file

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

View file

@ -16,14 +16,11 @@ bool g_profiling_all_threads;
PerformanceEventBuffer* g_global_perf_events;
u64 g_profiling_event_mask;
// NOTE: event_mask needs to be passed as a pointer as u64
// does not fit into a register on 32bit architectures.
ErrorOr<FlatPtr> Process::sys$profiling_enable(pid_t pid, Userspace<u64 const*> userspace_event_mask)
ErrorOr<FlatPtr> Process::sys$profiling_enable(pid_t pid, u64 event_mask)
{
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
TRY(require_no_promises());
auto const event_mask = TRY(copy_typed_from_user(userspace_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));
}
// NOTE: The offset is passed by pointer because off_t is 64bit,
// 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)
ErrorOr<FlatPtr> Process::sys$pread(int fd, Userspace<u8*> buffer, size_t size, off_t offset)
{
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
TRY(require_promise(Pledge::stdio));
@ -111,7 +109,6 @@ ErrorOr<FlatPtr> Process::sys$pread(int fd, Userspace<u8*> buffer, size_t size,
return 0;
if (size > NumericLimits<ssize_t>::max())
return EINVAL;
auto offset = TRY(copy_typed_from_user(userspace_offset));
if (offset < 0)
return EINVAL;
dbgln_if(IO_DEBUG, "sys$pread({}, {}, {}, {})", fd, buffer.ptr(), size, offset);

View file

@ -11,9 +11,7 @@
namespace Kernel {
// NOTE: The offset is passed by pointer because off_t is 64bit,
// 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)
ErrorOr<FlatPtr> Process::sys$pwritev(int fd, Userspace<const struct iovec*> iov, int iov_count, off_t base_offset)
{
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
TRY(require_promise(Pledge::stdio));
@ -33,11 +31,10 @@ ErrorOr<FlatPtr> Process::sys$pwritev(int fd, Userspace<const struct iovec*> iov
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));
if (!description->is_writable())
return EBADF;
// NOTE: Negative offset means "operate like writev" which seeks the file.
if (base_offset >= 0 && !description->file().is_seekable())
return EINVAL;

View file

@ -337,17 +337,17 @@ public:
ErrorOr<FlatPtr> sys$open(Userspace<Syscall::SC_open_params const*>);
ErrorOr<FlatPtr> sys$close(int fd);
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$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$stat(Userspace<Syscall::SC_stat_params const*>);
ErrorOr<FlatPtr> sys$annotate_mapping(Userspace<void*>, int flags);
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$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);
[[noreturn]] void sys$exit(int status);
ErrorOr<FlatPtr> sys$sigreturn(RegisterState& registers);
@ -443,7 +443,7 @@ public:
ErrorOr<FlatPtr> sys$getrandom(Userspace<void*>, size_t, unsigned int);
ErrorOr<FlatPtr> sys$getkeymap(Userspace<Syscall::SC_getkeymap_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> sys$profiling_disable(pid_t);
ErrorOr<FlatPtr> sys$profiling_free_buffer(pid_t);

View file

@ -213,7 +213,7 @@ private:
u32 virt$pledge(u32);
int virt$poll(FlatPtr);
int virt$profiling_disable(pid_t);
int virt$profiling_enable(pid_t);
int virt$profiling_enable(pid_t, u64);
int virt$purge(int mode);
u32 virt$read(int, FlatPtr, ssize_t);
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:
return virt$profiling_disable(arg1);
case SC_profiling_enable:
return virt$profiling_enable(arg1);
return virt$profiling_enable(arg1, arg2);
case SC_purge:
return virt$purge(arg1);
case SC_read:
@ -281,9 +281,9 @@ int Emulator::virt$recvfd(int socket, int 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)
@ -474,11 +474,10 @@ int Emulator::virt$get_stack_bounds(FlatPtr base, FlatPtr size)
return 0;
}
int Emulator::virt$ftruncate(int fd, FlatPtr length_addr)
int Emulator::virt$ftruncate(int fd, 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)

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)
{
// 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

View file

@ -22,7 +22,7 @@ int disown(pid_t pid)
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);
}

View file

@ -28,7 +28,7 @@ ssize_t pwritev(int fd, struct iovec const* iov, int iov_count, off_t offset)
{
__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);
}
}

View file

@ -392,7 +392,7 @@ ssize_t pread(int fd, void* buf, size_t count, off_t offset)
{
__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);
}
@ -897,7 +897,7 @@ char* getlogin()
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html
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);
}