summaryrefslogtreecommitdiff
path: root/doc/0xax.gitbooks.io_linux-insides_content_Booting_linux-bootstrap-2.txt
blob: c0663b3adedb95f10ba9506015894d92a4c3f189 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
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