电子商务网站开发方案,seo 优化技术难度大吗,浮动微信代码wordpress,12306的网站多少钱做的其实#xff0c;我们等了这一刻好久好久#xff0c;即使我不说#xff0c;大家也有这样的认识#xff0c;linux内核是用c 语言写的#xff0c;咱们肯定也要用c语言。其实...说点伤感情的话#xff0c;今后的工作只是大部分#xff08;99%#xff09;都要用c语言来写我们等了这一刻好久好久即使我不说大家也有这样的认识linux内核是用c 语言写的咱们肯定也要用c语言。其实...说点伤感情的话今后的工作只是大部分99%都要用c语言来写还有一些要用到汇编的地方。大家也不要因此气馁心灰其实突然不用汇编还会想它呢这不是玩笑我在此过程中一定会尽我所能让内容简单易接受。
我们的内核文件是kernel.bin这个文件是由loader将其从硬盘上读出并加载到内存中的到此接力棒传到了最后一个选手的手里。也就是说咱们需要事先把kernel.bin定入硬盘。好久不往虚拟硬盘上写东西了甭说是大家我都有点陌生了呢不过好在操作很简单写之前让我们先看看这块虚拟硬盘上的文件布局吧。
MBR是写在了硬盘的第0扇区第1扇区是空着的原因是个人喜好其实不空着也行不过硬盘那么大何必搞得那么拥挤呢。因此loader是写在硬盘的第2扇区由于loader.bin目前的大小是1342字节占用3个扇区所以第2~4扇区不能再用啦从第5扇区起我们可以自由使用。但此时我的强迫症又发作啦我这里并没有接着第5扇区写而是选的第9扇区要是起始为1的话算是第10个扇区。一是为了loader万一哪天要扩展得预留出硬盘空间二是您可能已经预计到了隔开点显得更放心这纯属是出于个人喜好做出的选择。
好既然已经确定了写入扇区的位置我们还是要通过dd命令往磁盘上写命令如下
dd if kernel.bin of/your_path/hd60M.img bs512 count200 seek9 convnotrunc回车
seek为9目的是跨过前9个扇区第0~8个扇区我们是在第9个扇区写入。
count为200目的是一次往参数of指定的文件中写入200个扇区。
至于为什么把count设成这么大原因是这样的每次写完内核后咱们要往磁盘中同步内核文件这样才能验证内核的正确性。按理说咱们现在的内核文件不足4扇区count4最合适。不过内核发展越来越大时每次都要根据实际内核文件大小去改写count参数这样就难免会有忘记修改的情况。之前我就深受其苦内核文件变大了而count忘记调整造成写入硬盘中的内核文件不完整所以到后来程序运行不受控制以至于调试的时候都调晕啦看着cpu中跑的指令我完全蒙圈了根本不是自己写的。恍然大悟之后我就干脆一步到位因为我们将来的内核大小不会超过100KB所以直接把count改为200块扇区。另外请大家不用担心dd命令会自己判断写入的数据量如果参数if指定的文件体积小于count*bs只按实际文件大小写入。
不过估计您也觉得参数太多了为了方便我通常是把下面三个命令编译、链接、再写入硬盘一起完成您可以将它们写成一个脚本脚本内容如下
gcc -c -o main.o main.c ld main.o -Ttext 0xc0001500 -e main -o kernel.bin dd if kernel.bin of/your_path/hd60M.img bs512 count200 seek9 convnotrunc
好啦上面命令在回车之后这样我们的内核文件就成功写进磁盘了。
菜配好啦就等下锅啦我们的内核是由loader加载的所以我们还要去修改下loader.S。
loader.S需要修改两个地方
λ加载内核需要把内核文件加载到内存缓冲区。λ初始化内核需要在分页后将加载进来的elf内核文件安置到相应的虚拟内存地址然后跳过去执行从此loader的工作结束。
先说第一个加载内核这里所说的加载内核只是把内核从硬盘上拷贝到内存中并不是运行内核代码。这项工作在开启分页前后都可以不过为了简单咱们把它安排在分页开启之前加载。
话说内核加载到内存中得有个加载地址也就是缓冲区。其实开发经验少的同学对缓冲区这个概念总是觉得有点“只可意会不可言传”的意思。借此机会多说两句。缓冲区buffer意味存放物品的地点也就是用于加工处理中暂存数据的地方。生活中的缓冲区例子有很多比如水杯是水的缓冲区水不是直接入口的总有个中间载体做为中转然后才入口。而且水杯的作用相当于暖瓶或水房的缓存咱们不是喝一口水就跑到水房接一口水而是一次接一大杯回来慢慢喝这样就减少了去水房的次数。由此可见缓冲区既有存放数据的空间之意又有提高效率的缓存之意。换在计算机世界里缓冲区必然也是个能存储数据的介质比如咱们这里所说的内存。
好啦不能扯太远啦咱们的缓冲区在设在哪里呢这不是乱放的得参考下目前内存中哪个地方还有可用的空间千万不能覆盖了重要数据。也许大家首先想到的是很久之前说到的那个内存布局图赞答对啦不过大家不用往前翻看啦一向体贴的我已经将其重点部分摘到这里啦大家请看图 内核被加载到内存后loader还要通过分析其elf结构将其展开到新的位置所以说内核在内存中是有两份拷贝一份是elf格式的原文件kernel.bin另一份是loader解析elf格式的kernel.bin后在内存中生成的内核映像也就是将程序中的各种段segment复制到内存后的程序体这个映像才是真正运行的内核。
将来内核肯定是越来越大为了多预留出生长空间咱们要将内核文件kernel.bin加载到地址较高的空间而内核映像要放置到较低的地址。内核文件经过loader解析后就没用啦这样内核映像将来往高地址处扩展时也可以覆盖原来的内核文件kernel.bin。所以咱们的结论是在0x7e00~0x9fbff这片区域的高地址中找一亩地给kernel.bin这里我擅自做主啦帮大家选的是0x70000。为什么没有为什么随意选的取了个整而已就是觉得0x70000~0x9fbff有0x2fbff190KB字节的空间而我们的内核不超过100KB够用就行。
好万事俱备啦代码走起请大家过目代码
147 ; ------------------------- 加载kernel ----------------------
148 mov eax, KERNEL_START_SECTOR ; kernel.bin所在的扇区号
149 mov ebx, KERNEL_BIN_BASE_ADDR; 从磁盘读出后写入到ebx指定的地址
150 mov ecx, 200 ; 读入的扇区数
151
152 call rd_disk_m_32
153
154 ; 创建页目录及页表并初始化页内存位图
155 call setup_page代码属于loader的一部分它的作用是把内核文件从硬盘上加载到内存中下面简要说一下。
第148~149行的KERNEL_START_SECTOR和KERNEL_BIN_BASE_ADDR是在boot/include/boot.inc中定义其值分别为0x9和0x70000。
第150行的ecx为200这是读入的扇区数这里应该同前面用dd命令往硬盘上写入内核文件时的参数count保持一致原因你懂的不解释。
以上的eax、ebx、ecx是函数rd_disk_m_32的三个参数是为调用下面的函数做准备。
第152行的函数是rd_disk_m_32用于从硬盘上读取文件。它的三个参数已经在上面赋值了。由于目前已经在32位保护模式下所以相比之前位于mbr中的函数rd_disk_m_16rd_disk_m_32只是版本由16位变成了32位的函数实现原理相差无几主要体现在里面所用的寄存器变成了32位。所以就不细说啦大家一看就明白啦。
接下来的第155行就是开始创建页表啦把它放在这是为了让大家知道代码是加到了哪里承上启下。setup_page函数实现没变无须多说。
内核加载到缓冲区中后现在该说要修改的第二处啦也就是初始化内核。