mirror of
https://github.com/gatieme/LDD-LinuxDeviceDrivers.git
synced 2026-09-24 22:43:42 +08:00
...
This commit is contained in:
@@ -1,185 +0,0 @@
|
||||
asmlinkage __visible void __init start_kernel(void)
|
||||
{
|
||||
char *command_line;
|
||||
char *after_dashes;
|
||||
|
||||
set_task_stack_end_magic(&init_task);
|
||||
smp_setup_processor_id();
|
||||
debug_objects_early_init();
|
||||
|
||||
/*
|
||||
* Set up the the initial canary ASAP:
|
||||
*/
|
||||
boot_init_stack_canary();
|
||||
|
||||
cgroup_init_early();
|
||||
|
||||
local_irq_disable();
|
||||
early_boot_irqs_disabled = true;
|
||||
|
||||
/*
|
||||
* Interrupts are still disabled. Do necessary setups, then
|
||||
* enable them
|
||||
*/
|
||||
boot_cpu_init();
|
||||
page_address_init();
|
||||
pr_notice("%s", linux_banner);
|
||||
setup_arch(&command_line);
|
||||
mm_init_cpumask(&init_mm);
|
||||
setup_command_line(command_line);
|
||||
setup_nr_cpu_ids();
|
||||
setup_per_cpu_areas();
|
||||
boot_cpu_state_init();
|
||||
smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
|
||||
|
||||
build_all_zonelists(NULL, NULL);
|
||||
page_alloc_init();
|
||||
|
||||
pr_notice("Kernel command line: %s\n", boot_command_line);
|
||||
parse_early_param();
|
||||
after_dashes = parse_args("Booting kernel",
|
||||
static_command_line, __start___param,
|
||||
__stop___param - __start___param,
|
||||
-1, -1, NULL, &unknown_bootoption);
|
||||
if (!IS_ERR_OR_NULL(after_dashes))
|
||||
parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
|
||||
NULL, set_init_arg);
|
||||
|
||||
jump_label_init();
|
||||
|
||||
/*
|
||||
* These use large bootmem allocations and must precede
|
||||
* kmem_cache_init()
|
||||
*/
|
||||
setup_log_buf(0);
|
||||
pidhash_init();
|
||||
vfs_caches_init_early();
|
||||
sort_main_extable();
|
||||
trap_init();
|
||||
mm_init();
|
||||
|
||||
/*
|
||||
* Set up the scheduler prior starting any interrupts (such as the
|
||||
* timer interrupt). Full topology setup happens at smp_init()
|
||||
* time - but meanwhile we still have a functioning scheduler.
|
||||
*/
|
||||
sched_init();
|
||||
/*
|
||||
* Disable preemption - early bootup scheduling is extremely
|
||||
* fragile until we cpu_idle() for the first time.
|
||||
*/
|
||||
preempt_disable();
|
||||
if (WARN(!irqs_disabled(),
|
||||
"Interrupts were enabled *very* early, fixing it\n"))
|
||||
local_irq_disable();
|
||||
idr_init_cache();
|
||||
rcu_init();
|
||||
|
||||
/* trace_printk() and trace points may be used after this */
|
||||
trace_init();
|
||||
|
||||
context_tracking_init();
|
||||
radix_tree_init();
|
||||
/* init some links before init_ISA_irqs() */
|
||||
early_irq_init();
|
||||
init_IRQ();
|
||||
tick_init();
|
||||
rcu_init_nohz();
|
||||
init_timers();
|
||||
hrtimers_init();
|
||||
softirq_init();
|
||||
timekeeping_init();
|
||||
time_init();
|
||||
sched_clock_postinit();
|
||||
printk_nmi_init();
|
||||
perf_event_init();
|
||||
profile_init();
|
||||
call_function_init();
|
||||
WARN(!irqs_disabled(), "Interrupts were enabled early\n");
|
||||
early_boot_irqs_disabled = false;
|
||||
local_irq_enable();
|
||||
|
||||
kmem_cache_init_late();
|
||||
|
||||
/*
|
||||
* HACK ALERT! This is early. We're enabling the console before
|
||||
* we've done PCI setups etc, and console_init() must be aware of
|
||||
* this. But we do want output early, in case something goes wrong.
|
||||
*/
|
||||
console_init();
|
||||
if (panic_later)
|
||||
panic("Too many boot %s vars at `%s'", panic_later,
|
||||
panic_param);
|
||||
|
||||
lockdep_info();
|
||||
|
||||
/*
|
||||
* Need to run this when irqs are enabled, because it wants
|
||||
* to self-test [hard/soft]-irqs on/off lock inversion bugs
|
||||
* too:
|
||||
*/
|
||||
locking_selftest();
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
if (initrd_start && !initrd_below_start_ok &&
|
||||
page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
|
||||
pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",
|
||||
page_to_pfn(virt_to_page((void *)initrd_start)),
|
||||
min_low_pfn);
|
||||
initrd_start = 0;
|
||||
}
|
||||
#endif
|
||||
page_ext_init();
|
||||
debug_objects_mem_init();
|
||||
kmemleak_init();
|
||||
setup_per_cpu_pageset();
|
||||
numa_policy_init();
|
||||
if (late_time_init)
|
||||
late_time_init();
|
||||
sched_clock_init();
|
||||
calibrate_delay();
|
||||
pidmap_init();
|
||||
anon_vma_init();
|
||||
acpi_early_init();
|
||||
#ifdef CONFIG_X86
|
||||
if (efi_enabled(EFI_RUNTIME_SERVICES))
|
||||
efi_enter_virtual_mode();
|
||||
#endif
|
||||
#ifdef CONFIG_X86_ESPFIX64
|
||||
/* Should be run before the first non-init thread is created */
|
||||
init_espfix_bsp();
|
||||
#endif
|
||||
thread_stack_cache_init();
|
||||
cred_init();
|
||||
fork_init();
|
||||
proc_caches_init();
|
||||
buffer_init();
|
||||
key_init();
|
||||
security_init();
|
||||
dbg_late_init();
|
||||
vfs_caches_init();
|
||||
signals_init();
|
||||
/* rootfs populating might need page-writeback */
|
||||
page_writeback_init();
|
||||
proc_root_init();
|
||||
nsfs_init();
|
||||
cpuset_init();
|
||||
cgroup_init();
|
||||
taskstats_init_early();
|
||||
delayacct_init();
|
||||
|
||||
check_bugs();
|
||||
|
||||
acpi_subsystem_init();
|
||||
sfi_init_late();
|
||||
|
||||
if (efi_enabled(EFI_RUNTIME_SERVICES)) {
|
||||
efi_late_init();
|
||||
efi_free_boot_services();
|
||||
}
|
||||
|
||||
ftrace_init();
|
||||
|
||||
/* Do the rest non-__init'ed, we're now alive */
|
||||
rest_init();
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
服务器体系与共享存储器架构
|
||||
=======
|
||||
|
||||
| 日期 | 内核版本 | 架构| 作者 | GitHub| CSDN |
|
||||
| ------- |:-------:|:-------:|:-------:|:-------:|:-------:|
|
||||
| 2016-06-14 | [Linux-4.7](http://lxr.free-electrons.com/source/?v=4.7) | X86 & arm | [gatieme](http://blog.csdn.net/gatieme) | [LinuxDeviceDrivers](https://github.com/gatieme/LDD-LinuxDeviceDrivers) | [Linux内存管理](http://blog.csdn.net/gatieme/article/category/6225543) |
|
||||
|
||||
|
||||
|
||||
|
||||
在内核初始化完成之后, 内存管理的责任就由伙伴系统来承担. 伙伴系统基于一种相对简单然而令人吃惊的强大算法.
|
||||
|
||||
|
||||
|
||||
#2 伙伴系统的结构
|
||||
-------
|
||||
|
||||
|
||||
系统内存中的每个物理内存页(页帧),都对应于一个struct page实例, 每个内存域都关联了一个struct zone的实例,其中保存了用于管理伙伴数据的主要数数组
|
||||
|
||||
|
||||
```cpp
|
||||
// http://lxr.free-electrons.com/source/include/linux/mmzone.h?v=4.7#L324
|
||||
struct zone
|
||||
{
|
||||
/* free areas of different sizes */
|
||||
struct free_area free_area[MAX_ORDER];
|
||||
};
|
||||
```
|
||||
|
||||
struct free_area是一个辅助数据结构, 它定义在[include/linux/mmzone.h?v=4.7, line 88](http://lxr.free-electrons.com/source/include/linux/mmzone.h?v=4.7#L88)
|
||||
|
||||
```cpp
|
||||
struct free_area {
|
||||
struct list_head free_list[MIGRATE_TYPES];
|
||||
unsigned long nr_free;
|
||||
};
|
||||
```
|
||||
|
||||
| 字段 | 描述 |
|
||||
|:-----:|:-----:|
|
||||
| free_list | 是用于连接空闲页的链表. 页链表包含大小相同的连续内存区 |
|
||||
| nr_free | 指定了当前内存区中空闲页块的数目(对0阶内存区逐页计算,对1阶内存区计算页对的数目,对2阶内存区计算4页集合的数目,依次类推 |
|
||||
|
||||
|
||||
阶是伙伴系统中一个非常重要的术语. 它描述了内存分配的数量单位. 内存块的长度是2order,其中order的范围从0到MAX_ORDER, 参见[include/linux/mmzone.h?v=4.7, line 22](http://lxr.free-electrons.com/source/include/linux/mmzone.h?v=4.7#L22)
|
||||
|
||||
```cpp
|
||||
/* Free memory management - zoned buddy allocator. */
|
||||
#ifndef CONFIG_FORCE_MAX_ZONEORDER
|
||||
#define MAX_ORDER 11
|
||||
#else
|
||||
#define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER
|
||||
#endif
|
||||
#define MAX_ORDER_NR_PAGES (1 << (MAX_ORDER - 1))
|
||||
```
|
||||
|
||||
|
||||
该常数通常设置为11,这意味着一次分配可以请求的页数最大是2^11=2048
|
||||
|
||||
但如果特定于体系结构的代码设置了FORCE_MAX_ZONEORDER配置选项, 该值也可以手工改变
|
||||
|
||||
例如,IA-64系统上巨大的地址空间可以处理`MAX_ORDER = 18`的情形,而ARM或v850系统则使用更小的值(如8或9). 但这不一定是由计算机支持的内存数量比较小引起的,也可能是内存对齐方式的要求所导致
|
||||
|
||||
或者可以参考arm体系结构的Kconfig配置文件的描述
|
||||
|
||||
```cpp
|
||||
config FORCE_MAX_ZONEORDER
|
||||
int
|
||||
default "14" if (ARM64_64K_PAGES && TRANSPARENT_HUGEPAGE)
|
||||
default "12" if (ARM64_16K_PAGES && TRANSPARENT_HUGEPAGE)
|
||||
default "11"`
|
||||
```
|
||||
|
||||
free_area[]数组中各个元素的索引也解释为阶,用于指定对应链表中的连续内存区包含多少个
|
||||
页帧。第0个链表包含的内存区为单页(20=1),第1个链表管理的内存区为两页(21=2),第3个管理
|
||||
的内存区为4页,依次类推。
|
||||
内存区是如何连接的?内存区中第1页内的链表元素,可用于将内存区维持在链表中。因此,也
|
||||
不必引入新的数据结构来管理物理上连续的页,否则这些页不可能在同一内存区中.
|
||||
|
||||
图3-22对此给出
|
||||
了图示。
|
||||
@@ -1,46 +0,0 @@
|
||||
服务器体系与共享存储器架构
|
||||
=======
|
||||
|
||||
| 日期 | 内核版本 | 架构| 作者 | GitHub| CSDN |
|
||||
| ------- |:-------:|:-------:|:-------:|:-------:|:-------:|
|
||||
| 2016-06-14 | [Linux-4.7](http://lxr.free-electrons.com/source/?v=4.7) | X86 & arm | [gatieme](http://blog.csdn.net/gatieme) | [LinuxDeviceDrivers](https://github.com/gatieme/LDD-LinuxDeviceDrivers) | [Linux内存管理](http://blog.csdn.net/gatieme/article/category/6225543) |
|
||||
|
||||
|
||||
#1 目录
|
||||
-------
|
||||
|
||||
| CSDN | GitHub |
|
||||
|:-------:|:-------:|
|
||||
| 描述物理内存 |
|
||||
| 页表管理 |
|
||||
| 初始化内存挂历 |
|
||||
| 物理内存的管理 |
|
||||
| slab分配器 |
|
||||
|
||||
| 非连续内存分配 |
|
||||
| 高端内存管理 |
|
||||
| 页面帧回收 |
|
||||
| 交换管理 |
|
||||
| 进程虚拟地址空间 |
|
||||
| 共享内存虚拟文件系统 |
|
||||
| 内存溢出管理 |
|
||||
|
||||
|
||||
#2 参考内容
|
||||
-------
|
||||
|
||||
| 链接 |
|
||||
|:-------:|
|
||||
| [内存管理(一)内存模型之Node](http://biancheng.dnbcw.info/linux/387391.html) |
|
||||
| [Linux 内存管理 重要结构体](http://blog.chinaunix.net/uid-26009500-id-3078986.html) |
|
||||
| [Bootmem机制](http://blog.csdn.net/samssm/article/details/25064897) |
|
||||
| [Linux-2.6.32 NUMA架构之内存和调度](http://www.cnblogs.com/zhenjing/archive/2012/03/21/linux_numa.html) |
|
||||
| [Linux 用户空间与内核空间——高端内存详解](http://blog.csdn.net/tommy_wxie/article/details/17122923) |
|
||||
| [探索 Linux 内存模型](http://www.ibm.com/developerworks/cn/linux/l-memmod/) |
|
||||
| [Linux内存管理](http://blog.chinaunix.net/uid/21718047/cid-151509-list-2.html) |
|
||||
| [内存管理-之内核内存管理-基于linux3.10](http://blog.csdn.net/shichaog/article/details/45509917) |
|
||||
| [内存管理(一)](http://www.cnblogs.com/openix/p/3334026.html) |
|
||||
| [Linux内存管理原理](http://www.cnblogs.com/zhaoyl/p/3695517.html) |
|
||||
| [第 15 章 内存映射和 DMA](http://www.embeddedlinux.org.cn/ldd3/ch15.html) |
|
||||
| [ 内存管理(二)struct page ](http://blog.chinaunix.net/uid-30282771-id-5176971.html) |
|
||||
|
||||
Reference in New Issue
Block a user