您的位置:首页 > 运维架构 > Linux

Linux内核分析作业第三周

2016-03-10 16:01 666 查看
一、实验楼实验

使用实验楼的虚拟机打开shell


1 cd LinuxKernel/
2 qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img


内核启动完成后进入menu程序,支持三个命令help、version和quit



使用gdb跟踪调试内核


1 qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S # 关于-s和-S选项的说明:
2 # -S freeze CPU at startup (use ’c’ to start execution)
3 # -s shorthand for -gdb tcp::1234 若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项





另开一个shell窗口


1 gdb
2 (gdb)file linux-3.18.6/vmlinux # 在gdb界面中targe remote之前加载符号表
3 (gdb)target remote:1234 # 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行
4 (gdb)break start_kernel # 断点的设置可以在target remote之前,也可以在之后







按c后系统开始运行,启动到start_cernel的位置



输入list之后看到执行的位置



再设置一个断点,系统执行到rest_init的位置



二、简单分析一下start_kernel

1、在init目录下main.c里找到start_kernel函数


500asmlinkage __visible void __init start_kernel(void)
501{
502	char *command_line;
503	char *after_dashes;
504
505	/*
506	 * Need to run as early as possible, to initialize the
507	 * lockdep hash:
508	 */
509	lockdep_init();
510	set_task_stack_end_magic(&init_task);    //全局变量init_task,即手工创建的PCB,0号进程即最终的idle进程
511	smp_setup_processor_id();
512	debug_objects_early_init();
513
514	/*
515	 * Set up the the initial canary ASAP:
516	 */
517	boot_init_stack_canary();
518
519	cgroup_init_early();
520
521	local_irq_disable();
522	early_boot_irqs_disabled = true;



init_process是一号进程。


393static noinline void __init_refok rest_init(void)
394{
395	int pid;
396
397	rcu_scheduler_starting();
398	/*
399	 * We need to spawn init first so that it obtains pid 1, however
400	 * the init task will end up wanting to create kthreads, which, if
401	 * we schedule it before we create kthreadd, will OOPS.
402	 */
403	kernel_thread(kernel_init, NULL, CLONE_FS);    //创建第一个用户态进程
404	numa_default_policy();
405	pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);    //内核进程来管理资源
406	rcu_read_lock();
407	kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
408	rcu_read_unlock();
409	complete(&kthreadd_done);


[b]三、总结
[/b]

  总的来说在rest_init函数中,内核产生第一个真正的进程:
    (pid=1):init_idle(current, smp_processor_id())函数的调用把init_task初始化成idle task
  init_idle函数的第一个参数current就是&init_task,在init_idle中将会把init_task加入到cpu的运行队列中,这样当运行队列中没有别的就绪进程时,init_task(也就是idle task)将会被调用。
  sched_init()初始化函数内对0号进程,即idle进程进行初始化rest_init()->cpu_startup_entry()->cpu_idle_loop()就是一直循环,当系统没有进程需要执行的时候就调度idle进程,从内核启动开始一直存在,0号进程。0号进程创建了1号进程,并且还创建了内核中其他的一些服务线程。
  init目录下main.c中的start_kernel是启动内核的起点。
[/code]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: