Merge pull request #276 from hust-open-atom-club/fix_code_syntax
Fix code syntax
BIN
Cgroups/images/menuconfig.png
Normal file
|
After Width: | Height: | Size: 103 KiB |
@@ -25,7 +25,7 @@
|
||||
|
||||
每个 `cgroup` 子系统是否被支持均与相关配置选项有关。例如,`cpuset` 子系统应该通过 `CONFIG_CPUSETS` 内核配置选项启用,`io` 子系统通过 `CONFIG_BLK_CGROUP` 内核配置选项等。所有这些内核配置选项都可以在 `General setup → Control Group support` 菜单里找到:
|
||||
|
||||

|
||||

|
||||
|
||||
你可以通过 [proc](https://en.wikipedia.org/wiki/Procfs) 虚拟文件系统在计算机上查看已经启用的 `cgroup`:
|
||||
|
||||
|
||||
BIN
Initialization/images/CONFIG_NR_CPUS.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
Initialization/images/NX.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
Initialization/images/brk_area.png
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
Initialization/images/kernel_command_line.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
@@ -94,7 +94,7 @@ noexec [X86]
|
||||
|
||||
我们可以在启动的时候看到:
|
||||
|
||||

|
||||

|
||||
|
||||
之后我们可以看到下面函数的调用:
|
||||
|
||||
@@ -419,7 +419,7 @@ struct mpf_intel {
|
||||
|
||||
正如我们在文档中看到的那样 - 系统 BIOS的主要功能之一就是创建MP浮点型指针结构和MP配置表。而且操作系统必须可以访问关于多处理器配置的有关信息, `mpf_intel` 中存储了多处理器配置表的物理地址(看结构体的第二个变量),然后,`smp_scan_config` 函数在指定的内存区域中循环查找 `MP floating pointer structure` 。这个函数还会检查当前字节是否指向 `SMP` 签名,然后检查签名的校验和,并且检查循环中的 `mpf->specification` 的值是1还是4(这个值只能是1或者是4):
|
||||
|
||||
```C7
|
||||
```C
|
||||
while (length > 0) {
|
||||
if ((*bp == SMP_MAGIC_IDENT) &&
|
||||
(mpf->length == 1) &&
|
||||
@@ -471,7 +471,7 @@ void __init early_alloc_pgt_buf(void)
|
||||
|
||||
我们也可以使用 `readelf` 工具来找到它:
|
||||
|
||||

|
||||

|
||||
|
||||
之后我们用 `_pa` 宏得到了新的 `brk` 区段的物理地址,我们计算页表缓冲区的基地址和结束地址。因为我们之前已经创建好了页面缓冲区,所以现在我们使用 `reserve_brk` 函数为 `brk` 区段保留内存块:
|
||||
|
||||
|
||||
@@ -390,7 +390,7 @@ void __init setup_nr_cpu_ids(void)
|
||||
|
||||
Here `nr_cpu_ids` represents number of CPUs, `NR_CPUS` represents the maximum number of CPUs which we can set in configuration time:
|
||||
|
||||

|
||||

|
||||
|
||||
Actually we need to call this function, because `NR_CPUS` can be greater than actual amount of the CPUs in the your computer. Here we can see that we call `find_last_bit` function and pass two parameters to it:
|
||||
|
||||
|
||||
@@ -178,7 +178,7 @@ and initializes handler for the `CPU` [hotplug](https://www.kernel.org/doc/Docum
|
||||
|
||||
After this we can see the kernel command line in the initialization output:
|
||||
|
||||

|
||||

|
||||
|
||||
And a couple of functions such as `parse_early_param` and `parse_args` which handles linux kernel command line. You may remember that we already saw the call of the `parse_early_param` function in the sixth [part](/Initialization/linux-initialization-6.md) of the kernel initialization chapter, so why we call it again? Answer is simple: we call this function in the architecture-specific code (`x86_64` in our case), but not all architecture calls this function. And we need to call the second function `parse_args` to parse and handle non-early command line arguments.
|
||||
|
||||
|
||||
BIN
Interrupts/images/kernel.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
@@ -159,7 +159,7 @@ In other way, when the `CONFIG_X86_IO_APIC` kernel configuration option is set,
|
||||
|
||||
We remember from the previous parts, that the amount of processors we can set during Linux kernel configuration process with the `CONFIG_NR_CPUS` configuration option:
|
||||
|
||||

|
||||

|
||||
|
||||
In the first case (`CPU_VECTOR_LIMIT > IO_APIC_VECTOR_LIMIT`), the `NR_IRQS` will be `4352`, in the second case (`CPU_VECTOR_LIMIT < IO_APIC_VECTOR_LIMIT`), the `NR_IRQS` will be `768`. In my case the `NR_CPUS` is `8` as you can see in the my configuration, the `CPU_VECTOR_LIMIT` is `512` and the `IO_APIC_VECTOR_LIMIT` is `4096`. So `NR_IRQS` for my configuration is `4352`:
|
||||
|
||||
|
||||
BIN
MM/images/kernel_configuration_menu1.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
MM/images/kernel_configuration_menu2.png
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
MM/images/memblock.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
@@ -392,7 +392,7 @@ memblock_dbg("memblock_reserve: [%#016llx-%#016llx] flags %#02lx %pF\n",
|
||||
|
||||
然后你将看到类似下图的画面:
|
||||
|
||||

|
||||

|
||||
|
||||
内存块技术也支持 [debugfs](http://en.wikipedia.org/wiki/Debugfs) 。如果你不是在 `X86` 架构下运行内核,你可以访问:
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ Kernel hacking
|
||||
-> Memory Debugging
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
||||
`kmemcheck` 机制还提供了一些内核配置参数,我们可以在下一个段落中看到所有的可选参数。最后一个需要注意的是,`kmemcheck` 仅在 [x86_64](https://en.wikipedia.org/wiki/X86-64) 体系中实现了。为了确信这一点,我们可以查看 `x86` 的内核配置文件 [arch/x86/Kconfig](https://github.com/torvalds/linux/blob/master/arch/x86/Kconfig):
|
||||
|
||||
@@ -165,7 +165,7 @@ struct my_struct *my_struct = kmalloc(sizeof(struct my_struct), GFP_KERNEL);
|
||||
|
||||
前面两个值得含义很明确,但是最后一个需要解释。这个选项会使 `kmemcheck` 进入一种特殊的模式:在第一次检测到未初始化内存的使用之后,就会关闭 `kmemcheck` 。实际上该模式是内核的默认选项:
|
||||
|
||||

|
||||

|
||||
|
||||
从Linux初始化过程章节的第七节 [part](/Initialization/linux-initialization-7.md) 中,我们知道在内核初始化过程中,会在 `do_initcall_level` , `do_early_param` 等函数中解析内核 command line。前面也提到过 `kmemcheck` 子系统由两部分组成,第一部分启动比较早。在源码 [mm/kmemcheck.c](https://github.com/torvalds/linux/blob/master/mm/kmemcheck.c) 中有一个函数 `param_kmemcheck` ,该函数在command line解析时就会用到:
|
||||
|
||||
|
||||
BIN
Misc/images/busybox_menu.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
Misc/images/dgap_menu.png
Normal file
|
After Width: | Height: | Size: 767 KiB |
BIN
Misc/images/git_diff.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
Misc/images/github.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
Misc/images/google_linux.png
Normal file
|
After Width: | Height: | Size: 107 KiB |
BIN
Misc/images/menuconfig.png
Normal file
|
After Width: | Height: | Size: 726 KiB |
BIN
Misc/images/nconfig.png
Normal file
|
After Width: | Height: | Size: 671 KiB |
BIN
Misc/images/qemu.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
@@ -10,11 +10,11 @@ Linux 内核开发
|
||||
|
||||
在我开始学习 Linux 内核的九个半月之后,我写了这部分内容,并且发布了本书的[第一部分](/Booting/linux-bootstrap-1.md)。到现在为止,本书共包括了四个部分,而这并不是终点。我之所以写这一系列关于 Linux 内核的文章其实更多的是为了我自己。你也知道,Linux 内核的代码量极其巨大,另外还非常容易忘记这一块或那一块内核代码做了什么,或者忘记某些东西是怎么实现的。出乎意料的是 [linux-insides](https://github.com/0xAX/linux-insides) 很快就火了,并且在九个月后积攒了 `9096` 个星星:
|
||||
|
||||

|
||||

|
||||
|
||||
看起来人们对 Linux 内核的内在机制非常的感兴趣。除此之外,在我写 `linux-insides` 的这段时间里,我收到了很多人发来的问题,这些问题大都是关于如何开始向 Linux 内核贡献代码。通常来说,人们是很有兴趣为开源项目做贡献的,Linux 内核也不例外:
|
||||
|
||||

|
||||

|
||||
|
||||
这么看起来大家对 Linux 内核的开发流程非常感兴趣。我认为如果这么一本关于 Linux 内核的书却不包括一部分来讲讲如何参与 Linux 内核开发的话,那就非常奇怪了。这就是我决定写这篇文章的原因。在本文中,你不会看到为什么你应该对贡献 Linux 内核感兴趣,但是如果你想参与 Linux 内核开发的话,那这部分就是为你而作。
|
||||
|
||||
@@ -102,7 +102,7 @@ $ cat /proc/config.gz | gunzip > ~/dev/linux/.config
|
||||
|
||||
如果你对发行版维护者提供的标准内核配置文件并不满意,你也可以手动配置 Linux 内核,有两种方式可以做到这一点。Linux 内核的根 [Makefile](https://github.com/torvalds/linux/blob/master/Makefile) 文件提供了一系列可配置的目标选项。例如 `menuconfig` 为内核配置提供了一个菜单界面:
|
||||
|
||||

|
||||

|
||||
|
||||
`defconfig` 参数会为当前的架构生成默认的内核配置文件,例如 [x86_64 defconfig](https://github.com/torvalds/linux/blob/master/arch/x86/configs/x86_64_defconfig)。你可以将 `ARCH` 命令行参数传递给 `make`,以此来为给定架构创建 `defconfig` 配置文件:
|
||||
|
||||
@@ -112,7 +112,7 @@ $ make ARCH=arm64 defconfig
|
||||
|
||||
`allnoconfig`、 `allyesconfig` 以及 `allmodconfig` 参数也允许你生成新的配置文件,其效果分别为尽可能多的选项都关闭、尽可能多的选项都启用或尽可能多的选项都作为模块启用。`nconfig` 命令行参数提供了基于 `ncurses` 的菜单程序来配置 Linux 内核:
|
||||
|
||||

|
||||

|
||||
|
||||
`randconfig` 参数甚至可以随机地生成 Linux 内核配置文件。我不会讨论如何去配置 Linux 内核或启用哪个选项,因为没有必要这么做:首先,我不知道你的硬件配置;其次,如果我知道了你的硬件配置,那么剩下的问题就是搞清楚如何使用程序生成内核配置,而这些程序的使用都是非常容易的。
|
||||
|
||||
@@ -224,7 +224,7 @@ $ make -j4
|
||||
|
||||
`busybox` 是一个可执行文件 - `/bin/busybox`,它包括了一系列类似于 [coreutils](https://en.wikipedia.org/wiki/GNU_Core_Utilities) 的标准工具。在 `busysbox` 菜单界面上我们需要启用 `Build BusyBox as a static binary (no shared libs)` 选项:
|
||||
|
||||

|
||||

|
||||
|
||||
我们可以按照下方的路径找到这个菜单项:
|
||||
|
||||
@@ -273,7 +273,7 @@ $ find . -print0 | cpio --null -ov --format=newc | gzip -9 > ~/dev/initrd_x86_64
|
||||
$ qemu-system-x86_64 -snapshot -m 8GB -serial stdio -kernel ~/dev/linux/arch/x86_64/boot/bzImage -initrd ~/dev/initrd_x86_64.gz -append "root=/dev/sda1 ignore_loglevel"
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
||||
从现在起,我们就可以在虚拟机内运行 Linux 内核了,这意味着我们可以开始对内核进行修改和测试了。
|
||||
|
||||
@@ -330,7 +330,7 @@ Device Drivers
|
||||
----> Digi EPCA PCI products
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
||||
现在是时候提交修改了,我使用下面的命令组合来完成这件事:
|
||||
|
||||
@@ -424,7 +424,7 @@ CHECK: spaces preferred around that '|' (ctx:VxV)
|
||||
|
||||
在 `git diff` 命令的帮助下,你也会看到一些有问题的地方:
|
||||
|
||||

|
||||

|
||||
|
||||
* [Linus 不接受 github pull requests](https://github.com/torvalds/linux/pull/17#issuecomment-5654674)
|
||||
|
||||
|
||||
@@ -329,7 +329,7 @@ archscripts: scripts_basic
|
||||
|
||||
我们可以看到 `archscripts` 是依赖于根 [Makefile](https://github.com/torvalds/linux/blob/master/Makefile) 里的 `scripts_basic` 。首先我们可以看出 `scripts_basic` 是按照 [scripts/basic](https://github.com/torvalds/linux/blob/master/scripts/basic/Makefile) 的 Makefile 执行 make 的:
|
||||
|
||||
```Maklefile
|
||||
```Makefile
|
||||
scripts_basic:
|
||||
$(Q)$(MAKE) $(build)=scripts/basic
|
||||
```
|
||||
|
||||
BIN
SysCall/images/ls_shell.png
Normal file
|
After Width: | Height: | Size: 407 KiB |
@@ -20,7 +20,7 @@ There are many different ways to launch an application from an user perspective.
|
||||
|
||||
In this part we will consider the way when we just launch an application from the shell. As you know, the standard way to launch an application from shell is the following: We just launch a [terminal emulator](https://en.wikipedia.org/wiki/Terminal_emulator) application and just write the name of the program and pass or not arguments to our program, for example:
|
||||
|
||||

|
||||

|
||||
|
||||
Let's consider what does occur when we launch an application from the shell, what does shell do when we write program name, what does Linux kernel do etc. But before we will start to consider these interesting things, I want to warn that this book is about the Linux kernel. That's why we will see Linux kernel insides related stuff mostly in this part. We will not consider in details what does shell do, we will not consider complex cases, for example subshells etc.
|
||||
|
||||
|
||||
BIN
Theory/images/4_level_paging.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
@@ -93,7 +93,7 @@ movl %eax, %cr3
|
||||
|
||||
按照图示,我们可以这样想象它:
|
||||
|
||||

|
||||

|
||||
|
||||
每一个对线性地址的访问不是一个管态访问就是用户态访问。这个访问是被 `CPL (Current Privilege Level)` 所决定。如果 `CPL < 3` ,那么它是管态访问级,否则,它就是用户态访问级。比如,最高级页表项包含访问位和如下的结构:
|
||||
|
||||
|
||||
BIN
Timers/images/HZ.png
Normal file
|
After Width: | Height: | Size: 383 KiB |
BIN
Timers/images/base_small.png
Normal file
|
After Width: | Height: | Size: 700 KiB |
@@ -259,7 +259,7 @@ The `jiffies` clock source uses the `NSEC_PER_JIFFY` multiplier conversion to sp
|
||||
|
||||
Where `CONFIG_HZ` can be one of the following values:
|
||||
|
||||

|
||||

|
||||
|
||||
This means that in our case the timer interrupt frequency is `250 HZ` or occurs `250` times per second or one timer interrupt each `4ms`.
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ struct tvec_root {
|
||||
|
||||
type. Note that the value of the `TVR_SIZE` depends on the `CONFIG_BASE_SMALL` kernel configuration option:
|
||||
|
||||

|
||||

|
||||
|
||||
that reduces size of the kernel data structures if disabled. The `v1` is array that may contain `64` or `256` elements where an each element represents a dynamic timer that will decay within the next `255` system timer interrupts. Next three fields: `tv2`, `tv3` and `tv4` are lists with dynamic timers too, but they store dynamic timers which will decay the next `2^14 - 1`, `2^20 - 1` and `2^26` respectively. The last `tv5` field represents list which stores dynamic timers with a large expiring period.
|
||||
|
||||
|
||||