Skip to content

Instantly share code, notes, and snippets.

@drvink
Forked from glandium/Makefile
Created June 4, 2022 03:06
Show Gist options
  • Select an option

  • Save drvink/7fc4ff8698bd1f55c56ebe40bb20c644 to your computer and use it in GitHub Desktop.

Select an option

Save drvink/7fc4ff8698bd1f55c56ebe40bb20c644 to your computer and use it in GitHub Desktop.

Revisions

  1. @glandium glandium revised this gist Sep 21, 2020. 1 changed file with 18 additions and 7 deletions.
    25 changes: 18 additions & 7 deletions zen_workaround.c
    Original file line number Diff line number Diff line change
    @@ -47,12 +47,19 @@ void on_write_msr(void *data, unsigned int msr, u64 val, int failed)
    }
    }

    static int install_probe(void)
    {
    return !boot_cpu_has(X86_FEATURE_AMD_SSBD) && !boot_cpu_has(X86_FEATURE_VIRT_SSBD);
    }

    static int enable_zen_workaround(void)
    {
    int ret = tracepoint_probe_register(&__tracepoint_write_msr, on_write_msr, NULL);
    if (ret) {
    pr_err("Registering tracepoint probe failed\n");
    return ret;
    if (install_probe()) {
    int ret = tracepoint_probe_register(&__tracepoint_write_msr, on_write_msr, NULL);
    if (ret) {
    pr_err("Registering tracepoint probe failed\n");
    return ret;
    }
    }
    do_zen_workaround(set_speclockmap_disable);
    return 0;
    @@ -68,7 +75,9 @@ static int pm_notification(struct notifier_block *this, unsigned long event, voi
    break;
    case PM_HIBERNATION_PREPARE:
    case PM_SUSPEND_PREPARE:
    tracepoint_probe_unregister(&__tracepoint_write_msr, on_write_msr, NULL);
    if (install_probe()) {
    tracepoint_probe_unregister(&__tracepoint_write_msr, on_write_msr, NULL);
    }
    break;
    }
    return NOTIFY_DONE;
    @@ -80,7 +89,7 @@ static struct notifier_block pm_notifier = {

    static int __init zen_workaround_init(void)
    {
    if (!static_cpu_has(X86_FEATURE_ZEN)) {
    if (!boot_cpu_has(X86_FEATURE_ZEN)) {
    pr_err("Cannot use the Zen workaround on a non-Zen CPU\n");
    return -EINVAL;
    }
    @@ -93,7 +102,9 @@ module_init(zen_workaround_init);
    static void __exit zen_workaround_exit(void)
    {
    unregister_pm_notifier(&pm_notifier);
    tracepoint_probe_unregister(&__tracepoint_write_msr, on_write_msr, NULL);
    if (install_probe()) {
    tracepoint_probe_unregister(&__tracepoint_write_msr, on_write_msr, NULL);
    }
    do_zen_workaround(unset_speclockmap_disable);
    }
    module_exit(zen_workaround_exit);
  2. @glandium glandium revised this gist Sep 21, 2020. 1 changed file with 40 additions and 12 deletions.
    52 changes: 40 additions & 12 deletions zen_workaround.c
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,6 @@
    #include <linux/module.h>
    #include <linux/tracepoint.h>
    #include <linux/suspend.h>

    #define MODULE_NAME "zen_workaround"

    @@ -33,40 +34,67 @@ static void edit_ls_cfg_on_cpu(void *info)
    }
    }

    static int do_zen_workaround(edit_msr_func_t edit_msr)
    static void do_zen_workaround(edit_msr_func_t edit_msr)
    {
    smp_call_function(edit_ls_cfg_on_cpu, edit_msr, 1);
    edit_ls_cfg_on_cpu(edit_msr);
    return 0;
    }

    void on_write_msr(void *data, unsigned int msr, u64 val, int failed) {
    void on_write_msr(void *data, unsigned int msr, u64 val, int failed)
    {
    if (msr == MSR_AMD64_LS_CFG && !(val & SPECLOCKMAP_DISABLE)) {
    native_wrmsrl(MSR_AMD64_LS_CFG, set_speclockmap_disable(val));
    }
    }

    static int __init zen_workaround_init(void)
    static int enable_zen_workaround(void)
    {
    int ret;
    if (!static_cpu_has(X86_FEATURE_ZEN)) {
    pr_err("Cannot use the Zen workaround on a non-Zen CPU\n");
    return -EINVAL;
    }
    ret = tracepoint_probe_register(&__tracepoint_write_msr, on_write_msr, NULL);
    int ret = tracepoint_probe_register(&__tracepoint_write_msr, on_write_msr, NULL);
    if (ret) {
    pr_err("Registering tracepoint probe failed\n");
    return ret;
    }
    do_zen_workaround(set_speclockmap_disable);
    return 0;
    }

    return do_zen_workaround(set_speclockmap_disable);
    static int pm_notification(struct notifier_block *this, unsigned long event, void *ptr)
    {
    switch (event) {
    case PM_POST_SUSPEND:
    case PM_POST_HIBERNATION:
    case PM_POST_RESTORE:
    enable_zen_workaround();
    break;
    case PM_HIBERNATION_PREPARE:
    case PM_SUSPEND_PREPARE:
    tracepoint_probe_unregister(&__tracepoint_write_msr, on_write_msr, NULL);
    break;
    }
    return NOTIFY_DONE;
    }

    static struct notifier_block pm_notifier = {
    .notifier_call = pm_notification,
    };

    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;
    }
    enable_zen_workaround();
    register_pm_notifier(&pm_notifier);
    return 0;
    }
    module_init(zen_workaround_init);

    static void __exit zen_workaround_exit(void)
    {
    do_zen_workaround(unset_speclockmap_disable);
    unregister_pm_notifier(&pm_notifier);
    tracepoint_probe_unregister(&__tracepoint_write_msr, on_write_msr, NULL);
    do_zen_workaround(unset_speclockmap_disable);
    }
    module_exit(zen_workaround_exit);

  3. @glandium glandium revised this gist Sep 21, 2020. 1 changed file with 17 additions and 58 deletions.
    75 changes: 17 additions & 58 deletions zen_workaround.c
    Original file line number Diff line number Diff line change
    @@ -1,31 +1,16 @@
    #include <linux/module.h>
    #include <linux/kallsyms.h>
    #include <linux/tracepoint.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;
    #define SPECLOCKMAP_DISABLE BIT_64(54)

    u64 set_speclockmap_disable(u64 msr) {
    return msr | BIT_64(54);
    return msr | SPECLOCKMAP_DISABLE;
    }

    u64 unset_speclockmap_disable(u64 msr) {
    return msr & ~BIT_64(54);
    return msr & ~SPECLOCKMAP_DISABLE;
    }

    typedef u64 (*edit_msr_func_t)(u64);
    @@ -50,55 +35,28 @@ static void edit_ls_cfg_on_cpu(void *info)

    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;
    }

    void on_write_msr(void *data, unsigned int msr, u64 val, int failed) {
    if (msr == MSR_AMD64_LS_CFG && !(val & SPECLOCKMAP_DISABLE)) {
    native_wrmsrl(MSR_AMD64_LS_CFG, set_speclockmap_disable(val));
    }
    }

    static int __init zen_workaround_init(void)
    {
    int ret;
    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;
    ret = tracepoint_probe_register(&__tracepoint_write_msr, on_write_msr, NULL);
    if (ret) {
    pr_err("Registering tracepoint probe failed\n");
    return ret;
    }

    return do_zen_workaround(set_speclockmap_disable);
    @@ -108,7 +66,8 @@ module_init(zen_workaround_init);
    static void __exit zen_workaround_exit(void)
    {
    do_zen_workaround(unset_speclockmap_disable);
    tracepoint_probe_unregister(&__tracepoint_write_msr, on_write_msr, NULL);
    }
    module_exit(zen_workaround_exit)
    module_exit(zen_workaround_exit);

    MODULE_LICENSE("GPL");
  4. @glandium glandium revised this gist Sep 19, 2020. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions zen_workaround.c
    Original file line number Diff line number Diff line change
    @@ -50,9 +50,9 @@ static void edit_ls_cfg_on_cpu(void *info)

    static int do_zen_workaround(edit_msr_func_t edit_msr)
    {
    u64 old_value = *x86_amd_ls_cfg_base_ptr;
    if (old_value) {
    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;
  5. @glandium glandium revised this gist Sep 19, 2020. 2 changed files with 121 additions and 1 deletion.
    8 changes: 7 additions & 1 deletion Makefile
    Original file line number Diff line number Diff line change
    @@ -1 +1,7 @@
    obj-m = zen_workaround.o
    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
    114 changes: 114 additions & 0 deletions zen_workaround.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,114 @@
    #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)
    {
    u64 old_value = *x86_amd_ls_cfg_base_ptr;
    if (old_value) {
    int ret;
    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");
  6. @glandium glandium created this gist Sep 19, 2020.
    1 change: 1 addition & 0 deletions Makefile
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    obj-m = zen_workaround.o