Przeglądaj źródła

AK+Userland: Stub out code that isn't currently implemented on AARCH64

Even though this almost certainly wouldn't run properly even if we had
a working kernel for AARCH64 this at least lets us build all the
userland binaries.
Gunnar Beutner 2 lat temu
rodzic
commit
31bd5b1a02

+ 1 - 0
AK/Assertions.h

@@ -24,4 +24,5 @@ extern "C" __attribute__((noreturn)) void ak_verification_failed(char const*);
 #    define VERIFY_NOT_REACHED() VERIFY(false) /* NOLINT(cert-dcl03-c,misc-static-assert) No, this can't be static_assert, it's a runtime check */
 static constexpr bool TODO = false;
 #    define TODO() VERIFY(TODO)                /* NOLINT(cert-dcl03-c,misc-static-assert) No, this can't be static_assert, it's a runtime check */
+#    define TODO_AARCH64() VERIFY(TODO)        /* NOLINT(cert-dcl03-c,misc-static-assert) No, this can't be static_assert, it's a runtime check */
 #endif

+ 23 - 0
Tests/Kernel/crash.cpp

@@ -200,7 +200,14 @@ int main(int argc, char** argv)
                 return Crash::Failure::UnexpectedError;
 
             u8* makeshift_esp = makeshift_stack + 2048;
+#if ARCH(I386) || ARCH(X86_64)
             asm volatile("mov %%eax, %%esp" ::"a"(makeshift_esp));
+#elif ARCH(AARCH64)
+            (void)makeshift_esp;
+            TODO_AARCH64();
+#else
+#    error Unknown architecture
+#endif
             getuid();
             dbgln("Survived syscall with MAP_STACK stack");
 
@@ -209,7 +216,14 @@ int main(int argc, char** argv)
                 return Crash::Failure::UnexpectedError;
 
             u8* bad_esp = bad_stack + 2048;
+#if ARCH(I386) || ARCH(X86_64)
             asm volatile("mov %%eax, %%esp" ::"a"(bad_esp));
+#elif ARCH(AARCH64)
+            (void)bad_esp;
+            TODO_AARCH64();
+#else
+#    error Unknown architecture
+#endif
             getuid();
             return Crash::Failure::DidNotCrash;
         }).run(run_type);
@@ -228,6 +242,9 @@ int main(int argc, char** argv)
 #elif ARCH(X86_64)
             asm volatile("movq %%rax, %%rsp" ::"a"(bad_esp));
             asm volatile("pushq $0");
+#elif ARCH(AARCH64)
+            (void)bad_esp;
+            TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif
@@ -267,7 +284,13 @@ int main(int argc, char** argv)
 
     if (do_trigger_user_mode_instruction_prevention) {
         any_failures |= !Crash("Trigger x86 User Mode Instruction Prevention", []() {
+#if ARCH(I386) || ARCH(X86_64)
             asm volatile("str %eax");
+#elif ARCH(AARCH64)
+            TODO_AARCH64();
+#else
+#    error Unknown architecture
+#endif
             return Crash::Failure::DidNotCrash;
         }).run(run_type);
     }

+ 3 - 0
Userland/Applications/CrashReporter/main.cpp

