背景信息:我在 QEMU 下运行 Xv6,并使用 GDB 作为调试器。我正在逐步浏览引导加载程序以查看它的功能。Xv6 旨在在加载内核之前切换为 32 位代码。
在汇编文件bootasm.S
中,跳转到 32 位。进行转换的指令如下:
# Complete transition to 32-bit protected mode by using long jmp
# to reload %cs and %eip. The segment descriptors are set up with no
# translation, so that the mapping is still the identity mapping.
ljmp $(SEG_KCODE<<3), $start32
跳转之前的分段地址寄存器(由CS
和EIP
连接的寄存器组成)的值,可以从GDB's info reg
命令中读取,是CS=0x0:EIP=7c2c
.
跳转之后,分段地址就是 now CS=0x8:EIP=0x7c31
,这里0x7c31
是 32 位代码的开始地址(包含在 bootasm.S 下start32
)。.
我知道分段地址通过乘以CS
16 并EIP
作为偏移量添加到物理地址中。例如,当 时CS = 0x0
,物理地址为(0x10 * 0xf000) + 0x7c2c = 0xf0000 + 0x7c2c = 0xf7c2c
。
我的问题是关于CS
寄存器的内在价值。现在如何CS
从0x0
等于0x8
运行 32 位代码?如果我理解正确,基于如何0x0 * 16 = 0xf0000
,那么0x8 * 16 = 0xf0080
,对吗?但是这个分段地址如何等同于 32 位呢?还是我只是误解了CS
寄存器的值代表什么?
编辑:感谢回复,我意识到LGDT
在跳转之前执行的指令是相关的。这是跳转前的指令及其后续指令,可在以下位置找到bootasm.S
:
# Switch from real to protected mode. Use a bootstrap GDT that makes
# virtual addresses map directly to physical addresses so that the
# effective memory map doesn't change during the transition.
lgdt gdtdesc
movl %cr0, %eax
orl $CR0_PE, %eax
movl %eax, %cr0