kernel booting process

Upload: manjunath-bheemappa

Post on 01-Mar-2018

237 views

Category:

Documents


2 download

TRANSCRIPT

  • 7/25/2019 Kernel Booting Process

    1/16

    Kernel booting process. Part 1.

    From the bootloader to the kernel

    If you have read my previous blog posts, you can see that sometime ago I

    started to get involved with low-level programming. I wrote some posts about

    x86_64 assembly programming for Linux. At the same time, I started to dive

    into the Linux 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 x86_64.

    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 0xAX, drop me

    an emailor just create an issue. I appreciate it. All posts will also be

    accessible at linux-insidesand if you find something wrong with my English or

    the post content, feel free to send a pull request.

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

    knowledge.

    Required knowledge

    Understanding C code

    Understanding assembly code (AT&T syntax)

    Anyway, if you just start to learn some tools, I will try to explain some parts

    during this and the following posts. Ok, simple introduction finishes and now

    we can start to dive into the kernel and low-level stuff.

  • 7/25/2019 Kernel Booting Process

    2/16

    All code is actually for kernel - 3.18. If there are changes, I will update the

    posts accordingly.

    The Magic Power Button, What happens next?

    Despite that this is a series of posts about the Linux kernel, we will not start

    from the kernel code (at least not in this paragraph). Ok, you press the magic

    power button on your laptop or desktop computer and it starts to work. After

    the motherboard sends a signal to the power supply, the power supply

    provides the computer with the proper amount of electricity. Once the

    motherboard receives the power good signal, it tries to start the CPU. The

    CPU resets all leftover data in its registers and sets up predefined values for

    each of them.

    80386and later CPUs define the following predefined data in CPU registers

    after the computer resets:

    !" $%&&&$ '( )*+*,-./ $%&$$$ '( 01)* $%&&&&$$$$

    The processor starts working in real mode. Let's back up a little to try and

    understand memory segmentation in this mode. Real mode is supported on all

    x86-compatible processors, from the 8086all 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-0x100000 address space (1 megabyte). But it only has

    16-bit registers, and with 16-bit registers the maximum address is 2^16 - 1 or

    0xffff (64 kilobytes). Memory segmentationis used to make use of all the

    address space available. All memory is divided into small, fixed-size segments

    of 65536 bytes, or 64 KB. Since we cannot address memory above 64 KB with

    16 bit registers, an alternate method is devised. An address consists of two

    parts: a segment selector which has an associated base address and an

    offset from this base address. In real mode, the associated base address of a

    segment selector is (*23*4- (*+*,-./ 5 67. Thus, to get a physical address in

    memory, we need to multiply the segment selector part by 16 and add the

    offset part:

  • 7/25/2019 Kernel Booting Process

    3/16

    "89):,1+;

  • 7/25/2019 Kernel Booting Process

    4/16

    (N'O!?P( Q JR?SO?" = $%&&&&&&&$T H = JR?SO?"T H/*)*- H @ Q

    5CH/*)*-F H = 6U T VWONC$%$$FT X X

    Now the BIOS starts: after initializing and checking the hardware, it 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 MBR partition layout, the boot sector is stored in the first

    446 bytes of the first sector (which is 512 bytes). The final two bytes of the

    first sector are $%UUand $%11, which signals the BIOS that this device is

    bootable. For example:

    T T P.-*@ -8:) *%13Y+* :) Z/:--*4 :4 !4-*+ ;))*30+9 )94-1% T [V!O( 67\ [?R]

    $%^,$$\ 0..-@ 3.K 1+_ G`G 3.K 18_ $%$* 3.K 08_ $%$$ 3.K 0+_

    $%$^ :4- $%6$ a3Y b -:3*) U6$MCbMbbF

  • 7/25/2019 Kernel Booting Process

    5/16

    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 0x10interrupt

    which just prints the `symbol. It fills the rest of the 510 bytes with zeros and

    finishes with the two magic bytes $%11and $%UU.

    You can see a binary dump of this with the .0a

  • 7/25/2019 Kernel Booting Process

    6/16

    NOTE: As you can read above the CPU is in real mode. In real mode,

    calculating the physical address in memory is done as follows:

    "89):,1+; $%&&&&F G$%6$&&*&G

    Where $%6$&&*&is equal to 6SV > 7EiV M 670. But a 8086processor, which is

    the first processor with real mode, has a 20 bit address line and AjA$ =

    6$EfU^7is 1MB. This means the actual memory available is 1MB.

    General real mode's memory map is:

    $%$$$$$$$$ M $%$$$$$hkk M R*1+ S.

  • 7/25/2019 Kernel Booting Process

    7/16

    Now that the BIOS has chosen a boot device and transferred control to the

    boot sector code, execution starts from boot.img. This code is very simple

    due to the limited amount of space available, and contains a pointer which is

    used to jump to the location of GRUB 2's core image. The core image beginswithdiskboot.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 into memory, which contains GRUB 2's kernel and drivers for

    handling filesystems. After loading the rest of the core image, it

    executesgrub_main.

    2/e0J31:4initializes the console, gets the base address for modules, sets the

    root device, loads/parses the grub configuration file, loads modules etc. At theend of execution, 2/e0J31:4moves grub to normal

    mode. 2/e0J4./31+J*%*,e-*(from 2/e0M,./*o4./31+o31:4H,) completes the last

    preparation and shows a menu to select an operating system. When we select

    one of the grub menu entries,2/e0J3*4eJ*%*,e-*J*4-/9runs, which executes

    the grub 0..-command, 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 $%$6&6offset from the

    kernel setup code. The kernel headerarch/x86/boot/header.Sstarts from:

    H2+.0+ 8

  • 7/25/2019 Kernel Booting Process

    8/16

    r "/.-*,-*

    r !o? 3*3./9 8.+* r $;$$$$ >MMMMMMMMMMMMMMMMMMMMMMMM> r

    R*)*/K*< &./ V!?( r p*1K* 1) 3e,8 1) Y.)):0+* e4e)*< s

    s r '.3314< +:4* r C'14 1+). 0* 0*+.Z -8* t>6$$$$ 31/nF

    t>6$$$$ >MMMMMMMMMMMMMMMMMMMMMMMM> r (-1,no8*1Y r k./

    e)* 09 -8* n*/4*+ /*1+M3.MMMMMMMMMMMMMMMMMMMMMMMM>

    r i*/4*+ )*-eY r O8* n*/4*+ /*1+M3. r V..- +.1 t > ):q*.&Ci*/4*+V..-(*,-./F > 6

    where tis the address of the kernel boot sector loaded. In my

    case tis $%6$$$$, as we can see in a memory dump:

    The bootloader has now loaded the Linux kernel into memory, filled the

    header fields and jumped to it. Now we can move directly to the kernel setup

    code.

  • 7/25/2019 Kernel Booting Process

    9/16

    Start of Kernel Setup

    Finally we are in the kernel. Technically the kernel hasn't run yet, we need to

    set up the kernel, memory manager, process manager etc first. Kernel setup

    execution starts from arch/x86/boot/header.Sat _start. It is a little strange at

    first sight, as there are several instructions before it.

    A Long time ago the Linux kernel had its own bootloader, but now if you run

    for example:

    d*3eM)9)-*3M%f7J7E K3+:4eqMhH6fM2*4*/:,

    You will see:

  • 7/25/2019 Kernel Booting Process

    10/16

    Actually 8*1

  • 7/25/2019 Kernel Booting Process

    11/16

    It means that segment registers will have the following values after kernel

    setup starts:

    2) = &) = *) =

  • 7/25/2019 Kernel Booting Process

    12/16

    Actually, almost all of the setup code is preparation for the C language

    environment in real mode. The next stepis checking the ))register value and

    making a correct stack if ))is wrong:

    3.KZ w))_ w

  • 7/25/2019 Kernel Booting Process

    13/16

    In the second scenario, ())!=

  • 7/25/2019 Kernel Booting Process

    14/16

    When ';PJm(NJxN;"is not set, we just use a minimal stack from J*4

    (O;'iJ(!vN:

    BSS Setup

  • 7/25/2019 Kernel Booting Process

    15/16

    The last two steps that need to happen before we can jump to the main C

    code, are setting up the BSSarea and checking the "magic" signature. First,

    signature checking:

    ,3Y+ b$%U1U111UU_ )*-eYJ):2 a4* )*-eYJ01