2019-05-29 | UNLOCK

2019-5-29-自己动手写操作系统(3)

前言:

一边自己写简易的操作系统,一边阅读《程序员的自我修养》了解操作系统,越发地体会到操作系统的复杂。今天为了之后实验更方便地进行调试,还需要安装一个X86的dos。

第一步:配置freedos

1、下载freedos

http://bochs.sourceforge.net/guestos/freedos-img.tar.gz上面下载FreeDos

2、创建镜像

bochs可以通过bximage命令快捷地创建镜像
avatar
其中红框部分就是要需要输入的,分别是选择功能、选择创建硬盘(hd)还是软盘(fd)镜像、设置软盘镜像大小、命名(pm.img)。
随后将下载好的freedos解压

1
tar vxzf freedos-img.tar.gz

将解压得到的a.img改名成freedos.img,和上一步创建的pm.img放在同一个工作目录下
之后可以将freedos解压文件中的bochsrc直接复制到该文件,然后修改部分配置选项
avatar
接着启动bochs

1
bochs  -f  bochsrc

启动后格式化b盘,然后退出bochs
avatar

第二步:编译pmtest1.asm

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
;=========================================
;pmtest1.asm
;编译方法: nasm pmtest1.asm -o pmtest1.com
;=========================================
%include "pm.inc";常量、宏,以及一些说明
org 0100h
jmp LABEL_BEGIN

[SECTION .gdt]
; GDT
LABEL_GDT: Descriptor 0, 0, 0 ;空描述符
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32
;代码段,32位
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW
;显存首地址
;GDT结束

GdtLen equ $ - LABEL_GDT ;GDT长度
GdtPtr dw GdtLen ;GDT界限
dd 0 ;GDT基地址

