2015-04-17 47 views
2

我正在开发我的操作系统项目。启动器代码已经跳转到长模式并设置临时页表。我现在已经安装并填充了自己的页面表,并以我需要的方式完成了映射内存。现在我需要在CR3寄存器中设置PML4T的物理地址。如何在长模式下设置CR3寄存器(64位)

238 void setcr3(void * addr){ 
239 uint64_t temp=(uint64_t)addr; 
240 
241 __asm__ ("movq %0, %%cr3;"::"b"(temp)); 
242 } 

执行该指令时发生崩溃。 GDB步步​​连接

0x0000000000000000 in ??() 
(gdb) b setcr3 
Breakpoint 1 at 0xffffffff80201205: file sys/paging.c, line 238. 
(gdb) c 
Continuing. 

Breakpoint 1, setcr3 (addr=0x221000) at sys/paging.c:238 
238  void setcr3(void * addr){ 
(gdb) si 
241  __asm__ ("movq %0, %%cr3;"::"b"(temp)); 
(gdb) si 
0xffffffff80201209  241  __asm__ ("movq %0, %%cr3;"::"b"(temp)); 
(gdb) si 
242  } 
(gdb) si 
Remote connection closed 
(gdb) 
244 #define write_cr3(x) \ 
245 __asm__ __volatile__("movl %0,%%cr3": :"r" (x)) 


Error while compiling 

sys/paging.c: Assembler messages: 
sys/paging.c:271: Error: unsupported instruction `mov' 

编辑:

printf("address in cr3 %x\n", (uint64_t)pml4t - 0xffffffff80200000 + physbase); 
setcr3((void *) ((uint64_t)pml4t - 0xffffffff80200000 + physbase)); 


line 1 prints: 
address in cr3 221000 
+0

你忘了指定你的目标体系 – m0skit0

回答

0

你忘了展现在故障的实际指令。我假设它是movq %rbx, %cr3。此外,您还忘记显示%rbx(或任何源寄存器)的值。

这就是说,指令集参考列出了故障这两个适用条件:

  • 如果如果试图以一个1写入任何保留的当前特权级别不是0
  • 位在CR3。
+1

值Im写入到寄存器0x221000 –

+0

即根据列出的条件看起来无害的。仔细检查它实际上并不是更改后的分页表,禁止读取下一条指令。您的调试环境可能也是一个问题。我能够将'0x221000'写入'cr3'。除非您可以发布完整的可运行代码,否则我认为我无法提供更多帮助。 – Jester

0

ASM( “MOVQ%0,%% CR 3;” :: “B”(临时));

代替“b”,我推荐使用“r”,以便编译器负责使用哪个寄存器来移动值并在执行指令后恢复它。

ASM挥发性( “MOVL%0,%% CR3”: “R”(X));

使用movq而不是movl。

setcr3((void *)((uint64_t)pml4t - 0xffffffff80200000 + physbase));

如果被设置在内核中首次页表,你只需要从pml4t的虚拟地址,以物理地址传递给CR3寄存器中扣除0xffffffff80200000。没有必要添加physbase。这是因为,你可能在加载内核的elf部分之后在内存中占用第一个可用地址。

最后,最好在asm块之前添加volatile,这样编译器不会优化指令。此外,为了避免类型转换,请直接使用下面的代码行来代替宏,看看会发生什么。

ASM挥发性( “MOVQ%[cr3_var],%% CR 3;” :: [cr3_var] “R”((uint64_t中)pml4t));

相关问题