summaryrefslogtreecommitdiff
path: root/doc/0xax.gitbooks.io_linux-insides_content_Booting_linux-bootstrap-1.txt
blob: d1e197119889ab4963beaef99512e0065a449ff3 (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
   #[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/20230308144716/https%3A//0xax.gitbooks.
   io/linux-insides/content/Booting/linux-bootstrap-1.html

   [4]Wayback Machine
   https://0xax.gitbook Go
   [5]86 captures
   01 Feb 2015 - 22 Mar 2023
   [6]Jan              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/20230308144716/https://0xax.gitbooks.io/lin
   ux-insides/content/Booting/linux-bootstrap-1.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]From bootloader to kernel

Kernel booting process. Part 1.

From the bootloader to the kernel

   If you read my previous [94]blog posts, you might have noticed that I
   have been involved with low-level programming for some time. I wrote
   some posts about assembly programming for x86_64 Linux and, at the same
   time, started to dive into the Linux kernel source code.

   I have a great interest in understanding how low-level things work, how
   programs run on my computer, how they are located in memory, how the
   kernel manages processes and memory, how the network stack works at a
   low level, and many many other things. So, I decided to write yet
   another series of posts about the Linux kernel for the x86_64
   architecture.

   Note that I'm not a professional kernel hacker and I don't write code
   for the kernel at work. It's just a hobby. I just like low-level stuff,
   and it is interesting for me to see how these things work. So if you
   notice anything confusing, or if you have any questions/remarks, ping
   me on Twitter [95]0xAX, drop me an [96]email or just create an
   [97]issue. I appreciate it.

   All posts will also be accessible at [98]github repo and, if you find
   something wrong with my English or the post content, feel free to send
   a pull request.

   Note that this isn't official documentation, just learning and sharing
   knowledge.

   Required knowledge
     * Understanding C code
     * Understanding assembly code (AT&T syntax)

   Anyway, if you're just starting to learn such tools, I will try to
   explain some parts during this and the following posts. Alright, this
   is the end of the simple introduction. Let's start to dive into the
   Linux kernel and low-level stuff!

   I started writing these posts at the time of the 3.18 Linux kernel, and
   many things have changed since that time. If there are changes, I will
   update the posts accordingly.

The Magical Power Button, What happens next?

   Although this is a series of posts about the Linux kernel, we won't
   start directly from the kernel code. As soon as you press the magical
   power button on your laptop or desktop computer, it starts working. The
   motherboard sends a signal to the [99]power supply device. After
   receiving the signal, the power supply provides the proper amount of
   electricity to the computer. Once the motherboard receives the
   [100]power good signal, it tries to start the CPU. The CPU resets all
   leftover data in its registers and sets predefined values for each of
   them.

   The [101]80386 and later CPUs define the following predefined data in
   CPU registers after the computer resets:
IP          0xfff0
CS selector 0xf000
CS base     0xffff0000

   The processor starts working in [102]real mode. Let's back up a little
   and try to understand [103]memory segmentation in this mode. Real mode
   is supported on all x86-compatible processors, from the [104]8086 CPU
   all the way to the modern Intel 64-bit CPUs. The 8086 processor has a
   20-bit address bus, which means that it could work with a 0-0xFFFFF or
   1 megabyte address space. But it only has 16-bit registers, which have
   a maximum address of 2^16 - 1 or 0xffff (64 kilobytes).

   [105]Memory segmentation is used to make use of all the address space
   available. All memory is divided into small, fixed-size segments of
   65536 bytes (64 KB). Since we cannot address memory above 64 KB with
   16-bit registers, an alternate method was devised.

   An address consists of two parts: a segment selector, which has a base
   address; and an offset from this base address. In real mode, the
   associated base address of a segment selector is Segment Selector * 16.
   Thus, to get a physical address in memory, we need to multiply the
   segment selector part by 16 and add the offset to it:
