Update Booting/linux-bootstrap-1.md

This commit is contained in:
hailin cai
2016-03-01 09:36:52 -08:00
parent 0e9494f0c3
commit 641fc57f73

View File

@@ -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`。这样我们就得到了正确的堆栈设置,具体请参考下图:
![stack](http://oi58.tinypic.com/16iwcis.jpg)
@@ -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中已经详细介绍了接着我们就得到了如下图所示的堆栈
![stack](http://oi62.tinypic.com/dr7b5w.jpg)