首页 > 解决方案 > 如何使用内联汇编在控制寄存器 (cr0) 中设置一个位?

问题描述

我正在尝试使用内联汇编设置 cr0 寄存器的第 30 位。我在我的内核模块中使用以下程序集,

__asm__ (
"mov %%cr0, %%rax\n\t"
"or 0x40000000, %%eax\n\t"
"mov %%rax, %%cr0\n\t"
:: 
:"%rax"
);

我的模块编译但在插入模块后我的终端冻结。当我尝试删除模块时,从新终端显示以下内容,

rmmod: ERROR: Module xxx is in use

dmesg在 中显示以下内容red color

RIP  [<ffffffffc09c604c>] hello_start+0x4c/0x1000 [ModuleName]

如何在 linux 上使用 gcc 程序集在 x86-64 中设置控制寄存器 0 (cr0) 位尝试通过 cr0 寄存器禁用分页也谈到了同样的问题。我尝试遵循他们的解决方案,但我无法让它发挥作用。任何帮助,我在内联汇编中哪里出错了?

更新帖子:

我已经根据@prl 的建议修复了代码,以下是我的完整源代码,

u64 get_cr0(void){
  u64 cr0;
  __asm__ (
  "mov %%cr0, %%rax\n\t"
  "mov %%eax, %0\n\t"
  : "=m" (cr0)
  : /* no input */
  : "%rax"
  );

  return cr0;
}   

static int __init hello_start(void){
  printk(KERN_INFO "Loading hello module...\n");
  printk(KERN_INFO "Hello world\n");

  printk(KERN_INFO "cr0 = 0x%8.8X\n", get_cr0());


  __asm__ (
  "mov %%cr0, %%rax\n\t"
  "or $0x40000000, %%eax\n\t"
  "mov %%rax, %%cr0\n\t"
   :: 
   :"%rax"
   );
   printk(KERN_INFO "cr0 after change = 0x%8.8X\n", get_cr0());
   return 0;
 }

static void __exit hello_end(void){
    printk(KERN_INFO "Goodbye Mr.\n");

    __asm__ (
    "mov %%cr0, %%rax\n\t"
    "and $~(0x40000000), %%eax\n\t"
    "mov %%rax, %%cr0\n\t"
    :: 
    :"%rax"
    );

}

事实上,我的系统在加载模块后运行速度非常慢。但是在更改位之后,我仍然没有看到cr0寄存器值有任何差异。以下是中的输出dmesg

[  +0.000400] Loading hello module...
[  +0.000001] Hello world
[  +0.000002] cr0 = 0x80050033
[  +0.000312] cr0 after change = 0x80050033
[  +6.085675] perf interrupt took too long (2522 > 2500), lowering kernel.perf_event_max_sample_rate to 50000

为什么我看不到 cr0 寄存器第 30 位的变化?

因此,在移除模块后,我尝试清除第 30 位,希望我的系统能够开始正常响应。但似乎没有奏效。我的系统仍然运行缓慢。任何想法,如何在修改后将系统恢复到正常功能状态cr0

标签: gcclinux-kernelx86x86-64inline-assembly

解决方案


推荐阅读