summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2023-04-10 14:58:46 +0200
committerAndreas Baumann <mail@andreasbaumann.cc>2023-04-10 14:58:46 +0200
commit7a51b6745d785f0a003a81c4d1fb819620224154 (patch)
tree112997084eed5450ae323ae313120740861367e7
downloaduflbbl-7a51b6745d785f0a003a81c4d1fb819620224154.tar.gz
uflbbl-7a51b6745d785f0a003a81c4d1fb819620224154.tar.bz2
first standalone version
-rw-r--r--README482
-rw-r--r--doc/www.os2museum.com_wp_a-brief-history-of-unreal-mode.txt1626
-rw-r--r--src/boot.asm1408
-rw-r--r--src/lstar.c102
-rwxr-xr-xtests/run_qemu.sh7
-rw-r--r--tests/test_a20.asm61
-rw-r--r--tests/test_unreal.asm49
-rw-r--r--todo/doc/0xax.gitbooks.io_linux-insides_content_Booting_linux-bootstrap-1.txt897
-rw-r--r--todo/doc/0xax.gitbooks.io_linux-insides_content_Booting_linux-bootstrap-2.txt937
-rw-r--r--todo/doc/dc0d32.blogspot.com_2010_06_real-mode-in-c-with-gcc-writing.txt892
-rw-r--r--todo/doc/fossbytes_com_redditor-boots-linux-kernel-5-8-0-rc2-floppy-intel-80486.txt339
-rw-r--r--todo/doc/people.freedesktop.org_~narmstrong_meson_drm_doc_admin-guide_initrd.txt453
-rw-r--r--todo/doc/www.kernel.org_doc_html_latest_x86_boot.txt2349
-rw-r--r--todo/doc/www.kernel.org_doc_html_latest_x86_zero-page.txt424
14 files changed, 10026 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..115f768
--- /dev/null
+++ b/README
@@ -0,0 +1,482 @@
+uflbbl - USTAR Floppy Linux BIOS Boot Loader
+--------------------------------------------
+
+For old BIOS based booting, loading a set of floppies which contain
+the kernel, the ramdisk, etc. in USTAR format. It can only load
+Linux kernels and ramdisks currently. And though it might be able
+to boot a AMD64 kernel this is not the primary focus. It is there
+to boot on old IA-32 based machines which have an original floppy
+drive.
+
+The filenames recognized are:
+- 'bzImage': the Linux kernel
+- 'ramdisk.img': the initial ramdisk
+- 'EOF': an empty file indicating the end of the tar file
+
+Customization of boot parameters must be done in source currently
+in 'KERNEL_CMD_LINE' in 'boot.asm'.
+
+You can also change the greeting mesage in varialble 'MESSAGE_GREETING'
+in 'boot.asm' to your likeing.
+
+An example boot sequence looks as follows:
+
+Booting from Floppy...
+UFLBB loading...
+Checking A20 address gate.. + enabled
+Switching to unreadl mode.. enabled
+Boot parameters 0x00 0x04 0x02 0x13
+ bzImage 00004727760 0013AFF0!
+Number of real-mode kernel sectors: 1D
+Number of protected-mode kernel sectors: 09BA
+Linux boot protocol version: 02.0F
+Linux kernel version: 6.2.10 (user@machine) #1 Mon Apr 10 11:33:20 CET 2023
+ ramdisk.img 00012114554 0028996C!
+Insert next floppy and press any key to continue..
+Insert next floppy and press any key to continue..
+Insert next floppy and press any key to continue..
+ EOF 00000000000 00000000
+Reached end of tar file..
+Ramdisk address: 008000000
+Ramdisk size: 0028996C
+Booting kernel..
+early console in setup code
+early console in extract_kernel
+input_data: 0x01328079
+input_len: 0x00132e1c
+output: 0x01000000
+output_len: 0x0032ce60
+kernel_total_size: 0x00472000
+needed_size: 0x00472000
+Decompressing Linux...
+...
+
+requirements
+------------
+
+nasm
+
+how to build a set of bootable floppies
+---------------------------------------
+
+Create a 'bzImage' kernel and an initial ramdisk 'ramdisk.img'.
+
+Assemble 'boot.asm', put it to start of 'floppy.img', tar the kernel,
+the 'ramdisk.img' and the 'EOF' file into a 'data.tar' file, concatenate
+the boot loader file 'boot.img' and the 'data.tar' file, then
+split into floppy size (assuming you have 3 1/4" 1.44MB floppies).
+
+nasm -o boot.img boot.asm
+touch EOF
+tar -cvf data.tar -b1 bzImage ramdisk.img EOF
+cat boot.img data.tar > floppy.img
+./lstar floppy.img
+split -d -b 1474560 floppy.img floppy
+dd if=floppy00 of=/dev/fd0 bs=512
+dd if=floppy01 of=/dev/fd0 bs=512
+..
+
+Boot the floppies in order, insert next floppy if asked by the boot
+loader.
+
+'lstar' is a small convenience program to list the entries in the tar
+(of course also 'tar xvf' works for this).
+
+gcc -lbsd -o lstar src/lstar.c
+./lstar floppy.img
+
+testing
+-------
+
+tests/run_qemu.sh
+
+when asked to change the floppy change to the Qemu console and
+type 'change floppy0 floppy01' (same for all other floppies).
+
+floppy format
+-------------
+
+512 bytes MBR stage 1 simple boot loader and magic boot string
+ loads stage 2 directly following stage 1, also assumes
+ stage 2 fits on one track of the floppy, so we don't
+ need a complicated loading method probing tracks per sector
+1024 bytes stage 2 boot loader, interprets tar format one sector after
+ stage 2 and reads files into memory (vmlinuz, ramdisk.img)
+N tar file format (no compression, we expect the files to
+ be well compressed). 2 blocks .ustar format, file names
+ are easy accessible (vmlinuz, ramdisk.img). We sacrifice 512
+ bytes for easier reading in multiple disks (for instance
+ a kernel disk, an initial ramdisk, a driver disk for
+ SCSI, a root file system, etc.), we could even do multi-floppy
+ kernels, so we can read the kernel distributed on more than
+ one floppy.
+
+ustar/tar format
+----------------
+
+offset length description example
+byte 0 100 filename in ascii, zero-term string "bzImage"
+byte 0x7c (124) 12 length in octal, zero-term string "00004014360"
+byte 0x94 (148) 8 checksum in octal, zero-term string "012757"
+ with an ending space for some reason
+ sum the header bytes with the checksum
+ bytes as spaces (0x20)
+byte 0x101 (257) 6 UStar indicator, zero-term string "ustar"
+ one of the easiest ways to detect
+ a tar header sector
+
+ramdisk
+-------
+
+find . | cpio -H newc -o -R root:root | xz --check=crc32 > ../ramdisk.img
+
+memory layout
+-------------
+
+0x07c00 - 0x08fff boot loader
+0x09000 - 0x091ff floppy read buffer
+0x0e000 - 0x09200 stack of real mode kernel
+0x10000 - 0x101ff Linux zero page (first part)
+0x10200 - 0x103ff zero page (part two), real mode entry point at 0x10200
+0x10400 - xxx continue code of real mode kernel
+0x1e000 - 0xe0ff cmd line for kernel
+0x100000 - xxx protected mode kernel code (at 1 MB)
+0x800000 - xxx ram disk (at 8 MB)
+
+state machine
+-------------
+
+tar state machine: reading metadata, reading data, we know
+whether we are in the kernel, ramdisk, etc.
+kernel substates:
+- sector 1: read number of real mode sectors
+- sector 2: read and check params, set params
+- sector >2: always read and copy data from floppy to destination area
+
+error codes
+-----------
+
+error codes consist of a error class (DISK, KERN) and a code
+
+ERR DISK 0x01 stage 1 read error while reading stage 2
+ERR DISK 0x02 stage 1 short read error (we didn't read as many stage 2
+ sectors as expected)
+ERR DISK 0x03 reading and interpreting tar state machine error
+ERR DISK 0xXX other read errors (BIOS int 0x13 codes), stage 2
+ERR A20 0x01 A20 address line not enabled
+ERR KERN 0x01 kernel read state machine error
+ERR KERN 0x02 kernel signature 'HdrS' not found
+ERR KERN 0x03 kernel boot protocol too old
+ERR KERN 0x04 kernel cannot be started (or better, we return from the
+ real mode jump)
+
+Linux IA-32 boot sequence
+-------------------------
+
+- load Kernel boot sector at 0x10000 (first 512 bytes)
+- read 0x10000+0x1f1 number of sectors
+ => minimal 4 sectors (if 0 is in 1f1), number of setup sectors
+- read 0x10200 (second part of the zero page)
+- compare 0x10202 to linux header 'HdrS', must be equal
+- compare 0x10206 to linux boot protocol version, don't allow anything
+ below 0x215 (the newest one) for now
+- set various zero page data
+ - test for KASLR enabled
+ 0x10211 has bit 1 set?
+ (this we might not want to do for old i486 kernels and systems)
+ - set 0xFF for non-registered boot loader in 0x10210
+ - set 0x80 in loadflags 0x10211
+ - CAN_USE_HEAP (bit 7)
+ - LOADED_HIGH? where do we load protected mode code?
+ - set head_end_ptr 0x10224 to 0xde00
+ ; heap_end = 0xe000
+ ; heap_end_ptr = heap_end - 0x200 = 0xde00
+ mov word [es:0x224], 0xde00 ;head_end_ptr
+ "Set this field to the offset (from the beginning of the real-mode
+ code) of the end of the setup stack/heap, minus 0x0200."
+ - set 0x10228 to 0x1e000
+ set to mov dword [es:0x228], 0x1e000 ;cmd line ptr
+ mov dword [es:0x228], 0x1e000 ; set cmd_line_ptr
+ also copy your command line to 0x1e000, for now from the boot loader
+ data segment (initialized data) area.
+ At offset 0x0020 (word), “cmd_line_magic”, enter the magic number 0xA33F.
+ At offset 0x0022 (word), “cmd_line_offset”, enter the offset of the kernel command line (relative to the start of the real-mode kernel).
+ The kernel command line must be within the memory region covered by setup_move_size, so you may need to adjust this field.
+- read to 0x10400 N-1 sectors (as much as we calculated above) as the
+ real mode kernel part
+- 0x1001f4 is the 16-byte paragraphs of 32-bit code for protected mode
+ kernel to load -> transform to 512 byte sectors to read
+- eventually get the prefered loading location for the kernel
+- load the protected part to 0x100000 by loading it to low memory and
+ copy it to high memory in unreal mode
+- print kernel version number, 020E, offset, but we must load the complete
+ kernel first
+- at end of kernel PM code read check if we have the same size as the tar
+ entry
+- run_kernel (real mode)
+ cli
+ mov ax, 0x1000
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+ mov sp, 0xe000
+ jmp 0x1020:0
+- eventually get the prefered loading location for the ramdisk
+ or highest possible location (should make the kernel happy), but
+ then we have to know a little bit about the memory layout and size of
+ the machine..
+- read ram image
+ - read octal size in tar metadata of ramdisk, convert do decimal
+ - set address and size in kernel zero page
+ - 0x218/4 ramdisk image address
+ - 0x21c/4 ramdisk image size
+
+Bochs commands
+--------------
+
+# have a look at the boot.map file for the address of a symbol
+# set breakpoint
+b 0x7F93
+
+# dump memory in floppy read buffer
+x /30b 0x0008800
+
+# dump real mode kernel code/data
+x /30b 0x0010000
+
+interrupts
+----------
+
+Relevant interrupts as documented in http://www.cs.cmu.edu/~ralf/files.html:
+
+--------B-1302-------------------------------
+INT 13 - DISK - READ SECTOR(S) INTO MEMORY
+ AH = 02h
+ AL = number of sectors to read (must be nonzero)
+ CH = low eight bits of cylinder number
+ CL = sector number 1-63 (bits 0-5)
+ high two bits of cylinder (bits 6-7, hard disk only)
+ DH = head number
+ DL = drive number (bit 7 set for hard disk)
+ ES:BX -> data buffer
+Return: CF set on error
+ if AH = 11h (corrected ECC error), AL = burst length
+ CF clear if successful
+ AH = status (see #00234)
+ AL = number of sectors transferred (only valid if CF set for some
+ BIOSes)
+Notes: errors on a floppy may be due to the motor failing to spin up quickly
+ enough; the read should be retried at least three times, resetting
+ the disk with AH=00h between attempts
+ most BIOSes support "multitrack" reads, where the value in AL
+ exceeds the number of sectors remaining on the track, in which
+ case any additional sectors are read beginning at sector 1 on
+ the following head in the same cylinder; the MSDOS CONFIG.SYS command
+ MULTITRACK (or the Novell DOS DEBLOCK=) can be used to force DOS to
+ split disk accesses which would wrap across a track boundary into two
+ separate calls
+ the IBM AT BIOS and many other BIOSes use only the low four bits of
+ DH (head number) since the WD-1003 controller which is the standard
+ AT controller (and the controller that IDE emulates) only supports
+ 16 heads
+ AWARD AT BIOS and AMI 386sx BIOS have been extended to handle more
+ than 1024 cylinders by placing bits 10 and 11 of the cylinder number
+ into bits 6 and 7 of DH
+ under Windows95, a volume must be locked (see INT 21/AX=440Dh/CX=084Bh)
+ in order to perform direct accesses such as INT 13h reads and writes
+ all versions of MS-DOS (including MS-DOS 7 [Windows 95]) have a bug
+ which prevents booting on hard disks with 256 heads (FFh), so many
+ modern BIOSes provide mappings with at most 255 (FEh) heads
+ some cache drivers flush their buffers when detecting that DOS is
+ bypassed by directly issuing INT 13h from applications. A dummy
+ read can be used as one of several methods to force cache
+ flushing for unknown caches (e.g. before rebooting).
+BUGS: When reading from floppies, some AMI BIOSes (around 1990-1991) trash
+ the byte following the data buffer, if it is not arranged to an even
+ memory boundary. A workaround is to either make the buffer word
+ aligned (which may also help to speed up things), or to add a dummy
+ byte after the buffer.
+ MS-DOS may leave interrupts disabled on return from this function.
+ Apparently some BIOSes or intercepting resident software have bugs
+ that may destroy DX on return or not properly set the Carry flag.
+ At least some Microsoft software frames calls to this function with
+ PUSH DX, STC, INT 13h, STI, POP DX.
+ on the original IBM AT BIOS (1984/01/10) this function does not disable
+ interrupts for harddisks (DL >= 80h). On these machines the MS-DOS/
+ PC DOS IO.SYS/IBMBIO.COM installs a special filter to bypass the
+ buggy code in the ROM (see CALL F000h:211Eh)
+SeeAlso: AH=03h,AH=0Ah,AH=06h"V10DISK.SYS",AH=21h"PS/1",AH=42h"IBM"
+SeeAlso: INT 21/AX=440Dh/CX=084Bh,INT 4D/AH=02h
+
+--------B-1300-------------------------------
+INT 13 - DISK - RESET DISK SYSTEM
+ AH = 00h
+ DL = drive (if bit 7 is set both hard disks and floppy disks reset)
+Return: AH = status (see #00234)
+ CF clear if successful (returned AH=00h)
+ CF set on error
+Note: forces controller to recalibrate drive heads (seek to track 0)
+ for PS/2 35SX, 35LS, 40SX and L40SX, as well as many other systems,
+ both the master drive and the slave drive respond to the Reset
+ function that is issued to either drive
+SeeAlso: AH=0Dh,AH=11h,INT 21/AH=0Dh,INT 4D/AH=00h"TI Professional"
+SeeAlso: INT 56"Tandy 2000",MEM 0040h:003Eh
+
+--------B-1308-------------------------------
+INT 13 - DISK - GET DRIVE PARAMETERS (PC,XT286,CONV,PS,ESDI,SCSI)
+ AH = 08h
+ DL = drive (bit 7 set for hard disk)
+ ES:DI = 0000h:0000h to guard against BIOS bugs
+Return: CF set on error
+ AH = status (07h) (see #00234)
+ CF clear if successful
+ AH = 00h
+ AL = 00h on at least some BIOSes
+ BL = drive type (AT/PS2 floppies only) (see #00242)
+ CH = low eight bits of maximum cylinder number
+ CL = maximum sector number (bits 5-0)
+ high two bits of maximum cylinder number (bits 7-6)
+ DH = maximum head number
+ DL = number of drives
+ ES:DI -> drive parameter table (floppies only)
+Notes: may return successful even though specified drive is greater than the
+ number of attached drives of that type (floppy/hard); check DL to
+ ensure validity
+ for systems predating the IBM AT, this call is only valid for hard
+ disks, as it is implemented by the hard disk BIOS rather than the
+ ROM BIOS
+ the IBM ROM-BIOS returns the total number of hard disks attached
+ to the system regardless of whether DL >= 80h on entry.
+ Toshiba laptops with HardRAM return DL=02h when called with DL=80h,
+ but fail on DL=81h. The BIOS data at 40h:75h correctly reports 01h.
+ may indicate only two drives present even if more are attached; to
+ ensure a correct count, one can use AH=15h to scan through possible
+ drives
+ Reportedly some Compaq BIOSes with more than one hard disk controller
+ return only the number of drives DL attached to the corresponding
+ controller as specified by the DL value on entry. However, on
+ Compaq machines with "COMPAQ" signature at F000h:FFEAh,
+ MS-DOS/PC DOS IO.SYS/IBMBIO.COM call INT 15/AX=E400h and
+ INT 15/AX=E480h to enable Compaq "mode 2" before retrieving the count
+ of hard disks installed in the system (DL) from this function.
+ the maximum cylinder number reported in CX is usually two less than
+ the total cylinder count reported in the fixed disk parameter table
+ (see INT 41h,INT 46h) because early hard disks used the last cylinder
+ for testing purposes; however, on some Zenith machines, the maximum
+ cylinder number reportedly is three less than the count in the fixed
+ disk parameter table.
+ for BIOSes which reserve the last cylinder for testing purposes, the
+ cylinder count is automatically decremented
+ on PS/1s with IBM ROM DOS 4, nonexistent drives return CF clear,
+ BX=CX=0000h, and ES:DI = 0000h:0000h
+ machines with lost CMOS memory may return invalid data for floppy
+ drives. In this situation CF is cleared, but AX,BX,CX,DX,DH,DI,
+ and ES contain only 0. At least under some circumstances, MS-DOS/
+ PC DOS IO.SYS/IBMBIO.COM just assumes a 360 KB floppy if it sees
+ CH to be zero for a floppy.
+ the PC-Tools PCFORMAT program requires that AL=00h before it will
+ proceed with the formatting
+ if this function fails, an alternative way to retrieve the number
+ of floppy drives installed in the system is to call INT 11h.
+ In fact, the MS-DOS/PC-DOS IO.SYS/IBMBIO.COM attempts to get the
+ number of floppy drives installed from INT 13/AH=08h, when INT 11h
+ AX bit 0 indicates there are no floppy drives installed. In addition
+ to testing the CF flag, it only trusts the result when the number of
+ sectors (CL preset to zero) is non-zero after the call.
+BUGS: several different Compaq BIOSes incorrectly report high-numbered
+ drives (such as 90h, B0h, D0h, and F0h) as present, giving them the
+ same geometry as drive 80h; as a workaround, scan through disk
+ numbers, stopping as soon as the number of valid drives encountered
+ equals the value in 0040h:0075h
+ a bug in Leading Edge 8088 BIOS 3.10 causes the DI,SI,BP,DS, and ES
+ registers to be destroyed
+ some Toshiba BIOSes (at least before 1995, maybe some laptops???
+ with 1.44 MB floppies) have a bug where they do not set the ES:DI
+ vector even for floppy drives. Hence these registers should be
+ preset with zero before the call and checked to be non-zero on
+ return before using them. Also it seems these BIOSes can return
+ wrong info in BL and CX, as S/DOS 1.0 can be configured to preset
+ these registers as for an 1.44 MB floppy.
+ the PS/2 Model 30 fails to reset the bus after INT 13/AH=08h and
+ INT 13/AH=15h. A workaround is to monitor for these functions
+ and perform a transparent INT 13/AH=01h status read afterwards.
+ This will reset the bus. The MS-DOS 6.0 IO.SYS takes care of
+ this by installing a special INT 13h interceptor for this purpose.
+ AD-DOS may leave interrupts disabled on return from this function.
+ Some Microsoft software explicitly sets STI after return.
+SeeAlso: AH=06h"Adaptec",AH=13h"SyQuest",AH=48h,AH=15h,INT 1E
+SeeAlso: INT 41"HARD DISK 0"
+
+(Table 00242)
+Values for diskette drive type:
+ 01h 360K
+ 02h 1.2M
+ 03h 720K
+ 04h 1.44M
+ 05h ??? (reportedly an obscure drive type shipped on some IBM machines)
+ 2.88M on some machines (at least AMI 486 BIOS)
+ 06h 2.88M
+ 10h ATAPI Removable Media Device
+--------d-1308-------------------------------
+INT 13 - V10DISK.SYS - SET FORMAT
+ AH = 08h
+ AL = number of sectors
+ CH = cylinder number (bits 8,9 in high bits of CL)
+ CL = sector number
+ DH = head
+ DL = drive
+Return: AH = status code (see #00234)
+Program: V10DISK.SYS is a driver for the Flagstaff Engineering 8" floppies
+Note: details not available
+SeeAlso: AH=03h,AH=06h"V10DISK.SYS"
+
+references
+----------
+
+- kernel boot up in all it's details, really nice documentation:
+ - https://www.kernel.org/doc/html/latest/x86/boot.html
+ - https://www.kernel.org/doc/html/latest/x86/zero-page.html
+ - https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
+ - https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+- debug kernel with bochs
+ - https://bochs.sourceforge.io/doc/docbook/user/debugging-with-gdb.html
+ - https://www.kernel.org/doc/html/v4.12/dev-tools/gdb-kernel-debugging.html
+ - https://www.cs.princeton.edu/courses/archive/fall09/cos318/precepts/bochs_gdb.html
+- interrupt list and BIOS documentation
+ - http://www.cs.cmu.edu/~ralf/files.html
+ - https://members.tripod.com/vitaly_filatov/ng/asm/
+- Linux boot protocol
+ - https://docs.kernel.org/x86/boot.html
+ - https://www.spinics.net/lists/linux-integrity/msg14580.html: version string
+- get available memory
+ - http://www.uruk.org/orig-grub/mem64mb.html
+ - https://wiki.osdev.org/Detecting_Memory_(x86)
+- create ramdisk.img:
+ https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html
+- tar format
+ - https://wiki.osdev.org/USTAR
+ - https://en.wikipedia.org/wiki/Tar_(computing)#UStar_format
+ - https://github.com/calccrypto/tar
+ - https://github.com/Papierkorb/tarfs
+- other minimal bootloader projects
+ - https://github.com/wikkyk/mlb
+ - https://github.com/owenson/tiny-linux-bootloader and
+ https://github.com/guineawheek/tiny-floppy-bootloader
+ - http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html (Small C and 16-bit code,
+ leads to a quite big boot loader, in the end we didn't use C but Unreal mode 16/32-bittish assembly)
+ - https://wiki.syslinux.org/wiki/index.php?title=The_Syslinux_Project
+ - Lilo (but the code is hard to read and looks quite chaotic)
+ - Linux 1.x old boot floppy code
+
+todos
+-----
+
+- have an early console also for serial (uart8250 in assembly, yuck)
+- the kernel parameters are in boot.asm hard-coded, cannot be passed
+ from outside
+- test more A20 switching stuff on real hardware
+- better detection of swapped disks (but do we want a special sector
+ with disk 2 of 5? This is much harder to create)
+- test other floppy sizes
diff --git a/doc/www.os2museum.com_wp_a-brief-history-of-unreal-mode.txt b/doc/www.os2museum.com_wp_a-brief-history-of-unreal-mode.txt
new file mode 100644
index 0000000..a02d0be
--- /dev/null
+++ b/doc/www.os2museum.com_wp_a-brief-history-of-unreal-mode.txt
@@ -0,0 +1,1626 @@
+ #[1]OS/2 Museum Feed [2]OS/2 Museum Comments Feed [3]OS/2 Museum
+ A Brief History of Unreal Mode Comments Feed [4]alternate [5]alternate
+ [6]alternate
+
+ [7]OS/2 Museum
+ OS/2, vintage PC computing, and random musings
+ [8]Skip to content
+ * [9]Home
+ * [10]About
+ + [11]Wanted List
+ * [12]OS/2 History
+ + [13]OS/2 Beginnings
+ + [14]OS/2 1.0
+ + [15]OS/2 1.1
+ + [16]OS/2 1.2 and 1.3
+ + [17]OS/2 16-bit Server
+ + [18]OS/2 2.0
+ + [19]OS/2 2.1 and 2.11
+ + [20]OS/2 Warp
+ + [21]OS/2 Warp, PowerPC Edition
+ + [22]OS/2 Warp 4
+ + [23]OS/2 Timeline
+ + [24]OS/2 Library
+ o [25]OS/2 1.x SDK
+ o [26]OS/2 1.x Programming
+ o [27]OS/2 2.0 Technical Library
+ + [28]OS/2 Videos, 1987
+ * [29]DOS History
+ + [30]DOS Beginnings
+ + [31]DOS 1.0 and 1.1
+ + [32]DOS 2.0 and 2.1
+ + [33]DOS 3.0, 3.1, and 3.2
+ + [34]DOS 3.3
+ + [35]DOS 4.0
+ + [36]DOS Library
+ * [37]NetWare History
+ + [38]NetWare Timeline
+ + [39]NetWare Library
+ * [40]Windows History
+ + [41]Windows Library
+ * [42]PC UNIX History
+ + [43]Solaris 2.1 for x86
+
+ [44]<- USB 0.9
+ [45]ANOMALY: meaningless REX prefix used ->
+
+A Brief History of Unreal Mode
+
+ Posted on [46]June 15, 2018 by [47]Michal Necasek
+
+ After a run-in with a particularly crazy manifestation of unreal mode
+ (Flat Assembler, or [48]fasm), I decided to dig deeper into the history
+ of this undocumented yet very widely used feature of 32-bit x86
+ processors.
+
+ For the purposes of this discussion, unreal mode is a variant of the
+ x86 real mode with non-standard segment limits and/or attributes,
+ different from the processor state at reset. To recap, real mode on the
+ 286 and later CPUs has much more in common with protected mode than
+ with the real (and only) mode of the 8086. Notably, undefined opcodes
+ raise exceptions, segment limit overruns cause general protection or
+ stack faults, and (on the 386 and later) 32-bit registers and 32-bit
+ addressing can be used--subject to limit checks.
+
+ The origins of unreal mode are shrouded in the mists of time. But
+ enough is known that certain outlines are quite clearly defined. Let's
+ present a rough timeline of unreal mode.
+ * 1985--the Intel 386 became available in silicon. Like the 286, the
+ 386 was not designed to switch from protected back to real mode.
+ Intel's idea was presumably that users should either leave the 386
+ in real mode, reset the CPU to get back to it (like a 286), or use
+ the 386's new V86 mode. This may sound like a crazy claim, but it's
+ not. In the October 15, 1991 issue of PC Magazine, page 436
+ ("Stepping Up"), Jeff Prosise [49]wrote quite clearly: "The very
+ first 80386 chips that rolled off the line (A-step chips) could not
+ be switched from protected to real mode." Indeed the confidential
+ Intel iAPX 386 Architecture Specification, revision 1.8 from June
+ 1985, had only this to say on the subject of switching from
+ protected back to real mode: "Disabling protection by loading a 0
+ into the PE bit in CR0 (assuming the current value is 1) will have
+ unpredictable effects." In other words, the original 386 design
+ tracked the 286: in real mode, segment limits and attributes retain
+ their initial reset values and cannot be changed.
+ * 1985?--someone or someones (Microsoft? Compaq?) convinced Intel to
+ relent and allow switching from protected to real mode by clearing
+ the PE bit in control register CR0; this was no doubt inspired by
+ the headaches the 286 was causing. It is unclear if there was
+ actual silicon change or only a documentation change. While a
+ transition to V86 mode always carefully loads all segment
+ registers, making any funny business impossible, the act of
+ clearing the PE bit in CR0 does almost nothing. It affects future
+ segment register loads in real mode, it affects interrupt and
+ exception dispatching, but it has near zero impact on the immediate
+ CPU state. Crucially, it does not change the current segment limits
+ or attributes, which allows the currently executing code to
+ continue running. Note that the I/O Permission Bitmap (applicable
+ in protected mode) was an even later addition to the 386 design.
+ * October 1985--The 386 datasheet (80386 High Performance
+ Microprocessor with Integrated Memory Management, Intel order no.
+ 231630-001), says in section 2.3.5: "In Real Address Mode, only the
+ base address is updated directly (by shifting the selector value
+ four bits to the left) [when loading segment registers], since the
+ segment maximum limit and attributes are fixed in Real Mode." In
+ section 2.3.4, the document says: "In Real Address Mode, the
+ maximum segment size is fixed at 64 Kbytes." In other words, this
+ document both explains why unreal mode works and claims that it
+ does not exist. The datasheet also declares in section 2.3.6 that
+ switching back to real mode is possible, but no additional detail
+ is given: "If PE [bit in CR0 register] is reset, the processor
+ operates again in Real Mode. PE may be set by loading MSW or CR0.
+ PE can be reset only by a load into CR0."
+ * January 8, 1986--Intel writes a confidential memo titled Returning
+ to real mode on the 80386. This memo explains not only how to set
+ up a canonical real-mode environment on return from real mode, but
+ also why it is necessary: "While operating in REAL mode, the 80386
+ uses exactly the same memory management functions as in protected
+ mode. However, when the part resets into real mode the values
+ loaded into the descriptors appear as if they were 8086 style
+ segments. In real mode, when a segment register is loaded, only the
+ base field is changed, in particular the value placed into the base
+ is selector*16. Since only the base is changed, it is necessary to
+ set the access rights while still in protected mode." The memo
+ proceeds to explain the required segment attribute setup,
+ information which appeared in the official 1986 PRM (Programmer's
+ Reference Manual) for the 80386. What the memo also says, and the
+ PRM does not, is that the code segment (CS) cannot be made writable
+ in protected mode, but "an architectural feature reloads real mode
+ attributes into the CS descriptor during real mode far jumps". This
+ memo explains real-mode operation of the 386 far better than the
+ official documentation, and serves unreal mode on a silver platter
+ to anyone willing to experiment even just a little.
+ * April 1986--The updated 386 datasheet, Intel order no. 231630-002,
+ offers a tantalizing hint of unreal mode in section 2.3.6:
+ "Resetting the PE bit [in CR0] is typically part of a longer
+ instruction sequence needed for proper transition from Protected
+ Mode to Real Mode." The quoted text was not present in the original
+ October 1985 edition of the datasheet, and presumably refers to the
+ information first published in the Jan '86 memo.
+ * 1986--The 1986 Intel 80386 Programmer's Reference Manual says that
+ to switch from protected to real mode, the programmer must among
+ other things transfer control to a code segment with 64K limit, and
+ load SS, DS, ES, FS, and GS segment registers with selectors that
+ have a 64K limit, are byte granular, expand-up, writable, and
+ present. Only then can CR0.PE be cleared. In other words, Intel was
+ practically begging programmers to see what happens when they don't
+ do that. The PRM publishes the how-to information from the Jan '86
+ memo, but none of the background explanation.
+ * 1987--In the 1987 edition of the 80386 System Software Writer's
+ Guide (Intel order no. 231499-001), in section 9.2 on page 9-3 (4th
+ para), Intel hints: "Because, except for base address, descriptor
+ register values cannot be loaded in real mode, 8086-compatible
+ attributes must be loaded into the data segment descriptor
+ registers before switching to real mode."
+ * January 15, 1988--Phoenix 386 BIOS with this date employs unreal
+ mode to emulate some aspects of the 286 LOADALL instruction, by
+ returning to real mode with segment bases not corresponding to the
+ segment register value. The date is tentative; this was the oldest
+ 386 BIOS using this technique available for analysis. More below.
+ * August 4, 1988--Microsoft adds 386 "Big Mode" or "Real Big Mode"
+ code to implement 386 extended memory moves in HIMEM.SYS 2.04.
+ Microsoft's method is quite clever, using an exception handler to
+ recover from anyone resetting the segment limits behind HIMEM's
+ back. Extended memory copying can thus be run with interrupts
+ enabled, with no impact on interrupt latency (that was a
+ significant problem on 286 CPUs). The term "unreal mode" is not
+ used. This change can be dated exactly, thanks to comments in
+ HIMEM.ASM. At the same time, LOADALL support was added to the HIMEM
+ 286 extended memory move.
+ * August 15, 1988--Microsoft makes an archive of the HIMEM.SYS 2.04
+ source code, with LOADALL usage removed but unreal mode code left
+ in place. It is unclear how widely this code was distributed at the
+ time. In 1992, the source archive from 1988 was published on
+ Softlib as part of [50]XMS.EXE, which contains the new XMS 3.0
+ specification. In the late 1980s and early 1990s, Microsoft
+ published the HIMEM.SYS source code together with the XMS 2.0
+ specification (the first published version was 2.01, before the
+ unreal mode code was added).
+ * February 7, 1989--Microsoft [51]publishes HIMEM.SYS version 2.06
+ source code as XMS20.ARC; unlike the previous release, this one
+ produces an exact match of the official binary, because the source
+ code includes 386 Real Big Mode and 286 LOADALL (yes, really!)
+ support.
+ * March 21, 1989--Microsoft publishes an updated HIMEM.SYS version
+ 2.06 source archive as S12023.EXE, formerly XMS20.ARC. This one
+ [52]survived to the present. Although the 1989 source code releases
+ were public, they seem to have gone more or less completely
+ unnoticed.
+ * 1989--In the 386 SX Microprocessor Programmer's Reference
+ Manual (order no. 140331-001), section 14.5 (Switching Back to
+ Real-Address Mode), Intel drops another big hint. To the paragraph
+ describing how to load segment registers when transitioning from
+ protected back to real mode, the following sentence is added: "Note
+ that if the segment registers are not reloaded, execution continues
+ using the descriptors loaded during protected mode." The same text
+ is also added to the updated 1990 edition of the 386 DX PRM, and
+ appears in the 1990 i486 PRM and all subsequent Intel programming
+ manuals.
+ * November 1989--In the November/December issue of Programmer's
+ Journal, Thomas Roden (a software engineer at AST Research, one of
+ the big PC OEMs) publishes an article titled Four Gigabytes in Real
+ Mode (page 89). This is the oldest known public description of
+ unreal mode, although the term "unreal mode" is never used. Unreal
+ mode is described, including the exception handler technique to
+ handle other code resetting the segment limits. Thanks to his
+ position at AST Research, Mr. Roden was already able to confirm
+ that unreal mode works not only on the 386DX and SX, but also on
+ the then-brand-new Intel 80486. The article mentions that it may be
+ possible to set the D-bit of the code segment to run in real mode
+ with 32-bit CS. There is no explicit mention or even a hint that
+ Mr. Roden was aware that HIMEM.SYS was already using unreal mode.
+ * January 1990--In the German c't magazine, Harald Albrecht publishes
+ an article titled Grenzenlos: Vier Gigabyte im Real Mode des 80386
+ adressieren (Boundless: Addressing four gigabytes in 80386's real
+ mode). Mr. Albrecht suggests that the 386 documentation directly
+ challenges programmers to not follow the prescribed
+ return-to-real-mode method exactly. The article is notable for
+ documenting that in real mode, a far jump partially changes CS
+ attributes, and also that after a switch to/from protected mode, a
+ near jump is sufficient to flush the prefetch queue (a far jump is
+ not necessary). Mr. Albrecht does not name the non-standard real
+ mode but presents a TSR which implements a fast INT 15h/87h block
+ move routine which uses 4GB selector limits, runs with interrupts
+ enabled, and does not disable the A20 gate when done. The author
+ incorrectly claims that (paraphrasing) no one needs the A20 gate
+ disabled, something that others learned the hard way not to be
+ true. Mr. Albrecht also notes that the segment limit extension
+ technique is unusable in V86 mode, and that 32-bit code or stack
+ segments are not practical due to corruption of the high word of
+ EIP/ESP. The article was probably written at about the same time as
+ Mr. Roden's PJ article; it may be an independent discovery,
+ although Mr. Albrecht's earlier article in the November 1989 issue
+ of c't (Odyssee im Adressraum) explicitly mentions the HIMEM.SYS
+ source code provided in Microsoft's XMS Developer's Kit.
+ * July 1990--In the July 1990 issue of Dr. Dobb's Journal, Al
+ Williams publishes an article titled DOS + 386 = 4 Gigabytes! (page
+ 62), again describing unreal mode. The article is by all
+ appearances another independent discovery of unreal mode, as there
+ are no hints Mr. Williams was aware of either HIMEM.SYS or the
+ Nov/Dec '89 PJ article. Again, the term unreal mode is not used.
+ * October 1990--In the October 1990 issue of DDJ (page 12), a reader
+ letter from Thomas Roden appears, pointing out minor problems with
+ the July '90 DDJ article about unreal mode. It is clear from the
+ letter that Mr. Roden had access to an ICE (In-Circuit Emulator),
+ which no doubt greatly eased unreal mode experimentation. An
+ editor's note identifies Mr. Roden as the author of the Nov/Dec '89
+ PJ article.
+ * January 1991--On page 176 of the 1/91 issue of German DOS
+ International magazine, an article titled Vier GByte im Real Mode
+ unter MS-DOS (Four Gigabytes in Real Mode under MS-DOS) by Martin
+ Althaus explains in detail how to change segment limits to enable
+ full 4GB addressing in real mode. The necessity of enabling the A20
+ gate is discussed, and complete example code is presented; the
+ article also notes that the technique does not work when EMM386 (or
+ V86 mode in general) is in use. The article does not explore what
+ might happen if segment attributes in real mode are changed in
+ other ways, beyond setting the G bit. The author does not claim to
+ have invented the unnamed technique, but also does not give any
+ references to earlier publications.
+ * March 1991--In Chapter 18 of Assembly Language Programming for the
+ Intel 80XXX Family, William B. Giles describes in detail (page 676
+ and following) how to program 386 real-mode selectors such that
+ they cover the entire 4GB address space. Example code is also
+ presented. The [53]code samples are dated September 4, 1990. The
+ '89 PJ article is referenced as the source of information on
+ expanding real-mode selector limits.
+ * March 1991--In Chapter 18 of DOS 5: A Developer's Guide, Al
+ Williams again describes unreal mode, with code examples. Note that
+ the exact publication date is unclear; March, August, September,
+ and October 1991 are given. A [54]1992 review of the book discusses
+ Chapter 18 in some detail, together with referencing the '90 DDJ
+ and '89 PJ articles.
+ * 1991--In 8086 Architecture & Programming Volume II: Architecture
+ Reference (page 72), Rakesh K. Agarwal (a former member of the
+ 80386 design team) clearly explains what all the official Intel
+ documentation carefully doesn't: "When [switching from protected to
+ real mode] is done, the only action taken by the 8086 is to clear
+ the PE flag. In particular, the current state of the descriptor
+ registers is left undisturbed." And further: "Such a pseudo REAL,
+ or UNREAL, execution mode can cause a REAL mode system to crash,
+ unless used very carefully" (capitalization in original). This may
+ be the first published use of the term "unreal mode".
+ * April 16, 1992--Origin releases [55]Ultima VII: The Black Gate, a
+ game using a custom DOS extender appropriately named "Voodoo".
+ Ultima VII is a proof that unreal mode is a terrible idea for DOS
+ applications; the game requires a significant amount of free
+ conventional memory, but is incompatible with 386-based DOS
+ extenders, as well as with any DOS-compatible advanced operating
+ systems.
+ * 1992--German DOS Extra Nr. 20 (supplement of the DOS International
+ magazine) publishes the HugeRealMode driver, enabling larger than
+ 64K code segments in unreal mode, with restrictions (more below).
+ * June 29, 1993--In his Tutor column starting on page 302, Jeff
+ Prosise [56]wrote a section on "accessing 4GB from real mode"
+ without using LOADALL. "Recently, another method of accessing 4GB
+ [...] was brought to my attention by a reader on PC MagNet." The
+ text gives a brief overview of unreal mode and refers to Chapter 18
+ of DOS 5: A Developer's Guide by Al Williams (also the author of
+ the 1990 DDJ article).
+ * January 1994--Chapter 8 (Extended Memory Access from Real Mode) of
+ Geoff Chappell's DOS Internals provides a very detailed description
+ of unreal mode and HIMEM's use of it. There is talk of "unreal"
+ segment properties (quotes in original, page 356), but the chapter
+ is about "real-mode Flat Memory Model", and "Big Real Mode" is also
+ gets a mention. The chapter also provides a detailed treatment of
+ 286 and 386 LOADALL. It is probably the best description of the
+ inner workings of HIMEM.SYS. Curiously, in Chapter 12 (page 443)
+ Mr. Chappell grumbles that only the outdated HIMEM.SYS 2.01 source
+ code is available on CompuServe (apparently uploaded by Steve
+ Gibson of InfoWorld). Clearly, Microsoft's 1989 and 1992 HIMEM.SYS
+ source code releases did a very good job of flying under the radar
+ when they escaped Mr. Chappell's laser-like attention.
+ * September 21, 1994--IBM files patent application 309,862 titled
+ Method for expanding addressable memory range in real-mode
+ processing to facilitate loading of large programs into high
+ memory. [57]U.S. patent 5,642,491 was granted on June 24, 1997. The
+ patent describes unreal mode, and mentions Chappell's DOS
+ Internals, pages 355-385. The patent makes strange references to a
+ "64-kbyte wrapping feature associated with true 8086 real mode";
+ that might refer to stack wrapping when PUSH and POP instruction
+ are used, but no such wrapping is used for data segments. The
+ patent suggests using unreal mode during operating system
+ initialization only, not at run-time.
+ * 1993-1995--Unreal mode becomes a thing and every up-and-coming
+ programmer writes a [58]utility or [59]library to use it. It is
+ popular among demo coders, who are dismayed when [60]EMM386 use is
+ mandated for Assembly '95, interfering with unreal mode.
+ * November 11, 1994--Italian programmer Daniele Paccaloni
+ [61]publishes UNREAL.EXE, a utility to enable unreal mode on a 386
+ or later CPU, and UNREAL.DOC, a document explaining how unreal mode
+ works. In a continuation of the recurring theme, Mr. Paccaloni
+ appears to have been completely unaware of the fact that unreal
+ mode had been in use for years, or the growing body of literature
+ about it. It appears that Mr. Paccaloni also independently
+ re-invented the term "unreal mode".
+ * September 1995--Robert R. Collins writes an article (NB: The exact
+ date is uncertain, Sep '95 is a guess based on source file
+ timestamps) titled [62]Descriptor Cache Register Anomalies; this is
+ probably the definitive description of unreal mode. Mr. Collins
+ thoroughly explored the CPU behavior using LOADALL for 386 CPUs,
+ and also using SMM together with an ICE on 486, Pentium, and
+ Pentium Pro CPUs. Mr. Collins showed that real mode is much closer
+ to protected mode than one would be led to believe, and most
+ protections are in fact in place. Mr. Collins also found that CS
+ register attributes are handled differently on different CPUs
+ generations. On older processors, far jumps change the CS
+ attributes as described in the Jan '86 memo, while newer CPUs
+ preserve the CS attributes but ignore them in real mode.
+ * February 1996--In the book Protected Mode Software
+ Architecture (chapter 5, page 61), Tom Shanley purportedly
+ describes "Big Real Mode", yet makes the ridiculous claim that
+ segment offsets are still restricted to 64K (while the segment base
+ can be set to any 32-bit address before returning to real mode).
+ Perhaps this is just shows that unreal mode is not well understood,
+ despite numerous authors' attempts to explain it.
+ * September 20, 1996--Phoenix and Intel publish the POST Memory
+ Manager Specification version 1.0 (PMM specification), which
+ mandates the use of "big real mode" (aka unreal mode). Big Real
+ Mode is not explained in detail, presumably because readers already
+ know how it works. The PMM specification is later adopted by the
+ PXE and PCI firmware 3.0 standards. Intel thus manages the
+ astonishing feat of specifying and mandating the use of unreal
+ mode, while simultaneously denying that it exists. Although the
+ original 1.0 PMM specification may be lost, the touched-up [63]PMM
+ 1.01 is available.
+ * August 1998--Dr. Dobb's Journal does not publish an article titled
+ [64]The Segment Descriptor Cache by Robert R. Collins. The article
+ says that "[u]nreal mode has been used commonly since it was
+ discovered on the 80386. Unreal mode is so commonly used, in fact,
+ that Intel has been forced to support this mode as part of legacy
+ 8086 behavior, though it's never been documented."
+ * August 2004--(This entry is only included for completeness.) In The
+ Unabridged Pentium 4, Tom Shanley correctly describes unreal mode,
+ saying that it "is sometimes referred to as Big Real Mode, Flat
+ Real Mode, Real Big Mode and UnReal Mode" (italics in original).
+ Unfortunately the author makes new, although minor, incorrect
+ claims, namely that CS:IP and SS:SP are always used in real mode,
+ precluding larger than 64K code and stack segments. Larger than 64K
+ code and stack segments are indeed in practice unusable in unreal
+ mode, but for different reasons.
+
+But... Is Unreal Mode Any Good?
+
+ Yes and no. As a general-purpose programming technique it is unusable,
+ because it absolutely cannot function in V86 mode. Transitions to V86
+ mode always force real-mode compatible segment limits and attributes.
+ That means unreal mode cannot be used together with EMM386 or other DOS
+ memory managers utilizing V86 mode. Unreal mode also cannot be used in
+ the DOS boxes of 386 Enhanced Mode Windows 3.x, in the DOS boxes of
+ OS/2 2.x, Windows NT, or Windows 9x. That is an extremely serious
+ drawback.
+
+ The reason why the Voodoo memory manager in Origin's Ultima VII games
+ is unique is that no one else wanted to repeat the same mistake. The
+ Ultima VII: The Black Isle credits capture the situation rather well:
+ Ultima VII's Voodoo Memory Management System
+
+ On the other hand, when unreal mode can be used, it is very useful.
+ HIMEM.SYS uses unreal mode to speed up extended memory access, and
+ perhaps more importantly, preserve normal interrupt latency. Firmware
+ can and does use unreal mode for accessing memory beyond 1 MB during
+ initialization; it avoids switching between real and protected mode,
+ and in firmware there is no danger of segment limits being reset.
+
+ Basic unreal mode (data segments with up to 4G limits, as well as data
+ segments with non-standard base) has become a standard part of the x86
+ architecture.
+
+Unreal LOADALL
+
+ At least as far back as January 1988, Phoenix 386 BIOS combined two
+ undocumented favorites, using unreal mode to emulate the 286 LOADALL
+ instruction. When handling an invalid opcode fault, the BIOS checks
+ whether the faulting instruction is a 286 LOADALL (opcode 0Fh 05h); if
+ so, it examines the provided LOADALL state buffer at address 800h and
+ checks whether the segment bases for ES and/or DS are 1MB or higher. If
+ so, the BIOS builds descriptors with the appropriate bases, loads them
+ in protected mode, and returns to real mode with these "unreal" values
+ in the segment descriptor cache (segment base other than 16 times
+ segment value). The segment bases will get overwritten as soon as ES or
+ DS gets reloaded in real mode, but that is entirely consistent with
+ LOADALL behavior.
+
+ The LOADALL emulation is very limited, but it is sufficient to support
+ the [65]use of LOADALL in OS/2, and possibly others.
+
+ The detailed history of this method is unclear. What's known is that
+ the first 386 BIOS, shipped with the Compaq DeskPro 386 in 1986, did
+ not use unreal mode. Compaq was clearly on good terms with Intel and
+ got the secret memo describing the 386 LOADALL instruction. The Compaq
+ 386 BIOS emulated 286 LOADALL rather accurately using the 386 LOADALL
+ instruction, going at least as far back as September 1986 and
+ continuing to use the same method at least until 1989 (it would no
+ longer work on a 486 CPU).
+
+ IBM's PS/2 Model 80 BIOS did not emulate LOADALL at all, and is
+ therefore uninteresting.
+
+ There are also known to have been more or less no-name 386 systems sold
+ around 1987 which used effectively a 286 BIOS and had no provisions to
+ emulate LOADALL, nor did they use 386 instructions at all.
+
+ It is unknown when Phoenix first introduced unreal mode usage to
+ emulate LOADALL, or if other vendors did that before Phoenix. Clone 386
+ BIOS images from before 1988 are rather difficult to find.
+
+Unreal Mode Compatibility
+
+ Basic unreal mode with extended DS, ES, FS, and/or GS segment limits is
+ widely compatible across all 32-bit x86 CPU implementations. After all
+ that's what is mandated by PMM and by extension, PXE and PCI 3.0
+ Firmware specifications, all standards created with a significant
+ involvement of Intel.
+
+ Extending data segment limits in fact causes shockingly few problems,
+ as evidenced by the fact that HIMEM.SYS does just that. On an 8086,
+ referencing a word at offset 0FFFFh causes a wrap-around and the second
+ byte is fetched from offset zero. The 286 is already incompatible with
+ this behavior, causing a #GP fault. On a 386, any attempt to address
+ beyond 64K likewise causes #GP faults, which are typically fatal.
+ Therefore, functioning software does not do it and extending the
+ segment limit has no visible impact.
+
+ Anything else gets more complicated, and interrupts are the number one
+ enemy. For example, Intel CPUs typically support non-standard data
+ segment attributes; it's possible to make DS read-only, but that won't
+ be terribly useful when running real-mode software. It is likewise
+ possible to set the segment limit smaller than 64K, but that won't make
+ 16-bit software happy.
+
+ It is possible to extend the CS limit up to 4GB and use 32-bit EIP in
+ unreal mode. In practice that is not very usable because interrupts in
+ real mode only save 16-bit IP and restore it on return. The German DOS
+ Extra magazine presented a [66]hair-raising scheme to solve the
+ problem, using the CR3 register to store the high word of EIP so that
+ it could be restored on return from interrupts, but this requires
+ software to manually keep track of the high word. In practice, larger
+ than 64K code segments are unusable in unreal mode because the
+ complications very quickly outweigh any benefits unreal mode might
+ have.
+
+ It is also possible to set the D bit in CS, changing the default
+ operand size to 32-bit. This may reduce the size of unreal code if it
+ is largely 32-bit (by obviating the need for overrides). Unfortunately,
+ this again causes serious trouble with interrupts, because existing
+ 16-bit code cannot run correctly with the D bit set. It is possible to
+ switch to protected mode, clear the D bit, and execute the 16-bit
+ handler every time an interrupt occurs, and in fact it's [67]exactly
+ what fasm does (or at least did in some versions), but with so much
+ mode switching and complexity, the advantages of unreal mode are
+ rapidly lost.
+
+ Similar trouble strikes when attempting to use larger than 64K stack
+ segments. It is possible, but again destroys compatibility with
+ existing 16-bit real-mode code. The complications are such that one
+ might as well use a regular DOS extender and skip all the unreal mode
+ incompatibilities.
+
+ A larger problem is that the "advanced" aspects of unreal mode may not
+ be implemented identically across CPU generations and vendors,
+ precisely because they have never been documented. It is not specified
+ anywhere exactly which segment attributes are ignored and which are
+ honored in real mode. Protected mode, on the other hand, works
+ consistently.
+
+What Does It All Mean?
+
+ Unreal mode is almost certainly an accident of history, a side effect
+ of the fact that the initial 386 design had no architected way of
+ switching from protected mode back to real mode. Once the technique
+ started being used, instead of clearly documenting how it works, Intel
+ in its typical fashion documented only certain aspects of it, such that
+ only programmers who already know about unreal mode find traces of it
+ in the official documentation.
+
+ On the other hand, Intel did leave enough hints in the public
+ documentation that unreal mode appears to have been independently
+ discovered a number of times. What is fascinating is that Microsoft
+ apparently implemented unreal mode support in HIMEM.SYS and made its
+ source code available before any literature on unreal mode was
+ published. Starting in late 1989, articles describing unreal mode were
+ written without knowing of each other, and likely without knowing of
+ Microsoft's prior published work. Reinventing wheels may be satisfying,
+ but in the end it's just not very productive.
+
+ PS: Images of 386 clone BIOSes (other than Compaq and IBM) from 1987
+ and earlier would be worth checking for LOADALL emulation and possible
+ other unreal mode use.
+
+ Feb 2021 Update: The original 231630-001 datasheet has now been
+ recovered and this post updated accordingly.
+ This entry was posted in [68]386, [69]Corrections, [70]Microsoft,
+ [71]PC history, [72]Undocumented. Bookmark the [73]permalink.
+ [74]<- USB 0.9
+ [75]ANOMALY: meaningless REX prefix used ->
+
+43 Responses to A Brief History of Unreal Mode
+
+ 1. [76]Neozeed says:
+ [77]June 15, 2018 at 5:38 am
+ The PCem folks are doing a good job of getting numerous 286/386
+ BIOS running on their framework, they ought to have quite a number
+ of images.
+ 2. [78]Yuhong Bao says:
+ [79]June 15, 2018 at 6:35 am
+ The fun thing is that they never changed the LMSW instruction. I
+ wonder why/
+ 3. dosfan says:
+ [80]June 15, 2018 at 8:33 am
+ Good article but why were you using fasm ? What fasm is doing
+ (32-bit real mode and relocating the IVT via LIDT) is crazy as it's
+ too much effort for too little gain and too many compatibility
+ issues. I'm not sure which is crazier, that or attempting to use
+ real mode paging on the 386 (which isn't allowed on 486 or later
+ CPUs).
+ 4. God says:
+ [81]June 15, 2018 at 1:59 pm
+ Love these sorts of "software archaeology" articles Michal - always
+ informative (and a pleasure) to read. However, something of a typo
+ jumped out at me:
+ >August 1998--Dr. Dobb's Journal does NOT publish an article titled
+ The Segment Descriptor Cache
+ 5. Michal Necasek says:
+ [82]June 15, 2018 at 7:07 pm
+ Presumably because someone was calling it in protected mode with
+ the PM bit clear, and expected to stay in protected mode...
+ 6. Michal Necasek says:
+ [83]June 15, 2018 at 7:07 pm
+ Oh, there are zillions of BIOS images out there. But 386 BIOS
+ images from 1986-87? Nada...
+ 7. Michal Necasek says:
+ [84]June 15, 2018 at 7:09 pm
+ I wasn't, I think the author is certifiably insane But someone else
+ using it made me aware of certain curious behaviors.
+ 8. Michal Necasek says:
+ [85]June 15, 2018 at 7:09 pm
+ It's not a typo. I could find no evidence that the article was ever
+ published in DDJ.
+ 9. Richard Wells says:
+ [86]June 15, 2018 at 9:18 pm
+ Early 386 BIOSes: Don Maslin's collection of ROMs includes the AMI
+ BIOS copyright 1987. I don't believe anyone has collected the
+ Phoenix BIOS used in the 1986 ALR 386 system.
+ While an interesting collection of the history, I believe you
+ overlooked one minor article. The October 1988 issue of Doctor
+ Dobbs had an article entitled "80386 PROTECTED MODE INITIALIZATION"
+ by Neal Marguiles (Intel employee). That title is a misnomer. It
+ covers the allocation of a 4 GB address space followed by a return
+ to real mode plus some other interesting concepts.
+ [87]http://www.drdobbs.com/80386-protected-mode-initialization/1844
+ 08010
+ 10. Rugxulo says:
+ [88]June 16, 2018 at 1:37 am
+ Actually, latest stable FASM seems to be 1.73.04, which silently
+ omits the unreal hack, hence you basically have to always use the
+ DPMI fallback nowadays. Not exactly sure why, he didn't (AFAIR)
+ publicly mention dropping it or why, nor whether it will come back
+ (somewhat unlikely, but he was always proud of his hack). Maybe it
+ (again) conflicted with his (Linux) 64-bit hosted version hack
+ (fasm.x64). Dunno, it's very complicated!
+ 11. dosfan says:
+ [89]June 16, 2018 at 2:17 am
+ A gross hack like that belongs in a technology demo, not production
+ software.
+ I'm not sure why anyone would bother with fasm in the first place ?
+ If you're writing assembly language code for DOS or Windows then
+ there's no reason not to use MASM which was *the* industry standard
+ or the highly MASM-compatible JWasm (or whatever its successor is).
+ 12. [90]Yuhong Bao says:
+ [91]June 18, 2018 at 2:47 am
+ Thinking about it, I wonder if reloading the real mode CS
+ attributes was the main change that allowed switching back to real
+ mode. It is unfortunate that writable code segments did not make
+ even the 80386 BTW.
+ 13. techfury90 says:
+ [92]June 18, 2018 at 3:33 am
+ Unreal mode seems to have been known to PC-98 programmers to an
+ extent as well. Oldest reference I can find is from April 1995:
+ [93]http://www.tsg.ne.jp/buho/189/tsg189.html#8086
+ Author may have discovered it independently. There may be earlier
+ examples in books and/or magazines, but I have yet to uncover them.
+ Their description of their first cited source is slightly
+ ambiguous: it's possible that they learned about unreal mode from
+ them. The stumbling block is that I cannot seem to find their name
+ for unreal mode in general. I don't think they adopted the name we
+ assigned to it, if there is even a "well-known" name.
+ 14. dosfan says:
+ [94]June 18, 2018 at 5:11 am
+ Why is it referred to as "unreal mode" anyway ? That's a foolish
+ and terrible name. Considering that it is referred to as "big real
+ mode" in an Intel doc and it involves setting the big bit in the
+ segment descriptor that should be the official name (not that it
+ really matters today). Certainly "flat real mode" is reasonable
+ alternative since you have direct access to the entire flat 4GB
+ address space.
+ 15. Richard Wells says:
+ [95]June 18, 2018 at 8:53 am
+ "Big real mode" suggests that existing code works exactly the same
+ except that the segments can be larger. "Unreal mode" showcases the
+ differences.
+ Those interested in a more intentional version of a similar concept
+ of accessing 32-bit memory for >64K allocations from 16-bit code
+ could look at 1980 Data General MV 8000 documentation especially
+ the section "MV/8000 C/350 Program Combinations" and the following
+ section "Anomolies."(sic) Some of the issues DG discovered were
+ similar to ones that programmers using Intel chip noticed a decade
+ later.
+ 16. [96]Yuhong Bao says:
+ [97]June 18, 2018 at 11:38 am
+ In this case, the only difference is that the segment limit is
+ larger, and existing real mode code do work the same.
+ 17. Michal Necasek says:
+ [98]June 18, 2018 at 3:03 pm
+ Hmm, I don't see anything about unreal mode in that article. It
+ only says that "to assure proper operation after returning to real
+ mode, the segment registers must be loaded with real mode type
+ selectors while still in protected mode", which is the official
+ Intel party line. And the sample code does exactly that.
+ I think I looked at that AMI BIOS and it's much newer than 1987.
+ It's somewhat common that the copyright message is older than the
+ BIOS date. The opposite also happens. I'm sure there had to be
+ clone BIOSes in 1986-87 but so far I've been unable to locate any.
+ 18. Michal Necasek says:
+ [99]June 18, 2018 at 3:06 pm
+ I know why, It's actually automatic. The unreal mode stuff is only
+ used if the code segment is smaller than 64K. In the newer fasm
+ versions there's more code than that, so the unreal mode code path
+ doesn't get compiled in (or at least not used). For that reason
+ it's very unlikely to come back, because using > 64K unreal mode
+ code segments brings another, much nastier layer of complications.
+ 19. Michal Necasek says:
+ [100]June 18, 2018 at 4:12 pm
+ That sounds quite plausible. It would be a silicon change, but a
+ very localized one, and only visible from switching from protected
+ back to real mode.
+ 20. Michal Necasek says:
+ [101]June 18, 2018 at 4:18 pm
+ Unreal mode because it's real mode, but not conforming to Intel's
+ definition of real mode. "Big real mode" is descriptive but it's
+ unclear whether it covers 32-bit code segments, or code or stack
+ segments with > 64K limits. Same problem with "flat real mode". I
+ suppose you could call it "not-real" mode, or "non-protected mode",
+ but "unreal mode" is really better.
+ To be clear, at least in this article, I use the term "unreal mode"
+ to mean any non-canonical real mode usage. I don't think the terms
+ "big real mode" or "flat real mode" were used to mean anything
+ other than 4G data segment limits, but there's more to unreal mode
+ than that. For example, unreal mode would cover running with
+ segment limits smaller than 64K (just because it's useless doesn't
+ mean it can't be done).
+ 21. Michal Necasek says:
+ [102]June 18, 2018 at 4:20 pm
+ "Breaking the wall", I kind of like that.
+ 22. dosfan says:
+ [103]June 18, 2018 at 8:08 pm
+ Big real mode (4GB address space) is the only thing that was ever
+ useful. Changing the default bit of the code segment would break
+ everything. If anything should be called "unreal mode" it's that
+ since it's still real mode per-se (no protections) but no regular
+ 16-bit real mode program would run properly.
+ 23. Michal Necasek says:
+ [104]June 19, 2018 at 2:02 pm
+ The other thing that was clearly useful (as in widely utilized) was
+ 64K segments with bases at or beyond 1MB. The rest is more about
+ understanding how the damn architecture actually works than about
+ having practical value.
+ 24. dosfan says:
+ [105]June 19, 2018 at 8:22 pm
+ I thought that particular trick was only done via 286 LOADALL. It
+ is of limited use since interrupts have to be disabled because once
+ the segment register is reloaded the base is changed and access
+ beyond 1MB is lost. Big real mode makes that trick impractical.
+ 25. Michal Necasek says:
+ [106]June 19, 2018 at 10:34 pm
+ 286 LOADALL... and the emulation thereof on 386s. Just about every
+ BIOS in the late 1980s and in the 1990s does that. Disabling
+ interrupts for a short time is still much better than resetting the
+ CPU, which isn't fast. Big real mode is certainly much better, but
+ doesn't emulate 286 LOADALL.
+ 26. M says:
+ [107]June 20, 2018 at 12:16 pm
+ I am wondering if the 64K wrap-around alluded to in the IBM patents
+ could be a clumsy reference to A20-behavior?
+ 27. Michal Necasek says:
+ [108]June 20, 2018 at 3:33 pm
+ That would be really clumsy, but as an explanation it makes as much
+ sense as anything
+ 28. M says:
+ [109]June 20, 2018 at 10:34 pm
+ @Michal: Yes - and it is inconsistent with what they write about
+ being compatible with only pmode and real-mode apps not relying on
+ the wrap-around etc. and the A20 wrap-around indeed does exist (and
+ would not be possible to emulate w paging in unreal-mode, as is
+ done in V86). But yeah, definitely clumsy
+ 29. Richard Wells says:
+ [110]June 20, 2018 at 11:13 pm
+ All 16-bit segments wrap around unless concealed behind the complex
+ logic of a 16-bit huge library. Some programs depended on it;
+ sometimes, it just concealed a bug. IBM's note in the patent on
+ wrap around boils down to keeping the standard 16-bit behavior for
+ all programs except those that specifically expect the big segments
+ of unreal mode. Otherwise, a program may be caught accessing memory
+ it didn't plan to leading to interesting results.
+ [111]https://www.pcjs.org/pubs/pc/reference/microsoft/kb/Q58987/
+ shows that wrap around has nothing to do with A20.
+ 30. Michal Necasek says:
+ [112]June 21, 2018 at 12:00 am
+ No, 16-bit segments do not wrap on a 286 or later (except for a
+ special case with stack pushes and pops). If you try to address
+ past the end of a segment, you get a #GP fault. The KB article
+ talks about 16-bit pointers wrapping around, which is a different
+ issue, and more likely than not avoids addressing past the end of a
+ segment.
+ 31. Chris M. says:
+ [113]June 21, 2018 at 4:11 am
+ AMI used dates instead of version numbers for their HiFlex BIOS
+ cores, hence why you would see two dates on a POST screen. One was
+ the "core" date/revision, and one was the built date/revision that
+ the vendor created. I think this changed when the WinBIOS was
+ introduced, but so many vendors went running to Award after that
+ disaster that nobody really noticed when they released a new
+ revision!
+ That 1988 Phoenix core was around for a long time, that 486
+ EISA/VLB board has it despite being from 1993! (it also has the
+ stupid 16MB RAM limitation when ROM shadowing is enabled) I think
+ Dell might have used it for a long time on their custom
+ motherboards as well (later stuff was mostly Intel OEM).
+ 32. Richard Wells says:
+ [114]June 22, 2018 at 11:45 pm
+ 16-bit relative near jumps will be done modulo 64k. That happens
+ according to the documentation even with latest chips. There may be
+ an exception triggered but most real mode systems should wind up
+ ignoring the exception. Otherwise, code involving relative 16-bit
+ jumps would have failed since it required overflow/underflow
+ wrapping to get to the more distant parts of the segment.
+ Memory access is a bit different because Intel decided not to
+ follow the 8086 practice of turning any incorrectly aligned word
+ access into a pair of byte accesses which had a side effect of
+ handling a word that occupied both the first and last bytes of a
+ segment. Speed beat out correctly handling an edge case. Some
+ programs seemed to still work with the exception being ignored
+ because I remember 1990s reports of people finally noticing the
+ exception. (Seemed to work because who knows what was in the second
+ byte of that word.)
+ 33. Michal Necasek says:
+ [115]June 24, 2018 at 2:22 pm
+ Relative jumps are signed and sign-extended, so there's normally no
+ overflow and no truncation. #GP faults are fatal, in real mode they
+ lead to hangs (the BIOS does nothing special, the
+ interrupt/exception handler will likely return but it will just
+ re-trigger the exception immediately) or visible fatal errors
+ (EMM386, QEMM, NTVDM).
+ I don't know if with the split-word access speed beat out
+ compatibility or if Intel decided that it was a quirk not worth
+ preserving. At any rate it was a well documented difference between
+ the 8086 and later CPUs; how much software it affected in practice
+ I don't know.
+ 34. Pingback: [116]Michael Tsai - Blog - A Brief History of Unreal Mode
+ 35. [117]Yuhong Bao says:
+ [118]July 8, 2018 at 1:00 am
+ Thinking about it, I think virtual 8086 mode was designed before
+ they officially supported switching the 80386 to real mode, right?
+ 36. Michal Necasek says:
+ [119]July 8, 2018 at 11:31 am
+ Yes, definitely. And the transitions into and out of V86 mode are
+ clean, with no way to leave junk in segment registers. It's
+ apparent that Intel's idea was that with V86 mode, no one needed
+ real mode anymore. But in the absence of a V86 monitor built into
+ the BIOS(?), that wasn't so simple.
+ 37. Michal Necasek says:
+ [120]July 10, 2018 at 4:16 pm
+ Found this in a 1985 IEEE Micro paper by El-Ayat and Agarwal called
+ The Intel 80386-Architecture and Implementation: "Real mode is
+ useful for initialization and for configuration of the processor
+ data structures needed to run in native 80386 protected mode. The
+ recommended method for running 8086 code is called virtual 86
+ mode." Intel's idea clearly was that real mode was for bring-up
+ only and no one would want to switch in and out. If you wanted to
+ run 8086 code, you were supposed to do that in a V86 monitor. Yet
+ another plan that did not survive first contact with reality.
+ 38. Al Williams says:
+ [121]July 29, 2018 at 7:47 am
+ Nice walk down memory lane. The original DDJ article was written on
+ my Intel Inboard 386 plugged into an XT-style motherboard. This did
+ not switch A20 like a "real" PC/AT and so my original code actually
+ would only work on the Inboard but I didn't know that. Later
+ versions (like in the book) would correct that.
+ I was looking. I got an e-mail from an Italian researcher that had
+ used the technique in some scholarly paper and referenced my
+ article for some kind of SEM or spectroscopy, but I couldn't find
+ that and I don't remember the exact year.
+ In addition -- and again, I can't remember the year -- a guy at
+ Software Development cornered me to tell me how he had started a
+ company based on the mode. I think he was selling a library or
+ something. I don't think he had much success. That had to be right
+ after it published within a year or so. I think he advertised with
+ a small ad in a couple of DDJs.
+ As for Necasek's comment, my DOS Extender PROT did run all the real
+ mode code like BIOS/DOS calls in V86 mode. As far as I know, it may
+ have been the first to do that in a nontrivial way.
+ 39. Michal Necasek says:
+ [122]July 31, 2018 at 4:14 pm
+ I saw the updates to your article... as I like to say, the A20 gate
+ is the most expensive bit in history. It never occurred to me but
+ of course the Inboard had to have a different A20 gate control
+ mechanism.
+ Do you remember anything about the unreal mode origins? Was that
+ something you independently discovered, or was it something that
+ was already common knowledge in certain circles?
+ 40. [123]Myself says:
+ [124]August 30, 2018 at 12:09 am
+ Bummer, I only have the third edition of the i386 datasheet
+ (231630-003, Nov. 1986).
+ In page 2, there is the "update notice" which lists updated
+ paragraphs.
+ If you have the version -002, maybe there are hints about changes
+ in the paragraphs you are emphasizing.
+ 41. [125]Al Williams says:
+ [126]August 30, 2018 at 5:19 pm
+ No I had been tantalized by the discussions in the Intel doc
+ warning you to set up the segment registers before switching. Like
+ you mentioned, they all but told you how to do it and then stopped
+ short. It reminded me of the old story about during prohibition
+ where you could buy a "grape block" that had a warning label:
+ Warning: Do not place in 2 quarts of water in a cool dark place for
+ 3 weeks or an illegal alcoholic beverage will result."
+ I have been experimenting with protected mode programs and
+ naturally had to try it out. The lead times in the publishing
+ business at the time means I probably was writing that about the
+ time the PJ article hit the streets if not a little before.
+ Consider it took us 3 months to publish a letter to the editor! By
+ the time an article went through the snail mail, the contracts came
+ back, then the editing and typesetting with galleys in the mail. So
+ I don't remember an exact date, but I do remember being surprised
+ when the PJ article was called out. None of us had heard of it as
+ PJ was not a major competitor so we were not tracking them the way
+ we did some of the other magazines.
+ 42. Michal Necasek says:
+ [127]August 31, 2018 at 10:16 am
+ Indeed there is. The -002 edition is at
+ [128]http://www.bitsavers.org/components/intel/80386/231746-001_Int
+ roduction_to_the_80386_Apr86.pdf and page 63 in the PDF (page 2 of
+ the actual datasheet) lists the changes, though with no detail.
+ Some of the relevant sections were "revised", but that's all we
+ know until the -001 edition turns up.
+ 43. Michal Necasek says:
+ [129]August 31, 2018 at 12:17 pm
+ Thanks for remembering! And the grape block bit, I've not heard of
+ that. Yeah, the Intel docs were like that, daring developers to see
+ what happens if they don't follow the recipe exactly.
+ It's hard to imagine how long the publishing turnaround was was
+ back then, but that's how it was. Entirely possible that someone
+ wrote an article and someone else independently came up with the
+ same thing before it was published. It's quite likely that the
+ articles in foreign press were also independent discoveries; I dug
+ into the German archives a little but I doubt they were the only
+ ones.
+
+Leave a Reply
+
+ Your email address will not be published. Required fields are marked *
+
+ Comment *
+ _____________________________________________
+ _____________________________________________
+ _____________________________________________
+ _____________________________________________
+ _____________________________________________
+ _____________________________________________
+ _____________________________________________
+ _____________________________________________
+
+ Name * ______________________________
+
+ Email * ______________________________
+
+ Website ______________________________
+
+ Post Comment
+
+ D
+ _____________________________________________
+ _____________________________________________
+ _____________________________________________
+ _____________________________________________
+ _____________________________________________
+ _____________________________________________
+ _____________________________________________
+ _____________________________________________
+
+ This site uses Akismet to reduce spam. [130]Learn how your comment data
+ is processed.
+ * Archives
+ + [131]June 2022
+ + [132]May 2022
+ + [133]April 2022
+ + [134]March 2022
+ + [135]February 2022
+ + [136]January 2022
+ + [137]December 2021
+ + [138]November 2021
+ + [139]October 2021
+ + [140]September 2021
+ + [141]August 2021
+ + [142]July 2021
+ + [143]June 2021
+ + [144]May 2021
+ + [145]April 2021
+ + [146]March 2021
+ + [147]February 2021
+ + [148]January 2021
+ + [149]December 2020
+ + [150]November 2020
+ + [151]October 2020
+ + [152]September 2020
+ + [153]August 2020
+ + [154]July 2020
+ + [155]June 2020
+ + [156]May 2020
+ + [157]April 2020
+ + [158]March 2020
+ + [159]February 2020
+ + [160]January 2020
+ + [161]December 2019
+ + [162]November 2019
+ + [163]October 2019
+ + [164]September 2019
+ + [165]August 2019
+ + [166]July 2019
+ + [167]June 2019
+ + [168]May 2019
+ + [169]April 2019
+ + [170]March 2019
+ + [171]February 2019
+ + [172]January 2019
+ + [173]December 2018
+ + [174]November 2018
+ + [175]October 2018
+ + [176]August 2018
+ + [177]July 2018
+ + [178]June 2018
+ + [179]May 2018
+ + [180]April 2018
+ + [181]March 2018
+ + [182]February 2018
+ + [183]January 2018
+ + [184]December 2017
+ + [185]November 2017
+ + [186]October 2017
+ + [187]August 2017
+ + [188]July 2017
+ + [189]June 2017
+ + [190]May 2017
+ + [191]April 2017
+ + [192]March 2017
+ + [193]February 2017
+ + [194]January 2017
+ + [195]December 2016
+ + [196]November 2016
+ + [197]October 2016
+ + [198]September 2016
+ + [199]August 2016
+ + [200]July 2016
+ + [201]June 2016
+ + [202]May 2016
+ + [203]April 2016
+ + [204]March 2016
+ + [205]February 2016
+ + [206]January 2016
+ + [207]December 2015
+ + [208]November 2015
+ + [209]October 2015
+ + [210]September 2015
+ + [211]August 2015
+ + [212]July 2015
+ + [213]June 2015
+ + [214]May 2015
+ + [215]April 2015
+ + [216]March 2015
+ + [217]February 2015
+ + [218]January 2015
+ + [219]December 2014
+ + [220]November 2014
+ + [221]October 2014
+ + [222]September 2014
+ + [223]August 2014
+ + [224]July 2014
+ + [225]June 2014
+ + [226]May 2014
+ + [227]April 2014
+ + [228]March 2014
+ + [229]February 2014
+ + [230]January 2014
+ + [231]December 2013
+ + [232]November 2013
+ + [233]October 2013
+ + [234]September 2013
+ + [235]August 2013
+ + [236]July 2013
+ + [237]June 2013
+ + [238]May 2013
+ + [239]April 2013
+ + [240]March 2013
+ + [241]February 2013
+ + [242]January 2013
+ + [243]December 2012
+ + [244]November 2012
+ + [245]October 2012
+ + [246]September 2012
+ + [247]August 2012
+ + [248]July 2012
+ + [249]June 2012
+ + [250]May 2012
+ + [251]April 2012
+ + [252]March 2012
+ + [253]February 2012
+ + [254]January 2012
+ + [255]December 2011
+ + [256]November 2011
+ + [257]October 2011
+ + [258]September 2011
+ + [259]August 2011
+ + [260]July 2011
+ + [261]June 2011
+ + [262]May 2011
+ + [263]April 2011
+ + [264]March 2011
+ + [265]January 2011
+ + [266]November 2010
+ + [267]October 2010
+ + [268]August 2010
+ + [269]July 2010
+
+ * Categories
+ + [270]286
+ + [271]386
+ + [272]3Com
+ + [273]3Dfx
+ + [274]486
+ + [275]8086/8088
+ + [276]Adaptec
+ + [277]AGP
+ + [278]AMD
+ + [279]AMD64
+ + [280]Apple
+ + [281]Archiving
+ + [282]Assembler
+ + [283]ATi
+ + [284]BIOS
+ + [285]Books
+ + [286]Borland
+ + [287]BSD
+ + [288]Bugs
+ + [289]BusLogic
+ + [290]C
+ + [291]C&T
+ + [292]CD-ROM
+ + [293]Cirrus Logic
+ + [294]CompactFlash
+ + [295]Compaq
+ + [296]Compression
+ + [297]Conner
+ + [298]Corrections
+ + [299]CP/M
+ + [300]Creative Labs
+ + [301]Crystal Semi
+ + [302]Cyrix
+ + [303]DDR RAM
+ + [304]Debugging
+ + [305]DEC
+ + [306]Development
+ + [307]Digital Research
+ + [308]Documentation
+ + [309]DOS
+ + [310]DOS Extenders
+ + [311]Dream
+ + [312]E-mu
+ + [313]Editors
+ + [314]EISA
+ + [315]Ensoniq
+ + [316]ESDI
+ + [317]Ethernet
+ + [318]Fakes
+ + [319]Fixes
+ + [320]Floppies
+ + [321]Graphics
+ + [322]Hardware Hacks
+ + [323]I18N
+ + [324]IBM
+ + [325]IDE
+ + [326]Intel
+ + [327]Internet
+ + [328]Keyboard
+ + [329]Kryoflux
+ + [330]Kurzweil
+ + [331]LAN Manager
+ + [332]Legal
+ + [333]Linux
+ + [334]MCA
+ + [335]Microsoft
+ + [336]MIDI
+ + [337]NetWare
+ + [338]Networking
+ + [339]NeXTSTEP
+ + [340]NFS
+ + [341]Novell
+ + [342]NT
+ + [343]OS X
+ + [344]OS/2
+ + [345]PC architecture
+ + [346]PC hardware
+ + [347]PC history
+ + [348]PC press
+ + [349]PCI
+ + [350]PCMCIA
+ + [351]Pentium
+ + [352]Pentium 4
+ + [353]Pentium II
+ + [354]Pentium III
+ + [355]Pentium Pro
+ + [356]Plug and Play
+ + [357]PowerPC
+ + [358]Pre-release
+ + [359]PS/2
+ + [360]QNX
+ + [361]Quantum
+ + [362]Random Thoughts
+ + [363]RDRAM
+ + [364]Roland
+ + [365]Ryzen
+ + [366]S3
+ + [367]SCO
+ + [368]SCSI
+ + [369]Seagate
+ + [370]Security
+ + [371]Site Management
+ + [372]SMP
+ + [373]Software Hacks
+ + [374]Solaris
+ + [375]Sound
+ + [376]Sound Blaster
+ + [377]Source code
+ + [378]Standards
+ + [379]Storage
+ + [380]Supermicro
+ + [381]TCP/IP
+ + [382]ThinkPad
+ + [383]Trident
+ + [384]UltraSound
+ + [385]Uncategorized
+ + [386]Undocumented
+ + [387]UNIX
+ + [388]UnixWare
+ + [389]USB
+ + [390]VGA
+ + [391]VirtualBox
+ + [392]Virtualization
+ + [393]VLB
+ + [394]Watcom
+ + [395]Wave Blaster
+ + [396]Western Digital
+ + [397]Windows
+ + [398]Windows 95
+ + [399]Windows XP
+ + [400]Wireless
+ + [401]WordStar
+ + [402]x86
+ + [403]Xenix
+ + [404]Xeon
+ + [405]Yamaha
+
+ [406]OS/2 Museum
+ [407]Proudly powered by WordPress.
+
+References
+
+ Visible links:
+ 1. http://www.os2museum.com/wp/feed/
+ 2. http://www.os2museum.com/wp/comments/feed/
+ 3. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/feed/
+ 4. http://www.os2museum.com/wp/wp-json/wp/v2/posts/4169
+ 5. http://www.os2museum.com/wp/wp-json/oembed/1.0/embed?url=http%3A%2F%2Fwww.os2museum.com%2Fwp%2Fa-brief-history-of-unreal-mode%2F
+ 6. http://www.os2museum.com/wp/wp-json/oembed/1.0/embed?url=http%3A%2F%2Fwww.os2museum.com%2Fwp%2Fa-brief-history-of-unreal-mode%2F&format=xml
+ 7. http://www.os2museum.com/wp/
+ 8. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#content
+ 9. http://www.os2museum.com/wp/
+ 10. http://www.os2museum.com/wp/about/
+ 11. http://www.os2museum.com/wp/about/wanted-list/
+ 12. http://www.os2museum.com/wp/os2-history/
+ 13. http://www.os2museum.com/wp/os2-history/os2-beginnings/
+ 14. http://www.os2museum.com/wp/os2-history/os2-1-0/
+ 15. http://www.os2museum.com/wp/os2-history/os2-1-1/
+ 16. http://www.os2museum.com/wp/os2-history/os2-1-2-and-1-3/
+ 17. http://www.os2museum.com/wp/os2-history/os2-16-bit-server/
+ 18. http://www.os2museum.com/wp/os2-history/os2-2-0/
+ 19. http://www.os2museum.com/wp/os2-history/os2-2-1-and-2-11/
+ 20. http://www.os2museum.com/wp/os2-history/os2-warp/
+ 21. http://www.os2museum.com/wp/os2-history/os2-warp-powerpc-edition/
+ 22. http://www.os2museum.com/wp/os2-history/os2-warp-4/
+ 23. http://www.os2museum.com/wp/os2-history/os2-timeline/
+ 24. http://www.os2museum.com/wp/os2-history/os2-library/
+ 25. http://www.os2museum.com/wp/os2-history/os2-library/os2-1-x-sdk/
+ 26. http://www.os2museum.com/wp/os2-history/os2-library/os2-1-x-programming/
+ 27. http://www.os2museum.com/wp/os2-history/os2-library/os2-2-0-technical-library/
+ 28. http://www.os2museum.com/wp/os2-history/os2-videos-1987/
+ 29. http://www.os2museum.com/wp/dos/
+ 30. http://www.os2museum.com/wp/dos/dos-beginnings/
+ 31. http://www.os2museum.com/wp/dos/dos-1-0-and-1-1/
+ 32. http://www.os2museum.com/wp/dos/dos-2-0-and-2-1/
+ 33. http://www.os2museum.com/wp/dos/dos-3-0-3-2/
+ 34. http://www.os2museum.com/wp/dos/dos-3-3/
+ 35. http://www.os2museum.com/wp/dos/dos-4-0/
+ 36. http://www.os2museum.com/wp/dos/dos-library/
+ 37. http://www.os2museum.com/wp/netware-history/
+ 38. http://www.os2museum.com/wp/netware-history/netware-timeline/
+ 39. http://www.os2museum.com/wp/netware-history/netware-library/
+ 40. http://www.os2museum.com/wp/windows-history/
+ 41. http://www.os2museum.com/wp/windows-history/windows-library/
+ 42. http://www.os2museum.com/wp/pc-unix-history/
+ 43. http://www.os2museum.com/wp/pc-unix-history/solaris-2-1-for-x86/
+ 44. http://www.os2museum.com/wp/usb-0-9/
+ 45. http://www.os2museum.com/wp/anomaly-meaningless-rex-prefix-used/
+ 46. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/
+ 47. http://www.os2museum.com/wp/author/michaln/
+ 48. https://en.wikipedia.org/wiki/FASM
+ 49. https://books.google.de/books?id=tSLe3yMjc-AC&lpg=PP1&pg=PT437#v=onepage&q&f=false
+ 50. http://www.gaby.de/ftp/pub/win3x/archive/softlib/xms.exe
+ 51. http://www.megalextoria.com/usenet-archive/news095f1/b118/comp/binaries/ibm/pc/d/00002158.html
+ 52. https://archives.scovetta.com/pub/power_programming/MICROSFT/
+ 53. https://vetusware.com/download/Assembly%20Language%20Programming%20for%20the%20Intel%2080XXX%20Family%201/?id=15869
+ 54. https://link.springer.com/content/pdf/10.3758/BF03203592.pdf
+ 55. https://en.wikipedia.org/wiki/Ultima_VII:_The_Black_Gate
+ 56. https://books.google.com/books?id=gCfzPMoPJWgC&pg=PA304&lpg=PA304&source=bl&ots=rnelM7Nq98&sig=NwfNst9V6yPrUqTMu4oSayD2594&hl=en&sa=X&ved=0ahUKEwinjISbjKjbAhXQZ1AKHfF3D3UQ6AEIPDAC#v=onepage&f=false
+ 57. https://patents.google.com/patent/US5642491
+ 58. http://ftp.lanet.lv/ftp/mirror/x2ftp/msdos/programming/memory/
+ 59. http://ftp.lanet.lv/ftp/mirror/x2ftp/msdos/programming/libs/
+ 60. http://dgi_il.tripod.com/gemmis.txt
+ 61. https://ftp.sunet.se/mirror/archive/ftp.sunet.se/pub/simtelnet/msdos/asmutl/unreal10.zip
+ 62. http://www.rcollins.org/Productivity/DescriptorCache.html
+ 63. https://web.archive.org/web/20051111084304/http://www.phoenix.com/NR/rdonlyres/873A00CF-33AC-4775-B77E-08E7B9754993/0/specspmm101.pdf
+ 64. http://www.rcollins.org/ddj/Aug98/Aug98.html
+ 65. http://www.os2museum.com/wp/more-on-loadall-and-os2/
+ 66. http://www.delorie.com/djgpp/doc/rbinter/it/91/37.html
+ 67. https://board.flatassembler.net/topic.php?t=11940
+ 68. http://www.os2museum.com/wp/category/386/
+ 69. http://www.os2museum.com/wp/category/corrections/
+ 70. http://www.os2museum.com/wp/category/microsoft/
+ 71. http://www.os2museum.com/wp/category/pc-history/
+ 72. http://www.os2museum.com/wp/category/undocumented/
+ 73. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/
+ 74. http://www.os2museum.com/wp/usb-0-9/
+ 75. http://www.os2museum.com/wp/anomaly-meaningless-rex-prefix-used/
+ 76. http://virtuallyfun.com/
+ 77. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347786
+ 78. https://yuhongbao.blogspot.com/
+ 79. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347787
+ 80. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347790
+ 81. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347796
+ 82. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347801
+ 83. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347802
+ 84. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347803
+ 85. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347804
+ 86. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347808
+ 87. http://www.drdobbs.com/80386-protected-mode-initialization/184408010
+ 88. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347810
+ 89. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347812
+ 90. https://yuhongbao.blogspot.com/
+ 91. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347858
+ 92. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347860
+ 93. http://www.tsg.ne.jp/buho/189/tsg189.html#8086
+ 94. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347861
+ 95. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347862
+ 96. https://yuhongbao.blogspot.com/
+ 97. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347864
+ 98. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347865
+ 99. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347866
+ 100. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347867
+ 101. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347868
+ 102. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347869
+ 103. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347872
+ 104. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347964
+ 105. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347974
+ 106. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347978
+ 107. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-347996
+ 108. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-348003
+ 109. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-348035
+ 110. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-348037
+ 111. https://www.pcjs.org/pubs/pc/reference/microsoft/kb/Q58987/
+ 112. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-348040
+ 113. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-348048
+ 114. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-348117
+ 115. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-348188
+ 116. https://mjtsai.com/blog/2018/07/03/a-brief-history-of-unreal-mode/
+ 117. https://yuhongbao.blogspot.com/
+ 118. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-348565
+ 119. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-348575
+ 120. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-348630
+ 121. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-348979
+ 122. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-349002
+ 123. http://temlib.org/
+ 124. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-349848
+ 125. http://www.awce.com/
+ 126. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-349870
+ 127. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-349883
+ 128. http://www.bitsavers.org/components/intel/80386/231746-001_Introduction_to_the_80386_Apr86.pdf
+ 129. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/#comment-349890
+ 130. https://akismet.com/privacy/
+ 131. http://www.os2museum.com/wp/2022/06/
+ 132. http://www.os2museum.com/wp/2022/05/
+ 133. http://www.os2museum.com/wp/2022/04/
+ 134. http://www.os2museum.com/wp/2022/03/
+ 135. http://www.os2museum.com/wp/2022/02/
+ 136. http://www.os2museum.com/wp/2022/01/
+ 137. http://www.os2museum.com/wp/2021/12/
+ 138. http://www.os2museum.com/wp/2021/11/
+ 139. http://www.os2museum.com/wp/2021/10/
+ 140. http://www.os2museum.com/wp/2021/09/
+ 141. http://www.os2museum.com/wp/2021/08/
+ 142. http://www.os2museum.com/wp/2021/07/
+ 143. http://www.os2museum.com/wp/2021/06/
+ 144. http://www.os2museum.com/wp/2021/05/
+ 145. http://www.os2museum.com/wp/2021/04/
+ 146. http://www.os2museum.com/wp/2021/03/
+ 147. http://www.os2museum.com/wp/2021/02/
+ 148. http://www.os2museum.com/wp/2021/01/
+ 149. http://www.os2museum.com/wp/2020/12/
+ 150. http://www.os2museum.com/wp/2020/11/
+ 151. http://www.os2museum.com/wp/2020/10/
+ 152. http://www.os2museum.com/wp/2020/09/
+ 153. http://www.os2museum.com/wp/2020/08/
+ 154. http://www.os2museum.com/wp/2020/07/
+ 155. http://www.os2museum.com/wp/2020/06/
+ 156. http://www.os2museum.com/wp/2020/05/
+ 157. http://www.os2museum.com/wp/2020/04/
+ 158. http://www.os2museum.com/wp/2020/03/
+ 159. http://www.os2museum.com/wp/2020/02/
+ 160. http://www.os2museum.com/wp/2020/01/
+ 161. http://www.os2museum.com/wp/2019/12/
+ 162. http://www.os2museum.com/wp/2019/11/
+ 163. http://www.os2museum.com/wp/2019/10/
+ 164. http://www.os2museum.com/wp/2019/09/
+ 165. http://www.os2museum.com/wp/2019/08/
+ 166. http://www.os2museum.com/wp/2019/07/
+ 167. http://www.os2museum.com/wp/2019/06/
+ 168. http://www.os2museum.com/wp/2019/05/
+ 169. http://www.os2museum.com/wp/2019/04/
+ 170. http://www.os2museum.com/wp/2019/03/
+ 171. http://www.os2museum.com/wp/2019/02/
+ 172. http://www.os2museum.com/wp/2019/01/
+ 173. http://www.os2museum.com/wp/2018/12/
+ 174. http://www.os2museum.com/wp/2018/11/
+ 175. http://www.os2museum.com/wp/2018/10/
+ 176. http://www.os2museum.com/wp/2018/08/
+ 177. http://www.os2museum.com/wp/2018/07/
+ 178. http://www.os2museum.com/wp/2018/06/
+ 179. http://www.os2museum.com/wp/2018/05/
+ 180. http://www.os2museum.com/wp/2018/04/
+ 181. http://www.os2museum.com/wp/2018/03/
+ 182. http://www.os2museum.com/wp/2018/02/
+ 183. http://www.os2museum.com/wp/2018/01/
+ 184. http://www.os2museum.com/wp/2017/12/
+ 185. http://www.os2museum.com/wp/2017/11/
+ 186. http://www.os2museum.com/wp/2017/10/
+ 187. http://www.os2museum.com/wp/2017/08/
+ 188. http://www.os2museum.com/wp/2017/07/
+ 189. http://www.os2museum.com/wp/2017/06/
+ 190. http://www.os2museum.com/wp/2017/05/
+ 191. http://www.os2museum.com/wp/2017/04/
+ 192. http://www.os2museum.com/wp/2017/03/
+ 193. http://www.os2museum.com/wp/2017/02/
+ 194. http://www.os2museum.com/wp/2017/01/
+ 195. http://www.os2museum.com/wp/2016/12/
+ 196. http://www.os2museum.com/wp/2016/11/
+ 197. http://www.os2museum.com/wp/2016/10/
+ 198. http://www.os2museum.com/wp/2016/09/
+ 199. http://www.os2museum.com/wp/2016/08/
+ 200. http://www.os2museum.com/wp/2016/07/
+ 201. http://www.os2museum.com/wp/2016/06/
+ 202. http://www.os2museum.com/wp/2016/05/
+ 203. http://www.os2museum.com/wp/2016/04/
+ 204. http://www.os2museum.com/wp/2016/03/
+ 205. http://www.os2museum.com/wp/2016/02/
+ 206. http://www.os2museum.com/wp/2016/01/
+ 207. http://www.os2museum.com/wp/2015/12/
+ 208. http://www.os2museum.com/wp/2015/11/
+ 209. http://www.os2museum.com/wp/2015/10/
+ 210. http://www.os2museum.com/wp/2015/09/
+ 211. http://www.os2museum.com/wp/2015/08/
+ 212. http://www.os2museum.com/wp/2015/07/
+ 213. http://www.os2museum.com/wp/2015/06/
+ 214. http://www.os2museum.com/wp/2015/05/
+ 215. http://www.os2museum.com/wp/2015/04/
+ 216. http://www.os2museum.com/wp/2015/03/
+ 217. http://www.os2museum.com/wp/2015/02/
+ 218. http://www.os2museum.com/wp/2015/01/
+ 219. http://www.os2museum.com/wp/2014/12/
+ 220. http://www.os2museum.com/wp/2014/11/
+ 221. http://www.os2museum.com/wp/2014/10/
+ 222. http://www.os2museum.com/wp/2014/09/
+ 223. http://www.os2museum.com/wp/2014/08/
+ 224. http://www.os2museum.com/wp/2014/07/
+ 225. http://www.os2museum.com/wp/2014/06/
+ 226. http://www.os2museum.com/wp/2014/05/
+ 227. http://www.os2museum.com/wp/2014/04/
+ 228. http://www.os2museum.com/wp/2014/03/
+ 229. http://www.os2museum.com/wp/2014/02/
+ 230. http://www.os2museum.com/wp/2014/01/
+ 231. http://www.os2museum.com/wp/2013/12/
+ 232. http://www.os2museum.com/wp/2013/11/
+ 233. http://www.os2museum.com/wp/2013/10/
+ 234. http://www.os2museum.com/wp/2013/09/
+ 235. http://www.os2museum.com/wp/2013/08/
+ 236. http://www.os2museum.com/wp/2013/07/
+ 237. http://www.os2museum.com/wp/2013/06/
+ 238. http://www.os2museum.com/wp/2013/05/
+ 239. http://www.os2museum.com/wp/2013/04/
+ 240. http://www.os2museum.com/wp/2013/03/
+ 241. http://www.os2museum.com/wp/2013/02/
+ 242. http://www.os2museum.com/wp/2013/01/
+ 243. http://www.os2museum.com/wp/2012/12/
+ 244. http://www.os2museum.com/wp/2012/11/
+ 245. http://www.os2museum.com/wp/2012/10/
+ 246. http://www.os2museum.com/wp/2012/09/
+ 247. http://www.os2museum.com/wp/2012/08/
+ 248. http://www.os2museum.com/wp/2012/07/
+ 249. http://www.os2museum.com/wp/2012/06/
+ 250. http://www.os2museum.com/wp/2012/05/
+ 251. http://www.os2museum.com/wp/2012/04/
+ 252. http://www.os2museum.com/wp/2012/03/
+ 253. http://www.os2museum.com/wp/2012/02/
+ 254. http://www.os2museum.com/wp/2012/01/
+ 255. http://www.os2museum.com/wp/2011/12/
+ 256. http://www.os2museum.com/wp/2011/11/
+ 257. http://www.os2museum.com/wp/2011/10/
+ 258. http://www.os2museum.com/wp/2011/09/
+ 259. http://www.os2museum.com/wp/2011/08/
+ 260. http://www.os2museum.com/wp/2011/07/
+ 261. http://www.os2museum.com/wp/2011/06/
+ 262. http://www.os2museum.com/wp/2011/05/
+ 263. http://www.os2museum.com/wp/2011/04/
+ 264. http://www.os2museum.com/wp/2011/03/
+ 265. http://www.os2museum.com/wp/2011/01/
+ 266. http://www.os2museum.com/wp/2010/11/
+ 267. http://www.os2museum.com/wp/2010/10/
+ 268. http://www.os2museum.com/wp/2010/08/
+ 269. http://www.os2museum.com/wp/2010/07/
+ 270. http://www.os2museum.com/wp/category/286/
+ 271. http://www.os2museum.com/wp/category/386/
+ 272. http://www.os2museum.com/wp/category/3com/
+ 273. http://www.os2museum.com/wp/category/3dfx/
+ 274. http://www.os2museum.com/wp/category/486/
+ 275. http://www.os2museum.com/wp/category/8086-8088/
+ 276. http://www.os2museum.com/wp/category/adaptec/
+ 277. http://www.os2museum.com/wp/category/agp/
+ 278. http://www.os2museum.com/wp/category/amd/
+ 279. http://www.os2museum.com/wp/category/amd64/
+ 280. http://www.os2museum.com/wp/category/apple/
+ 281. http://www.os2museum.com/wp/category/archiving/
+ 282. http://www.os2museum.com/wp/category/assembler/
+ 283. http://www.os2museum.com/wp/category/ati/
+ 284. http://www.os2museum.com/wp/category/bios/
+ 285. http://www.os2museum.com/wp/category/books/
+ 286. http://www.os2museum.com/wp/category/borland/
+ 287. http://www.os2museum.com/wp/category/bsd/
+ 288. http://www.os2museum.com/wp/category/bugs/
+ 289. http://www.os2museum.com/wp/category/buslogic/
+ 290. http://www.os2museum.com/wp/category/c/
+ 291. http://www.os2museum.com/wp/category/ct/
+ 292. http://www.os2museum.com/wp/category/cd-rom/
+ 293. http://www.os2museum.com/wp/category/cirrus-logic/
+ 294. http://www.os2museum.com/wp/category/compactflash/
+ 295. http://www.os2museum.com/wp/category/compaq/
+ 296. http://www.os2museum.com/wp/category/compression/
+ 297. http://www.os2museum.com/wp/category/conner/
+ 298. http://www.os2museum.com/wp/category/corrections/
+ 299. http://www.os2museum.com/wp/category/cp-m/
+ 300. http://www.os2museum.com/wp/category/creative-labs/
+ 301. http://www.os2museum.com/wp/category/crystal-semi/
+ 302. http://www.os2museum.com/wp/category/cyrix/
+ 303. http://www.os2museum.com/wp/category/ddr-ram/
+ 304. http://www.os2museum.com/wp/category/debugging/
+ 305. http://www.os2museum.com/wp/category/dec/
+ 306. http://www.os2museum.com/wp/category/development/
+ 307. http://www.os2museum.com/wp/category/digital-research/
+ 308. http://www.os2museum.com/wp/category/documentation/
+ 309. http://www.os2museum.com/wp/category/dos/
+ 310. http://www.os2museum.com/wp/category/dos-extenders/
+ 311. http://www.os2museum.com/wp/category/dream/
+ 312. http://www.os2museum.com/wp/category/e-mu/
+ 313. http://www.os2museum.com/wp/category/editors/
+ 314. http://www.os2museum.com/wp/category/eisa/
+ 315. http://www.os2museum.com/wp/category/ensoniq/
+ 316. http://www.os2museum.com/wp/category/esdi/
+ 317. http://www.os2museum.com/wp/category/ethernet/
+ 318. http://www.os2museum.com/wp/category/fakes/
+ 319. http://www.os2museum.com/wp/category/fixes/
+ 320. http://www.os2museum.com/wp/category/floppies/
+ 321. http://www.os2museum.com/wp/category/graphics/
+ 322. http://www.os2museum.com/wp/category/hardware-hacks/
+ 323. http://www.os2museum.com/wp/category/i18n/
+ 324. http://www.os2museum.com/wp/category/ibm/
+ 325. http://www.os2museum.com/wp/category/ide/
+ 326. http://www.os2museum.com/wp/category/intel/
+ 327. http://www.os2museum.com/wp/category/internet/
+ 328. http://www.os2museum.com/wp/category/keyboard/
+ 329. http://www.os2museum.com/wp/category/kryoflux/
+ 330. http://www.os2museum.com/wp/category/kurzweil/
+ 331. http://www.os2museum.com/wp/category/lan-manager/
+ 332. http://www.os2museum.com/wp/category/legal/
+ 333. http://www.os2museum.com/wp/category/linux/
+ 334. http://www.os2museum.com/wp/category/mca/
+ 335. http://www.os2museum.com/wp/category/microsoft/
+ 336. http://www.os2museum.com/wp/category/midi/
+ 337. http://www.os2museum.com/wp/category/netware/
+ 338. http://www.os2museum.com/wp/category/networking/
+ 339. http://www.os2museum.com/wp/category/nextstep/
+ 340. http://www.os2museum.com/wp/category/nfs/
+ 341. http://www.os2museum.com/wp/category/novell/
+ 342. http://www.os2museum.com/wp/category/nt/
+ 343. http://www.os2museum.com/wp/category/os-x/
+ 344. http://www.os2museum.com/wp/category/os2/
+ 345. http://www.os2museum.com/wp/category/pc-architecture/
+ 346. http://www.os2museum.com/wp/category/pc-hardware/
+ 347. http://www.os2museum.com/wp/category/pc-history/
+ 348. http://www.os2museum.com/wp/category/pc-press/
+ 349. http://www.os2museum.com/wp/category/pci/
+ 350. http://www.os2museum.com/wp/category/pcmcia/
+ 351. http://www.os2museum.com/wp/category/pentium/
+ 352. http://www.os2museum.com/wp/category/pentium-4/
+ 353. http://www.os2museum.com/wp/category/pentium-ii/
+ 354. http://www.os2museum.com/wp/category/pentium-iii/
+ 355. http://www.os2museum.com/wp/category/pentium-pro/
+ 356. http://www.os2museum.com/wp/category/plug-and-play/
+ 357. http://www.os2museum.com/wp/category/powerpc/
+ 358. http://www.os2museum.com/wp/category/pre-release/
+ 359. http://www.os2museum.com/wp/category/ps2/
+ 360. http://www.os2museum.com/wp/category/qnx/
+ 361. http://www.os2museum.com/wp/category/quantum/
+ 362. http://www.os2museum.com/wp/category/random-thoughts/
+ 363. http://www.os2museum.com/wp/category/rdram/
+ 364. http://www.os2museum.com/wp/category/roland/
+ 365. http://www.os2museum.com/wp/category/ryzen/
+ 366. http://www.os2museum.com/wp/category/s3/
+ 367. http://www.os2museum.com/wp/category/sco/
+ 368. http://www.os2museum.com/wp/category/scsi/
+ 369. http://www.os2museum.com/wp/category/seagate/
+ 370. http://www.os2museum.com/wp/category/security/
+ 371. http://www.os2museum.com/wp/category/site-management/
+ 372. http://www.os2museum.com/wp/category/smp/
+ 373. http://www.os2museum.com/wp/category/software-hacks/
+ 374. http://www.os2museum.com/wp/category/solaris/
+ 375. http://www.os2museum.com/wp/category/sound/
+ 376. http://www.os2museum.com/wp/category/sound-blaster/
+ 377. http://www.os2museum.com/wp/category/source-code/
+ 378. http://www.os2museum.com/wp/category/standards/
+ 379. http://www.os2museum.com/wp/category/storage/
+ 380. http://www.os2museum.com/wp/category/supermicro/
+ 381. http://www.os2museum.com/wp/category/tcp-ip/
+ 382. http://www.os2museum.com/wp/category/thinkpad/
+ 383. http://www.os2museum.com/wp/category/trident/
+ 384. http://www.os2museum.com/wp/category/ultrasound/
+ 385. http://www.os2museum.com/wp/category/uncategorized/
+ 386. http://www.os2museum.com/wp/category/undocumented/
+ 387. http://www.os2museum.com/wp/category/unix/
+ 388. http://www.os2museum.com/wp/category/unixware/
+ 389. http://www.os2museum.com/wp/category/usb/
+ 390. http://www.os2museum.com/wp/category/vga/
+ 391. http://www.os2museum.com/wp/category/virtualbox/
+ 392. http://www.os2museum.com/wp/category/virtualization/
+ 393. http://www.os2museum.com/wp/category/vlb/
+ 394. http://www.os2museum.com/wp/category/watcom/
+ 395. http://www.os2museum.com/wp/category/wave-blaster/
+ 396. http://www.os2museum.com/wp/category/western-digital/
+ 397. http://www.os2museum.com/wp/category/windows/
+ 398. http://www.os2museum.com/wp/category/windows-95/
+ 399. http://www.os2museum.com/wp/category/windows-xp/
+ 400. http://www.os2museum.com/wp/category/wireless/
+ 401. http://www.os2museum.com/wp/category/wordstar/
+ 402. http://www.os2museum.com/wp/category/x86/
+ 403. http://www.os2museum.com/wp/category/xenix/
+ 404. http://www.os2museum.com/wp/category/xeon/
+ 405. http://www.os2museum.com/wp/category/yamaha/
+ 406. http://www.os2museum.com/wp/
+ 407. https://wordpress.org/
+
+ Hidden links:
+ 409. http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/ultima-vii-voodoo/
diff --git a/src/boot.asm b/src/boot.asm
new file mode 100644
index 0000000..e96237d
--- /dev/null
+++ b/src/boot.asm
@@ -0,0 +1,1408 @@
+; stage 1
+
+; 16-bit real-mode
+[bits 16]
+
+; BIOS always loads us to this location
+[org 0x7c00]
+
+; export a map of boot loader symbols for debugging
+[map symbols boot.map]
+
+stage1:
+
+; no interrupts, initializing segment registers and a real mode stack
+; growing downwards from 0x7c00 where the stage 1 code and data lives
+ cli
+ cld
+ xor ax, ax
+ mov ds, ax
+ mov ss, ax
+ mov sp, 0x7c00
+ mov bp, sp
+ sti
+
+; dl contains the boot drive, primarily because that's the last function
+; called by the BIOS MBR loader, we remember that for loading additional
+; blocks from the boot medium
+ mov [BOOT_DRIVE], dl
+
+; print greeting message
+ mov si, MESSAGE_GREETING
+ call print_string
+
+; size of stage 2 in sectors (3584-512 bytes, size of boot.img minus stage 1)
+NOF_SECTORS_STAGE2 equ 6
+
+; load stage 2 with simple load method to 0x7e00 (directly
+; after the boot sector), we assume stage 2 fits on a track
+ mov ah, 0x02 ; read sectors from drive
+ mov al, NOF_SECTORS_STAGE2 ; read sectors of stage 2
+ mov ch, 0 ; select first cylinder
+ mov dl, [BOOT_DRIVE] ; drive to read from
+ mov dh, 0 ; first head
+ mov cl, 2 ; second sector after boot sector
+ mov bx, 0 ; where to store the data
+ mov es, bx
+ mov bx, 0x7e00 ; 512 bytes after first sector
+ int 0x13
+ jc .read_error
+ jmp .read_ok
+
+.read_error:
+ mov di, ERR_DISK
+ mov ax, 0x01
+ call print_error
+.read_ok:
+ cmp al, NOF_SECTORS_STAGE2 ; correct number of sectors read?
+ jne .short_read_error ; if not, short read
+ jmp .short_read_ok
+.short_read_error:
+ mov di, ERR_DISK
+ mov ax, 0x02
+ call print_error
+.short_read_ok:
+ jmp stage2
+
+; di: pointer to additional message
+; ax: error code in ASCII, never returns
+print_error:
+ mov si, NL
+ call print_string
+ mov si, MESSAGE_ERROR
+ call print_string
+ mov si, di
+ call print_string
+ call print_hex_nice
+ call kill_motor
+ mov si, NL
+ call print_string
+ jmp reboot
+
+; IN si
+print_string:
+ push ax
+ push bx
+.loop:
+ lodsb
+ cmp al, 0
+ je .fini
+ call print_char
+ jmp .loop
+.fini:
+ pop bx
+ pop ax
+ ret
+
+; IN al: character to print
+; MOD ah
+print_char:
+ mov ah, 0x0e
+ int 0x10
+ ret
+
+; IN ah: hex value to print
+print_hex_nice:
+ push si
+ mov si, HEX_PREFIX
+ call print_string
+ call print_hex
+ mov si, SPACE
+ call print_string
+ pop si
+ ret
+
+; IN ah: hex value to print
+print_hex:
+ push bx
+ push si
+ mov si, HEX_TEMPLATE
+ mov bx, ax
+ and bx, 0x00FF
+ shr bx, 4
+ mov bx, [HEXABET+bx]
+ mov [HEX_TEMPLATE], bl
+ mov bx, ax
+ and bx, 0x000F
+ mov bx, [HEXABET+bx]
+ mov [HEX_TEMPLATE+1], bl
+ call print_string
+ pop si
+ pop bx
+ ret
+
+; IN: eax: value to print in hex
+print_hex_dword:
+ push eax
+ push ebx
+ mov ebx, eax
+ mov eax, ebx
+ shr eax, 24
+ call print_hex
+ mov eax, ebx
+ shr eax, 16
+ call print_hex
+ mov eax, ebx
+ shr eax, 8
+ call print_hex
+ mov eax, ebx
+ call print_hex
+ pop ebx
+ pop eax
+ ret
+
+kill_motor:
+ push dx
+ mov dx, 0x3F2
+ mov al, 0x00
+ out dx, al
+ pop dx
+ ret
+
+reset_drive:
+ push ax
+ push dx
+ mov ax, 0x00
+ mov dl, [BOOT_DRIVE]
+ int 0x13
+ pop dx
+ pop ax
+ ret
+
+HEX_TEMPLATE:
+ db '??', 0
+
+HEX_PREFIX:
+ db '0x', 0
+
+HEXABET:
+ db '0123456789ABCDEF'
+
+MESSAGE_GREETING:
+ db "UFLBBL loading...", 13, 10, 0
+
+MESSAGE_ERROR:
+ db "ERR ", 0
+
+SPACE:
+ db " ", 0
+
+NL:
+ db 13, 10, 0
+
+BOOT_DRIVE:
+ db 0
+
+; pad rest of sector with zeroes so we get 512 bytes in the end
+ times 510-($-$$) db 0
+
+; magic number of a boot sector
+ dw 0xaa55
+
+; stage 2
+stage2:
+
+; check A20 gate
+ mov si, MESSAGE_CHECKING_A20
+ call print_string
+ call check_and_enable_A20
+ cmp ax, 1
+ je .A20_enabled
+ mov si, MESSAGE_DISABLED
+ call print_string
+ mov di, ERR_A20
+ mov ax, 0x01
+ call print_error
+
+.A20_enabled:
+ mov si, MESSAGE_ENABLED
+ call print_string
+
+unreal_mode:
+; now switching to bigger data and extra segments (so copying kernels and ramdisks
+; is not overly painful)
+ mov si, MESSAGE_SWITCHING_TO_UNREAL_MODE
+ call print_string
+
+; disable interrupts for now as we do mode switching and segment manipulations
+ cli
+
+; load GDT (global descriptor table)
+ lgdt [gdt_descriptor]
+
+; switch to protected mode
+ mov eax, cr0
+ or eax, 0x1
+ mov cr0, eax
+
+; unconditional far jump into code segment,
+; wipes the instruction prefetch pipeline
+ jmp $+2
+
+; data descriptor in GDT
+ mov ax, CODE_DATA_SEGMENT
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+
+; back to real mode
+ and al, 0xFE
+ mov cr0, eax
+
+; restore segment values - now limits are removed but seg regs still work as normal
+; we keep cs and ss in real mode locations as before, code is small and stack
+; is not expected to get big, besides they stop working above 1 MB as SP and IP
+; are used and not ESP and EIP!
+ xor ax,ax
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+
+; now we are in UNREAL mode, we can also reenable real mode interrupts, as the
+; code segment is still small, so saving IP should work just fine
+ sti
+ mov si, MESSAGE_ENABLED
+ call print_string
+
+; detect disk geometry
+; IN dl: drive
+detect_disk_geometry:
+ xor ax, ax
+ mov es, ax
+ mov di, ax
+ mov ah, 0x08
+ mov dl, [BOOT_DRIVE]
+ int 0x13
+ jc .error
+ jmp .ok
+
+.error:
+; AH contains return code
+ mov si, ERR_DISK
+ call print_error
+
+; all went well, remember and print drive parameters
+.ok:
+ mov si, MESSAGE_DRIVE_PARAMETERS
+ call print_string
+ mov ax, [BOOT_DRIVE]
+ call print_hex_nice
+ xor ax, ax
+ mov [FLOPPY_TYPE], BYTE bl
+ mov al, [FLOPPY_TYPE]
+ call print_hex_nice
+ add dh, 1
+ mov [NOF_HEADS], BYTE dh
+ add cl, 1
+ mov [SECTORS_PER_CYLINDER], BYTE cl
+ mov al, [NOF_HEADS]
+ call print_hex_nice
+ xor ax, ax
+ mov al, [SECTORS_PER_CYLINDER]
+ call print_hex_nice
+ mov si, NL
+ call print_string
+
+ call reset_drive
+
+; read now sectors after stage 2 as long as we can find
+; tar index sectors containing filenames,
+; depending on the filename we have to load things to different places
+; (and move them to memory above 1MB)
+; start to read after stage 1 (512 on sector 1) and stage 2 (starting on sector 2)
+ mov [CURRENT_SECTOR], byte NOF_SECTORS_STAGE2 + 2
+
+read_next_sector:
+
+ mov bx, 0x0900 ; where to store the data (our floppy data read buffer)
+ mov es, bx
+ mov bx, 0x0
+
+; print (C/H/S) info where we are currently reading and in which state
+; and how many data sectors are left in the current tar entry
+ jmp .no_verbose
+
+; states
+ mov al, 0x0d
+ call print_char
+ mov al, byte [READ_STATE]
+ call print_hex
+ mov al, ' '
+ call print_char
+ mov al, byte [KERNEL_STATE]
+ call print_hex
+ mov al, ' '
+ call print_char
+
+; tar data sectors to read for current file
+ mov dx, word [READ_DATA_SECTORS]
+ mov ax, dx
+ shr ax, 8
+ call print_hex
+ mov ax, dx
+ call print_hex
+ mov al, ' '
+ call print_char
+
+; disk geometry (current position on the floppy)
+ mov al, '('
+ call print_char
+ xor ax, ax
+ mov al, byte [CURRENT_CYLINDER]
+ call print_hex
+ mov al, '/'
+ call print_char
+ xor ax, ax
+ mov al, byte [CURRENT_HEAD]
+ call print_hex
+ mov al, '/'
+ call print_char
+ xor ax, ax
+ mov al, byte [CURRENT_SECTOR]
+ call print_hex
+ mov al, ')'
+ call print_char
+
+.no_verbose:
+ call read_one_sector_from_disk
+
+; states in the main sector read loop
+STATE_READ_METADATA equ 0
+STATE_READ_KERNEL equ 1
+STATE_READ_INITRD equ 2
+STATE_KERNEL_READ_SECTOR_0 equ 1
+STATE_KERNEL_READ_SECTOR_1 equ 2
+STATE_KERNEL_READ_SECTORS_REAL_MODE equ 3
+STATE_KERNEL_READ_SECTORS_PROTECTED_MODE equ 4
+STATE_KERNEL_FINISHED equ 5
+
+; depending on the read state we have to do different stuff now
+ mov ah, byte [READ_STATE]
+ cmp ah, STATE_READ_METADATA
+ je handle_read_metadata
+ cmp ah, STATE_READ_KERNEL
+ je handle_read_kernel
+ cmp ah, STATE_READ_INITRD
+ je handle_read_initrd
+ mov di, ERR_DISK
+ mov ax, 0x03
+ call print_error
+
+; state: STATE_READ_METADATA
+handle_read_metadata:
+ push bx
+ mov esi, 0x09000 + 0x101 ; 5 chars must match 'ustar' for being a tar metadata block
+ mov edi, USTAR_MAGIC
+ mov bx, 5
+ call strncmp
+ pop bx
+ cmp ax, 0
+ je .print_tar_metadata
+ jmp advance_to_next_sector ; read over unknown data or non-tar entries
+
+.print_tar_metadata:
+ mov al, ' '
+ call print_char
+ mov si, 0x09000 + 0x00 ; the filename in the tar
+ call print_string
+ mov al, ' '
+ call print_char
+ mov si, 0x09000 + 0x7c ; the size in ASCII octal
+ call print_string
+ mov si, SPACE
+ call print_string
+ mov si, 0x09000 + 0x7c
+ mov ecx, 11
+
+ ; compute size in decimal and compute number of data sectors we have to read
+ call octal_string_to_int
+ a32 mov [READ_DATA_SIZE], eax
+ call print_hex_dword
+
+ mov ecx, eax ; ecx contains the number of 512 byte sectors
+ shr ecx, 9 ; number of sectors a 512 bytes
+ mov edx, ebx ; compute if we have a remainder
+ and edx, 0x01FF
+ cmp edx, 0 ; no remainder, ending at full sector
+ je .full_sector
+ inc ecx ; one non-full sector more to read
+.full_sector:
+ mov [READ_DATA_SECTORS], ecx
+
+ ; enable to debug metadata in tar
+ ;~ mov si, NL
+ ;~ call print_string
+ ;~ mov ax, 0x0900
+ ;~ mov es, ax
+ ;~ call print_memory
+
+.search_kernel:
+ mov esi, 0x09000 + 0x00
+ mov edi, FILE_BZIMAGE
+ call strcmp
+ cmp ax, 0
+ je .found_kernel
+ jmp .search_initrd
+
+.found_kernel:
+ mov [READ_STATE], byte STATE_READ_KERNEL
+ mov [KERNEL_STATE], byte STATE_KERNEL_READ_SECTOR_0
+ mov [READ_DESTINATION_PTR], dword 0x10000
+ mov al, '!'
+ call print_char
+ mov si, NL
+ call print_string
+ jmp advance_to_next_sector
+
+.search_initrd:
+ mov esi, 0x09000 + 0x00
+ mov edi, FILE_RAMDISK
+ call strcmp
+ cmp ax, 0
+ je .found_initrd
+ jmp .search_eof
+
+.found_initrd:
+ mov [READ_STATE], byte STATE_READ_INITRD
+; qemu initrd start location 7fab000, 133869568 (this is 128MB) too high for us,
+; kernel gives us alignment hints and hints where to load initrd to?
+; let's use 8MB, TODO: does the kernel release the initial ramdisk? I think so. is
+; it relocating it's structures? or do we get fragmented heap and stuff?
+ a32 mov [READ_DESTINATION_PTR], dword 0x00800000
+ a32 mov [INITRD_ADDRESS], dword 0x00800000
+ a32 mov eax, [READ_DATA_SIZE]
+ a32 mov [INITRD_SIZE], eax
+ mov al, '!'
+ call print_char
+ mov si, NL
+ call print_string
+
+ jmp advance_to_next_sector
+
+.search_eof:
+ mov esi, 0x09000 + 0x00
+ mov edi, FILE_EOF
+ call strcmp
+ cmp ax, 0
+ je .found_eof
+ jmp .unknown_file
+
+.found_eof:
+ mov si, NL
+ call print_string
+ mov si, MESSAGE_EOF_REACHED
+ call print_string
+ jmp finished_reading
+
+.unknown_file:
+ mov al, '?'
+ call print_char
+ mov si, NL
+ call print_string
+ jmp advance_to_next_sector
+
+; STATE: STATE_READ_KERNEL
+handle_read_kernel:
+
+ ; move kernel code/data from 0x09000 (our disk read scratch space
+ ; in low memory to 0x10000 (which is the real mode location for the
+ ; kernel code)
+ mov ax, ds
+ mov es, ax
+ mov esi, 0x09000
+ mov edi, dword [READ_DESTINATION_PTR]
+ mov ecx, 512
+ cld
+ a32 rep movsb
+ mov [READ_DESTINATION_PTR], edi
+
+ mov ax, word [READ_DATA_SECTORS]
+ dec ax
+ mov word [READ_DATA_SECTORS], ax
+ cmp ax, 0
+ je .data_end
+ jmp kernel_switch
+.data_end:
+ mov [READ_STATE], byte STATE_READ_METADATA
+ jmp advance_to_next_sector
+
+ ; depending on the kernel substate
+kernel_switch:
+ xor ax, ax
+ mov ah, byte [KERNEL_STATE]
+ cmp ah, STATE_KERNEL_READ_SECTOR_0
+ je handle_data_kernel_sector_0
+ cmp ah, STATE_KERNEL_READ_SECTOR_1
+ je handle_data_kernel_sector_1
+ cmp ah, STATE_KERNEL_READ_SECTORS_REAL_MODE
+ je handle_data_kernel_real_mode
+ cmp ah, STATE_KERNEL_READ_SECTORS_PROTECTED_MODE
+ je handle_data_kernel_protected_mode
+ mov di, ERR_KERN
+ mov ax, 0x01
+ call print_error
+
+; STATE: STATE_KERNEL_READ_SECTOR_0
+handle_data_kernel_sector_0:
+
+; first sector if real mode kernel
+
+ ; enable to debug real mode zero page metadata
+ ;~ mov si, NL
+ ;~ call print_string
+ ;~ mov ax, 0x1000
+ ;~ mov es, ax
+ ;~ call print_memory
+
+ ; get the number of real mode kernel sectors to read
+ ; (or mininmally 4 if 0 is returned), each 512 bytes
+ mov si, NL
+ call print_string
+ a32 mov al, byte [0x10000+0x1f1]
+ cmp al, 0
+ jne .nof_sectors_ok
+ mov al, 4 ; minimally 4 sectors
+
+.nof_sectors_ok:
+ mov si, MESSAGE_KERNEL_NOF_REAL_SECTORS
+ call print_string
+ mov [KERNEL_NOF_REAL_MODE_SECTORS], al
+ call print_hex
+ mov si, NL
+ call print_string
+
+ ; get size of protected mode kernel in 16 bytes
+ a32 mov eax, [0x10000+0x1f4]
+ mov ecx, eax
+ shr ecx, 5 ; 16-pages, shifting by 5 to the right gives
+ ; us the number of sectors a 512 bytes
+ mov ebx, eax ; compute if we have to read one sector more with partial data
+ and ebx, 0x001F ; 32 times 16 bytes per page
+ cmp ebx, 0
+ je .full_sector
+ inc ecx
+.full_sector:
+ mov [KERNEL_NOF_PROTECTED_MODE_SECTORS], word cx
+ mov si, MESSAGE_KERNEL_NOF_PROTECTED_SECTORS
+ call print_string
+ mov bx, [KERNEL_NOF_PROTECTED_MODE_SECTORS]
+ mov ax, bx
+ and ax, 0xFF00
+ shr ax, 8
+ call print_hex
+ mov ax, bx
+ and ax, 0x00FF
+ call print_hex
+ mov si, NL
+ call print_string
+
+ mov [KERNEL_STATE], byte STATE_KERNEL_READ_SECTOR_1
+
+ jmp advance_to_next_sector
+
+; STATE: STATE_KERNEL_READ_SECTOR_1
+handle_data_kernel_sector_1:
+ ; enable to debug real mode zero page metadata
+ ;~ mov si, NL
+ ;~ call print_string
+ ;~ mov ax, 0x1020
+ ;~ mov es, ax
+ ;~ call print_memory
+
+ ; compare header
+ mov esi, 0x10000 + 0x202
+ mov edi, KERNEL_MAGIC
+ mov bx, 4
+ call strncmp
+ cmp ax, 0
+ je .kernel_HdrS_found
+ mov di, ERR_KERN
+ mov ax, 0x02
+ call print_error
+
+.kernel_HdrS_found:
+ ; get protocol version, don't allow anothing below 2.15 (which
+ ; os kernel 5.5 or above)
+ mov al, 0x0d
+ call print_char
+ mov si, NL
+ call print_string
+ mov si, MESSAGE_KERNEL_BOOT_PROTOCOL
+ call print_string
+ a32 mov al, byte [0x10000+0x207]
+ mov byte [KERNEL_BOOT_PROTOCOL_MAJOR], al
+ call print_hex
+ mov al, '.'
+ call print_char
+ a32 mov al, byte [0x10000+0x206]
+ mov byte [KERNEL_BOOT_PROTOCOL_MINOR], al
+ call print_hex
+ mov si, NL
+ call print_string
+ xor ax, ax
+ mov al, byte [KERNEL_BOOT_PROTOCOL_MAJOR]
+ cmp al, 2
+ jl .protocol_error
+ xor ax, ax
+ mov al, byte [KERNEL_BOOT_PROTOCOL_MINOR]
+ cmp al, 15
+ jl .protocol_error
+ jmp .get_kernel_version_offset
+
+.protocol_error:
+ mov di, ERR_KERN
+ mov ax, 0x03
+ call print_error
+
+ ; get offset pointing to human readable kernel message,
+ ; we can print it only after having read the real mode part
+ ; of the kernel (or just before we actually start the kernel)
+.get_kernel_version_offset:
+ a32 mov ax, word [0x10000+0x20e]
+ mov [KERNEL_VERSION_PTR], ax
+ jmp .set_boot_data
+
+.set_boot_data:
+ ; not quite clear what the kernel does with this data, TODO: must read kernel code
+ a32 mov byte [0x10000+0x210], 0xe1 ; Extended bootloader type
+ a32 mov byte [0x10000+0x226], 0x00 ; ext_loader_ver
+ a32 mov byte [0x10000+0x227], 0x01 ; ext_loader_type (id: 0x11)
+ a32 or byte [0x10000+0x211], 0x80 ; set CAN_USE_HEAP
+ a32 mov word [0x10000+0x224], 0xde00 ; head_end_ptr
+
+ ; set up area and copy command line from the boot loader area to
+ ; a area registered with the kernel (0x1e000)
+ a32 mov dword [0x10000+0x228], 0x1e000 ; set cmd_line_ptr
+ xor ax, ax
+ mov es, ax
+ mov esi, KERNEL_CMD_LINE
+ mov edi, 0x1e000
+ mov ecx, KERNEL_CMD_SIZE
+ cld
+ a32 rep movsb
+
+ jmp .change_state
+
+.change_state:
+ ; enable to debug real mode zero page metadata after modifying and setting parameters
+ ;~ mov si, NL
+ ;~ call print_string
+ ;~ mov ax, 0x1020
+ ;~ mov es, ax
+ ;~ call print_memory
+
+ mov [KERNEL_STATE], byte STATE_KERNEL_READ_SECTORS_REAL_MODE
+ ; intentional fallthrough, decrement real mode sectors below
+
+; STATE: STATE_KERNEL_READ_SECTORS_REAL_MODE
+handle_data_kernel_real_mode:
+ ; read at most KERNEL_NOF_REAL_MODE_SECTORS sectors for real
+ ; mode code/data
+ mov al, byte [KERNEL_NOF_REAL_MODE_SECTORS]
+ dec al
+ mov byte [KERNEL_NOF_REAL_MODE_SECTORS], al
+ cmp al, 0
+ je .last_real_mode_sector_read
+ jmp advance_to_next_sector
+
+.last_real_mode_sector_read:
+ ; show kernel version
+ mov al, 0x0d
+ call print_char
+ mov si, NL
+ call print_string
+ mov si, MESSAGE_KERNEL_VERSION
+ call print_string
+ mov esi, [KERNEL_VERSION_PTR]
+ add esi, 0x200
+ push ds
+ mov ax, 0x1000
+ mov ds, ax
+ call print_string
+ pop ds
+ mov si, NL
+ call print_string
+
+ ; change load pointer to protected mode area 0x100000
+ mov [KERNEL_STATE], byte STATE_KERNEL_READ_SECTORS_PROTECTED_MODE
+ mov [READ_DESTINATION_PTR], dword 0x100000
+
+ jmp advance_to_next_sector
+
+; STATE: STATE_KERNEL_READ_SECTORS_PROTECTED_MODE
+handle_data_kernel_protected_mode:
+ ; read at most KERNEL_NOF_PROTECTED_MODE_SECTORS sectors for protected
+ ; mode code/data
+ mov ax, word [KERNEL_NOF_PROTECTED_MODE_SECTORS]
+ dec ax
+ mov word [KERNEL_NOF_PROTECTED_MODE_SECTORS], ax
+ cmp ax, 0
+ je .last_protected_mode_sector_read
+ jmp advance_to_next_sector
+.last_protected_mode_sector_read:
+ mov [READ_STATE], byte STATE_READ_METADATA
+ mov [KERNEL_STATE], byte STATE_KERNEL_FINISHED
+ jmp advance_to_next_sector
+
+; STATE: STATE_READ_INITRD
+handle_read_initrd:
+ ; move ramdisk data from 0x09000 (our disk read scratch space
+ ; in low memory to high memory 0xaaaa0000
+ mov ax, ds
+ mov es, ax
+ mov esi, 0x09000
+
+ mov edi, dword [READ_DESTINATION_PTR]
+ mov ecx, 512
+ cld
+ a32 rep movsb
+ mov [READ_DESTINATION_PTR], edi
+
+ mov ax, word [READ_DATA_SECTORS]
+ dec ax
+ mov word [READ_DATA_SECTORS], ax
+ cmp ax, 0
+ je .data_end
+ jmp .nothing_todo
+.data_end:
+ mov [READ_STATE], byte STATE_READ_METADATA
+ jmp advance_to_next_sector
+
+.nothing_todo:
+
+advance_to_next_sector:
+ add [CURRENT_SECTOR], byte 1 ; next sector
+ mov ch, [SECTORS_PER_CYLINDER]
+ cmp [CURRENT_SECTOR], ch ; after the end of the current track?
+ je .next_head
+ jmp read_next_sector
+
+.next_head:
+ shr bx, 4 ; make it a segment offset..
+ mov ax, es
+ add ax, bx
+ mov es, ax ; ..and add it to ES
+ mov bx, 0x0 ; we also reset bx and update es to avoid hitting the 64k wrap around point
+ mov [CURRENT_SECTOR], byte 1 ; start from first sector again
+ add [CURRENT_HEAD], byte 1 ; advance head
+ mov ch, [NOF_HEADS]
+ cmp [CURRENT_HEAD], ch ; after the number of heads?
+ je .next_track
+ jmp read_next_sector
+
+.next_track:
+ mov [CURRENT_HEAD], byte 0 ; start from head 0 again
+ add [CURRENT_CYLINDER], byte 1 ; advance track
+ ; TODO depends on boot parameters (the floppy media, add a table)
+ cmp [CURRENT_CYLINDER], byte 80
+ jae .next_floppy
+ jmp read_next_sector
+
+.next_floppy:
+ call kill_motor
+ mov si, NL
+ call print_string
+ mov si, MESSAGE_NEXT_FLOPPY
+ call print_string
+ call wait_for_keypress
+ call reset_drive
+ ; TODO: check for floppy disk change (is there a BIOS function for this?)
+ ; TODO: maybe also check some checksum or so of the floppy data and see
+ ; if we indeed have a new floppy
+ mov [CURRENT_SECTOR], byte 0 ; will be incremented at advance_to_next_sector
+ mov [CURRENT_HEAD], byte 0
+ mov [CURRENT_CYLINDER], byte 0
+ jmp advance_to_next_sector
+
+finished_reading:
+ ; make sure the floppy is not spinnig (also in print_error)
+ call kill_motor
+
+start_kernel:
+
+ ; set ramdisk
+ a32 mov eax, [INITRD_ADDRESS] ; ramdisk size in bytes
+ a32 mov [0x10000+0x218], eax
+ mov si, MESSAGE_INITRD_ADDRESS
+ call print_string
+ a32 mov eax, [INITRD_ADDRESS]
+ call print_hex_dword
+ mov si, NL
+ call print_string
+ a32 mov eax, [INITRD_SIZE] ; ramdisk address in bytes
+ a32 mov [0x10000+0x21c], eax
+ mov si, MESSAGE_INITRD_SIZE
+ call print_string
+ a32 mov eax, [INITRD_SIZE]
+ call print_hex_dword
+ mov si, NL
+ call print_string
+
+ ; TODO: check if we actually do have reached the KERNEL_FINISHED state
+ mov si, MESSAGE_BOOTING_KERNEL
+ call print_string
+
+ ; set up segments for running the real mode kernel
+ cli
+ mov ax, 0x1000
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+ mov sp, 0xe000
+
+ ; jump to kernel real mode entry
+ jmp 0x1020:0
+
+; we should not return here, rather the machine will reset, hang or kernel will OUPS,
+; just in case, restore segments and print an error message just in case it happens..
+ mov ax, CODE_DATA_SEGMENT
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+ mov sp, 0x7c00
+
+ mov si, ERR_KERN
+ mov ax, 0x01
+ call print_error
+
+; allow rebooting if something goes sour in the kernel
+reboot:
+ mov si, MESSAGE_REBOOT
+ call print_string
+
+ call wait_for_keypress
+
+; reboot (cannot use jmp here)
+ db 0xea
+ dw 0x0000
+ dw 0xFFFF
+
+; endless loop if reboot fails
+ jmp $
+
+; wait for key to be pressed
+wait_for_keypress:
+ push ax
+ xor ax, ax
+ int 0x16
+ pop ax
+ ret
+
+; GDT global descriptor table
+
+gdt_start:
+
+; mandatory null entry
+gdt_null:
+ dd 0x0
+ dd 0x0
+
+; on big unreal segment, code and data are in the same unprotected segment
+gdt_code_data:
+ dw 0xffff ; limit (bits 0-15)
+ dw 0x0 ; base (bits 0-15)
+ db 0x0 ; base (bits 16-23)
+ db 10010010b ; flags
+ db 11001111b ; flags, limit (bits 16-19)
+ db 0x0 ; base (bit 24-31)
+
+gdt_end:
+
+gdt_descriptor:
+ dw gdt_end - gdt_start - 1 ; size
+ dd gdt_start ; start address of the GDT
+
+; constants representing the segment bases
+CODE_DATA_SEGMENT equ gdt_code_data - gdt_start
+
+check_and_enable_A20:
+ call check_A20_enabled
+ cmp ax, 1
+ je A20_ENABLED
+
+A20_FAST_SPECIAL_PORT:
+
+ mov al, 'F'
+ call print_char
+
+ in al, 0x92
+ or al, 2
+ out 0x92, al
+
+ call check_A20_enabled
+ cmp ax, 1
+ je A20_ENABLED
+
+A20_ENABLE_KBD_PORT:
+ mov al, 'K'
+ call print_char
+ mov al, 0xdd
+ out 0x64, al
+
+ call check_A20_enabled
+ cmp ax, 1
+ je A20_ENABLED
+
+A20_ENABLE_VIA_BIOS:
+ mov al, 'B'
+ call print_char
+ mov ax, 0x2401
+ int 0x15
+
+ call check_A20_enabled
+ cmp ax, 1
+
+A20_ENABLE_KBD_OUT:
+
+ mov al, 'k'
+ call print_char
+
+ cli ; disable interrupts, we talk directly to the keyboard ports
+
+ call .wait_input
+ mov al,0xAD
+ out 0x64,al ; disable keyboard
+ call .wait_input
+
+ mov al,0xD0
+ out 0x64,al ; tell controller to read output port
+ call .wait_output
+
+ in al,0x60
+ push eax ; get output port data and store it
+ call .wait_input
+
+ mov al,0xD1
+ out 0x64,al ; tell controller to write output port
+ call .wait_input
+
+ pop eax
+ or al,2 ; set bit 1 (enable a20)
+ out 0x60,al ; write out data back to the output port
+
+ call .wait_input
+ mov al,0xAE ; enable keyboard
+ out 0x64,al
+
+ call .wait_input
+
+ sti
+
+ jmp .retest
+
+; wait for input buffer to be clear
+.wait_input:
+ in al,0x64
+ test al,2
+ jnz .wait_input
+ ret
+
+; wait for output buffer to be clear
+.wait_output:
+ in al,0x64
+ test al,1
+ jz .wait_output
+ ret
+
+.retest:
+ call check_A20_enabled
+ cmp ax, 1
+ je A20_ENABLED
+
+A20_ENABLED:
+ ret
+
+; returns 0 if not A20_ENABLED, 1 if A20_ENABLED in AX
+check_A20_enabled:
+ pushf
+ push ds
+ push es
+ push di
+ push si
+
+ cli
+
+ xor ax, ax
+ mov es, ax
+ mov di, 0x0500 ; es:di = 0000:0500
+
+ mov ax, 0xffff
+ mov ds, ax
+ mov si, 0x0510 ; ds:si = ffff:0510
+
+ mov al, byte [es:di] ; preserve values in memory
+ push ax ; on stack
+ mov al, byte [ds:si]
+ push ax
+
+ mov byte [es:di], 0x00 ; now the test: write 0x00 to 0000:0500
+ mov byte [ds:si], 0xFF ; write 0xff to ffff:0510
+
+ cmp byte [es:di], 0xFF ; memory wrap? A20 not enabled
+ je .disabled
+ jmp .enabled
+
+.restore:
+ pop bx ; restore original memory contents
+ mov byte [ds:si], bl
+ pop bx
+ mov byte [es:di], bl
+ jmp .exit
+
+.enabled:
+ mov al, '+'
+ call print_char
+ mov ax, 1 ; not wrapped around
+ jmp .restore
+
+.disabled:
+ mov al, '-'
+ call print_char
+ mov ax, 0 ; wrapped around (last cmp)
+ jmp .restore
+
+.exit:
+ pop si
+ pop di
+ pop es
+ pop ds
+ popf
+
+ ret
+
+; Read one sector from floppy using CHS adressing
+read_one_sector_from_disk:
+
+ mov ah, 0x02 ; read sectors from drive
+ mov al, 1 ; read 1 sector
+ mov ch, BYTE [CURRENT_CYLINDER]
+ mov dh, BYTE [CURRENT_HEAD]
+ mov dl, BYTE [BOOT_DRIVE]
+ mov cl, BYTE [CURRENT_SECTOR]
+ mov BYTE [CURRENT_RETRIES], 0
+
+ int 0x13
+
+ jc .read_error
+
+ cmp al, 1 ; 1 sector read?
+ jne .short_read ; if not, short read
+
+ ret
+
+.read_error:
+ cmp BYTE [CURRENT_RETRIES], 3
+ jl .read_again
+ jmp .print_error
+.read_again:
+ dec BYTE [CURRENT_RETRIES]
+ call reset_drive
+ jmp read_one_sector_from_disk
+
+.print_error:
+ ;~ xor ax, ax
+ ;~ mov dh, 0
+ ;~ mov dl, ah
+ mov di, ERR_DISK
+ call print_error
+
+.short_read:
+ mov di, ERR_DISK
+ call print_string
+
+; IN al: character to print if printable, dot otherwise
+; MOD ah
+print_dump_char:
+ cmp byte al, 0x20 ; space
+ jl .print_dot
+ test byte al, al ; above 0x7f ~
+ js .print_dot
+ call print_char
+ jmp .done
+.print_dot:
+ mov al, 0x2e ; .
+ call print_char
+.done:
+ ret
+
+; print a dump of 512 bytes in memory (a sector) for debugging purposes
+; IN: es base address (as segment) where to start printing
+print_memory:
+ xor bx, bx
+.next_line:
+ xor cx, cx
+ mov ax, es
+ and ax, 0xFF00
+ shr ax, 8
+ call print_hex
+ mov ax, es
+ and ax, 0x00FF
+ call print_hex
+ xor ax, ax
+ mov ah, ':'
+ call print_char
+ mov al, bh
+ call print_hex
+ mov al, bl
+ call print_hex
+ mov si, DUMP_SEP
+ call print_string
+.next_byte:
+ mov al, [es:bx]
+ call print_hex
+ mov si, SPACE
+ call print_string
+ inc bx
+ inc cx
+ cmp cx, 8
+ je .gap
+ jmp .after_gap
+.gap:
+ mov si, SPACE
+ call print_string
+.after_gap:
+ cmp cx, 16
+ jne .next_byte
+.print_chars:
+ xor cx, cx
+ sub bx, 16
+.next_char:
+ mov al, [es:bx]
+ call print_dump_char
+ inc bx
+ inc cx
+ cmp cx, 16
+ jne .next_char
+.newline:
+ mov si, NL
+ call print_string
+ cmp bx, 256
+ je .wait
+ jmp .cont
+.wait:
+ mov si, MESSAGE_PRESS_KEY_TO_CONTINUE
+ call print_string
+ call wait_for_keypress
+.cont:
+ cmp bx, 512
+ jne .next_line
+ ret
+
+DUMP_SEP:
+ db ": ", 0
+
+; compare strings
+; IN: si, di: start of two zero terminated strings
+; OUT: ax <0 si < di, >0 si > di; =0 si = di
+; CLOBBERS: si, di
+strcmp:
+ push dx
+.loop:
+ a32 mov dl, [esi]
+ a32 mov dh, [edi]
+ cmp dh, $0
+ je .done
+ cmp dl, $0
+ je .done
+ cmp dh, dl
+ jne .done
+ inc si
+ inc di
+ jmp .loop
+.done:
+ xor ax, ax
+ mov al, byte dh
+ sub al, byte dl
+.end:
+ pop dx
+ ret
+
+; compare strings up to a maximal number of characters
+; IN: si, di: start of two zero terminated strings, bx: number of chars
+; OUT: ax <0 si < di, >0 si > di; =0 si = di
+; CLOBBERS: si, di, bx
+strncmp:
+ push dx
+.loop:
+ a32 mov dl, [esi]
+ a32 mov dh, [edi]
+ cmp dh, $0
+ je .done
+ cmp dl, $0
+ je .done
+ cmp dh, dl
+ jne .done
+ inc si
+ inc di
+ dec bx
+ jz .done
+ jmp .loop
+.done:
+ xor ax, ax
+ mov al, byte dh
+ sub al, byte dl
+.end:
+ pop dx
+ ret
+
+; convert octal string to integer
+; IN: si, cx: pointer to the string and length of the string
+; OUT: eax: converted integer
+; clobbers: ebx
+octal_string_to_int:
+ xor ebx, ebx
+.next:
+ movzx eax, byte [esi]
+ inc esi
+ sub al, '0' ; assuming ASCII
+ shl ebx, 3 ; octal, multiply by 8
+ add ebx, eax ; add current digit
+ loop .next ; cx--
+ mov eax, ebx
+ ret
+
+MESSAGE_CHECKING_A20:
+ db "Checking A20 address gate.. ", 0
+
+MESSAGE_ENABLED:
+ db " enabled", 13, 10, 0
+
+MESSAGE_DISABLED:
+ db " disabled", 13, 10, 0
+
+MESSAGE_SWITCHING_TO_UNREAL_MODE:
+ db "Switching to unreal mode..", 0
+
+MESSAGE_DRIVE_PARAMETERS:
+ db "Boot parameters ", 0
+
+MESSAGE_EOF_REACHED:
+ db "Reached end of tar file..", 13, 10, 0
+
+MESSAGE_BOOTING_KERNEL:
+ db "Booting kernel..", 13, 10, 0
+
+MESSAGE_REBOOT:
+ db "Press any key for rebooting..", 13, 10, 0
+
+MESSAGE_NEXT_FLOPPY:
+ db "Insert next floppy and press any key to continue..", 13, 10, 0
+
+MESSAGE_PRESS_KEY_TO_CONTINUE:
+ db "Press any key to continue..", 13, 10, 0
+
+MESSAGE_KERNEL_NOF_REAL_SECTORS:
+ db "Number of real-mode kernel sectors: ", 0
+
+MESSAGE_KERNEL_NOF_PROTECTED_SECTORS:
+ db "Number of protected-mode kernel sectors: ", 0
+
+MESSAGE_KERNEL_BOOT_PROTOCOL:
+ db "Linux boot protocol version: ", 0
+
+MESSAGE_KERNEL_VERSION:
+ db "Linux kernel version: ", 0
+
+MESSAGE_INITRD_ADDRESS:
+ db "Ramdisk address: ", 0
+
+MESSAGE_INITRD_SIZE:
+ db "Ramdisk size: ", 0
+
+ERR_A20:
+ db "A20 ", 0
+
+ERR_DISK:
+ db "DISK ", 0
+
+ERR_KERN:
+ db "KERN ", 0
+
+USTAR_MAGIC:
+ db "ustar", 0
+
+KERNEL_MAGIC:
+ db 'HdrS', 0
+
+; data sections used for reading from floppy, default to some sane values
+; get probed and filled in during floppy drive probing
+FLOPPY_TYPE:
+ db 0x00 ; drive type, usually 0x04 after probing for 3 1/4" 1.44MB
+
+SECTORS_PER_CYLINDER:
+ db 0x3F ; detect parameters enters the correct value here (sectors + 1)
+ ; if detection fails, force int13 to read ahead
+NOF_HEADS:
+ db 0x01 ; number of heads + 1
+
+; read route reads and updates those values while reading from floppy
+CURRENT_SECTOR:
+ db 1
+
+CURRENT_CYLINDER:
+ db 0
+
+CURRENT_HEAD:
+ db 0
+
+CURRENT_RETRIES:
+ db 0
+
+FILE_BZIMAGE:
+ db "bzImage", 0
+
+FILE_RAMDISK:
+ db "ramdisk.img", 0
+
+FILE_EOF:
+ db "EOF", 0
+
+READ_STATE:
+ db STATE_READ_METADATA
+
+READ_DATA_SECTORS:
+ dd 0
+
+READ_DESTINATION_PTR:
+ dd 0x10000
+
+READ_DATA_SIZE:
+ dd 0
+
+KERNEL_STATE:
+ db STATE_KERNEL_READ_SECTOR_0
+
+KERNEL_NOF_REAL_MODE_SECTORS:
+ db 0
+
+KERNEL_NOF_PROTECTED_MODE_SECTORS:
+ dw 0
+
+KERNEL_CMD_LINE:
+ db "debug loglevel=7 earlycon=uart8250,io,0x3f8,9600n8 console=tty0 console=ttyS0,9600n8 rdinit=/bin/sinit root=/dev/ram0 rootfstype=ramfs iommu=off", 0
+
+KERNEL_CMD_SIZE equ $-KERNEL_CMD_LINE
+
+KERNEL_BOOT_PROTOCOL_MAJOR:
+ db 0
+
+KERNEL_BOOT_PROTOCOL_MINOR:
+ db 0
+
+KERNEL_VERSION_PTR:
+ dw 0
+
+INITRD_ADDRESS:
+ dd 0
+
+INITRD_SIZE:
+ dd 0
+
+; make sure we have full sectors
+times (NOF_SECTORS_STAGE2+1)*512-($-$$) db 0
diff --git a/src/lstar.c b/src/lstar.c
new file mode 100644
index 0000000..2a7d541
--- /dev/null
+++ b/src/lstar.c
@@ -0,0 +1,102 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <bsd/string.h>
+#include <string.h>
+
+static int octal_to_int( char *s, int size )
+{
+ int n = 0;
+ char *c = s;
+ while( size > 0 ) {
+ n *= 8;
+ n += *c - '0';
+ c++;
+ size--;
+ }
+
+ return n;
+}
+
+int main( int argc, char *argv[] )
+{
+ FILE *f = NULL;
+ char buf[512];
+ char filename[100];
+ char size_octal[12];
+ char cksum_octal[8];
+ int size;
+ unsigned int cksum;
+ unsigned int computed_cksum;
+ int i, n;
+ int terminate = 0;
+
+ if( argc != 2 ) {
+ fprintf( stderr, "usage: %s <tarfile>\n", argv[0] );
+ exit( EXIT_FAILURE );
+ }
+
+ f = fopen( argv[1], "r" );
+ if( f == NULL ) {
+ fprintf( stderr, "ERROR: failed to open file '%s'\n", argv[1] );
+ exit( EXIT_FAILURE );
+ }
+
+ do {
+ clearerr( f );
+ n = fread( buf, 512, 1, f );
+ if( n == 0 ) {
+ if( ferror( f ) ) {
+ fprintf( stderr, "ERR: read error\n" );
+ terminate = 1;
+ } else if( feof( f ) ) {
+ terminate = 1;
+ break;
+ }
+ }
+
+ if( memcmp( &buf[257], "ustar", 5 ) == 0 ) {
+ strlcpy( filename, buf, 100 );
+
+ if( strcmp( filename, "" ) != 0 ) {
+
+ printf( "file: %s\n", filename );
+
+ strlcpy( size_octal, &buf[124], 12 );
+ printf( "size (octal): %s\n", size_octal );
+
+ size = octal_to_int( size_octal, 11 );
+ printf( "size (decimal): %d\n", size );
+
+ strlcpy( cksum_octal, &buf[148], 8 );
+ printf( "cksum (octal): %s\n", cksum_octal );
+ cksum = octal_to_int( cksum_octal, 6 );
+ printf( "cksum (decimal): %d\n", cksum );
+
+ for( i = 148; i < 148+8; i++ ) {
+ buf[i] = ' ';
+ }
+ computed_cksum = 0;
+ for( i = 0; i < 512; i++ ) {
+ computed_cksum += (unsigned char)buf[i];
+ }
+ printf( "cksum (computed): %d\n", computed_cksum );
+ if( cksum != computed_cksum ) {
+ fprintf( stderr, "ERR: checksum mismatch in header!\n" );
+ }
+
+ while( size > 0 ) {
+ fread( buf, 512, 1, f );
+ size -= 512;
+ }
+ } else {
+ fprintf( stderr, "INFO: the end\n" );
+ }
+ } else {
+ fprintf( stderr, "WARN: skipping non TAR header\n" );
+ }
+ } while( !terminate );
+
+ fclose( f );
+
+ exit( EXIT_SUCCESS );
+}
diff --git a/tests/run_qemu.sh b/tests/run_qemu.sh
new file mode 100755
index 0000000..5c825f1
--- /dev/null
+++ b/tests/run_qemu.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+sleep 2 && \
+qemu-system-i386 -cpu 486 -m 128M \
+ -drive "file=floppy00,if=floppy,format=raw" \
+ -netdev user,id=net0,net=10.0.0.0/24,host=10.0.0.2,dhcpstart=10.0.0.16,hostfwd=tcp::8080-:80,hostfwd=udp::8081-:81 \
+ -device rtl8139,netdev=net0
diff --git a/tests/test_a20.asm b/tests/test_a20.asm
new file mode 100644
index 0000000..43da6e3
--- /dev/null
+++ b/tests/test_a20.asm
@@ -0,0 +1,61 @@
+; The following code is public domain licensed
+
+[bits 16]
+
+; Function: check_a20
+;
+; Purpose: to check the status of the a20 line in a completely self-contained state-preserving way.
+; The function can be modified as necessary by removing push's at the beginning and their
+; respective pop's at the end if complete self-containment is not required.
+;
+; Returns: 0 in ax if the a20 line is disabled (memory wraps around)
+; 1 in ax if the a20 line is enabled (memory does not wrap around)
+
+check_a20:
+ pushf
+ push ds
+ push es
+ push di
+ push si
+
+ cli
+
+ xor ax, ax ; ax = 0
+ mov es, ax
+
+ not ax ; ax = 0xFFFF
+ mov ds, ax
+
+ mov di, 0x0500
+ mov si, 0x0510
+
+ mov al, byte [es:di]
+ push ax
+
+ mov al, byte [ds:si]
+ push ax
+
+ mov byte [es:di], 0x00
+ mov byte [ds:si], 0xFF
+
+ cmp byte [es:di], 0xFF
+
+ pop ax
+ mov byte [ds:si], al
+
+ pop ax
+ mov byte [es:di], al
+
+ mov ax, 0
+ je check_a20__exit
+
+ mov ax, 1
+
+check_a20__exit:
+ pop si
+ pop di
+ pop es
+ pop ds
+ popf
+
+ ret
diff --git a/tests/test_unreal.asm b/tests/test_unreal.asm
new file mode 100644
index 0000000..687a528
--- /dev/null
+++ b/tests/test_unreal.asm
@@ -0,0 +1,49 @@
+; Assembly example
+
+; nasm boot.asm -o boot.bin
+; partcopy boot.bin 0 200 -f0
+
+[ORG 0x7c00] ; add to offsets
+
+start: xor ax, ax ; make it zero
+ mov ds, ax ; DS=0
+ mov ss, ax ; stack starts at seg 0
+ mov sp, 0x9c00 ; 2000h past code start,
+ ; making the stack 7.5k in size
+
+ cli ; no interrupts
+ push ds ; save real mode
+
+ lgdt [gdtinfo] ; load gdt register
+
+ mov eax, cr0 ; switch to pmode by
+ or al,1 ; set pmode bit
+ mov cr0, eax
+
+ jmp $+2 ; tell 386/486 to not crash
+
+ mov bx, 0x08 ; select descriptor 1
+ mov ds, bx ; 8h = 1000b
+
+ and al,0xFE ; back to realmode
+ mov cr0, eax ; by toggling bit again
+
+ pop ds ; get back old segment
+ sti
+
+ mov bx, 0x0f01 ; attrib/char of smiley
+ mov eax, 0x0b8000 ; note 32 bit offset
+ mov word [ds:eax], bx
+
+ jmp $ ; loop forever
+
+gdtinfo:
+ dw gdt_end - gdt - 1 ;last byte in table
+ dd gdt ;start of table
+
+gdt dd 0,0 ; entry 0 is always unused
+flatdesc db 0xff, 0xff, 0, 0, 0, 10010010b, 11001111b, 0
+gdt_end:
+
+ times 510-($-$$) db 0 ; fill sector w/ 0's
+ dw 0xAA55 ; Required by some BIOSes
diff --git a/todo/doc/0xax.gitbooks.io_linux-insides_content_Booting_linux-bootstrap-1.txt b/todo/doc/0xax.gitbooks.io_linux-insides_content_Booting_linux-bootstrap-1.txt
new file mode 100644
index 0000000..d1e1971
--- /dev/null
+++ b/todo/doc/0xax.gitbooks.io_linux-insides_content_Booting_linux-bootstrap-1.txt
@@ -0,0 +1,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
diff --git a/todo/doc/0xax.gitbooks.io_linux-insides_content_Booting_linux-bootstrap-2.txt b/todo/doc/0xax.gitbooks.io_linux-insides_content_Booting_linux-bootstrap-2.txt
new file mode 100644
index 0000000..c0663b3
--- /dev/null
+++ b/todo/doc/0xax.gitbooks.io_linux-insides_content_Booting_linux-bootstrap-2.txt
@@ -0,0 +1,937 @@
+ #[1]next [2]prev
+
+ IFRAME:
+ [3]https://archive.org/includes/donate.php?as_page=1&platform=wb&refere
+ r=https%3A//web.archive.org/web/20230308144724/https%3A//0xax.gitbooks.
+ io/linux-insides/content/Booting/linux-bootstrap-2.html
+
+ [4]Wayback Machine
+ https://0xax.gitbook Go
+ [5]47 captures
+ 02 Feb 2015 - 22 Mar 2023
+ [6]Dec MAR Apr
+ [7]Previous capture 08 [8]Next capture
+ [9]2022 2023 2024
+ success
+ fail
+ [10]About this capture
+ COLLECTED BY
+ Collection: [11]mega002
+ TIMESTAMPS
+ loading
+
+ The Wayback Machine -
+ https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/lin
+ ux-insides/content/Booting/linux-bootstrap-2.html
+
+ ____________________
+
+ * [12]Linux Inside
+ *
+ * Summary
+ * [13]Introduction
+ * [14]Booting
+ + [15]From bootloader to kernel
+ + [16]First steps in the kernel setup code
+ + [17]Video mode initialization and transition to protected mode
+ + [18]Transition to 64-bit mode
+ + [19]Kernel decompression
+ + [20]Kernel load address randomization
+ * [21]Initialization
+ + [22]First steps in the kernel
+ + [23]Early interrupts handler
+ + [24]Last preparations before the kernel entry point
+ + [25]Kernel entry point
+ + [26]Continue architecture-specific boot-time initializations
+ + [27]Architecture-specific initializations, again...
+ + [28]End of the architecture-specific initializations,
+ almost...
+ + [29]Scheduler initialization
+ + [30]RCU initialization
+ + [31]End of initialization
+ * [32]Interrupts
+ + [33]Introduction
+ + [34]Start to dive into interrupts
+ + [35]Interrupt handlers
+ + [36]Initialization of non-early interrupt gates
+ + [37]Implementation of some exception handlers
+ + [38]Handling Non-Maskable interrupts
+ + [39]Dive into external hardware interrupts
+ + [40]Initialization of external hardware interrupts structures
+ + [41]Softirq, Tasklets and Workqueues
+ + [42]Last part
+ * [43]System calls
+ + [44]Introduction to system calls
+ + [45]How the Linux kernel handles a system call
+ + [46]vsyscall and vDSO
+ + [47]How the Linux kernel runs a program
+ + [48]Implementation of the open system call
+ + [49]Limits on resources in Linux
+ * [50]Timers and time management
+ + [51]Introduction
+ + [52]Clocksource framework
+ + [53]The tick broadcast framework and dyntick
+ + [54]Introduction to timers
+ + [55]Clockevents framework
+ + [56]x86 related clock sources
+ + [57]Time related system calls
+ * [58]Synchronization primitives
+ + [59]Introduction to spinlocks
+ + [60]Queued spinlocks
+ + [61]Semaphores
+ + [62]Mutex
+ + [63]Reader/Writer semaphores
+ + [64]SeqLock
+ + RCU
+ + Lockdep
+ * [65]Memory management
+ + [66]Memblock
+ + [67]Fixmaps and ioremap
+ + [68]kmemcheck
+ * [69]Cgroups
+ + [70]Introduction to Control Groups
+ * SMP
+ * [71]Concepts
+ + [72]Per-CPU variables
+ + [73]Cpumasks
+ + [74]The initcall mechanism
+ + [75]Notification Chains
+ * [76]Data Structures in the Linux Kernel
+ + [77]Doubly linked list
+ + [78]Radix tree
+ + [79]Bit arrays
+ * [80]Theory
+ + [81]Paging
+ + [82]Elf64
+ + [83]Inline assembly
+ + CPUID
+ + MSR
+ * Initial ram disk
+ + initrd
+ * [84]Misc
+ + [85]Linux kernel development
+ + [86]How the kernel is compiled
+ + [87]Linkers
+ + [88]Program startup process in userspace
+ + Write and Submit your first Linux kernel Patch
+ + Data types in the kernel
+ * [89]KernelStructures
+ + [90]IDT
+ * [91]Useful links
+ * [92]Contributors
+ *
+
+ Powered by GitBook
+
+[93]First steps in the kernel setup code
+
+Kernel booting process. Part 2.
+
+First steps in the kernel setup
+
+ We started to dive into the linux kernel's insides in the previous
+ [94]part and saw the initial part of the kernel setup code. We stopped
+ at the first call to the main function (which is the first function
+ written in C) from [95]arch/x86/boot/main.c.
+
+ In this part, we will continue to research the kernel setup code and go
+ over
+ * what protected mode is,
+ * the transition into it,
+ * the initialization of the heap and the console,
+ * memory detection, CPU validation and keyboard initialization
+ * and much much more.
+
+ So, let's go ahead.
+
+Protected mode
+
+ Before we can move to the native Intel64 [96]Long Mode, the kernel must
+ switch the CPU into protected mode.
+
+ What is [97]protected mode? Protected mode was first added to the x86
+ architecture in 1982 and was the main mode of Intel processors from the
+ [98]80286 processor until Intel 64 and long mode came.
+
+ The main reason to move away from [99]Real mode is that there is very
+ limited access to the RAM. As you may remember from the previous part,
+ there are only 2^20 bytes or 1 Megabyte, sometimes even only 640
+ Kilobytes of RAM available in Real mode.
+
+ Protected mode brought many changes, but the main one is the difference
+ in memory management. The 20-bit address bus was replaced with a 32-bit
+ address bus. It allowed access to 4 Gigabytes of memory vs the 1
+ Megabyte in Real mode. Also, [100]paging support was added, which you
+ can read about in the next sections.
+
+ Memory management in Protected mode is divided into two, almost
+ independent parts:
+ * Segmentation
+ * Paging
+
+ Here we will only talk about segmentation. Paging will be discussed in
+ the next sections.
+
+ As you can read in the previous part, addresses consist of two parts in
+ Real mode:
+ * Base address of the segment
+ * Offset from the segment base
+
+ And we can get the physical address if we know these two parts by:
+PhysicalAddress = Segment Base * 16 + Offset
+
+ Memory segmentation was completely redone in protected mode. There are
+ no 64 Kilobyte fixed-size segments. Instead, the size and location of
+ each segment is described by an associated data structure called the
+ Segment Descriptor. These segment descriptors are stored in a data
+ structure called the Global Descriptor Table (GDT).
+
+ The GDT is a structure which resides in memory. It has no fixed place
+ in the memory, so its address is stored in the special GDTR register.
+ Later we will see how the GDT is loaded in the Linux kernel code. There
+ will be an operation for loading it from memory, something like:
+lgdt gdt
+
+ where the lgdt instruction loads the base address and limit(size) of
+ the global descriptor table to the GDTR register. GDTR is a 48-bit
+ register and consists of two parts:
+ * the size(16-bit) of the global descriptor table;
+ * the address(32-bit) of the global descriptor table.
+
+ As mentioned above, the GDT contains segment descriptors which describe
+ memory segments. Each descriptor is 64-bits in size. The general scheme
+ of a descriptor is:
+ 63 56 51 48 45 39 32
+------------------------------------------------------------
+| | |B| |A| | | | |0|E|W|A| |
+| BASE 31:24 |G|/|L|V| LIMIT |P|DPL|S| TYPE | BASE 23:16 |
+| | |D| |L| 19:16 | | | |1|C|R|A| |
+------------------------------------------------------------
+
+ 31 16 15 0
+------------------------------------------------------------
+| | |
+| BASE 15:0 | LIMIT 15:0 |
+| | |
+------------------------------------------------------------
+
+ Don't worry, I know it looks a little scary after Real mode, but it's
+ easy. For example LIMIT 15:0 means that bits 0-15 of the segment limit
+ are located at the beginning of the Descriptor. The rest of it is in
+ LIMIT 19:16, which is located at bits 48-51 of the Descriptor. So, the
+ size of Limit is 0-19 i.e 20-bits. Let's take a closer look at it:
+ 1. Limit[20-bits] is split between bits 0-15 and 48-51. It defines the
+ length_of_segment - 1. It depends on the G(Granularity) bit.
+ + if G (bit 55) is 0 and the segment limit is 0, the size of the
+ segment is 1 Byte
+ + if G is 1 and the segment limit is 0, the size of the segment
+ is 4096 Bytes
+ + if G is 0 and the segment limit is 0xfffff, the size of the
+ segment is 1 Megabyte
+ + if G is 1 and the segment limit is 0xfffff, the size of the
+ segment is 4 Gigabytes
+ So, what this means is
+ + if G is 0, Limit is interpreted in terms of 1 Byte and the
+ maximum size of the segment can be 1 Megabyte.
+ + if G is 1, Limit is interpreted in terms of 4096 Bytes = 4
+ KBytes = 1 Page and the maximum size of the segment can be 4
+ Gigabytes. Actually, when G is 1, the value of Limit is
+ shifted to the left by 12 bits. So, 20 bits + 12 bits = 32
+ bits and 2^32 = 4 Gigabytes.
+ 2. Base[32-bits] is split between bits 16-31, 32-39 and 56-63. It
+ defines the physical address of the segment's starting location.
+ 3. Type/Attribute[5-bits] is represented by bits 40-44. It defines the
+ type of segment and how it can be accessed.
+ + The S flag at bit 44 specifies the descriptor type. If S is 0
+ then this segment is a system segment, whereas if S is 1 then
+ this is a code or data segment (Stack segments are data
+ segments which must be read/write segments).
+
+ To determine if the segment is a code or data segment, we can check its
+ Ex(bit 43) Attribute (marked as 0 in the above diagram). If it is 0,
+ then the segment is a Data segment, otherwise, it is a code segment.
+
+ A segment can be of one of the following types:
+--------------------------------------------------------------------------------
+------
+| Type Field | Descriptor Type | Description
+ |
+|-----------------------------|-----------------|-------------------------------
+-----|
+| Decimal | |
+ |
+| 0 E W A | |
+ |
+| 0 0 0 0 0 | Data | Read-Only
+ |
+| 1 0 0 0 1 | Data | Read-Only, accessed
+ |
+| 2 0 0 1 0 | Data | Read/Write
+ |
+| 3 0 0 1 1 | Data | Read/Write, accessed
+ |
+| 4 0 1 0 0 | Data | Read-Only, expand-down
+ |
+| 5 0 1 0 1 | Data | Read-Only, expand-down, access
+ed |
+| 6 0 1 1 0 | Data | Read/Write, expand-down
+ |
+| 7 0 1 1 1 | Data | Read/Write, expand-down, acces
+sed |
+| C R A | |
+ |
+| 8 1 0 0 0 | Code | Execute-Only
+ |
+| 9 1 0 0 1 | Code | Execute-Only, accessed
+ |
+| 10 1 0 1 0 | Code | Execute/Read
+ |
+| 11 1 0 1 1 | Code | Execute/Read, accessed
+ |
+| 12 1 1 0 0 | Code | Execute-Only, conforming
+ |
+| 14 1 1 0 1 | Code | Execute-Only, conforming, acce
+ssed |
+| 13 1 1 1 0 | Code | Execute/Read, conforming
+ |
+| 15 1 1 1 1 | Code | Execute/Read, conforming, acce
+ssed |
+--------------------------------------------------------------------------------
+------
+
+ As we can see the first bit(bit 43) is 0 for a data segment and 1 for a
+ code segment. The next three bits (40, 41, 42) are either EWA(Expansion
+ Writable Accessible) or CRA(Conforming Readable Accessible).
+ * if E(bit 42) is 0, expand up, otherwise, expand down. Read more
+ [101]here.
+ * if W(bit 41)(for Data Segments) is 1, write access is allowed, and
+ if it is 0, the segment is read-only. Note that read access is
+ always allowed on data segments.
+ * A(bit 40) controls whether the segment can be accessed by the
+ processor or not.
+ * C(bit 43) is the conforming bit(for code selectors). If C is 1, the
+ segment code can be executed from a lower level privilege (e.g.
+ user) level. If C is 0, it can only be executed from the same
+ privilege level.
+ * R(bit 41) controls read access to code segments; when it is 1, the
+ segment can be read from. Write access is never granted for code
+ segments.
+
+ 1. DPL[2-bits] (Descriptor Privilege Level) comprises the bits 45-46.
+ It defines the privilege level of the segment. It can be 0-3 where
+ 0 is the most privileged level.
+ 2. The P flag(bit 47) indicates if the segment is present in memory or
+ not. If P is 0, the segment will be presented as invalid and the
+ processor will refuse to read from this segment.
+ 3. AVL flag(bit 52) - Available and reserved bits. It is ignored in
+ Linux.
+ 4. The L flag(bit 53) indicates whether a code segment contains native
+ 64-bit code. If it is set, then the code segment executes in 64-bit
+ mode.
+ 5. The D/B flag(bit 54) (Default/Big flag) represents the operand size
+ i.e 16/32 bits. If set, operand size is 32 bits. Otherwise, it is
+ 16 bits.
+
+ Segment registers contain segment selectors as in real mode. However,
+ in protected mode, a segment selector is handled differently. Each
+ Segment Descriptor has an associated Segment Selector which is a 16-bit
+ structure:
+ 15 3 2 1 0
+-----------------------------
+| Index | TI | RPL |
+-----------------------------
+
+ Where,
+ * Index stores the index number of the descriptor in the GDT.
+ * TI(Table Indicator) indicates where to search for the descriptor.
+ If it is 0 then the descriptor is searched for in the Global
+ Descriptor Table(GDT). Otherwise, it will be searched for in the
+ Local Descriptor Table(LDT).
+ * And RPL contains the Requester's Privilege Level.
+
+ Every segment register has a visible and a hidden part.
+ * Visible - The Segment Selector is stored here.
+ * Hidden - The Segment Descriptor (which contains the base, limit,
+ attributes & flags) is stored here.
+
+ The following steps are needed to get a physical address in protected
+ mode:
+ * The segment selector must be loaded in one of the segment
+ registers.
+ * The CPU tries to find a segment descriptor at the offset GDT
+ address + Index from the selector and then loads the descriptor
+ into the hidden part of the segment register.
+ * If paging is disabled, the linear address of the segment, or its
+ physical address, is given by the formula: Base address (found in
+ the descriptor obtained in the previous step) + Offset.
+
+ Schematically it will look like this:
+
+ linear address
+
+ The algorithm for the transition from real mode into protected mode is:
+ * Disable interrupts
+ * Describe and load the GDT with the lgdt instruction
+ * Set the PE (Protection Enable) bit in CR0 (Control Register 0)
+ * Jump to protected mode code
+
+ We will see the complete transition to protected mode in the linux
+ kernel in the next part, but before we can move to protected mode, we
+ need to do some more preparations.
+
+ Let's look at [102]arch/x86/boot/main.c. We can see some routines there
+ which perform keyboard initialization, heap initialization, etc...
+ Let's take a look.
+
+Copying boot parameters into the "zeropage"
+
+ We will start from the main routine in "main.c". The first function
+ which is called in main is [103]copy_boot_params(void). It copies the
+ kernel setup header into the corresponding field of the boot_params
+ structure which is defined in the
+ [104]arch/x86/include/uapi/asm/bootparam.h header file.
+
+ The boot_params structure contains the struct setup_header hdr field.
+ This structure contains the same fields as defined in the [105]linux
+ boot protocol and is filled by the boot loader and also at kernel
+ compile/build time. copy_boot_params does two things:
+ 1. It copies hdr from [106]header.S to the setup_header field in
+ boot_params structure.
+ 2. It updates the pointer to the kernel command line if the kernel was
+ loaded with the old command line protocol.
+
+ Note that it copies hdr with the memcpy function, defined in the
+ [107]copy.S source file. Let's have a look inside:
+GLOBAL(memcpy)
+ pushw %si
+ pushw %di
+ movw %ax, %di
+ movw %dx, %si
+ pushw %cx
+ shrw $2, %cx
+ rep; movsl
+ popw %cx
+ andw $3, %cx
+ rep; movsb
+ popw %di
+ popw %si
+ retl
+ENDPROC(memcpy)
+
+ Yeah, we just moved to C code and now assembly again :) First of all,
+ we can see that memcpy and other routines which are defined here, start
+ and end with the two macros: GLOBAL and ENDPROC. GLOBAL is described in
+ [108]arch/x86/include/asm/linkage.h which defines the globl directive
+ and its label. ENDPROC is described in [109]include/linux/linkage.h and
+ marks the name symbol as a function name and ends with the size of the
+ name symbol.
+
+ The implementation of memcpy is simple. At first, it pushes values from
+ the si and di registers to the stack to preserve their values because
+ they will change during the memcpy. As we can see in the
+ REALMODE_CFLAGS in arch/x86/Makefile, the kernel build system uses the
+ -mregparm=3 option of GCC, so functions get the first three parameters
+ from ax, dx and cx registers. Calling memcpy looks like this:
+memcpy(&boot_params.hdr, &hdr, sizeof hdr);
+
+ So,
+ * ax will contain the address of boot_params.hdr
+ * dx will contain the address of hdr
+ * cx will contain the size of hdr in bytes.
+
+ memcpy puts the address of boot_params.hdr into di and saves cx on the
+ stack. After this it shifts the value right 2 times (or divides it by
+ 4) and copies four bytes from the address at si to the address at di.
+ After this, we restore the size of hdr again, align it by 4 bytes and
+ copy the rest of the bytes from the address at si to the address at di
+ byte by byte (if there is more). Now the values of si and di are
+ restored from the stack and the copying operation is finished.
+
+Console initialization
+
+ After hdr is copied into boot_params.hdr, the next step is to
+ initialize the console by calling the console_init function, defined in
+ [110]arch/x86/boot/early_serial_console.c.
+
+ It tries to find the earlyprintk option in the command line and if the
+ search was successful, it parses the port address and baud rate of the
+ serial port and initializes the serial port. The value of the
+ earlyprintk command line option can be one of these:
+ * serial,0x3f8,115200
+ * serial,ttyS0,115200
+ * ttyS0,115200
+
+ After serial port initialization we can see the first output:
+if (cmdline_find_option_bool("debug"))
+ puts("early console in setup code\n");
+
+ The definition of puts is in [111]tty.c. As we can see it prints
+ character by character in a loop by calling the putchar function. Let's
+ look into the putchar implementation:
+void __attribute__((section(".inittext"))) putchar(int ch)
+{
+ if (ch == '\n')
+ putchar('\r');
+
+ bios_putchar(ch);
+
+ if (early_serial_base != 0)
+ serial_putchar(ch);
+}
+
+ __attribute__((section(".inittext"))) means that this code will be in
+ the .inittext section. We can find it in the linker file [112]setup.ld.
+
+ First of all, putchar checks for the \n symbol and if it is found,
+ prints \r before. After that it prints the character on the VGA screen
+ by calling the BIOS with the 0x10 interrupt call:
+static void __attribute__((section(".inittext"))) bios_putchar(int ch)
+{
+ struct biosregs ireg;
+
+ initregs(&ireg);
+ ireg.bx = 0x0007;
+ ireg.cx = 0x0001;
+ ireg.ah = 0x0e;
+ ireg.al = ch;
+ intcall(0x10, &ireg, NULL);
+}
+
+ Here initregs takes the biosregs structure and first fills biosregs
+ with zeros using the memset function and then fills it with register
+ values.
+ memset(reg, 0, sizeof *reg);
+ reg->eflags |= X86_EFLAGS_CF;
+ reg->ds = ds();
+ reg->es = ds();
+ reg->fs = fs();
+ reg->gs = gs();
+
+ Let's look at the implementation of [113]memset:
+GLOBAL(memset)
+ pushw %di
+ movw %ax, %di
+ movzbl %dl, %eax
+ imull $0x01010101,%eax
+ pushw %cx
+ shrw $2, %cx
+ rep; stosl
+ popw %cx
+ andw $3, %cx
+ rep; stosb
+ popw %di
+ retl
+ENDPROC(memset)
+
+ As you can read above, it uses the same calling conventions as the
+ memcpy function, which means that the function gets its parameters from
+ the ax, dx and cx registers.
+
+ The implementation of memset is similar to that of memcpy. It saves the
+ value of the di register on the stack and puts the value ofax, which
+ stores the address of the biosregs structure, into di . Next is the
+ movzbl instruction, which copies the value of dl to the lowermost byte
+ of the eax register. The remaining 3 high bytes of eax will be filled
+ with zeros.
+
+ The next instruction multiplies eax with 0x01010101. It needs to
+ because memset will copy 4 bytes at the same time. For example, if we
+ need to fill a structure whose size is 4 bytes with the value 0x7 with
+ memset, eax will contain the 0x00000007. So if we multiply eax with
+ 0x01010101, we will get 0x07070707 and now we can copy these 4 bytes
+ into the structure. memset uses the rep; stosl instruction to copy eax
+ into es:di.
+
+ The rest of the memset function does almost the same thing as memcpy.
+
+ After the biosregs structure is filled with memset, bios_putchar calls
+ the [114]0x10 interrupt which prints a character. Afterwards it checks
+ if the serial port was initialized or not and writes a character there
+ with [115]serial_putchar and inb/outb instructions if it was set.
+
+Heap initialization
+
+ After the stack and bss section have been prepared in [116]header.S
+ (see previous [117]part), the kernel needs to initialize the [118]heap
+ with the [119]init_heap function.
+
+ First of all init_heap checks the [120]CAN_USE_HEAP flag from the
+ [121]loadflags structure in the kernel setup header and calculates the
+ end of the stack if this flag was set:
+ char *stack_end;
+
+ if (boot_params.hdr.loadflags & CAN_USE_HEAP) {
+ asm("leal %P1(%%esp),%0"
+ : "=r" (stack_end) : "i" (-STACK_SIZE));
+
+ or in other words stack_end = esp - STACK_SIZE.
+
+ Then there is the heap_end calculation:
+ heap_end = (char *)((size_t)boot_params.hdr.heap_end_ptr + 0x200);
+
+ which means heap_end_ptr or _end + 512 (0x200h). The last check is
+ whether heap_end is greater than stack_end. If it is then stack_end is
+ assigned to heap_end to make them equal.
+
+ Now the heap is initialized and we can use it using the GET_HEAP
+ method. We will see what it is used for, how to use it and how it is
+ implemented in the next posts.
+
+CPU validation
+
+ The next step as we can see is cpu validation through the validate_cpu
+ function from [122]arch/x86/boot/cpu.c source code file.
+
+ It calls the [123]check_cpu function and passes cpu level and required
+ cpu level to it and checks that the kernel launches on the right cpu
+ level.
+check_cpu(&cpu_level, &req_level, &err_flags);
+if (cpu_level < req_level) {
+ ...
+ return -1;
+}
+
+ The check_cpu function checks the CPU's flags, the presence of
+ [124]long mode in the case of x86_64(64-bit) CPU, checks the
+ processor's vendor and makes preparations for certain vendors like
+ turning off SSE+SSE2 for AMD if they are missing, etc.
+
+ at the next step, we may see a call to the set_bios_mode function after
+ setup code found that a CPU is suitable. As we may see, this function
+ is implemented only for the x86_64 mode:
+static void set_bios_mode(void)
+{
+#ifdef CONFIG_X86_64
+ struct biosregs ireg;
+
+ initregs(&ireg);
+ ireg.ax = 0xec00;
+ ireg.bx = 2;
+ intcall(0x15, &ireg, NULL);
+#endif
+}
+
+ The set_bios_mode function executes the 0x15 BIOS interrupt to tell the
+ BIOS that [125]long mode (if bx == 2) will be used.
+
+Memory detection
+
+ The next step is memory detection through the detect_memory function.
+ detect_memory basically provides a map of available RAM to the CPU. It
+ uses different programming interfaces for memory detection like 0xe820,
+ 0xe801 and 0x88. We will see only the implementation of the 0xE820
+ interface here.
+
+ Let's look at the implementation of the detect_memory_e820 function
+ from the [126]arch/x86/boot/memory.c source file. First of all, the
+ detect_memory_e820 function initializes the biosregs structure as we
+ saw above and fills registers with special values for the 0xe820 call:
+ initregs(&ireg);
+ ireg.ax = 0xe820;
+ ireg.cx = sizeof buf;
+ ireg.edx = SMAP;
+ ireg.di = (size_t)&buf;
+
+ * ax contains the number of the function (0xe820 in our case)
+ * cx contains the size of the buffer which will contain data about
+ the memory
+ * edx must contain the SMAP magic number
+ * es:di must contain the address of the buffer which will contain
+ memory data
+ * ebx has to be zero.
+
+ Next is a loop where data about the memory will be collected. It starts
+ with a call to the 0x15 BIOS interrupt, which writes one line from the
+ address allocation table. For getting the next line we need to call
+ this interrupt again (which we do in the loop). Before the next call
+ ebx must contain the value returned previously:
+ intcall(0x15, &ireg, &oreg);
+ ireg.ebx = oreg.ebx;
+
+ Ultimately, this function collects data from the address allocation
+ table and writes this data into the e820_entry array:
+ * start of memory segment
+ * size of memory segment
+ * type of memory segment (whether the particular segment is usable or
+ reserved)
+
+ You can see the result of this in the dmesg output, something like:
+[ 0.000000] e820: BIOS-provided physical RAM map:
+[ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
+[ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
+[ 0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved
+[ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000003ffdffff] usable
+[ 0.000000] BIOS-e820: [mem 0x000000003ffe0000-0x000000003fffffff] reserved
+[ 0.000000] BIOS-e820: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved
+
+Keyboard initialization
+
+ The next step is the initialization of the keyboard with a call to the
+ [127]keyboard_init function. At first keyboard_init initializes
+ registers using the initregs function. It then calls the [128]0x16
+ interrupt to query the status of the keyboard.
+ initregs(&ireg);
+ ireg.ah = 0x02; /* Get keyboard status */
+ intcall(0x16, &ireg, &oreg);
+ boot_params.kbd_status = oreg.al;
+
+ After this it calls [129]0x16 again to set the repeat rate and delay.
+ ireg.ax = 0x0305; /* Set keyboard repeat rate */
+ intcall(0x16, &ireg, NULL);
+
+Querying
+
+ The next couple of steps are queries for different parameters. We will
+ not dive into details about these queries but we will get back to them
+ in later parts. Let's take a short look at these functions:
+
+ The first step is getting [130]Intel SpeedStep information by calling
+ the query_ist function. It checks the CPU level and if it is correct,
+ calls 0x15 to get the info and saves the result to boot_params.
+
+ Next, the [131]query_apm_bios function gets [132]Advanced Power
+ Management information from the BIOS. query_apm_bios calls the 0x15
+ BIOS interruption too, but with ah = 0x53 to check APM installation.
+ After 0x15 finishes executing, the query_apm_bios functions check the
+ PM signature (it must be 0x504d), the carry flag (it must be 0 if APM
+ supported) and the value of the cx register (if it's 0x02, the
+ protected mode interface is supported).
+
+ Next, it calls 0x15 again, but with ax = 0x5304 to disconnect the APM
+ interface and connect the 32-bit protected mode interface. In the end,
+ it fills boot_params.apm_bios_info with values obtained from the BIOS.
+
+ Note that query_apm_bios will be executed only if the CONFIG_APM or
+ CONFIG_APM_MODULE compile time flag was set in the configuration file:
+#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
+ query_apm_bios();
+#endif
+
+ The last is the [133]query_edd function, which queries Enhanced Disk
+ Drive information from the BIOS. Let's look at how query_edd is
+ implemented.
+
+ First of all, it reads the [134]edd option from the kernel's command
+ line and if it was set to off then query_edd just returns.
+
+ If EDD is enabled, query_edd goes over BIOS-supported hard disks and
+ queries EDD information in the following loop:
+for (devno = 0x80; devno < 0x80+EDD_MBR_SIG_MAX; devno++) {
+ if (!get_edd_info(devno, &ei) && boot_params.eddbuf_entries < EDDMAXNR) {
+ memcpy(edp, &ei, sizeof ei);
+ edp++;
+ boot_params.eddbuf_entries++;
+ }
+ ...
+ ...
+ ...
+ }
+
+ where 0x80 is the first hard drive and the value of the EDD_MBR_SIG_MAX
+ macro is 16. It collects data into an array of [135]edd_info
+ structures. get_edd_info checks that EDD is present by invoking the
+ 0x13 interrupt with ah as 0x41 and if EDD is present, get_edd_info
+ again calls the 0x13 interrupt, but with ah as 0x48 and si containing
+ the address of the buffer where EDD information will be stored.
+
+Conclusion
+
+ This is the end of the second part about the insides of the Linux
+ kernel. In the next part, we will see video mode setting and the rest
+ of the preparations before the transition to protected mode and
+ directly transitioning into it.
+
+ If you have any questions or suggestions write me a comment or ping me
+ at [136]twitter.
+
+ Please note that English is not my first language, And I am really
+ sorry for any inconvenience. If you find any mistakes please send me a
+ PR to [137]linux-insides.
+
+Links
+
+ * [138]Protected mode
+ * [139]Protected mode
+ * [140]Long mode
+ * [141]Nice explanation of CPU Modes with code
+ * [142]How to Use Expand Down Segments on Intel 386 and Later CPUs
+ * [143]earlyprintk documentation
+ * [144]Kernel Parameters
+ * [145]Serial console
+ * [146]Intel SpeedStep
+ * [147]APM
+ * [148]EDD specification
+ * [149]TLDP documentation for Linux Boot Process (old)
+ * [150]Previous Part
+
+results matching ""
+
+No results matching ""
+
+References
+
+ Visible links:
+ 1. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-3.html
+ 2. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
+ 3. https://archive.org/includes/donate.php?as_page=1&platform=wb&referer=https%3A//web.archive.org/web/20230308144724/https%3A//0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 4. https://web.archive.org/web/
+ 5. https://web.archive.org/web/20230308144724*/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 6. https://web.archive.org/web/20221206122118/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 7. https://web.archive.org/web/20221206122118/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 8. https://web.archive.org/web/20230322150041/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 9. https://web.archive.org/web/20220123200511/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 10. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html#expand
+ 11. https://archive.org/details/mega-002
+ 12. https://web.archive.org/web/20230308144724/https://legacy.gitbook.com/book/0xax/linux-insides
+ 13. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/
+ 14. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/
+ 15. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
+ 16. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 17. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-3.html
+ 18. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-4.html
+ 19. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-5.html
+ 20. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-6.html
+ 21. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/
+ 22. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-1.html
+ 23. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-2.html
+ 24. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-3.html
+ 25. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-4.html
+ 26. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-5.html
+ 27. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-6.html
+ 28. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-7.html
+ 29. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-8.html
+ 30. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-9.html
+ 31. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Initialization/linux-initialization-10.html
+ 32. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/
+ 33. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-1.html
+ 34. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-2.html
+ 35. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-3.html
+ 36. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-4.html
+ 37. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-5.html
+ 38. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-6.html
+ 39. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-7.html
+ 40. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-8.html
+ 41. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-9.html
+ 42. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-10.html
+ 43. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SysCall/
+ 44. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-1.html
+ 45. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-2.html
+ 46. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-3.html
+ 47. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-4.html
+ 48. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-5.html
+ 49. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-6.html
+ 50. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Timers/
+ 51. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-1.html
+ 52. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-2.html
+ 53. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-3.html
+ 54. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-4.html
+ 55. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-5.html
+ 56. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-6.html
+ 57. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Timers/linux-timers-7.html
+ 58. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/
+ 59. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-1.html
+ 60. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-2.html
+ 61. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-3.html
+ 62. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-4.html
+ 63. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-5.html
+ 64. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-6.html
+ 65. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/MM/
+ 66. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/MM/linux-mm-1.html
+ 67. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/MM/linux-mm-2.html
+ 68. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/MM/linux-mm-3.html
+ 69. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Cgroups/
+ 70. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Cgroups/linux-cgroups-1.html
+ 71. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Concepts/
+ 72. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-1.html
+ 73. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html
+ 74. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-3.html
+ 75. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-4.html
+ 76. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/DataStructures/
+ 77. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-1.html
+ 78. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-2.html
+ 79. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-3.html
+ 80. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Theory/
+ 81. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-1.html
+ 82. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-2.html
+ 83. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Theory/linux-theory-3.html
+ 84. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Misc/
+ 85. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Misc/linux-misc-1.html
+ 86. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Misc/linux-misc-2.html
+ 87. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Misc/linux-misc-3.html
+ 88. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Misc/linux-misc-4.html
+ 89. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/KernelStructures/
+ 90. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/KernelStructures/linux-kernelstructure-1.html
+ 91. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/LINKS.html
+ 92. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/contributors.html
+ 93. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/
+ 94. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
+ 95. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/main.c
+ 96. https://web.archive.org/web/20230308144724/http://en.wikipedia.org/wiki/Long_mode
+ 97. https://web.archive.org/web/20230308144724/https://en.wikipedia.org/wiki/Protected_mode
+ 98. https://web.archive.org/web/20230308144724/http://en.wikipedia.org/wiki/Intel_80286
+ 99. https://web.archive.org/web/20230308144724/http://wiki.osdev.org/Real_Mode
+ 100. https://web.archive.org/web/20230308144724/http://en.wikipedia.org/wiki/Paging
+ 101. https://web.archive.org/web/20230308144724/http://www.sudleyplace.com/dpmione/expanddown.html
+ 102. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/main.c
+ 103. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/main.c
+ 104. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/include/uapi/asm/bootparam.h
+ 105. https://web.archive.org/web/20230308144724/https://www.kernel.org/doc/Documentation/x86/boot.txt
+ 106. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/header.S#L280
+ 107. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/copy.S
+ 108. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/include/asm/linkage.h
+ 109. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/include/linux/linkage.h
+ 110. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/early_serial_console.c
+ 111. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/tty.c
+ 112. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/setup.ld
+ 113. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/copy.S#L36
+ 114. https://web.archive.org/web/20230308144724/http://www.ctyme.com/intr/rb-0106.htm
+ 115. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/tty.c
+ 116. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/header.S
+ 117. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
+ 118. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/main.c
+ 119. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/main.c
+ 120. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/include/uapi/asm/bootparam.h#L24
+ 121. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/header.S#L320
+ 122. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/cpu.c
+ 123. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/cpucheck.c
+ 124. https://web.archive.org/web/20230308144724/http://en.wikipedia.org/wiki/Long_mode
+ 125. https://web.archive.org/web/20230308144724/https://en.wikipedia.org/wiki/Long_mode
+ 126. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/memory.c
+ 127. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/main.c
+ 128. https://web.archive.org/web/20230308144724/http://www.ctyme.com/intr/rb-1756.htm
+ 129. https://web.archive.org/web/20230308144724/http://www.ctyme.com/intr/rb-1757.htm
+ 130. https://web.archive.org/web/20230308144724/http://en.wikipedia.org/wiki/SpeedStep
+ 131. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/apm.c#L21
+ 132. https://web.archive.org/web/20230308144724/http://en.wikipedia.org/wiki/Advanced_Power_Management
+ 133. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/edd.c#L122
+ 134. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/Documentation/admin-guide/kernel-parameters.rst
+ 135. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/include/uapi/linux/edd.h
+ 136. https://web.archive.org/web/20230308144724/https://twitter.com/0xAX
+ 137. https://web.archive.org/web/20230308144724/https://github.com/0xAX/linux-internals
+ 138. https://web.archive.org/web/20230308144724/http://en.wikipedia.org/wiki/Protected_mode
+ 139. https://web.archive.org/web/20230308144724/http://wiki.osdev.org/Protected_Mode
+ 140. https://web.archive.org/web/20230308144724/http://en.wikipedia.org/wiki/Long_mode
+ 141. https://web.archive.org/web/20230308144724/http://www.codeproject.com/Articles/45788/The-Real-Protected-Long-mode-assembly-tutorial-for
+ 142. https://web.archive.org/web/20230308144724/http://www.sudleyplace.com/dpmione/expanddown.html
+ 143. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/Documentation/x86/earlyprintk.txt
+ 144. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/Documentation/admin-guide/kernel-parameters.rst
+ 145. https://web.archive.org/web/20230308144724/https://github.com/torvalds/linux/blob/v4.16/Documentation/admin-guide/serial-console.rst
+ 146. https://web.archive.org/web/20230308144724/http://en.wikipedia.org/wiki/SpeedStep
+ 147. https://web.archive.org/web/20230308144724/https://en.wikipedia.org/wiki/Advanced_Power_Management
+ 148. https://web.archive.org/web/20230308144724/http://www.t13.org/documents/UploadedDocuments/docs2004/d1572r3-EDD3.pdf
+ 149. https://web.archive.org/web/20230308144724/http://www.tldp.org/HOWTO/Linux-i386-Boot-Code-HOWTO/setup.html
+ 150. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
+
+ Hidden links:
+ 152. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 153. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 154. https://archive.org/account/login.php
+ 155. http://faq.web.archive.org/
+ 156. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html#close
+ 157. https://web.archive.org/web/20230308144724/http://web.archive.org/screenshot/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 158. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 159. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 160. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-2.html
+ 161. https://web.archive.org/web/20230308144724/https://www.gitbook.com/?utm_source=public_site_legacy&utm_medium=referral&utm_campaign=trademark&utm_term=0xax&utm_content=powered_by
+ 162. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-1.html
+ 163. https://web.archive.org/web/20230308144724/https://0xax.gitbooks.io/linux-insides/content/Booting/linux-bootstrap-3.html
diff --git a/todo/doc/dc0d32.blogspot.com_2010_06_real-mode-in-c-with-gcc-writing.txt b/todo/doc/dc0d32.blogspot.com_2010_06_real-mode-in-c-with-gcc-writing.txt
new file mode 100644
index 0000000..6834acd
--- /dev/null
+++ b/todo/doc/dc0d32.blogspot.com_2010_06_real-mode-in-c-with-gcc-writing.txt
@@ -0,0 +1,892 @@
+ #[1]dc0d32 - Atom [2]dc0d32 - RSS [3]dc0d32 - Atom
+
+[4]dc0d32
+
+Tuesday, June 15, 2010
+
+Real mode in C with gcc : writing a bootloader
+
+ Usually the x86 boot loader is written in assembler. We will be
+ exploring the possibility of writing one in C language (as much as
+ possible) compiled with gcc, and runs in real mode. Note that you can
+ also use the 16 bit bcc or TurboC compiler, but we will be focusing on
+ gcc in this post. Most open source kernels are compiled with gcc, and
+ it makes sense to write C bootloader with gcc instead of bcc as you get
+ a much cleaner toolchain :)
+ As of today (20100614), gcc 4.4.4 officially only emits code for
+ protected/long mode and does not support the real mode natively (this
+ may [5]change in future).
+ Also note that we will not discuss the very fundamentals of booting.
+ This article is fairly advanced and assumes that you know what it takes
+ to write a simple boot-loader in assembler. It is also expected that
+ you know how to write gcc inline assembly. Not everything can be done
+ in C!
+
+getting the tool-chain working
+
+.code16gcc
+
+ As we will be running in 16 bit real mode, this tells gas that the
+ assembler was generated by gcc and is intended to be run in real mode.
+ With this directive, gas automatically adds addr32 prefix wherever
+ required. For each C file which contains code to be run in real mode,
+ this directive should be present at the top of effectively generated
+ assembler code. This can be ensured by defining in a header and
+ including it before any other.
+#ifndef _CODE16GCC_H_
+#define _CODE16GCC_H_
+__asm__(".code16gcc\n");
+#endif
+
+ This is great for bootloaders as well as parts of kernel that must run
+ in real mode but are desired written in C instead of asm. In my opinion
+ C code is a lot easier to debug and maintain than asm code, at expense
+ of code size and performance at times.
+
+Special linking
+
+ As bootloader is supposed to run at physical 0x7C00, we need to tell
+ that to linker. The mbr/vbr should end with the proper boot signature
+ 0xaa55.
+ All this can be taken care of by a simple linker script.
+ENTRY(main);
+SECTIONS
+{
+ . = 0x7C00;
+ .text : AT(0x7C00)
+ {
+ _text = .;
+ *(.text);
+ _text_end = .;
+ }
+ .data :
+ {
+ _data = .;
+ *(.bss);
+ *(.bss*);
+ *(.data);
+ *(.rodata*);
+ *(COMMON)
+ _data_end = .;
+ }
+ .sig : AT(0x7DFE)
+ {
+ SHORT(0xaa55);
+ }
+ /DISCARD/ :
+ {
+ *(.note*);
+ *(.iplt*);
+ *(.igot*);
+ *(.rel*);
+ *(.comment);
+/* add any unwanted sections spewed out by your version of gcc and flags here */
+ }
+}
+
+ gcc emits elf binaries with sections, whereas a bootloader is a
+ monolithic plain binary with no sections. Conversion from elf to binary
+ can be done as follows:
+$ objcopy -O binary vbr.elf vbr.bin
+
+The code
+
+ With the toolchain set up, we can start writing our hello world
+ bootloader!
+ vbr.c (the only source file) looks something like this:
+/*
+ * A simple bootloader skeleton for x86, using gcc.
+ *
+ * Prashant Borole (boroleprashant at Google mail)
+ * */
+
+/* XXX these must be at top */
+#include "code16gcc.h"
+__asm__ ("jmpl $0, $main\n");
+
+
+#define __NOINLINE __attribute__((noinline))
+#define __REGPARM __attribute__ ((regparm(3)))
+#define __NORETURN __attribute__((noreturn))
+
+/* BIOS interrupts must be done with inline assembly */
+void __NOINLINE __REGPARM print(const char *s){
+ while(*s){
+ __asm__ __volatile__ ("int $0x10" : : "a"(0x0E00 | *s), "b"(7))
+;
+ s++;
+ }
+}
+/* and for everything else you can use C! Be it traversing the filesystem, or ve
+rifying the kernel image etc.*/
+
+void __NORETURN main(){
+ print("woo hoo!\r\n:)");
+ while(1);
+}
+
+
+ compile it as
+$ gcc -c -g -Os -march=i686 -ffreestanding -Wall -Werror -I. -o vbr.o vbr.c
+$ ld -static -Tlinker.ld -nostdlib --nmagic -o vbr.elf vbr.o
+$ objcopy -O binary vbr.elf vbr.bin
+
+ and that should have created vbr.elf file (which you can use as a
+ symbols file with gdb for source level debugging the vbr with gdbstub
+ and qemu/bochs) as well as 512 byte vbr.bin. To test it, first create a
+ dummy 1.44M floppy image, and overwrite it's mbr by vbr.bin with dd.
+$ dd if=/dev/zero of=floppy.img bs=1024 count=1440
+$ dd if=vbr.bin of=floppy.img bs=1 count=512 conv=notrunc
+
+ and now we are ready to test it out :D
+$ qemu -fda floppy.img -boot a
+
+ and you should see the message!
+ Once you get to this stage, you are pretty much set with respect to the
+ tooling itself. Now you can go ahead and write code to read the
+ filesystem, search for next stage or kernel and pass control to it.
+ Here is a simple example of a floppy boot record with no filesystem,
+ and the next stage or kernel written to the floppy immediately after
+ the boot record. The next image LMA and entry are fixed in a bunch of
+ macros. It simply reads the image starting one sector after boot record
+ and passes control to it. There are many obvious holes, which I left
+ open for sake of brevity.
+/*
+ * A simple bootloader skeleton for x86, using gcc.
+ *
+ * Prashant Borole (boroleprashant at Google mail)
+ * */
+
+/* XXX these must be at top */
+#include "code16gcc.h"
+__asm__ ("jmpl $0, $main\n");
+
+
+#define __NOINLINE __attribute__((noinline))
+#define __REGPARM __attribute__ ((regparm(3)))
+#define __PACKED __attribute__((packed))
+#define __NORETURN __attribute__((noreturn))
+
+#define IMAGE_SIZE 8192
+#define BLOCK_SIZE 512
+#define IMAGE_LMA 0x8000
+#define IMAGE_ENTRY 0x800c
+
+/* BIOS interrupts must be done with inline assembly */
+void __NOINLINE __REGPARM print(const char *s){
+ while(*s){
+ __asm__ __volatile__ ("int $0x10" : : "a"(0x0E00 | *s), "b"(7))
+;
+ s++;
+ }
+}
+
+#if 0
+/* use this for the HD/USB/Optical boot sector */
+typedef struct __PACKED TAGaddress_packet_t{
+ char size;
+ char :8;
+ unsigned short blocks;
+ unsigned short buffer_offset;
+ unsigned short buffer_segment;
+ unsigned long long lba;
+ unsigned long long flat_buffer;
+}address_packet_t ;
+
+int __REGPARM lba_read(const void *buffer, unsigned int lba, unsigned short
+blocks, unsigned char bios_drive){
+ int i;
+ unsigned short failed = 0;
+ address_packet_t packet = {.size = sizeof(address_packet_t), .blocks
+= blocks, .buffer_offset = 0xFFFF, .buffer_segment = 0xFFFF, .lba = lba, .flat_b
+uffer = (unsigned long)buffer};
+ for(i = 0; i < 3; i++){
+ packet.blocks = blocks;
+ __asm__ __volatile__ (
+ "movw $0, %0\n"
+ "int $0x13\n"
+ "setcb %0\n"
+ :"=m"(failed) : "a"(0x4200), "d"(bios_drive), "S
+"(&packet) : "cc" );
+ /* do something with the error_code */
+ if(!failed)
+ break;
+ }
+ return failed;
+}
+#else
+/* use for floppy, or as a fallback */
+typedef struct {
+ unsigned char spt;
+ unsigned char numh;
+}drive_params_t;
+
+int __REGPARM __NOINLINE get_drive_params(drive_params_t *p, unsigned char
+bios_drive){
+ unsigned short failed = 0;
+ unsigned short tmp1, tmp2;
+ __asm__ __volatile__
+ (
+ "movw $0, %0\n"
+ "int $0x13\n"
+ "setcb %0\n"
+ : "=m"(failed), "=c"(tmp1), "=d"(tmp2)
+ : "a"(0x0800), "d"(bios_drive), "D"(0)
+ : "cc", "bx"
+ );
+ if(failed)
+ return failed;
+ p->spt = tmp1 & 0x3F;
+ p->numh = tmp2 >> 8;
+ return failed;
+}
+
+int __REGPARM __NOINLINE lba_read(const void *buffer, unsigned int lba, uns
+igned char blocks, unsigned char bios_drive, drive_params_t *p){
+ unsigned char c, h, s;
+ c = lba / (p->numh * p->spt);
+ unsigned short t = lba % (p->numh * p->spt);
+ h = t / p->spt;
+ s = (t % p->spt) + 1;
+ unsigned char failed = 0;
+ unsigned char num_blocks_transferred = 0;
+ __asm__ __volatile__
+ (
+ "movw $0, %0\n"
+ "int $0x13\n"
+ "setcb %0"
+ : "=m"(failed), "=a"(num_blocks_transferred)
+ : "a"(0x0200 | blocks), "c"((s << 8) | s), "d"((h << 8) | bios_driv
+e), "b"(buffer)
+ );
+ return failed || (num_blocks_transferred != blocks);
+}
+#endif
+
+/* and for everything else you can use C! Be it traversing the filesystem, or ve
+rifying the kernel image etc.*/
+
+void __NORETURN main(){
+ unsigned char bios_drive = 0;
+ __asm__ __volatile__("movb %%dl, %0" : "=r"(bios_drive)); /* the B
+IOS drive number of the device we booted from is passed in dl register */
+
+ drive_params_t p = {};
+ get_drive_params(&p, bios_drive);
+
+ void *buff = (void*)IMAGE_LMA;
+ unsigned short num_blocks = ((IMAGE_SIZE / BLOCK_SIZE) + (IMAGE_SIZE %
+BLOCK_SIZE == 0 ? 0 : 1));
+ if(lba_read(buff, 1, num_blocks, bios_drive, &p) != 0){
+ print("read error :(\r\n");
+ while(1);
+ }
+ print("Running next image...\r\n");
+ void* e = (void*)IMAGE_ENTRY;
+ __asm__ __volatile__("" : : "d"(bios_drive));
+ goto *e;
+}
+
+
+ removing __NOINLINE may result in even smaller code in this case. I had
+ it in place so that I could figure out what was happening.
+
+Concluding remarks
+
+ C in no way matches the code size and performance of hand tuned
+ size/speed optimized assembler. Also, because of an extra byte (0x66,
+ 0x67) wasted (in addr32) with almost every instruction, it is highly
+ unlikely that you can cram up the same amount of functionality as
+ assembler.
+ Global and static variables, initialized as well as uninitialized, can
+ quickly fill those precious 446 bytes. Changing them to local and
+ passing around instead may increase or decrease size; there is no thumb
+ rule and it has to be worked out on per case basis. Same goes for
+ function in-lining.
+ You also need to be extremely careful with various gcc optimization
+ flags. For example, if you have a loop in your code whose number of
+ iterations are small and deducible at compile time, and the loop body
+ is relatively small (even 20 bytes), with default -Os, gcc will unroll
+ that loop. If the loop is not unrolled (-fno-tree-loop-optimize), you
+ might be able to shave off big chunk of bytes there. Same holds true
+ for frame setups on i386 - you may want to get rid of them whenever not
+ required using -fomit-frame-pointer. Moral of the story : you need to
+ be extra careful with gcc flags as well as version update. This is not
+ much of an issue for other real mode modules of the kernel where size
+ is not of this prime importance.
+ Also, you must be very cautious with assembler warnings when compiling
+ with .code16gcc. Truncation is common. It is a very good idea to use
+ --save-temp and analyze the assembler code generated from your C and
+ inline assembly. Always take care not to mess with the C calling
+ convention in inline assembly and meticulously check and update the
+ clobber list for inline assembly doing BIOS or APM calls (but you
+ already knew it, right?).
+ It is likely that you want to switch to protected/long mode as early as
+ possible, though. Even then, I still think that maintainability wins
+ over asm's size/speed in case of a bootloader as well as the real mode
+ portions of the kernel.
+ It would be interesting if someone could try this with
+ c++/java/fortran. Please let me know if you do!
+ at [6]June 15, 2010
+ [7]Email This[8]BlogThis![9]Share to Twitter[10]Share to
+ Facebook[11]Share to Pinterest
+ Labels: [12]assembler, [13]bootloader, [14]c, [15]gas, [16]gcc,
+ [17]kernel, [18]osdev
+
+25 comments:
+
+ 1. [19]Girija[20]Tuesday, June 15, 2010 at 6:12:00 PM GMT+5:30
+ Dokyaawarun 10 foot.. kiwwa jaastach.
+ :-|
+ Reply[21]Delete
+ Replies
+ Reply
+ 2. [22]descent[23]Tuesday, December 21, 2010 at 1:10:00 PM GMT+5:30
+ Hi,
+ Thank you for your sharing.
+ in void __NOINLINE __REGPARM print(const char *s)
+ I change the print function to access pointer,
+ like this:
+ videoram[0]='H';
+ but I got the warning message:
+ /tmp/cc5qsy9l.s:33: Warning: 00000000000b8000 shortened to
+ 0000000000008000
+ Do I miss something?
+ Reply[24]Delete
+ Replies
+ Reply
+ 3. [25]descent[26]Tuesday, December 21, 2010 at 2:05:00 PM GMT+5:30
+ Hi,
+ I use gcc-3.4 to compile again.
+ I see no warning message, but in qemu,
+ I still cannot see char H.
+ videoram is static variable.
+ static unsigned char *videoram = (unsigned char *) 0xb8000;
+ Reply[27]Delete
+ Replies
+ Reply
+ 4. [28]descent[29]Tuesday, December 21, 2010 at 3:16:00 PM GMT+5:30
+ Hi,
+ I got something. In 16bit mode, the pointer is 16bit length. So
+ 0xb8000 shortened to 0x8000.
+ I write a c file and a function,
+ void put_char()
+ {
+ unsigned char *videoram = (unsigned char *) 0xb8000;
+ videoram[0]='H';
+ videoram[2]='H';
+ videoram[40]='H';
+ }
+ no include code16gcc.h, I think the pointer is 32bits length, but I
+ still can not see the H character.
+ Reply[30]Delete
+ Replies
+ Reply
+ 5. [31]Prashant[32]Tuesday, December 21, 2010 at 7:16:00 PM GMT+5:30
+ @descent: check the '--save-temps' preserved assembler version of
+ the C function.
+ This article assumes that the reader has low level programming
+ experience with x86.
+ To access the vidmem with b8000h, you have 2 options:
+ 1. write inline assembly to set es to b800h, and di to the address
+ in the real mode segment. Then write byte/word to es:di.
+ 2. Enter unreal mode. Then you can use the full 4G memory,
+ one-to-one mapped.
+ I personally would not recommend any of these methods for printing
+ - BIOS int 10h is pretty good. Remember - do not try and do
+ anything fancy in the (m/v)br; do it in the next stage instead as
+ you have pretty much unconstrained image size in later stages.
+ Reply[33]Delete
+ Replies
+ Reply
+ 6. [34]descent[35]Wednesday, December 22, 2010 at 9:41:00 AM GMT+5:30
+ Hi Prashant,
+ Thank you for your explanation.
+ Because in protected mode, I can use C,
+ and direct access 0xb8000, so I am confused.
+ real/protect mode, gcc/gas 16/32 bit also confuse me.
+ They are very complicate.
+ Reply[36]Delete
+ Replies
+ Reply
+ 7. [37]Sebastian[38]Saturday, March 12, 2011 at 6:26:00 PM GMT+5:30
+ you are a genius!
+ Reply[39]Delete
+ Replies
+ Reply
+ 8. [40]Unknown[41]Sunday, April 17, 2011 at 5:48:00 AM GMT+5:30
+ I've got that infamous runtime error...
+ bootloader.exe has encountered a problem and needs to close. We are
+ sorry for the inconvenience.
+ Reply[42]Delete
+ Replies
+ Reply
+ 9. [43]Unknown[44]Saturday, May 21, 2011 at 2:39:00 AM GMT+5:30
+ Managed to do it in C++.
+ Code is the same.
+ Linker file needs to discard eh_frame.
+ When building on x86-64 add -m32 to g++ and -melf_i386 on ld
+ command line.
+ Trying to rewrite it in a more c++-ish style.
+ My e-mail is boskovits@cogito-top.hu .
+ Reply[45]Delete
+ Replies
+ Reply
+ 10. [46]Prashant[47]Saturday, May 21, 2011 at 3:02:00 AM GMT+5:30
+ @abraker95: are you trying to run the MZ/PE image in windows? that
+ is like sinning and then spitting on the devil when in hell.
+ @boskov1985: cool man! let us know how it goes :D
+ Reply[48]Delete
+ Replies
+ Reply
+ 11. Anonymous[49]Friday, November 25, 2011 at 2:50:00 AM GMT+5:30
+ It's easier to to this without objcopy. Modern ld versions support
+ --oformat=binary , so just one line does the direct compilation
+ job.
+ gcc -g -Os -march=i686 -ffreestanding -Wall -Werror -I. -static
+ -nostdlib -Wl,-Tlinker.ld -Wl,--nmagic -Wl,--oformat=binary -o
+ loader.bin loader.c
+ Reply[50]Delete
+ Replies
+ Reply
+ 12. [51]Prashant[52]Friday, November 25, 2011 at 8:01:00 AM GMT+5:30
+ I can't verify right now whether it works, but thanks for letting
+ us know, rpfh!
+ Reply[53]Delete
+ Replies
+ Reply
+ 13. [54]descent[55]Sunday, December 4, 2011 at 9:42:00 PM GMT+5:30
+ Hi,
+ The c code uses function call, why need not set stack (ss:esp)?
+ Reply[56]Delete
+ Replies
+ Reply
+ 14. [57]Prashant[58]Tuesday, December 6, 2011 at 10:18:00 AM GMT+5:30
+ good point @decent. I guess you will need to set up the stack first
+ in main, probably in assembler.
+ Reply[59]Delete
+ Replies
+ Reply
+ 15. [60]descent[61]Saturday, December 24, 2011 at 8:02:00 PM GMT+5:30
+ I change %ss:%esp to 0x07a0:0000,
+ Is any side effect?
+ void __NORETURN main(){
+ __asm__ ("mov %cs, %ax\n");
+ __asm__ ("mov %ax, %ds\n");
+ __asm__ ("mov $0x07a0, %ax\n");
+ __asm__ ("mov %ax, %ss\n");
+ __asm__ ("mov $0, %esp\n");
+ print("woo hoo!\r\n:)");
+ while(1);
+ }
+ Reply[62]Delete
+ Replies
+ Reply
+ 16. [63]descent[64]Monday, July 30, 2012 at 8:16:00 AM GMT+5:30
+ Hi,
+ I test c bootloader in real machine, in my eeepc 904, need add some
+ code to setup stack.
+ http://descent-incoming.blogspot.tw/2012/05/x86-bootloader-hello-wo
+ rld.html
+ The article is written by Chinese, but the code, picture can give
+ some reference.
+ cppb.cpp is cpp version (compile by g++), it can work, I test it in
+ real machine(eeepc 904).
+ Reply[65]Delete
+ Replies
+ Reply
+ 17. [66]axiomfinity[67]Saturday, April 20, 2013 at 10:46:00 AM GMT+5:30
+ linker fails whats up with it..?
+ Reply[68]Delete
+ Replies
+ Reply
+ 18. [69]Prashant[70]Sunday, April 21, 2013 at 9:34:00 AM GMT+5:30
+ Fails how? Can you please elaborate?
+ Reply[71]Delete
+ Replies
+ Reply
+ 19. [72]Unknown[73]Wednesday, November 13, 2013 at 12:51:00 PM GMT+5:30
+ Thank you for detaile explanation
+ Linker failed nt sure why..ld: error: load segment overlap [0x7c00
+ -> 0x7e50] and [0x7dfe -> 0x7e00]
+ Reply[74]Delete
+ Replies
+ Reply
+ 20. [75]osdev[76]Saturday, May 31, 2014 at 1:35:00 AM GMT+5:30
+ someone here? I need to test, but...
+ "c"((s << 8) | s) <-- duplicate s in CH and CL?
+ c = lba / (p->numh * p->spt); <-- 'c' is never used...
+ maybe -> "c"((c << 8) | s)
+ Reply[77]Delete
+ Replies
+ Reply
+ 21. [78]Unknown[79]Thursday, February 5, 2015 at 8:39:00 PM GMT+5:30
+ Thank you for your nice post! I'm trying to run it on my x86-64
+ linux box, but gcc reports errors like "bad register name rax", I'm
+ a little confused by the various compiler options here, could you
+ please give me suggestions on how to compile the C source file on
+ x86-64 machines? Thanks
+ Reply[80]Delete
+ Replies
+ 1. [81]Jose Fernando Lopez Fernandez[82]Friday, January 20, 2017
+ at 2:56:00 PM GMT+5:30
+ rax is a 64 bit register. A bootloader is running in 16 bits,
+ so you cannot use rax (64 bit) or eax (32 bit). You have to
+ use ax.
+ Also, you said your computer is an x86-64. Which one is it?
+ x86 (32 bit) or 64 (64 bit)? If you have an x86, it will have
+ no idea what rax is, since it has no knowledge of 64 bit
+ registers.
+ I'm just speculating as to your problem here, though. If
+ anything here is incorrect/misguided by all means let me know,
+ I'm only a beginner too
+ [83]Delete
+ Replies
+ Reply
+ 2. [84]Jose Fernando Lopez Fernandez[85]Friday, January 20, 2017
+ at 2:57:00 PM GMT+5:30
+ @Jing Peng
+ rax is a 64 bit register. A bootloader is running in 16 bits,
+ so you cannot use rax (64 bit) or eax (32 bit). You have to
+ use ax.
+ Also, you said your computer is an x86-64. Which one is it?
+ x86 (32 bit) or 64 (64 bit)? If you have an x86, it will have
+ no idea what rax is, since it has no knowledge of 64 bit
+ registers.
+ I'm just speculating as to your problem here, though. If
+ anything here is incorrect/misguided by all means let me know,
+ I'm only a beginner too
+ [86]Delete
+ Replies
+ Reply
+ Reply
+ 22. [87]Unknown[88]Thursday, February 5, 2015 at 8:40:00 PM GMT+5:30
+ Thank you for your nice post! I'm trying to run it on my x86-64
+ linux box, but gcc reports errors like "bad register name rax", I'm
+ a little confused by the various compiler options here, could you
+ please give me suggestions on how to compile the C source file on
+ x86-64 machines? Thanks
+ Reply[89]Delete
+ Replies
+ Reply
+ 23. [90]Unknown[91]Sunday, February 7, 2016 at 8:43:00 PM GMT+5:30
+ hello i ma atif
+ Reply[92]Delete
+ Replies
+ Reply
+
+ Add comment
+ Load more...
+
+ [93]Newer Post [94]Older Post [95]Home
+ Subscribe to: [96]Post Comments (Atom)
+ * [97]Real mode in C with gcc : writing a bootloader
+ Usually the x86 boot loader is written in assembler. We will be
+ exploring the possibility of writing one in C language (as much as
+ possible)...
+ * [98]Writing kernel in Windows with Visual Studio C/C++
+ Most hobby osdev projects prefer *nix+gcc combination these days,
+ primarily because there are a bunch of nice tutorials and examples
+ availab...
+ * [99]Debugging kernel with qemu and gdb
+ Assuming that you have your (or Linux/*BSD/Solaris/Windows or any
+ other) kernel on a bootable device, you can debug the kernel and
+ also the ...
+
+Blog Archive
+
+ * [100]|> [101]2012 (1)
+ + [102]|> [103]Feb 2012 (1)
+
+ * [104]v [105]2010 (7)
+ + [106]v [107]Jun 2010 (2)
+ o [108]Cold boot attack
+ o [109]Real mode in C with gcc : writing a bootloader
+ + [110]|> [111]May 2010 (2)
+ + [112]|> [113]Apr 2010 (1)
+ + [114]|> [115]Mar 2010 (1)
+ + [116]|> [117]Feb 2010 (1)
+
+ * [118]|> [119]2009 (12)
+ + [120]|> [121]Dec 2009 (1)
+ + [122]|> [123]Nov 2009 (2)
+ + [124]|> [125]Sep 2009 (1)
+ + [126]|> [127]Aug 2009 (1)
+ + [128]|> [129]Jul 2009 (2)
+ + [130]|> [131]Feb 2009 (2)
+ + [132]|> [133]Jan 2009 (3)
+
+ * [134]|> [135]2008 (9)
+ + [136]|> [137]Nov 2008 (2)
+ + [138]|> [139]Oct 2008 (3)
+ + [140]|> [141]Aug 2008 (1)
+ + [142]|> [143]Jun 2008 (3)
+
+Labels
+
+ [144]linux [145]kernel [146]8800 [147]FreeBSD [148]gdb [149]nvidia
+ [150]osdev [151]windows 7 [152]bochs [153]boot [154]bootloader
+ [155]debug [156]dual boot [157]gas [158]gcc [159]overclock [160]pidgin
+ [161]windows [162]windows server 2008 [163]2k8 [164]3DMark [165]3DMark
+ vantage [166]820 [167]DRAM [168]Directx 10 [169]Dirext 11 [170]Java
+ [171]OpenJDK [172]OpenOffice [173]Pentium D [174]RAID [175]Sun
+ [176]UUID [177]Unicode [178]VirtualBox [179]X [180]Xorg [181]ageis
+ [182]assembler [183]authentication [184]bash [185]c [186]coolbits
+ [187]dx10 [188]fedora [189]fortune [190]gdm [191]ghostscript [192]gnome
+ [193]google [194]gs [195]gtalk [196]heat sink [197]invisible
+ [198]jabber [199]kde [200]latex [201]lvm [202]lyx [203]mount
+ [204]networked audio [205]networked sound [206]nvclock [207]oolatex
+ [208]ooolatex [209]perl [210]phonon [211]physics [212]physx [213]picasa
+ [214]plugin [215]proxy [216]pulseaudio [217]qemu [218]rsync [219]rtp
+ [220]scp [221]scp stdin [222]security [223]server [224]shell [225]squid
+ [226]ssh [227]sync [228]tar [229]udev [230]unix [231]xdm [232]xfce
+ [233]xmpp [234]xorg.conf [235]zsh
+ [236]visit counter for blogspot
+
+ Theme images by [237]5ugarless. Powered by [238]Blogger.
+
+References
+
+ Visible links:
+ 1. http://dc0d32.blogspot.com/feeds/posts/default
+ 2. http://dc0d32.blogspot.com/feeds/posts/default?alt=rss
+ 3. http://dc0d32.blogspot.com/feeds/6370208028763486595/comments/default
+ 4. http://dc0d32.blogspot.com/
+ 5. http://gcc.gnu.org/ml/gcc/1999-07n/msg00483.html
+ 6. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html
+ 7. https://www.blogger.com/share-post.g?blogID=35813921&postID=6370208028763486595&target=email
+ 8. https://www.blogger.com/share-post.g?blogID=35813921&postID=6370208028763486595&target=blog
+ 9. https://www.blogger.com/share-post.g?blogID=35813921&postID=6370208028763486595&target=twitter
+ 10. https://www.blogger.com/share-post.g?blogID=35813921&postID=6370208028763486595&target=facebook
+ 11. https://www.blogger.com/share-post.g?blogID=35813921&postID=6370208028763486595&target=pinterest
+ 12. http://dc0d32.blogspot.com/search/label/assembler
+ 13. http://dc0d32.blogspot.com/search/label/bootloader
+ 14. http://dc0d32.blogspot.com/search/label/c
+ 15. http://dc0d32.blogspot.com/search/label/gas
+ 16. http://dc0d32.blogspot.com/search/label/gcc
+ 17. http://dc0d32.blogspot.com/search/label/kernel
+ 18. http://dc0d32.blogspot.com/search/label/osdev
+ 19. https://www.blogger.com/profile/06904019980664523275
+ 20. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1276605767623#c7537756629084768590
+ 21. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=7537756629084768590
+ 22. https://www.blogger.com/profile/17992312956580227764
+ 23. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1292917257855#c7916645211913421716
+ 24. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=7916645211913421716
+ 25. https://www.blogger.com/profile/17992312956580227764
+ 26. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1292920505936#c6914976194912758237
+ 27. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=6914976194912758237
+ 28. https://www.blogger.com/profile/17992312956580227764
+ 29. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1292924802000#c3509490007866551116
+ 30. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=3509490007866551116
+ 31. https://www.blogger.com/profile/15716533043357974705
+ 32. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1292939196737#c8552773997968662641
+ 33. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=8552773997968662641
+ 34. https://www.blogger.com/profile/17992312956580227764
+ 35. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1292991102048#c3691472389082213083
+ 36. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=3691472389082213083
+ 37. https://www.blogger.com/profile/04546527990311411722
+ 38. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1299934567958#c8861407369344586215
+ 39. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=8861407369344586215
+ 40. https://www.blogger.com/profile/13931402888317484377
+ 41. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1302999537204#c1796379189090357880
+ 42. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=1796379189090357880
+ 43. https://www.blogger.com/profile/10664008816666619973
+ 44. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1305925792707#c309698377277262219
+ 45. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=309698377277262219
+ 46. https://www.blogger.com/profile/15716533043357974705
+ 47. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1305927124224#c7619831240140737017
+ 48. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=7619831240140737017
+ 49. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1322169605658#c1693276418345545837
+ 50. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=1693276418345545837
+ 51. https://www.blogger.com/profile/15716533043357974705
+ 52. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1322188282688#c6259496576598783959
+ 53. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=6259496576598783959
+ 54. https://www.blogger.com/profile/17992312956580227764
+ 55. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1323015134989#c3945832952459710949
+ 56. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=3945832952459710949
+ 57. https://www.blogger.com/profile/15716533043357974705
+ 58. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1323146939454#c2066813635755540091
+ 59. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=2066813635755540091
+ 60. https://www.blogger.com/profile/17992312956580227764
+ 61. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1324737140263#c7908397772486068687
+ 62. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=7908397772486068687
+ 63. https://www.blogger.com/profile/17992312956580227764
+ 64. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1343616406999#c8117194716929362278
+ 65. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=8117194716929362278
+ 66. https://www.blogger.com/profile/00410755183408310829
+ 67. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1366435009449#c1258130037332531147
+ 68. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=1258130037332531147
+ 69. https://www.blogger.com/profile/15716533043357974705
+ 70. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1366517094365#c8123329091843779139
+ 71. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=8123329091843779139
+ 72. https://www.blogger.com/profile/17234059656421576642
+ 73. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1384327289704#c4134298820836763034
+ 74. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=4134298820836763034
+ 75. https://www.blogger.com/profile/16683260877229099988
+ 76. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1401480336214#c455729903293178418
+ 77. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=455729903293178418
+ 78. https://www.blogger.com/profile/07765096042053323038
+ 79. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1423148995473#c7126019925062815723
+ 80. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=7126019925062815723
+ 81. https://www.blogger.com/profile/01833111909520604012
+ 82. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1484904386672#c7038618115198897417
+ 83. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=7038618115198897417
+ 84. https://www.blogger.com/profile/01833111909520604012
+ 85. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1484904424918#c1284220459583274955
+ 86. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=1284220459583274955
+ 87. https://www.blogger.com/profile/07765096042053323038
+ 88. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1423149010339#c2287827836063649127
+ 89. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=2287827836063649127
+ 90. https://www.blogger.com/profile/17596900636592437710
+ 91. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html?showComment=1454858010555#c4198004625201390279
+ 92. https://www.blogger.com/delete-comment.g?blogID=35813921&postID=4198004625201390279
+ 93. http://dc0d32.blogspot.com/2010/06/cold-boot-attack.html
+ 94. http://dc0d32.blogspot.com/2010/05/how-not-to-look-like-fool-on-facebook.html
+ 95. http://dc0d32.blogspot.com/
+ 96. http://dc0d32.blogspot.com/feeds/6370208028763486595/comments/default
+ 97. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html
+ 98. http://dc0d32.blogspot.com/2012/02/writing-kernel-in-windows-with-visual.html
+ 99. http://dc0d32.blogspot.com/2010/03/debugging-kernel-with-qemu-and-gdb.html
+ 100. javascript:void(0)
+ 101. http://dc0d32.blogspot.com/2012/
+ 102. javascript:void(0)
+ 103. http://dc0d32.blogspot.com/2012/02/
+ 104. javascript:void(0)
+ 105. http://dc0d32.blogspot.com/2010/
+ 106. javascript:void(0)
+ 107. http://dc0d32.blogspot.com/2010/06/
+ 108. http://dc0d32.blogspot.com/2010/06/cold-boot-attack.html
+ 109. http://dc0d32.blogspot.com/2010/06/real-mode-in-c-with-gcc-writing.html
+ 110. javascript:void(0)
+ 111. http://dc0d32.blogspot.com/2010/05/
+ 112. javascript:void(0)
+ 113. http://dc0d32.blogspot.com/2010/04/
+ 114. javascript:void(0)
+ 115. http://dc0d32.blogspot.com/2010/03/
+ 116. javascript:void(0)
+ 117. http://dc0d32.blogspot.com/2010/02/
+ 118. javascript:void(0)
+ 119. http://dc0d32.blogspot.com/2009/
+ 120. javascript:void(0)
+ 121. http://dc0d32.blogspot.com/2009/12/
+ 122. javascript:void(0)
+ 123. http://dc0d32.blogspot.com/2009/11/
+ 124. javascript:void(0)
+ 125. http://dc0d32.blogspot.com/2009/09/
+ 126. javascript:void(0)
+ 127. http://dc0d32.blogspot.com/2009/08/
+ 128. javascript:void(0)
+ 129. http://dc0d32.blogspot.com/2009/07/
+ 130. javascript:void(0)
+ 131. http://dc0d32.blogspot.com/2009/02/
+ 132. javascript:void(0)
+ 133. http://dc0d32.blogspot.com/2009/01/
+ 134. javascript:void(0)
+ 135. http://dc0d32.blogspot.com/2008/
+ 136. javascript:void(0)
+ 137. http://dc0d32.blogspot.com/2008/11/
+ 138. javascript:void(0)
+ 139. http://dc0d32.blogspot.com/2008/10/
+ 140. javascript:void(0)
+ 141. http://dc0d32.blogspot.com/2008/08/
+ 142. javascript:void(0)
+ 143. http://dc0d32.blogspot.com/2008/06/
+ 144. http://dc0d32.blogspot.com/search/label/linux
+ 145. http://dc0d32.blogspot.com/search/label/kernel
+ 146. http://dc0d32.blogspot.com/search/label/8800
+ 147. http://dc0d32.blogspot.com/search/label/FreeBSD
+ 148. http://dc0d32.blogspot.com/search/label/gdb
+ 149. http://dc0d32.blogspot.com/search/label/nvidia
+ 150. http://dc0d32.blogspot.com/search/label/osdev
+ 151. http://dc0d32.blogspot.com/search/label/windows%207
+ 152. http://dc0d32.blogspot.com/search/label/bochs
+ 153. http://dc0d32.blogspot.com/search/label/boot
+ 154. http://dc0d32.blogspot.com/search/label/bootloader
+ 155. http://dc0d32.blogspot.com/search/label/debug
+ 156. http://dc0d32.blogspot.com/search/label/dual%20boot
+ 157. http://dc0d32.blogspot.com/search/label/gas
+ 158. http://dc0d32.blogspot.com/search/label/gcc
+ 159. http://dc0d32.blogspot.com/search/label/overclock
+ 160. http://dc0d32.blogspot.com/search/label/pidgin
+ 161. http://dc0d32.blogspot.com/search/label/windows
+ 162. http://dc0d32.blogspot.com/search/label/windows%20server%202008
+ 163. http://dc0d32.blogspot.com/search/label/2k8
+ 164. http://dc0d32.blogspot.com/search/label/3DMark
+ 165. http://dc0d32.blogspot.com/search/label/3DMark%20vantage
+ 166. http://dc0d32.blogspot.com/search/label/820
+ 167. http://dc0d32.blogspot.com/search/label/DRAM
+ 168. http://dc0d32.blogspot.com/search/label/Directx%2010
+ 169. http://dc0d32.blogspot.com/search/label/Dirext%2011
+ 170. http://dc0d32.blogspot.com/search/label/Java
+ 171. http://dc0d32.blogspot.com/search/label/OpenJDK
+ 172. http://dc0d32.blogspot.com/search/label/OpenOffice
+ 173. http://dc0d32.blogspot.com/search/label/Pentium%20D
+ 174. http://dc0d32.blogspot.com/search/label/RAID
+ 175. http://dc0d32.blogspot.com/search/label/Sun
+ 176. http://dc0d32.blogspot.com/search/label/UUID
+ 177. http://dc0d32.blogspot.com/search/label/Unicode
+ 178. http://dc0d32.blogspot.com/search/label/VirtualBox
+ 179. http://dc0d32.blogspot.com/search/label/X
+ 180. http://dc0d32.blogspot.com/search/label/Xorg
+ 181. http://dc0d32.blogspot.com/search/label/ageis
+ 182. http://dc0d32.blogspot.com/search/label/assembler
+ 183. http://dc0d32.blogspot.com/search/label/authentication
+ 184. http://dc0d32.blogspot.com/search/label/bash
+ 185. http://dc0d32.blogspot.com/search/label/c
+ 186. http://dc0d32.blogspot.com/search/label/coolbits
+ 187. http://dc0d32.blogspot.com/search/label/dx10
+ 188. http://dc0d32.blogspot.com/search/label/fedora
+ 189. http://dc0d32.blogspot.com/search/label/fortune
+ 190. http://dc0d32.blogspot.com/search/label/gdm
+ 191. http://dc0d32.blogspot.com/search/label/ghostscript
+ 192. http://dc0d32.blogspot.com/search/label/gnome
+ 193. http://dc0d32.blogspot.com/search/label/google
+ 194. http://dc0d32.blogspot.com/search/label/gs
+ 195. http://dc0d32.blogspot.com/search/label/gtalk
+ 196. http://dc0d32.blogspot.com/search/label/heat%20sink
+ 197. http://dc0d32.blogspot.com/search/label/invisible
+ 198. http://dc0d32.blogspot.com/search/label/jabber
+ 199. http://dc0d32.blogspot.com/search/label/kde
+ 200. http://dc0d32.blogspot.com/search/label/latex
+ 201. http://dc0d32.blogspot.com/search/label/lvm
+ 202. http://dc0d32.blogspot.com/search/label/lyx
+ 203. http://dc0d32.blogspot.com/search/label/mount
+ 204. http://dc0d32.blogspot.com/search/label/networked%20audio
+ 205. http://dc0d32.blogspot.com/search/label/networked%20sound
+ 206. http://dc0d32.blogspot.com/search/label/nvclock
+ 207. http://dc0d32.blogspot.com/search/label/oolatex
+ 208. http://dc0d32.blogspot.com/search/label/ooolatex
+ 209. http://dc0d32.blogspot.com/search/label/perl
+ 210. http://dc0d32.blogspot.com/search/label/phonon
+ 211. http://dc0d32.blogspot.com/search/label/physics
+ 212. http://dc0d32.blogspot.com/search/label/physx
+ 213. http://dc0d32.blogspot.com/search/label/picasa
+ 214. http://dc0d32.blogspot.com/search/label/plugin
+ 215. http://dc0d32.blogspot.com/search/label/proxy
+ 216. http://dc0d32.blogspot.com/search/label/pulseaudio
+ 217. http://dc0d32.blogspot.com/search/label/qemu
+ 218. http://dc0d32.blogspot.com/search/label/rsync
+ 219. http://dc0d32.blogspot.com/search/label/rtp
+ 220. http://dc0d32.blogspot.com/search/label/scp
+ 221. http://dc0d32.blogspot.com/search/label/scp%20stdin
+ 222. http://dc0d32.blogspot.com/search/label/security
+ 223. http://dc0d32.blogspot.com/search/label/server
+ 224. http://dc0d32.blogspot.com/search/label/shell
+ 225. http://dc0d32.blogspot.com/search/label/squid
+ 226. http://dc0d32.blogspot.com/search/label/ssh
+ 227. http://dc0d32.blogspot.com/search/label/sync
+ 228. http://dc0d32.blogspot.com/search/label/tar
+ 229. http://dc0d32.blogspot.com/search/label/udev
+ 230. http://dc0d32.blogspot.com/search/label/unix
+ 231. http://dc0d32.blogspot.com/search/label/xdm
+ 232. http://dc0d32.blogspot.com/search/label/xfce
+ 233. http://dc0d32.blogspot.com/search/label/xmpp
+ 234. http://dc0d32.blogspot.com/search/label/xorg.conf
+ 235. http://dc0d32.blogspot.com/search/label/zsh
+ 236. http://www.statcounter.com/blogger/
+ 237. http://www.istockphoto.com/portfolio/5ugarless?platform=blogger
+ 238. https://www.blogger.com/
+
+ Hidden links:
+ 240. https://www.blogger.com/post-edit.g?blogID=35813921&postID=6370208028763486595&from=pencil
+ 241. https://www.blogger.com/comment/frame/35813921?po=6370208028763486595&hl=en
diff --git a/todo/doc/fossbytes_com_redditor-boots-linux-kernel-5-8-0-rc2-floppy-intel-80486.txt b/todo/doc/fossbytes_com_redditor-boots-linux-kernel-5-8-0-rc2-floppy-intel-80486.txt
new file mode 100644
index 0000000..72c3e20
--- /dev/null
+++ b/todo/doc/fossbytes_com_redditor-boots-linux-kernel-5-8-0-rc2-floppy-intel-80486.txt
@@ -0,0 +1,339 @@
+ #[1]Fossbytes Feed [2]Fossbytes Comments Feed [3]Fossbytes
+ Redditor Boots Linux Kernel 5.8 On 30-Year-Old Intel Processor via
+ Floppy Disk Comments Feed [4]alternate [5]alternate [6]alternate
+
+ [7]Skip to content
+
+ [8]FOSSBYTES TECH SIMPLIFIED LOGO
+ [9]Facebook
+ [10]Twitter
+ [11]Instagram
+
+ * [12]News
+ * [13]Geek
+ * [14]Hacked
+ * [15]Gaming
+ * [16]Drive X
+ * [17]How To
+ * [18]Top X
+ * [19]Tools
+
+ Menu
+
+ * [20]News
+ * [21]Geek
+ * [22]Hacked
+ * [23]Gaming
+ * [24]Drive X
+ * [25]How To
+ * [26]Top X
+ * [27]Tools
+
+ Search
+ ____________________
+
+ Menu
+
+ * [28]News
+ * [29]Geek
+ * [30]Hacked
+ * [31]Gaming
+ * [32]Drive X
+ * [33]How To
+ * [34]Top X
+ * [35]Tools
+
+ [36]FOSSBYTES TECH SIMPLIFIED LOGO
+ Search
+ ____________________
+ Close
+
+ News
+
+ * [37]Privacy
+ * [38]Facebook
+ * [39]Apple
+ * [40]Google
+ * [41]Microsoft
+ * [42]Linux
+ * [43]Tesla
+ * [44]EV
+
+ Menu
+
+ * [45]Privacy
+ * [46]Facebook
+ * [47]Apple
+ * [48]Google
+ * [49]Microsoft
+ * [50]Linux
+ * [51]Tesla
+ * [52]EV
+
+ * [53]Geek, [54]News
+
+Redditor Boots Linux Kernel 5.8 On 30-Year-Old Intel Processor via Floppy
+Disk
+
+ * [55]Sarvottam Kumar
+ * [56]June 30, 2020
+
+ Redditor Booted Linux Kernel 5.8.0-rc2+ From A Floppy On Intel 80486
+
+ Do you remember your first PC on which you booted Linux from floppy?
+ Well, Floppy disk is almost dead. The majority of people now use USB
+ sticks or DVDs to install Linux distros on their PCs. However, retro
+ enthusiasts love to revive their old hardware and relive the flashback.
+
+ Recently, a Redditor who goes by the name
+ `FozzTexx' [57]demonstrated the latest stable Linux Kernel 5.8.0-rc2+
+ running from his floppy disk. He successfully booted a tiny kernel on a
+ 30-year-old 32-bit Intel 80486 (i486 or 486) CPU.
+
+ Now, if you think Linux kernel has dropped support for anything older
+ than i686, it may prove you wrong. You know that freedom,
+ customization, and support for legacy hardware are the characteristics
+ of Linux.
+
+ Speaking of booting OS, if you're 90s kid, you may remember installing
+ Linux with boot floppies or installation CDs offered by Linux distros.
+ Nowadays, the scenario has changed as people download the ISO from
+ official websites and install it by creating a bootable USB or DVD.
+
+ In case you're still wondering about booting Linux from floppy, a retro
+ enthusiasts FozzTexx did it using a single 1.44MB floppy disk on his
+ i486 CPU.
+ Booting Linux from 1.44MB floppy Booting Linux from 1.44MB floppy
+
+ He pulled the fresh Kernel 5.8.0-rc2+ from the git repo and shrank it
+ to fit on a floppy using make tinyconfig. Then, he booted it on 486
+ into a busybox shell using rootfs.cpio.gz from Aboriginal Linux.
+
+ The tiny kernel surely misses network support or any other functional
+ support. Though it may seem useless, the Redditor also added options
+ like IDE support. Surprisingly, when he attached a hard drive and
+ booted into the shell, he could see the drive as connected and its full
+ capacity. You can see the result in the picture below.
+ Hard disk attached to 486 CPU Hard disk attached to 486 CPU
+
+ You can also read the Twitter [58]thread describing how he started
+ loading kernel 5.8 on a 486 from floppy.
+
+ This is for all you [59]#floppy lovers out there: Linux 5.8.0-rc2+
+ pulled fresh from the git repo this morning booting into a busybox
+ shell using the rootfs.cpio.gz from Aboriginal Linux.
+ [60]#RetroComputing [61]pic.twitter.com/zaB9lpggPX
+ -- FozzTexx (@FozzTexx) [62]June 28, 2020
+
+ If you also have a 486 system lying around and want to load Linux, you
+ can follow the tutorial which he'll put on his [63]blog site soon.
+ [64]Sarvottam Kumar
+ [65]
+
+Sarvottam Kumar
+
+ Being a fossbyter, I cover the latest releases, news, information, and
+ trends in the world of Linux and Open source.
+
+Leave a Comment [66]Cancel Reply
+
+ Your email address will not be published. Required fields are marked *
+
+ Type here..
+ _____________________________________________
+ _____________________________________________
+ _____________________________________________
+ _____________________________________________
+ _____________________________________________
+ _____________________________________________
+ _____________________________________________
+ _____________________________________________
+
+ Name* ______________________________
+
+ Email* ______________________________
+
+ Website ______________________________
+
+ [ ] Save my name, email, and website in this browser for the next time
+ I comment.
+
+ Post Comment
+
+News & Opeds
+
+ Tesla Model S and Model X
+
+[67]Why NHTSA Is Asking Tesla To Recall 158,000 Model S And Model X?
+
+ Netflix Movies 2021 All 70 Movies Coming To Netflix This Year
+
+[68]Netflix Movies 2021: All 70 Movies Releasing On Netflix This Year
+
+ Official Best of CES 2021 awards
+
+[69]CES 2021 Awards: This Is The Tech To Look Forward To In 2021
+
+ More From Fossbytes
+
+Popular In News
+
+ How do electric cars work_
+
+[70]How Do Electric Cars Work? Electric Motors And Batteries Explained
+
+ Netflix Movies 2021 All 70 Movies Coming To Netflix This Year
+
+[71]Netflix Movies 2021: All 70 Movies Releasing On Netflix This Year
+
+ Security-Focused Tails OS Plans To Switch From Xorg To Wayland
+
+[72]Security-Focused Tails OS Plans To Switch From Xorg To Wayland
+
+[73]CloudLinux Renames Its CentOS Alternative `Project Lenix' To `AlmaLinux'
+
+ FOSSBYTES
+
+ * [74]About Us
+ * [75]Privacy Policy
+ * [76]Cookie Policy
+
+ [77]Facebook
+ [78]Twitter
+ [79]Instagram
+ * [80]Contact Us
+ * [81]Our Team
+ * [82]Work With Us
+
+Learn Something New Today
+
+ [83]Academy
+
+ Fossbytes Media Pvt Ltd 2021
+
+ FOSSBYTES
+
+ [84]Facebook
+ [85]Twitter
+ [86]Instagram
+
+Learn Something New Today
+
+ [87]Academy
+ * [88]About Us
+ * [89]Privacy Policy
+ * [90]Cookie Policy
+
+ * [91]Contact Us
+ * [92]Our Team
+ * [93]Work With Us
+
+ Fossbytes Media Pvt Ltd 2021
+
+ Scroll to Top
+
+References
+
+ Visible links:
+ 1. https://fossbytes.com/feed/
+ 2. https://fossbytes.com/comments/feed/
+ 3. https://fossbytes.com/redditor-boots-linux-kernel-5-8-0-rc2-floppy-intel-80486/feed/
+ 4. https://fossbytes.com/wp-json/wp/v2/posts/173003
+ 5. https://fossbytes.com/wp-json/oembed/1.0/embed?url=https%3A%2F%2Ffossbytes.com%2Fredditor-boots-linux-kernel-5-8-0-rc2-floppy-intel-80486%2F
+ 6. https://fossbytes.com/wp-json/oembed/1.0/embed?url=https%3A%2F%2Ffossbytes.com%2Fredditor-boots-linux-kernel-5-8-0-rc2-floppy-intel-80486%2F&format=xml
+ 7. https://fossbytes.com/redditor-boots-linux-kernel-5-8-0-rc2-floppy-intel-80486/#content
+ 8. https://fossbytes.com/
+ 9. https://www.facebook.com/fossbytes
+ 10. https://twitter.com/Fossbytes14
+ 11. https://instagram.com/fossbytes
+ 12. https://fossbytes.com/category/news/
+ 13. https://fossbytes.com/category/geek/
+ 14. https://fossbytes.com/category/security/
+ 15. https://fossbytes.com/category/entertainment/gaming-and-sports/
+ 16. https://fossbytes.com/category/transportation/
+ 17. https://fossbytes.com/category/how-to/
+ 18. https://fossbytes.com/category/more/lists/
+ 19. https://fossbytes.com/tools/
+ 20. https://fossbytes.com/category/news/
+ 21. https://fossbytes.com/category/geek/
+ 22. https://fossbytes.com/category/security/
+ 23. https://fossbytes.com/category/entertainment/gaming-and-sports/
+ 24. https://fossbytes.com/category/transportation/
+ 25. https://fossbytes.com/category/how-to/
+ 26. https://fossbytes.com/category/more/lists/
+ 27. https://fossbytes.com/tools/
+ 28. https://fossbytes.com/category/news/
+ 29. https://fossbytes.com/category/geek/
+ 30. https://fossbytes.com/category/security/
+ 31. https://fossbytes.com/category/entertainment/gaming-and-sports/
+ 32. https://fossbytes.com/category/transportation/
+ 33. https://fossbytes.com/category/how-to/
+ 34. https://fossbytes.com/category/more/lists/
+ 35. https://fossbytes.com/tools/
+ 36. https://fossbytes.com/
+ 37. https://fossbytes.com/tag/privacy/
+ 38. https://fossbytes.com/tag/facebook/
+ 39. https://fossbytes.com/tag/apple/
+ 40. https://fossbytes.com/tag/google/
+ 41. https://fossbytes.com/tag/microsoft/
+ 42. https://fossbytes.com/tag/linux/
+ 43. https://fossbytes.com/tag/tesla/
+ 44. https://fossbytes.com/tag/electric-cars/
+ 45. https://fossbytes.com/tag/privacy/
+ 46. https://fossbytes.com/tag/facebook/
+ 47. https://fossbytes.com/tag/apple/
+ 48. https://fossbytes.com/tag/google/
+ 49. https://fossbytes.com/tag/microsoft/
+ 50. https://fossbytes.com/tag/linux/
+ 51. https://fossbytes.com/tag/tesla/
+ 52. https://fossbytes.com/tag/electric-cars/
+ 53. https://fossbytes.com/category/geek/
+ 54. https://fossbytes.com/category/news/
+ 55. https://fossbytes.com/author/sarvottam/
+ 56. https://fossbytes.com/2020/06/30/
+ 57. https://www.reddit.com/r/retrobattlestations/comments/hi3kbq/booting_linux_kernel_580rc2_from_a_single_floppy/
+ 58. https://twitter.com/FozzTexx/status/1277251556010676225
+ 59. https://twitter.com/hashtag/floppy?src=hash&ref_src=twsrc%5Etfw
+ 60. https://twitter.com/hashtag/RetroComputing?src=hash&ref_src=twsrc%5Etfw
+ 61. https://t.co/zaB9lpggPX
+ 62. https://twitter.com/FozzTexx/status/1277296880813105152?ref_src=twsrc%5Etfw
+ 63. https://www.insentricity.com/
+ 64. https://fossbytes.com/author/sarvottam/
+ 65. https://fossbytes.com/author/sarvottam/
+ 66. https://fossbytes.com/redditor-boots-linux-kernel-5-8-0-rc2-floppy-intel-80486/#respond
+ 67. https://fossbytes.com/why-nhtsa-is-asking-tesla-to-recall-158000-model-s-and-model-x/
+ 68. https://fossbytes.com/netflix-movies-2021-all-70-movies-releasing-on-netflix-this-year/
+ 69. https://fossbytes.com/official-best-of-ces-2021/
+ 70. https://fossbytes.com/how-do-electric-cars-work-electric-motors-and-batteries-explained/
+ 71. https://fossbytes.com/netflix-movies-2021-all-70-movies-releasing-on-netflix-this-year/
+ 72. https://fossbytes.com/security-focused-tails-os-plans-to-switch-from-xorg-to-wayland/
+ 73. https://fossbytes.com/cloudlinux-renames-centos-alternative-project-lenix-to-almalinux/
+ 74. https://fossbytes.com/about/
+ 75. https://fossbytes.com/privacy-policy/
+ 76. https://fossbytes.com/cookie-policy-for-fossbytes/
+ 77. https://www.facebook.com/fossbytes
+ 78. https://twitter.com/Fossbytes14
+ 79. https://instagram.com/fossbytes
+ 80. https://fossbytes.com/contact-us/
+ 81. https://fossbytes.com/fossbytes-team/
+ 82. https://fossbytes.com/jobs/
+ 83. https://academy.fossbytes.com/
+ 84. https://www.facebook.com/fossbytes
+ 85. https://twitter.com/Fossbytes14
+ 86. https://instagram.com/fossbytes
+ 87. https://academy.fossbytes.com/
+ 88. https://fossbytes.com/about/
+ 89. https://fossbytes.com/privacy-policy/
+ 90. https://fossbytes.com/cookie-policy-for-fossbytes/
+ 91. https://fossbytes.com/contact-us/
+ 92. https://fossbytes.com/fossbytes-team/
+ 93. https://fossbytes.com/jobs/
+
+ Hidden links:
+ 95. https://fossbytes.com/why-nhtsa-is-asking-tesla-to-recall-158000-model-s-and-model-x/
+ 96. https://fossbytes.com/netflix-movies-2021-all-70-movies-releasing-on-netflix-this-year/
+ 97. https://fossbytes.com/official-best-of-ces-2021/
+ 98. https://fossbytes.com/how-do-electric-cars-work-electric-motors-and-batteries-explained/
+ 99. https://fossbytes.com/netflix-movies-2021-all-70-movies-releasing-on-netflix-this-year/
+ 100. https://fossbytes.com/security-focused-tails-os-plans-to-switch-from-xorg-to-wayland/
+ 101. https://fossbytes.com/cloudlinux-renames-centos-alternative-project-lenix-to-almalinux/
diff --git a/todo/doc/people.freedesktop.org_~narmstrong_meson_drm_doc_admin-guide_initrd.txt b/todo/doc/people.freedesktop.org_~narmstrong_meson_drm_doc_admin-guide_initrd.txt
new file mode 100644
index 0000000..0c2351e
--- /dev/null
+++ b/todo/doc/people.freedesktop.org_~narmstrong_meson_drm_doc_admin-guide_initrd.txt
@@ -0,0 +1,453 @@
+ #[1]The Linux Kernel 4.11.0-rc4-00191-g7de6e5d documentation [2]The
+ Linux kernel user's and administrator's guide [3]Linux Serial Console
+ [4]Rules on how to access information in sysfs
+
+Navigation
+
+ * [5]index
+ * [6]next |
+ * [7]previous |
+ * [8]The Linux Kernel 4.11.0-rc4-00191-g7de6e5d documentation
+ * [9]The Linux kernel user's and administrator's guide
+
+Using the initial RAM disk (initrd)[10]
+
+ Written 1996,2000 by Werner Almesberger
+ <[11]werner.almesberger@epfl.ch> and Hans Lermen <[12]lermen@fgan.de>
+
+ initrd provides the capability to load a RAM disk by the boot loader.
+ This RAM disk can then be mounted as the root file system and programs
+ can be run from it. Afterwards, a new root file system can be mounted
+ from a different device. The previous root (from initrd) is then moved
+ to a directory and can be subsequently unmounted.
+
+ initrd is mainly designed to allow system startup to occur in two
+ phases, where the kernel comes up with a minimum set of compiled-in
+ drivers, and where additional modules are loaded from initrd.
+
+ This document gives a brief overview of the use of initrd. A more
+ detailed discussion of the boot process can be found in [13][1].
+
+Operation[14]
+
+ When using initrd, the system typically boots as follows:
+
+ 1. the boot loader loads the kernel and the initial RAM disk
+ 2. the kernel converts initrd into a "normal" RAM disk and frees the
+ memory used by initrd
+ 3. if the root device is not /dev/ram0, the old (deprecated)
+ change_root procedure is followed. see the "Obsolete root change
+ mechanism" section below.
+ 4. root device is mounted. if it is /dev/ram0, the initrd image is
+ then mounted as root
+ 5. /sbin/init is executed (this can be any valid executable, including
+ shell scripts; it is run with uid 0 and can do basically everything
+ init can do).
+ 6. init mounts the "real" root file system
+ 7. init places the root file system at the root directory using the
+ pivot_root system call
+ 8. init execs the /sbin/init on the new root filesystem, performing
+ the usual boot sequence
+ 9. the initrd file system is removed
+
+ Note that changing the root directory does not involve unmounting it.
+ It is therefore possible to leave processes running on initrd during
+ that procedure. Also note that file systems mounted under initrd
+ continue to be accessible.
+
+Boot command-line options[15]
+
+ initrd adds the following new options:
+initrd=<path> (e.g. LOADLIN)
+
+ Loads the specified file as the initial RAM disk. When using LILO, you
+ have to specify the RAM disk image file in /etc/lilo.conf, using the
+ INITRD configuration variable.
+
+noinitrd
+
+ initrd data is preserved but it is not converted to a RAM disk and
+ the "normal" root file system is mounted. initrd data can be read
+ from /dev/initrd. Note that the data in initrd can have any structure
+ in this case and doesn't necessarily have to be a file system image.
+ This option is used mainly for debugging.
+
+ Note: /dev/initrd is read-only and it can only be used once. As soon
+ as the last process has closed it, all data is freed and /dev/initrd
+ can't be opened anymore.
+
+root=/dev/ram0
+
+ initrd is mounted as root, and the normal boot procedure is followed,
+ with the RAM disk mounted as root.
+
+Compressed cpio images[16]
+
+ Recent kernels have support for populating a ramdisk from a compressed
+ cpio archive. On such systems, the creation of a ramdisk image doesn't
+ need to involve special block devices or loopbacks; you merely create a
+ directory on disk with the desired initrd content, cd to that
+ directory, and run (as an example):
+find . | cpio --quiet -H newc -o | gzip -9 -n > /boot/imagefile.img
+
+ Examining the contents of an existing image file is just as simple:
+mkdir /tmp/imagefile
+cd /tmp/imagefile
+gzip -cd /boot/imagefile.img | cpio -imd --quiet
+
+Installation[17]
+
+ First, a directory for the initrd file system has to be created on the
+ "normal" root file system, e.g.:
+# mkdir /initrd
+
+ The name is not relevant. More details can be found on the
+ pivot_root(2) man page.
+
+ If the root file system is created during the boot procedure (i.e. if
+ you're building an install floppy), the root file system creation
+ procedure should create the /initrd directory.
+
+ If initrd will not be mounted in some cases, its content is still
+ accessible if the following device has been created:
+# mknod /dev/initrd b 1 250
+# chmod 400 /dev/initrd
+
+ Second, the kernel has to be compiled with RAM disk support and with
+ support for the initial RAM disk enabled. Also, at least all components
+ needed to execute programs from initrd (e.g. executable format and file
+ system) must be compiled into the kernel.
+
+ Third, you have to create the RAM disk image. This is done by creating
+ a file system on a block device, copying files to it as needed, and
+ then copying the content of the block device to the initrd file. With
+ recent kernels, at least three types of devices are suitable for that:
+
+ * a floppy disk (works everywhere but it's painfully slow)
+ * a RAM disk (fast, but allocates physical memory)
+ * a loopback device (the most elegant solution)
+
+ We'll describe the loopback device method:
+
+ 1. make sure loopback block devices are configured into the kernel
+ 2. create an empty file system of the appropriate size, e.g.:
+# dd if=/dev/zero of=initrd bs=300k count=1
+# mke2fs -F -m0 initrd
+
+ (if space is critical, you may want to use the Minix FS instead of
+ Ext2)
+ 3. mount the file system, e.g.:
+# mount -t ext2 -o loop initrd /mnt
+
+ 4. create the console device:
+# mkdir /mnt/dev
+# mknod /mnt/dev/console c 5 1
+
+ 5. copy all the files that are needed to properly use the initrd
+ environment. Don't forget the most important file, /sbin/init
+ Note
+ /sbin/init permissions must include "x" (execute).
+ 6. correct operation the initrd environment can frequently be tested
+ even without rebooting with the command:
+# chroot /mnt /sbin/init
+
+ This is of course limited to initrds that do not interfere with the
+ general system state (e.g. by reconfiguring network interfaces,
+ overwriting mounted devices, trying to start already running
+ demons, etc. Note however that it is usually possible to use
+ pivot_root in such a chroot'ed initrd environment.)
+ 7. unmount the file system:
+# umount /mnt
+
+ 8. the initrd is now in the file "initrd". Optionally, it can now be
+ compressed:
+# gzip -9 initrd
+
+ For experimenting with initrd, you may want to take a rescue floppy and
+ only add a symbolic link from /sbin/init to /bin/sh. Alternatively, you
+ can try the experimental newlib environment [18][2] to create a small
+ initrd.
+
+ Finally, you have to boot the kernel and load initrd. Almost all Linux
+ boot loaders support initrd. Since the boot process is still compatible
+ with an older mechanism, the following boot command line parameters
+ have to be given:
+root=/dev/ram0 rw
+
+ (rw is only necessary if writing to the initrd file system.)
+
+ With LOADLIN, you simply execute:
+LOADLIN <kernel> initrd=<disk_image>
+
+ e.g.:
+LOADLIN C:\LINUX\BZIMAGE initrd=C:\LINUX\INITRD.GZ root=/dev/ram0 rw
+
+ With LILO, you add the option INITRD=<path> to either the global
+ section or to the section of the respective kernel in /etc/lilo.conf,
+ and pass the options using APPEND, e.g.:
+image = /bzImage
+ initrd = /boot/initrd.gz
+ append = "root=/dev/ram0 rw"
+
+ and run /sbin/lilo
+
+ For other boot loaders, please refer to the respective documentation.
+
+ Now you can boot and enjoy using initrd.
+
+Changing the root device[19]
+
+ When finished with its duties, init typically changes the root device
+ and proceeds with starting the Linux system on the "real" root device.
+
+ The procedure involves the following steps:
+
+ + mounting the new root file system
+ + turning it into the root file system
+ + removing all accesses to the old (initrd) root file system
+ + unmounting the initrd file system and de-allocating the RAM
+ disk
+
+ Mounting the new root file system is easy: it just needs to be mounted
+ on a directory under the current root. Example:
+# mkdir /new-root
+# mount -o ro /dev/hda1 /new-root
+
+ The root change is accomplished with the pivot_root system call, which
+ is also available via the pivot_root utility (see pivot_root(8) man
+ page; pivot_root is distributed with util-linux version 2.10h or higher
+ [20][3]). pivot_root moves the current root to a directory under the
+ new root, and puts the new root at its place. The directory for the old
+ root must exist before calling pivot_root. Example:
+# cd /new-root
+# mkdir initrd
+# pivot_root . initrd
+
+ Now, the init process may still access the old root via its executable,
+ shared libraries, standard input/output/error, and its current root
+ directory. All these references are dropped by the following command:
+# exec chroot . what-follows <dev/console >dev/console 2>&1
+
+ Where what-follows is a program under the new root, e.g. /sbin/init If
+ the new root file system will be used with udev and has no valid /dev
+ directory, udev must be initialized before invoking chroot in order to
+ provide /dev/console.
+
+ Note: implementation details of pivot_root may change with time. In
+ order to ensure compatibility, the following points should be observed:
+
+ * before calling pivot_root, the current directory of the invoking
+ process should point to the new root directory
+ * use . as the first argument, and the _relative_ path of the
+ directory for the old root as the second argument
+ * a chroot program must be available under the old and the new root
+ * chroot to the new root afterwards
+ * use relative paths for dev/console in the exec command
+
+ Now, the initrd can be unmounted and the memory allocated by the RAM
+ disk can be freed:
+# umount /initrd
+# blockdev --flushbufs /dev/ram0
+
+ It is also possible to use initrd with an NFS-mounted root, see the
+ pivot_root(8) man page for details.
+
+Usage scenarios[21]
+
+ The main motivation for implementing initrd was to allow for modular
+ kernel configuration at system installation. The procedure would work
+ as follows:
+
+ 1. system boots from floppy or other media with a minimal kernel (e.g.
+ support for RAM disks, initrd, a.out, and the Ext2 FS) and loads
+ initrd
+ 2. /sbin/init determines what is needed to (1) mount the "real" root
+ FS (i.e. device type, device drivers, file system) and (2) the
+ distribution media (e.g. CD-ROM, network, tape, ...). This can be
+ done by asking the user, by auto-probing, or by using a hybrid
+ approach.
+ 3. /sbin/init loads the necessary kernel modules
+ 4. /sbin/init creates and populates the root file system (this doesn't
+ have to be a very usable system yet)
+ 5. /sbin/init invokes pivot_root to change the root file system and
+ execs - via chroot - a program that continues the installation
+ 6. the boot loader is installed
+ 7. the boot loader is configured to load an initrd with the set of
+ modules that was used to bring up the system (e.g. /initrd can be
+ modified, then unmounted, and finally, the image is written from
+ /dev/ram0 or /dev/rd/0 to a file)
+ 8. now the system is bootable and additional installation tasks can be
+ performed
+
+ The key role of initrd here is to re-use the configuration data during
+ normal system operation without requiring the use of a bloated
+ "generic" kernel or re-compiling or re-linking the kernel.
+
+ A second scenario is for installations where Linux runs on systems with
+ different hardware configurations in a single administrative domain. In
+ such cases, it is desirable to generate only a small set of kernels
+ (ideally only one) and to keep the system-specific part of
+ configuration information as small as possible. In this case, a common
+ initrd could be generated with all the necessary modules. Then, only
+ /sbin/init or a file read by it would have to be different.
+
+ A third scenario is more convenient recovery disks, because information
+ like the location of the root FS partition doesn't have to be provided
+ at boot time, but the system loaded from initrd can invoke a
+ user-friendly dialog and it can also perform some sanity checks (or
+ even some form of auto-detection).
+
+ Last not least, CD-ROM distributors may use it for better installation
+ from CD, e.g. by using a boot floppy and bootstrapping a bigger RAM
+ disk via initrd from CD; or by booting via a loader like LOADLIN or
+ directly from the CD-ROM, and loading the RAM disk from CD without need
+ of floppies.
+
+Obsolete root change mechanism[22]
+
+ The following mechanism was used before the introduction of pivot_root.
+ Current kernels still support it, but you should _not_ rely on its
+ continued availability.
+
+ It works by mounting the "real" root device (i.e. the one set with rdev
+ in the kernel image or with root=... at the boot command line) as the
+ root file system when linuxrc exits. The initrd file system is then
+ unmounted, or, if it is still busy, moved to a directory /initrd, if
+ such a directory exists on the new root file system.
+
+ In order to use this mechanism, you do not have to specify the boot
+ command options root, init, or rw. (If specified, they will affect the
+ real root file system, not the initrd environment.)
+
+ If /proc is mounted, the "real" root device can be changed from within
+ linuxrc by writing the number of the new root FS device to the special
+ file /proc/sys/kernel/real-root-dev, e.g.:
+# echo 0x301 >/proc/sys/kernel/real-root-dev
+
+ Note that the mechanism is incompatible with NFS and similar file
+ systems.
+
+ This old, deprecated mechanism is commonly called change_root, while
+ the new, supported mechanism is called pivot_root.
+
+Mixed change_root and pivot_root mechanism[23]
+
+ In case you did not want to use root=/dev/ram0 to trigger the
+ pivot_root mechanism, you may create both /linuxrc and /sbin/init in
+ your initrd image.
+
+ /linuxrc would contain only the following:
+#! /bin/sh
+mount -n -t proc proc /proc
+echo 0x0100 >/proc/sys/kernel/real-root-dev
+umount -n /proc
+
+ Once linuxrc exited, the kernel would mount again your initrd as root,
+ this time executing /sbin/init. Again, it would be the duty of this
+ init to build the right environment (maybe using the root= device
+ passed on the cmdline) before the final execution of the real
+ /sbin/init.
+
+Resources[24]
+
+ [25][1] Almesberger, Werner; "Booting Linux: The History and the
+ Future" [26]http://www.almesberger.net/cv/papers/ols2k-9.ps.gz
+ [27][2] newlib package (experimental), with initrd example
+ [28]https://www.sourceware.org/newlib/
+ [29][3] util-linux: Miscellaneous utilities for Linux
+ [30]https://www.kernel.org/pub/linux/utils/util-linux/
+
+[31]Table Of Contents
+
+ * [32]Using the initial RAM disk (initrd)
+ + [33]Operation
+ + [34]Boot command-line options
+ + [35]Compressed cpio images
+ + [36]Installation
+ + [37]Changing the root device
+ + [38]Usage scenarios
+ + [39]Obsolete root change mechanism
+ + [40]Mixed change_root and pivot_root mechanism
+ + [41]Resources
+
+Previous topic
+
+ [42]Rules on how to access information in sysfs
+
+Next topic
+
+ [43]Linux Serial Console
+
+This Page
+
+ * [44]Show Source
+
+Quick search
+
+ ____________________ Go
+
+ Enter search terms or a module, class or function name.
+
+Navigation
+
+ * [45]index
+ * [46]next |
+ * [47]previous |
+ * [48]The Linux Kernel 4.11.0-rc4-00191-g7de6e5d documentation
+ * [49]The Linux kernel user's and administrator's guide
+
+ Copyright The kernel development community. Created using [50]Sphinx
+ 1.2.2.
+
+References
+
+ 1. https://people.freedesktop.org/~narmstrong/meson_drm_doc/index.html
+ 2. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/index.html
+ 3. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/serial-console.html
+ 4. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/sysfs-rules.html
+ 5. https://people.freedesktop.org/~narmstrong/meson_drm_doc/genindex.html
+ 6. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/serial-console.html
+ 7. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/sysfs-rules.html
+ 8. https://people.freedesktop.org/~narmstrong/meson_drm_doc/index.html
+ 9. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/index.html
+ 10. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#using-the-initial-ram-disk-initrd
+ 11. mailto:werner.almesberger%40epfl.ch
+ 12. mailto:lermen%40fgan.de
+ 13. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#f1
+ 14. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#operation
+ 15. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#boot-command-line-options
+ 16. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#compressed-cpio-images
+ 17. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#installation
+ 18. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#f2
+ 19. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#changing-the-root-device
+ 20. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#f3
+ 21. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#usage-scenarios
+ 22. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#obsolete-root-change-mechanism
+ 23. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#mixed-change-root-and-pivot-root-mechanism
+ 24. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#resources
+ 25. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#id1
+ 26. http://www.almesberger.net/cv/papers/ols2k-9.ps.gz
+ 27. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#id2
+ 28. https://www.sourceware.org/newlib/
+ 29. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#id3
+ 30. https://www.kernel.org/pub/linux/utils/util-linux/
+ 31. https://people.freedesktop.org/~narmstrong/meson_drm_doc/index.html
+ 32. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html
+ 33. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#operation
+ 34. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#boot-command-line-options
+ 35. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#compressed-cpio-images
+ 36. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#installation
+ 37. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#changing-the-root-device
+ 38. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#usage-scenarios
+ 39. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#obsolete-root-change-mechanism
+ 40. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#mixed-change-root-and-pivot-root-mechanism
+ 41. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/initrd.html#resources
+ 42. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/sysfs-rules.html
+ 43. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/serial-console.html
+ 44. https://people.freedesktop.org/~narmstrong/meson_drm_doc/_sources/admin-guide/initrd.txt
+ 45. https://people.freedesktop.org/~narmstrong/meson_drm_doc/genindex.html
+ 46. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/serial-console.html
+ 47. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/sysfs-rules.html
+ 48. https://people.freedesktop.org/~narmstrong/meson_drm_doc/index.html
+ 49. https://people.freedesktop.org/~narmstrong/meson_drm_doc/admin-guide/index.html
+ 50. http://sphinx-doc.org/
diff --git a/todo/doc/www.kernel.org_doc_html_latest_x86_boot.txt b/todo/doc/www.kernel.org_doc_html_latest_x86_boot.txt
new file mode 100644
index 0000000..0ef56f7
--- /dev/null
+++ b/todo/doc/www.kernel.org_doc_html_latest_x86_boot.txt
@@ -0,0 +1,2349 @@
+ #[1]Index [2]Search [3]2. DeviceTree Booting [4]x86-specific
+ Documentation
+
+[5]The Linux Kernel
+
+ 6.3.0-rc6
+
+Quick search
+
+ ____________________ Go
+
+Contents
+
+ [X]
+ * [6]A guide to the Kernel Development Process
+ * [7]Submitting patches: the essential guide to getting your code
+ into the kernel
+ * [8]Code of conduct
+ * [9]Kernel Maintainer Handbook
+ * [10]All development-process docs
+
+ * [11]Core API Documentation
+ * [12]Driver implementer's API guide
+ * [13]Kernel subsystem documentation
+ * [14]Locking in the kernel
+
+ * [15]Linux kernel licensing rules
+ * [16]How to write kernel documentation
+ * [17]Development tools for the kernel
+ * [18]Kernel Testing Guide
+ * [19]Kernel Hacking Guides
+ * [20]Linux Tracing Technologies
+ * [21]fault-injection
+ * [22]Kernel Livepatching
+ * [23]Rust
+
+ * [24]The Linux kernel user's and administrator's guide
+ * [25]The kernel build system
+ * [26]Reporting issues
+ * [27]User-space tools
+ * [28]The Linux kernel user-space API guide
+
+ * [29]The Linux kernel firmware guide
+ * [30]Open Firmware and Devicetree
+
+ * [31]CPU Architectures
+ + [32]ARC architecture
+ + [33]ARM Architecture
+ + [34]ARM64 Architecture
+ + [35]IA-64 Architecture
+ + [36]LoongArch Architecture
+ + [37]m68k Architecture
+ + [38]MIPS-specific Documentation
+ + [39]Nios II Specific Documentation
+ + [40]OpenRISC Architecture
+ + [41]PA-RISC Architecture
+ + [42]powerpc
+ + [43]RISC-V architecture
+ + [44]s390 Architecture
+ + [45]SuperH Interfaces Guide
+ + [46]Sparc Architecture
+ + [47]x86-specific Documentation
+ o [48]1. The Linux/x86 Boot Protocol
+ o [49]2. DeviceTree Booting
+ o [50]3. x86 Feature Flags
+ o [51]4. x86 Topology
+ o [52]5. Kernel level exception handling
+ o [53]6. Kernel Stacks
+ o [54]7. Kernel Entries
+ o [55]8. Early Printk
+ o [56]9. ORC unwinder
+ o [57]10. Zero Page
+ o [58]11. The TLB
+ o [59]12. MTRR (Memory Type Range Register) control
+ o [60]13. PAT (Page Attribute Table)
+ o [61]14. Hardware-Feedback Interface for scheduling on
+ Intel Hardware
+ o [62]15. x86 IOMMU Support
+ o [63]16. Intel(R) TXT Overview
+ o [64]17. AMD Memory Encryption
+ o [65]18. AMD HSMP interface
+ o [66]19. Intel Trust Domain Extensions (TDX)
+ o [67]20. Page Table Isolation (PTI)
+ o [68]21. Microarchitectural Data Sampling (MDS) mitigation
+ o [69]22. The Linux Microcode Loader
+ o [70]23. User Interface for Resource Control feature
+ o [71]24. TSX Async Abort (TAA) mitigation
+ o [72]25. Bus lock detection and handling
+ o [73]26. USB Legacy support
+ o [74]27. i386 Support
+ o [75]28. x86_64 Support
+ o [76]29. In-Field Scan
+ o [77]30. Shared Virtual Addressing (SVA) with ENQCMD
+ o [78]31. Software Guard eXtensions (SGX)
+ o [79]32. Feature status on x86 architecture
+ o [80]33. x86-specific ELF Auxiliary Vectors
+ o [81]34. Using XSTATE features in user space applications
+ + [82]Xtensa Architecture
+
+ * [83]Unsorted Documentation
+
+ * [84]Translations
+
+This Page
+
+ * [85]Show Source
+
+1. The Linux/x86 Boot Protocol[86]
+
+ On the x86 platform, the Linux kernel uses a rather complicated boot
+ convention. This has evolved partially due to historical aspects, as
+ well as the desire in the early days to have the kernel itself be a
+ bootable image, the complicated PC memory model and due to changed
+ expectations in the PC industry caused by the effective demise of
+ real-mode DOS as a mainstream operating system.
+
+ Currently, the following versions of the Linux/x86 boot protocol exist.
+
+ Old kernels
+
+ zImage/Image support only. Some very early kernels may not even support
+ a command line.
+
+ Protocol 2.00
+
+ (Kernel 1.3.73) Added bzImage and initrd support, as well as a
+ formalized way to communicate between the boot loader and the kernel.
+ setup.S made relocatable, although the traditional setup area still
+ assumed writable.
+
+ Protocol 2.01
+
+ (Kernel 1.3.76) Added a heap overrun warning.
+
+ Protocol 2.02
+
+ (Kernel 2.4.0-test3-pre3) New command line protocol. Lower the
+ conventional memory ceiling. No overwrite of the traditional setup
+ area, thus making booting safe for systems which use the EBDA from SMM
+ or 32-bit BIOS entry points. zImage deprecated but still supported.
+
+ Protocol 2.03
+
+ (Kernel 2.4.18-pre1) Explicitly makes the highest possible initrd
+ address available to the bootloader.
+
+ Protocol 2.04
+
+ (Kernel 2.6.14) Extend the syssize field to four bytes.
+
+ Protocol 2.05
+
+ (Kernel 2.6.20) Make protected mode kernel relocatable. Introduce
+ relocatable_kernel and kernel_alignment fields.
+
+ Protocol 2.06
+
+ (Kernel 2.6.22) Added a field that contains the size of the boot
+ command line.
+
+ Protocol 2.07
+
+ (Kernel 2.6.24) Added paravirtualised boot protocol. Introduced
+ hardware_subarch and hardware_subarch_data and KEEP_SEGMENTS flag in
+ load_flags.
+
+ Protocol 2.08
+
+ (Kernel 2.6.26) Added crc32 checksum and ELF format payload. Introduced
+ payload_offset and payload_length fields to aid in locating the
+ payload.
+
+ Protocol 2.09
+
+ (Kernel 2.6.26) Added a field of 64-bit physical pointer to single
+ linked list of struct setup_data.
+
+ Protocol 2.10
+
+ (Kernel 2.6.31) Added a protocol for relaxed alignment beyond the
+ kernel_alignment added, new init_size and pref_address fields. Added
+ extended boot loader IDs.
+
+ Protocol 2.11
+
+ (Kernel 3.6) Added a field for offset of EFI handover protocol entry
+ point.
+
+ Protocol 2.12
+
+ (Kernel 3.8) Added the xloadflags field and extension fields to struct
+ boot_params for loading bzImage and ramdisk above 4G in 64bit.
+
+ Protocol 2.13
+
+ (Kernel 3.14) Support 32- and 64-bit flags being set in xloadflags to
+ support booting a 64-bit kernel from 32-bit EFI
+
+ Protocol 2.14
+
+ BURNT BY INCORRECT COMMIT ae7e1238e68f2a472a125673ab506d49158c1889
+ (x86/boot: Add ACPI RSDP address to setup_header) DO NOT USE!!! ASSUME
+ SAME AS 2.13.
+
+ Protocol 2.15
+
+ (Kernel 5.5) Added the kernel_info and kernel_info.setup_type_max.
+
+ Note
+
+ The protocol version number should be changed only if the setup header
+ is changed. There is no need to update the version number if
+ boot_params or kernel_info are changed. Additionally, it is recommended
+ to use xloadflags (in this case the protocol version number should not
+ be updated either) or kernel_info to communicate supported Linux kernel
+ features to the boot loader. Due to very limited space available in the
+ original setup header every update to it should be considered with
+ great care. Starting from the protocol 2.15 the primary way to
+ communicate things to the boot loader is the kernel_info.
+
+1.1. Memory Layout[87]
+
+ The traditional memory map for the kernel loader, used for Image or
+ zImage kernels, typically looks like:
+ | |
+0A0000 +------------------------+
+ | Reserved for BIOS | Do not use. Reserved for BIOS EBDA.
+09A000 +------------------------+
+ | Command line |
+ | Stack/heap | For use by the kernel real-mode code.
+098000 +------------------------+
+ | Kernel setup | The kernel real-mode code.
+090200 +------------------------+
+ | Kernel boot sector | The kernel legacy boot sector.
+090000 +------------------------+
+ | Protected-mode kernel | The bulk of the kernel image.
+010000 +------------------------+
+ | Boot loader | <- Boot sector entry point 0000:7C00
+001000 +------------------------+
+ | Reserved for MBR/BIOS |
+000800 +------------------------+
+ | Typically used by MBR |
+000600 +------------------------+
+ | BIOS use only |
+000000 +------------------------+
+
+ When using bzImage, the protected-mode kernel was relocated to 0x100000
+ ("high memory"), and the kernel real-mode block (boot sector, setup,
+ and stack/heap) was made relocatable to any address between 0x10000 and
+ end of low memory. Unfortunately, in protocols 2.00 and 2.01 the
+ 0x90000+ memory range is still used internally by the kernel; the 2.02
+ protocol resolves that problem.
+
+ It is desirable to keep the "memory ceiling" - the highest point in low
+ memory touched by the boot loader - as low as possible, since some
+ newer BIOSes have begun to allocate some rather large amounts of
+ memory, called the Extended BIOS Data Area, near the top of low memory.
+ The boot loader should use the "INT 12h" BIOS call to verify how much
+ low memory is available.
+
+ Unfortunately, if INT 12h reports that the amount of memory is too low,
+ there is usually nothing the boot loader can do but to report an error
+ to the user. The boot loader should therefore be designed to take up as
+ little space in low memory as it reasonably can. For zImage or old
+ bzImage kernels, which need data written into the 0x90000 segment, the
+ boot loader should make sure not to use memory above the 0x9A000 point;
+ too many BIOSes will break above that point.
+
+ For a modern bzImage kernel with boot protocol version >= 2.02, a
+ memory layout like the following is suggested:
+ ~ ~
+ | 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 mar
+k)
+ X+10000 +------------------------+
+ | Stack/heap | For use by the kernel real-mode co
+de.
+ X+08000 +------------------------+
+ | Kernel setup | The kernel real-mode code.
+ | Kernel boot sector | The kernel legacy boot sector.
+ X +------------------------+
+ | Boot loader | <- Boot sector entry point 0000:7C
+00
+ 001000 +------------------------+
+ | Reserved for MBR/BIOS |
+ 000800 +------------------------+
+ | Typically used by MBR |
+ 000600 +------------------------+
+ | BIOS use only |
+ 000000 +------------------------+
+
+... where the address X is as low as the design of the boot loader permits.
+
+1.2. The Real-Mode Kernel Header[88]
+
+ In the following text, and anywhere in the kernel boot sequence, "a
+ sector" refers to 512 bytes. It is independent of the actual sector
+ size of the underlying medium.
+
+ The first step in loading a Linux kernel should be to load the
+ real-mode code (boot sector and setup code) and then examine the
+ following header at offset 0x01f1. The real-mode code can total up to
+ 32K, although the boot loader may choose to load only the first two
+ sectors (1K) and then examine the bootup sector size.
+
+ The header looks like:
+
+ Offset/Size
+
+ Proto
+
+ Name
+
+ Meaning
+
+ 01F1/1
+
+ ALL(1)
+
+ setup_sects
+
+ The size of the setup in sectors
+
+ 01F2/2
+
+ ALL
+
+ root_flags
+
+ If set, the root is mounted readonly
+
+ 01F4/4
+
+ 2.04+(2)
+
+ syssize
+
+ The size of the 32-bit code in 16-byte paras
+
+ 01F8/2
+
+ ALL
+
+ ram_size
+
+ DO NOT USE - for bootsect.S use only
+
+ 01FA/2
+
+ ALL
+
+ vid_mode
+
+ Video mode control
+
+ 01FC/2
+
+ ALL
+
+ root_dev
+
+ Default root device number
+
+ 01FE/2
+
+ ALL
+
+ boot_flag
+
+ 0xAA55 magic number
+
+ 0200/2
+
+ 2.00+
+
+ jump
+
+ Jump instruction
+
+ 0202/4
+
+ 2.00+
+
+ header
+
+ Magic signature "HdrS"
+
+ 0206/2
+
+ 2.00+
+
+ version
+
+ Boot protocol version supported
+
+ 0208/4
+
+ 2.00+
+
+ realmode_swtch
+
+ Boot loader hook (see below)
+
+ 020C/2
+
+ 2.00+
+
+ start_sys_seg
+
+ The load-low segment (0x1000) (obsolete)
+
+ 020E/2
+
+ 2.00+
+
+ kernel_version
+
+ Pointer to kernel version string
+
+ 0210/1
+
+ 2.00+
+
+ type_of_loader
+
+ Boot loader identifier
+
+ 0211/1
+
+ 2.00+
+
+ loadflags
+
+ Boot protocol option flags
+
+ 0212/2
+
+ 2.00+
+
+ setup_move_size
+
+ Move to high memory size (used with hooks)
+
+ 0214/4
+
+ 2.00+
+
+ code32_start
+
+ Boot loader hook (see below)
+
+ 0218/4
+
+ 2.00+
+
+ ramdisk_image
+
+ initrd load address (set by boot loader)
+
+ 021C/4
+
+ 2.00+
+
+ ramdisk_size
+
+ initrd size (set by boot loader)
+
+ 0220/4
+
+ 2.00+
+
+ bootsect_kludge
+
+ DO NOT USE - for bootsect.S use only
+
+ 0224/2
+
+ 2.01+
+
+ heap_end_ptr
+
+ Free memory after setup end
+
+ 0226/1
+
+ 2.02+(3)
+
+ ext_loader_ver
+
+ Extended boot loader version
+
+ 0227/1
+
+ 2.02+(3)
+
+ ext_loader_type
+
+ Extended boot loader ID
+
+ 0228/4
+
+ 2.02+
+
+ cmd_line_ptr
+
+ 32-bit pointer to the kernel command line
+
+ 022C/4
+
+ 2.03+
+
+ initrd_addr_max
+
+ Highest legal initrd address
+
+ 0230/4
+
+ 2.05+
+
+ kernel_alignment
+
+ Physical addr alignment required for kernel
+
+ 0234/1
+
+ 2.05+
+
+ relocatable_kernel
+
+ Whether kernel is relocatable or not
+
+ 0235/1
+
+ 2.10+
+
+ min_alignment
+
+ Minimum alignment, as a power of two
+
+ 0236/2
+
+ 2.12+
+
+ xloadflags
+
+ Boot protocol option flags
+
+ 0238/4
+
+ 2.06+
+
+ cmdline_size
+
+ Maximum size of the kernel command line
+
+ 023C/4
+
+ 2.07+
+
+ hardware_subarch
+
+ Hardware subarchitecture
+
+ 0240/8
+
+ 2.07+
+
+ hardware_subarch_data
+
+ Subarchitecture-specific data
+
+ 0248/4
+
+ 2.08+
+
+ payload_offset
+
+ Offset of kernel payload
+
+ 024C/4
+
+ 2.08+
+
+ payload_length
+
+ Length of kernel payload
+
+ 0250/8
+
+ 2.09+
+
+ setup_data
+
+ 64-bit physical pointer to linked list of struct setup_data
+
+ 0258/8
+
+ 2.10+
+
+ pref_address
+
+ Preferred loading address
+
+ 0260/4
+
+ 2.10+
+
+ init_size
+
+ Linear memory required during initialization
+
+ 0264/4
+
+ 2.11+
+
+ handover_offset
+
+ Offset of handover entry point
+
+ 0268/4
+
+ 2.15+
+
+ kernel_info_offset
+
+ Offset of the kernel_info
+
+ Note
+ 1. For backwards compatibility, if the setup_sects field contains 0,
+ the real value is 4.
+ 2. For boot protocol prior to 2.04, the upper two bytes of the syssize
+ field are unusable, which means the size of a bzImage kernel cannot
+ be determined.
+ 3. Ignored, but safe to set, for boot protocols 2.02-2.09.
+
+ If the "HdrS" (0x53726448) magic number is not found at offset 0x202,
+ the boot protocol version is "old". Loading an old kernel, the
+ following parameters should be assumed:
+Image type = zImage
+initrd not supported
+Real-mode kernel must be located at 0x90000.
+
+ Otherwise, the "version" field contains the protocol version, e.g.
+ protocol version 2.01 will contain 0x0201 in this field. When setting
+ fields in the header, you must make sure only to set fields supported
+ by the protocol version in use.
+
+1.3. Details of Header Fields[89]
+
+ For each field, some are information from the kernel to the bootloader
+ ("read"), some are expected to be filled out by the bootloader
+ ("write"), and some are expected to be read and modified by the
+ bootloader ("modify").
+
+ All general purpose boot loaders should write the fields marked
+ (obligatory). Boot loaders who want to load the kernel at a nonstandard
+ address should fill in the fields marked (reloc); other boot loaders
+ can ignore those fields.
+
+ The byte order of all fields is littleendian (this is x86, after all.)
+
+ Field name:
+
+ setup_sects
+
+ Type:
+
+ read
+
+ Offset/size:
+
+ 0x1f1/1
+
+ Protocol:
+
+ ALL
+
+ The size of the setup code in 512-byte sectors. If this field is 0, the
+ real value is 4. The real-mode code consists of the boot sector (always
+ one 512-byte sector) plus the setup code.
+
+ Field name:
+
+ root_flags
+
+ Type:
+
+ modify (optional)
+
+ Offset/size:
+
+ 0x1f2/2
+
+ Protocol:
+
+ ALL
+
+ If this field is nonzero, the root defaults to readonly. The use of
+ this field is deprecated; use the "ro" or "rw" options on the command
+ line instead.
+
+ Field name:
+
+ syssize
+
+ Type:
+
+ read
+
+ Offset/size:
+
+ 0x1f4/4 (protocol 2.04+) 0x1f4/2 (protocol ALL)
+
+ Protocol:
+
+ 2.04+
+
+ The size of the protected-mode code in units of 16-byte paragraphs. For
+ protocol versions older than 2.04 this field is only two bytes wide,
+ and therefore cannot be trusted for the size of a kernel if the
+ LOAD_HIGH flag is set.
+
+ Field name:
+
+ ram_size
+
+ Type:
+
+ kernel internal
+
+ Offset/size:
+
+ 0x1f8/2
+
+ Protocol:
+
+ ALL
+
+ This field is obsolete.
+
+ Field name:
+
+ vid_mode
+
+ Type:
+
+ modify (obligatory)
+
+ Offset/size:
+
+ 0x1fa/2
+
+ Please see the section on SPECIAL COMMAND LINE OPTIONS.
+
+ Field name:
+
+ root_dev
+
+ Type:
+
+ modify (optional)
+
+ Offset/size:
+
+ 0x1fc/2
+
+ Protocol:
+
+ ALL
+
+ The default root device device number. The use of this field is
+ deprecated, use the "root=" option on the command line instead.
+
+ Field name:
+
+ boot_flag
+
+ Type:
+
+ read
+
+ Offset/size:
+
+ 0x1fe/2
+
+ Protocol:
+
+ ALL
+
+ Contains 0xAA55. This is the closest thing old Linux kernels have to a
+ magic number.
+
+ Field name:
+
+ jump
+
+ Type:
+
+ read
+
+ Offset/size:
+
+ 0x200/2
+
+ Protocol:
+
+ 2.00+
+
+ Contains an x86 jump instruction, 0xEB followed by a signed offset
+ relative to byte 0x202. This can be used to determine the size of the
+ header.
+
+ Field name:
+
+ header
+
+ Type:
+
+ read
+
+ Offset/size:
+
+ 0x202/4
+
+ Protocol:
+
+ 2.00+
+
+ Contains the magic number "HdrS" (0x53726448).
+
+ Field name:
+
+ version
+
+ Type:
+
+ read
+
+ Offset/size:
+
+ 0x206/2
+
+ Protocol:
+
+ 2.00+
+
+ Contains the boot protocol version, in (major << 8)+minor format, e.g.
+ 0x0204 for version 2.04, and 0x0a11 for a hypothetical version 10.17.
+
+ Field name:
+
+ realmode_swtch
+
+ Type:
+
+ modify (optional)
+
+ Offset/size:
+
+ 0x208/4
+
+ Protocol:
+
+ 2.00+
+
+ Boot loader hook (see ADVANCED BOOT LOADER HOOKS below.)
+
+ Field name:
+
+ start_sys_seg
+
+ Type:
+
+ read
+
+ Offset/size:
+
+ 0x20c/2
+
+ Protocol:
+
+ 2.00+
+
+ The load low segment (0x1000). Obsolete.
+
+ Field name:
+
+ kernel_version
+
+ Type:
+
+ read
+
+ Offset/size:
+
+ 0x20e/2
+
+ Protocol:
+
+ 2.00+
+
+ If set to a nonzero value, contains a pointer to a NUL-terminated
+ human-readable kernel version number string, less 0x200. This can be
+ used to display the kernel version to the user. This value should be
+ less than (0x200*setup_sects).
+
+ For example, if this value is set to 0x1c00, the kernel version number
+ string can be found at offset 0x1e00 in the kernel file. This is a
+ valid value if and only if the "setup_sects" field contains the value
+ 15 or higher, as:
+0x1c00 < 15*0x200 (= 0x1e00) but
+0x1c00 >= 14*0x200 (= 0x1c00)
+
+0x1c00 >> 9 = 14, So the minimum value for setup_secs is 15.
+
+ Field name:
+
+ type_of_loader
+
+ Type:
+
+ write (obligatory)
+
+ Offset/size:
+
+ 0x210/1
+
+ Protocol:
+
+ 2.00+
+
+ If your boot loader has an assigned id (see table below), enter 0xTV
+ here, where T is an identifier for the boot loader and V is a version
+ number. Otherwise, enter 0xFF here.
+
+ For boot loader IDs above T = 0xD, write T = 0xE to this field and
+ write the extended ID minus 0x10 to the ext_loader_type field.
+ Similarly, the ext_loader_ver field can be used to provide more than
+ four bits for the bootloader version.
+
+ For example, for T = 0x15, V = 0x234, write:
+type_of_loader <- 0xE4
+ext_loader_type <- 0x05
+ext_loader_ver <- 0x23
+
+ Assigned boot loader ids (hexadecimal):
+
+ 0
+
+ LILO (0x00 reserved for pre-2.00 bootloader)
+
+ 1
+
+ Loadlin
+
+ 2
+
+ bootsect-loader (0x20, all other values reserved)
+
+ 3
+
+ Syslinux
+
+ 4
+
+ Etherboot/gPXE/iPXE
+
+ 5
+
+ ELILO
+
+ 7
+
+ GRUB
+
+ 8
+
+ U-Boot
+
+ 9
+
+ Xen
+
+ A
+
+ Gujin
+
+ B
+
+ Qemu
+
+ C
+
+ Arcturus Networks uCbootloader
+
+ D
+
+ kexec-tools
+
+ E
+
+ Extended (see ext_loader_type)
+
+ F
+
+ Special (0xFF = undefined)
+
+ 10
+
+ Reserved
+
+ 11
+
+ Minimal Linux Bootloader <[90]http://sebastian-plotz.blogspot.de>
+
+ 12
+
+ OVMF UEFI virtualization stack
+
+ 13
+
+ barebox
+
+ Please contact <[91]hpa@zytor.com> if you need a bootloader ID value
+ assigned.
+
+ Field name:
+
+ loadflags
+
+ Type:
+
+ modify (obligatory)
+
+ Offset/size:
+
+ 0x211/1
+
+ Protocol:
+
+ 2.00+
+
+ This field is a bitmask.
+
+ Bit 0 (read): LOADED_HIGH
+
+ * If 0, the protected-mode code is loaded at 0x10000.
+ * If 1, the protected-mode code is loaded at 0x100000.
+
+ Bit 1 (kernel internal): KASLR_FLAG
+
+ * Used internally by the compressed kernel to communicate KASLR
+ status to kernel proper.
+
+ + If 1, KASLR enabled.
+ + If 0, KASLR disabled.
+
+ Bit 5 (write): QUIET_FLAG
+
+ * If 0, print early messages.
+ * If 1, suppress early messages.
+
+ This requests to the kernel (decompressor and early kernel) to not
+ write early messages that require accessing the display hardware
+ directly.
+
+ Bit 6 (obsolete): KEEP_SEGMENTS
+
+ Protocol: 2.07+
+ * This flag is obsolete.
+
+ 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.
+
+ Field name:
+
+ setup_move_size
+
+ Type:
+
+ modify (obligatory)
+
+ Offset/size:
+
+ 0x212/2
+
+ Protocol:
+
+ 2.00-2.01
+
+ When using protocol 2.00 or 2.01, if the real mode kernel is not loaded
+ at 0x90000, it gets moved there later in the loading sequence. Fill in
+ this field if you want additional data (such as the kernel command
+ line) moved in addition to the real-mode kernel itself.
+
+ The unit is bytes starting with the beginning of the boot sector.
+
+ This field is can be ignored when the protocol is 2.02 or higher, or if
+ the real-mode code is loaded at 0x90000.
+
+ Field name:
+
+ code32_start
+
+ Type:
+
+ modify (optional, reloc)
+
+ Offset/size:
+
+ 0x214/4
+
+ Protocol:
+
+ 2.00+
+
+ The address to jump to in protected mode. This defaults to the load
+ address of the kernel, and can be used by the boot loader to determine
+ the proper load address.
+
+ This field can be modified for two purposes:
+
+ 1. as a boot loader hook (see Advanced Boot Loader Hooks below.)
+ 2. if a bootloader which does not install a hook loads a relocatable
+ kernel at a nonstandard address it will have to modify this field
+ to point to the load address.
+
+ Field name:
+
+ ramdisk_image
+
+ Type:
+
+ write (obligatory)
+
+ Offset/size:
+
+ 0x218/4
+
+ Protocol:
+
+ 2.00+
+
+ The 32-bit linear address of the initial ramdisk or ramfs. Leave at
+ zero if there is no initial ramdisk/ramfs.
+
+ Field name:
+
+ ramdisk_size
+
+ Type:
+
+ write (obligatory)
+
+ Offset/size:
+
+ 0x21c/4
+
+ Protocol:
+
+ 2.00+
+
+ Size of the initial ramdisk or ramfs. Leave at zero if there is no
+ initial ramdisk/ramfs.
+
+ Field name:
+
+ bootsect_kludge
+
+ Type:
+
+ kernel internal
+
+ Offset/size:
+
+ 0x220/4
+
+ Protocol:
+
+ 2.00+
+
+ This field is obsolete.
+
+ Field name:
+
+ heap_end_ptr
+
+ Type:
+
+ write (obligatory)
+
+ Offset/size:
+
+ 0x224/2
+
+ Protocol:
+
+ 2.01+
+
+ Set this field to the offset (from the beginning of the real-mode code)
+ of the end of the setup stack/heap, minus 0x0200.
+
+ Field name:
+
+ ext_loader_ver
+
+ Type:
+
+ write (optional)
+
+ Offset/size:
+
+ 0x226/1
+
+ Protocol:
+
+ 2.02+
+
+ This field is used as an extension of the version number in the
+ type_of_loader field. The total version number is considered to be
+ (type_of_loader & 0x0f) + (ext_loader_ver << 4).
+
+ The use of this field is boot loader specific. If not written, it is
+ zero.
+
+ Kernels prior to 2.6.31 did not recognize this field, but it is safe to
+ write for protocol version 2.02 or higher.
+
+ Field name:
+
+ ext_loader_type
+
+ Type:
+
+ write (obligatory if (type_of_loader & 0xf0) == 0xe0)
+
+ Offset/size:
+
+ 0x227/1
+
+ Protocol:
+
+ 2.02+
+
+ This field is used as an extension of the type number in type_of_loader
+ field. If the type in type_of_loader is 0xE, then the actual type is
+ (ext_loader_type + 0x10).
+
+ This field is ignored if the type in type_of_loader is not 0xE.
+
+ Kernels prior to 2.6.31 did not recognize this field, but it is safe to
+ write for protocol version 2.02 or higher.
+
+ Field name:
+
+ cmd_line_ptr
+
+ Type:
+
+ write (obligatory)
+
+ Offset/size:
+
+ 0x228/4
+
+ Protocol:
+
+ 2.02+
+
+ Set this field to the linear address of the kernel command line. The
+ kernel command line can be located anywhere between the end of the
+ setup heap and 0xA0000; it does not have to be located in the same 64K
+ segment as the real-mode code itself.
+
+ Fill in this field even if your boot loader does not support a command
+ line, in which case you can point this to an empty string (or better
+ yet, to the string "auto".) If this field is left at zero, the kernel
+ will assume that your boot loader does not support the 2.02+ protocol.
+
+ Field name:
+
+ initrd_addr_max
+
+ Type:
+
+ read
+
+ Offset/size:
+
+ 0x22c/4
+
+ Protocol:
+
+ 2.03+
+
+ The maximum address that may be occupied by the initial ramdisk/ramfs
+ contents. For boot protocols 2.02 or earlier, this field is not
+ present, and the maximum address is 0x37FFFFFF. (This address is
+ defined as the address of the highest safe byte, so if your ramdisk is
+ exactly 131072 bytes long and this field is 0x37FFFFFF, you can start
+ your ramdisk at 0x37FE0000.)
+
+ Field name:
+
+ kernel_alignment
+
+ Type:
+
+ read/modify (reloc)
+
+ Offset/size:
+
+ 0x230/4
+
+ Protocol:
+
+ 2.05+ (read), 2.10+ (modify)
+
+ Alignment unit required by the kernel (if relocatable_kernel is true.)
+ A relocatable kernel that is loaded at an alignment incompatible with
+ the value in this field will be realigned during kernel initialization.
+
+ Starting with protocol version 2.10, this reflects the kernel alignment
+ preferred for optimal performance; it is possible for the loader to
+ modify this field to permit a lesser alignment. See the min_alignment
+ and pref_address field below.
+
+ Field name:
+
+ relocatable_kernel
+
+ Type:
+
+ read (reloc)
+
+ Offset/size:
+
+ 0x234/1
+
+ Protocol:
+
+ 2.05+
+
+ If this field is nonzero, the protected-mode part of the kernel can be
+ loaded at any address that satisfies the kernel_alignment field. After
+ loading, the boot loader must set the code32_start field to point to
+ the loaded code, or to a boot loader hook.
+
+ Field name:
+
+ min_alignment
+
+ Type:
+
+ read (reloc)
+
+ Offset/size:
+
+ 0x235/1
+
+ Protocol:
+
+ 2.10+
+
+ This field, if nonzero, indicates as a power of two the minimum
+ alignment required, as opposed to preferred, by the kernel to boot. If
+ a boot loader makes use of this field, it should update the
+ kernel_alignment field with the alignment unit desired; typically:
+kernel_alignment = 1 << min_alignment
+
+ There may be a considerable performance cost with an excessively
+ misaligned kernel. Therefore, a loader should typically try each
+ power-of-two alignment from kernel_alignment down to this alignment.
+
+ Field name:
+
+ xloadflags
+
+ Type:
+
+ read
+
+ Offset/size:
+
+ 0x236/2
+
+ Protocol:
+
+ 2.12+
+
+ This field is a bitmask.
+
+ Bit 0 (read): XLF_KERNEL_64
+
+ * If 1, this kernel has the legacy 64-bit entry point at 0x200.
+
+ Bit 1 (read): XLF_CAN_BE_LOADED_ABOVE_4G
+
+ * If 1, kernel/boot_params/cmdline/ramdisk can be above 4G.
+
+ Bit 2 (read): XLF_EFI_HANDOVER_32
+
+ * If 1, the kernel supports the 32-bit EFI handoff entry point given
+ at handover_offset.
+
+ Bit 3 (read): XLF_EFI_HANDOVER_64
+
+ * If 1, the kernel supports the 64-bit EFI handoff entry point given
+ at handover_offset + 0x200.
+
+ Bit 4 (read): XLF_EFI_KEXEC
+
+ * If 1, the kernel supports kexec EFI boot with EFI runtime support.
+
+ Field name:
+
+ cmdline_size
+
+ Type:
+
+ read
+
+ Offset/size:
+
+ 0x238/4
+
+ Protocol:
+
+ 2.06+
+
+ The maximum size of the command line without the terminating zero. This
+ means that the command line can contain at most cmdline_size
+ characters. With protocol version 2.05 and earlier, the maximum size
+ was 255.
+
+ Field name:
+
+ hardware_subarch
+
+ Type:
+
+ write (optional, defaults to x86/PC)
+
+ Offset/size:
+
+ 0x23c/4
+
+ Protocol:
+
+ 2.07+
+
+ In a paravirtualized environment the hardware low level architectural
+ pieces such as interrupt handling, page table handling, and accessing
+ process control registers needs to be done differently.
+
+ This field allows the bootloader to inform the kernel we are in one one
+ of those environments.
+
+ 0x00000000
+
+ The default x86/PC environment
+
+ 0x00000001
+
+ lguest
+
+ 0x00000002
+
+ Xen
+
+ 0x00000003
+
+ Moorestown MID
+
+ 0x00000004
+
+ CE4100 TV Platform
+
+ Field name:
+
+ hardware_subarch_data
+
+ Type:
+
+ write (subarch-dependent)
+
+ Offset/size:
+
+ 0x240/8
+
+ Protocol:
+
+ 2.07+
+
+ A pointer to data that is specific to hardware subarch This field is
+ currently unused for the default x86/PC environment, do not modify.
+
+ Field name:
+
+ payload_offset
+
+ Type:
+
+ read
+
+ Offset/size:
+
+ 0x248/4
+
+ Protocol:
+
+ 2.08+
+
+ If non-zero then this field contains the offset from the beginning of
+ the protected-mode code to the payload.
+
+ The payload may be compressed. The format of both the compressed and
+ uncompressed data should be determined using the standard magic
+ numbers. The currently supported compression formats are gzip (magic
+ numbers 1F 8B or 1F 9E), bzip2 (magic number 42 5A), LZMA (magic number
+ 5D 00), XZ (magic number FD 37), LZ4 (magic number 02 21) and ZSTD
+ (magic number 28 B5). The uncompressed payload is currently always ELF
+ (magic number 7F 45 4C 46).
+
+ Field name:
+
+ payload_length
+
+ Type:
+
+ read
+
+ Offset/size:
+
+ 0x24c/4
+
+ Protocol:
+
+ 2.08+
+
+ The length of the payload.
+
+ Field name:
+
+ setup_data
+
+ Type:
+
+ write (special)
+
+ Offset/size:
+
+ 0x250/8
+
+ Protocol:
+
+ 2.09+
+
+ The 64-bit physical pointer to NULL terminated single linked list of
+ struct setup_data. This is used to define a more extensible boot
+ parameters passing mechanism. The definition of struct setup_data is as
+ follow:
+struct setup_data {
+ u64 next;
+ u32 type;
+ u32 len;
+ u8 data[0];
+};
+
+ Where, the next is a 64-bit physical pointer to the next node of linked
+ list, the next field of the last node is 0; the type is used to
+ identify the contents of data; the len is the length of data field; the
+ data holds the real payload.
+
+ This list may be modified at a number of points during the bootup
+ process. Therefore, when modifying this list one should always make
+ sure to consider the case where the linked list already contains
+ entries.
+
+ The setup_data is a bit awkward to use for extremely large data
+ objects, both because the setup_data header has to be adjacent to the
+ data object and because it has a 32-bit length field. However, it is
+ important that intermediate stages of the boot process have a way to
+ identify which chunks of memory are occupied by kernel data.
+
+ Thus setup_indirect struct and SETUP_INDIRECT type were introduced in
+ protocol 2.15:
+struct setup_indirect {
+ __u32 type;
+ __u32 reserved; /* Reserved, must be set to zero. */
+ __u64 len;
+ __u64 addr;
+};
+
+ The type member is a SETUP_INDIRECT | SETUP_* type. However, it cannot
+ be SETUP_INDIRECT itself since making the setup_indirect a tree
+ structure could require a lot of stack space in something that needs to
+ parse it and stack space can be limited in boot contexts.
+
+ Let's give an example how to point to SETUP_E820_EXT data using
+ setup_indirect. In this case setup_data and setup_indirect will look
+ like this:
+struct setup_data {
+ __u64 next = 0 or <addr_of_next_setup_data_struct>;
+ __u32 type = SETUP_INDIRECT;
+ __u32 len = sizeof(setup_indirect);
+ __u8 data[sizeof(setup_indirect)] = struct setup_indirect {
+ __u32 type = SETUP_INDIRECT | SETUP_E820_EXT;
+ __u32 reserved = 0;
+ __u64 len = <len_of_SETUP_E820_EXT_data>;
+ __u64 addr = <addr_of_SETUP_E820_EXT_data>;
+ }
+}
+
+ Note
+
+ SETUP_INDIRECT | SETUP_NONE objects cannot be properly distinguished
+ from SETUP_INDIRECT itself. So, this kind of objects cannot be provided
+ by the bootloaders.
+
+ Field name:
+
+ pref_address
+
+ Type:
+
+ read (reloc)
+
+ Offset/size:
+
+ 0x258/8
+
+ Protocol:
+
+ 2.10+
+
+ This field, if nonzero, represents a preferred load address for the
+ kernel. A relocating bootloader should attempt to load at this address
+ if possible.
+
+ A non-relocatable kernel will unconditionally move itself and to run at
+ this address.
+
+ Field name:
+
+ init_size
+
+ Type:
+
+ read
+
+ Offset/size:
+
+ 0x260/4
+
+ This field indicates the amount of linear contiguous memory starting at
+ the kernel runtime start address that the kernel needs before it is
+ capable of examining its memory map. This is not the same thing as the
+ total amount of memory the kernel needs to boot, but it can be used by
+ a relocating boot loader to help select a safe load address for the
+ kernel.
+
+ The kernel runtime start address is determined by the following
+ algorithm:
+if (relocatable_kernel)
+runtime_start = align_up(load_address, kernel_alignment)
+else
+runtime_start = pref_address
+
+ Field name:
+
+ handover_offset
+
+ Type:
+
+ read
+
+ Offset/size:
+
+ 0x264/4
+
+ This field is the offset from the beginning of the kernel image to the
+ EFI handover protocol entry point. Boot loaders using the EFI handover
+ protocol to boot the kernel should jump to this offset.
+
+ See EFI HANDOVER PROTOCOL below for more details.
+
+ Field name:
+
+ kernel_info_offset
+
+ Type:
+
+ read
+
+ Offset/size:
+
+ 0x268/4
+
+ Protocol:
+
+ 2.15+
+
+ This field is the offset from the beginning of the kernel image to the
+ kernel_info. The kernel_info structure is embedded in the Linux image
+ in the uncompressed protected mode region.
+
+1.4. The kernel_info[92]
+
+ The relationships between the headers are analogous to the various data
+ sections:
+
+ setup_header = .data boot_params/setup_data = .bss
+
+ What is missing from the above list? That's right:
+
+ kernel_info = .rodata
+
+ We have been (ab)using .data for things that could go into .rodata or
+ .bss for a long time, for lack of alternatives and - especially early
+ on - inertia. Also, the BIOS stub is responsible for creating
+ boot_params, so it isn't available to a BIOS-based loader (setup_data
+ is, though).
+
+ setup_header is permanently limited to 144 bytes due to the reach of
+ the 2-byte jump field, which doubles as a length field for the
+ structure, combined with the size of the "hole" in struct boot_params
+ that a protected-mode loader or the BIOS stub has to copy it into. It
+ is currently 119 bytes long, which leaves us with 25 very precious
+ bytes. This isn't something that can be fixed without revising the boot
+ protocol entirely, breaking backwards compatibility.
+
+ boot_params proper is limited to 4096 bytes, but can be arbitrarily
+ extended by adding setup_data entries. It cannot be used to communicate
+ properties of the kernel image, because it is .bss and has no
+ image-provided content.
+
+ kernel_info solves this by providing an extensible place for
+ information about the kernel image. It is readonly, because the kernel
+ cannot rely on a bootloader copying its contents anywhere, but that is
+ OK; if it becomes necessary it can still contain data items that an
+ enabled bootloader would be expected to copy into a setup_data chunk.
+
+ All kernel_info data should be part of this structure. Fixed size data
+ have to be put before kernel_info_var_len_data label. Variable size
+ data have to be put after kernel_info_var_len_data label. Each chunk of
+ variable size data has to be prefixed with header/magic and its size,
+ e.g.:
+kernel_info:
+ .ascii "LToP" /* Header, Linux top (structure). */
+ .long kernel_info_var_len_data - kernel_info
+ .long kernel_info_end - kernel_info
+ .long 0x01234567 /* Some fixed size data for the bootloaders. */
+kernel_info_var_len_data:
+example_struct: /* Some variable size data for the bootloaders.
+*/
+ .ascii "0123" /* Header/Magic. */
+ .long example_struct_end - example_struct
+ .ascii "Struct"
+ .long 0x89012345
+example_struct_end:
+example_strings: /* Some variable size data for the bootloaders.
+*/
+ .ascii "ABCD" /* Header/Magic. */
+ .long example_strings_end - example_strings
+ .asciz "String_0"
+ .asciz "String_1"
+example_strings_end:
+kernel_info_end:
+
+ This way the kernel_info is self-contained blob.
+
+ Note
+
+ Each variable size data header/magic can be any 4-character string,
+ without 0 at the end of the string, which does not collide with
+ existing variable length data headers/magics.
+
+1.5. Details of the kernel_info Fields[93]
+
+ Field name:
+
+ header
+
+ Offset/size:
+
+ 0x0000/4
+
+ Contains the magic number "LToP" (0x506f544c).
+
+ Field name:
+
+ size
+
+ Offset/size:
+
+ 0x0004/4
+
+ This field contains the size of the kernel_info including
+ kernel_info.header. It does not count
+ kernel_info.kernel_info_var_len_data size. This field should be used by
+ the bootloaders to detect supported fixed size fields in the
+ kernel_info and beginning of kernel_info.kernel_info_var_len_data.
+
+ Field name:
+
+ size_total
+
+ Offset/size:
+
+ 0x0008/4
+
+ This field contains the size of the kernel_info including
+ kernel_info.header and kernel_info.kernel_info_var_len_data.
+
+ Field name:
+
+ setup_type_max
+
+ Offset/size:
+
+ 0x000c/4
+
+ This field contains maximal allowed type for setup_data and
+ setup_indirect structs.
+
+1.6. The Image Checksum[94]
+
+ From boot protocol version 2.08 onwards the CRC-32 is calculated over
+ the entire file using the characteristic polynomial 0x04C11DB7 and an
+ initial remainder of 0xffffffff. The checksum is appended to the file;
+ therefore the CRC of the file up to the limit specified in the syssize
+ field of the header is always 0.
+
+1.7. The Kernel Command Line[95]
+
+ The kernel command line has become an important way for the boot loader
+ to communicate with the kernel. Some of its options are also relevant
+ to the boot loader itself, see "special command line options" below.
+
+ The kernel command line is a null-terminated string. The maximum length
+ can be retrieved from the field cmdline_size. Before protocol version
+ 2.06, the maximum was 255 characters. A string that is too long will be
+ automatically truncated by the kernel.
+
+ If the boot protocol version is 2.02 or later, the address of the
+ kernel command line is given by the header field cmd_line_ptr (see
+ above.) This address can be anywhere between the end of the setup heap
+ and 0xA0000.
+
+ If the protocol version is not 2.02 or higher, the kernel command line
+ is entered using the following protocol:
+
+ * At offset 0x0020 (word), "cmd_line_magic", enter the magic number
+ 0xA33F.
+ * At offset 0x0022 (word), "cmd_line_offset", enter the offset of the
+ kernel command line (relative to the start of the real-mode
+ kernel).
+ * The kernel command line must be within the memory region covered by
+ setup_move_size, so you may need to adjust this field.
+
+1.8. Memory Layout of The Real-Mode Code[96]
+
+ The real-mode code requires a stack/heap to be set up, as well as
+ memory allocated for the kernel command line. This needs to be done in
+ the real-mode accessible memory in bottom megabyte.
+
+ It should be noted that modern machines often have a sizable Extended
+ BIOS Data Area (EBDA). As a result, it is advisable to use as little of
+ the low megabyte as possible.
+
+ Unfortunately, under the following circumstances the 0x90000 memory
+ segment has to be used:
+
+ * When loading a zImage kernel ((loadflags & 0x01) == 0).
+ * When loading a 2.01 or earlier boot protocol kernel.
+
+ Note
+
+ For the 2.00 and 2.01 boot protocols, the real-mode code can be loaded
+ at another address, but it is internally relocated to 0x90000. For the
+ "old" protocol, the real-mode code must be loaded at 0x90000.
+
+ When loading at 0x90000, avoid using memory above 0x9a000.
+
+ For boot protocol 2.02 or higher, the command line does not have to be
+ located in the same 64K segment as the real-mode setup code; it is thus
+ permitted to give the stack/heap the full 64K segment and locate the
+ command line above it.
+
+ The kernel command line should not be located below the real-mode code,
+ nor should it be located in high memory.
+
+1.9. Sample Boot Configuartion[97]
+
+ As a sample configuration, assume the following layout of the real mode
+ segment.
+
+ When loading below 0x90000, use the entire segment:
+
+ 0x0000-0x7fff
+
+ Real mode kernel
+
+ 0x8000-0xdfff
+
+ Stack and heap
+
+ 0xe000-0xffff
+
+ Kernel command line
+
+ When loading at 0x90000 OR the protocol version is 2.01 or earlier:
+
+ 0x0000-0x7fff
+
+ Real mode kernel
+
+ 0x8000-0x97ff
+
+ Stack and heap
+
+ 0x9800-0x9fff
+
+ Kernel command line
+
+ Such a boot loader should enter the following fields in the header:
+unsigned long base_ptr; /* base address for real-mode segment */
+
+if ( setup_sects == 0 ) {
+ setup_sects = 4;
+}
+
+if ( protocol >= 0x0200 ) {
+ type_of_loader = <type code>;
+ if ( loading_initrd ) {
+ ramdisk_image = <initrd_address>;
+ ramdisk_size = <initrd_size>;
+ }
+
+ if ( protocol >= 0x0202 && loadflags & 0x01 )
+ heap_end = 0xe000;
+ else
+ heap_end = 0x9800;
+
+ if ( protocol >= 0x0201 ) {
+ heap_end_ptr = heap_end - 0x200;
+ loadflags |= 0x80; /* CAN_USE_HEAP */
+ }
+
+ if ( protocol >= 0x0202 ) {
+ cmd_line_ptr = base_ptr + heap_end;
+ strcpy(cmd_line_ptr, cmdline);
+ } else {
+ cmd_line_magic = 0xA33F;
+ cmd_line_offset = heap_end;
+ setup_move_size = heap_end + strlen(cmdline)+1;
+ strcpy(base_ptr+cmd_line_offset, cmdline);
+ }
+} else {
+ /* Very old kernel */
+
+ heap_end = 0x9800;
+
+ cmd_line_magic = 0xA33F;
+ cmd_line_offset = heap_end;
+
+ /* A very old kernel MUST have its real-mode code
+ loaded at 0x90000 */
+
+ if ( base_ptr != 0x90000 ) {
+ /* Copy the real-mode kernel */
+ memcpy(0x90000, base_ptr, (setup_sects+1)*512);
+ base_ptr = 0x90000; /* Relocated */
+ }
+
+ strcpy(0x90000+cmd_line_offset, cmdline);
+
+ /* It is recommended to clear memory up to the 32K mark */
+ memset(0x90000 + (setup_sects+1)*512, 0,
+ (64-(setup_sects+1))*512);
+}
+
+1.10. Loading The Rest of The Kernel[98]
+
+ The 32-bit (non-real-mode) kernel starts at offset (setup_sects+1)*512
+ in the kernel file (again, if setup_sects == 0 the real value is 4.) It
+ should be loaded at address 0x10000 for Image/zImage kernels and
+ 0x100000 for bzImage kernels.
+
+ The kernel is a bzImage kernel if the protocol >= 2.00 and the 0x01 bit
+ (LOAD_HIGH) in the loadflags field is set:
+is_bzImage = (protocol >= 0x0200) && (loadflags & 0x01);
+load_address = is_bzImage ? 0x100000 : 0x10000;
+
+ Note that Image/zImage kernels can be up to 512K in size, and thus use
+ the entire 0x10000-0x90000 range of memory. This means it is pretty
+ much a requirement for these kernels to load the real-mode part at
+ 0x90000. bzImage kernels allow much more flexibility.
+
+1.11. Special Command Line Options[99]
+
+ If the command line provided by the boot loader is entered by the user,
+ the user may expect the following command line options to work. They
+ should normally not be deleted from the kernel command line even though
+ not all of them are actually meaningful to the kernel. Boot loader
+ authors who need additional command line options for the boot loader
+ itself should get them registered in [100]The kernel's command-line
+ parameters to make sure they will not conflict with actual kernel
+ options now or in the future.
+
+ vga=<mode>
+ <mode> here is either an integer (in C notation, either decimal,
+ octal, or hexadecimal) or one of the strings "normal" (meaning
+ 0xFFFF), "ext" (meaning 0xFFFE) or "ask" (meaning 0xFFFD). This
+ value should be entered into the vid_mode field, as it is used
+ by the kernel before the command line is parsed.
+
+ mem=<size>
+ <size> is an integer in C notation optionally followed by (case
+ insensitive) K, M, G, T, P or E (meaning << 10, << 20, << 30, <<
+ 40, << 50 or << 60). This specifies the end of memory to the
+ kernel. This affects the possible placement of an initrd, since
+ an initrd should be placed near end of memory. Note that this is
+ an option to both the kernel and the bootloader!
+
+ initrd=<file>
+ An initrd should be loaded. The meaning of <file> is obviously
+ bootloader-dependent, and some boot loaders (e.g. LILO) do not
+ have such a command.
+
+ In addition, some boot loaders add the following options to the
+ user-specified command line:
+
+ BOOT_IMAGE=<file>
+ The boot image which was loaded. Again, the meaning of <file> is
+ obviously bootloader-dependent.
+
+ auto
+ The kernel was booted without explicit user intervention.
+
+ If these options are added by the boot loader, it is highly recommended
+ that they are located first, before the user-specified or
+ configuration-specified command line. Otherwise, "init=/bin/sh" gets
+ confused by the "auto" option.
+
+1.12. Running the Kernel[101]
+
+ The kernel is started by jumping to the kernel entry point, which is
+ located at segment offset 0x20 from the start of the real mode kernel.
+ This means that if you loaded your real-mode kernel code at 0x90000,
+ the kernel entry point is 9020:0000.
+
+ At entry, ds = es = ss should point to the start of the real-mode
+ kernel code (0x9000 if the code is loaded at 0x90000), sp should be set
+ up properly, normally pointing to the top of the heap, and interrupts
+ should be disabled. Furthermore, to guard against bugs in the kernel,
+ it is recommended that the boot loader sets fs = gs = ds = es = ss.
+
+ In our example from above, we would do:
+/* Note: in the case of the "old" kernel protocol, base_ptr must
+ be == 0x90000 at this point; see the previous sample code */
+
+seg = base_ptr >> 4;
+
+cli(); /* Enter with interrupts disabled! */
+
+/* Set up the real-mode kernel stack */
+_SS = seg;
+_SP = heap_end;
+
+_DS = _ES = _FS = _GS = seg;
+jmp_far(seg+0x20, 0); /* Run the kernel */
+
+ If your boot sector accesses a floppy drive, it is recommended to
+ switch off the floppy motor before running the kernel, since the kernel
+ boot leaves interrupts off and thus the motor will not be switched off,
+ especially if the loaded kernel has the floppy driver as a
+ demand-loaded module!
+
+1.13. Advanced Boot Loader Hooks[102]
+
+ If the boot loader runs in a particularly hostile environment (such as
+ LOADLIN, which runs under DOS) it may be impossible to follow the
+ standard memory location requirements. Such a boot loader may use the
+ following hooks that, if set, are invoked by the kernel at the
+ appropriate time. The use of these hooks should probably be considered
+ an absolutely last resort!
+
+ IMPORTANT: All the hooks are required to preserve %esp, %ebp, %esi and
+ %edi across invocation.
+
+ realmode_swtch:
+ A 16-bit real mode far subroutine invoked immediately before
+ entering protected mode. The default routine disables NMI, so
+ your routine should probably do so, too.
+
+ code32_start:
+ A 32-bit flat-mode routine jumped to immediately after the
+ transition to protected mode, but before the kernel is
+ uncompressed. No segments, except CS, are guaranteed to be set
+ up (current kernels do, but older ones do not); you should set
+ them up to BOOT_DS (0x18) yourself.
+
+ After completing your hook, you should jump to the address that
+ was in this field before your boot loader overwrote it
+ (relocated, if appropriate.)
+
+1.14. 32-bit Boot Protocol[103]
+
+ For machine with some new BIOS other than legacy BIOS, such as EFI,
+ LinuxBIOS, etc, and kexec, the 16-bit real mode setup code in kernel
+ based on legacy BIOS can not be used, so a 32-bit boot protocol needs
+ to be defined.
+
+ In 32-bit boot protocol, the first step in loading a Linux kernel
+ should be to setup the boot parameters (struct boot_params,
+ traditionally known as "zero page"). The memory for struct boot_params
+ should be allocated and initialized to all zero. Then the setup header
+ from offset 0x01f1 of kernel image on should be loaded into struct
+ boot_params and examined. The end of setup header can be calculated as
+ follow:
+0x0202 + byte value at offset 0x0201
+
+ In addition to read/modify/write the setup header of the struct
+ boot_params as that of 16-bit boot protocol, the boot loader should
+ also fill the additional fields of the struct boot_params as described
+ in chapter [104]Zero Page.
+
+ After setting up the struct boot_params, the boot loader can load the
+ 32/64-bit kernel in the same way as that of 16-bit boot protocol.
+
+ In 32-bit boot protocol, the kernel is started by jumping to the 32-bit
+ kernel entry point, which is the start address of loaded 32/64-bit
+ kernel.
+
+ At entry, the CPU must be in 32-bit protected mode with paging
+ disabled; a GDT must be loaded with the descriptors for selectors
+ __BOOT_CS(0x10) and __BOOT_DS(0x18); both descriptors must be 4G flat
+ segment; __BOOT_CS must have execute/read permission, and __BOOT_DS
+ must have read/write permission; CS must be __BOOT_CS and DS, ES, SS
+ must be __BOOT_DS; interrupt must be disabled; %esi must hold the base
+ address of the struct boot_params; %ebp, %edi and %ebx must be zero.
+
+1.15. 64-bit Boot Protocol[105]
+
+ For machine with 64bit cpus and 64bit kernel, we could use 64bit
+ bootloader and we need a 64-bit boot protocol.
+
+ In 64-bit boot protocol, the first step in loading a Linux kernel
+ should be to setup the boot parameters (struct boot_params,
+ traditionally known as "zero page"). The memory for struct boot_params
+ could be allocated anywhere (even above 4G) and initialized to all
+ zero. Then, the setup header at offset 0x01f1 of kernel image on should
+ be loaded into struct boot_params and examined. The end of setup header
+ can be calculated as follows:
+0x0202 + byte value at offset 0x0201
+
+ In addition to read/modify/write the setup header of the struct
+ boot_params as that of 16-bit boot protocol, the boot loader should
+ also fill the additional fields of the struct boot_params as described
+ in chapter [106]Zero Page.
+
+ After setting up the struct boot_params, the boot loader can load
+ 64-bit kernel in the same way as that of 16-bit boot protocol, but
+ kernel could be loaded above 4G.
+
+ In 64-bit boot protocol, the kernel is started by jumping to the 64-bit
+ kernel entry point, which is the start address of loaded 64-bit kernel
+ plus 0x200.
+
+ At entry, the CPU must be in 64-bit mode with paging enabled. The range
+ with setup_header.init_size from start address of loaded kernel and
+ zero page and command line buffer get ident mapping; a GDT must be
+ loaded with the descriptors for selectors __BOOT_CS(0x10) and
+ __BOOT_DS(0x18); both descriptors must be 4G flat segment; __BOOT_CS
+ must have execute/read permission, and __BOOT_DS must have read/write
+ permission; CS must be __BOOT_CS and DS, ES, SS must be __BOOT_DS;
+ interrupt must be disabled; %rsi must hold the base address of the
+ struct boot_params.
+
+1.16. EFI Handover Protocol (deprecated)[107]
+
+ This protocol allows boot loaders to defer initialisation to the EFI
+ boot stub. The boot loader is required to load the kernel/initrd(s)
+ from the boot media and jump to the EFI handover protocol entry point
+ which is hdr->handover_offset bytes from the beginning of
+ startup_{32,64}.
+
+ The boot loader MUST respect the kernel's PE/COFF metadata when it
+ comes to section alignment, the memory footprint of the executable
+ image beyond the size of the file itself, and any other aspect of the
+ PE/COFF header that may affect correct operation of the image as a
+ PE/COFF binary in the execution context provided by the EFI firmware.
+
+ The function prototype for the handover entry point looks like this:
+efi_main(void *handle, efi_system_table_t *table, struct boot_params *bp)
+
+ `handle' is the EFI image handle passed to the boot loader by the EFI
+ firmware, `table' is the EFI system table - these are the first two
+ arguments of the "handoff state" as described in section 2.3 of the
+ UEFI specification. `bp' is the boot loader-allocated boot params.
+
+ The boot loader must fill out the following fields in bp:
+- hdr.cmd_line_ptr
+- hdr.ramdisk_image (if applicable)
+- hdr.ramdisk_size (if applicable)
+
+ All other fields should be zero.
+
+ NOTE: The EFI Handover Protocol is deprecated in favour of the ordinary
+ PE/COFF
+ entry point, combined with the LINUX_EFI_INITRD_MEDIA_GUID based
+ initrd loading protocol (refer to [0] for an example of the
+ bootloader side of this), which removes the need for any
+ knowledge on the part of the EFI bootloader regarding the
+ internal representation of boot_params or any
+ requirements/limitations regarding the placement of the command
+ line and ramdisk in memory, or the placement of the kernel image
+ itself.
+
+ [0]
+ [108]https://github.com/u-boot/u-boot/commit/ec80b4735a593961fe701cc3a5
+ d717d4739b0fd0
+
+ The kernel development community. | Powered by [109]Sphinx 5.0.1 &
+ [110]Alabaster 0.7.12 | [111]Page source
+
+References
+
+ 1. https://www.kernel.org/doc/html/latest/genindex.html
+ 2. https://www.kernel.org/doc/html/latest/search.html
+ 3. https://www.kernel.org/doc/html/latest/x86/booting-dt.html
+ 4. https://www.kernel.org/doc/html/latest/x86/index.html
+ 5. https://www.kernel.org/doc/html/latest/index.html
+ 6. https://www.kernel.org/doc/html/latest/process/development-process.html
+ 7. https://www.kernel.org/doc/html/latest/process/submitting-patches.html
+ 8. https://www.kernel.org/doc/html/latest/process/code-of-conduct.html
+ 9. https://www.kernel.org/doc/html/latest/maintainer/index.html
+ 10. https://www.kernel.org/doc/html/latest/process/index.html
+ 11. https://www.kernel.org/doc/html/latest/core-api/index.html
+ 12. https://www.kernel.org/doc/html/latest/driver-api/index.html
+ 13. https://www.kernel.org/doc/html/latest/subsystem-apis.html
+ 14. https://www.kernel.org/doc/html/latest/locking/index.html
+ 15. https://www.kernel.org/doc/html/latest/process/license-rules.html
+ 16. https://www.kernel.org/doc/html/latest/doc-guide/index.html
+ 17. https://www.kernel.org/doc/html/latest/dev-tools/index.html
+ 18. https://www.kernel.org/doc/html/latest/dev-tools/testing-overview.html
+ 19. https://www.kernel.org/doc/html/latest/kernel-hacking/index.html
+ 20. https://www.kernel.org/doc/html/latest/trace/index.html
+ 21. https://www.kernel.org/doc/html/latest/fault-injection/index.html
+ 22. https://www.kernel.org/doc/html/latest/livepatch/index.html
+ 23. https://www.kernel.org/doc/html/latest/rust/index.html
+ 24. https://www.kernel.org/doc/html/latest/admin-guide/index.html
+ 25. https://www.kernel.org/doc/html/latest/kbuild/index.html
+ 26. https://www.kernel.org/doc/html/latest/admin-guide/reporting-issues.html
+ 27. https://www.kernel.org/doc/html/latest/tools/index.html
+ 28. https://www.kernel.org/doc/html/latest/userspace-api/index.html
+ 29. https://www.kernel.org/doc/html/latest/firmware-guide/index.html
+ 30. https://www.kernel.org/doc/html/latest/devicetree/index.html
+ 31. https://www.kernel.org/doc/html/latest/arch.html
+ 32. https://www.kernel.org/doc/html/latest/arc/index.html
+ 33. https://www.kernel.org/doc/html/latest/arm/index.html
+ 34. https://www.kernel.org/doc/html/latest/arm64/index.html
+ 35. https://www.kernel.org/doc/html/latest/ia64/index.html
+ 36. https://www.kernel.org/doc/html/latest/loongarch/index.html
+ 37. https://www.kernel.org/doc/html/latest/m68k/index.html
+ 38. https://www.kernel.org/doc/html/latest/mips/index.html
+ 39. https://www.kernel.org/doc/html/latest/nios2/index.html
+ 40. https://www.kernel.org/doc/html/latest/openrisc/index.html
+ 41. https://www.kernel.org/doc/html/latest/parisc/index.html
+ 42. https://www.kernel.org/doc/html/latest/powerpc/index.html
+ 43. https://www.kernel.org/doc/html/latest/riscv/index.html
+ 44. https://www.kernel.org/doc/html/latest/s390/index.html
+ 45. https://www.kernel.org/doc/html/latest/sh/index.html
+ 46. https://www.kernel.org/doc/html/latest/sparc/index.html
+ 47. https://www.kernel.org/doc/html/latest/x86/index.html
+ 48. https://www.kernel.org/doc/html/latest/x86/boot.html
+ 49. https://www.kernel.org/doc/html/latest/x86/booting-dt.html
+ 50. https://www.kernel.org/doc/html/latest/x86/cpuinfo.html
+ 51. https://www.kernel.org/doc/html/latest/x86/topology.html
+ 52. https://www.kernel.org/doc/html/latest/x86/exception-tables.html
+ 53. https://www.kernel.org/doc/html/latest/x86/kernel-stacks.html
+ 54. https://www.kernel.org/doc/html/latest/x86/entry_64.html
+ 55. https://www.kernel.org/doc/html/latest/x86/earlyprintk.html
+ 56. https://www.kernel.org/doc/html/latest/x86/orc-unwinder.html
+ 57. https://www.kernel.org/doc/html/latest/x86/zero-page.html
+ 58. https://www.kernel.org/doc/html/latest/x86/tlb.html
+ 59. https://www.kernel.org/doc/html/latest/x86/mtrr.html
+ 60. https://www.kernel.org/doc/html/latest/x86/pat.html
+ 61. https://www.kernel.org/doc/html/latest/x86/intel-hfi.html
+ 62. https://www.kernel.org/doc/html/latest/x86/iommu.html
+ 63. https://www.kernel.org/doc/html/latest/x86/intel_txt.html
+ 64. https://www.kernel.org/doc/html/latest/x86/amd-memory-encryption.html
+ 65. https://www.kernel.org/doc/html/latest/x86/amd_hsmp.html
+ 66. https://www.kernel.org/doc/html/latest/x86/tdx.html
+ 67. https://www.kernel.org/doc/html/latest/x86/pti.html
+ 68. https://www.kernel.org/doc/html/latest/x86/mds.html
+ 69. https://www.kernel.org/doc/html/latest/x86/microcode.html
+ 70. https://www.kernel.org/doc/html/latest/x86/resctrl.html
+ 71. https://www.kernel.org/doc/html/latest/x86/tsx_async_abort.html
+ 72. https://www.kernel.org/doc/html/latest/x86/buslock.html
+ 73. https://www.kernel.org/doc/html/latest/x86/usb-legacy-support.html
+ 74. https://www.kernel.org/doc/html/latest/x86/i386/index.html
+ 75. https://www.kernel.org/doc/html/latest/x86/x86_64/index.html
+ 76. https://www.kernel.org/doc/html/latest/x86/ifs.html
+ 77. https://www.kernel.org/doc/html/latest/x86/sva.html
+ 78. https://www.kernel.org/doc/html/latest/x86/sgx.html
+ 79. https://www.kernel.org/doc/html/latest/x86/features.html
+ 80. https://www.kernel.org/doc/html/latest/x86/elf_auxvec.html
+ 81. https://www.kernel.org/doc/html/latest/x86/xstate.html
+ 82. https://www.kernel.org/doc/html/latest/xtensa/index.html
+ 83. https://www.kernel.org/doc/html/latest/staging/index.html
+ 84. https://www.kernel.org/doc/html/latest/translations/index.html
+ 85. https://www.kernel.org/doc/html/latest/_sources/x86/boot.rst.txt
+ 86. https://www.kernel.org/doc/html/latest/x86/boot.html#the-linux-x86-boot-protocol
+ 87. https://www.kernel.org/doc/html/latest/x86/boot.html#memory-layout
+ 88. https://www.kernel.org/doc/html/latest/x86/boot.html#the-real-mode-kernel-header
+ 89. https://www.kernel.org/doc/html/latest/x86/boot.html#details-of-header-fields
+ 90. http://sebastian-plotz.blogspot.de/
+ 91. mailto:hpa%40zytor.com
+ 92. https://www.kernel.org/doc/html/latest/x86/boot.html#the-kernel-info
+ 93. https://www.kernel.org/doc/html/latest/x86/boot.html#details-of-the-kernel-info-fields
+ 94. https://www.kernel.org/doc/html/latest/x86/boot.html#the-image-checksum
+ 95. https://www.kernel.org/doc/html/latest/x86/boot.html#the-kernel-command-line
+ 96. https://www.kernel.org/doc/html/latest/x86/boot.html#memory-layout-of-the-real-mode-code
+ 97. https://www.kernel.org/doc/html/latest/x86/boot.html#sample-boot-configuartion
+ 98. https://www.kernel.org/doc/html/latest/x86/boot.html#loading-the-rest-of-the-kernel
+ 99. https://www.kernel.org/doc/html/latest/x86/boot.html#special-command-line-options
+ 100. https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html
+ 101. https://www.kernel.org/doc/html/latest/x86/boot.html#running-the-kernel
+ 102. https://www.kernel.org/doc/html/latest/x86/boot.html#advanced-boot-loader-hooks
+ 103. https://www.kernel.org/doc/html/latest/x86/boot.html#bit-boot-protocol
+ 104. https://www.kernel.org/doc/html/latest/x86/zero-page.html
+ 105. https://www.kernel.org/doc/html/latest/x86/boot.html#id1
+ 106. https://www.kernel.org/doc/html/latest/x86/zero-page.html
+ 107. https://www.kernel.org/doc/html/latest/x86/boot.html#efi-handover-protocol-deprecated
+ 108. https://github.com/u-boot/u-boot/commit/ec80b4735a593961fe701cc3a5d717d4739b0fd0
+ 109. http://sphinx-doc.org/
+ 110. https://github.com/bitprophet/alabaster
+ 111. https://www.kernel.org/doc/html/latest/_sources/x86/boot.rst.txt
diff --git a/todo/doc/www.kernel.org_doc_html_latest_x86_zero-page.txt b/todo/doc/www.kernel.org_doc_html_latest_x86_zero-page.txt
new file mode 100644
index 0000000..da384f1
--- /dev/null
+++ b/todo/doc/www.kernel.org_doc_html_latest_x86_zero-page.txt
@@ -0,0 +1,424 @@
+ #[1]Index [2]Search [3]11. The TLB [4]9. ORC unwinder
+
+[5]The Linux Kernel
+
+ 6.3.0-rc6
+
+Quick search
+
+ ____________________ Go
+
+Contents
+
+ [X]
+ * [6]A guide to the Kernel Development Process
+ * [7]Submitting patches: the essential guide to getting your code
+ into the kernel
+ * [8]Code of conduct
+ * [9]Kernel Maintainer Handbook
+ * [10]All development-process docs
+
+ * [11]Core API Documentation
+ * [12]Driver implementer's API guide
+ * [13]Kernel subsystem documentation
+ * [14]Locking in the kernel
+
+ * [15]Linux kernel licensing rules
+ * [16]How to write kernel documentation
+ * [17]Development tools for the kernel
+ * [18]Kernel Testing Guide
+ * [19]Kernel Hacking Guides
+ * [20]Linux Tracing Technologies
+ * [21]fault-injection
+ * [22]Kernel Livepatching
+ * [23]Rust
+
+ * [24]The Linux kernel user's and administrator's guide
+ * [25]The kernel build system
+ * [26]Reporting issues
+ * [27]User-space tools
+ * [28]The Linux kernel user-space API guide
+
+ * [29]The Linux kernel firmware guide
+ * [30]Open Firmware and Devicetree
+
+ * [31]CPU Architectures
+ + [32]ARC architecture
+ + [33]ARM Architecture
+ + [34]ARM64 Architecture
+ + [35]IA-64 Architecture
+ + [36]LoongArch Architecture
+ + [37]m68k Architecture
+ + [38]MIPS-specific Documentation
+ + [39]Nios II Specific Documentation
+ + [40]OpenRISC Architecture
+ + [41]PA-RISC Architecture
+ + [42]powerpc
+ + [43]RISC-V architecture
+ + [44]s390 Architecture
+ + [45]SuperH Interfaces Guide
+ + [46]Sparc Architecture
+ + [47]x86-specific Documentation
+ o [48]1. The Linux/x86 Boot Protocol
+ o [49]2. DeviceTree Booting
+ o [50]3. x86 Feature Flags
+ o [51]4. x86 Topology
+ o [52]5. Kernel level exception handling
+ o [53]6. Kernel Stacks
+ o [54]7. Kernel Entries
+ o [55]8. Early Printk
+ o [56]9. ORC unwinder
+ o [57]10. Zero Page
+ o [58]11. The TLB
+ o [59]12. MTRR (Memory Type Range Register) control
+ o [60]13. PAT (Page Attribute Table)
+ o [61]14. Hardware-Feedback Interface for scheduling on
+ Intel Hardware
+ o [62]15. x86 IOMMU Support
+ o [63]16. Intel(R) TXT Overview
+ o [64]17. AMD Memory Encryption
+ o [65]18. AMD HSMP interface
+ o [66]19. Intel Trust Domain Extensions (TDX)
+ o [67]20. Page Table Isolation (PTI)
+ o [68]21. Microarchitectural Data Sampling (MDS) mitigation
+ o [69]22. The Linux Microcode Loader
+ o [70]23. User Interface for Resource Control feature
+ o [71]24. TSX Async Abort (TAA) mitigation
+ o [72]25. Bus lock detection and handling
+ o [73]26. USB Legacy support
+ o [74]27. i386 Support
+ o [75]28. x86_64 Support
+ o [76]29. In-Field Scan
+ o [77]30. Shared Virtual Addressing (SVA) with ENQCMD
+ o [78]31. Software Guard eXtensions (SGX)
+ o [79]32. Feature status on x86 architecture
+ o [80]33. x86-specific ELF Auxiliary Vectors
+ o [81]34. Using XSTATE features in user space applications
+ + [82]Xtensa Architecture
+
+ * [83]Unsorted Documentation
+
+ * [84]Translations
+
+This Page
+
+ * [85]Show Source
+
+10. Zero Page[86]
+
+ The additional fields in struct boot_params as a part of 32-bit boot
+ protocol of kernel. These should be filled by bootloader or 16-bit
+ real-mode setup code of the kernel. References/settings to it mainly
+ are in:
+arch/x86/include/uapi/asm/bootparam.h
+
+ Offset/Size
+
+ Proto
+
+ Name
+
+ Meaning
+
+ 000/040
+
+ ALL
+
+ screen_info
+
+ Text mode or frame buffer information (struct screen_info)
+
+ 040/014
+
+ ALL
+
+ apm_bios_info
+
+ APM BIOS information (struct apm_bios_info)
+
+ 058/008
+
+ ALL
+
+ tboot_addr
+
+ Physical address of tboot shared page
+
+ 060/010
+
+ ALL
+
+ ist_info
+
+ Intel SpeedStep (IST) BIOS support information (struct ist_info)
+
+ 070/008
+
+ ALL
+
+ acpi_rsdp_addr
+
+ Physical address of ACPI RSDP table
+
+ 080/010
+
+ ALL
+
+ hd0_info
+
+ hd0 disk parameter, OBSOLETE!!
+
+ 090/010
+
+ ALL
+
+ hd1_info
+
+ hd1 disk parameter, OBSOLETE!!
+
+ 0A0/010
+
+ ALL
+
+ sys_desc_table
+
+ System description table (struct sys_desc_table), OBSOLETE!!
+
+ 0B0/010
+
+ ALL
+
+ olpc_ofw_header
+
+ OLPC's OpenFirmware CIF and friends
+
+ 0C0/004
+
+ ALL
+
+ ext_ramdisk_image
+
+ ramdisk_image high 32bits
+
+ 0C4/004
+
+ ALL
+
+ ext_ramdisk_size
+
+ ramdisk_size high 32bits
+
+ 0C8/004
+
+ ALL
+
+ ext_cmd_line_ptr
+
+ cmd_line_ptr high 32bits
+
+ 13C/004
+
+ ALL
+
+ cc_blob_address
+
+ Physical address of Confidential Computing blob
+
+ 140/080
+
+ ALL
+
+ edid_info
+
+ Video mode setup (struct edid_info)
+
+ 1C0/020
+
+ ALL
+
+ efi_info
+
+ EFI 32 information (struct efi_info)
+
+ 1E0/004
+
+ ALL
+
+ alt_mem_k
+
+ Alternative mem check, in KB
+
+ 1E4/004
+
+ ALL
+
+ scratch
+
+ Scratch field for the kernel setup code
+
+ 1E8/001
+
+ ALL
+
+ e820_entries
+
+ Number of entries in e820_table (below)
+
+ 1E9/001
+
+ ALL
+
+ eddbuf_entries
+
+ Number of entries in eddbuf (below)
+
+ 1EA/001
+
+ ALL
+
+ edd_mbr_sig_buf_entries
+
+ Number of entries in edd_mbr_sig_buffer (below)
+
+ 1EB/001
+
+ ALL
+
+ kbd_status
+
+ Numlock is enabled
+
+ 1EC/001
+
+ ALL
+
+ secure_boot
+
+ Secure boot is enabled in the firmware
+
+ 1EF/001
+
+ ALL
+
+ sentinel
+
+ Used to detect broken bootloaders
+
+ 290/040
+
+ ALL
+
+ edd_mbr_sig_buffer
+
+ EDD MBR signatures
+
+ 2D0/A00
+
+ ALL
+
+ e820_table
+
+ E820 memory map table (array of struct e820_entry)
+
+ D00/1EC
+
+ ALL
+
+ eddbuf
+
+ EDD data (array of struct edd_info)
+
+ The kernel development community. | Powered by [87]Sphinx 5.0.1 &
+ [88]Alabaster 0.7.12 | [89]Page source
+
+References
+
+ 1. https://www.kernel.org/doc/html/latest/genindex.html
+ 2. https://www.kernel.org/doc/html/latest/search.html
+ 3. https://www.kernel.org/doc/html/latest/x86/tlb.html
+ 4. https://www.kernel.org/doc/html/latest/x86/orc-unwinder.html
+ 5. https://www.kernel.org/doc/html/latest/index.html
+ 6. https://www.kernel.org/doc/html/latest/process/development-process.html
+ 7. https://www.kernel.org/doc/html/latest/process/submitting-patches.html
+ 8. https://www.kernel.org/doc/html/latest/process/code-of-conduct.html
+ 9. https://www.kernel.org/doc/html/latest/maintainer/index.html
+ 10. https://www.kernel.org/doc/html/latest/process/index.html
+ 11. https://www.kernel.org/doc/html/latest/core-api/index.html
+ 12. https://www.kernel.org/doc/html/latest/driver-api/index.html
+ 13. https://www.kernel.org/doc/html/latest/subsystem-apis.html
+ 14. https://www.kernel.org/doc/html/latest/locking/index.html
+ 15. https://www.kernel.org/doc/html/latest/process/license-rules.html
+ 16. https://www.kernel.org/doc/html/latest/doc-guide/index.html
+ 17. https://www.kernel.org/doc/html/latest/dev-tools/index.html
+ 18. https://www.kernel.org/doc/html/latest/dev-tools/testing-overview.html
+ 19. https://www.kernel.org/doc/html/latest/kernel-hacking/index.html
+ 20. https://www.kernel.org/doc/html/latest/trace/index.html
+ 21. https://www.kernel.org/doc/html/latest/fault-injection/index.html
+ 22. https://www.kernel.org/doc/html/latest/livepatch/index.html
+ 23. https://www.kernel.org/doc/html/latest/rust/index.html
+ 24. https://www.kernel.org/doc/html/latest/admin-guide/index.html
+ 25. https://www.kernel.org/doc/html/latest/kbuild/index.html
+ 26. https://www.kernel.org/doc/html/latest/admin-guide/reporting-issues.html
+ 27. https://www.kernel.org/doc/html/latest/tools/index.html
+ 28. https://www.kernel.org/doc/html/latest/userspace-api/index.html
+ 29. https://www.kernel.org/doc/html/latest/firmware-guide/index.html
+ 30. https://www.kernel.org/doc/html/latest/devicetree/index.html
+ 31. https://www.kernel.org/doc/html/latest/arch.html
+ 32. https://www.kernel.org/doc/html/latest/arc/index.html
+ 33. https://www.kernel.org/doc/html/latest/arm/index.html
+ 34. https://www.kernel.org/doc/html/latest/arm64/index.html
+ 35. https://www.kernel.org/doc/html/latest/ia64/index.html
+ 36. https://www.kernel.org/doc/html/latest/loongarch/index.html
+ 37. https://www.kernel.org/doc/html/latest/m68k/index.html
+ 38. https://www.kernel.org/doc/html/latest/mips/index.html
+ 39. https://www.kernel.org/doc/html/latest/nios2/index.html
+ 40. https://www.kernel.org/doc/html/latest/openrisc/index.html
+ 41. https://www.kernel.org/doc/html/latest/parisc/index.html
+ 42. https://www.kernel.org/doc/html/latest/powerpc/index.html
+ 43. https://www.kernel.org/doc/html/latest/riscv/index.html
+ 44. https://www.kernel.org/doc/html/latest/s390/index.html
+ 45. https://www.kernel.org/doc/html/latest/sh/index.html
+ 46. https://www.kernel.org/doc/html/latest/sparc/index.html
+ 47. https://www.kernel.org/doc/html/latest/x86/index.html
+ 48. https://www.kernel.org/doc/html/latest/x86/boot.html
+ 49. https://www.kernel.org/doc/html/latest/x86/booting-dt.html
+ 50. https://www.kernel.org/doc/html/latest/x86/cpuinfo.html
+ 51. https://www.kernel.org/doc/html/latest/x86/topology.html
+ 52. https://www.kernel.org/doc/html/latest/x86/exception-tables.html
+ 53. https://www.kernel.org/doc/html/latest/x86/kernel-stacks.html
+ 54. https://www.kernel.org/doc/html/latest/x86/entry_64.html
+ 55. https://www.kernel.org/doc/html/latest/x86/earlyprintk.html
+ 56. https://www.kernel.org/doc/html/latest/x86/orc-unwinder.html
+ 57. https://www.kernel.org/doc/html/latest/x86/zero-page.html
+ 58. https://www.kernel.org/doc/html/latest/x86/tlb.html
+ 59. https://www.kernel.org/doc/html/latest/x86/mtrr.html
+ 60. https://www.kernel.org/doc/html/latest/x86/pat.html
+ 61. https://www.kernel.org/doc/html/latest/x86/intel-hfi.html
+ 62. https://www.kernel.org/doc/html/latest/x86/iommu.html
+ 63. https://www.kernel.org/doc/html/latest/x86/intel_txt.html
+ 64. https://www.kernel.org/doc/html/latest/x86/amd-memory-encryption.html
+ 65. https://www.kernel.org/doc/html/latest/x86/amd_hsmp.html
+ 66. https://www.kernel.org/doc/html/latest/x86/tdx.html
+ 67. https://www.kernel.org/doc/html/latest/x86/pti.html
+ 68. https://www.kernel.org/doc/html/latest/x86/mds.html
+ 69. https://www.kernel.org/doc/html/latest/x86/microcode.html
+ 70. https://www.kernel.org/doc/html/latest/x86/resctrl.html
+ 71. https://www.kernel.org/doc/html/latest/x86/tsx_async_abort.html
+ 72. https://www.kernel.org/doc/html/latest/x86/buslock.html
+ 73. https://www.kernel.org/doc/html/latest/x86/usb-legacy-support.html
+ 74. https://www.kernel.org/doc/html/latest/x86/i386/index.html
+ 75. https://www.kernel.org/doc/html/latest/x86/x86_64/index.html
+ 76. https://www.kernel.org/doc/html/latest/x86/ifs.html
+ 77. https://www.kernel.org/doc/html/latest/x86/sva.html
+ 78. https://www.kernel.org/doc/html/latest/x86/sgx.html
+ 79. https://www.kernel.org/doc/html/latest/x86/features.html
+ 80. https://www.kernel.org/doc/html/latest/x86/elf_auxvec.html
+ 81. https://www.kernel.org/doc/html/latest/x86/xstate.html
+ 82. https://www.kernel.org/doc/html/latest/xtensa/index.html
+ 83. https://www.kernel.org/doc/html/latest/staging/index.html
+ 84. https://www.kernel.org/doc/html/latest/translations/index.html
+ 85. https://www.kernel.org/doc/html/latest/_sources/x86/zero-page.rst.txt
+ 86. https://www.kernel.org/doc/html/latest/x86/zero-page.html#zero-page
+ 87. http://sphinx-doc.org/
+ 88. https://github.com/bitprophet/alabaster
+ 89. https://www.kernel.org/doc/html/latest/_sources/x86/zero-page.rst.txt