-
-
Save drvink/7fc4ff8698bd1f55c56ebe40bb20c644 to your computer and use it in GitHub Desktop.
Linux kernel module for Zen workaround for rr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| obj-m = zen_workaround.o | |
| all: | |
| make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules | |
| clean: | |
| make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <linux/module.h> | |
| #include <linux/kallsyms.h> | |
| #define MODULE_NAME "zen_workaround" | |
| typedef int set_memory_fn_t(unsigned long, int); | |
| unsigned long need_symbol(const char *name) | |
| { | |
| unsigned long sym = kallsyms_lookup_name(name); | |
| if (sym) { | |
| pr_info("%s is 0x%lx\n", name, sym); | |
| } else { | |
| pr_err("could not find kernel symbol %s\n", name); | |
| } | |
| return sym; | |
| } | |
| static set_memory_fn_t *set_memory_ro, *set_memory_rw; | |
| static _Atomic u64 *x86_amd_ls_cfg_base_ptr; | |
| static _Atomic int *kernel_set_to_readonly_ptr; | |
| u64 set_speclockmap_disable(u64 msr) { | |
| return msr | BIT_64(54); | |
| } | |
| u64 unset_speclockmap_disable(u64 msr) { | |
| return msr & ~BIT_64(54); | |
| } | |
| typedef u64 (*edit_msr_func_t)(u64); | |
| static void edit_ls_cfg_on_cpu(void *info) | |
| { | |
| int cpu = get_cpu(); | |
| u64 value = 0; | |
| if (!rdmsrl_safe(MSR_AMD64_LS_CFG, &value)) { | |
| edit_msr_func_t edit_msr = (edit_msr_func_t) info; | |
| u64 new_value = edit_msr(value); | |
| if (!wrmsrl_safe(MSR_AMD64_LS_CFG, new_value)) { | |
| pr_info("MSR_AMD64_LS_CFG for cpu %d was 0x%llx, setting to 0x%llx\n", | |
| cpu, value, new_value); | |
| } else { | |
| pr_err("MSR_AMD64_LS_CFG for cpu %d was 0x%llx, setting to 0x%llx failed\n", | |
| cpu, value, new_value); | |
| } | |
| } | |
| } | |
| static int do_zen_workaround(edit_msr_func_t edit_msr) | |
| { | |
| if (boot_cpu_has(X86_FEATURE_LS_CFG_SSBD)) { | |
| int ret; | |
| u64 old_value = *x86_amd_ls_cfg_base_ptr; | |
| u64 new_value = edit_msr(old_value); | |
| *kernel_set_to_readonly_ptr = 0; | |
| ret = set_memory_rw((unsigned long)x86_amd_ls_cfg_base_ptr, 1); | |
| *kernel_set_to_readonly_ptr = 1; | |
| if (ret) { | |
| pr_err("set_memory_rw failed with %d\n", ret); | |
| return -EPERM; | |
| } | |
| *x86_amd_ls_cfg_base_ptr = new_value; | |
| pr_info("x86_amd_ls_cfg_base was 0x%llx, setting to 0x%llx\n", old_value, new_value); | |
| *kernel_set_to_readonly_ptr = 0; | |
| ret = set_memory_ro((unsigned long)x86_amd_ls_cfg_base_ptr, 1); | |
| *kernel_set_to_readonly_ptr = 1; | |
| if (ret) { | |
| pr_err("set_memory_ro failed with %d\n", ret); | |
| // Not returning early because we still presumably set x86_amd_ls_cfg_base. | |
| } | |
| } else { | |
| pr_info("x86_amd_ls_cfg_base is unused."); | |
| } | |
| smp_call_function(edit_ls_cfg_on_cpu, edit_msr, 1); | |
| edit_ls_cfg_on_cpu(edit_msr); | |
| return 0; | |
| } | |
| static int __init zen_workaround_init(void) | |
| { | |
| if (!static_cpu_has(X86_FEATURE_ZEN)) { | |
| pr_err("Cannot use the Zen workaround on a non-Zen CPU\n"); | |
| return -EINVAL; | |
| } | |
| set_memory_ro = (set_memory_fn_t*) need_symbol("set_memory_ro"); | |
| set_memory_rw = (set_memory_fn_t*) need_symbol("set_memory_rw"); | |
| x86_amd_ls_cfg_base_ptr = (_Atomic u64*) need_symbol("x86_amd_ls_cfg_base"); | |
| kernel_set_to_readonly_ptr = (_Atomic int*) need_symbol("kernel_set_to_readonly"); | |
| if (!set_memory_ro || !set_memory_rw || !x86_amd_ls_cfg_base_ptr || | |
| !kernel_set_to_readonly_ptr) { | |
| return -ENOENT; | |
| } | |
| return do_zen_workaround(set_speclockmap_disable); | |
| } | |
| module_init(zen_workaround_init); | |
| static void __exit zen_workaround_exit(void) | |
| { | |
| do_zen_workaround(unset_speclockmap_disable); | |
| } | |
| module_exit(zen_workaround_exit) | |
| MODULE_LICENSE("GPL"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment