Skip to content

Commit

Permalink
aarch64: osi_linux fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
lacraig2 committed Oct 16, 2024
1 parent 01777e1 commit 16678b9
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 38 deletions.
80 changes: 42 additions & 38 deletions panda/plugins/osi_linux/default_profile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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?)
Expand Down
26 changes: 26 additions & 0 deletions panda/plugins/osi_linux/osi_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

/**
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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");
Expand Down

0 comments on commit 16678b9

Please sign in to comment.