引导加载程序 - 将处理器切换到保护模式
我很难理解简单的引导加载程序是如何工作的。我所说的引导加载程序来自麻省理工学院的“操作系统工程”课程。
首先给大家看一段BIOS执行的汇编代码:
[f000:fec3] 0xffec3: lidtw %cs:0x7908
[f000:fec9] 0xffec9: lgdtw %cs:0x7948
[f000:fecf] 0xffecf: mov %cr0,%eax
[f000:fed2] 0xffed2: or $0x1,%eax
[f000:fed6] 0xffed6: mov %eax,%cr0
[f000:fed9] 0xffed9: ljmpl $0x8,$0xffee1
从代码来看,这段代码设置了中断表和描述符表,然后开启了保护模式。
- 为什么我们要进入保护模式 在BIOS中?不应该是 引导加载程序以实模式运行(顺便说一句 - 为什么需要真实运行 模式?)
- 我搜索但没有找到任何地方 ljmpl 指令到底如何 有效,并且是之间的区别 it 和 ljmp 以及常规 jmp - I 如果有人愿意,我将不胜感激 指向正确的方向。
- 我们为什么要进行跳跃?什么是 该指令的目的?
继续讨论引导加载程序代码 -
# Switch from real to protected mode, using a bootstrap GDT
# and segment translation that makes virtual addresses
# identical to their physical addresses, so that the
# effective memory map does not change during the switch.
lgdt gdtdesc
movl %cr0, %eax
orl $CR0_PE_ON, %eax
movl %eax, %cr0
# Jump to next instruction, but in 32-bit code segment.
# Switches processor into 32-bit mode.
ljmp $PROT_MODE_CSEG, $protcseg
- 它表示处理器处于 实模式 - 但我们刚刚看到 BIOS 切换到保护模式... 我很困惑——怎么会这样 可能的?
- 我们如何切换到32位模式?什么 导致处理器神奇地运行 由于 ljmp 进入 32 位模式 操作说明?
另一件我不明白的事情 - 当我使用 gdb 跟踪引导加载程序的执行时,我看到正在执行以下指令(这是引导加载程序代码中的 ljmp 指令):
ljmp $0x8,$0x7c32
但是当我查看 .asm 文件时,我看到了以下:
ljmp $0xb866,$0x87c32
完全迷失了 - 为什么.asm文件中写入的指令和执行的指令不同?我有预感这与保护模式及其如何转换地址有关,但我不太明白。
我将不胜感激任何帮助!
I'm having difficulties understanding how a simple boot loader works. The boot loader I'm talking about is the one from MITs course "Operating Systems Engineering".
First, let me show you a piece of assembly code the BIOS executes:
[f000:fec3] 0xffec3: lidtw %cs:0x7908
[f000:fec9] 0xffec9: lgdtw %cs:0x7948
[f000:fecf] 0xffecf: mov %cr0,%eax
[f000:fed2] 0xffed2: or $0x1,%eax
[f000:fed6] 0xffed6: mov %eax,%cr0
[f000:fed9] 0xffed9: ljmpl $0x8,$0xffee1
From the looks of it, This code sets up the interrupt table and the descriptor table and then turns on the protected mode.
- Why do we go into protected mode
in the BIOS? Shouldn't the
bootloader run in real mode (btw -
why does it need to run in real
mode?) - I searched but didn't find anywhere
exactly how the ljmpl instruction
works, and is the difference between
it and ljmp and regular jmp - I
would appreciate if someone would
point in the right direction. - Why do we perform the jump? What is
the purpose of this instruction?
Moving on to the boot loader code -
# Switch from real to protected mode, using a bootstrap GDT
# and segment translation that makes virtual addresses
# identical to their physical addresses, so that the
# effective memory map does not change during the switch.
lgdt gdtdesc
movl %cr0, %eax
orl $CR0_PE_ON, %eax
movl %eax, %cr0
# Jump to next instruction, but in 32-bit code segment.
# Switches processor into 32-bit mode.
ljmp $PROT_MODE_CSEG, $protcseg
- It says that the processor is in
real mode - but we just saw that the
BIOS switches to protected mode...
I'm confused - how can this be
possible? - How do we switch to 32bit mode? What
causes the processor to magically go
into 32bit mode due to the ljmp
instruction?
And another thing that I don't understand - when I track the execution of the bootloader with gdb I see the following instruction being executed (that's the ljmp instruction from the bootloader code):
ljmp $0x8,$0x7c32
But when I looked in the .asm file I saw the following:
ljmp $0xb866,$0x87c32
Totally lost here - How come the instruction written in the .asm file and the instruction executed are different? I have a hunch this has to do with the protected mode and how it translates the addresses but I don't really get it.
I would appreciate any help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
某些 BIOS 实现在进入引导加载程序之前会进入保护模式。大多数人没有。 BIOS 可能会短暂切换到保护模式,然后在进入引导加载程序之前切换回来,这将允许它利用保护模式的一些好处(例如 32 位是默认地址大小)。引导加载程序应处于实模式的原因是,大多数 BIOS 功能只能在实模式下工作,因此您需要处于实模式才能使用它们。
ljmp 除了指定要跳转到的地址之外,还指定要切换到的代码段。它们非常相似(至少在 GAS 中),汇编器将为您将带有 2 个操作数的 jmp 切换为 ljmp。
ljmp 是更改 cs 寄存器的唯一方法之一。需要执行此操作才能激活保护模式,因为 cs 寄存器需要包含 GDT 中代码段的选择器。 (如果您想知道,更改 cs 的其他方法是远调用、远返回和中断返回)
请参阅第 1 项。要么 BIOS 切换回实模式,要么此引导加载程序将无法与此 BIOS 一起工作。
参见第 3 项。它更改 cs 以指定 32 位代码段,因此处理器进入 32 位模式。
当您查看 .asm 文件时,该指令被解释为地址大小为 32 位,但 GDB 将其解释为地址大小为 16 位。指令地址处的数据为 0xEA 32 7C 08 00 66 B8。 EA 是跳远操作码。在 32 位地址空间中,对于地址 0x87C32,将使用接下来的 4 个字节来指定地址,但在 16 位地址空间中,对于地址 0x7C32,仅使用 2 个字节。地址后的 2 个字节指定请求的代码段,在 32 位模式下为 0xB866,在 16 位模式下为 0x0008。 0x66 B8 是下一条指令的开始,该指令将 16 位立即值移入 ax 寄存器,可能是为了设置保护模式的数据段。
Some BIOS implementations go into protected mode before entering the bootloader. Most don't. It is possible that BIOS switches to protected mode for a short period and switches back before going to the bootloader, which would allow it to use some of the benefits of protected mode (such as 32 bit being the default address size). The reason that the bootloader should be in real mode is that most BIOS functions only work in real mode, so you need to be in real mode to use them.
ljmp specifies a code segment to switch to in addition to the address to jump to. They are so similar that (at least in GAS) the assembler will switch a jmp with 2 operands to a ljmp for you.
ljmp is one of the only ways to change the cs register. This needs to be done to activate protected mode, as the cs register needs to contain the selector for a code segment in the GDT. (In case you want to know, the other ways to change cs are far call, far return, and interrupt return)
See item 1. Either BIOS switched back to real mode, or this bootloader will not work with this BIOS.
See item 3. It changes cs to specify a 32 bit code segment, so the processor goes into 32 bit mode.
When you looked at the .asm file, the instruction was interpretted as if the address size was 32 bits, but GDB interpretted it as if the address size was 16 bits. The data at the address of the instruction would be 0xEA 32 7C 08 00 66 B8. EA is the long jump opcode. In a 32 bit address space, the address would be specified using the next four bytes, for an address of 0x87C32, but in a 16 bit address space, only 2 bytes are used, for an address of 0x7C32. The 2 bytes after the address specify the requested code segment, which would be 0xB866 in 32 bit mode and 0x0008 in 16 bit mode. The 0x66 B8 is the start of the next instruction, which is moving a 16 bit immediate value into the ax register, probably to set up the data segments for protected mode.
为什么BIOS要进入保护模式?引导加载程序不应该在实模式下运行吗(顺便说一句 - 为什么它需要在实模式下运行?)
保护模式只是提供比实模式更多的功能:本质上是 Intel CPU 的保护环特权机制(http://en.wikipedia. org/wiki/Ring_(computer_security)、32位模式执行等。
我搜索过但没有找到 ljmpl 指令的工作原理,以及它与 ljmp 和常规 jmp 之间的区别 - 如果有人指出,我将不胜感激在正确的方向上,
ljmpl 和 ljmp 在这里的上下文是相同的。
为什么我们执行该指令的目的是什么?
这是英特尔手册中所要求的,并且也内联在下面所示的代码中。
对于实际到受保护的转换,它在 stage2 引导加载程序中实现:
http://src.illumos.org/source/xref/illumos-gate/usr/src/grub/grub-0.97/stage2/asm.S#real_to_prot< /a>
正如你所看到的,代码的每一部分都有一个功能,ljmp本质上是冲出预取队列,按照Intel手册中的要求,我不记得在哪里了。
Why do we go into protected mode in the BIOS? Shouldn't the bootloader run in real mode (btw - why does it need to run in real mode?)
Protected mode simply offer a lot more feature than realmode: essentially Intel CPU's protection ring privilege mechanism (http://en.wikipedia.org/wiki/Ring_(computer_security), 32-bit mode execution etc.
I searched but didn't find anywhere exactly how the ljmpl instruction works, and is the difference between it and ljmp and regular jmp - I would appreciate if someone would point in the right direction.
ljmpl and ljmp is the same contextually here.
Why do we perform the jump? What is the purpose of this instruction?
This is required as documented in Intel manual, and documented inlined in the code shown below as well..
For the real-to-protected transition, it is implemented in stage2 bootloader here:
http://src.illumos.org/source/xref/illumos-gate/usr/src/grub/grub-0.97/stage2/asm.S#real_to_prot
As u can see, each part of the code has a function, and ljmp is essentially to flush out the prefetch queue, as required in the Intel manual, I cannot remember where.