From 16678b9c04ef6bf09bb3c18719ab3d890f3a4bfa Mon Sep 17 00:00:00 2001 From: Luke Craig Date: Wed, 16 Oct 2024 15:13:47 -0400 Subject: [PATCH] aarch64: osi_linux fixes --- panda/plugins/osi_linux/default_profile.cpp | 80 +++++++++++---------- panda/plugins/osi_linux/osi_linux.cpp | 26 +++++++ 2 files changed, 68 insertions(+), 38 deletions(-) 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");