From ac4219aea3bdaba5ee1a032ce33eeb40db4d2dfd Mon Sep 17 00:00:00 2001 From: Hanlu Li Date: Fri, 14 Aug 2026 15:24:56 +0800 Subject: [PATCH] LATX, fix: Scope KZT compatibility fallback by library group Compatibility checks previously disabled the process-wide KZT option when an application path contained a private guest library matching any wrapped SONAME. This also disabled unrelated library families, while wrapper-selection logs could still describe the configured groups rather than the execution-time result. Keep the configured mask as the requested state and prune incompatible families only from a separate effective mask. Derive the execution-time KZT predicate from the process-level 0/1/2 mode and the effective mask, then use it consistently for translation, bridge, signal, address-validation, relocation, and callback paths. Configuration, direct-exec, and Wine deferral continue to manage the process-level mode. Match private guest libraries at the .so boundary and confirm each candidate is an x86_64 ELF. Remove the undocumented GTK3/libXt name gate; retain the existing Chrome process gate as an explicit all-family rejection. Signed-off-by: Hanlu Li --- accel/tcg/cpu-exec.c | 8 +-- accel/tcg/tb-flush.c | 1 + accel/tcg/translate-all.c | 2 +- accel/tcg/user-exec.c | 5 +- include/exec/cpu_ldst.h | 6 +- linux-user/i386/cpu_loop.c | 2 +- linux-user/signal.c | 3 +- target/i386/latx/context/elfloader.c | 75 ++++++++++++++++++------- target/i386/latx/context/kzt-groups.c | 70 +++++++++++++++++++---- target/i386/latx/context/myalign.c | 23 +++++--- target/i386/latx/context/wrapperdebug.c | 8 ++- target/i386/latx/include/elfloader.h | 2 +- target/i386/latx/include/kzt-groups.h | 13 ++++- target/i386/latx/include/kzt-runtime.h | 31 ++++++++++ target/i386/latx/include/latx-options.h | 2 + target/i386/latx/ir1/ir1.c | 5 +- target/i386/latx/translator/tr-misc.c | 4 +- target/i386/latx/translator/translate.c | 4 +- 18 files changed, 206 insertions(+), 58 deletions(-) create mode 100644 target/i386/latx/include/kzt-runtime.h diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index fd007263050..1f0d6af6038 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -195,7 +195,7 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit) if (qemu_loglevel_mask(CPU_LOG_EXEC)) { #ifdef CONFIG_LATX_KZT Dl_info dl_info; - if (option_kzt && itb->pc > reserved_va && + if (latx_kzt_runtime_enabled() && itb->pc > reserved_va && dladdr ((const void *)((onebridge_t *)itb->pc)->f, &dl_info)) { qemu_log_mask_and_addr(CPU_LOG_EXEC, itb->pc, "pid(%d) - tid(%" PRIuPTR ") Trace cpu%d: %p [ " @@ -285,7 +285,7 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit) } lazypc = rettb->pc + rettb->lazypc[0]; #if defined(CONFIG_LATX_KZT) - if (option_kzt && lazypc >= reserved_va) { + if (latx_kzt_runtime_enabled() && lazypc >= reserved_va) { uintptr_t alt_pc = (uintptr_t)getAlternate((void *)(uintptr_t)lazypc); if (alt_pc != (uintptr_t)lazypc) { lazypc = alt_pc; @@ -853,7 +853,7 @@ TranslationBlock * kzt_tb_find_exp( static inline bool cpu_handle_exception(CPUState *cpu, int *ret) { #if defined(CONFIG_LATX_KZT) - if (option_kzt) { + if (latx_kzt_runtime_enabled()) { CPUArchState *env = cpu->env_ptr; if(env->eip == (uint64_t)&RunFunctionWithState){ *ret = 0xCC; @@ -945,7 +945,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, TranslationBlock **last_tb) { #if defined(CONFIG_LATX_KZT) - if (option_kzt) { + if (latx_kzt_runtime_enabled()) { CPUArchState *env = cpu->env_ptr; if(env->eip == (uint64_t)&RunFunctionWithState){ *last_tb = NULL; diff --git a/accel/tcg/tb-flush.c b/accel/tcg/tb-flush.c index 8dc4bb2d314..8103d14969a 100644 --- a/accel/tcg/tb-flush.c +++ b/accel/tcg/tb-flush.c @@ -106,6 +106,7 @@ void do_tb_flush(CPUState *cpu, run_on_cpu_data tb_flush_count) } #if defined(CONFIG_LATX_KZT) CPU_FOREACH(cpu) { + /* The installer also checks the effective library-group mask. */ if (cpu && option_kzt) { kzt_install_runtime_callbacks(cpu, &info1); } diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 98d79bd2caa..6cac103e56c 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -3817,7 +3817,7 @@ void *page_alloc_target_data(target_ulong address, size_t size) bool page_check_range(target_ulong start, target_ulong len, int flags) { #if defined(CONFIG_LATX_KZT) - if (option_kzt && start > reserved_va) { + if (latx_kzt_runtime_enabled() && start > reserved_va) { return true; } #endif diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index a2c25bc2a76..b5f38f390b1 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -1360,7 +1360,8 @@ int cpu_signal_handler(int host_signum, void *pinfo, } } #if defined(CONFIG_LATX_KZT) - if (option_kzt && (int64_t)info->si_addr >= info1.start_data && + if (latx_kzt_runtime_enabled() && + (int64_t)info->si_addr >= info1.start_data && (int64_t)info->si_addr <= info1.end_data && info->si_signo == SIGSEGV) { int ret = elf_data_interpret(info, uc); @@ -1369,7 +1370,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, return 1; } } - if (option_kzt && info->si_signo == SIGSEGV) { + if (latx_kzt_runtime_enabled() && info->si_signo == SIGSEGV) { for (int i = 0; i < sizeof(elf_native_func) / sizeof(int); i++) { if (!find_stack_func_exist(elf_native_func[i], 4)) { int ret = elf_data_interpret(info, uc); diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index 9a989db6e03..9e0fd328e33 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -58,7 +58,7 @@ #define CPU_LDST_H #if defined(CONFIG_LATX_KZT) -extern int option_kzt; +#include "kzt-runtime.h" #endif #if defined(CONFIG_USER_ONLY) /* sparc32plus has 64bit long but 32bit space address @@ -93,7 +93,7 @@ static inline void *g2h(CPUState *cs, abi_ptr x) static inline bool guest_addr_valid_untagged(abi_ulong x) { #if defined(CONFIG_LATX_KZT) - if (option_kzt) { + if (latx_kzt_runtime_enabled()) { return true; } else #endif @@ -103,7 +103,7 @@ static inline bool guest_addr_valid_untagged(abi_ulong x) static inline bool guest_range_valid_untagged(abi_ulong start, abi_ulong len) { #if defined(CONFIG_LATX_KZT) - if (option_kzt) { + if (latx_kzt_runtime_enabled()) { return true; } else #endif diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c index 92dd11d0ce9..98c0afcdcca 100644 --- a/linux-user/i386/cpu_loop.c +++ b/linux-user/i386/cpu_loop.c @@ -221,7 +221,7 @@ void cpu_loop(CPUX86State *env) cpu_exec_end(cs); process_queued_cpu_work(cs); #if defined(CONFIG_LATX_KZT) - if(option_kzt && trapnr == 0xCC) + if (latx_kzt_runtime_enabled() && trapnr == 0xCC) break; #endif switch(trapnr) { diff --git a/linux-user/signal.c b/linux-user/signal.c index 264ec8fb4d9..6a56cf34ec8 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1308,7 +1308,8 @@ static void host_signal_handler(int host_signum, siginfo_t *info, cpu_exit(thread_cpu); #if defined(CONFIG_LATX_KZT) #define SIGCANCEL __SIGRTMIN - if (host_signum == SIGCANCEL + 2 && option_kzt && pc > reserved_va) { + if (host_signum == SIGCANCEL + 2 && latx_kzt_runtime_enabled() && + pc > reserved_va) { #define BTSIZT 64 void * array[BTSIZT] = {0}; size_t size; diff --git a/target/i386/latx/context/elfloader.c b/target/i386/latx/context/elfloader.c index e959bb9a895..b79768472ad 100755 --- a/target/i386/latx/context/elfloader.c +++ b/target/i386/latx/context/elfloader.c @@ -653,7 +653,22 @@ static int isChromeApp(elfheader_t* h, int con_score) return 0; } -int CheckEnableKZT(elfheader_t* h, char** target_argv, int target_argc) +static bool kzt_soname_matches_filename(const char *soname, + const char *filename) +{ + const char *suffix = strstr(soname, ".so"); + size_t prefix_length; + + if (!suffix) { + return !strcmp(soname, filename); + } + prefix_length = suffix - soname + strlen(".so"); + return !strncmp(soname, filename, prefix_length) && + (filename[prefix_length] == '\0' || + filename[prefix_length] == '.'); +} + +void CheckEnableKZT(elfheader_t *h, char **target_argv, int target_argc) { path_collection_t lib_path = {0,0,0}; char *rpathref; @@ -675,11 +690,6 @@ int CheckEnableKZT(elfheader_t* h, char** target_argv, int target_argc) } break; case DT_NEEDED: - if (strstr(h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val, "libgtk-3.so")||//skip gtk - strstr(h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val, "libXt.so")) {//skip mainexec needed libXt.so - printf_log(LOG_INFO, "latx find libgtk or libXt, skip kzt\n"); - return 0; - } ++needlibcnt; break; } @@ -696,11 +706,6 @@ int CheckEnableKZT(elfheader_t* h, char** target_argv, int target_argc) if (!kzt_library_is_enabled(wrappedlibs_name[i])) { continue; } - char *p = box_strdup(wrappedlibs_name[i]); - char *p2 = strchr(p, '.'); - if (++p2) { - *p2 = '\0'; - } for (int j=0; jd_type == DT_REG) { // Check if it's a regular file - if (!strncmp(entry->d_name, p, strlen(p))) { - printf_log(LOG_INFO, "File starting with '%s' found: %s at %s\n", p, entry->d_name, lib_path.paths[j]); - closedir(dir); - FreeCollection(&lib_path); - return 0; - } + char candidate[PATH_MAX]; + char reason[PATH_MAX + 96]; + KztLibraryGroup group; + int candidate_length; + + if (!kzt_soname_matches_filename(wrappedlibs_name[i], + entry->d_name)) { + continue; } + candidate_length = snprintf( + candidate, sizeof(candidate), "%s%s%s", lib_path.paths[j], + lib_path.paths[j][strlen(lib_path.paths[j]) - 1] == '/' + ? "" : "/", + entry->d_name); + if (candidate_length < 0 || + (size_t)candidate_length >= sizeof(candidate)) { + continue; + } + if (!FileExist(candidate, IS_FILE) || + !FileIsX64ELF(candidate)) { + continue; + } + group = kzt_group_for_library(wrappedlibs_name[i]); + snprintf(reason, sizeof(reason), + "guest %s resolved from application path %s", + entry->d_name, lib_path.paths[j]); + kzt_group_disable(group, reason); + break; } closedir(dir); + if (!kzt_library_is_enabled(wrappedlibs_name[i])) { + break; + } } } FreeCollection(&lib_path); //disable kzt chrome app for(int i = 0; i < target_argc; i++) { if (!strcmp(target_argv[i], "--no-sandbox")) { - return !isChromeApp(h, 5); + if (isChromeApp(h, 5)) { + kzt_groups_disable_all( + "main executable matched the Chrome compatibility gate"); + } + return; } } - return !isChromeApp(h, 10); + if (isChromeApp(h, 10)) { + kzt_groups_disable_all( + "main executable matched the Chrome compatibility gate"); + } } const char* ElfName(elfheader_t* head) diff --git a/target/i386/latx/context/kzt-groups.c b/target/i386/latx/context/kzt-groups.c index 908a946c7c3..f050423a730 100644 --- a/target/i386/latx/context/kzt-groups.c +++ b/target/i386/latx/context/kzt-groups.c @@ -39,7 +39,8 @@ static const KztLibraryGroupEntry kzt_library_groups[] = { #undef GO #undef GOALIAS -static uint32_t enabled_groups = KZT_GROUP_STABLE; +static uint32_t requested_groups = KZT_GROUP_STABLE; +uint32_t kzt_effective_groups = KZT_GROUP_STABLE; static bool group_log_enabled; static char group_error[128]; static bool library_decision_logged[ARRAY_SIZE(kzt_library_groups)]; @@ -268,7 +269,7 @@ static void kzt_groups_log_effective(const char *spec, uint32_t dependencies, if (pruned) { kzt_groups_log_mask("disabled dependent library groups", pruned); } - kzt_groups_log_mask("enabled library groups", enabled_groups); + kzt_groups_log_mask("enabled library groups", kzt_effective_groups); } KztLibraryGroup kzt_group_for_library(const char *soname) @@ -326,7 +327,8 @@ void kzt_groups_print_available(void) void kzt_groups_reset(void) { - enabled_groups = KZT_GROUP_STABLE; + requested_groups = KZT_GROUP_STABLE; + kzt_effective_groups = KZT_GROUP_STABLE; group_log_enabled = false; group_error[0] = '\0'; memset(library_decision_logged, 0, sizeof(library_decision_logged)); @@ -349,7 +351,8 @@ bool kzt_groups_configure(const char *spec, bool log_enabled) memset(library_decision_logged, 0, sizeof(library_decision_logged)); if (!kzt_parse_group_spec(spec, &mode, &selected, &added, &removed, &use_stable)) { - enabled_groups = KZT_GROUP_NONE; + requested_groups = KZT_GROUP_NONE; + kzt_effective_groups = KZT_GROUP_NONE; group_log_enabled = log_enabled; return false; } @@ -367,8 +370,9 @@ bool kzt_groups_configure(const char *spec, bool log_enabled) dependencies = groups & ~before_dependencies; groups &= ~removed; before_prune = groups; - enabled_groups = kzt_prune_missing_dependencies(groups); - pruned = before_prune & ~enabled_groups; + requested_groups = kzt_prune_missing_dependencies(groups); + kzt_effective_groups = requested_groups; + pruned = before_prune & ~kzt_effective_groups; group_log_enabled = log_enabled; kzt_groups_log_effective(spec, dependencies, removed, pruned); return true; @@ -376,19 +380,65 @@ bool kzt_groups_configure(const char *spec, bool log_enabled) void kzt_groups_reject_configuration(const char *reason, bool log_enabled) { - enabled_groups = KZT_GROUP_NONE; + requested_groups = KZT_GROUP_NONE; + kzt_effective_groups = KZT_GROUP_NONE; group_log_enabled = log_enabled; snprintf(group_error, sizeof(group_error), "%s", reason); } -uint32_t kzt_groups_enabled_mask(void) +uint32_t kzt_groups_requested_mask(void) { - return enabled_groups; + return requested_groups; +} + +uint32_t kzt_groups_effective_mask(void) +{ + return kzt_effective_groups; +} + +bool kzt_group_disable(KztLibraryGroup group, const char *reason) +{ + uint32_t before_prune; + uint32_t pruned; + + if (group == KZT_GROUP_NONE || !(kzt_effective_groups & group)) { + return false; + } + + kzt_effective_groups &= ~group; + before_prune = kzt_effective_groups; + kzt_effective_groups = kzt_prune_missing_dependencies(kzt_effective_groups); + pruned = before_prune & ~kzt_effective_groups; + + if (group_log_enabled) { + fprintf(stderr, "KZT: disabled library group %s: %s\n", + kzt_group_name(group), + reason ? reason : "compatibility check failed"); + if (pruned) { + kzt_groups_log_mask("disabled dependent library groups", pruned); + } + kzt_groups_log_mask("enabled library groups", kzt_effective_groups); + } + return true; +} + +void kzt_groups_disable_all(const char *reason) +{ + if (kzt_effective_groups == KZT_GROUP_NONE) { + return; + } + kzt_effective_groups = KZT_GROUP_NONE; + if (group_log_enabled) { + fprintf(stderr, "KZT: disabled all library groups: %s\n", + reason ? reason : "compatibility check failed"); + kzt_groups_log_mask("enabled library groups", kzt_effective_groups); + } } bool kzt_group_is_enabled(KztLibraryGroup group) { - return group != KZT_GROUP_NONE && (enabled_groups & group) == group; + return group != KZT_GROUP_NONE && + (kzt_effective_groups & group) == group; } bool kzt_library_is_enabled(const char *soname) diff --git a/target/i386/latx/context/myalign.c b/target/i386/latx/context/myalign.c index ac4aa00b15d..efb58ff45ef 100644 --- a/target/i386/latx/context/myalign.c +++ b/target/i386/latx/context/myalign.c @@ -11,6 +11,7 @@ #include "myalign.h" #include "elfloader.h" #include "elfloader_private.h" +#include "kzt-groups.h" #include "kzt_public_loader_observer.h" #include "kzt_relro_preprotect.h" #include "latx-options.h" @@ -2102,7 +2103,7 @@ int kzt_init(char** argv, int argc,char** target_argv, int target_argc, elf_header = LoadFromNative(bprm, info); } if (option_kzt == 1 && elf_header) { - option_kzt = CheckEnableKZT(elf_header, target_argv, target_argc); + CheckEnableKZT(elf_header, target_argv, target_argc); } const char* prog = argv[1]; LoadEnvVars(my_context); @@ -2735,7 +2736,8 @@ void kzt_try_bind_before_guest_relro(uintptr_t start, size_t length, int prot) size_t dynamic_count; int processed = 0; - if (!option_kzt || in_preprotect || !my_context || !elf_header || + if (!latx_kzt_runtime_enabled() || + in_preprotect || !my_context || !elf_header || !have_mmap_lock() || !(prot & PROT_READ) || (prot & PROT_WRITE) || !length || (start & (TARGET_PAGE_SIZE - 1)) || @@ -3068,8 +3070,14 @@ void kzt_install_runtime_callbacks(CPUState *cpu, void *info) { struct image_info * execinfo = (struct image_info *)info; static uint32 jmpinst_exec [2] = {0}; - CPUArchState *env = cpu->env_ptr; - target_ulong eip = env->eip; + CPUArchState *env; + target_ulong eip; + + if (!latx_kzt_runtime_enabled()) { + return; + } + env = cpu->env_ptr; + eip = env->eip; kzt_public_loader_observer_reset(&kzt_public_loader_observer); memset(kzt_public_r_brk_inst, 0, sizeof(kzt_public_r_brk_inst)); @@ -3091,7 +3099,7 @@ void kzt_bridge_init(void) CPUState *cpu_tmp; kzt_tbbridge_init(); CPU_FOREACH(cpu_tmp) { - if (cpu_tmp && elf_header && option_kzt) { + if (cpu_tmp && elf_header && latx_kzt_runtime_enabled()) { kzt_install_runtime_callbacks(cpu_tmp, &info1); } } @@ -3120,7 +3128,7 @@ static void m_handle_ld(char * file_name, abi_ulong start) }; CPUState *cpu_tmp; CPU_FOREACH(cpu_tmp) { - if (cpu_tmp && option_kzt) { + if (cpu_tmp && latx_kzt_runtime_enabled()) { kzt_install_runtime_callbacks(cpu_tmp, &execinfo); } } @@ -3204,7 +3212,8 @@ void kzt_wine_bridge(abi_ulong start, int fd) void kzt_wine_init_x86(void) { - if (!option_kzt ||!latx_wine ||my_context->mallocmapsize) { + if (!latx_kzt_runtime_enabled() || !latx_wine || + my_context->mallocmapsize) { return; } struct malloc_map* m = malloc(sizeof(struct malloc_map)); diff --git a/target/i386/latx/context/wrapperdebug.c b/target/i386/latx/context/wrapperdebug.c index 041db5d596c..0b4ed382082 100644 --- a/target/i386/latx/context/wrapperdebug.c +++ b/target/i386/latx/context/wrapperdebug.c @@ -13,6 +13,7 @@ #include "debug.h" #include "library.h" #include "fileutils.h" +#include "latx-options.h" #if defined(CONFIG_LATX_KZT) && defined(CONFIG_LATX_DEBUG) void AddDebugInfo(int type, char *name, unsigned long start, unsigned long end) @@ -44,14 +45,15 @@ static struct latx_kzt_debug * latx_kzt_debuginfo_scan(uintptr_t x86pc) } return NULL; } -extern int option_kzt; - void latx_kzt_debuginfo_check(void) { char buf[4096]; FILE *f; uintptr_t tbptr, cs_base, threadhandle, x86pc, tbflags; - if (!option_kzt || !(qemu_loglevel & CPU_LOG_EXEC)) { //LAT_LOG=exec + + /* LAT_LOG=exec */ + if (!latx_kzt_runtime_enabled() || + !(qemu_loglevel & CPU_LOG_EXEC)) { return; } QemuLogFile *logfile = qatomic_rcu_read(&qemu_logfile); diff --git a/target/i386/latx/include/elfloader.h b/target/i386/latx/include/elfloader.h index 431903a6836..2c51770d5f1 100755 --- a/target/i386/latx/include/elfloader.h +++ b/target/i386/latx/include/elfloader.h @@ -73,5 +73,5 @@ void PltResolver(void); int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t* head, int cnt, Elf64_Rela *rela, int* need_resolv); uintptr_t loadSoaddrFromMap(char * real_path); void ElfHeadReFix (elfheader_t* head, uintptr_t delta); -int CheckEnableKZT(elfheader_t* h, char** target_argv, int target_argc); +void CheckEnableKZT(elfheader_t *h, char **target_argv, int target_argc); #endif //__ELF_LOADER_H_ diff --git a/target/i386/latx/include/kzt-groups.h b/target/i386/latx/include/kzt-groups.h index 5010b069e29..54aec692811 100644 --- a/target/i386/latx/include/kzt-groups.h +++ b/target/i386/latx/include/kzt-groups.h @@ -11,6 +11,7 @@ #include #include "kzt-group-list.h" +#include "kzt-runtime.h" typedef enum KztLibraryGroup { KZT_GROUP_NONE = 0, @@ -45,7 +46,17 @@ void kzt_groups_print_available(void); void kzt_groups_reset(void); bool kzt_groups_configure(const char *spec, bool log_enabled); void kzt_groups_reject_configuration(const char *reason, bool log_enabled); -uint32_t kzt_groups_enabled_mask(void); + +/* + * requested_mask is the dependency-complete user selection. Runtime + * compatibility checks remove unsafe families only from enabled_mask, so + * requested_mask & ~effective_mask identifies compatibility-disabled + * families. + */ +uint32_t kzt_groups_requested_mask(void); +uint32_t kzt_groups_effective_mask(void); +bool kzt_group_disable(KztLibraryGroup group, const char *reason); +void kzt_groups_disable_all(const char *reason); bool kzt_group_is_enabled(KztLibraryGroup group); bool kzt_library_is_enabled(const char *soname); const char *kzt_groups_last_error(void); diff --git a/target/i386/latx/include/kzt-runtime.h b/target/i386/latx/include/kzt-runtime.h new file mode 100644 index 00000000000..906cb7fd55f --- /dev/null +++ b/target/i386/latx/include/kzt-runtime.h @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2026 LAT Project Authors + * + * SPDX-License-Identifier: GPL-2.0-only + */ + +#ifndef LATX_KZT_RUNTIME_H +#define LATX_KZT_RUNTIME_H + +#include +#include + +/* + * option_kzt is the process-level 0/1/2 mode after loader policy, including + * direct-exec and Wine deferral. kzt_effective_groups is the library + * selection after dependency and compatibility pruning. Keeping these as + * separate facts makes every execution-time KZT hook follow both decisions. + * + * Group mutations are confined to kzt-groups.c and finish before guest code + * starts, so the hot execution paths can read the mask without another + * cached "active" flag. + */ +extern int option_kzt; +extern uint32_t kzt_effective_groups; + +static inline bool latx_kzt_runtime_enabled(void) +{ + return option_kzt != 0 && kzt_effective_groups != 0; +} + +#endif /* LATX_KZT_RUNTIME_H */ diff --git a/target/i386/latx/include/latx-options.h b/target/i386/latx/include/latx-options.h index bb396086e45..a751c96c28e 100644 --- a/target/i386/latx/include/latx-options.h +++ b/target/i386/latx/include/latx-options.h @@ -32,6 +32,8 @@ extern int option_tu_link; #endif #ifdef CONFIG_LATX_KZT +#include "kzt-runtime.h" + extern int option_kzt_log; extern char *option_kzt_libs; extern char *option_kzt_error; diff --git a/target/i386/latx/ir1/ir1.c b/target/i386/latx/ir1/ir1.c index 2fa7de401af..9df52561781 100644 --- a/target/i386/latx/ir1/ir1.c +++ b/target/i386/latx/ir1/ir1.c @@ -1719,7 +1719,10 @@ int ir1_is_syscall(IR1_INST *ir1) bool ir1_is_tb_ending(IR1_INST *ir1) { #if defined(CONFIG_LATX_KZT) - if(option_kzt && ir1_opcode(ir1) == dt_X86_INS_INT3) return true; + if (latx_kzt_runtime_enabled() && + ir1_opcode(ir1) == dt_X86_INS_INT3) { + return true; + } #endif if (option_anonym && (ir1_opcode(ir1) == dt_X86_INS_POPF || diff --git a/target/i386/latx/translator/tr-misc.c b/target/i386/latx/translator/tr-misc.c index e2e6d086c24..ee730750497 100644 --- a/target/i386/latx/translator/tr-misc.c +++ b/target/i386/latx/translator/tr-misc.c @@ -256,7 +256,9 @@ bool translate_int_3(IR1_INST *pir1) state_info.cflags = cpu->tcg_cflags; cpu_get_tb_cpu_state(cpu->env_ptr, &state_info.current_pc, &state_info.cs_base, &state_info.flags); - if(option_kzt && Peek8(state_info.current_pc + 1, 0) == 'S' && Peek8(state_info.current_pc + 1, 1) == 'C') + if (latx_kzt_runtime_enabled() && + Peek8(state_info.current_pc + 1, 0) == 'S' && + Peek8(state_info.current_pc + 1, 1) == 'C') { TranslationBlock *tb = NULL; mmap_lock(); diff --git a/target/i386/latx/translator/translate.c b/target/i386/latx/translator/translate.c index 6e47599018e..c7787b2f842 100644 --- a/target/i386/latx/translator/translate.c +++ b/target/i386/latx/translator/translate.c @@ -26,7 +26,7 @@ static int ss_generate_match_fail_native_code(void* code_buf); #if defined(CONFIG_LATX_KZT) uintptr_t kzt_get_alternate_pc(uintptr_t addr) { - if (!option_kzt || addr < reserved_va) { + if (!latx_kzt_runtime_enabled() || addr < reserved_va) { return addr; } return (uintptr_t)getAlternate((void *)addr); @@ -2760,7 +2760,7 @@ void tr_generate_exit_tb(IR1_INST *branch, int succ_id) la_profile_begin(); #endif #if defined(CONFIG_LATX_KZT) - if (option_kzt && succ_x86_addr >= reserved_va) { + if (latx_kzt_runtime_enabled() && succ_x86_addr >= reserved_va) { uintptr_t alt_pc = (uintptr_t)getAlternate((void *)(uintptr_t)succ_x86_addr); if (alt_pc != (uintptr_t)succ_x86_addr) { succ_x86_addr = (ADDR)alt_pc;