diff --git a/Booting/linux-bootstrap-3.md b/Booting/linux-bootstrap-3.md index e97bedc..2cd453c 100644 --- a/Booting/linux-bootstrap-3.md +++ b/Booting/linux-bootstrap-3.md @@ -323,9 +323,9 @@ io_delay(); 上面的代码首先调用 `cli` 汇编指令清楚了中断标志 `IF`,这条指令执行之后,外部中断就被禁止了,紧接着的下一行代码就禁止了 NMI 中断。 -An interrupt is a signal to the CPU which is emitted by hardware or software. After getting the signal, the CPU suspends the current instruction sequence, saves its state and transfers control to the interrupt handler. After the interrupt handler has finished it's work, it transfers control to the interrupted instruction. Non-maskable interrupts (NMI) are interrupts which are always processed, independently of permission. It cannot be ignored and is typically used to signal for non-recoverable hardware errors. We will not dive into details of interrupts now, but will discuss it in the next posts. +这里简单介绍一下中断。中断是由硬件或者软件产生的,当中断产生的时候, CPU 将得到通知。这个时候, CPU 将停止当前指令的执行,保存当前代码的环境,然后将控制权移交到中断处理程序。当中断处理程序完成之后,将恢复中断之前的运行环境,那么被中断的代码将继续运行。 NMI 中断是一类特殊的中断,往往预示着系统发生了不可恢复的错误,所以在正常运行的操作系统中,NMI 中断是不会被禁止的,但是在进入保护模式之前,由于特殊需求,代码禁止了这类中断。我们将在后续的章节中对中断做更多的介绍,这里就不展开了。 -Let's get back to the code. We can see that second line is writing `0x80` (disabled bit) byte to `0x70` (CMOS Address register). After that, a call to the `io_delay` function occurs. `io_delay` causes a small delay and looks like: +现在让我们回到上面的代码,在 NMI 中断被禁止之后(通过写 `0x80` 进 CMOS 地址寄存器 `0x70` ),函数接着调用了 `io_delay` 函数进行了短暂的延时以等待 I/O 操作完成。下面就是 `io_delay` 函数的实现: ```C static inline void io_delay(void) @@ -335,9 +335,9 @@ static inline void io_delay(void) } ``` -Outputting any byte to the port `0x80` should delay exactly 1 microsecond. So we can write any value (value from `AL` register in our case) to the `0x80` port. After this delay `realmode_switch_hook` function has finished execution and we can move to the next function. +对 I/O 端口 `0x80` 写入任何的字节都将得到 1 ms 的延时。在上面的代码中,代码将 `al` 寄存器中的值写到了这个端口。在这个 `io_delay` 调用完成之后, `realmode_switch_hook` 函数就完成了所有工作,下面让我们进入下一个函数。 -The next function is `enable_a20`, which enables [A20 line](http://en.wikipedia.org/wiki/A20_line). This function is defined in [arch/x86/boot/a20.c](https://github.com/torvalds/linux/blob/master/arch/x86/boot/a20.c) and it tries to enable the A20 gate with different methods. The first is the `a20_test_short` function which checks if A20 is already enabled or not with the `a20_test` function: +下一个函数调用是 `enable_a20`,这个函数使能 [A20 line](http://en.wikipedia.org/wiki/A20_line),你可以在 [arch/x86/boot/a20.c](https://github.com/torvalds/linux/blob/master/arch/x86/boot/a20.c) 找到这个函数的定义,这个函数会尝试使用不同的方式来使能 A20 地址线。首先这个函数将调用 `a20_test_short`(该函数将调用 `a20_test` 函数) 来检测 A20 地址线是否已经被激活了: ```C static int a20_test(int loops) @@ -363,11 +363,11 @@ static int a20_test(int loops) } ``` -First of all we put `0x0000` in the `FS` register and `0xffff` in the `GS` register. Next we read the value in address `A20_TEST_ADDR` (it is `0x200`) and put this value into the `saved` variable and `ctr`. +这个函数首先将 `0x0000` 放入 `FS` 寄存器,将 `0xffff` 放入 `GS` 寄存器。然后通过 `rdfs32` 函数调用,将 `A20_TEST_ADDR` 内存地址的内容放入 `saved` 和 `ctr` 变量。 -Next we write an updated `ctr` value into `fs:gs` with the `wrfs32` function, then delay for 1ms, and then read the value from the `GS` register by address `A20_TEST_ADDR+0x10`, if it's not zero we already have enabled the A20 line. If A20 is disabled, we try to enable it with a different method which you can find in the `a20.c`. For example with call of `0x15` BIOS interrupt with `AH=0x2041` etc. +接下来我们使用 `wrfs32` 函数将更新过的 `ctr` 的值写入 `fs:gs` ,然后延时 1ms,接着从Next we write an updated `ctr` value into `fs:gs` with the `wrfs32` function, then delay for 1ms, 接着从 `GS:A20_TEST_ADDR+0x10` 读取内容,如果该地址内容不为0,那么 A20 已经被激活。如果 A20 没有被激活,代码将尝试使用多种方法进行 A20 地址激活。其中的一种方法就是调用 BIOS `0X15` 中断激活 A20 地址线。 -If the `enabled_a20` function finished with fail, print an error message and call function `die`. You can remember it from the first source code file where we started - [arch/x86/boot/header.S](https://github.com/torvalds/linux/blob/master/arch/x86/boot/header.S): +如果 `enabled_a20` 函数调用失败,显示一个错误消息并且调用 `die` 函数结束操作系统运行。`die` 函数定义在 [arch/x86/boot/header.S](https://github.com/torvalds/linux/blob/master/arch/x86/boot/header.S): ```assembly die: @@ -376,21 +376,25 @@ die: .size die, .-die ``` -After the A20 gate is successfully enabled, the `reset_coprocessor` function is called: +A20 地址线被激活之后,`reset_coprocessor` 函数被调用: + ```C outb(0, 0xf0); outb(0, 0xf1); ``` -This function clears the Math Coprocessor by writing `0` to `0xf0` and then resets it by writing `0` to `0xf1`. -After this, the `mask_all_interrupts` function is called: +这个函数非常简单,通过将 `0` 写入 I/O 端口 `0xf0` 和 `0xf1` 以清除数字协处理器。 + +接下来 `mask_all_interrupts` 函数将被调用: + ```C outb(0xff, 0xa1); /* Mask all interrupts on the secondary PIC */ outb(0xfb, 0x21); /* Mask all but cascade on the primary PIC */ ``` -This masks all interrupts on the secondary PIC (Programmable Interrupt Controller) and primary PIC except for IRQ2 on the primary PIC. -And after all of these preparations, we can see the actual transition into protected mode. +这个函数调用激活主和从中断控制器 (Programmable Interrupt Controller)上的中断,唯一的例外是主中断控制器上的级联中断(所有从中断控制器的中断将通过这个级联中断报告给 CPU )。 + +到这里位置,我们就完成了所有的准备工作,下面我们就将正式开始从实模式转换到保护模式。 Set up Interrupt Descriptor Table --------------------------------------------------------------------------------