mirror of
https://github.com/MintCN/linux-insides-zh.git
synced 2026-04-25 11:11:20 +08:00
Update Booting/linux-bootstrap-1.md
This commit is contained in:
@@ -320,7 +320,7 @@ _start:
|
||||
state.cs = segment + 0x20;
|
||||
```
|
||||
|
||||
在我的机器上,因为我的内核代码被加载到了内存地址 `0x10000` 处,所以在上面的代码执行完成之后 `cs = 0x1020` ( 一次第一条指令的内存地址将是 `cs << 4 + 0 = 0x10200`,刚好是 `0x10000` 开始后的 `0x200` 处的指令):
|
||||
在我的机器上,因为我的内核代码被加载到了内存地址 `0x10000` 处,所以在上面的代码执行完成之后 `cs = 0x1020` ( 因此第一条指令的内存地址将是 `cs << 4 + 0 = 0x10200`,刚好是 `0x10000` 开始后的 `0x200` 处的指令):
|
||||
|
||||
```
|
||||
fs = es = ds = ss = 0x1000
|
||||
@@ -345,7 +345,7 @@ cs = 0x1020
|
||||
sti
|
||||
```
|
||||
|
||||
就像我在上面一节中所写的, 为了能够跳转到 `_start` 标号出执行代码,grub2 将 `cs` 段寄存器的值设置成了 `0x1020`,这个值和其他段寄存器都是不一样的,因此接下来的代码就是将 `cs` 段寄存器的值和其他段寄存器一致:
|
||||
就像我在上面一节中所写的, 为了能够跳转到 `_start` 标号出执行代码,grub2 将 `cs` 段寄存器的值设置成了 `0x1020`,这个值和其他段寄存器都是不一样的,因此下面的代码就是将 `cs` 段寄存器的值和其他段寄存器一致:
|
||||
|
||||
```assembly
|
||||
pushw %ds
|
||||
@@ -353,12 +353,12 @@ cs = 0x1020
|
||||
lretw
|
||||
```
|
||||
|
||||
上面的代码使用了一个小小的技巧来重置 `cs` 寄存器的内容,下面我们就来仔细份额系。 这段代码首先将 `ds`寄存器的值入栈,然后将标号为 `6` 的代码段地址入栈 [6](https://github.com/torvalds/linux/blob/master/arch/x86/boot/header.S#L494),接着执行 `lretw` 指令,这条指令,将把标号为 `6` 的内存地址放入 `ip` 寄存器 [instruction pointer](https://en.wikipedia.org/wiki/Program_counter),将 `ds` 寄存器的值放入 `cs` 寄存器。 这样一来 `ds` 和 `cs` 段寄存器就拥有了相同的值。
|
||||
上面的代码使用了一个小小的技巧来重置 `cs` 寄存器的内容,下面我们就来仔细分析。 这段代码首先将 `ds`寄存器的值入栈,然后将标号为 [6](https://github.com/torvalds/linux/blob/master/arch/x86/boot/header.S#L494) 的代码段地址入栈 ,接着执行 `lretw` 指令,这条指令,将把标号为 `6` 的内存地址放入 `ip` 寄存器 ([instruction pointer](https://en.wikipedia.org/wiki/Program_counter)),将 `ds` 寄存器的值放入 `cs` 寄存器。 这样一来 `ds` 和 `cs` 段寄存器就拥有了相同的值。
|
||||
|
||||
设置堆栈
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
绝大部分的 setup 代码都是在为 C 语言运行环境做准备。在设置了 `ds` 和 `es` 寄存器之后,接下来 [step](https://github.com/torvalds/linux/blob/master/arch/x86/boot/header.S#L467) 的代码将检查 `ss` 寄存器的内容,如果寄存器的内容不对,那么将进行更正:
|
||||
绝大部分的 setup 代码都是为 C 语言运行环境做准备。在设置了 `ds` 和 `es` 寄存器之后,接下来 [step](https://github.com/torvalds/linux/blob/master/arch/x86/boot/header.S#L467) 的代码将检查 `ss` 寄存器的内容,如果寄存器的内容不对,那么将进行更正:
|
||||
|
||||
```assembly
|
||||
movw %ss, %dx
|
||||
@@ -375,7 +375,7 @@ cs = 0x1020
|
||||
|
||||
下面我们就来分析在这三中情况下,代码都是如何工作的:
|
||||
|
||||
1. `ss` 寄存器的值是 0x10000,在这种情况下,代码将直接调准到标号为 `2` 的代码处执行:
|
||||
1. `ss` 寄存器的值是 0x10000,在这种情况下,代码将直接跳转到标号为 `2` 的代码处执行:
|
||||
|
||||
```
|
||||
2: andw $~3, %dx
|
||||
@@ -386,7 +386,7 @@ cs = 0x1020
|
||||
sti
|
||||
```
|
||||
|
||||
这段代码首先将 `dx` 寄存器的值(就是当前`sp` 寄存器的值)4字节对齐,然后检查是否为0(如果是0,堆栈就不对了,因为堆栈是从大地址向小地址发展的),如果是0,那么就将 `dx` 寄存器的值设置成 `0xfffc` (64KB地址段的最后一个4字节地址)。如果不是0,那么就保持当前值不变。接下来,就将 `ax` 寄存器的值( 0x10000 )设置到 `ss` 寄存器,并根据 `bx` 寄存器的值设置正确的 `sp`。这样我们就得到了正确的堆栈设置,具体请参考下图:
|
||||
这段代码首先将 `dx` 寄存器的值(就是当前`sp` 寄存器的值)4字节对齐,然后检查是否为0(如果是0,堆栈就不对了,因为堆栈是从大地址向小地址发展的),如果是0,那么就将 `dx` 寄存器的值设置成 `0xfffc` (64KB地址段的最后一个4字节地址)。如果不是0,那么就保持当前值不变。接下来,就将 `ax` 寄存器的值( 0x10000 )设置到 `ss` 寄存器,并根据 `dx` 寄存器的值设置正确的 `sp`。这样我们就得到了正确的堆栈设置,具体请参考下图:
|
||||
|
||||

|
||||
|
||||
@@ -412,7 +412,7 @@ Field name: loadflags
|
||||
#define CAN_USE_HEAP (1<<7)
|
||||
```
|
||||
|
||||
如果 `CAN_USE_HEAP` 被置位,那么将 `heap_end_ptr` 放入 `dx` 寄存器,然后加上 `STACK_SIZE` (最小堆栈大小是 512 bytes)。在加法完成之后,如果结果没有溢出(CF flag 没有置位),那么就跳转到标号为 `2` 的代码处继续执行(这段代码的逻辑在1中已经详细介绍了),接着我们就得到了如下图所示的堆栈:
|
||||
如果 `CAN_USE_HEAP` 被置位,那么将 `heap_end_ptr` 放入 `dx` 寄存器,然后加上 `STACK_SIZE` (最小堆栈大小是 512 bytes)。在加法完成之后,如果结果没有溢出(CF flag 没有置位,如果置位那么程序就出错了),那么就跳转到标号为 `2` 的代码处继续执行(这段代码的逻辑在1中已经详细介绍了),接着我们就得到了如下图所示的堆栈:
|
||||
|
||||

|
||||
|
||||
|
||||
Reference in New Issue
Block a user