Global Descriptor Table(GDT).
GDTRregister. 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:
lgdtinstruction loads the base address and limit(size) of the global descriptor table to the
GDTRis a 48-bit register and consists of two parts:
segment descriptorswhich describe memory segments. Each descriptor is 64-bits in size. The general scheme of a descriptor is:
length_of_segment - 1. It depends on the
G(bit 55) is 0 and the segment limit is 0, the size of the segment is 1 Byte
Gis 1 and the segment limit is 0, the size of the segment is 4096 Bytes
Gis 0 and the segment limit is 0xfffff, the size of the segment is 1 Megabyte
Gis 1 and the segment limit is 0xfffff, the size of the segment is 4 Gigabytes
Sflag at bit 44 specifies the descriptor type. If
Sis 0 then this segment is a system segment, whereas if
Sis 1 then this is a code or data segment (Stack segments are data segments which must be read/write segments).
0for a data segment and
1for a code segment. The next three bits (40, 41, 42) are either
EWA(Expansion Writable Accessible) or CRA(Conforming Readable Accessible).
GDT address + Indexfrom the selector and then loads the descriptor into the hidden part of the segment register.
boot_paramsstructure contains the
struct setup_header hdrfield. This structure contains the same fields as defined in the linux boot protocol and is filled by the boot loader and also at kernel compile/build time.
copy_boot_paramsdoes two things:
memcpyand other routines which are defined here, start and end with the two macros:
GLOBALis described in arch/x86/include/asm/linkage.h which defines the
globldirective and its label.
ENDPROCis described in include/linux/linkage.h and marks the
namesymbol as a function name and ends with the size of the
memcpyis simple. At first, it pushes values from the
diregisters to the stack to preserve their values because they will change during the
memcpy. As we can see in the
arch/x86/Makefile, the kernel build system uses the
-mregparm=3option of GCC, so functions get the first three parameters from
memcpylooks like this:
axwill contain the address of
dxwill contain the address of
cxwill contain the size of
memcpyputs the address of
cxon the stack. After this it shifts the value right 2 times (or divides it by 4) and copies four bytes from the address at
sito the address at
di. After this, we restore the size of
hdragain, align it by 4 bytes and copy the rest of the bytes from the address at
sito the address at
dibyte by byte (if there is more). Now the values of
diare restored from the stack and the copying operation is finished.
earlyprintkoption 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
earlyprintkcommand line option can be one of these:
putcharchecks for the symbol and if it is found, prints before. After that it prints the character on the VGA screen by calling the BIOS with the
biosregsstructure and first fills
biosregswith zeros using the
memsetfunction and then fills it with register values.
memcpyfunction, which means that the function gets its parameters from the
memsetis similar to that of memcpy. It saves the value of the
diregister on the stack and puts the value of
ax, which stores the address of the
di. Next is the
movzblinstruction, which copies the value of
dlto the lowermost byte of the
eaxregister. The remaining 3 high bytes of
eaxwill be filled with zeros.
0x01010101. It needs to because
memsetwill copy 4 bytes at the same time. For example, if we need to fill a structure whose size is 4 bytes with the value
eaxwill contain the
0x00000007. So if we multiply
0x01010101, we will get
0x07070707and now we can copy these 4 bytes into the structure.
rep; stoslinstruction to copy
memsetfunction does almost the same thing as
stack_end = esp - STACK_SIZE.
0x200h). The last check is whether
heap_endis greater than
stack_end. If it is then
stack_endis assigned to
heap_endto make them equal.
GET_HEAPmethod. We will see what it is used for, how to use it and how it is implemented in the next posts.
check_cpufunction checks the CPU's flags, the presence of 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.
set_bios_modefunction after setup code found that a CPU is suitable. As we may see, this function is implemented only for the
detect_memorybasically provides a map of available RAM to the CPU. It uses different programming interfaces for memory detection like
0x88. We will see only the implementation of the 0xE820 interface here.
detect_memory_e820function from the arch/x86/boot/memory.c source file. First of all, the
detect_memory_e820function initializes the
biosregsstructure as we saw above and fills registers with special values for the
axcontains the number of the function (0xe820 in our case)
cxcontains the size of the buffer which will contain data about the memory
edxmust contain the
es:dimust contain the address of the buffer which will contain memory data
ebxhas to be zero.
0x15BIOS 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
ebxmust contain the value returned previously:
dmesgoutput, something like:
0x15BIOS interruption too, but with
0x15finishes executing, the
query_apm_biosfunctions check the
PMsignature (it must be
0x504d), the carry flag (it must be 0 if
APMsupported) and the value of the
cxregister (if it's 0x02, the protected mode interface is supported).
0x15again, but with
ax = 0x5304to disconnect the
APMinterface and connect the 32-bit protected mode interface. In the end, it fills
boot_params.apm_bios_infowith values obtained from the BIOS.
query_apm_bioswill be executed only if the
CONFIG_APM_MODULEcompile time flag was set in the configuration file:
query_eddgoes over BIOS-supported hard disks and queries EDD information in the following loop:
0x80is the first hard drive and the value of the
EDD_MBR_SIG_MAXmacro is 16. It collects data into an array of edd_info structures.
get_edd_infochecks that EDD is present by invoking the
0x41and if EDD is present,
get_edd_infoagain calls the
0x13interrupt, but with
sicontaining the address of the buffer where EDD information will be stored.