|
@@ -1,10 +1,10 @@
|
|
Kernel booting process. Part 1.
|
|
Kernel booting process. Part 1.
|
|
================================================================================
|
|
================================================================================
|
|
|
|
|
|
-From the bootloader to kernel
|
|
|
|
|
|
+From the bootloader to the kernel
|
|
--------------------------------------------------------------------------------
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
-If you have read my previous [blog posts](http://0xax.blogspot.com/search/label/asm), you can see that sometime ago I started to get involved with low-level programming. I wrote some posts about x86_64 assembly programming for Linux. At the same time, I started to dive into the Linux source code. I have a great interest in understanding how low-level things work, how programs run on my computer, how they are located in memory, how the kernel manages processes and memory, how the network stack works on low-level and many many other things. So, I decided to write yet another series of posts about the Linux kernel for **x86_64**.
|
|
|
|
|
|
+If you have read my previous [blog posts](http://0xax.blogspot.com/search/label/asm), you can see that sometime ago I started to get involved with low-level programming. I wrote some posts about x86_64 assembly programming for Linux. At the same time, I started to dive into the Linux source code. I have a great interest in understanding how low-level things work, how programs run on my computer, how they are located in memory, how the kernel manages processes and memory, how the network stack works at a low level and many many other things. So, I decided to write yet another series of posts about the Linux kernel for **x86_64**.
|
|
|
|
|
|
Note that I'm not a professional kernel hacker and I don't write code for the kernel at work. It's just a hobby. I just like low-level stuff, and it is interesting for me to see how these things work. So if you notice anything confusing, or if you have any questions/remarks, ping me on twitter [0xAX](https://twitter.com/0xAX), drop me an [email](anotherworldofworld@gmail.com) or just create an [issue](https://github.com/0xAX/linux-insides/issues/new). I appreciate it. All posts will also be accessible at [linux-insides](https://github.com/0xAX/linux-insides) and if you find something wrong with my English or the post content, feel free to send a pull request.
|
|
Note that I'm not a professional kernel hacker and I don't write code for the kernel at work. It's just a hobby. I just like low-level stuff, and it is interesting for me to see how these things work. So if you notice anything confusing, or if you have any questions/remarks, ping me on twitter [0xAX](https://twitter.com/0xAX), drop me an [email](anotherworldofworld@gmail.com) or just create an [issue](https://github.com/0xAX/linux-insides/issues/new). I appreciate it. All posts will also be accessible at [linux-insides](https://github.com/0xAX/linux-insides) and if you find something wrong with my English or the post content, feel free to send a pull request.
|
|
|
|
|
|
@@ -58,7 +58,7 @@ which is 65519 bytes over first megabyte. Since only one megabyte is accessible
|
|
|
|
|
|
Ok, now we know about real mode and memory addressing. Let's get back to discuss about register values after reset:
|
|
Ok, now we know about real mode and memory addressing. Let's get back to discuss about register values after reset:
|
|
|
|
|
|
-`CS` register consists of two parts: the visible segment selector and hidden base address. We know predefined `CS` base and `IP` value, so the logical address will be:
|
|
|
|
|
|
+The `CS` register consists of two parts: the visible segment selector and hidden base address. We know the predefined `CS` base and `IP` value, so the logical address will be:
|
|
|
|
|
|
```
|
|
```
|
|
0xffff0000:0xfff0
|
|
0xffff0000:0xfff0
|
|
@@ -97,7 +97,7 @@ SECTIONS {
|
|
}
|
|
}
|
|
```
|
|
```
|
|
|
|
|
|
-Now the BIOS starts: after initializing and checking the hardware, it needs to find a bootable device. A boot order is stored in the BIOS configuration, controlling which devices the kernel attempts to boot from. When attempting to boot from a hard drive, the BIOS tries to find a boot sector. On hard drives partitioned with an MBR partition layout, the boot sector is stored in the first 446 bytes of the first sector (which is 512 bytes). The final two bytes of the first sector are `0x55` and `0xaa`, which signals the BIOS that this device is bootable. For example:
|
|
|
|
|
|
+Now the BIOS starts: after initializing and checking the hardware, it needs to find a bootable device. A boot order is stored in the BIOS configuration, controlling which devices the BIOS attempts to boot from. When attempting to boot from a hard drive, the BIOS tries to find a boot sector. On hard drives partitioned with an MBR partition layout, the boot sector is stored in the first 446 bytes of the first sector (which is 512 bytes). The final two bytes of the first sector are `0x55` and `0xaa`, which signals the BIOS that this device is bootable. For example:
|
|
|
|
|
|
```assembly
|
|
```assembly
|
|
;
|
|
;
|
|
@@ -127,7 +127,7 @@ Build and run it with:
|
|
nasm -f bin boot.nasm && qemu-system-x86_64 boot
|
|
nasm -f bin boot.nasm && qemu-system-x86_64 boot
|
|
```
|
|
```
|
|
|
|
|
|
-This will instruct [QEMU](http://qemu.org) to use the `boot` binary we just built as a disk image. Since the binary generated by the assembly code above fulfills the requirements of the boot sector (the origin is set to `0x7c00`, and we end with the magic sequence), QEMU will treat the binary as the master boot record(MBR) of a disk image.
|
|
|
|
|
|
+This will instruct [QEMU](http://qemu.org) to use the `boot` binary we just built as a disk image. Since the binary generated by the assembly code above fulfills the requirements of the boot sector (the origin is set to `0x7c00`, and we end with the magic sequence), QEMU will treat the binary as the master boot record (MBR) of a disk image.
|
|
|
|
|
|
You will see:
|
|
You will see:
|
|
|
|
|
|
@@ -144,7 +144,7 @@ objdump -D -b binary -mi386 -Maddr16,data16,intel boot
|
|
|
|
|
|
A real-world boot sector has code to continue the boot process and the partition table instead of a bunch of 0's and an exclamation mark :) From this point onwards, BIOS hands over control to the bootloader.
|
|
A real-world boot sector has code to continue the boot process and the partition table instead of a bunch of 0's and an exclamation mark :) From this point onwards, BIOS hands over control to the bootloader.
|
|
|
|
|
|
-**NOTE**: As you can read above the CPU is in real mode. In real mode, calculating the physical address in memory is done as following:
|
|
|
|
|
|
+**NOTE**: As you can read above the CPU is in real mode. In real mode, calculating the physical address in memory is done as follows:
|
|
|
|
|
|
```
|
|
```
|
|
PhysicalAddress = Segment * 16 + Offset
|
|
PhysicalAddress = Segment * 16 + Offset
|
|
@@ -241,7 +241,7 @@ So when the bootloader transfers control to the kernel, it starts at:
|
|
0x1000 + X + sizeof(KernelBootSector) + 1
|
|
0x1000 + X + sizeof(KernelBootSector) + 1
|
|
```
|
|
```
|
|
|
|
|
|
-where `X` is the address of the kernel bootsector loaded. In my case `X` is `0x10000`, as we can see in a memory dump:
|
|
|
|
|
|
+where `X` is the address of the kernel boot sector loaded. In my case `X` is `0x10000`, as we can see in a memory dump:
|
|
|
|
|
|

|
|

|
|
|
|
|
|
@@ -458,27 +458,27 @@ The BSS section is used to store statically allocated, uninitialized data. Linux
|
|
rep; stosl
|
|
rep; stosl
|
|
```
|
|
```
|
|
|
|
|
|
-First of all the [__bss_start](https://github.com/torvalds/linux/blob/master/arch/x86/boot/setup.ld#L47) address is moved into `di` and the `_end + 3` address (+3 - aligns to 4 bytes) is moved into `cx`. The `eax` register is cleared (using an `xor` instruction), and the bss section size (`cx`-`di`) is calculated and put into `cx`. Then, `cx` is divided by four (the size of a 'word'), and the `stosl` instruction is repeatedly used, storing the value of `eax` (zero) into the address pointed to by `di`, automatically increasing `di` by four (this occurs until `cx` reaches zero). The net effect of this code is that zeros are written through all words in memory from `__bss_start` to `_end`:
|
|
|
|
|
|
+First of all the [__bss_start](https://github.com/torvalds/linux/blob/master/arch/x86/boot/setup.ld#L47) address is moved into `di` and the `_end + 3` address (+3 - aligns to 4 bytes) is moved into `cx`. The `eax` register is cleared (using a `xor` instruction), and the bss section size (`cx`-`di`) is calculated and put into `cx`. Then, `cx` is divided by four (the size of a 'word'), and the `stosl` instruction is repeatedly used, storing the value of `eax` (zero) into the address pointed to by `di`, automatically increasing `di` by four (this occurs until `cx` reaches zero). The net effect of this code is that zeros are written through all words in memory from `__bss_start` to `_end`:
|
|
|
|
|
|

|
|

|
|
|
|
|
|
Jump to main
|
|
Jump to main
|
|
--------------------------------------------------------------------------------
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
-That's all, we have the stack, BSS so we can jump to the `main()` C function:
|
|
|
|
|
|
+That's all, we have the stack and BSS so we can jump to the `main()` C function:
|
|
|
|
|
|
```assembly
|
|
```assembly
|
|
calll main
|
|
calll main
|
|
```
|
|
```
|
|
|
|
|
|
-The `main()` function is located in [arch/x86/boot/main.c](https://github.com/torvalds/linux/blob/master/arch/x86/boot/main.c). What this does, you can read in the next part.
|
|
|
|
|
|
+The `main()` function is located in [arch/x86/boot/main.c](https://github.com/torvalds/linux/blob/master/arch/x86/boot/main.c). You can read about what this does in the next part.
|
|
|
|
|
|
Conclusion
|
|
Conclusion
|
|
--------------------------------------------------------------------------------
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
-This is the end of the first part about Linux kernel internals. If you have questions or suggestions, ping me in twitter [0xAX](https://twitter.com/0xAX), drop me [email](anotherworldofworld@gmail.com) or just create [issue](https://github.com/0xAX/linux-internals/issues/new). In the next part we will see first C code which executes in Linux kernel setup, implementation of memory routines as `memset`, `memcpy`, `earlyprintk` implementation and early console initialization and many more.
|
|
|
|
|
|
+This is the end of the first part about Linux kernel insides. If you have questions or suggestions, ping me in twitter [0xAX](https://twitter.com/0xAX), drop me [email](anotherworldofworld@gmail.com) or just create [issue](https://github.com/0xAX/linux-internals/issues/new). In the next part we will see first C code which executes in Linux kernel setup, implementation of memory routines as `memset`, `memcpy`, `earlyprintk` implementation and early console initialization and many more.
|
|
|
|
|
|
-**Please note that English is not my first language and I am really sorry for any inconvenience. If you found any mistakes please send me PR to [linux-internals](https://github.com/0xAX/linux-internals).**
|
|
|
|
|
|
+**Please note that English is not my first language and I am really sorry for any inconvenience. If you found any mistakes please send me PR to [linux-insides](https://github.com/0xAX/linux-internals).**
|
|
|
|
|
|
Links
|
|
Links
|
|
--------------------------------------------------------------------------------
|
|
--------------------------------------------------------------------------------
|