;GDT选择子
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
;END of [SECTION .gdt]
[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0100h

;初始化32位代码段描述符
xor eax, eax
mov ax, cs
shl eax, 4
add eax, LABEL_SEG_CODE32
mov word [LABEL_DESC_CODE32 + 2], ax
shr eax, 16
mov byte [LABEL_DESC_CODE32 + 4], al
mov byte [LABEL_DESC_CODE32 + 7], ah

;为加载gdtr做准备
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_GDT
mov dword [GdtPtr + 2], eax

;加载gdtr
lgdt [GdtPtr]

;关中断
cli

;打开地址线A20
in al, 92h
or al, 00000010b
out 92h, al

;准备切换到保护模式
mov eax, cr0
or eax, 1
mov cr0, eax

;真正进入保护方式
jmp dword SelectorCode32:0 ;执行这一句会把SelectorCode32装入cs,并跳转到SelectorCode32:0处

[SECTION .32]; 32位代码段,由实模式跳入
[BITS 32]

LABEL_SEG_CODE32:
mov ax, SelectorVideo
mov gs, ax ;视频段选择子(目的)
mov edi, (80 * 10 + 0) * 2 ;屏幕第10行,第0列
mov ah, 0ch ;0000:黑底 1100:红字
mov al, 'P'
mov [gs:edi], ax

;到此为止

jmp $

SegCode32Len equ $ - LABEL_SEG_CODE32
;END of [SECTION .s32]

另外还要准备pm.inc(代码来源https://blog.csdn.net/jltxgcy/article/details/8656101)

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
74
75
76
77
78
79
80
81
82
83
84
85
;----------------------------------------------------------------------------
; 描述符类型值说明
; 其中:
; DA_ : Descriptor Attribute
; D : 数据段
; C : 代码段
; S : 系统段
; R : 只读
; RW : 读写
; A : 已访问
; 其它 : 可按照字面意思理解
;G D 0 AVL 0 0 0 0 P DPL(2位) DT TYPE(4位)
;----------------------------------------------------------------------------
DA_32 EQU 4000h ; 32 位段 0100 0000 0000 0000

DA_DPL0 EQU 00h ; DPL = 0 0000 0000
DA_DPL1 EQU 20h ; DPL = 1 0010 0000
DA_DPL2 EQU 40h ; DPL = 2 0100 0000
DA_DPL3 EQU 60h ; DPL = 3 0110 0000
;----------------------------------------------------------------------------
; 存储段描述符类型值说明
;----------------------------------------------------------------------------
DA_DR EQU 90h ; 存在的只读数据段类型值 1001 0000
DA_DRW EQU 92h ; 存在的可读写数据段属性值 1001 0010
DA_DRWA EQU 93h ; 存在的已访问可读写数据段类型值 1001 0011
DA_C EQU 98h ; 存在的只执行代码段属性值 1001 1000
DA_CR EQU 9Ah ; 存在的可执行可读代码段属性值 1001 1010
DA_CCO EQU 9Ch ; 存在的只执行一致代码段属性值 1001 1100
DA_CCOR EQU 9Eh ; 存在的可执行可读一致代码段属性值 1001 1110
;----------------------------------------------------------------------------
; 系统段描述符类型值说明
;----------------------------------------------------------------------------
DA_LDT EQU 82h ; 局部描述符表段类型值 1000 0010
DA_TaskGate EQU 85h ; 任务门类型值 1000 0101
DA_386TSS EQU 89h ; 可用 386 任务状态段类型值 1000 1001
DA_386CGate EQU 8Ch ; 386 调用门类型值 1000 1100
DA_386IGate EQU 8Eh ; 386 中断门类型值 1000 1110
DA_386TGate EQU 8Fh ; 386 陷阱门类型值 1000 1111
;----------------------------------------------------------------------------


;----------------------------------------------------------------------------
; 选择子类型值说明
; 其中:
; SA_ : Selector Attribute


SA_RPL0 EQU 0 ; ┓00
SA_RPL1 EQU 1 ; ┣RPL01
SA_RPL2 EQU 2 ; ┃10
SA_RPL3 EQU 3 ; ┛11

SA_TIG EQU 0 ; ┓TI 0000
SA_TIL EQU 4 ; ┛ 0100
;----------------------------------------------------------------------------


;宏----------------------------------------------------------------------------------------
;
; 描述符
; usage: Descriptor Base, Limit, Attr
; Base: dd
; Limit: dd (low 20 bits available)低二十位可用
; Attr: dw (lower 4 bits of higher byte are always 0)高字节的低四位始终为0
%macro Descriptor 3 ;段界限为低地址 1代表Base 2代表Limit 3代表属性
dw %2 & 0FFFFh ; 段界限 1 (2 字节)
dw %1 & 0FFFFh ; 段首地址 1 (2 字节)
db (%1 >> 16) & 0FFh ; 段首地址 2 (1 字节)
dw ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)
; 属性 1 + 段界限 2 + 属性 2 (2 字节)
db (%1 >> 24) & 0FFh ; 段首地址 3 (1 字节)
%endmacro ; 共 8 字节
;
; 门
; usage: Gate Selector, Offset, DCount, Attr
; Selector: dw
; Offset: dd
; DCount: db
; Attr: db
%macro Gate 4 ;1代表Selector 2代表Offset 3代表DCount 4代表Attr
dw (%2 & 0FFFFh) ; 偏移 1 (2 字节)
dw %1 ; 选择子 (2 字节)
dw (%3 & 1Fh) | ((%4 << 8) & 0FF00h) ; 属性 (2 字节)
dw ((%2 >> 16) & 0FFFFh) ; 偏移 2 (2 字节)
%endmacro ; 共 8 字节

最后编译pmtest1.com

1
nasm pmtest1.asm -o pmtest1.com

#第三步:在freedos中运行pmtest1.com
这里可以用linux下的mount命令,在mnt目录下创建一个文件,然后和pm.img关联

1
2
3
4
5
6
7
sudo mkdir /mnt/floppy

sudo mount -o loop pm.img /mnt/floppy

sudo cp pmtest1.com /mnt/floppy

sudo umount /mnt/floppy

运行freedos,在b盘可以看到出现了pmtest1.com
avatar
然后输入pmtest1.com就可以运行了
avatar
屏幕出现了一个红色P,说明pmtest运行成功

参考自https://blog.csdn.net/yudale/article/details/68500536

评论加载中