boot-4: Improve first two sections of the 4th boot part#902
Conversation
|
E-books generated for this pull request available at: https://github.com/0xAX/linux-insides/actions/runs/21835197541 |
8b3b3be to
65db41e
Compare
|
E-books generated for this pull request available at: https://github.com/0xAX/linux-insides/actions/runs/21913484730 |
65db41e to
c673536
Compare
c673536 to
6a37263
Compare
|
E-books generated for this pull request available at: https://github.com/0xAX/linux-insides/actions/runs/22016058397 |
|
CI is read because of #903 |
6a37263 to
a07792d
Compare
|
E-books generated for this pull request available at: https://github.com/0xAX/linux-insides/actions/runs/22016174757 |
Booting/linux-bootstrap-4.md
Outdated
| - The processor now can address up to four gigabytes of memory | ||
| - The privilege levels were set for the memory access | ||
|
|
||
| Despite this, the kernel is still in its early setup mode. There are many different things which the early setup code should prepare before we will reach the main kernel's entry point. Right now the processor operates in protected mode. However, protected mode is not the main mode in which x86_64 processors should operate but exists only for backward compatibility. The next crucial step is to switch to the native mode for `x86_64` - [long mode](https://en.wikipedia.org/wiki/Long_mode). |
There was a problem hiding this comment.
| Despite this, the kernel is still in its early setup mode. There are many different things which the early setup code should prepare before we will reach the main kernel's entry point. Right now the processor operates in protected mode. However, protected mode is not the main mode in which x86_64 processors should operate but exists only for backward compatibility. The next crucial step is to switch to the native mode for `x86_64` - [long mode](https://en.wikipedia.org/wiki/Long_mode). | |
| Despite this, the kernel is still in its early setup mode. There are many different things that the early setup code should prepare before we reach the main kernel's entry point. Right now, the processor operates in protected mode. However, protected mode is not the main mode in which `x86_64` processors should operate – it exists only for backward compatibility. The next crucial step is to switch to the native mode for `x86_64` - [long mode](https://en.wikipedia.org/wiki/Long_mode). |
Booting/linux-bootstrap-4.md
Outdated
| ``` | ||
|
|
||
| When the direction flag is clear, all string operations which usually used for copying data, like for example [stos](http://x86.renejeschke.de/html/file_module_x86_id_306.html), [scas](http://x86.renejeschke.de/html/file_module_x86_id_287.html) and others, will increment the index registers `esi` or `edi`. We need to clear the direction flag because later we will use strings operations to perform various operations such as clearing space for page tables or copying data. | ||
| When the direction flag is clear, all string or copy-like operations which usually used for copying data, like for example [stos](http://x86.renejeschke.de/html/file_module_x86_id_306.html), [scas](http://x86.renejeschke.de/html/file_module_x86_id_287.html) and others, will increment the index registers `esi` or `edi`. We need to clear the direction flag because later we will use strings operations to perform various operations such as clearing space for page tables or copying data. |
There was a problem hiding this comment.
| When the direction flag is clear, all string or copy-like operations which usually used for copying data, like for example [stos](http://x86.renejeschke.de/html/file_module_x86_id_306.html), [scas](http://x86.renejeschke.de/html/file_module_x86_id_287.html) and others, will increment the index registers `esi` or `edi`. We need to clear the direction flag because later we will use strings operations to perform various operations such as clearing space for page tables or copying data. | |
| When the direction flag is clear, all string or copy-like operations used for copying data, like for example [stos](http://x86.renejeschke.de/html/file_module_x86_id_306.html) or [scas](http://x86.renejeschke.de/html/file_module_x86_id_287.html), will increment the index registers `esi` or `edi`. We need to clear the direction flag because later we will use string operations for tasks such as clearing space for page tables or copying data. |
Booting/linux-bootstrap-4.md
Outdated
| When the direction flag is clear, all string operations which usually used for copying data, like for example [stos](http://x86.renejeschke.de/html/file_module_x86_id_306.html), [scas](http://x86.renejeschke.de/html/file_module_x86_id_287.html) and others, will increment the index registers `esi` or `edi`. We need to clear the direction flag because later we will use strings operations to perform various operations such as clearing space for page tables or copying data. | ||
| When the direction flag is clear, all string or copy-like operations which usually used for copying data, like for example [stos](http://x86.renejeschke.de/html/file_module_x86_id_306.html), [scas](http://x86.renejeschke.de/html/file_module_x86_id_287.html) and others, will increment the index registers `esi` or `edi`. We need to clear the direction flag because later we will use strings operations to perform various operations such as clearing space for page tables or copying data. | ||
|
|
||
| The next instruction is to disable interrupts - `cli`. We already have seen it in previous chapter. The interrupts are disabled "twice" because modern bootloaders can load the kernel starting from this point but not only one that we have seen in the [first chapter](./linux-bootstrap-1.md). |
There was a problem hiding this comment.
| The next instruction is to disable interrupts - `cli`. We already have seen it in previous chapter. The interrupts are disabled "twice" because modern bootloaders can load the kernel starting from this point but not only one that we have seen in the [first chapter](./linux-bootstrap-1.md). | |
| The next instruction is to disable interrupts - `cli`. We have already seen it in the previous chapter. The interrupts are disabled "twice" because modern bootloaders can load the kernel starting from this point, but not only one that we have seen in the [first chapter](./linux-bootstrap-1.md). |
There was a problem hiding this comment.
The interrupts are disabled "twice" because modern bootloaders can load the kernel starting from this point, but not only one that we have seen in the first chapter.
This sentence is a bit unclear
Booting/linux-bootstrap-4.md
Outdated
| The `call` instruction is used to get the real address of the kernel. This trick works because after the `call` instruction is executed, the stack should have return address on its top. In the code above we setup a temporary mini stack to get the address of the kernel and execute the call to the nearest label `1`. Since the top of the stack contains the return address, we put it into the `ebp` register. Using the last instruction we subtract the difference between the address of the label `1` and `strtup_32` address from the return address that we got at the previous step: | ||
| The `call` instruction is used to get the physical address where the kernel is actually loaded. This trick works because after the `call` instruction is executed, the stack should have the return address on top. This return address will be exactly the address of the label `1`. | ||
|
|
||
| In the code above, kernel setups a temporary mini stack where the return address will be stored after the `call` instruction. Right after the call, we pop this address from the stack and save it in the `ebp` register. Using the last instruction, we subtract the difference between the address of the label `1` and the `startup_32` physical address using the `rva` macro and `subl` instruction and store the result in the `ebp` register. |
There was a problem hiding this comment.
| In the code above, kernel setups a temporary mini stack where the return address will be stored after the `call` instruction. Right after the call, we pop this address from the stack and save it in the `ebp` register. Using the last instruction, we subtract the difference between the address of the label `1` and the `startup_32` physical address using the `rva` macro and `subl` instruction and store the result in the `ebp` register. | |
| In the code above, the kernel sets up a temporary mini stack where the return address will be stored after the `call` instruction. Right after the call, we pop this address from the stack and save it in the `ebp` register. Using the last instruction, we subtract the difference between the address of the label `1` and the `startup_32` physical address using the `rva` macro and `subl` instruction, and store the result in the `ebp` register. |
Booting/linux-bootstrap-4.md
Outdated
|
|
||
| In the code above, kernel setups a temporary mini stack where the return address will be stored after the `call` instruction. Right after the call, we pop this address from the stack and save it in the `ebp` register. Using the last instruction, we subtract the difference between the address of the label `1` and the `startup_32` physical address using the `rva` macro and `subl` instruction and store the result in the `ebp` register. | ||
|
|
||
| The `rva` macro defined in the same source code file and looks like this: |
There was a problem hiding this comment.
| The `rva` macro defined in the same source code file and looks like this: | |
| The `rva` macro is defined in the same source code file and looks like this: |
Booting/linux-bootstrap-4.md
Outdated
| - Second task state descriptor | ||
|
|
||
| We already saw the loading the Global Descriptor Table in the previous [part](./linux-bootstrap-3.md#set-up-global-descriptor-table), and now we're doing almost the same here, but we set descriptors to use `CS.L = 1` and `CS.D = 0` for execution in 64 bit mode. | ||
| We already saw the loading the Global Descriptor Table in the previous [part](./linux-bootstrap-3.md#set-up-global-descriptor-table), and now we're doing almost the same here, but we set descriptors to use `CS.L = 1` and `CS.D = 0` for execution in `64` bit mode. |
There was a problem hiding this comment.
| We already saw the loading the Global Descriptor Table in the previous [part](./linux-bootstrap-3.md#set-up-global-descriptor-table), and now we're doing almost the same here, but we set descriptors to use `CS.L = 1` and `CS.D = 0` for execution in `64` bit mode. | |
| We already saw loading the Global Descriptor Table in the previous [part](./linux-bootstrap-3.md#set-up-global-descriptor-table), and now we're doing almost the same, but we set descriptors to use `CS.L = 1` and `CS.D = 0` for execution in `64` bit mode. |
Booting/linux-bootstrap-4.md
Outdated
| We already saw the loading the Global Descriptor Table in the previous [part](./linux-bootstrap-3.md#set-up-global-descriptor-table), and now we're doing almost the same here, but we set descriptors to use `CS.L = 1` and `CS.D = 0` for execution in `64` bit mode. | ||
|
|
||
| After the new Global Descriptor Table is loaded, the kernel can setup the new stack: | ||
| After the new Global Descriptor Table is loaded, the next step is is the setup of the stack: |
There was a problem hiding this comment.
| After the new Global Descriptor Table is loaded, the next step is is the setup of the stack: | |
| After the new Global Descriptor Table is loaded, the next step is to set up the stack: |
Booting/linux-bootstrap-4.md
Outdated
| ``` | ||
|
|
||
| At the previous step we loaded new Global Descriptor Table, but all the segment registers may have selectors from old table. If those selectors point to invalid entries in the new Global Descriptor Table, next memory access can cause [General Protection Fault](https://en.wikipedia.org/wiki/General_protection_fault). Setting them to the `__BOOT_DS` which is a known-good descriptor should fix this potential fault and allow us to set proper stack pointed by the `boot_stack_end`. | ||
| At the previous step we loaded new Global Descriptor Table, but all the segment registers may have selectors from the old table. If those selectors point to invalid entries in the new Global Descriptor Table, next memory access can cause [General Protection Fault](https://en.wikipedia.org/wiki/General_protection_fault). Setting them to the `__BOOT_DS` which is a known-good descriptor should fix this potential fault and allow us to set proper stack pointed by the `boot_stack_end`. |
There was a problem hiding this comment.
| At the previous step we loaded new Global Descriptor Table, but all the segment registers may have selectors from the old table. If those selectors point to invalid entries in the new Global Descriptor Table, next memory access can cause [General Protection Fault](https://en.wikipedia.org/wiki/General_protection_fault). Setting them to the `__BOOT_DS` which is a known-good descriptor should fix this potential fault and allow us to set proper stack pointed by the `boot_stack_end`. | |
| In the previous step, we loaded a new Global Descriptor Table; however, all the segment registers may still have selectors from the old table. If those selectors point to invalid entries in the new Global Descriptor Table, the next memory access can cause [General Protection Fault](https://en.wikipedia.org/wiki/General_protection_fault). Setting them to `__BOOT_DS`, which is a well-known descriptor, should fix this potential fault and allow us to set the proper stack pointed by `boot_stack_end`. |
Booting/linux-bootstrap-4.md
Outdated
| At the previous step we loaded new Global Descriptor Table, but all the segment registers may have selectors from old table. If those selectors point to invalid entries in the new Global Descriptor Table, next memory access can cause [General Protection Fault](https://en.wikipedia.org/wiki/General_protection_fault). Setting them to the `__BOOT_DS` which is a known-good descriptor should fix this potential fault and allow us to set proper stack pointed by the `boot_stack_end`. | ||
| At the previous step we loaded new Global Descriptor Table, but all the segment registers may have selectors from the old table. If those selectors point to invalid entries in the new Global Descriptor Table, next memory access can cause [General Protection Fault](https://en.wikipedia.org/wiki/General_protection_fault). Setting them to the `__BOOT_DS` which is a known-good descriptor should fix this potential fault and allow us to set proper stack pointed by the `boot_stack_end`. | ||
|
|
||
| The last action after we loaded the new Global Descriptor Table is to reload `cs` descriptor: |
There was a problem hiding this comment.
| The last action after we loaded the new Global Descriptor Table is to reload `cs` descriptor: | |
| The last action after we loaded the new Global Descriptor Table is to reload the `cs` descriptor: |
Booting/linux-bootstrap-4.md
Outdated
| ``` | ||
|
|
||
| Since we can not change segment registers using simple `mov` instruction, we need to apply a trick with the `lretl` instruction. This instruction fetches the two values from the top of the stack and put the first value into the `eip` register and the second value to the `cs` register. Since this moment we have proper kernel code selector and instruction pointer values. | ||
| Since we can not change segment registers using a `mov` instruction, we need to apply a trick with the `lretl` instruction. This instruction fetches two values from the top of the stack, then put the first value into the `eip` register and the second value to the `cs` register. Since this moment, we have a proper kernel code selector and instruction pointer values. |
There was a problem hiding this comment.
| Since we can not change segment registers using a `mov` instruction, we need to apply a trick with the `lretl` instruction. This instruction fetches two values from the top of the stack, then put the first value into the `eip` register and the second value to the `cs` register. Since this moment, we have a proper kernel code selector and instruction pointer values. | |
| Since we can not change segment registers using the `mov` instruction, we need to apply a trick with the `lretl` instruction. This instruction fetches two values from the top of the stack, then puts the first value into the `eip` register and the second value into the `cs` register. Since this moment, we have a proper kernel code selector and instruction pointer values. |
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
a07792d to
2e9ac6a
Compare
|
E-books generated for this pull request available at: https://github.com/0xAX/linux-insides/actions/runs/22034387558 |
Description
This PR improves the wording in the first sections of the 4th part of the Linux kernel booting process.