PhysicalAddress = Segment Selector * 16 + Offset

   For example, if CS:IP is 0x2000:0x0010, then the corresponding physical
   address will be:
>>> hex((0x2000 << 4) + 0x0010)
'0x20010'

   But, if we take the largest segment selector and offset, 0xffff:0xffff,
   then the resulting address will be:
>>> hex((0xffff << 4) + 0xffff)
'0x10ffef'

   which is 65520 bytes past the first megabyte. Since only one megabyte
   is accessible in real mode, 0x10ffef becomes 0x00ffef with the [106]A20
   line disabled.

   Ok, now we know a little bit about real mode and its memory addressing.
   Let's get back to discussing register values after reset.

   The CS register consists of two parts: the visible segment selector and
   the hidden base address. While the base address is normally formed by
   multiplying the segment selector value by 16, during a hardware reset
   the segment selector in the CS register is loaded with 0xf000 and the
   base address is loaded with 0xffff0000. The processor uses this special
   base address until CS changes.

   The starting address is formed by adding the base address to the value
   in the EIP register:
>>> 0xffff0000 + 0xfff0
'0xfffffff0'

   We get 0xfffffff0, which is 16 bytes below 4GB. This point is called
   the [107]reset vector. It's the memory location at which the CPU
   expects to find the first instruction to execute after reset. It
   contains a [108]jump (jmp) instruction that usually points to the
   [109]BIOS (Basic Input/Output System) entry point. For example, if we
   look in the [110]coreboot source code (src/cpu/x86/16bit/reset16.inc),
   we see:
    .section ".reset", "ax", %progbits
    .code16
.globl    _start
_start:
    .byte  0xe9
    .int   _start16bit - ( . + 2 )
    ...

   Here we can see the jmp instruction [111]opcode, which is 0xe9, and its
   destination address at _start16bit - ( . + 2).

   We also see that the reset section is 16 bytes and is compiled to start
   from the address 0xfffffff0 (src/cpu/x86/16bit/reset16.ld):
