跟我一起写操作系统(二)——史上最简单的内核

2023-05-16

跟我一起写操作系统(二)——史上最简单的内核

  转载注明出处:http://www.cnblogs.com/lucasysfeng/p/4847662.html

  上一讲地址:http://www.cnblogs.com/lucasysfeng/p/4846119.html

  项目地址:https://github.com/lucasysfeng/lucasOS

  

  上一讲我们介绍了计算机的启动流程,并给出了一份简单的主引导记录代码,此份代码仅仅是显示几个字符,并没有做它本应该做的事--启动内核。本讲我们首先看下内核是如何被启动的,然后写一个简单的内核,用已经实现的主引导记录配合GRUB启动它。

如何启动内核


  前一讲我们说到,计算机读取"主引导记录"前面446字节的机器码之后,会运行事先安装的“启动管理器”bootloader,由用户选择启动哪个内核,之后就会载入内核,将控制权交给内核。GNU GRUB(GRand Unified Bootloader)就是一种bootloader,满足多重引导规范(The Multiboot Specification),GRUB可选择操作系统分区上的不同内核,下图就是GRUB的图形界面:

图 GRUB界面

  能够被GRUB启动的内核需要满足两个的条件:

(1) 内核的前8K字节内必须要包含多重引导规范的头信息(Multiboot Header);
(2) 内核要加载在内存地址的1MB以上。

  那么Multiboot Header是什么样子的呢?它必须包含4字节对齐的3个域(还有其他非必须域,我们不讨论),如下:

魔数域(magic):标志头的魔数,必须等于 0x1BADB002。。 
标志域(flag):是否需要引导程序支持某些特性,我们不关心这些特性,这个标志置为0。 
校验域(checksum):校验等式是否成立(magic + flags + checksum = 0)

   本文不讨论GRUB的实现,我们会用前人已经写好的GRUB(笔者会给出),我们要做的是完成符合GRUB启动规范的内核。为了完成这个内核,我们需要写少量的汇编用来在内核中加入Multiboot Header,然后用C语言写内核入口,最后将汇编目标代码和C语言目标代码链接起来生成真正的内核。下面就让我们一步步地完成这些吧!

 

第一步 汇编入口


  1. 汇编代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
; 文件名 boot.asm
; Copyright: www.cnblogs.com/lucasysfeng
 
MBOOT_MAGIC  equ 0x1BADB002  ; multiboot magic域,必须为此值
MBOOT_FLAGS  equ 0x00        ; multiboot flag域, GRUB启动时是否要做一些特殊操作
MBOOT_CHECKSUM  equ -(MBOOT_MAGIC + MBOOT_FLAGS) ; multiboot checksum域,校验上面两个域是否正确
 
[BITS 32]                    ; 以32位编译
 
section .text
   dd  MBOOT_MAGIC
   dd  MBOOT_FLAGS
   dd  MBOOT_CHECKSUM
   dd  start
 
[GLOBAL start]
[EXTERN kernel_main]         ; 内核入口函数, EXTERN表明此符号在外部定义
 
start:
   cli                        ; 禁用中断
   call kernel_main           ; 调用内核入口函数
   jmp $                      ; 无限循环

  在上面汇编中,我们定义了GRUB启动需要的域MBOOT_MAGIC、MBOOT_FLAGS和MBOOT_CHECKSUM,并调用了内核入口函数kernel_main, kernel_main下一节实现。

  2. 编译生成目标文件boot.o

# nasm -f elf boot.asm -o boot.o

  运行上面命令后会生成目标文件boot.o,-f  elf的意思是生成ELF格式的目标代码。

 

第二步 内核入口


   1. 内核代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/****************************************************
# Copyright(c) www.cnblogs.com/lucasysfeng, all rights reserved
# File        : kernel.c
# Author      : lucasysfeng
# Description : 内核入口函数
****************************************************/
 
