Skip to content

Commit

Permalink
FEXLoader: Increase minimum kernel requirement from 5.0 to 5.15
Browse files Browse the repository at this point in the history
Brought up in #4225 where it had issues with Openat2 which was added in
5.8.

The main driving force around minimum kernel version requirement is that
the lowest kernel version in our CI is 5.15. A benefit to this choice is
that this is an LTS release, which is also what Ubuntu 22.04 is
shipping.

Once the single CI machine is fixed to ship something newer then the
next logical choice would be kernel 6.1 which is also LTS, but until
then just lift it to 5.15. This version was released in October 2021,
and is supported by the kernel developers until 2026. Our previous
minimum of 5.0 was released in March 2019, so a two year leap here.

This removes the openat2 workaround that was necessary to pass our CI
since it is no longer necessary.
  • Loading branch information
Sonicadvance1 committed Jan 1, 2025
1 parent 90b1ac4 commit 4cfb811
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 206 deletions.
2 changes: 1 addition & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# FEX - Fast x86 emulation frontend
FEX allows you to run x86 and x86-64 binaries on an AArch64 host, similar to qemu-user and box86.
It has native support for a rootfs overlay, so you don't need to chroot, as well as some thunklibs so it can forward things like GL to the host.
FEX presents a Linux 5.0+ interface to the guest, and supports only AArch64 as a host.
FEX presents a Linux 5.15+ interface to the guest, and supports only AArch64 as a host.
FEX is very much work in progress, so expect things to change.


Expand Down
5 changes: 2 additions & 3 deletions Source/Tools/FEXLoader/FEXLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -439,9 +439,8 @@ int main(int argc, char** argv, char** const envp) {
}

uint32_t KernelVersion = FEX::HLE::SyscallHandler::CalculateHostKernelVersion();
if (KernelVersion < FEX::HLE::SyscallHandler::KernelVersion(4, 17)) {
// We require 4.17 minimum for MAP_FIXED_NOREPLACE
LogMan::Msg::EFmt("FEXLoader requires kernel 4.17 minimum. Expect problems.");
if (KernelVersion < FEX::HLE::SyscallHandler::KernelVersion(5, 15)) {
LogMan::Msg::EFmt("FEXLoader requires kernel 5.15 minimum. Expect problems.");
}

// Before we go any further, set all of our host environment variables that the config has provided
Expand Down
19 changes: 7 additions & 12 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,8 +333,6 @@ FileManager::FileManager(FEXCore::Context::Context* ctx)
ProcFSDev = Buffer.st_dev;
}

uint32_t KernelVersion = FEX::HLE::SyscallHandler::CalculateHostKernelVersion();
HasOpenat2 = KernelVersion >= FEX::HLE::SyscallHandler::KernelVersion(5, 8, 0);
UpdatePID(::getpid());
}

