[linux内核] 2.menuos搭建及内核启动过程调试

学习内容来自庖丁解牛,仅作为个人学习研究用途,如作者认为侵权请联系第一时间删除。

1.MenuOS

menuos是基于linux内核源码构造的一个简单的操作系统。它和上一篇文章中提到的mykernel没有任何关系。
上一篇文章mykernel是在硬件起初上模拟一个cpu环境,用来学习内核的时钟中断。
这篇文章的menuos就是在官方的linux源码基础加上老师写的一个内存文件镜像和一个应用程序(menu)实现的一个操作系统。


2.linux内核目录

linux内核根目录

arch/:与体系结构相关的子目录列表,比如 arm、x86、MIPS、PPC等。alpha、arm、arm64等不同目录分别支持不同的CPU和体系结构。

block/:存放关于块设备管理的代码

crypto/:存放常见的加密算法的C语言代码

Documentation/:存放一些文档

drivers/:驱动目录

firmware/:固件

fs/:文件系统

include/:头文件目录,存放公共的头文件

init/:存放内核启动时的初始化代码
init目录下的main.c中的start_kernel函数就是内核的入口,start_kernel函数之前使用汇编进行硬件初始化

ipc/:进程间通信

kernel/:存放内核本身需要的一些核心代码文件

lib/:公用的库文件。注意在内核编程中不能用C语言标准库函数,这里的lib目录下的库函数就是用来替代那些标准库函数的。

mm/:内存管理

net/:网络相关


3.内核编译安装步骤

(1)安装依赖包
(2)下载源码
(3).config:准备配置文件
(4)make menuconfig:配置内核选项
(5)make [-j #]
(6)make modules_install:安装模块
(7)make install:安装内核相关文件
(8)安装 bzImage
(9)生成 initramfs 文件
(10)编辑grub的配置文件

相关解释

qemu仿真kerne

bzImage是vmLinux经过gzip压缩后的文件,是压缩的内核映像,(b->big)
bzImage 适用于大内核,zImage 适用于小内核

vmLinux是编译出来的最原始的内核ELF文件

根文件系统一般包括内存根文件系统磁盘根文件系统

initrd是“initial ramdisk”的简写,
普通Linux系统在启动时,是boot loader将存储介质中的initrd文件加载到内存,
内核启动时先访问initrd文件系统(内存根文件系统),然后再切换到磁盘文件系统。


4.构建MenuOs

补充
IA32是Intel32位体系结构,个人理解是一个架构规范

x86一开始指Intel推出的一套通用的计算机指令集
AMD为了提高性能推出了64位指令集叫amd64
后来intel也推出了64位指令集,叫x86-64

i386是32位cpu处理器型号,从16位80286扩展而来;
80286又是从16位8086发展而来兼容其所有功能

个人理解为:在i386等的处理器芯片上加上32位指令集(x86)就构成了一个cpu,
而这两者都是遵循IA32体系结构

这里构造的 MenuOS 系统是由 Linux 内核镜像和根文件系统集成起来的。本次实验只使用initrd根文件系统。
这里的根文件系统也比较简单,只是创建了一个 rootfs.img,其中只有一个 init 的功能采用一个自己写好的menu名字的程序。

安装rootfs的过程中gcc命令会生成init可执行文件,通过qemu相关参数设置为第一个用户态的进程。
通过把这个init文件放到rootfs目录下,再使用cpio方式将其打包成一个镜像文件,
就制作成一个简单的内存根文件系统镜像。


总结
观察搭建MenuOS三个步骤及一个qemu启动命令来看。
menuos就是先下载一个linux官方的源码并编译安装好,然后再安装老师给的项目做成一个rootfs文件系统镜像。
最后通过qemu虚拟机将内核和这个文件系统镜像放进去并设置内核从磁盘加载的内存根文件系统换成我们做好的这个文件系统(其中调用程序menu),从而模拟了一个新的操作系统。
后面要进行调试跟踪,重新配置编译 Linux 内核,使之携带调试信息。


5.跟踪调试 Linux 内核的启动过程


5.1 跟踪内核启动

使用qemu虚拟机,链接内核镜像,并设置加载内核文件系统镜像为刚才做好的rootfs.img。
-s监听1234端口
-SCPU 初始化之前冻结起来

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -S -s 

重新打开一个终端,打开gdb,链接1234端口,并设置断点
请添加图片描述


5.2 源码分析

首先看下start_kernel函数中比较重要的部分。注意start_kernel函数之前使用汇编进行硬件初始化。

asmlinkage __visible void __init start_kernel(void)	
{
	/*
	 * Need to run as early as possible, to initialize the
	 * lockdep hash:
	 */
	lockdep_init();	
	set_task_stack_end_magic(&init_task);	//初始化第一个进程pcb
	...
	trap_init();	//初始化中断向量
	mm_init();	//内存管理的初始化
	sched_init();	//调度模块的初始化
	...
	rest_init();
}

先看一下里面set_task_stack_end_magic(&init_task); //初始化第一个进程pcb
\linux-3.18.6\init\init_task.c中看到 init_task 的定义。

struct task_struct init_task = INIT_TASK(init_task);

变量init_task是用宏 INIT_TASK 对其进行初始化的,并没有通过fork。这里需要注意,如果没有fork,就算0号进程。
init_task 是唯一没有通过 fork 方式产生的进程。

之后在函数start_kernel中进行了其他一系列初始化工作,最后调用了rest_init();函数。


rest_init 函数定义

static noinline void __init_refok rest_init(void)
{
	int pid;

	rcu_scheduler_starting();
	/*
	 * We need to spawn init first so that it obtains pid 1, however
	 * the init task will end up wanting to create kthreads, which, if
	 * we schedule it before we create kthreadd, will OOPS.
	 */
	kernel_thread(kernel_init, NULL, CLONE_FS);
	numa_default_policy();
	pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
	rcu_read_lock();
	kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
	rcu_read_unlock();
	complete(&kthreadd_done);

	/*
	 * The boot idle thread must execute schedule()
	 * at least once to get things moving:
	 */
	init_idle_bootup_task(current);
	schedule_preempt_disabled();
	/* Call into cpu_idle with preempt disabled */
	cpu_startup_entry(CPUHP_ONLINE);
}

先调用了 kernel_thread(kernel_init, NULL, CLONE_FS);fork创建了1号内核线程。
又调用pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);创建了2号内核线程。
最后执行了 init_idle_bootup_task(current);演变成idle进程。


