从零实现一个操作系统-day4-5

在软盘中安装grub

昨天在这一步出了点问题,很难受,今天来解决一下
我发现问题可能跟我使用的是腾讯云的vps有关,后来我换了一台vultr的centos的vps之后就没问题了,接着昨天的
用loop0把floppy.img虚拟成块设备

1
sudo losetup /dev/loop0 floppy.img

进入grub命令行

1
sudo grub

然后输入下面的命令

1
2
3
device (fd0) /dev/loop0
root (fd0)
setup (fd0)

然后解除loop0和floppy.img的关联,解除挂载

1
2
sudo losetup -d /dev/loop0
sudo umount /mnt/kernel

现在软盘镜像就做好了,不过还没有内核,先来测试一下

1
qemu -fda floppy.img -boot a

看到grub的菜单界面就成功了

注意:如果用的是vps,那么ssh客户端一定要支持x11,不然虚拟机运行不了,因为虚拟机需要图形化界面,今天grub命令行和x11花了我大量的时间,摸索Google了半天,总算解决了2333,所以昨天就没更新bolg,内容太少了233

内核的入口

boot/boot.s

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
; ----------------------------------------------------------------
;
; boot.s -- 内核从这里开始
;
; ----------------------------------------------------------------

; Multiboot 魔数,由规范决定的
MBOOT_HEADER_MAGIC equ 0x1BADB002

; 0 号位表示所有的引导模块将按页(4KB)边界对齐
MBOOT_PAGE_ALIGN equ 1 << 0

; 1 号位通过 Multiboot 信息结构的 mem_* 域包括可用内存的信息
; 告诉(把内存空间的信息包含在信息结构中GRUBMultiboot)
MBOOT_MEM_INFO equ 1 << 1

; 定义我们使用的 Multiboot 的标记
MBOOT_HEADER_FLAGS equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO

; 域是一个位的无符号值,当与其他的域checksum32magic也就是(和magicflags)
; 相加时,要求其结果必须是位的无符号值32 0 即(magic+flags+checksum = 0)
MBOOT_CHECKSUM equ -(MBOOT_HEADER_MAGIC+MBOOT_HEADER_FLAGS)

; 符合规范的Multiboot OS 映象需要这样一个 magic Multiboot 头
; Multiboot 头的分布必须如下表所示:
; ----------------------------------------------------------
; 偏移量类型域名备注
;
; 0 u32 magic 必需
; 4 u32 flags 必需
; 8 u32 checksum 必需
;
; 我们只使用到这些就够了,更多的详细说明请参阅 GNU 相关文档
;-----------------------------------------------------------

;-----------------------------------------------------------------------------

[BITS 32] ; 所有代码以 32-bit 的方式编译
section .text ; 代码段从这里开始

; 在代码段的起始位置设置符合 Multiboot 规范的标记

dd MBOOT_HEADER_MAGIC ; GRUB 会通过这个魔数判断该映像是否支持
dd MBOOT_HEADER_FLAGS ; GRUB 的一些加载时选项,其详细注释在定义处
dd MBOOT_CHECKSUM ; 检测数值,其含义在定义处

[GLOBAL start] ; 向外部声明内核代码入口,此处提供该声明给链接器
[GLOBAL glb_mboot_ptr] ; 向外部声明 struct multiboot * 变量
[EXTERN kern_entry] ; 声明内核 C 代码的入口函数

start:
cli ; 此时还没有设置好保护模式的中断处理,要关闭中断
; 所以必须关闭中断
mov esp, STACK_TOP ; 设置内核栈地址
mov ebp, 0 ; 帧指针修改为 0
and esp, 0FFFFFFF0H ; 栈地址按照字节对齐16
mov [glb_mboot_ptr], ebx ; 将 ebx 中存储的指针存入全局变量
call kern_entry ; 调用内核入口函数
stop:
hlt ; 停机指令,可以降低 CPU 功耗
jmp stop ; 到这里结束,关机什么的后面再说

;-----------------------------------------------------------------------------

section .bss ; 未初始化的数据段从这里开始
stack:
resb 32768 ; 这里作为内核栈
glb_mboot_ptr: ; 全局的 multiboot 结构体指针
resb 4

STACK_TOP equ $-stack-1 ; 内核栈顶,$ 符指代是当前地址

;-----------------------------------------------------------------------------

上面这段是汇编的代码,分号后面的是注释
7-22行定义了Multiboot规范要用到的一些值,Multiboot定义的Multiboot 头的分布必须如下表所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
偏移量 类型 域名 备注
0 u32 magic 必需
4 u32 flags 必需
8 u32 checksum 必需
12 u32 header_addr 如果flags[16]被置位
16 u32 load_addr 如果flags[16]被置位
20 u32 load_end_addr 如果flags[16]被置位
24 u32 bss_end_addr 如果flags[16]被置位
28 u32 entry_addr 如果flags[16]被置位
32 u32 mode_type 如果flags[2]被置位
36 u32 width 如果flags[2]被置位
40 u32 height 如果flags[2]被置位
44 u32 depth 如果flags[2]被置位

这里只用到了前三个,MBOOT_HEADER_MAGIC 就是标志头的魔数,必须等于0x1BADB002
MBOOT_HEADER_FLAGS 就是flag,一共32位,不同位置1有不同的含义,这里将0和1位置1了,代表的意义在注释上
MBOOT_CHECKSUM 就是checksum ,域checksum是一个32位的无符号值,当与其他的magic域(也就是magic和flags)相加时,结果必须是32位的无符号值0(即magic + flags + checksum = 0)。
43-45行定义了这三个数为32位,即4字节
51行的start就是链接器脚本定义的内核入口函数
start干的事情就是关中断,设置栈,然后将grub提供的信息的指针放到全局变量里面((按照协议,GRUB把一些计算机硬件和我们内核文件相关的信息放在了一个结构
体中,并且将这个结构体指针放在了ebx寄存器中)
最后调用c语言写的函数kern_entry,这个函数返回后就是hlt待机了
65行到最后定义了未初始化的一些空间,定义了栈大小为32768字节,glb_mboot_ptr指针为4字节,定义了栈顶的地址

init/entry.c

汇编写完了,现在可以来写c语言啦

1
2
3
4
int kern_entry()
{
return 0;
}

这个就是上面汇编调用的c的函数,函数啥也没干233

include/types.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#ifndef INCLUDE_TYPES_H_
#define INCLUDE_TYPES_H_

#ifndef NULL
#define NULL 0
#endif

#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif

typedef unsigned int uint32_t;
typedef int int32_t;
typedef unsigned short uint16_t;
typedef short int16_t;
typedef unsigned char uint8_t;
typedef char int8_t;

#endif // INCLUDE_TYPES_H_

这个就是做了一些宏定义,并且把c语言的一些类型名字做了重命名
现在的目录结构是这样的:

现在我们来启动试试看

1
2
make 
make qemu

先看到grub的菜单,然后选择操作系统之后就啥也不干了,毕竟我们啥也没写233
今天就先结束了,成完成了一个啥也不做的内核2333

本文标题:从零实现一个操作系统-day4-5

文章作者:

发布时间:2020年04月19日 - 14:04

最后更新:2020年04月21日 - 01:04

原始链接:http://startcraft.cn/post/c6c2daa1.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------The End-------------