Expand Down Expand Up @@ -648,17 +646,16 @@ uint64_t FileManager::Open(const char* pathname, int flags, uint32_t mode) {

if (!ShouldSkipOpenInEmu(flags)) {
FDPathTmpData TmpFilename;
auto Path = GetEmulatedFDPath(AT_FDCWD, SelfPath, !HasOpenat2, TmpFilename);
auto Path = GetEmulatedFDPath(AT_FDCWD, SelfPath, false, TmpFilename);
if (Path.first != -1) {
FEX::HLE::open_how how = {
.flags = (uint64_t)flags,
.mode = (flags & (O_CREAT | O_TMPFILE)) ? mode & 07777 : 0, // openat2() is stricter about this
.resolve = (Path.first == AT_FDCWD) ? 0u : RESOLVE_IN_ROOT, // AT_FDCWD means it's a thunk and not via RootFS
};
if (HasOpenat2) {
fd = ::syscall(SYSCALL_DEF(openat2), Path.first, Path.second, &how, sizeof(how));
}
if (fd == -1 && (!HasOpenat2 || errno == EXDEV)) {
fd = ::syscall(SYSCALL_DEF(openat2), Path.first, Path.second, &how, sizeof(how));

if (fd == -1 && errno == EXDEV) {
// This means a magic symlink (/proc/foo) was involved. In this case we
// just punt and do the access without RESOLVE_IN_ROOT.
fd = ::syscall(SYSCALL_DEF(openat), Path.first, Path.second, flags, mode);
Expand Down Expand Up @@ -903,17 +900,15 @@ uint64_t FileManager::Openat([[maybe_unused]] int dirfs, const char* pathname, i

if (!ShouldSkipOpenInEmu(flags)) {
FDPathTmpData TmpFilename;
auto Path = GetEmulatedFDPath(dirfs, SelfPath, !HasOpenat2, TmpFilename);
auto Path = GetEmulatedFDPath(dirfs, SelfPath, false, TmpFilename);
if (Path.first != -1) {
FEX::HLE::open_how how = {
.flags = (uint64_t)flags,
.mode = (flags & (O_CREAT | O_TMPFILE)) ? mode & 07777 : 0, // openat2() is stricter about this,
.resolve = (Path.first == AT_FDCWD) ? 0u : RESOLVE_IN_ROOT, // AT_FDCWD means it's a thunk and not via RootFS
};
if (HasOpenat2) {
fd = ::syscall(SYSCALL_DEF(openat2), Path.first, Path.second, &how, sizeof(how));
}
if (fd == -1 && (!HasOpenat2 || errno == EXDEV)) {
fd = ::syscall(SYSCALL_DEF(openat2), Path.first, Path.second, &how, sizeof(how));
if (fd == -1 && errno == EXDEV) {
// This means a magic symlink (/proc/foo) was involved. In this case we
// just punt and do the access without RESOLVE_IN_ROOT.
fd = ::syscall(SYSCALL_DEF(openat), Path.first, Path.second, flags, mode);
Expand Down
1 change: 0 additions & 1 deletion Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,5 @@ class FileManager final {
int64_t RootFSFDInode = 0;
int64_t ProcFDInode = 0;
dev_t ProcFSDev;
bool HasOpenat2;
};
} // namespace FEX::HLE
4 changes: 2 additions & 2 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -808,8 +808,8 @@ uint32_t SyscallHandler::CalculateHostKernelVersion() {
}

uint32_t SyscallHandler::CalculateGuestKernelVersion() {
// We currently only emulate a kernel between the ranges of Kernel 5.0.0 and 6.11.0
return std::max(KernelVersion(5, 0), std::min(KernelVersion(6, 11), GetHostKernelVersion()));
// We currently only emulate a kernel between the ranges of Kernel 5.15.0 and 6.11.0
return std::max(KernelVersion(5, 15), std::min(KernelVersion(6, 11), GetHostKernelVersion()));
}

uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::CpuStateFrame* Frame, FEXCore::HLE::SyscallArguments* Args) {
Expand Down
53 changes: 21 additions & 32 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/FD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,29 +110,22 @@ void RegisterFD(FEX::HLE::SyscallHandler* Handler) {
SYSCALL_ERRNO();
});

if (Handler->IsHostKernelVersionAtLeast(5, 8, 0)) {
// Only exists on kernel 5.8+
REGISTER_SYSCALL_IMPL_FLAGS(faccessat2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
[](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, int mode, int flags) -> uint64_t {
uint64_t Result = FEX::HLE::_SyscallHandler->FM.FAccessat2(dirfd, pathname, mode, flags);
SYSCALL_ERRNO();
});

REGISTER_SYSCALL_IMPL_FLAGS(
openat2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
[](FEXCore::Core::CpuStateFrame* Frame, int dirfs, const char* pathname, struct open_how* how, size_t usize) -> uint64_t {
open_how HostHow {};
size_t HostSize = std::min(sizeof(open_how), usize);
memcpy(&HostHow, how, HostSize);

HostHow.flags = FEX::HLE::RemapFromX86Flags(HostHow.flags);
uint64_t Result = FEX::HLE::_SyscallHandler->FM.Openat2(dirfs, pathname, &HostHow, HostSize);
SYSCALL_ERRNO();
});
} else {
REGISTER_SYSCALL_IMPL(faccessat2, UnimplementedSyscallSafe);
REGISTER_SYSCALL_IMPL(openat2, UnimplementedSyscallSafe);
}
REGISTER_SYSCALL_IMPL_FLAGS(faccessat2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
[](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, int mode, int flags) -> uint64_t {
uint64_t Result = FEX::HLE::_SyscallHandler->FM.FAccessat2(dirfd, pathname, mode, flags);
SYSCALL_ERRNO();
});

REGISTER_SYSCALL_IMPL_FLAGS(openat2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
[](FEXCore::Core::CpuStateFrame* Frame, int dirfs, const char* pathname, struct open_how* how, size_t usize) -> uint64_t {
open_how HostHow {};
size_t HostSize = std::min(sizeof(open_how), usize);
memcpy(&HostHow, how, HostSize);

HostHow.flags = FEX::HLE::RemapFromX86Flags(HostHow.flags);
uint64_t Result = FEX::HLE::_SyscallHandler->FM.Openat2(dirfs, pathname, &HostHow, HostSize);
SYSCALL_ERRNO();
});

REGISTER_SYSCALL_IMPL_FLAGS(eventfd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
[](FEXCore::Core::CpuStateFrame* Frame, uint32_t count) -> uint64_t {
Expand All @@ -155,14 +148,10 @@ void RegisterFD(FEX::HLE::SyscallHandler* Handler) {
SYSCALL_ERRNO();
});

if (Handler->IsHostKernelVersionAtLeast(5, 9, 0)) {
REGISTER_SYSCALL_IMPL_FLAGS(close_range, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
[](FEXCore::Core::CpuStateFrame* Frame, unsigned int first, unsigned int last, unsigned int flags) -> uint64_t {
uint64_t Result = FEX::HLE::_SyscallHandler->FM.CloseRange(first, last, flags);
SYSCALL_ERRNO();
});
} else {
REGISTER_SYSCALL_IMPL(close_range, UnimplementedSyscallSafe);
}
REGISTER_SYSCALL_IMPL_FLAGS(close_range, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
[](FEXCore::Core::CpuStateFrame* Frame, unsigned int first, unsigned int last, unsigned int flags) -> uint64_t {
uint64_t Result = FEX::HLE::_SyscallHandler->FM.CloseRange(first, last, flags);
SYSCALL_ERRNO();
});
}
} // namespace FEX::HLE
Loading

0 comments on commit 4cfb811

Please sign in to comment.