初识操作系统(启动区和初始化)

工具介绍

寄存器介绍

介绍在8086中存在的寄存器。

通用寄存器:

  • AX,accumulator,累加寄存器
  • CX,counter,计数寄存器
  • DX,data,数据寄存器
  • BX,base,基址寄存器

X表示extend,因为之前的寄存器都是8位的。因此8位寄存器有:AL,AH,CL,CH,DL,DH,BL,BH。

另外32位通用寄存器为:EAX,ECX,EBX,EDX。


索引寄存器,包含段地址的偏移量:

  • SP,stack pointer,栈指针寄存器
  • BP,base pointer,基址指针寄存器
  • SI,source index,源变址寄存器
  • DI,destination index,目的变址寄存器

32位索引寄存器为:ESP,EBP,ESI,EDI。


段寄存器,作程序指令,数据或栈的基础位置:

  • CS,code segment,代码段寄存器
  • SS,stack segment,栈段寄存器
  • DS,data segment,数据段寄存器
  • ES,extra segment,附加段寄存器
  • FS,segment part2,没用名称
  • GS,segment part3, 没有名称

状态和控制寄存器:

  • IP,instruction pointer,指令指针寄存器,它是从 Code Segment 代码寄存器处的偏移来存储执行的下一条指令
  • FLAG : Flag 寄存器用于存储当前进程的状态

启动区介绍(bootloader)

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
CYLS   EQU   10
entry:
MOV AX, 0 ; 初始化寄存器
MOV SS, AX
MOV SP, 0x7c00 ;https://wiki.osdev.org/Memory_Map_(x86)
MOV DS, AX

; 读取硬盘
MOV AX, 0x0820
MOV ES, AX
MOV CH, 0 ; 柱面0
MOV DH, 0 ; 磁头0
MOV CL, 2 ; 扇区2,从第二个开始读,第一个默认读取

readloop:
MOV SI, 0 ; 记录失败次数的寄存器
retry:
MOV AH, 0x02 ; AH=0x02:读盘
MOV AL, 1 ; 1个扇区
MOV BX, 0
MOV DL, 0x00 ; A驱动器
INT 0x13 ; 调用磁盘BIOS
JNC next ; 没出错跳转到next

ADD SI, 1 ; 失败次数+1
CMP SI, 5 ; 失败次数是否达到5次
JAE error ; 失败次数达到5次跳转到error
MOV AH, 0x00
MOV DL, 0x00 ; A驱动器
INT 0x13 ; 重置驱动器
JMP retry

next:
MOV AX, ES ; 把内存地址后移0x200,移动一个软盘的位置
ADD AX, 0x0020
MOV ES, AX ; 实现ES += 0x0020的目的

; 扇区范围 1~18
ADD CL, 1 ; 扇区加1
CMP CL, 18 ; 扇区是否达到18
JBE readloop ; 小于等于18扇区则跳转到readloop

MOV CL, 1 ; 恢复到扇区1
; 磁头范围 0~1(正面0,反面1)
ADD DH, 1
CMP DH, 2
JB readloop ; 磁头未达到2则跳转到readloop

MOV DH, 0
; 柱面范围 0 ~ 79
ADD CH, 1
CMP CH, CYLS
JB readloop ; 读取指定数量的柱面,未达到CYLS则跳转readloop

; 读取完毕,跳转到haribote.sys执行
MOV [0x0ff0], CH ; 记下IPL读了多远
JMP 0xc200

初始化寄存器,其中0x7c00表示程序装载的位置,可以参考链接中的内存分布图,0x00007C00 — 0x00007DFF为启动区装载地址(IBM规定)。参考:https://www.glamenv-septzen.net/en/view/6

初始化之后为读盘操作,这里读了10个柱面,每个柱面18个扇区,2个磁头(1张软盘有80个柱面,2个磁头,18个扇区,一个扇区512字节),即C0-H0-S1 -> C9-H1-S18,共180KB内容。INT指令为调用BIOS函数。

整体地址:

+ 0x00007C00 -- 0x00007DFF:启动区状态地址
+ 0x000008000 -- 0x000008200:启动区内容,默认读取
+ 0x000008200 -- 0x00000E600:软盘剩下内容

一般向一个空软盘保存文件时:

  1. 文件名会写在0X002600以后的地方
  2. 文件的内容会写在0X004200以后的地方

因此磁盘的内容位于内存0X8000+0X4200=0XC200的地方,即最后的jump语句执行的地方。

初始化介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
; 有关BOOT_INFO
CYLS EQU 0x0ff0 ; 设置启动区
LEDS EQU 0x0ff1
VMODE EQU 0x0ff2 ; 关于颜色数目的信息,颜色的位数
SCRNX EQU 0x0ff4 ; 分辨率X
SCRNY EQU 0x0ff6 ; 分辨率Y
VRAM EQU 0x0ff8 ; 图像缓冲区的起始位置

entry:
; 设置屏幕模式
MOV AL, 0x13 ; VGA显卡,320x200x8 bit
MOV AH, 0x00
INT 0x10 ; 调用bios

MOV BYTE [VMODE], 8 ; 屏幕的模式
MOV WORD [SCRNX], 320
MOV WORD [SCRNY], 200
MOV DWORD [VRAM], 0x000a0000

; 用BIOS取得键盘上各种LED指示灯的状态
MOV AH, 0x02
INT 0x16 ; 键盘BIOS
MOV [LEDS], AL

将画面模式信息保存在内存里面,同时把像素数、颜色数、键盘信息保存在0x0ff0附近,从内存分布图上来看,这块没有被使用。

参考BIOS设定:https://wiki.osdev.org/BIOS

MAKEFILE详解:

来源:https://github.com/ghosind/HariboteOS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

AS := nasm
CC := $(GCCPREFIX)gcc
LD := $(GCCPREFIX)ld

ipl.bin:
$(AS) -f bin ipl.asm -o ipl.bin -l ipl.lst

asmhead.bin:
$(AS) -f elf asmhead.asm -o asmhead.bin -l asmhead.lst

bootpack.bin:
$(CC) $(CFLAGS) -c bootpack.c -o bootpack.bin

func.bin:
$(AS) -f elf func.asm -o func.bin -l func.lst

haribote.sys: asmhead.bin bootpack.bin func.bin
$(LD) -m elf_i386 --oformat binary asmhead.bin bootpack.bin func.bin -o haribote.sys -T haribote.ld

image: ipl.bin haribote.sys
dd if=/dev/zero of=$(IMG) bs=512 count=2880
dd if=ipl.bin of=$(IMG) bs=512 count=1 conv=notrunc
dd if=haribote.sys of=$(IMG) seek=33 bs=512 conv=notrunc (512*33=0x4200)

gcc已经做好编译汇编的操作,在haribote.sys进行链接,最后用dd命令生成img文件。

Linux启动介绍

内核启动过程:https://www.cnblogs.com/anywherego/p/18217546

启动区需要看grub源码~