60 | 搭建操作系统实验环境(上):授人以鱼不如授人以渔
下载APP
关闭
渠道合作
推荐作者
60 | 搭建操作系统实验环境(上):授人以鱼不如授人以渔
2019-08-14 刘超 来自北京
《趣谈Linux操作系统》
课程介绍
讲述:刘超
时长14:48大小13.57M
操作系统的理论部分我们就讲完了,但是计算机这门学科是实验性的。为了更加深入地了解操作系统的本质,我们必须能够做一些上手实验。操作系统的实验,相比其他计算机课程的实验要更加复杂一些。
我们做任何实验,都需要一个实验环境。这个实验环境要搭建在操作系统之上,但是,我们这个课程本身就是操作系统实验,难不成要自己 debug 自己?到底该咋整呢?
我们有一个利器,那就是 qemu 啊,不知道你还记得吗?它可以在操作系统之上模拟一个操作系统,就像一个普通的进程。那我们是否可以像 debug 普通进程那样,通过 qemu 来 debug 虚拟机里面的操作系统呢?
这一节和下一节,我们就按照这个思路,来试试看,搭建一个操作系统的实验环境。
运行一个 qemu 虚拟机,首先我们要有一个虚拟机的镜像。咱们在虚拟机那一节,已经制作了一个虚拟机的镜像。假设我们要基于 ubuntu-18.04.2-live-server-amd64.iso,它对应的内核版本是 linux-source-4.15.0。
当时我们启动虚拟机的过程很复杂,设置参数的时候也很复杂,以至于解析这些参数就花了我们一章的时间。所以,这里我介绍一个简单的创建和管理虚拟机的方法。
创建虚拟机
首先,在宿主机上,我们需要一个网桥。我们用下面的命令创建一个网桥,并且设置一个 IP 地址。
为了访问外网,这里还需要设置 /etc/sysctl.conf 文件中 net.ipv4.ip_forward=1 参数,并且执行以下的命令,设置 NAT。
接下来,就要创建虚拟机了。这次我们就不再一个个指定虚拟机启动的参数,而是用 libvirt。首先,使用下面的命令,安装 libvirt。
libvirt 管理 qemu 虚拟机,是基于 XML 文件,这样容易维护。
在这个 XML 文件中,/mnt/vdc/ubuntutest.img 就是虚拟机的镜像,br0 就是我们创建的网桥,连接到网桥上的网卡 libvirt 会自动帮我们创建。
接下来,需要将这个 XML 保存为 domain.xml,然后调用下面的命令,交给 libvirt 进行管理。
接下来,运行 virsh list --all,我们就可以看到这个定义好的虚拟机了,然后我们调用 virsh start ubuntutest,启动这个虚拟机。
我们可以通过 ps 查看 libvirt 启动的 qemu 进程。这个命令行是不是很眼熟?我们之前花了一章来讲解。如果不记得了,你可以回去看看前面的内容。
从这里,我们可以看到,VNC 的设置为 0.0.0.0:0。我们可以用 VNCViewer 工具登录到这个虚拟机的界面,但是这样实在是太麻烦了,其实 virsh 有一个特别好的工具,但是需要在虚拟机里面配置一些东西。
在 grub.cfg 中,在 submenu ‘Advanced options for Ubuntu’ 这一项,在这一行的 linux /boot/vmlinuz-4.15.0-55-generic root=UUID=470f3a42-7a97-4b9d-aaa0-26deb3d234f9 ro console=ttyS0 maybe-ubiquity 中,加上了 console=ttyS0。
在 menu.lst 文件中,在 Ubuntu 18.04.2 LTS, kernel 4.15.0-55-generic 这一项,在 kernel /boot/vmlinuz-4.15.0-55-generic root=/dev/hda1 ro console=hvc0 console=ttyS0 这一行加入 console=ttyS0。
接下来,我们重启虚拟机,重启后上面的配置就起作用了。这时候,我们可以通过下面的命令,进入机器的控制台,可以不依赖于 SSH 和 IP 地址进行登录。
下面,我们可以配置这台机器的 IP 地址了。对于 ubuntu-18.04 来讲,IP 地址的配置方式为修改 /etc/netplan/50-cloud-init.yaml 文件。
然后,我们可以通过 netplan apply,让配置生效,这样,虚拟机里面的 IP 地址就配置好了。现在,我们应该能 ping 得通公网的一个网站了。
虚拟机就此创建好了,接下来我们需要下载源代码重新编译。
下载源代码
首先,我们先下载源代码。
这行命令会将代码下载到 /usr/src/ 目录下,我们可以通过下面的命令解压缩。
至此,路径 /usr/src/linux-source-4.15.0 下,就是解压好的内核代码。
准备工作都做好了。这一节,我们先来做第一个实验,也就是,在原有内核代码的基础上加一个我们自己的系统调用。
第一个要加的地方是 arch/x86/entry/syscalls/syscall_64.tbl。这里面登记了所有的系统调用号以及相应的处理函数。
在这里,我们找到 332 号系统调用 sys_statx,然后照猫画虎,添加一个 sys_sayhelloworld,这里我们只添加 64 位操作系统的。
第二个要加的地方是 include/linux/syscalls.h,也就是系统调用的头文件,然后添加一个系统调用的声明。
同样,我们找到 sys_statx 的声明,照猫画虎,声明一个 sys_sayhelloworld。其中,words 参数是用户态传递给内核态的文本的指针,count 是数目。
第三个就是对于这个系统调用的实现,方便起见,我们不再用 SYSCALL_DEFINEx 系列的宏来定义了,直接在 kernel/sys.c 中实现。
接下来就要开始编译内核了。
编译内核
编译之前,我们需要安装一些编译要依赖的包。
首先,我们要定义编译选项。
然后,我们能通过选中下面的选项,激活 CONFIG_DEBUG_INFO 和 CONFIG_FRAME_POINTER 选项。
选择完毕之后,配置会保存在.config 文件中。如果我们打开看,能看到这样的配置:
接下来,我们编译内核。
这是一个非常长的过程,请耐心等待,可能需要数个小时,因而这里用了 nohup,你可以去干别的事情。
当编译完毕之后,grub 和 menu.lst 都会发生改变。例如,grub.conf 里面会多一个新内核的项。
例如,menu.lst 也多了新的内核的项。
别忘了,这里面都要加上 console=ttyS0。
下面,我们要做的就是重启虚拟机。进入的时候,会出现 GRUB 界面。我们选择 Ubuntu 高级选项,然后选择第一项进去,通过 uname 命令,我们就进入了新的内核。
进入新的系统后,我们写一个测试程序。
然后,我们能利用 gcc 编译器编译后运行。如果我们查看日志 /var/log/syslog,就能够看到里面打印出来下面的日志,这说明我们的系统调用已经添加成功了。
总结时刻
这一节是一节实战课,我们创建了一台虚拟机,在里面下载源代码,尝试修改了 Linux 内核,添加了一个自己的系统调用,并且进行了编译并安装了新内核。如果你按照这个过程做下来,你会惊喜地发现,原来令我们敬畏的内核,也是能够加以干预,为我而用的呢。没错,这就是你开始逐渐掌握内核的重要一步。
课堂练习
这一节的课堂练习,希望你能够按照整个过程,一步一步操作下来。毕竟看懂不算懂,做出来才算入门啊。
欢迎留言和我分享你的疑惑和见解,也欢迎你收藏本节内容,反复研读。你也可以把今天的内容分享给你的朋友,和他一起学习、进步。
分享给需要的人,Ta购买本课程,你将得20元
生成海报并分享
赞 11
提建议
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
上一篇
59 | 数据中心操作系统:上市敲钟
下一篇
61 | 搭建操作系统实验环境(下):授人以鱼不如授人以渔
精选留言(19)
- 王建峰2021-05-10希望我的记录能帮助到各位同学 Ubuntu20.04上搭建操作系统实验环境:https://blog.csdn.net/feit2417/article/details/1165043418
- Gnayils2020-06-071. apt安装qemu-kvm,使用/usr/bin/kvm作为domain.xml中的emulator, 然后更改domain节点的type值为kvm,这样虚拟机的速度会更快。 2. 创建ubuntutest.img文件时,size至少30G,否则kernel的编译中间结果很大,会造成编译失败。 3. 将虚拟机的内存改大一些,否则在make install后使用带有debug info的内核启动系统时,unpack initramfs会失败。展开
作者回复: 赞,实战派
共 3 条评论7 - 一栋人2020-03-10如果使用 virt-install 加上 "--graphics none --extra-args='console=ttyS0'" 就能直接 virsh console 上了。2
- ThisCat2020-01-14那个xml文件中没有指定硬盘路径,我VNC连接进去后安装系统的时候找不到硬盘2
- LDxy2019-08-15可以在虚拟机里运行虚拟机吗?
作者回复: 可以,就是慢的一塌糊涂了
1 - leslie2019-08-14发现老师的课如老师自己介绍的学习方法一样:不是一遍就能学懂的,跟着做跟着反思;要第二遍或者第三遍才能理解和明白老师所讲所授的知识。 看来所谓的第一遍或者第二遍第三遍只是大概:其实应当是三个阶段/层次;努力坚持努力学习,希望多遍之后能尽力掌握其6-8成。
作者回复: 是的,加油
1 - Geek_739cf02022-09-25 来自湖北我在自己的Ubuntu20虚拟机上编译了linux-5.4.214。我编译成功的步骤和老师不同的地方: 1. 333 64 sayhelloworld sys_sayhelloworld 按照已经存在的调用格式,在sys_sayhelloworld前面加__64_ ,即__64_sys_sayhelloworld; 2. kernel/sys.c 中的实现也改成了: SYSCALL_DEFINE0(sayhelloworld) { printk("printfmsg SYSTEM CALL IS ALIVE\n"); return 0; } 3. 所以头文件里也改成asmlinkage long sys_(void); 这样就编译通过了,想快速验证可以只编译vmlinux。 使用make vmlinux,总比每次都编译整个内核好。 我遇到的坑: 1. 没有规则可制作“debian/canonical-certs.pem"...... 这个能百度到,在内核的主目录里打开.config 文件,删除CONFIG_SYSTEM_TRUSTED_KEYS =“debian/canonical-certs.pem" 这一项里冒号里的内容就好 2. undefined reference to '__x64_sys_sayhelloworld' 这个错误对我来说最麻烦,试了google找到的好几种方式都不行,最后还是改成宏定义而且没有额外参数的实现最后编译成功展开
- 施天助2021-07-13老师,选了您两门趣谈课。都很好,我就是在实践环节老碰到各种环境问题,折腾了好几天都不出来,能否加您微信或给您邮箱发送求助? 实在没辙了
- 听雨听风2021-05-25qemu 虚拟机 是基于liunx系统上安装的吗?
- 青年祭司2020-07-24编译后,内核自动就安装了吗
- 李海涛2020-05-19在定义xml文件时, <emulator>/usr/bin/qemu-system-x86_64</emulator>里面为什么是/usr/bin/qemu-system-x86_64?我看还有的文档说用 <emulator>/usr/bin/kvm</emulator>, 或 <emulator>/usr/libexec/qemu-kvm</emulator>? 请问这几个的区别?各个的适合使用场景?谢谢!
作者回复: ls一下,看是不是指向同一个文件,不同系统安装完,名字不一定一样
- 扩散性百万咸面包2020-04-05我们OS课第一个作业也是编译Linux内核,Module是写Fork函数实现一些递归功能和执行
- 暮鼓晨钟2019-12-23"在虚拟机里面,我们修改 /boot/grub/ 里面的两个文件,一个是 grub.cfg,另一个是 menu.lst,这里面就是咱们在系统初始化的时候,讲过的那个启动列表。" 老师,还没进入虚拟机,这两文件如何修改啊?共 1 条评论
- 星亦辰2019-12-07Kvm虚拟机里,配置足够好,是不是也可以完成上边的实验?
- David2019-11-05老师 如何进到虚拟机去修改配置呢?共 1 条评论
- 许童童2019-08-14跟着老师一起动手,实战。
作者回复: 动手好,印象深刻
- 郭江伟2019-08-14请问下老师 每次修改内核都需要全部编译吗? 可以部分编译吗?
作者回复: 如果是模块,可以部分编译,然后加载,核心的部分,就需要全部编译了
- 大王叫我来巡山2019-08-14当年上课的时候只是给了个文档,让增加系统调用,其实并不明白,终于看明白了
作者回复: 自己尝试一把
- Marshall2019-08-14后期准备跟着老师动手一下
作者回复: 一定要动手哦