@@ -120,6 +120,9 @@ static TitleAndText build_cpu_registers(const ELF::Core::ThreadInfo& thread_info
     builder.appendff(" r8={:p}  r9={:p} r10={:p} r11={:p}\n", regs.r8, regs.r9, regs.r10, regs.r11);
     builder.appendff("r12={:p} r13={:p} r14={:p} r15={:p}\n", regs.r12, regs.r13, regs.r14, regs.r15);
     builder.appendff("rip={:p} rflags={:p}", regs.rip, regs.rflags);
+#elif ARCH(AARCH64)
+    (void)regs;
+    TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif

+ 6 - 0
Userland/Applications/Debugger/main.cpp

@@ -49,6 +49,9 @@ static void handle_print_registers(PtraceRegisters const& regs)
     outln("r8 ={:p} r9 ={:p} r10={:p} r11={:p}", regs.r8, regs.r9, regs.r10, regs.r11);
     outln("r12={:p} r13={:p} r14={:p} r15={:p}", regs.r12, regs.r13, regs.r14, regs.r15);
     outln("rip={:p} rflags={:p}", regs.rip, regs.rflags);
+#elif ARCH(AARCH64)
+    (void)regs;
+    TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif
@@ -250,6 +253,9 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
         const FlatPtr ip = regs.eip;
 #elif ARCH(X86_64)
         const FlatPtr ip = regs.rip;
+#elif ARCH(AARCH64)
+        const FlatPtr ip = 0; // FIXME
+        TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif

+ 5 - 0
Userland/DevTools/HackStudio/Debugger/RegistersModel.cpp

@@ -51,6 +51,8 @@ RegistersModel::RegistersModel(PtraceRegisters const& regs)
     m_registers.append({ "es", regs.es });
     m_registers.append({ "fs", regs.fs });
     m_registers.append({ "gs", regs.gs });
+#elif ARCH(AARCH64)
+    TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif
@@ -97,6 +99,9 @@ RegistersModel::RegistersModel(PtraceRegisters const& current_regs, PtraceRegist
     m_registers.append({ "es", current_regs.es, current_regs.es != previous_regs.es });
     m_registers.append({ "fs", current_regs.fs, current_regs.fs != previous_regs.fs });
     m_registers.append({ "gs", current_regs.gs, current_regs.gs != previous_regs.gs });
+#elif ARCH(AARCH64)
+    (void)previous_regs;
+    TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif

+ 40 - 0
Userland/Libraries/LibC/fenv.cpp

@@ -10,6 +10,7 @@
 // This is the size of the floating point environment image in protected mode
 static_assert(sizeof(__x87_floating_point_environment) == 28);
 
+#ifndef AK_ARCH_AARCH64
 static u16 read_status_register()
 {
     u16 status_register;
@@ -45,6 +46,7 @@ static void set_mxcsr(u32 new_mxcsr)
 }
 
 static constexpr u32 default_mxcsr_value = 0x1f80;
+#endif
 
 extern "C" {
 
@@ -53,10 +55,14 @@ int fegetenv(fenv_t* env)
     if (!env)
         return 1;
 
+#ifdef AK_ARCH_AARCH64
+    TODO_AARCH64();
+#else
     asm volatile("fnstenv %0"
                  : "=m"(env->__x87_fpu_env)::"memory");
 
     env->__mxcsr = read_mxcsr();
+#endif
 
     return 0;
 }
@@ -66,6 +72,9 @@ int fesetenv(fenv_t const* env)
     if (!env)
         return 1;
 
+#ifdef AK_ARCH_AARCH64
+    TODO_AARCH64();
+#else
     if (env == FE_DFL_ENV) {
         asm volatile("finit");
         set_mxcsr(default_mxcsr_value);
@@ -76,6 +85,7 @@ int fesetenv(fenv_t const* env)
                  : "memory");
 
     set_mxcsr(env->__mxcsr);
+#endif
 
     return 0;
 }
@@ -87,9 +97,13 @@ int feholdexcept(fenv_t* env)
     fenv_t current_env;
     fegetenv(&current_env);
 
+#ifdef AK_ARCH_AARCH64
+    TODO_AARCH64();
+#else
     current_env.__x87_fpu_env.__status_word &= ~FE_ALL_EXCEPT;
     current_env.__x87_fpu_env.__status_word &= ~(1 << 7);      // Clear the "Exception Status Summary" bit
     current_env.__x87_fpu_env.__control_word &= FE_ALL_EXCEPT; // Masking these bits stops the corresponding exceptions from being generated according to the Intel Programmer's Manual
+#endif
 
     fesetenv(&current_env);
 
@@ -122,8 +136,12 @@ int fesetexceptflag(fexcept_t const* except, int exceptions)
     fegetenv(&current_env);
 
     exceptions &= FE_ALL_EXCEPT;
+#ifdef AK_ARCH_AARCH64
+    TODO_AARCH64();
+#else
     current_env.__x87_fpu_env.__status_word &= exceptions;
     current_env.__x87_fpu_env.__status_word &= ~(1 << 7); // Make sure exceptions don't get raised
+#endif
 
     fesetenv(&current_env);
     return 0;
@@ -131,8 +149,12 @@ int fesetexceptflag(fexcept_t const* except, int exceptions)
 
 int fegetround()
 {
+#ifdef AK_ARCH_AARCH64
+    TODO_AARCH64();
+#else
     // There's no way to signal whether the SSE rounding mode and x87 ones are different, so we assume they're the same
     return (read_status_register() >> 10) & 3;
+#endif
 }
 
 int fesetround(int rounding_mode)
@@ -140,6 +162,9 @@ int fesetround(int rounding_mode)
     if (rounding_mode < FE_TONEAREST || rounding_mode > FE_TOWARDZERO)
         return 1;
 
+#ifdef AK_ARCH_AARCH64
+    TODO_AARCH64();
+#else
     auto control_word = read_control_word();
 
     control_word &= ~(3 << 10);
@@ -154,6 +179,8 @@ int fesetround(int rounding_mode)
 
     set_mxcsr(mxcsr);
 
+#endif
+
     return 0;
 }
 