SECTIONS {
    /* Trigger an error if I have an unuseable start address */
    _bogus = ASSERT(_start16bit >= 0xffff0000, "_start16bit too low. Please repo
rt.");
    _ROMTOP = 0xfffffff0;
    . = _ROMTOP;
    .reset . : {
        *(.reset);
        . = 15;
        BYTE(0x00);
    }
}

   Now the BIOS starts. After initializing and checking the hardware, the
   BIOS needs to find a bootable device. A boot order is stored in the
   BIOS configuration, controlling which devices the BIOS attempts to boot
   from. When attempting to boot from a hard drive, the BIOS tries to find
   a boot sector. On hard drives partitioned with an [112]MBR partition
   layout, the boot sector is stored in the first 446 bytes of the first
   sector, where each sector is 512 bytes. The final two bytes of the
   first sector are 0x55 and 0xaa, which designates to the BIOS that this
   device is bootable.

   For example:
;
; Note: this example is written in Intel Assembly syntax
;
[BITS 16]

boot:
    mov al, '!'
    mov ah, 0x0e
    mov bh, 0x00
    mov bl, 0x07

    int 0x10
    jmp $

times 510-($-$$) db 0

db 0x55
db 0xaa

   Build and run this with:
nasm -f bin boot.nasm && qemu-system-x86_64 boot

   This will instruct [113]QEMU to use the boot binary that we just built
   as a disk image. Since the binary generated by the assembly code above
   fulfills the requirements of the boot sector (the origin is set to
   0x7c00 and we end it with the magic sequence), QEMU will treat the
   binary as the master boot record (MBR) of a disk image.

   You will see:

   Simple bootloader which prints only `!`

   In this example, we can see that the code will be executed in 16-bit
   real mode and will start at 0x7c00 in memory. After starting, it calls
   the [114]0x10 interrupt, which just prints the ! symbol. It fills the
   remaining 510 bytes with zeros and finishes with the two magic bytes
   0xaa and 0x55.

   You can see a binary dump of this using the objdump utility:
nasm -f bin boot.nasm
objdump -D -b binary -mi386 -Maddr16,data16,intel boot

   A real-world boot sector has code for continuing the boot process and a
   partition table instead of a bunch of 0's and an exclamation mark. :)
   From this point onwards, the BIOS hands control over to the bootloader.

   NOTE: As explained above, the CPU is in real mode. In real mode,
   calculating the physical address in memory is done as follows:
PhysicalAddress = Segment Selector * 16 + Offset

   just as explained above. We have only 16-bit general purpose registers,
   which has a maximum value of 0xffff, so if we take the largest values
   the result will be:
>>> hex((0xffff * 16) + 0xffff)
'0x10ffef'

   where 0x10ffef is equal to 1MB + 64KB - 16b. An [115]8086 processor
   (which was the first processor with real mode), in contrast, has a
   20-bit address line. Since 2^20 = 1048576 is 1MB, this means that the
   actual available memory is 1MB.

   In general, real mode's memory map is as follows:
0x00000000 - 0x000003FF - Real Mode Interrupt Vector Table
0x00000400 - 0x000004FF - BIOS Data Area
0x00000500 - 0x00007BFF - Unused
0x00007C00 - 0x00007DFF - Our Bootloader
0x00007E00 - 0x0009FFFF - Unused
0x000A0000 - 0x000BFFFF - Video RAM (VRAM) Memory
0x000B0000 - 0x000B7777 - Monochrome Video Memory
0x000B8000 - 0x000BFFFF - Color Video Memory
0x000C0000 - 0x000C7FFF - Video ROM BIOS
0x000C8000 - 0x000EFFFF - BIOS Shadow Area
0x000F0000 - 0x000FFFFF - System BIOS

   At the beginning of this post, I wrote that the first instruction
   executed by the CPU is located at address 0xFFFFFFF0, which is much
   larger than 0xFFFFF (1MB). How can the CPU access this address in real
   mode? The answer is in the [116]coreboot documentation:
0xFFFE_0000 - 0xFFFF_FFFF: 128 kilobyte ROM mapped into address space

   At the start of execution, the BIOS is not in RAM, but in ROM.

Bootloader

   There are a number of bootloaders that can boot Linux, such as
   [117]GRUB 2 and [118]syslinux. The Linux kernel has a [119]Boot
   protocol which specifies the requirements for a bootloader to implement
   Linux support. This example will describe GRUB 2.

   Continuing from before, now that the BIOS has chosen a boot device and
   transferred control to the boot sector code, execution starts from
   [120]boot.img. Its code is very simple, due to the limited amount of
   space available. It contains a pointer which is used to jump to the
   location of GRUB 2's core image. The core image begins with
   [121]diskboot.img, which is usually stored immediately after the first
   sector in the unused space before the first partition. The above code
   loads the rest of the core image, which contains GRUB 2's kernel and
   drivers for handling filesystems, into memory. After loading the rest
   of the core image, it executes the [122]grub_main function.

   The grub_main function initializes the console, gets the base address
   for modules, sets the root device, loads/parses the grub configuration
   file, loads modules, etc. At the end of execution, the grub_main
   function moves grub to normal mode. The grub_normal_execute function
   (from the grub-core/normal/main.c source code file) completes the final
   preparations and shows a menu to select an operating system. When we
   select one of the grub menu entries, the grub_menu_execute_entry
   function runs, executing the grub boot command and booting the selected
   operating system.

   As we can read in the kernel boot protocol, the bootloader must read
   and fill some fields of the kernel setup header, which starts at offset
   0x01f1 from the kernel setup code. You may look at the boot [123]linker
   script to confirm the value of this offset. The kernel header
   [124]arch/x86/boot/header.S starts from:
    .globl hdr
hdr:
    setup_sects: .byte 0
    root_flags:  .word ROOT_RDONLY
    syssize:     .long 0
    ram_size:    .word 0
    vid_mode:    .word SVGA_MODE
    root_dev:    .word 0
    boot_flag:   .word 0xAA55

   The bootloader must fill this and the rest of the headers (which are
   only marked as being type write in the Linux boot protocol, such as in
   [125]this example) with values either received from the command line or
   calculated during booting. (We will not go over full descriptions and
   explanations for all fields of the kernel setup header for now, but we
   shall do so when discussing how the kernel uses them. You can find a
   description of all fields in the [126]boot protocol.)

   As we can see in the kernel boot protocol, memory will be mapped as
   follows after loading the kernel:
         | Protected-mode kernel  |
100000   +------------------------+
         | I/O memory hole        |
0A0000   +------------------------+
         | Reserved for BIOS      | Leave as much as possible unused
         ~                        ~
         | Command line           | (Can also be below the X+10000 mark)
X+10000  +------------------------+
         | Stack/heap             | For use by the kernel real-mode code.
X+08000  +------------------------+
         | Kernel setup           | The kernel real-mode code.
         | Kernel boot sector     | The kernel legacy boot sector.
       X +------------------------+
         | Boot loader            | <- Boot sector entry point 0x7C00
001000   +------------------------+
         | Reserved for MBR/BIOS  |
000800   +------------------------+
         | Typically used by MBR  |
000600   +------------------------+
         | BIOS use only          |
000000   +------------------------+

   When the bootloader transfers control to the kernel, it starts at:
X + sizeof(KernelBootSector) + 1

   where X is the address of the kernel boot sector being loaded. In my
   case, X is 0x10000, as we can see in a memory dump:

   kernel first address

   The bootloader has now loaded the Linux kernel into memory, filled the
   header fields, and then jumped to the corresponding memory address. We
   now move directly to the kernel setup code.

The Beginning of the Kernel Setup Stage

   Finally, we are in the kernel! Technically, the kernel hasn't run yet.
   First, the kernel setup part must configure stuff such as the
   decompressor and some memory management related things, to name a few.
   After all these things are done, the kernel setup part will decompress
   the actual kernel and jump to it. Execution of the setup part starts
   from [127]arch/x86/boot/header.S at the [128]_start symbol.

   It may look a bit strange at first sight, as there are several
   instructions before it. A long time ago, the Linux kernel had its own
   bootloader. Now, however, if you run, for example,
qemu-system-x86_64 vmlinuz-3.18-generic

   then you will see:

   Try vmlinuz in qemu

   Actually, the file header.S starts with the magic number [129]MZ (see
   image above), the error message that displays and, following that, the
   [130]PE header:
#ifdef CONFIG_EFI_STUB
# "MZ", MS-DOS header
.byte 0x4d
.byte 0x5a
#endif
...
...
...
pe_header:
    .ascii "PE"
    .word 0

   It needs this to load an operating system with [131]UEFI support. We
   won't be looking into its inner workings right now but will cover it in
   upcoming chapters.

   The actual kernel setup entry point is:
// header.S line 292
.globl _start
_start:

   The bootloader (GRUB 2 and others) knows about this point (at an offset
   of 0x200 from MZ) and jumps directly to it, despite the fact that
   header.S starts from the .bstext section, which prints an error
   message:
//
// arch/x86/boot/setup.ld
//
. = 0;                    // current position
.bstext : { *(.bstext) }  // put .bstext section to position 0
.bsdata : { *(.bsdata) }

   The kernel setup entry point is:
    .globl _start
_start:
    .byte  0xeb
    .byte  start_of_setup-1f
1:
    //
    // rest of the header
    //

   Here we can see a jmp instruction opcode (0xeb) that jumps to the
   start_of_setup-1f point. In Nf notation, 2f, for example, refers to the
   local label 2:. In our case, it's label 1: that is present right after
   the jump, and contains the rest of the setup [132]header. Right after
   the setup header, we see the .entrytext section, which starts at the
   start_of_setup label.

   This is the first code that actually runs (aside from the previous jump
   instructions, of course). After the kernel setup part receives control
   from the bootloader, the first jmp instruction is located at the 0x200
   offset from the start of the kernel real mode, i.e., after the first
   512 bytes. This can be seen in both the Linux kernel boot protocol and
   the GRUB 2 source code:
segment = grub_linux_real_target >> 4;
state.gs = state.fs = state.es = state.ds = state.ss = segment;
state.cs = segment + 0x20;

   In my case, the kernel is loaded at the physical address 0x10000. This
   means that segment registers have the following values after kernel
   setup starts:
gs = fs = es = ds = ss = 0x1000
cs = 0x1020

   After the jump to start_of_setup, the kernel needs to do the following:
     * Make sure that all segment register values are equal
     * Set up a correct stack, if needed
     * Set up [133]bss
     * Jump to the C code in [134]arch/x86/boot/main.c

   Let's look at the implementation.

Aligning the Segment Registers

   First of all, the kernel ensures that the ds and es segment registers
   point to the same address. Next, it clears the direction flag using the
   cld instruction:
    movw    %ds, %ax
    movw    %ax, %es
    cld

   As I wrote earlier, grub2 loads kernel setup code at address 0x10000 by
   default and cs at 0x1020 because execution doesn't start from the start
   of the file, but from the jump here:
_start:
    .byte 0xeb
    .byte start_of_setup-1f

   which is at a 512 byte offset from [135]4d 5a. We also need to align cs
   from 0x1020 to 0x1000, as well as all other segment registers. After
   that, we set up the stack:
    pushw   %ds
    pushw   $6f
    lretw

   which pushes the value of ds to the stack, followed by the address of
   the [136]6 label and executes the lretw instruction. When the lretw
   instruction is called, it loads the address of label 6 into the
   [137]instruction pointer register and loads cs with the value of ds.
   Afterward, ds and cs will have the same values.

Stack Setup

   Almost all of the setup code is for preparing the C language
   environment in real mode. The next [138]step is checking the ss
   register's value and setting up a correct stack if ss is wrong:
    movw    %ss, %dx
    cmpw    %ax, %dx
    movw    %sp, %dx
    je      2f

   This can lead to 3 different scenarios:
     * ss has a valid value 0x1000 (as do all the other segment registers
       besides cs)
     * ss is invalid and the CAN_USE_HEAP flag is set (see below)
     * ss is invalid and the CAN_USE_HEAP flag is not set (see below)

   Let's look at all three of these scenarios in turn:
     * ss has a correct address (0x1000). In this case, we go to label
       [139]2:

2:  andw    $~3, %dx
    jnz     3f
    movw    $0xfffc, %dx
3:  movw    %ax, %ss
    movzwl  %dx, %esp
    sti

   Here we set the alignment of dx (which contains the value of sp as
   given by the bootloader) to 4 bytes and check if it is zero. If it is,
   we set dx to 0xfffc (The last 4-byte aligned address in a 64KB
   segment). If it is not zero, we continue to use the value of sp given
   by the bootloader (0xf7f4 in my case). Afterwards, we put the value of
   ax (0x1000) into ss. We now have a correct stack:

   stack
     * The second scenario, (ss != ds). First, we put the value of
       [140]_end (the address of the end of the setup code) into dx and
       check the loadflags header field using the testb instruction to see
       whether we can use the heap. [141]loadflags is a bitmask header
       defined as:

#define LOADED_HIGH     (1<<0)
#define QUIET_FLAG      (1<<5)
#define KEEP_SEGMENTS   (1<<6)
#define CAN_USE_HEAP    (1<<7)

   and as we can read in the boot protocol:
Field name: loadflags

  This field is a bitmask.

  Bit 7 (write): CAN_USE_HEAP
    Set this bit to 1 to indicate that the value entered in the
    heap_end_ptr is valid.  If this field is clear, some setup code
    functionality will be disabled.

   If the CAN_USE_HEAP bit is set, we put heap_end_ptr into dx (which
   points to _end) and add STACK_SIZE (the minimum stack size, 1024 bytes)
   to it. After this, if dx is not carried (it will not be carried, dx =
   _end + 1024), jump to label 2 (as in the previous case) and make a
   correct stack.

   stack
     * When CAN_USE_HEAP is not set, we just use a minimal stack from _end
       to _end + STACK_SIZE:

   minimal stack

BSS Setup

   The last two steps that need to happen before we can jump to the main C
   code are setting up the [142]BSS area and checking the "magic"
   signature. First, signature checking:
    cmpl    $0x5a5aaa55, setup_sig
    jne     setup_bad

   This simply compares the [143]setup_sig with the magic number
   0x5a5aaa55. If they are not equal, a fatal error is reported.

   If the magic number matches, knowing we have a set of correct segment
   registers and a stack, we only need to set up the BSS section before
   jumping into the C code.

   The BSS section is used to store statically allocated, uninitialized
   data. Linux carefully ensures this area of memory is first zeroed using
   the following code:
    movw    $__bss_start, %di
    movw    $_end+3, %cx
    xorl    %eax, %eax
    subw    %di, %cx
    shrw    $2, %cx
    rep; stosl

   First, the [144]__bss_start address is moved into di. Next, the _end +
   3 address (+3 - aligns to 4 bytes) is moved into cx. The eax register
   is cleared (using the xor instruction), and the bss section size (cx -
   di) is calculated and put into cx. Then, cx is divided by four (the
   size of a 'word'), and the stosl instruction is used repeatedly,
   storing the value of eax (zero) into the address pointed to by di,
   automatically increasing di by four, repeating until cx reaches zero.
   The net effect of this code is that zeros are written through all words
   in memory from __bss_start to _end:

   bss

Jump to main

   That's all! We have the stack and BSS, so we can jump to the main() C
   function:
    calll main

   The main() function is located in [145]arch/x86/boot/main.c. You can
   read about what this does in the next part.

Conclusion

   This is the end of the first part about Linux kernel insides. If you
   have questions or suggestions, ping me on Twitter [146]0xAX, drop me an
   [147]email, or just create an [148]issue. In the next part, we will see
   the first C code that executes in the Linux kernel setup, the
   implementation of memory routines such as memset, memcpy, earlyprintk,
   early console implementation and initialization, and much more.

   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 PR to
   [149]linux-insides.

Links

     * [150]Intel 80386 programmer's reference manual 1986
     * [151]Minimal Boot Loader for Intel® Architecture
     * [152]Minimal Boot Loader in Assembler with comments
     * [153]8086
     * [154]80386
     * [155]Reset vector
     * [156]Real mode
     * [157]Linux kernel boot protocol
     * [158]coreboot developer manual
     * [159]Ralf Brown's Interrupt List
     * [160]Power supply
     * [161]Power good signal

results matching ""

No results matching ""

References

   Visible links:
   1. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
   2. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/
   3. https://archive.org/includes/donate.php?as_page=1&platform=wb&referer=https%3A//web.archive.org/web/20230308144716/https%3A//0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
   4. https://web.archive.org/web/
   5. https://web.archive.org/web/20230308144716*/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
   6. https://web.archive.org/web/20230125232251/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
   7. https://web.archive.org/web/20230221231350/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
   8. https://web.archive.org/web/20230322150040/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
   9. https://web.archive.org/web/20220120153936/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
  10. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html#expand
  11. https://archive.org/details/mega-002
  12. https://web.archive.org/web/20230308144716/https://legacy.gitbook.com/book/0xax/linux-insides
  13. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/
  14. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/
  15. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
  16. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
  17. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-3.html
  18. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-4.html
  19. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-5.html
  20. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-6.html
  21. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Initialization/
  22. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-1.html
  23. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-2.html
  24. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-3.html
  25. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-4.html
  26. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-5.html
  27. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-6.html
  28. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-7.html
  29. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-8.html
  30. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-9.html
  31. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-10.html
  32. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Interrupts/
  33. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-1.html
  34. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-2.html
  35. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-3.html
  36. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-4.html
  37. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-5.html
  38. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-6.html
  39. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-7.html
  40. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-8.html
  41. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-9.html
  42. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-10.html
  43. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/SysCall/
  44. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-1.html
  45. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-2.html
  46. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-3.html
  47. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-4.html
  48. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-5.html
  49. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-6.html
  50. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Timers/
  51. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-1.html
  52. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-2.html
  53. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-3.html
  54. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-4.html
  55. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-5.html
  56. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-6.html
  57. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-7.html
  58. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/
  59. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-1.html
  60. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-2.html
  61. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-3.html
  62. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-4.html
  63. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-5.html
  64. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-6.html
  65. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/MM/
  66. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/MM/linux-mm-1.html
  67. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/MM/linux-mm-2.html
  68. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/MM/linux-mm-3.html
  69. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Cgroups/
  70. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Cgroups/linux-cgroups-1.html
  71. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Concepts/
  72. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html
  73. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html
  74. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-3.html
  75. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-4.html
  76. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/DataStructures/
  77. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-1.html
  78. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-2.html
  79. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-3.html
  80. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Theory/
  81. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-1.html
  82. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-2.html
  83. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-3.html
  84. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Misc/
  85. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Misc/linux-misc-1.html
  86. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Misc/linux-misc-2.html
  87. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Misc/linux-misc-3.html
  88. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Misc/linux-misc-4.html
  89. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/KernelStructures/
  90. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/KernelStructures/linux-kernelstructure-1.html
  91. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/LINKS.html
  92. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/contributors.html
  93. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/
  94. https://web.archive.org/web/20230308144716/https://0xax.github.io/categories/assembler/
  95. https://web.archive.org/web/20230308144716/https://twitter.com/0xAX
  96. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/anotherworldofworld@gmail.com
  97. https://web.archive.org/web/20230308144716/https://github.com/0xAX/linux-insides/issues/new
  98. https://web.archive.org/web/20230308144716/https://github.com/0xAX/linux-insides
  99. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Power_supply
 100. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Power_good_signal
 101. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Intel_80386
 102. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Real_mode
 103. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Memory_segmentation
 104. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Intel_8086
 105. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Memory_segmentation
 106. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/A20_line
 107. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Reset_vector
 108. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/JMP_%28x86_instruction%29
 109. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/BIOS
 110. https://web.archive.org/web/20230308144716/https://www.coreboot.org/
 111. https://web.archive.org/web/20230308144716/http://ref.x86asm.net/coder32.html#xE9
 112. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Master_boot_record
 113. https://web.archive.org/web/20230308144716/https://www.qemu.org/
 114. https://web.archive.org/web/20230308144716/http://www.ctyme.com/intr/rb-0106.htm
 115. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Intel_8086
 116. https://web.archive.org/web/20230308144716/https://www.coreboot.org/Developer_Manual/Memory_map
 117. https://web.archive.org/web/20230308144716/https://www.gnu.org/software/grub/
 118. https://web.archive.org/web/20230308144716/http://www.syslinux.org/wiki/index.php/The_Syslinux_Project
 119. https://web.archive.org/web/20230308144716/https://github.com/torvalds/linux/blob/v4.16/Documentation/x86/boot.txt
 120. https://web.archive.org/web/20230308144716/http://git.savannah.gnu.org/gitweb/?p=grub.git;a=blob;f=grub-core/boot/i386/pc/boot.S;hb=HEAD
 121. https://web.archive.org/web/20230308144716/http://git.savannah.gnu.org/gitweb/?p=grub.git;a=blob;f=grub-core/boot/i386/pc/diskboot.S;hb=HEAD
 122. https://web.archive.org/web/20230308144716/http://git.savannah.gnu.org/gitweb/?p=grub.git;a=blob;f=grub-core/kern/main.c
 123. https://web.archive.org/web/20230308144716/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/setup.ld
 124. https://web.archive.org/web/20230308144716/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/header.S
 125. https://web.archive.org/web/20230308144716/https://github.com/torvalds/linux/blob/v4.16/Documentation/x86/boot.txt#L354
 126. https://web.archive.org/web/20230308144716/https://github.com/torvalds/linux/blob/v4.16/Documentation/x86/boot.txt#L156
 127. https://web.archive.org/web/20230308144716/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/header.S
 128. https://web.archive.org/web/20230308144716/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/header.S#L292
 129. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/DOS_MZ_executable
 130. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Portable_Executable
 131. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface
 132. https://web.archive.org/web/20230308144716/https://github.com/torvalds/linux/blob/v4.16/Documentation/x86/boot.txt#L156
 133. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/.bss
 134. https://web.archive.org/web/20230308144716/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/main.c
 135. https://web.archive.org/web/20230308144716/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/header.S#L46
 136. https://web.archive.org/web/20230308144716/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/header.S#L602
 137. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Program_counter
 138. https://web.archive.org/web/20230308144716/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/header.S#L575
 139. https://web.archive.org/web/20230308144716/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/header.S#L589
 140. https://web.archive.org/web/20230308144716/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/setup.ld
 141. https://web.archive.org/web/20230308144716/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/header.S#L320
 142. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/.bss
 143. https://web.archive.org/web/20230308144716/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/setup.ld
 144. https://web.archive.org/web/20230308144716/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/setup.ld
 145. https://web.archive.org/web/20230308144716/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/main.c
 146. https://web.archive.org/web/20230308144716/https://twitter.com/0xAX
 147. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/anotherworldofworld@gmail.com
 148. https://web.archive.org/web/20230308144716/https://github.com/0xAX/linux-internals/issues/new
 149. https://web.archive.org/web/20230308144716/https://github.com/0xAX/linux-internals
 150. https://web.archive.org/web/20230308144716/http://css.csail.mit.edu/6.858/2014/readings/i386.pdf
 151. https://web.archive.org/web/20230308144716/https://www.cs.cmu.edu/~410/doc/minimal_boot.pdf
 152. https://web.archive.org/web/20230308144716/https://github.com/Stefan20162016/linux-insides-code/blob/master/bootloader.asm
 153. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Intel_8086
 154. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Intel_80386
 155. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Reset_vector
 156. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Real_mode
 157. https://web.archive.org/web/20230308144716/https://www.kernel.org/doc/Documentation/x86/boot.txt
 158. https://web.archive.org/web/20230308144716/https://www.coreboot.org/Developer_Manual
 159. https://web.archive.org/web/20230308144716/http://www.ctyme.com/intr/int.htm
 160. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Power_supply
 161. https://web.archive.org/web/20230308144716/https://en.wikipedia.org/wiki/Power_good_signal

   Hidden links:
 163. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
 164. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
 165. https://archive.org/account/login.php
 166. http://faq.web.archive.org/
 167. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html#close
 168. https://web.archive.org/web/20230308144716/http://web.archive.org/screenshot/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
 169. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
 170. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
 171. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
 172. https://web.archive.org/web/20230308144716/https://www.gitbook.com/?utm_source=public_site_legacy&utm_medium=referral&utm_campaign=trademark&utm_term=0xax&utm_content=powered_by
 173. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/
 174. https://web.archive.org/web/20230308144716/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html