int  kernel_main()
{
     // 显存开始地址
     char  *display_buf = ( char *)0xb8000;        
 
     // 清屏
     unsigned  int  i = 0;
     const  unsigned  int  total = 80 * 25 * 2;       // 一屏25行,每行80个字符,每个字符2个字节
     while (i < total)
     {
         display_buf[i++] =  ' ' ;
         display_buf[i++] = 0x04;                  // 颜色
     }
 
     // 显示字符
     const  char  *str =  "Hello World, welcome to kernel!" ;
     for  (i = 0;  '\0'  != *str;)
     {
         display_buf[i++] = *(str++);
         display_buf[i++] = 0x04;
     }
 
     return  0;
}

  0xb8000h是显存开始的地址,读者可以看第一讲(http://www.cnblogs.com/lucasysfeng/p/4846119.html)“实模式内存地址空间分布”那张图,找到0xb8000h这个地址。从0xb8000h这个地址开始,每2个字节表示一个字符,前一个字节是字符的ASCII码,后一个字节是这个字符的颜色和属性,颜色和属性此处先不用关心。这段C代码的其余部分相信读者都能看得懂,我就不过多解释了。 

  2. 编译生成目标文件kernel.o

# gcc -m32 -c -o kernel.o kernel.c

  运行上面命令后,目标文件kernel.o就生成了。

 

第三步 生成内核


   上面讲到了能被GRUB启动的内核需要满足的条件:

(1) 内核的前8K字节内必须要包含多重引导规范的头信息(Multiboot Header);
(2) 内核要加载在内存地址的1MB以上。

  我们将头信息放在了汇编生成的目标文件boot.o中,因此我们需要将boot.o和kernel.o链接到一起生成真正的kernel,并且这个真正的内核要加载到1MB内存上,为此,我们需要下面的链接脚本和命令(关于链接脚本的使用自行google):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/***************************
* 文件名: link.ld  
***************************/
 
ENTRY(start)
SECTIONS
{
     . = 0x100000;
 
     .text :
     {
         *(.text)
         . = ALIGN(4096);
     }
     .data :
     {
         *(.data)
         *(.rodata)
         . = ALIGN(4096);
     }
}

  我们用ld命令链接目标文件boot.o和kernel.o,指明使用链接脚本link.ld:

# ld -T link.ld -m elf_i386 -nostdlib boot.o kernel.o -o kernel

  运行上面命令后,会生成我们要启动的真正的内核kernel,那么这个kernel是否满足GRUB启动规范呢?我们可以通过反汇编来看一下:

# objdump -d  kernel | head -n30

  结果如下图所示,我们看到100000了吗,这个就是.text段起始的地址即1M,看到02 b0 ad 1b 00 00了吗,这个就是GRUB魔数域1b ad b0 02(大小端问题,反向存储)

 

第四步 将内核拷贝到软盘镜像


  我们这里不制作软盘镜像,而是使用已经制作好的软盘镜像,镜像名称lucasOS.img,已经放在github上了。我们也无需制作GRUB,这个软盘镜像已经包含了GRUB.我们要做的是把内核文件kernel拷贝到软盘镜像lucasOS.img中。

  1. 获取lucasOS.img软盘镜像。

  lucasOS目录下的lucasOS.img就是我们要的软盘镜像。

# git clone https://github.com/lucasysfeng/lucasOS.git

  2. 创建挂载点。

# sudo mkdir /mnt/lucasOS

  3. 挂载软盘镜像。

  注意把lucasOS.img改为你的lucasOS.img所在路径。

# sudo mount lucasOS.img /mnt/lucasOS     

  4. 把内核文件拷贝到软盘镜像中。

  注意把kernel改为你的kernel所在路径。

# sudo cp kernel /mnt/lucasOS/kernel          

   5. 卸载软盘镜像。

# sudo umount /mnt/lucasOS

 

第五步 启动内核


   上一讲我们用软盘镜像启动了一个空的虚拟机,下面用同样地操作启动虚拟机,要记得把软盘镜像lucasOS.img从ubuntu拷贝到windows下。这里我们使用VMware创建虚拟机,当然也可以使用其他软件创建虚拟机。

  1. 创建空的虚拟机,去掉开机从CD/DVD启动选项。  

  2. 网络选择host-only模式。

  3. 选择从软盘驱动,路径选择已经拷贝到windows下的镜像lucasOS.img.

  4. 开启虚拟机电源,看到如下的画面(约停留2s),恭喜你,GRUB成功了!

  5. GRUB启动成功后,会自动载入内核,出现下面画面,恭喜你,载入内核成功!

  好了,至此,我们完成了内核的启动流程,下一讲我们开始内核之旅!

 

代码获取


  本系列GitHub地址 https://github.com/lucasysfeng/lucasOS,用下面命令获取代码:

# git clone https://github.com/lucasysfeng/lucasOS.git

  本讲的代码是code/chapter2,笔者已经将上面的命令集成到Makefile中了,读者只需进入目录,按ReadMe.txt说明执行即可,有问题请留言

 

参考


 1. http://www.jamesmolloy.co.uk/tutorial_html/2.-Genesis.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

跟我一起写操作系统(二)——史上最简单的内核 的相关文章

  • word设置页眉页码 首页没有页眉(终于搞懂了)

    1 设置首页没有页眉 主要是通过分节符完成的 xff0c 顾名思义 xff0c 分节符就是将全文分为两节 xff0c 然后就可以实现对两节内容的分别设置 比如首页没有页眉 在首页的最后一行插入分节符 xff0c 然后就会显示出 xff08
  • 一步步使用Tomcat+CAS完成单点登录

    1 最基本的单点登录 客户端配置 xff1a 1 Tomcat配置SSL 1 生成证书 打开cmd或终端 xff0c 命令行切换到Tomcat所在目录 xff0c 执行如下命令 xff1a D JayHe Environment tomca
  • 人脸识别读书笔记

    浅析人脸检测之 Haar 分类器方法 一 Haar 分类器的前世今生 目前的人脸检测方法主要有两大类 xff1a 基于知识和基于统计 基于知识的方法主要利用先验知识将人脸看作器官特征的组合 xff0c 根据眼睛 眉毛 嘴巴 鼻子等器官的特征
  • make编译时的常见错误

    make编译时的常见错误 未定义的引用1 xff1a 缺少头文件未定义的引用2 xff1a 没找这个系统头文件未定义的引用3 xff1a 链接库没包括进来静态库动态库 必须承认的是 xff0c 写代码最痛苦的不是算法 xff0c 而是环境的
  • 深度学习中的常见名词(baseline,benchmark,etc)

    本文主要用于解释一些在深度学习中常见的名词 xff0c 重点参考了博客 xff1a https towardsdatascience com generalization regularization overfitting bias an
  • Ubuntu安装docker-ce

    docker在大型项目上使用范围很广 xff0c 为了在Ubuntu自测docker xff0c 心血来潮 xff0c 准备自己搭建docker进行测试 因为使用apt直接安装docker的版本比较低 xff0c 在此按照官网的教程安装do
  • 【stm32】UART串口中断方式收发任意长度数据(HAL库开发,中断中不使用库函数 使用寄存器和自定义存储函数)

    一 起因 为什么要写一个串口接收不定长数据 xff0c 还要把数据保存起来 xff1f xff1f 因为存起来的数据要用要判断要根据数据做不同的处理 xff0c 要把数据拿到后解析 但是 xff0c 最开始想当然的使用HAL库中的HAL U
  • 腾讯云轻量应用服务器安装和配置宝塔 Linux 面板腾讯云专享版

    宝塔 Linux 面板腾讯云专享版由腾讯云与堡塔公司联合开发 xff0c 专享版在已支持普通版所有功能的基础上 xff0c 还默认集成腾讯云对象存储 文件存储 内容分发网络和 DNS 解析插件 插件具备如下功能 xff1a 支持将对象存储的
  • Ubuntu操作系统如何搭建可视化界面?

    VNC xff08 Virtual Network Console xff09 是虚拟网络控制台的缩写 它是一款优秀的远程控制工具软件 xff0c 由著名的 AT amp T 的欧洲研究实验室开发 VNC 是基于 UNIX 和 Linux
  • ubuntu密码忘记-解决方法

    1 xff1a 开机按Shift键 xff0c 出现如下界面 xff08 手速要快 xff0c Shift键要按时间久一点 xff09 选择第二项 2 xff1a 按回车键进入如下界面 xff0c 然后选中有recovery mode的选项
  • git 仓库迁移,保留提交记录,同时提交到多个仓库

    git 仓库迁移 xff0c 保留提交记录 xff0c 同时提交到多个仓库 1 仓库迁移并保留原有的提交记录 应用场景 原有需求在 A 存储库地址进行开发 xff0c 现在新建了一个 B 存储库 xff0c 要求将 A 的代码和提交记录一起
  • STM32MP157开发-STM32CubeProgrammer-No DFU detected解决

    STM32MP157开发 STM32CubeProgrammer No DFU detected解决 xff0c 在开发时 xff0c 需要用STM32CubeProgrammer烧录固件 xff0c 但是按照官方文档 xff0c 安装后
  • Python正则表达式学习(5)——re.findall()

    re findall xff08 pattern xff0c string xff0c flags 61 0 xff09 返回字符串中模式的所有非重叠匹配 xff0c 作为字符串列表 字符串从左到右扫描 xff0c 并按照找到的顺序返回匹配
  • linux内核插入模块时 Unknown symbol in module

    编译驱动的时候碰到了 insmod error inserting 39 igb ko 39 1 Unknown symbol in module 的问题 xff0c 在网上看了下 xff0c 说是查看 dmesg tail 看输出信息中的
  • Linux路由器

    宽带上网已经不是什么新鲜事情 xff0c 人们对相关的网络器件已经不再陌生 xff0c 比如说常见的路由器 对于一般的网络用户 xff0c 他们能知道怎样使用路由器来上网 玩游戏等就已经感到很满足了 xff0c 通常情况下对路由器的深层技术
  • 树莓派linux驱动学习之hello world

    http blog csdn net hcx25909 article details 16860055 最近想学习一下linux驱动 xff0c 看了一些书和教学视频 xff0c 大概了解了一下 xff0c 不过要想深入 xff0c 肯定
  • 微信端口及协议分析

    http blog newxd com 7235 html 有朋友公司需求如下 xff0c 手机通过WIFI连接上网 xff0c 而老板要求 xff0c 员工使用手机只能上微信 xff0c 而不能上其他网页和看在线视频 上网搜索了微信使用协
  • git报错fatal: HTTP request failed

    1 在使用git pull git push git clone会报类似如下的错误 xff1a sudo git clone https github com pcduino a20 kernel fatal HTTP request fa
  • 树莓派2在U8300W平台上用pppd拨号时出现“pppd: The remote system is required to authenticate itself”

    利用pppd拨号 xff0c 首先需要调试好驱动 1 xff09 安装ppp sudo apt get install y ppp sudo apt get install y ppp dev sudo apt get install y
  • armv7架构下lubuntu系统apt-get安装ffmpeg方法

    What s up doc 17 08 2007 I think you have noticed the Google Ads I need that to pay the huge amount of bandwidth 10 05 2

随机推荐

  • shell脚本转换成二进制的可执行文件方法--加密

    http www 360doc com content 14 0507 14 10058718 375504586 shtml http www linuxidc com Linux 2014 12 110612 htm http www
  • Linux下jhead简介以及使用

    jhead 源代码下载地址 http www sentex net mwandel jhead locate r 34 io h 34 find usr include name 34 io h 34 一个现成更改照片时间的程式 jhead
  • Linux 内核和驱动开发工程师的发展前景怎么样

    或许这样的标题 xff0c 应该是由像Linus或Greg KH这样的大师级的高手才有资格写的吧 但是作为我来说 xff0c 也许我更想把这个标题作为一个疑问句来使用 xff0c 整理一下自己的认识 xff0c 用来勉励自己 xff0c 和
  • Linux awk 中 BEGIN 和 END 的使用方法

    1 awk的流程控制BEGIN和END http blog 51cto com 151wqooo 1309851 2 awk详解 http blog 51cto com 7177526 1387238
  • SLAM 介绍

    http www slamcn org index php E9 A6 96 E9 A1 B5 比较好的开源SLAM Odometry代码 xff1a https github com ethz asl rovio https github
  • MIPI接口介绍

    文章转自 xff1a http blog csdn net shen924 article details 9140509 xff0c 留此作为备份 xff0c 感谢原创贡献 xff5e 一 MIPI MIPI xff08 移动行业处理器接
  • STL的多线程安全问题

    1 stl的线程安全 说一些关于stl容器的线程安全相关的话题 一般说来 xff0c stl对于多线程的支持仅限于下列两点 xff1a 貌似Effective STL中有描述 1 多个读取者是安全的 即多个线程可以同时读取一个容器中的内容
  • 树莓派安装docker,Go语言。附VNC软件安装重启后,进入白屏登录界面的解决方案

    树莓派安装docker xff0c Go语言 附VNC软件安装重启后 xff0c 进入白屏登录界面的解决方案 背景 xff1a 课题要使用hyperledger xff0c 在ARM上应用 涉及到docker xff0c go语言 之后会包
  • 黑马程序员C++课程笔记二(模板、STL)

    笔记 C 43 43 模板 STL学习笔记 代码地址 xff1a 程序文件名与课程P一致 文章目录 笔记 C 43 43 模板 STL学习笔记1 模板1 1 模板的概念1 2 函数模板1 2 1 函数模板语法1 2 2 函数模板注意事项1
  • Nano板使用USB与PX4通信

    环境配置 USB micro与PX4通信 文章目录 环境配置 USB micro与PX4通信1 硬件接线2 软件环境 最近项目需要PX4与记载电脑通信 xff0c 查了下资料目前方案有 1 使用TELEM2串口的 xff0c 阿木的就是使用
  • 在Win下Visual Studio配置Eigen

    在Win下Visual Studio配置Eigen 最近在使用Visual Studio时想使用一下著名的矩阵运算库 xff1a Eigen xff0c 摸索了一下如何在Visual Studio中配置 1 下载Eigen源码 直接到Eig
  • AirSim中运行VIO算法(VINS-Mono)

    VINS Mono在AirSim上跑通 文章目录 VINS Mono在AirSim上跑通一 IMU参数配置二 相机参数设置三 AirSim发布数据问题 关于相机 IMU内外参的完整解释 xff0c 可以参考我的另一篇文章 一 IMU参数配置
  • AirSim中获取视觉、惯性数据方法研究

    AirSim中获取视觉 惯性数据方法研究 文章目录 AirSim中获取视觉 惯性数据方法研究1 获取ROS bag格式数据2 获取文件形式 EuRoc数据集格式 3 其他方案 最近在做AirSim中部署V SLAM xff0c 抽空将之前尝
  • 如何引用开源库(BibTex转为endnote)方法

    前言 xff1a 我们在写论文时 xff0c 论文的工作有时可能会用到别人的开源算法库 xff0c 那么我们如何在参考文献中引用呢 以Ceres库为例 xff0c 该库是谷歌开发的一款求解非线性优化问题的库 xff0c 相信做SLAM相关的
  • 关于MAC 安装 laravel4 的一些经验 二

    unix 和windows 完全不同 xff0c 只好恶补了一些UNIX的知识 xff0c 找到了 profie 这个是隐藏文件 xff0c 在find里面找不到的 接下来只能自己配置PHP环境或者下载其他软件 我下载了XAMPP xff0
  • AirSim相机、IMU内外参分析(VIO、vSLAM)

    作者 朱贞欣 xff0c 公ZH xff1a SLAM学习er 文章目录 0 引入1 世界坐标系2 IMU2 1 IMU数据生成2 2 关于IMU噪声 3 相机3 1 相机外参3 2 内参 0 引入 假设你想通过AirSim获取仿真数据运行
  • C++ cout输出小数位数

    方法一 xff1a 使用setiosflags span class token macro property span class token directive hash span span class token directive
  • kubeadm init 运行时kebelet启动失败问题

    最近在部署kebeedge xff0c 需要先在云服上部署k8s xff0c 期间通过kubeadm init config的方式进行master的部署 xff0c 记录一下遇到的kubelet相关的错误 在通过kubeadm init c
  • 2288hv5超融合服务器 数码管报888

    问题现象 2288hv5超融合服务器 xff0c 前面板数码管报888 xff0c 电源灯黄灯闪烁 xff0c 开不了机 xff0c ibmc网络是通的 xff0c 但是web网页打不开 问题原因 iBMC的版本过低 xff0c iBMC在
  • 跟我一起写操作系统(二)——史上最简单的内核

    跟我一起写操作系统 二 史上最简单的内核 转载注明出处 xff1a http www cnblogs com lucasysfeng p 4847662 html 上一讲地址 xff1a http www cnblogs com lucas