@@ -164,8 +191,12 @@ int feclearexcept(int exceptions)
     fenv_t current_env;
     fegetenv(&current_env);
 
+#ifdef AK_ARCH_AARCH64
+    TODO_AARCH64();
+#else
     current_env.__x87_fpu_env.__status_word &= ~exceptions;
     current_env.__x87_fpu_env.__status_word &= ~(1 << 7); // Clear the "Exception Status Summary" bit
+#endif
 
     fesetenv(&current_env);
     return 0;
@@ -173,10 +204,15 @@ int feclearexcept(int exceptions)
 
 int fetestexcept(int exceptions)
 {
+#ifdef AK_ARCH_AARCH64
+    (void)exceptions;
+    TODO_AARCH64();
+#else
     u16 status_register = read_status_register() & FE_ALL_EXCEPT;
     exceptions &= FE_ALL_EXCEPT;
 
     return status_register & exceptions;
+#endif
 }
 
 int feraiseexcept(int exceptions)
@@ -186,6 +222,9 @@ int feraiseexcept(int exceptions)
 
     exceptions &= FE_ALL_EXCEPT;
 
+#ifdef AK_ARCH_AARCH64
+    TODO_AARCH64();
+#else
     // While the order in which the exceptions is raised is unspecified, FE_OVERFLOW and FE_UNDERFLOW must be raised before FE_INEXACT, so handle that case in this branch
     if (exceptions & FE_INEXACT) {
         env.__x87_fpu_env.__status_word &= ((u16)exceptions & ~FE_INEXACT);
@@ -203,6 +242,7 @@ int feraiseexcept(int exceptions)
     env.__x87_fpu_env.__status_word &= exceptions;
     fesetenv(&env);
     asm volatile("fwait");
+#endif
 
     return 0;
 }

+ 55 - 2
Userland/Libraries/LibC/math.cpp

@@ -9,7 +9,9 @@
 
 #include <AK/BuiltinWrappers.h>
 #include <AK/ExtraMathConstants.h>
-#include <AK/FPControl.h>
+#ifndef AK_ARCH_AARCH64
+#    include <AK/FPControl.h>
+#endif
 #include <AK/Math.h>
 #include <AK/Platform.h>
 #include <AK/StdLibExtras.h>
