如何在所有 CPU 上执行一段内核代码?
How to execute a piece of kernel code on all CPUs?
我正在尝试制作一个内核模块来为 x87 FPU 启用 FOP 兼容模式。这是通过设置 IA32_MISC_ENABLE
MSR 中的位 2 来完成的。这是代码:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/msr-index.h>
#include <asm/msr.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("10110111");
MODULE_DESCRIPTION("Module to enable FOPcode compatibility mode");
MODULE_VERSION("0.1");
static int __init fopCompat_init(void)
{
unsigned long long misc_enable=native_read_msr(MSR_IA32_MISC_ENABLE);
printk(KERN_INFO "Before trying to set FOP_COMPAT, IA32_MISC_ENABLE=%llx,"
" i.e. FOP_COMPAT is %senabled\n"
,misc_enable,misc_enable&MSR_IA32_MISC_ENABLE_X87_COMPAT?"":"NOT ");
wrmsrl(MSR_IA32_MISC_ENABLE,misc_enable|MSR_IA32_MISC_ENABLE_X87_COMPAT);
misc_enable=native_read_msr(MSR_IA32_MISC_ENABLE);
printk(KERN_INFO "Tried to set FOP_COMPAT. Result: IA32_MISC_ENABLE=%llx,"
" i.e. FOP_COMPAT is now %senabled\n"
,misc_enable,misc_enable&MSR_IA32_MISC_ENABLE_X87_COMPAT?"":"NOT ");
return 0;
}
static void __exit fopCompat_exit(void)
{
const unsigned long long misc_enable=native_read_msr(MSR_IA32_MISC_ENABLE);
printk(KERN_INFO "Quitting FOP-compat with IA32_MISC_ENABLE=%llx\n",misc_enable);
if(!(misc_enable & MSR_IA32_MISC_ENABLE_X87_COMPAT))
printk(KERN_INFO "NOTE: seems some CPUs still have to be set up, "
"or compatibility mode will work inconsistently\n");
printk(KERN_INFO "\n");
}
module_init(fopCompat_init);
module_exit(fopCompat_exit);
它似乎有效,但在多个 insmod/rmmod
周期中,我有时会得到 dmesg
输出,即兼容模式仍未启用,尽管它是在 wrmsr
之后立即启用的。经过一番思考,我意识到这是因为模块代码是在不同的逻辑 CPU 上执行的(我的 Core i7 有 4 个核心*HT=8 个逻辑 CPU),所以我有 1/8 的机会得到 "enabled" 打印做 rmmod
。重复这个循环大约 20 次后,我得到了一致的 "enabled" 打印,我的用户空间应用程序也很乐意使用它。
所以现在我的问题是:我怎样才能让我的代码在系统上存在的所有逻辑 CPU 上执行,以便为所有逻辑 CPU 启用兼容模式?
要在每个 CPU 上执行代码,请使用 on_each_cpu
函数。
签名:
int on_each_cpu(void (*func) (void *info), void *info, int wait)
描述:
Call a function on all processors.
如果 wait
参数是 non-zero,它会在所有 CPU 上等待函数完成。
函数 func
不应休眠,但整个 on_each_cpu()
调用不应在原子上下文中完成。
我正在尝试制作一个内核模块来为 x87 FPU 启用 FOP 兼容模式。这是通过设置 IA32_MISC_ENABLE
MSR 中的位 2 来完成的。这是代码:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/msr-index.h>
#include <asm/msr.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("10110111");
MODULE_DESCRIPTION("Module to enable FOPcode compatibility mode");
MODULE_VERSION("0.1");
static int __init fopCompat_init(void)
{
unsigned long long misc_enable=native_read_msr(MSR_IA32_MISC_ENABLE);
printk(KERN_INFO "Before trying to set FOP_COMPAT, IA32_MISC_ENABLE=%llx,"
" i.e. FOP_COMPAT is %senabled\n"
,misc_enable,misc_enable&MSR_IA32_MISC_ENABLE_X87_COMPAT?"":"NOT ");
wrmsrl(MSR_IA32_MISC_ENABLE,misc_enable|MSR_IA32_MISC_ENABLE_X87_COMPAT);
misc_enable=native_read_msr(MSR_IA32_MISC_ENABLE);
printk(KERN_INFO "Tried to set FOP_COMPAT. Result: IA32_MISC_ENABLE=%llx,"
" i.e. FOP_COMPAT is now %senabled\n"
,misc_enable,misc_enable&MSR_IA32_MISC_ENABLE_X87_COMPAT?"":"NOT ");
return 0;
}
static void __exit fopCompat_exit(void)
{
const unsigned long long misc_enable=native_read_msr(MSR_IA32_MISC_ENABLE);
printk(KERN_INFO "Quitting FOP-compat with IA32_MISC_ENABLE=%llx\n",misc_enable);
if(!(misc_enable & MSR_IA32_MISC_ENABLE_X87_COMPAT))
printk(KERN_INFO "NOTE: seems some CPUs still have to be set up, "
"or compatibility mode will work inconsistently\n");
printk(KERN_INFO "\n");
}
module_init(fopCompat_init);
module_exit(fopCompat_exit);
它似乎有效,但在多个 insmod/rmmod
周期中,我有时会得到 dmesg
输出,即兼容模式仍未启用,尽管它是在 wrmsr
之后立即启用的。经过一番思考,我意识到这是因为模块代码是在不同的逻辑 CPU 上执行的(我的 Core i7 有 4 个核心*HT=8 个逻辑 CPU),所以我有 1/8 的机会得到 "enabled" 打印做 rmmod
。重复这个循环大约 20 次后,我得到了一致的 "enabled" 打印,我的用户空间应用程序也很乐意使用它。
所以现在我的问题是:我怎样才能让我的代码在系统上存在的所有逻辑 CPU 上执行,以便为所有逻辑 CPU 启用兼容模式?
要在每个 CPU 上执行代码,请使用 on_each_cpu
函数。
签名:
int on_each_cpu(void (*func) (void *info), void *info, int wait)
描述:
Call a function on all processors.
如果 wait
参数是 non-zero,它会在所有 CPU 上等待函数完成。
函数 func
不应休眠,但整个 on_each_cpu()
调用不应在原子上下文中完成。