《Linux内核分析》MOOC课程第三次实验作业
来源:互联网 发布:多重搜索算法 编辑:程序博客网 时间:2024/05/17 22:32
ustc赵凌云 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
操作系统启动综述
计算机启动的过程其实在Andrew S.Tanenbaum所著的《现代操作系统》(中文版第18页)中就有大略的描述:
1.计算机启动时,存储在RAM中的BIOS程序检查计算机的所有设备,包括RAM、键盘、鼠标、ISA及PCI总线上的设备等,这些设备将被记录下来。
2.BIOS寻找可引导介质,从软盘、CD或硬盘中加载操作系统,将控制权交给操作系统中的引导程序。
3.操作系统询问BIOS,获得各个设备的配置信息,然后开始进行初始化工作。
start_kernel函数分析
asmlinkage __visible void __init start_kernel(void)
{
...
// lockdep_init()是个宏,定义在kernel/fork.c中第388行,如下:
// # define lockdep_init() do { } while (0)
// 可见没做什么事,留作未来扩展之用。
lockdep_init();
// init_task的类型为task_struct.task_struct包含了一个进程相关的所有信息,
// task_struct就是进程描述符(process descriptor)。
// init_task就是内核中第一个进程,也就是idle进程或0号进程的process descriptor,
// init_task由INIT_TASK宏完成初始化,
// set_task_stack_end_magic函数定义在kernel/fork.c中第297行到303行,
// 用于设置进程栈增长的终点。进程描述符和紧挨着的线程描述符thread_info,通常占据内核
// 分配的8K空间,并占据两个连续的内存页框,堆栈从这8K的高地址开始增长,在thread_info
// 结构外设置一个魔数,避免栈数据覆盖了thread_info结构。
set_task_stack_end_magic(&init_task);
// 以下3个函数定义为空,不做分析
smp_setup_processor_id();
debug_objects_early_init();
boot_init_stack_canary();
// 函数体为return 0,不做分析
cgroup_init_early();
// 关闭当前CPU中断
local_irq_disable();
early_boot_irqs_disabled = true;
// 在多CPU机器上选择CPU
boot_cpu_init();
// 定义在mm/highmem.c第479行,用于高端内存初始化
page_address_init();
// 打印linux版本信息
pr_notice("%s", linux_banner);
// setup_arch是个特定与体系结构的函数,主要关注内存管理各个方面的初始化。
// 在IA-32系统上,首先记录下内核在物理和虚拟内存中的位置。
// 调用setup_memory_map初始化bootmem分配器;
// 调用parse_early_param对命令行参数进行部分解释,处理与内存管理设置相关的参数;
setup_arch(&command_line);
mm_init_cpumask(&init_mm);
// 对command_line备份与保存
setup_command_line(command_line);
// 以下3个函数在IA-32定义为空
setup_nr_cpu_ids();
setup_per_cpu_areas();
smp_prepare_boot_cpu();
// 设置内存的相关节点和其中的内存域数据结构
build_all_zonelists(NULL, NULL);
// 初始化page allocation相关数据结构
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, &unknown_bootoption);
if (!IS_ERR_OR_NULL(after_dashes))
parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
set_init_arg);
jump_label_init();
// 使用bootmem分配一个启动信息的缓冲区
setup_log_buf(0);
// 使用bootmem分配并初始化PID散列表
pidhash_init();
// 前期VFS缓存初始化
vfs_caches_init_early();
// 对内核异常表进行排序
sort_main_extable();
// 对内核陷阱异常经行初始化
trap_init();
// 初始化内核内存分配器,启动信息中的内存信息来自此函数中的mem_init函数
mm_init();
// 初始化调度器的数据结构,并创建运行队列
sched_init();
// 禁用抢占和中断,早期启动时期,调度是极其脆弱的
preempt_disable();
if (WARN(!irqs_disabled(),
"Interrupts were enabled *very* early, fixing it\n"))
local_irq_disable();
// 为IDR机制分配缓存
idr_init_cache();
// 内核RCU机制初始化
rcu_init();
context_tracking_init();
// 内核radix树算法初始化
radix_tree_init();
// 前期外部中断描述符初始化
early_irq_init();
// 架构相关中断初始化
init_IRQ();
// 初始化内核时钟
tick_init();
// 函数定义为空
rcu_init_nohz();
// 以下5个函数是软中断和内核时钟机制初始化
init_timers();
hrtimers_init();
softirq_init();
timekeeping_init();
time_init();
sched_clock_postinit();
perf_event_init();
// profile子系统初始化,内核的性能调试工具
profile_init();
call_function_init();
WARN(!irqs_disabled(), "Interrupts were enabled early\n");
// 开启总中断
early_boot_irqs_disabled = false;
local_irq_enable();
// slab分配器后期初始化
kmem_cache_init_late();
// 初始化控制台
console_init();
if (panic_later)
panic("Too many boot %s vars at `%s'", panic_later,
panic_param);
// 打印lockdep调试模块信息
lockdep_info();
// 开启总中断后,用于测试lock inversion bugs
locking_selftest();
...
// 以下3个函数定义为空
page_cgroup_init();
debug_objects_mem_init();
kmemleak_init();
// 设置每个CPU的页组并初始化
setup_per_cpu_pageset();
// 分一致性内存访问(NUMA)初始化
numa_policy_init();
if (late_time_init)
late_time_init();
// 初始化调度时钟
sched_clock_init();
calibrate_delay();
// PID分配映射初始化
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_info_cache_init();
// 任务信用系统初始化
cred_init();
// 进程创建机制初始化
fork_init(totalram_pages);
proc_caches_init();
// 缓存系统初始化,创建缓存头空间,并检查其大小限制
buffer_init();
// 内核密钥管理系统初始化
key_init();
// 内核安全框架初始化
security_init();
// 内核调试系统后期初始化
dbg_late_init();
// 虚拟文件系统缓存初始化
vfs_caches_init(totalram_pages);
// 信号管理系统初始化
signals_init();
// 页回写机制初始化
page_writeback_init();
// proc文件系统初始化
proc_root_init();
// 定义为空
cgroup_init();
// CPUSET初始化
cpuset_init();
// 任务状态早期初始化函数,为任务获取高速缓存并初始化互斥机制
taskstats_init_early();
// 任务延迟机制初始化
delayacct_init();
check_bugs();
sfi_init_late();
if (efi_enabled(EFI_RUNTIME_SERVICES)) {
efi_late_init();
efi_free_boot_services();
}
ftrace_init();
// 其余部分初始化
rest_init();
}
总结:
1 )idle和1号进程怎么来的:
函数创建第一个核心进程kernel_init,同时init_task进程继续对Linux系统初始化。在完成初始化后,init_task会退化为cpu_idle进程,当Core0的就绪队列中没有其它进程时,该进程将会获得CPU运行。新创建的1号进程kernel_init将会逐个启动次CPU,并最终创建用户进程!
kernel_init 1号线程初始化
主要包括三方面
第一:引导SMP系统中的其它CPU(即AP(Aplication Processor))
第二:调用do_basic_setup()函数,完成Linux系统其它模块的初始化;
第三:更换核心进程kernel_init为普通进程之后,完成对Linux系统的二次引导,即对Linux系统应用程序的引导
2)start_kernel如何运行的:
调用load_up_mmu()重新装载MMU相关的寄存器,开启MMU并跳到start_kernel
再次让CPU进入是实地址模式,去运行load_up_mmu()函数。这样做的目的是让core0在实模式下调用load_up_mmu()函数来重新装载MMU相关的寄存器,比如SDR1,BAT寄存器等。之所以要重新转载,是因为我们在<11>:blinitial_bats,创建的临时BAT块地址映射,只是启动的第一阶段用到的临时映射,现在这个临时地址映射需要舍弃了,我们需要重新初始化MMU,来建立正式的MMU地址映射从__start()到start_here()再到调用start_kernel(),主要的工作与当前目标板的硬件结构密切相关,包含对一些底层硬件进行最基本初始化操作等等,从start_kernel()开始的初始化操作与处理器的类型基本无关了。
- 《Linux内核分析》MOOC课程第三次实验作业
- 《Linux内核分析》MOOC课程第一次实验作业
- 《Linux内核分析》MOOC课程第二次实验作业
- 《Linux内核分析》MOOC课程第四次实验作业
- 《Linux内核分析》MOOC课程第五次实验作业
- 《Linux内核分析》MOOC课程第六次实验作业
- 《Linux内核分析》MOOC课程第七次实验作业
- 《Linux内核分析》MOOC课程第八次实验作业
- MOOC课程"Linux内核分析"之作业一
- MOOC课程"Linux内核分析"之作业二
- Linux内核分析 第三次作业
- Linux内核分析MOOC课程汇编分析
- 《LINUX 内核分析》MOOC课程总结
- 网易MOOC《Linux内核分析》第一节作业
- 《Linux内核分析》MOOC课-mykernel实验
- 2010.11 Linux内核分析第三次作业
- 李望 原创作品转载请注明出处 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-10000290
- MOOC课程《Linux内核分析》——反汇编一个简单的C程序
- 手机信息页面设置
- 街道管理
- C语言指针总结之程序举例分析
- 类型转换
- 多线程等待唤醒机制之生产消费者模式
- 《Linux内核分析》MOOC课程第三次实验作业
- 全模型驱动架构(f-MDA)的基本思想
- 如何取消笔记本的触屏功能
- 新手理解HTML、CSS、javascript之间的关系
- 使用C语言查看/创建/终止进程
- 数据库基本知识(一)
- 安装sqlserver时“试图执行未经授权的操作”的错误
- URAL
- NIO和AIO