diff --git a/panda/plugins/osi_linux/default_profile.cpp b/panda/plugins/osi_linux/default_profile.cpp index 0be9af4874d..c3725bb9049 100644 --- a/panda/plugins/osi_linux/default_profile.cpp +++ b/panda/plugins/osi_linux/default_profile.cpp @@ -11,53 +11,57 @@ target_ptr_t default_get_current_task_struct(CPUState *cpu) target_ptr_t current_task_addr; target_ptr_t ts; -#ifdef TARGET_ARM +#ifdef TARGET_AARCH64 + extern target_ptr_t spel0; //aarch64 - if (((CPUARMState*) cpu->env_ptr)->aarch64) { - //for kernel versions >= 4.10.0 - if(PROFILE_KVER_GE(ki, 4, 10, 0)) { - current_task_addr = ki.task.init_addr; - - //for kernel versions between 3.7.0 and 4.9.257 - } else if(PROFILE_KVER_LT(ki, 4, 10, 0) && PROFILE_KVER_GE(ki, 3, 7, 0)) { - target_ptr_t kernel_sp = panda_current_ksp(cpu); //((CPUARMState*) cpu->env_ptr)->sp_el[1]; - target_ptr_t task_thread_info = kernel_sp & ~(0x4000-1); - current_task_addr = task_thread_info+0x10; - - - //because some kernel versions use both per_cpu variables AND access the task_struct - //via the thread_info struct, the default call to struct_get with the per_cpu_offset_0_addr can be incorrect - err = struct_get(cpu, &ts, current_task_addr, 0); - assert(err == struct_get_ret_t::SUCCESS && "failed to get current task struct"); - fixupendian2(ts); - return ts; - } else { - assert(false && "cannot use kernel version older than 3.7"); - } - - //arm32 - } else { - target_ptr_t kernel_sp = panda_current_ksp(cpu); - - // XXX: This should use THREADINFO_MASK but that's hardcoded and wrong for my test system - // We need to expose that as a part of the OSI config - See issue #651 - target_ptr_t task_thread_info = kernel_sp & ~(0x2000 -1); - - //for kernel versions >= 5.18.0 - if (PROFILE_KVER_GE(ki, 5, 18, 0)) { - return task_thread_info; - } - - current_task_addr=task_thread_info+0xC; - + if (PROFILE_KVER_GE(ki, 4, 10, 0)){ + // https://elixir.bootlin.com/linux/v4.10/source/arch/arm64/include/asm/current.h#L25 + return spel0; + } else if (PROFILE_KVER_GE(ki, 4, 6, 0)) { + // untested + // https://elixir.bootlin.com/linux/v4.6/source/arch/arm64/include/asm/thread_info.h#L79 + target_ptr_t task_thread_info = spel0; + current_task_addr = task_thread_info+0x10; + err = struct_get(cpu, &ts, current_task_addr, 0); + return ts; + } else if(PROFILE_KVER_GE(ki, 3, 7, 0)) { + // https://elixir.bootlin.com/linux/v3.7/source/arch/arm64/include/asm/thread_info.h#L79 + target_ptr_t kernel_sp = panda_current_ksp(cpu); //((CPUARMState*) cpu->env_ptr)->sp_el[1]; + target_ptr_t task_thread_info = kernel_sp & ~(0x4000-1); + current_task_addr = task_thread_info+0x10; //because some kernel versions use both per_cpu variables AND access the task_struct //via the thread_info struct, the default call to struct_get with the per_cpu_offset_0_addr can be incorrect err = struct_get(cpu, &ts, current_task_addr, 0); assert(err == struct_get_ret_t::SUCCESS && "failed to get current task struct"); fixupendian2(ts); return ts; + } else { + // solid chance the above implemntation just works for older kernels + // see: https://elixir.bootlin.com/linux/v2.6.39.4/source/arch/arm/include/asm/thread_info.h#L92 + assert(false && "cannot use kernel version older than 3.7"); + } +#elif defined(TARGET_ARM) && !defined(TARGET_AARCH64) + //arm32 + target_ptr_t kernel_sp = panda_current_ksp(cpu); + // XXX: This should use THREADINFO_MASK but that's hardcoded and wrong for my test system + // We need to expose that as a part of the OSI config - See issue #651 + target_ptr_t task_thread_info = kernel_sp & ~(0x2000 -1); + + //for kernel versions >= 5.18.0 + if (PROFILE_KVER_GE(ki, 5, 18, 0)) { + return task_thread_info; } + + current_task_addr=task_thread_info+0xC; + + //because some kernel versions use both per_cpu variables AND access the task_struct + //via the thread_info struct, the default call to struct_get with the per_cpu_offset_0_addr can be incorrect + err = struct_get(cpu, &ts, current_task_addr, 0); + assert(err == struct_get_ret_t::SUCCESS && "failed to get current task struct"); + fixupendian2(ts); + return ts; + #elif defined(TARGET_MIPS) // __current_thread_info is stored in KERNEL r28 // userspace clobbers it but kernel restores (somewhow?) diff --git a/panda/plugins/osi_linux/osi_linux.cpp b/panda/plugins/osi_linux/osi_linux.cpp index 7375943dcc9..6d766b33d52 100644 --- a/panda/plugins/osi_linux/osi_linux.cpp +++ b/panda/plugins/osi_linux/osi_linux.cpp @@ -349,6 +349,19 @@ inline bool can_read_current(CPUState *cpu) { // won't check again until the first syscall. bool r28_set = false; inline void check_cache_r28(CPUState *cpu); +#elif TARGET_AARCH64 + +target_ulong spel0 = 0; +bool aarch64_initialized = false; + +void aarch64_sbe(CPUState *cpu, TranslationBlock *tb); +void aarch64_sbe(CPUState *cpu, TranslationBlock *tb) { + if (unlikely(panda_in_kernel_code_linux(cpu) && ((CPUARMState*) cpu->env_ptr)->sp_el[0] != 0)){ + aarch64_initialized = true; + spel0 = ((CPUARMState*) cpu->env_ptr)->sp_el[0]; + } +} + #endif /** @@ -379,6 +392,13 @@ bool osi_guest_is_ready(CPUState *cpu, void** ret) { return false; } } + #elif defined(TARGET_AARCH64) + if (PROFILE_KVER_GE(ki, 4, 6, 0)){ + if (!aarch64_initialized){ + *ret = NULL; + return false; + } + } #endif first_osi_check = false; @@ -1315,6 +1335,12 @@ bool init_plugin(void *self) { notify_task_change(cpu); } }); +#ifdef TARGET_AARCH64 + if (PROFILE_KVER_GE(ki, 4, 6, 0)){ + panda_cb pcb = { .start_block_exec = aarch64_sbe }; + panda_register_callback(self, PANDA_CB_START_BLOCK_EXEC, pcb); + } +#endif return true; #else fprintf(stderr, PLUGIN_NAME "Unsupported guest architecture\n"); diff --git a/panda/plugins/syscalls2/syscalls2.cpp b/panda/plugins/syscalls2/syscalls2.cpp index bccbbb39b08..ea57472192a 100644 --- a/panda/plugins/syscalls2/syscalls2.cpp +++ b/panda/plugins/syscalls2/syscalls2.cpp @@ -514,21 +514,20 @@ target_ulong calc_retaddr_linux_arm(CPUState* cpu, target_ulong pc) { offset = 4; // Note: this is NOT 8 for AARCH64! } -// 32-bit specific -#if !defined(TARGET_AARCH64) +#if defined(TARGET_AARCH64) + //64-bit specific + // if (!in_thumb_mode) { + // unsigned char buf[4] = {}; + // panda_virtual_memory_rw(cpu, pc, buf, 4, 0); + // if (!((buf[0] == 0x01) && (buf[1] == 0) && (buf[2] == 0) && (buf[3] == 0xd4))) { + // assert((1==0) && "Tried to calculate AARCH64 ret addr when instr was not a syscall!"); + // } + // } +#else + // 32-bit specific // TODO: check syscall encoding here? // If so, check both EABI and OABI! -// 64-bit specific -#else - if (!in_thumb_mode) { - unsigned char buf[4] = {}; - panda_virtual_memory_rw(cpu, pc, buf, 4, 0); - if (!((buf[0] == 0x01) && (buf[1] == 0) && (buf[2] == 0) && (buf[3] == 0xd4))) { - assert((1==0) && "Tried to calculate AARCH64 ret addr when instr was not a syscall!"); - } - } -#endif if (in_thumb_mode) { unsigned char buf[2] = {}; panda_virtual_memory_rw(cpu, pc, buf, 2, 0); @@ -536,6 +535,7 @@ target_ulong calc_retaddr_linux_arm(CPUState* cpu, target_ulong pc) { assert((1==0) && "Tried to calculate THUMB ret addr when instr was not a syscall!"); } } +#endif return mask_retaddr_to_pc(pc + offset); #else @@ -1074,7 +1074,7 @@ target_ulong doesBlockContainSyscall(CPUState *cpu, TranslationBlock *tb, int* s return pc; } -#else +#endif // ARM32 // Check for ARM mode syscall CPUArchState *env = (CPUArchState*)cpu->env_ptr; @@ -1105,7 +1105,6 @@ target_ulong doesBlockContainSyscall(CPUState *cpu, TranslationBlock *tb, int* s return pc; } } -#endif // Arm32/aarch64 - not a match return 0; #elif defined(TARGET_MIPS)