summaryrefslogtreecommitdiff
path: root/doc/0xax.gitbooks.io_linux-insides_content_Booting_linux-bootstrap-2.txt
diff options
context:
space:
mode:
Diffstat (limited to 'doc/0xax.gitbooks.io_linux-insides_content_Booting_linux-bootstrap-2.txt')
-rw-r--r--doc/0xax.gitbooks.io_linux-insides_content_Booting_linux-bootstrap-2.txt937
1 files changed, 937 insertions, 0 deletions
diff --git a/doc/0xax.gitbooks.io_linux-insides_content_Booting_linux-bootstrap-2.txt b/doc/0xax.gitbooks.io_linux-insides_content_Booting_linux-bootstrap-2.txt
new file mode 100644
index 0000000..c0663b3
--- /dev/null
+++ b/doc/0xax.gitbooks.io_linux-insides_content_Booting_linux-bootstrap-2.txt
@@ -0,0 +1,937 @@
+ #[1]next [2]prev
+
+ IFRAME:
+ [3]https://archive.org/includes/donate.php?as_page=1&platform=wb&refere
+ r=https%3A//web.archive.org/web/20230308144724/https%3A//0xax.gitbooks.
+ io/linux-insides/content/Booting/linux-bootstrap-2.html
+
+ [4]Wayback Machine
+ https://0xax.gitbook Go
+ [5]47 captures
+ 02 Feb 2015 - 22 Mar 2023
+ [6]Dec MAR Apr
+ [7]Previous capture 08 [8]Next capture
+ [9]2022 2023 2024
+ success
+ fail
+ [10]About this capture
+ COLLECTED BY
+ Collection: [11]mega002
+ TIMESTAMPS
+ loading
+
+ The Wayback Machine -
+ https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/lin
+ ux-insides/content/Booting/linux-bootstrap-2.html
+
+ ____________________
+
+ * [12]Linux Inside
+ *
+ * Summary
+ * [13]Introduction
+ * [14]Booting
+ + [15]From bootloader to kernel
+ + [16]First steps in the kernel setup code
+ + [17]Video mode initialization and transition to protected mode
+ + [18]Transition to 64-bit mode
+ + [19]Kernel decompression
+ + [20]Kernel load address randomization
+ * [21]Initialization
+ + [22]First steps in the kernel
+ + [23]Early interrupts handler
+ + [24]Last preparations before the kernel entry point
+ + [25]Kernel entry point
+ + [26]Continue architecture-specific boot-time initializations
+ + [27]Architecture-specific initializations, again...
+ + [28]End of the architecture-specific initializations,
+ almost...
+ + [29]Scheduler initialization
+ + [30]RCU initialization
+ + [31]End of initialization
+ * [32]Interrupts
+ + [33]Introduction
+ + [34]Start to dive into interrupts
+ + [35]Interrupt handlers
+ + [36]Initialization of non-early interrupt gates
+ + [37]Implementation of some exception handlers
+ + [38]Handling Non-Maskable interrupts
+ + [39]Dive into external hardware interrupts
+ + [40]Initialization of external hardware interrupts structures
+ + [41]Softirq, Tasklets and Workqueues
+ + [42]Last part
+ * [43]System calls
+ + [44]Introduction to system calls
+ + [45]How the Linux kernel handles a system call
+ + [46]vsyscall and vDSO
+ + [47]How the Linux kernel runs a program
+ + [48]Implementation of the open system call
+ + [49]Limits on resources in Linux
+ * [50]Timers and time management
+ + [51]Introduction
+ + [52]Clocksource framework
+ + [53]The tick broadcast framework and dyntick
+ + [54]Introduction to timers
+ + [55]Clockevents framework
+ + [56]x86 related clock sources
+ + [57]Time related system calls
+ * [58]Synchronization primitives
+ + [59]Introduction to spinlocks
+ + [60]Queued spinlocks
+ + [61]Semaphores
+ + [62]Mutex
+ + [63]Reader/Writer semaphores
+ + [64]SeqLock
+ + RCU
+ + Lockdep
+ * [65]Memory management
+ + [66]Memblock
+ + [67]Fixmaps and ioremap
+ + [68]kmemcheck
+ * [69]Cgroups
+ + [70]Introduction to Control Groups
+ * SMP
+ * [71]Concepts
+ + [72]Per-CPU variables
+ + [73]Cpumasks
+ + [74]The initcall mechanism
+ + [75]Notification Chains
+ * [76]Data Structures in the Linux Kernel
+ + [77]Doubly linked list
+ + [78]Radix tree
+ + [79]Bit arrays
+ * [80]Theory
+ + [81]Paging
+ + [82]Elf64
+ + [83]Inline assembly
+ + CPUID
+ + MSR
+ * Initial ram disk
+ + initrd
+ * [84]Misc
+ + [85]Linux kernel development
+ + [86]How the kernel is compiled
+ + [87]Linkers
+ + [88]Program startup process in userspace
+ + Write and Submit your first Linux kernel Patch
+ + Data types in the kernel
+ * [89]KernelStructures
+ + [90]IDT
+ * [91]Useful links
+ * [92]Contributors
+ *
+
+ Powered by GitBook
+
+[93]First steps in the kernel setup code
+
+Kernel booting process. Part 2.
+
+First steps in the kernel setup
+
+ We started to dive into the linux kernel's insides in the previous
+ [94]part and saw the initial part of the kernel setup code. We stopped
+ at the first call to the main function (which is the first function
+ written in C) from [95]arch/x86/boot/main.c.
+
+ In this part, we will continue to research the kernel setup code and go
+ over
+ * what protected mode is,
+ * the transition into it,
+ * the initialization of the heap and the console,
+ * memory detection, CPU validation and keyboard initialization
+ * and much much more.
+
+ So, let's go ahead.
+
+Protected mode
+
+ Before we can move to the native Intel64 [96]Long Mode, the kernel must
+ switch the CPU into protected mode.
+
+ What is [97]protected mode? Protected mode was first added to the x86
+ architecture in 1982 and was the main mode of Intel processors from the
+ [98]80286 processor until Intel 64 and long mode came.
+
+ The main reason to move away from [99]Real mode is that there is very
+ limited access to the RAM. As you may remember from the previous part,
+ there are only 2^20 bytes or 1 Megabyte, sometimes even only 640
+ Kilobytes of RAM available in Real mode.
+
+ Protected mode brought many changes, but the main one is the difference
+ in memory management. The 20-bit address bus was replaced with a 32-bit
+ address bus. It allowed access to 4 Gigabytes of memory vs the 1
+ Megabyte in Real mode. Also, [100]paging support was added, which you
+ can read about in the next sections.
+
+ Memory management in Protected mode is divided into two, almost
+ independent parts:
+ * Segmentation
+ * Paging
+
+ Here we will only talk about segmentation. Paging will be discussed in
+ the next sections.
+
+ As you can read in the previous part, addresses consist of two parts in
+ Real mode:
+ * Base address of the segment
+ * Offset from the segment base
+
+ And we can get the physical address if we know these two parts by:
+PhysicalAddress = Segment Base * 16 + Offset
+
+ Memory segmentation was completely redone in protected mode. There are
+ no 64 Kilobyte fixed-size segments. Instead, the size and location of
+ each segment is described by an associated data structure called the
+ Segment Descriptor. These segment descriptors are stored in a data
+ structure called the Global Descriptor Table (GDT).
+
+ The GDT is a structure which resides in memory. It has no fixed place
+ in the memory, so its address is stored in the special GDTR register.
+ Later we will see how the GDT is loaded in the Linux kernel code. There
+ will be an operation for loading it from memory, something like:
+lgdt gdt
+
+ where the lgdt instruction loads the base address and limit(size) of
+ the global descriptor table to the GDTR register. GDTR is a 48-bit
+ register and consists of two parts:
+ * the size(16-bit) of the global descriptor table;
+ * the address(32-bit) of the global descriptor table.
+
+ As mentioned above, the GDT contains segment descriptors which describe
+ memory segments. Each descriptor is 64-bits in size. The general scheme
+ of a descriptor is:
+ 63 56 51 48 45 39 32
+------------------------------------------------------------
+| | |B| |A| | | | |0|E|W|A| |
+| BASE 31:24 |G|/|L|V| LIMIT |P|DPL|S| TYPE | BASE 23:16 |
+| | |D| |L| 19:16 | | | |1|C|R|A| |
+------------------------------------------------------------
+
+ 31 16 15 0
+------------------------------------------------------------
+| | |
+| BASE 15:0 | LIMIT 15:0 |
+| | |
+------------------------------------------------------------
+
+ Don't worry, I know it looks a little scary after Real mode, but it's
+ easy. For example LIMIT 15:0 means that bits 0-15 of the segment limit
+ are located at the beginning of the Descriptor. The rest of it is in
+ LIMIT 19:16, which is located at bits 48-51 of the Descriptor. So, the
+ size of Limit is 0-19 i.e 20-bits. Let's take a closer look at it:
+ 1. Limit[20-bits] is split between bits 0-15 and 48-51. It defines the
+ length_of_segment - 1. It depends on the G(Granularity) bit.
+ + if G (bit 55) is 0 and the segment limit is 0, the size of the
+ segment is 1 Byte
+ + if G is 1 and the segment limit is 0, the size of the segment
+ is 4096 Bytes
+ + if G is 0 and the segment limit is 0xfffff, the size of the
+ segment is 1 Megabyte
+ + if G is 1 and the segment limit is 0xfffff, the size of the
+ segment is 4 Gigabytes
+ So, what this means is
+ + if G is 0, Limit is interpreted in terms of 1 Byte and the
+ maximum size of the segment can be 1 Megabyte.
+ + if G is 1, Limit is interpreted in terms of 4096 Bytes = 4
+ KBytes = 1 Page and the maximum size of the segment can be 4
+ Gigabytes. Actually, when G is 1, the value of Limit is
+ shifted to the left by 12 bits. So, 20 bits + 12 bits = 32
+ bits and 2^32 = 4 Gigabytes.
+ 2. Base[32-bits] is split between bits 16-31, 32-39 and 56-63. It
+ defines the physical address of the segment's starting location.
+ 3. Type/Attribute[5-bits] is represented by bits 40-44. It defines the
+ type of segment and how it can be accessed.
+ + The S flag at bit 44 specifies the descriptor type. If S is 0
+ then this segment is a system segment, whereas if S is 1 then
+ this is a code or data segment (Stack segments are data
+ segments which must be read/write segments).
+
+ To determine if the segment is a code or data segment, we can check its
+ Ex(bit 43) Attribute (marked as 0 in the above diagram). If it is 0,
+ then the segment is a Data segment, otherwise, it is a code segment.
+
+ A segment can be of one of the following types:
+--------------------------------------------------------------------------------
+------
+| Type Field | Descriptor Type | Description
+ |
+|-----------------------------|-----------------|-------------------------------
+-----|
+| Decimal | |
+ |
+| 0 E W A | |
+ |
+| 0 0 0 0 0 | Data | Read-Only
+ |
+| 1 0 0 0 1 | Data | Read-Only, accessed
+ |
+| 2 0 0 1 0 | Data | Read/Write
+ |
+| 3 0 0 1 1 | Data | Read/Write, accessed
+ |
+| 4 0 1 0 0 | Data | Read-Only, expand-down
+ |
+| 5 0 1 0 1 | Data | Read-Only, expand-down, access
+ed |
+| 6 0 1 1 0 | Data | Read/Write, expand-down
+ |
+| 7 0 1 1 1 | Data | Read/Write, expand-down, acces
+sed |
+| C R A | |
+ |
+| 8 1 0 0 0 | Code | Execute-Only
+ |
+| 9 1 0 0 1 | Code | Execute-Only, accessed
+ |
+| 10 1 0 1 0 | Code | Execute/Read
+ |
+| 11 1 0 1 1 | Code | Execute/Read, accessed
+ |
+| 12 1 1 0 0 | Code | Execute-Only, conforming
+ |
+| 14 1 1 0 1 | Code | Execute-Only, conforming, acce
+ssed |
+| 13 1 1 1 0 | Code | Execute/Read, conforming
+ |
+| 15 1 1 1 1 | Code | Execute/Read, conforming, acce
+ssed |
+--------------------------------------------------------------------------------
+------
+
+ As we can see the first bit(bit 43) is 0 for a data segment and 1 for a
+ code segment. The next three bits (40, 41, 42) are either EWA(Expansion
+ Writable Accessible) or CRA(Conforming Readable Accessible).
+ * if E(bit 42) is 0, expand up, otherwise, expand down. Read more
+ [101]here.
+ * if W(bit 41)(for Data Segments) is 1, write access is allowed, and
+ if it is 0, the segment is read-only. Note that read access is
+ always allowed on data segments.
+ * A(bit 40) controls whether the segment can be accessed by the
+ processor or not.
+ * C(bit 43) is the conforming bit(for code selectors). If C is 1, the
+ segment code can be executed from a lower level privilege (e.g.
+ user) level. If C is 0, it can only be executed from the same
+ privilege level.
+ * R(bit 41) controls read access to code segments; when it is 1, the
+ segment can be read from. Write access is never granted for code
+ segments.
+
+ 1. DPL[2-bits] (Descriptor Privilege Level) comprises the bits 45-46.
+ It defines the privilege level of the segment. It can be 0-3 where
+ 0 is the most privileged level.
+ 2. The P flag(bit 47) indicates if the segment is present in memory or
+ not. If P is 0, the segment will be presented as invalid and the
+ processor will refuse to read from this segment.
+ 3. AVL flag(bit 52) - Available and reserved bits. It is ignored in
+ Linux.
+ 4. The L flag(bit 53) indicates whether a code segment contains native
+ 64-bit code. If it is set, then the code segment executes in 64-bit
+ mode.
+ 5. The D/B flag(bit 54) (Default/Big flag) represents the operand size
+ i.e 16/32 bits. If set, operand size is 32 bits. Otherwise, it is
+ 16 bits.
+
+ Segment registers contain segment selectors as in real mode. However,
+ in protected mode, a segment selector is handled differently. Each
+ Segment Descriptor has an associated Segment Selector which is a 16-bit
+ structure:
+ 15 3 2 1 0
+-----------------------------
+| Index | TI | RPL |
+-----------------------------
+
+ Where,
+ * Index stores the index number of the descriptor in the GDT.
+ * TI(Table Indicator) indicates where to search for the descriptor.
+ If it is 0 then the descriptor is searched for in the Global
+ Descriptor Table(GDT). Otherwise, it will be searched for in the
+ Local Descriptor Table(LDT).
+ * And RPL contains the Requester's Privilege Level.
+
+ Every segment register has a visible and a hidden part.
+ * Visible - The Segment Selector is stored here.
+ * Hidden - The Segment Descriptor (which contains the base, limit,
+ attributes & flags) is stored here.
+
+ The following steps are needed to get a physical address in protected
+ mode:
+ * The segment selector must be loaded in one of the segment
+ registers.
+ * The CPU tries to find a segment descriptor at the offset GDT
+ address + Index from the selector and then loads the descriptor
+ into the hidden part of the segment register.
+ * If paging is disabled, the linear address of the segment, or its
+ physical address, is given by the formula: Base address (found in
+ the descriptor obtained in the previous step) + Offset.
+
+ Schematically it will look like this:
+
+ linear address
+
+ The algorithm for the transition from real mode into protected mode is:
+ * Disable interrupts
+ * Describe and load the GDT with the lgdt instruction
+ * Set the PE (Protection Enable) bit in CR0 (Control Register 0)
+ * Jump to protected mode code
+
+ We will see the complete transition to protected mode in the linux
+ kernel in the next part, but before we can move to protected mode, we
+ need to do some more preparations.
+
+ Let's look at [102]arch/x86/boot/main.c. We can see some routines there
+ which perform keyboard initialization, heap initialization, etc...
+ Let's take a look.
+
+Copying boot parameters into the "zeropage"
+
+ We will start from the main routine in "main.c". The first function
+ which is called in main is [103]copy_boot_params(void). It copies the
+ kernel setup header into the corresponding field of the boot_params
+ structure which is defined in the
+ [104]arch/x86/include/uapi/asm/bootparam.h header file.
+
+ The boot_params structure contains the struct setup_header hdr field.
+ This structure contains the same fields as defined in the [105]linux
+ boot protocol and is filled by the boot loader and also at kernel
+ compile/build time. copy_boot_params does two things:
+ 1. It copies hdr from [106]header.S to the setup_header field in
+ boot_params structure.
+ 2. It updates the pointer to the kernel command line if the kernel was
+ loaded with the old command line protocol.
+
+ Note that it copies hdr with the memcpy function, defined in the
+ [107]copy.S source file. Let's have a look inside:
+GLOBAL(memcpy)
+ pushw %si
+ pushw %di
+ movw %ax, %di
+ movw %dx, %si
+ pushw %cx
+ shrw $2, %cx
+ rep; movsl
+ popw %cx
+ andw $3, %cx
+ rep; movsb
+ popw %di
+ popw %si
+ retl
+ENDPROC(memcpy)
+
+ Yeah, we just moved to C code and now assembly again :) First of all,
+ we can see that memcpy and other routines which are defined here, start
+ and end with the two macros: GLOBAL and ENDPROC. GLOBAL is described in
+ [108]arch/x86/include/asm/linkage.h which defines the globl directive
+ and its label. ENDPROC is described in [109]include/linux/linkage.h and
+ marks the name symbol as a function name and ends with the size of the
+ name symbol.
+
+ The implementation of memcpy is simple. At first, it pushes values from
+ the si and di registers to the stack to preserve their values because
+ they will change during the memcpy. As we can see in the
+ REALMODE_CFLAGS in arch/x86/Makefile, the kernel build system uses the
+ -mregparm=3 option of GCC, so functions get the first three parameters
+ from ax, dx and cx registers. Calling memcpy looks like this:
+memcpy(&boot_params.hdr, &hdr, sizeof hdr);
+
+ So,
+ * ax will contain the address of boot_params.hdr
+ * dx will contain the address of hdr
+ * cx will contain the size of hdr in bytes.
+
+ memcpy puts the address of boot_params.hdr into di and saves cx on the
+ stack. After this it shifts the value right 2 times (or divides it by
+ 4) and copies four bytes from the address at si to the address at di.
+ After this, we restore the size of hdr again, align it by 4 bytes and
+ copy the rest of the bytes from the address at si to the address at di
+ byte by byte (if there is more). Now the values of si and di are
+ restored from the stack and the copying operation is finished.
+
+Console initialization
+
+ After hdr is copied into boot_params.hdr, the next step is to
+ initialize the console by calling the console_init function, defined in
+ [110]arch/x86/boot/early_serial_console.c.
+
+ It tries to find the earlyprintk option in the command line and if the
+ search was successful, it parses the port address and baud rate of the
+ serial port and initializes the serial port. The value of the
+ earlyprintk command line option can be one of these:
+ * serial,0x3f8,115200
+ * serial,ttyS0,115200
+ * ttyS0,115200
+
+ After serial port initialization we can see the first output:
+if (cmdline_find_option_bool("debug"))
+ puts("early console in setup code\n");
+
+ The definition of puts is in [111]tty.c. As we can see it prints
+ character by character in a loop by calling the putchar function. Let's
+ look into the putchar implementation:
+void __attribute__((section(".inittext"))) putchar(int ch)
+{
+ if (ch == '\n')
+ putchar('\r');
+
+ bios_putchar(ch);
+
+ if (early_serial_base != 0)
+ serial_putchar(ch);
+}
+
+ __attribute__((section(".inittext"))) means that this code will be in
+ the .inittext section. We can find it in the linker file [112]setup.ld.
+
+ First of all, putchar checks for the \n symbol and if it is found,
+ prints \r before. After that it prints the character on the VGA screen
+ by calling the BIOS with the 0x10 interrupt call:
+static void __attribute__((section(".inittext"))) bios_putchar(int ch)
+{
+ struct biosregs ireg;
+
+ initregs(&ireg);
+ ireg.bx = 0x0007;
+ ireg.cx = 0x0001;
+ ireg.ah = 0x0e;
+ ireg.al = ch;
+ intcall(0x10, &ireg, NULL);
+}
+
+ Here initregs takes the biosregs structure and first fills biosregs
+ with zeros using the memset function and then fills it with register
+ values.
+ memset(reg, 0, sizeof *reg);
+ reg->eflags |= X86_EFLAGS_CF;
+ reg->ds = ds();
+ reg->es = ds();
+ reg->fs = fs();
+ reg->gs = gs();
+
+ Let's look at the implementation of [113]memset:
+GLOBAL(memset)
+ pushw %di
+ movw %ax, %di
+ movzbl %dl, %eax
+ imull $0x01010101,%eax
+ pushw %cx
+ shrw $2, %cx
+ rep; stosl
+ popw %cx
+ andw $3, %cx
+ rep; stosb
+ popw %di
+ retl
+ENDPROC(memset)
+
+ As you can read above, it uses the same calling conventions as the
+ memcpy function, which means that the function gets its parameters from
+ the ax, dx and cx registers.
+
+ The implementation of memset is similar to that of memcpy. It saves the
+ value of the di register on the stack and puts the value ofax, which
+ stores the address of the biosregs structure, into di . Next is the
+ movzbl instruction, which copies the value of dl to the lowermost byte
+ of the eax register. The remaining 3 high bytes of eax will be filled
+ with zeros.
+
+ The next instruction multiplies eax with 0x01010101. It needs to
+ because memset will copy 4 bytes at the same time. For example, if we
+ need to fill a structure whose size is 4 bytes with the value 0x7 with
+ memset, eax will contain the 0x00000007. So if we multiply eax with
+ 0x01010101, we will get 0x07070707 and now we can copy these 4 bytes
+ into the structure. memset uses the rep; stosl instruction to copy eax
+ into es:di.
+
+ The rest of the memset function does almost the same thing as memcpy.
+
+ After the biosregs structure is filled with memset, bios_putchar calls
+ the [114]0x10 interrupt which prints a character. Afterwards it checks
+ if the serial port was initialized or not and writes a character there
+ with [115]serial_putchar and inb/outb instructions if it was set.
+
+Heap initialization
+
+ After the stack and bss section have been prepared in [116]header.S
+ (see previous [117]part), the kernel needs to initialize the [118]heap
+ with the [119]init_heap function.
+
+ First of all init_heap checks the [120]CAN_USE_HEAP flag from the
+ [121]loadflags structure in the kernel setup header and calculates the
+ end of the stack if this flag was set:
+ char *stack_end;
+
+ if (boot_params.hdr.loadflags & CAN_USE_HEAP) {
+ asm("leal %P1(%%esp),%0"
+ : "=r" (stack_end) : "i" (-STACK_SIZE));
+
+ or in other words stack_end = esp - STACK_SIZE.
+
+ Then there is the heap_end calculation:
+ heap_end = (char *)((size_t)boot_params.hdr.heap_end_ptr + 0x200);
+
+ which means heap_end_ptr or _end + 512 (0x200h). The last check is
+ whether heap_end is greater than stack_end. If it is then stack_end is
+ assigned to heap_end to make them equal.
+
+ Now the heap is initialized and we can use it using the GET_HEAP
+ method. We will see what it is used for, how to use it and how it is
+ implemented in the next posts.
+
+CPU validation
+
+ The next step as we can see is cpu validation through the validate_cpu
+ function from [122]arch/x86/boot/cpu.c source code file.
+
+ It calls the [123]check_cpu function and passes cpu level and required
+ cpu level to it and checks that the kernel launches on the right cpu
+ level.
+check_cpu(&cpu_level, &req_level, &err_flags);
+if (cpu_level < req_level) {
+ ...
+ return -1;
+}
+
+ The check_cpu function checks the CPU's flags, the presence of
+ [124]long mode in the case of x86_64(64-bit) CPU, checks the
+ processor's vendor and makes preparations for certain vendors like
+ turning off SSE+SSE2 for AMD if they are missing, etc.
+
+ at the next step, we may see a call to the set_bios_mode function after
+ setup code found that a CPU is suitable. As we may see, this function
+ is implemented only for the x86_64 mode:
+static void set_bios_mode(void)
+{
+#ifdef CONFIG_X86_64
+ struct biosregs ireg;
+
+ initregs(&ireg);
+ ireg.ax = 0xec00;
+ ireg.bx = 2;
+ intcall(0x15, &ireg, NULL);
+#endif
+}
+
+ The set_bios_mode function executes the 0x15 BIOS interrupt to tell the
+ BIOS that [125]long mode (if bx == 2) will be used.
+
+Memory detection
+
+ The next step is memory detection through the detect_memory function.
+ detect_memory basically provides a map of available RAM to the CPU. It
+ uses different programming interfaces for memory detection like 0xe820,
+ 0xe801 and 0x88. We will see only the implementation of the 0xE820
+ interface here.
+
+ Let's look at the implementation of the detect_memory_e820 function
+ from the [126]arch/x86/boot/memory.c source file. First of all, the
+ detect_memory_e820 function initializes the biosregs structure as we
+ saw above and fills registers with special values for the 0xe820 call:
+ initregs(&ireg);
+ ireg.ax = 0xe820;
+ ireg.cx = sizeof buf;
+ ireg.edx = SMAP;
+ ireg.di = (size_t)&buf;
+
+ * ax contains the number of the function (0xe820 in our case)
+ * cx contains the size of the buffer which will contain data about
+ the memory
+ * edx must contain the SMAP magic number
+ * es:di must contain the address of the buffer which will contain
+ memory data
+ * ebx has to be zero.
+
+ Next is a loop where data about the memory will be collected. It starts
+ with a call to the 0x15 BIOS interrupt, which writes one line from the
+ address allocation table. For getting the next line we need to call
+ this interrupt again (which we do in the loop). Before the next call
+ ebx must contain the value returned previously:
+ intcall(0x15, &ireg, &oreg);
+ ireg.ebx = oreg.ebx;
+
+ Ultimately, this function collects data from the address allocation
+ table and writes this data into the e820_entry array:
+ * start of memory segment
+ * size of memory segment
+ * type of memory segment (whether the particular segment is usable or
+ reserved)
+
+ You can see the result of this in the dmesg output, something like:
+[ 0.000000] e820: BIOS-provided physical RAM map:
+[ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
+[ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
+[ 0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved
+[ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000003ffdffff] usable
+[ 0.000000] BIOS-e820: [mem 0x000000003ffe0000-0x000000003fffffff] reserved
+[ 0.000000] BIOS-e820: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved
+
+Keyboard initialization
+
+ The next step is the initialization of the keyboard with a call to the
+ [127]keyboard_init function. At first keyboard_init initializes
+ registers using the initregs function. It then calls the [128]0x16
+ interrupt to query the status of the keyboard.
+ initregs(&ireg);
+ ireg.ah = 0x02; /* Get keyboard status */
+ intcall(0x16, &ireg, &oreg);
+ boot_params.kbd_status = oreg.al;
+
+ After this it calls [129]0x16 again to set the repeat rate and delay.
+ ireg.ax = 0x0305; /* Set keyboard repeat rate */
+ intcall(0x16, &ireg, NULL);
+
+Querying
+
+ The next couple of steps are queries for different parameters. We will
+ not dive into details about these queries but we will get back to them
+ in later parts. Let's take a short look at these functions:
+
+ The first step is getting [130]Intel SpeedStep information by calling
+ the query_ist function. It checks the CPU level and if it is correct,
+ calls 0x15 to get the info and saves the result to boot_params.
+
+ Next, the [131]query_apm_bios function gets [132]Advanced Power
+ Management information from the BIOS. query_apm_bios calls the 0x15
+ BIOS interruption too, but with ah = 0x53 to check APM installation.
+ After 0x15 finishes executing, the query_apm_bios functions check the
+ PM signature (it must be 0x504d), the carry flag (it must be 0 if APM
+ supported) and the value of the cx register (if it's 0x02, the
+ protected mode interface is supported).
+
+ Next, it calls 0x15 again, but with ax = 0x5304 to disconnect the APM
+ interface and connect the 32-bit protected mode interface. In the end,
+ it fills boot_params.apm_bios_info with values obtained from the BIOS.
+
+ Note that query_apm_bios will be executed only if the CONFIG_APM or
+ CONFIG_APM_MODULE compile time flag was set in the configuration file:
+#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
+ query_apm_bios();
+#endif
+
+ The last is the [133]query_edd function, which queries Enhanced Disk
+ Drive information from the BIOS. Let's look at how query_edd is
+ implemented.
+
+ First of all, it reads the [134]edd option from the kernel's command
+ line and if it was set to off then query_edd just returns.
+
+ If EDD is enabled, query_edd goes over BIOS-supported hard disks and
+ queries EDD information in the following loop:
+for (devno = 0x80; devno < 0x80+EDD_MBR_SIG_MAX; devno++) {
+ if (!get_edd_info(devno, &ei) && boot_params.eddbuf_entries < EDDMAXNR) {
+ memcpy(edp, &ei, sizeof ei);
+ edp++;
+ boot_params.eddbuf_entries++;
+ }
+ ...
+ ...
+ ...
+ }
+
+ where 0x80 is the first hard drive and the value of the EDD_MBR_SIG_MAX
+ macro is 16. It collects data into an array of [135]edd_info
+ structures. get_edd_info checks that EDD is present by invoking the
+ 0x13 interrupt with ah as 0x41 and if EDD is present, get_edd_info
+ again calls the 0x13 interrupt, but with ah as 0x48 and si containing
+ the address of the buffer where EDD information will be stored.
+
+Conclusion
+
+ This is the end of the second part about the insides of the Linux
+ kernel. In the next part, we will see video mode setting and the rest
+ of the preparations before the transition to protected mode and
+ directly transitioning into it.
+
+ If you have any questions or suggestions write me a comment or ping me
+ at [136]twitter.
+
+ Please note that English is not my first language, And I am really
+ sorry for any inconvenience. If you find any mistakes please send me a
+ PR to [137]linux-insides.
+
+Links
+
+ * [138]Protected mode
+ * [139]Protected mode
+ * [140]Long mode
+ * [141]Nice explanation of CPU Modes with code
+ * [142]How to Use Expand Down Segments on Intel 386 and Later CPUs
+ * [143]earlyprintk documentation
+ * [144]Kernel Parameters
+ * [145]Serial console
+ * [146]Intel SpeedStep
+ * [147]APM
+ * [148]EDD specification
+ * [149]TLDP documentation for Linux Boot Process (old)
+ * [150]Previous Part
+
+results matching ""
+
+No results matching ""
+
+References
+
+ Visible links:
+ 1. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-3.html
+ 2. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
+ 3. https://archive.org/includes/donate.php?as_page=1&platform=wb&referer=https%3A//web.archive.org/web/20230308144724/https%3A//0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 4. https://web.archive.org/web/
+ 5. https://web.archive.org/web/20230308144724*/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 6. https://web.archive.org/web/20221206122118/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 7. https://web.archive.org/web/20221206122118/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 8. https://web.archive.org/web/20230322150041/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 9. https://web.archive.org/web/20220123200511/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 10. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html#expand
+ 11. https://archive.org/details/mega-002
+ 12. https://web.archive.org/web/20230308144724/https://legacy.gitbook.com/book/0xax/linux-insides
+ 13. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/
+ 14. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/
+ 15. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
+ 16. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 17. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-3.html
+ 18. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-4.html
+ 19. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-5.html
+ 20. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-6.html
+ 21. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/
+ 22. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-1.html
+ 23. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-2.html
+ 24. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-3.html
+ 25. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-4.html
+ 26. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-5.html
+ 27. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-6.html
+ 28. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-7.html
+ 29. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-8.html
+ 30. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-9.html
+ 31. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-10.html
+ 32. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/
+ 33. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-1.html
+ 34. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-2.html
+ 35. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-3.html
+ 36. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-4.html
+ 37. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-5.html
+ 38. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-6.html
+ 39. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-7.html
+ 40. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-8.html
+ 41. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-9.html
+ 42. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-10.html
+ 43. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SysCall/
+ 44. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-1.html
+ 45. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-2.html
+ 46. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-3.html
+ 47. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-4.html
+ 48. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-5.html
+ 49. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-6.html
+ 50. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Timers/
+ 51. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-1.html
+ 52. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-2.html
+ 53. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-3.html
+ 54. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-4.html
+ 55. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-5.html
+ 56. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-6.html
+ 57. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-7.html
+ 58. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/
+ 59. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-1.html
+ 60. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-2.html
+ 61. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-3.html
+ 62. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-4.html
+ 63. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-5.html
+ 64. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-6.html
+ 65. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/MM/
+ 66. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/MM/linux-mm-1.html
+ 67. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/MM/linux-mm-2.html
+ 68. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/MM/linux-mm-3.html
+ 69. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Cgroups/
+ 70. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Cgroups/linux-cgroups-1.html
+ 71. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Concepts/
+ 72. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html
+ 73. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html
+ 74. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-3.html
+ 75. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-4.html
+ 76. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/DataStructures/
+ 77. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-1.html
+ 78. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-2.html
+ 79. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-3.html
+ 80. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Theory/
+ 81. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-1.html
+ 82. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-2.html
+ 83. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-3.html
+ 84. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Misc/
+ 85. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Misc/linux-misc-1.html
+ 86. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Misc/linux-misc-2.html
+ 87. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Misc/linux-misc-3.html
+ 88. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Misc/linux-misc-4.html
+ 89. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/KernelStructures/
+ 90. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/KernelStructures/linux-kernelstructure-1.html
+ 91. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/LINKS.html
+ 92. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/contributors.html
+ 93. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/
+ 94. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
+ 95. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/main.c
+ 96. https://web.archive.org/web/20230308144724/http://en.wikipedia.org/wiki/Long_mode
+ 97. https://web.archive.org/web/20230308144724/https://en.wikipedia.org/wiki/Protected_mode
+ 98. https://web.archive.org/web/20230308144724/http://en.wikipedia.org/wiki/Intel_80286
+ 99. https://web.archive.org/web/20230308144724/http://wiki.osdev.org/Real_Mode
+ 100. https://web.archive.org/web/20230308144724/http://en.wikipedia.org/wiki/Paging
+ 101. https://web.archive.org/web/20230308144724/http://www.sudleyplace.com/dpmione/expanddown.html
+ 102. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/main.c
+ 103. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/main.c
+ 104. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/include/uapi/asm/bootparam.h
+ 105. https://web.archive.org/web/20230308144724/https://www.kernel.org/doc/Documentation/x86/boot.txt
+ 106. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/header.S#L280
+ 107. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/copy.S
+ 108. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/include/asm/linkage.h
+ 109. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/include/linux/linkage.h
+ 110. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/early_serial_console.c
+ 111. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/tty.c
+ 112. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/setup.ld
+ 113. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/copy.S#L36
+ 114. https://web.archive.org/web/20230308144724/http://www.ctyme.com/intr/rb-0106.htm
+ 115. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/tty.c
+ 116. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/header.S
+ 117. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
+ 118. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/main.c
+ 119. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/main.c
+ 120. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/include/uapi/asm/bootparam.h#L24
+ 121. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/header.S#L320
+ 122. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/cpu.c
+ 123. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/cpucheck.c
+ 124. https://web.archive.org/web/20230308144724/http://en.wikipedia.org/wiki/Long_mode
+ 125. https://web.archive.org/web/20230308144724/https://en.wikipedia.org/wiki/Long_mode
+ 126. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/memory.c
+ 127. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/main.c
+ 128. https://web.archive.org/web/20230308144724/http://www.ctyme.com/intr/rb-1756.htm
+ 129. https://web.archive.org/web/20230308144724/http://www.ctyme.com/intr/rb-1757.htm
+ 130. https://web.archive.org/web/20230308144724/http://en.wikipedia.org/wiki/SpeedStep
+ 131. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/apm.c#L21
+ 132. https://web.archive.org/web/20230308144724/http://en.wikipedia.org/wiki/Advanced_Power_Management
+ 133. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/edd.c#L122
+ 134. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/Documentation/admin-guide/kernel-parameters.rst
+ 135. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/include/uapi/linux/edd.h
+ 136. https://web.archive.org/web/20230308144724/https://twitter.com/0xAX
+ 137. https://web.archive.org/web/20230308144724/https://github.com/0xAX/linux-internals
+ 138. https://web.archive.org/web/20230308144724/http://en.wikipedia.org/wiki/Protected_mode
+ 139. https://web.archive.org/web/20230308144724/http://wiki.osdev.org/Protected_Mode
+ 140. https://web.archive.org/web/20230308144724/http://en.wikipedia.org/wiki/Long_mode
+ 141. https://web.archive.org/web/20230308144724/http://www.codeproject.com/Articles/45788/The-Real-Protected-Long-mode-assembly-tutorial-for
+ 142. https://web.archive.org/web/20230308144724/http://www.sudleyplace.com/dpmione/expanddown.html
+ 143. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/Documentation/x86/earlyprintk.txt
+ 144. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/Documentation/admin-guide/kernel-parameters.rst
+ 145. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/Documentation/admin-guide/serial-console.rst
+ 146. https://web.archive.org/web/20230308144724/http://en.wikipedia.org/wiki/SpeedStep
+ 147. https://web.archive.org/web/20230308144724/https://en.wikipedia.org/wiki/Advanced_Power_Management
+ 148. https://web.archive.org/web/20230308144724/http://www.t13.org/documents/UploadedDocuments/docs2004/d1572r3-EDD3.pdf
+ 149. https://web.archive.org/web/20230308144724/http://www.tldp.org/HOWTO/Linux-i386-Boot-Code-HOWTO/setup.html
+ 150. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
+
+ Hidden links:
+ 152. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 153. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 154. https://archive.org/account/login.php
+ 155. http://faq.web.archive.org/
+ 156. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html#close
+ 157. https://web.archive.org/web/20230308144724/http://web.archive.org/screenshot/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 158. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 159. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 160. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 161. https://web.archive.org/web/20230308144724/https://www.gitbook.com/?utm_source=public_site_legacy&utm_medium=referral&utm_campaign=trademark&utm_term=0xax&utm_content=powered_by
+ 162. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
+ 163. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-3.html