@@ -62,7 +64,7 @@ enum class RoundingMode {
 template<typename T>
 union FloatExtractor;
 
-#if ARCH(I386) || ARCH(X86_64)
+#if ARCH(I386) || ARCH(X86_64) || ARCH(AARCH64)
 // This assumes long double is 80 bits, which is true with GCC on Intel platforms
 template<>
 union FloatExtractor<long double> {
@@ -413,6 +415,7 @@ MAKE_AK_BACKED2(remainder);
 
 long double truncl(long double x) NOEXCEPT
 {
+#ifndef AK_ARCH_AARCH64
     if (fabsl(x) < LONG_LONG_MAX) {
         // This is 1.6 times faster than the implementation using the "internal_to_integer"
         // helper (on x86_64)
@@ -425,12 +428,14 @@ long double truncl(long double x) NOEXCEPT
             : [temp] "m"(temp));
         return x;
     }
+#endif
 
     return internal_to_integer(x, RoundingMode::ToZero);
 }
 
 double trunc(double x) NOEXCEPT
 {
+#ifndef AK_ARCH_AARCH64
     if (fabs(x) < LONG_LONG_MAX) {
         u64 temp;
         asm(
@@ -440,12 +445,14 @@ double trunc(double x) NOEXCEPT
             : [temp] "m"(temp));
         return x;
     }
+#endif
 
     return internal_to_integer(x, RoundingMode::ToZero);
 }
 
 float truncf(float x) NOEXCEPT
 {
+#ifndef AK_ARCH_AARCH64
     if (fabsf(x) < LONG_LONG_MAX) {
         u64 temp;
         asm(
@@ -455,40 +462,60 @@ float truncf(float x) NOEXCEPT
             : [temp] "m"(temp));
         return x;
     }
+#endif
 
     return internal_to_integer(x, RoundingMode::ToZero);
 }
 
 long double rintl(long double value)
 {
+#ifdef AK_ARCH_AARCH64
+    (void)value;
+    TODO_AARCH64();
+#else
     long double res;
     asm(
         "frndint\n"
         : "=t"(res)
         : "0"(value));
     return res;
+#endif
 }
 double rint(double value)
 {
+#ifdef AK_ARCH_AARCH64
+    (void)value;
+    TODO_AARCH64();
+#else
     double res;
     asm(
         "frndint\n"
         : "=t"(res)
         : "0"(value));
     return res;
+#endif
 }
 float rintf(float value)
 {
+#ifdef AK_ARCH_AARCH64
+    (void)value;
+    TODO_AARCH64();
+#else
     float res;
     asm(
         "frndint\n"
         : "=t"(res)
         : "0"(value));
     return res;
+#endif
 }
 
 long lrintl(long double value)
 {
+#ifdef AK_ARCH_AARCH64
+    (void)value;
+    TODO_AARCH64();
+#else
     long res;
     asm(
         "fistpl %0\n"
@@ -496,9 +523,14 @@ long lrintl(long double value)
         : "t"(value)
         : "st");
     return res;
+#endif
 }
 long lrint(double value)
 {
+#ifdef AK_ARCH_AARCH64
+    (void)value;
+    TODO_AARCH64();
+#else
     long res;
     asm(
         "fistpl %0\n"
@@ -506,9 +538,14 @@ long lrint(double value)
         : "t"(value)
         : "st");
     return res;
+#endif
 }
 long lrintf(float value)
 {
+#ifdef AK_ARCH_AARCH64
+    (void)value;
+    TODO_AARCH64();
+#else
     long res;
     asm(
         "fistpl %0\n"
@@ -516,10 +553,15 @@ long lrintf(float value)
         : "t"(value)
         : "st");
     return res;
+#endif
 }
 
 long long llrintl(long double value)
 {
+#ifdef AK_ARCH_AARCH64
+    (void)value;
+    TODO_AARCH64();
+#else
     long long res;
     asm(
         "fistpq %0\n"
@@ -527,9 +569,14 @@ long long llrintl(long double value)
         : "t"(value)
         : "st");
     return res;
+#endif
 }
 long long llrint(double value)
 {
+#ifdef AK_ARCH_AARCH64
+    (void)value;
+    TODO_AARCH64();
+#else
     long long res;
     asm(
         "fistpq %0\n"
@@ -537,9 +584,14 @@ long long llrint(double value)
         : "t"(value)
         : "st");
     return res;
+#endif
 }
 long long llrintf(float value)
 {
+#ifdef AK_ARCH_AARCH64
+    (void)value;
+    TODO_AARCH64();
+#else
     long long res;
     asm(
         "fistpq %0\n"
@@ -547,6 +599,7 @@ long long llrintf(float value)
         : "t"(value)
         : "st");
     return res;
+#endif
 }
 
 // On systems where FLT_RADIX == 2, ldexp is equivalent to scalbn

+ 4 - 0
Userland/Libraries/LibC/pthread.cpp

@@ -102,6 +102,10 @@ static int create_thread(pthread_t* thread, void* (*entry)(void*), void* argumen
     thread_params->rsi = (FlatPtr)argument;
     thread_params->rdx = (FlatPtr)thread_params->stack_location;
     thread_params->rcx = thread_params->stack_size;
+#elif ARCH(AARCH64)
+    (void)entry;
+    (void)argument;
+    TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif

+ 13 - 0
Userland/Libraries/LibC/string.cpp

@@ -136,6 +136,11 @@ void* memcpy(void* dest_ptr, void const* src_ptr, size_t n)
         "rep movsb"
         : "+D"(dest_ptr), "+S"(src_ptr), "+c"(n)::"memory");
     return original_dest;
+#elif ARCH(AARCH64)
+    (void)dest_ptr;
+    (void)src_ptr;
+    (void)n;
+    TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif
@@ -168,6 +173,14 @@ void* memset(void* dest_ptr, int c, size_t n)
 }
 #elif ARCH(X86_64)
 // For x86-64, an optimized ASM implementation is found in ./arch/x86_64/memset.S