kernel_init函数中执行了ret = run_init_process(ramdisk_execute_command);而括号中的变量就是设置的文件系统镜像的init文件程序。是第一个用户态进程。

kthreadd 函数的是管理和调度其他内核线程,因此所有的内核线程都是直接或者间接地以 kthreadd 为父进程的。


5.3 内核启动总结

当开机启动进入start_kernel前通过了一些汇编代码。

在start_kernel函数(0号进程执行的)中创建了init_task进程(由于不是通过fork创建的,所以init_task还是0号进程),做好了一些初始化的工作后,最后调用了rest_init()函数。

在这个函数中先创建了1号内核线程,其中执行了文件系统镜像(第一个用户态进程);
然后又创建了2号内核线程,其中是管理和调度其他内核线程,因此所有的内核线程都是直接或者间接地以 kthreadd 为父进程的。

在rest_init函数最后,init_task演变成了idle进程。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
enuetOS是一个为x86(IBM兼容)计算机开发的业余操作系统,它是一款完全由汇编语言(32位)写成的迷你操作系统,因此它更小、更快,并且系统本身用应用程序占用很少的系统资源。   项目最初是芬兰人 Ville Turjanmaa(赫尔辛基大学) 利用业余时间开发完成。现在世界各地都有 MenuetOS 的开发者,他们正在不断完善这个操作系统。    这个项目目前由 Jarek Pelczar(jarekp3[@]wp[.]pl) 接管。项目的中文版由本站站长 E-mean X. 开发。   MenuetOS 并不像现在流行的 Linux 及其它如 FreeBSD、Minix 一样是一个类 Unix 的操作系统,它完全由32位汇编语言编写的系统。Menuet 及其应用程序不基于当前任何一款流行的操作系统而运作,主要是为在开发过程中避免复杂的编程及各种不可预料的 Bug。   尽管Menuet是完全用 32位汇编写成的,但它的系统程序构架并不完全是为汇编语言而保留,它的接口实际上可用于任何程序设计语言。尽管如此,系统开发的目的还是为更简化 Asm程序设计而设计,系统下 GUI编程尤其体现这一点。 ·Menuet OS 的特点   - 多任务,多线程  - 图形用户界面,可以达到 32bit color,1280x1024 分辨率  - 程序开发比 Windows 和 Linux 之类的系统更容易  - IDE环境:自带应用程序及内核编辑编译工具  - 完全开放的源代码(GPL)  - TCP/IP 协议栈、PPP 及 局域网络  - HTTP,MP3,Mail 服务器,3D迷宫  - irc, http, nntp 及 tftp客户端  - 自由的界面,窗口可换“皮肤”  - 仅一张 1.44M 软盘可以装下! ·Menuet OS 对硬件的基本要求  CPU : 386 或与之相兼容的 CPU 显示: 支持 VESA 2.0(建议使用) 或 VESA 1.2 的显卡,VGA/EGA 显示器。 声卡: Creative SB(Sound blaster) 16或兼容声效卡 硬盘: ATA LBA 模式 FAT32文件系统 网络: Realtech 8029/8139, Intel 8255x, 3com, PCNET32 Ethernet PCI cards PPP dialup 鼠标: PS/2 或 COM 内存: 至少32M

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

H4ppyD0g

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值