or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Do you want to remove this version name and description?
Syncing
xxxxxxxxxx
Booting 1 ~ 3
note:
Hello, everyone. Today, we'll discuss the first three chapters of the book.
From Bootloader to Kernel
note:
Lets start the first chapter.
Power button -> BIOS -> MBR (bootloader)
-> kernel real-mode code
note:
This chapter details the process starting from powering on the device, accessing the BIOS, loading the bootloader from the disk, and finally executing the kernel code.
Power Button
note:
When the power button is pressed, the motherboard sends a signal to the power supply, which then delivers the appropriate amount of electricity to the computer. Upon receiving the "power good" signal, the motherboard initiates the startup of the CPU. The CPU then clears any leftover data in its registers and assigns predefined values to each.
The Program Counter of x86 in real mode
CS
(Code Segment) (CS_selector
)CS_base
is hidden from programmer.IP
(Instruction Pointer)note:
Now, we'll introduce the program counter in the x86 CPU architecture when operating in real mode, which we'll cover in detail later. In real mode, two visible 16-bit registers combine to form a 20-bit memory address space. CS, standing for Code Segment (or CS_selector), is used to select a memory segment. Additionally, for the Intel 80386 and later models, there's a hidden register called CS_base, designed to accommodate larger memory spaces. Next, the IP, or Instruction Pointer, specifies the offset within the memory segment.
note:
These are the predefined values for CS and IP, as illustrated in the slide.
BIOS
\[ \begin{aligned} \text{CS Base} &= \text{CS Selector} \times 16\\ \text{Memory Address} &= \text{CS Base} + \text{IP} \end{aligned} \]
note:
After the processor starts, it operates in "real mode," which is a mode present in all x86 processors. In real mode, addresses directly correspond to physical memory locations, meaning there is no memory protection feature. Regardless of being 16-bit or 32-bit, programs are limited to a 20-bit memory address space.
The relationship between the registers is defined by a formula: CS_base equals CS_selector multiplied by 16, or equivalently, shifted left by 4 bits. The memory address is then calculated by adding the CS_base to the instruction pointer.
0xFFFF_FFF0
.near jump
instruction, guiding the system to the rest of BIOS boot code.note:
After the processor starts, it begins executing the first instruction located at a specific address, known as the reset vector. Since RAM is empty at boot, the motherboard's memory controller redirects memory read requests to the BIOS ROM. Notably, the first instruction at the reset vector is typically a near jump command, which directs the system to the remainder of the BIOS boot code.
Recall the initial register data and formula:
\[ \begin{aligned} \text{CS Base} &= \text{CS Selector} \times 16\\ \text{Memory Address} &= \text{CS Base} + \text{IP} \end{aligned} \]
According to the formula above,
CS_base
should be0xF_0000
instead of0xFFFF_0000
.Why
CS_base
is notCS selector
times 16?note:
Recall the initial register data and formula, can you spot something is wrong? According to the formula above,
CS_base
should be0xF_0000
instead of0xFFFF_0000
.Why
CS_base
is notCS selector
times 16?0xF_FFF0
0xFFFF_FFF0
note:
For the Intel 8086, the reset vector corresponds directly to its CS and IP values. However, for the Intel 80386 and later models, the reset vector is a 32-bit address. Considering that real mode only supports a 20-bit memory address space, how can a processor access this larger address?
To address this difference and maintain compatibility with the 20-bit memory address system of the real mode, modern x86 CPUs are designed to initialize the
CS selector
andCS base
register in a way that aligns with this legacy requirement.Furthermore, the distinction between jump instructions is also important.
A
near jump
affects onlyIP
, leaving theCS
as is. However, when the system employs afar jump
, both theCS selector
and theCS base
are synchronized.Bootloader
note:
Next, we'll talk about bootloader. This essential component serves as the bridge between the firmware's initial power-on state and the loading of the operating system.
How does the bootloader starts?
0x7c00
and jumps to therenote:
The BIOS, a basic check-up system for your computer, turns on first. It looks for a place to start the operating system from a list of sources like hard drives or USBs. It searches for a unique code, known as the 'magic number,' that marks the beginning of this process. Once found, it moves this code to a specific memory location and starts running it
Bootloader - GRUB 2
boot.img
note:
boot.img is the first step in using GRUB 2, our main bootloader.
Because of space limits, it's very compact. Its job is to locate and jump to GRUB 2's core program.
Bootloader - GRUB 2
diskboot.img
diskboot.img
grub_main
function.note:
diskboot.img comes next, stored in a space before the first partition. It loads the complete GRUB 2, which includes the drivers necessary for reading the filesystem into memory, and then starts grub_main.
Bootloader - GRUB 2
grub_main
note:
grub_main is where the action happens in GRUB 2. It sets up the console for display, figures out where modules are stored, and chooses the 'root' device. Then, it reads the GRUB configuration file to know what else needs to be loaded.
// This step is crucial for loading other modules and preparing the system for use.
Bootloader - GRUB 2
grub_main
grub_normal_execute
note:
At the end of execution, the grub_main function moves grub to normal mode. The grub_normal_execute function completes the final preparations and shows a menu to select an operating system.
Bootloader - GRUB 2
grub_menu_execute_entry
X + sizeof(KernalBootSector) + 1
note:
In the grub_menu_execute_entry phase, GRUB 2 carefully prepares to hand over control to the operating system's kernel. This process is guided by specific rules known as the boot protocol, ensuring that the kernel is loaded correctly into memory.
The transition point, or where GRUB hands off to the kernel, is calculated by the formula shows bellow. Here, 'X' is the address of the kernel boot sector being loaded, and sizeof(KernelBootSector) calculates the size of the kernel's boot sector, ensuring the kernel starts executing at exactly the right location. This precision ensures the system boots smoothly.
The Beginning of the Kernel Setup Stage
note:
Its first task is to get ready for the main event. Since the kernel is stored in a compressed format to save space, it must first be decompressed. But before that, the kernel sets up the necessary environment. This setup involves configuring the decompressor and arranging memory management components.
After these preparations, the kernel proceeds to decompress itself. Once decompression is complete, the kernel jumps into action, beginning its core functions and taking over the system's operation. This moment is critical, marking the transition from booting to an operational state where the operating system takes the lead.
The boot sector
MZ
and follows by aPE
header.start_up_setup
note:
The boot sector is essentially the starting line for the operating system's kernel. It has a unique signature that begins with 'MZ', followed by a 'PE' header.
However, the actual starting point for setting up the kernel isn't right at the beginning of this sector. It's a bit further along, at a specific distance known as an offset.
Once we reach this starting point, the kernel begins its setup routine, known as start_up_setup. This phase involves configuring a variety of settings, known as headers, which tell the kernel how to behave and what resources it has at its disposal
That's a closer look at how a computer transitions from off to fully operational through the bootloader and kernel setup. This process, while complex, ensures that your computer starts correctly and is ready for use
Bootloader -> kernel (real-mode code)
Kernel real-mode code
In this case X = 0x10000;
Kernel setup is at 0x10200
header.S
lagacy boot sector (512 bytes)
first part of kernel setup
(boot header information)
Kernel legacy code
header.S
Kernel legacy code
According to the Linux boot protocol
Kernel legacy code
contains some code to show the error message
if we don't use 3rd party bootloader and let BIOS load the first sector of kernel image into memory at 0x7c00 and run