+#elif ARCH(AARCH64)
+void* memset(void* dest_ptr, int c, size_t n)
+{
+    (void)dest_ptr;
+    (void)c;
+    (void)n;
+    TODO_AARCH64();
+}
 #else
 #    error Unknown architecture
 #endif

+ 14 - 4
Userland/Libraries/LibC/sys/arch/i386/regs.h

@@ -23,8 +23,10 @@ struct [[gnu::packed]] PtraceRegisters : public __mcontext {
     {
 #        if ARCH(I386)
         return eip;
-#        else
+#        elif ARCH(X86_64)
         return rip;
+#        else
+        TODO_AARCH64();
 #        endif
     }
 
@@ -32,8 +34,11 @@ struct [[gnu::packed]] PtraceRegisters : public __mcontext {
     {
 #        if ARCH(I386)
         eip = ip;
-#        else
+#        elif ARCH(X86_64)
         rip = ip;
+#        else
+        (void)ip;
+        TODO_AARCH64();
 #        endif
     }
 
@@ -41,8 +46,10 @@ struct [[gnu::packed]] PtraceRegisters : public __mcontext {
     {
 #        if ARCH(I386)
         return ebp;
-#        else
+#        elif ARCH(X86_64)
         return rbp;
+#        else
+        TODO_AARCH64();
 #        endif
     }
 
@@ -50,8 +57,11 @@ struct [[gnu::packed]] PtraceRegisters : public __mcontext {
     {
 #        if ARCH(I386)
         ebp = bp;
-#        else
+#        elif ARCH(X86_64)
         rbp = bp;
+#        else
+        (void)bp;
+        TODO_AARCH64();
 #        endif
     }
 #    endif

+ 4 - 0
Userland/Libraries/LibCoredump/Backtrace.cpp

@@ -50,6 +50,10 @@ Backtrace::Backtrace(Reader const& coredump, const ELF::Core::ThreadInfo& thread
 #elif ARCH(X86_64)
     auto start_bp = m_thread_info.regs.rbp;
     auto start_ip = m_thread_info.regs.rip;
+#elif ARCH(AARCH64)
+    auto start_bp = 0;
+    auto start_ip = 0;
+    TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif

+ 2 - 0
Userland/Libraries/LibDebug/DebugInfo.cpp

@@ -171,6 +171,8 @@ NonnullOwnPtrVector<DebugInfo::VariableInfo> DebugInfo::get_variables_in_current
         ip = regs.eip;
 #elif ARCH(X86_64)
         ip = regs.rip;
+#elif ARCH(AARCH64)
+        TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif

+ 6 - 0
Userland/Libraries/LibDebug/DebugSession.cpp

@@ -343,11 +343,15 @@ FlatPtr DebugSession::single_step()
     // After the debuggee has stopped, we clear the TRAP flag.
 
     auto regs = get_registers();
+#if ARCH(I386) || ARCH(X86_64)
     constexpr u32 TRAP_FLAG = 0x100;
+#endif
 #if ARCH(I386)
     regs.eflags |= TRAP_FLAG;
 #elif ARCH(X86_64)
     regs.rflags |= TRAP_FLAG;
+#elif ARCH(AARCH64)
+    TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif
@@ -365,6 +369,8 @@ FlatPtr DebugSession::single_step()
     regs.eflags &= ~(TRAP_FLAG);
 #elif ARCH(X86_64)
     regs.rflags &= ~(TRAP_FLAG);
+#elif ARCH(AARCH64)
+    TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif

+ 9 - 0
Userland/Libraries/LibDebug/DebugSession.h

@@ -188,6 +188,9 @@ void DebugSession::run(DesiredInitialDebugeeState initial_debugee_state, Callbac
         FlatPtr current_instruction = regs.eip;
 #elif ARCH(X86_64)
         FlatPtr current_instruction = regs.rip;
+#elif ARCH(AARCH64)
+        FlatPtr current_instruction;
+        TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif
@@ -211,6 +214,9 @@ void DebugSession::run(DesiredInitialDebugeeState initial_debugee_state, Callbac
                 FlatPtr current_ebp = regs.ebp;
 #elif ARCH(X86_64)
                 FlatPtr current_ebp = regs.rbp;
+#elif ARCH(AARCH64)
+                FlatPtr current_ebp;
+                TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif
@@ -259,6 +265,9 @@ void DebugSession::run(DesiredInitialDebugeeState initial_debugee_state, Callbac
             regs.eip = breakpoint_addr;
 #elif ARCH(X86_64)
             regs.rip = breakpoint_addr;
+#elif ARCH(AARCH64)
+            (void)breakpoint_addr;
+            TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif

+ 4 - 0
Userland/Libraries/LibELF/DynamicLinker.cpp

@@ -660,7 +660,11 @@ void ELF::DynamicLinker::linker_main(String&& main_program_name, int main_progra
 
     dbgln_if(DYNAMIC_LOAD_DEBUG, "Jumping to entry point: {:p}", entry_point_function);
     if (s_do_breakpoint_trap_before_entry) {
+#ifdef AK_ARCH_AARCH64
+        asm("brk #0");
+#else
         asm("int3");
+#endif
     }
 
     _invoke_entry(argc, argv, envp, entry_point_function);

+ 8 - 0
Userland/Utilities/functrace.cpp

@@ -66,6 +66,11 @@ static void print_syscall(PtraceRegisters& regs, size_t depth)
         regs.rcx,
         regs.rbx,
         end_color);
+#elif ARCH(AARCH64)
+    (void)regs;
+    (void)begin_color;
+    (void)end_color;
+    TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif
@@ -145,6 +150,9 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
         const FlatPtr ip = regs.value().eip;
 #elif ARCH(X86_64)
         const FlatPtr ip = regs.value().rip;
+#elif ARCH(AARCH64)
+        const FlatPtr ip = 0; // FIXME
+        TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif

+ 9 - 0
Userland/Utilities/strace.cpp

@@ -894,6 +894,12 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
         syscall_arg_t arg1 = regs.rdx;
         syscall_arg_t arg2 = regs.rcx;
         syscall_arg_t arg3 = regs.rbx;
+#elif ARCH(AARCH64)
+        syscall_arg_t syscall_index = 0; // FIXME
+        syscall_arg_t arg1 = 0;          // FIXME
+        syscall_arg_t arg2 = 0;          // FIXME
+        syscall_arg_t arg3 = 0;          // FIXME
+        TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif
@@ -910,6 +916,9 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
         u32 res = regs.eax;
 #elif ARCH(X86_64)
         u64 res = regs.rax;
+#elif ARCH(AARCH64)
+        u64 res = 0; // FIXME
+        TODO_AARCH64();
 #else
 #    error Unknown architecture
 #endif