2

我正在研究我的操作系统项目。入门代码已经跳转到长模式并设置临时页表。我现在已经设置并填充了我自己的页表,并按照我需要的方式完成了内存映射。现在我需要在 CR3 寄存器中设置 PML4T 的物理地址。

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
4

2 回答 2

1

You forgot to show the actual instruction at the fault. I assume it is movq %rbx, %cr3. Furthermore, you also forgot to show the value of %rbx (or whatever the source register is).

That said, the instruction set reference lists these two applicable conditions for a fault:

  • If the current privilege level is not 0.
  • If an attempt is made to write a 1 to any reserved bit in CR3.
于 2015-04-17T23:02:51.037 回答
0

asm ("movq %0, %%cr3;"::"b"(temp));

代替“b”,我建议使用“r”,以便编译器处理用于移动值的寄存器并在执行指令后恢复它。

asm volatile ("movl %0,%%cr3": :"r" (x));

使用 movq 而不是 movl。

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

如果是第一次在内核中设置页表,则只需从 pml4t 的虚拟地址中减去 0xffffffff80200000 即可将物理地址传递给 cr3 寄存器。无需添加 physbase。这是因为,您可能会在加载内核的 elf 部分后获取内存中的第一个可用地址。

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

asm volatile ("movq %[cr3_var], %%cr3;"::[cr3_var]"r"((uint64_t)pml4t));

于 2015-04-18T10:39:51.690 回答