Kernel setup code in Header.S
Kernel setup code in header.S
Aligning the segment registers
we want es=cs=ss=ds=0x1000
Aligning the segment registers
Make sure that all segment register values are equal
Aligning the segment registers
grub2 loads kernel setup code at address 0x10000, but starts from 0x10200
we want to let cs = 0x1000
Stack setup
Stack setup
or
if heap_end_ptr + STACK_SIZE is overflow
BSS setup
Now we have the stack and BSS, so we can jump to the main() C function
Takeaway Questions (1)
(A).
0xF_FFF0
(B).
0xFFFF_FFF0
(C).
0xFFFF_FFFF_FFFF_FFF0
Takeaway Questions (2)
0x55
,0xaa
) ?(A). Bootloader
(B). BIOS
(C). Kernel setup
Takeaway Questions (3)
(A).
0x7C00
(B).
0x10000
(C).
0x10200
First steps in the kernel setup code
Protected mode
Protected mode
was the main mode of Intel processors from the 80286 processor until Intel 64 andlong mode
came.real mode
, which is only1 MB
.real mode
andprotected mode
is memory management.Memory management in protected mode
Segment Descriptor
.Global Descriptor Table (GDT)
.GDTR
register. There will be an operation for loading it from memory, something like:Segment descriptor in GDT
Segment selector in protected mode
real mode
.Index
stores the index number of the descriptor in the GDT.RPL
contains the Requester's Privilege Level.Get physical address in protected mode
GDT address + Index
from the selector.Copy boot parameters
copy_boot_params(void)
.boot_params
structure includes a membersetup_header hdr
which contains some useful parameters in later initialization.memcpy
defined incopy.S
to copyhdr
toboot_params
.Console initialization
console_init
would be called.puts
function can print character by character by interrypt0x10
.Heap initialization
init_heap
function.CAN_USE_HEAP
flag fromloadflags
.loadflags
is a bitmask and it also contains other mask.stack_end
.stack_end = esp - STACK_SIZE;
Heap initialization
And
heap_end
is defined in other header file.The last check is whether
heap_end
is greater thanstack_end
. If it is thenstack_end
is assigned toheap_end
to make them equal.Takeaway Questions (4)
protected mode
?(A). Faster execution speed.
(B). More available memory space.
(C). Lower hardware requirements.
CPU Validation
validate_cpu
check_cpu
CPU Validation
check_cpu
e.g. long mode in x86_64
e.g. SSE+SSE2 for AMD if missing
CPU Validation
set_bios_mode
is called.0x15
BIOS interrupt to tell BIOS long mode will be used.Memory Detection
detect_memory
function provides a map of available RAM to the CPU.0xe820
,0xe801
and0x88
.0xe820
for example.Memory Detection:
detect_memory_e820
biosregs
structure with0xe820
call.Memory Detection:
detect_memory_e820
ax
: the number of the function (0xe820)cx
: size of the buffer which will contain data about the memory (sizeof buf
)edx
:SMAP
(ASCII) magic numberes:di
: contain the address of the buffer (&buf
)ebx
: Initialized to zero in the first time.Memory Detection:
detect_memory_e820
intcall(0x15, &ireg, &oreg)
ebx
= 0e820_entry
Memory Detection:
detect_memory_e820
e820_entry
containdmesg
likeKeyboard Initialization
keyboard_init
function0x16
to query the status of the keyboard0x16
again to set repeat rate and delay.Querying
Function:
query_ist
query_ist
function.0x15
to get the info and saves the result toboot_params
.Function:
query_apm_bios
query_apm_bios
calls the interrupt0x15
withah=0x53
to checkAPM
installation.Function:
query_apm_bios
0x15
again, but withah=0x5304
to disconnectAPM
interface and connect the 32-bit protected mode interface.boot_params.apm_bios_info
with values obtained from the BIOS.Function:
query_apm_bios
query_apm_bios
will be executed only whenCONFIG_APM
orCONFIG_APM_MODULE
compile flag was set.Function:
query_edd
query_edd
function, which queries EDD(Enhanced Disk Drive
) info from BIOS.Function:
query_edd
query_edd
Takeaway Questions (5)
validate_cpu
do?(A). Check if CPU is in right level.
(B). Check whether CPU is broken.
(C). Benchmark to check the speed of the CPU.
Takeaway Questions (6)
detect_memory_e820
do?(A). Detect the bandwith of memory.
(B). Detect the DRAM generation.
(C). Get information about available address
Video mode initialization and transition to protected mode
main()
inarch/x86/boot/main.c
Kernel data types
Heap API
Defined in
arch/x86/boot/boot.h
Video Mode
main()
inarch/x86/boot/main.c
set_video()
inarch/x86/boot/video.c
set_video()
inarch/x86/boot/video.c
vid_mode
0x01FA
/ size2
vga=<mode>
normal
/ext
/ask
set_video()
inarch/x86/boot/video.c
boot_params.screen_info
.In
arch/x86/boot/video.c
store_mode_params()
set_video()
inarch/x86/boot/video.c
save_screen()
set_video()
inarch/x86/boot/video.c
probe_cards()
inarch/x86/boot/video-mode.c
video_vga
in arch/x86/boot/video-vga.c__videocard
macro inarch/x86/boot/video.h
video_cards
inarch/x86/boot/setup.ld
set_video()
inarch/x86/boot/video.c
mode_menu()
inarch/x86/boot/video.c
set_video()
inarch/x86/boot/video.c
set_mode()
inarch/x86/boot/video-mode.c
raw_set_mode()
inarch/x86/boot/video-mode.c
arch/x86/boot/video-vga.c
vga_set_mode()
vga_set_8font()
in arch/x86/boot/video-vga.cset_video()
inarch/x86/boot/video.c
Last preparation before transition into protected mode
arch/x86/boot/main.c
arch/x86/boot/pm.c
realmode_switch_hook
arch/x86/boot/pm.c
realmode_switch_hook
io_delay
asm volatile("outb %%al,%0" : : "dN" (DELAY_PORT));
ADVANCED BOOT LOADER HOOKS
realmode_switch_hook (No hook)
Enable A20 line
arch/x86/boot/pm.c
Enable A20 line
Disable Coprocessor
arch/x86/boot/pm.c
Disable Coprocessor
Mask All Interrupt
arch/x86/boot/pm.c
Mask All Interrupt
PIC
(Programmable Interrupt Controller) and primaryPIC
IRQ2
on the primaryPIC
.IRQ2
line cascade PIC1 and PIC2Setting up the Interrupt Descriptor Table
arch/x86/boot/pm.c
IDT Struct
arch/x86/boot/pm.c
Set up Global Descriptor Table
arch/x86/boot/pm.c
boot_gdt
Load GDT
GDT_ENTRY
MacroGDT_ENTRY(base, limit, flag)
flag
of GDT_ENTRYActual transition into protected mode
arch/x86/boot/pm.c
protected_mode_jump(jump_location, boot_paramters)
arch/x86/boot/pmjump.S
cs
Register intobx
&boot_params
intoedx
arch/x86/boot/pmjump.S
in_pm32
in_pm32
# Transition to 32-bit modeWhat?
What? Explained
Store DS and TSS
Enable Protected-mode
PE
bit in Control Registercr0
Finally, A Long Jump
0x66
Prefix which allows us to mix 16-bit and 32-bit code0xea
Jump opcodein_pm32
(cs << 4) + in_pm32__BOOT_CS
Target code segmentFirst time running under Protected-mode
arch/x86/boot/pmjump.S
arch/x86/boot/pmjump.S
arch/x86/boot/pmjump.S
arch/x86/boot/pmjump.S
Takeaway Questions (7)
heap_free
function?(A). Free memory allocated on the heap.
(B). Check if the heap has enough space.
(C). Swap the heap to disk to free memory.
Takeaway Questions (8)
(A). Clear out prefetched instuction
(B). Recalculate PC by an offset
(C). Store general purpose registers
Thanks