ebook img

Linux Inside PDF

2016·5.1 MB·English
by  0xAX
Save to my drive
Quick download
Download
Most books are stored in the elastic cloud where traffic is expensive. For this reason, we have a limit on daily download.

Preview Linux Inside

Linux Inside Table of Contents Introduction 0 Booting 1 From bootloader to kernel 1.1 First steps in the kernel setup code 1.2 Video mode initialization and transition to protected mode 1.3 Transition to 64-bit mode 1.4 Kernel decompression 1.5 Initialization 2 First steps in the kernel 2.1 Early interrupts handler 2.2 Last preparations before the kernel entry point 2.3 Kernel entry point 2.4 Continue architecture-specific boot-time initializations 2.5 Architecture-specific initializations, again... 2.6 End of the architecture-specific initializations, almost... 2.7 Scheduler initialization 2.8 RCU initialization 2.9 End of initialization 2.10 Interrupts 3 Introduction 3.1 Start to dive into interrupts 3.2 Interrupt handlers 3.3 Initialization of non-early interrupt gates 3.4 Implementation of some exception handlers 3.5 Handling Non-Maskable interrupts 3.6 Dive into external hardware interrupts 3.7 Initialization of external hardware interrupts structures 3.8 Softirq, Tasklets and Workqueues 3.9 Last part 3.10 System calls 4 2 Linux Inside Introduction to system calls 4.1 How the Linux kernel handles a system call 4.2 vsyscall and vDSO 4.3 How the Linux kernel runs a program 4.4 Timers and time management 5 Introduction 5.1 Clocksource framework 5.2 The tick broadcast framework and dyntick 5.3 Introduction to timers 5.4 Clockevents framework 5.5 x86 related clock sources 5.6 Time related system calls 5.7 Synchronization primitives 6 Introduction to spinlocks 6.1 Memory management 7 Memblock 7.1 Fixmaps and ioremap 7.2 SMP 8 Concepts 9 Per-CPU variables 9.1 Cpumasks 9.2 The initcall mechanism 9.3 Data Structures in the Linux Kernel 10 Doubly linked list 10.1 Radix tree 10.2 Bit arrays 10.3 Theory 11 Paging 11.1 Elf64 11.2 CPUID 11.3 MSR 11.4 Initial ram disk 12 initrd 12.1 Misc 13 3 Linux Inside How the kernel is compiled 13.1 Linkers 13.2 Linux kernel development 13.3 Write and Submit your first Linux kernel Patch 13.4 Data types in the kernel 13.5 Useful links 14 Contributors 15 4 Linux Inside linux-insides An book-in-progress about the linux kernel and its insides. The goal is simple - to share my modest knowledge about the insides of the linux kernel and help people who are interested in linux kernel insides, and other low-level subject matter. Questions/Suggestions: Feel free about any questions or suggestions by pinging me at twitter @0xAX, adding an issue or just drop me an email. Support Support If you like linux-insides you can support me with: On other languages Chinese Spanish LICENSE Licensed BY-NC-SA Creative Commons. Contributions Feel free to create issues or pull-requests if you have any problems. Please read CONTRIBUTING.md before pushing any changes. Introduction 5 Linux Inside Author @0xAX Introduction 6 Linux Inside Kernel boot process This chapter describes the linux kernel boot process. You will see here a couple of posts which describe the full cycle of the kernel loading process: From the bootloader to kernel - describes all stages from turning on the computer to running the first instruction of the kernel; First steps in the kernel setup code - describes first steps in the kernel setup code. You will see heap initialization, query of different parameters like EDD, IST and etc... Video mode initialization and transition to protected mode - describes video mode initialization in the kernel setup code and transition to protected mode. Transition to 64-bit mode - describes preparation for transition into 64-bit mode and details of transition. Kernel Decompression - describes preparation before kernel decompression and details of direct decompression. Booting 7 Linux Inside 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 email or just create an issue. I appreciate it. All posts will also be accessible at linux-insides 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 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. 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. From bootloader to kernel 8 Linux Inside 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 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 8086 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-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 segmentation is 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 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 part: PhysicalAddress = Segment Selector * 16 + Offset For example if CS:IP is 0x2000:0x0010 , the corresponding physical address will be: >>> hex((0x2000 << 4) + 0x0010) '0x20010' But if we take the largest segment selector and offset: 0xffff:0xffff , it will be: >>> hex((0xffff << 4) + 0xffff) '0x10ffef' which is 65520 bytes over first megabyte. Since only one megabyte is accessible in real mode, 0x10ffef becomes 0x00ffef with disabled A20. Ok, now we know about real mode and memory addressing. Let's get back to discuss about 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 From bootloader to kernel 9 Linux Inside 0xf000 and the base address is loaded with 0xffff0000. The processor uses this special base address until CS is changed. 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 4GB - 16 bytes. This point is called the Reset vector. This is the memory location at which the CPU expects to find the first instruction to execute after reset. It contains a jump instruction which usually points to the BIOS entry point. For example, if we look in the coreboot source code, we see: .section ".reset" .code16 .globl reset_vector reset_vector: .byte 0xe9 .int _start - ( . + 2 ) ... Here we can see the jmp instruction opcode - 0xe9 and its destination address - _start - ( . + 2) , and we can see that the reset section is 16 bytes and starts at 0xfffffff0 : SECTIONS { _ROMTOP = 0xfffffff0; . = _ROMTOP; .reset . : { *(.reset) . = 15 ; BYTE(0x00); } } 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 0x55 and 0xaa , which signals the BIOS that this device is bootable. For example: From bootloader to kernel 10

See more

The list of books you might like

Most books are stored in the elastic cloud where traffic is expensive. For this reason, we have a limit on daily download.