Antz系统更新地址: https://www.cnblogs.com/LexMoon/category/1262287.html
Linux内核源码分析地址:https://www.cnblogs.com/LexMoon/category/1267413.html
在前几天的任务中,我们已经简单实现了MBR,直接操作显示器和硬盘操作来加载其他扇区的程序,如今已经可以进入保护模式了,简单引入了C语言,接下来我们编写自己的内核。
0. 汇编生成ELF
完成实模式到保护模式跳转的这一任务是由loader进行的,而我们不应该用loader做太多的事,loader只需要完成跳转就好了,剩下的工作交给内核。
为了加载内核到内存,需要使用ELF格式,如何编译这种格式呢?
来看看下面这个例子。
[section .data]
strHello db "Hello, Antz !", 0Ah
STRLEN equ $ - strHello
[section .text]
global _start
_start:
mov edx, STRLEN
mov ecx, strHello
mov ebx, 1
mov eax, 4
int 0x80
mov ebx, 0
mov eax, 1
int 0x80
global _start定义了程序的入口地址,相当于c/c++中main。
接下来使用NASM编译。
-f elf 指定了输出文件的格式为ELF格式。
编译完成之后要进行链接,链接指令如下:
(出现警告,在linux无警告,Windows下会有,可以无视)
-s是strip的简写,可以去掉符号表等内容,对生成的可执行代码进行减肥。
1. 汇编与C语言共同使用
我们已经可以生成一个支持载入内存的内核格式文件了,现在我们要学会把汇编程序和c语言程序链接在一起。这是我们编写内核的一大步。
先来看看c代码:
其中定义了一个choose函数,声明了一个myprint函数。
1 void myprint(char* msg, int len);
2
3 int choose(int a, int b)
4 {
5 if(a >= b){
6 myprint("the 1st one\n", 13);
7 }
8 else{
9 myprint("the 2nd one\n", 13);
10 }
11
12 return 0;
13 }
再来看看汇编代码:
1 extern choose
2
3
4 [section .data] ; 数据在此
5
6 num1st dd 3
7 num2nd dd 4
8
9
10 [section .text] ; 代码在此
11
12 global _start
13 global myprint
14
15 _start:
16 push num2nd
17 push num1st
18 call choose
19 add esp, 4
20
21 mov ebx, 0
22 mov eax, 1
23 int 0x80
24
25 ; void myprint(char* msg, int len)
26 myprint:
27 mov edx, [esp + 8] ; len
28 mov ecx, [esp + 4] ; msg
29 mov ebx, 1
30 mov eax, 4 ; sys_write
31 int 0x80
32 ret
33
如果你懂汇编,这个代码一定没有如何问题。
第一行的extern choose就是指c代码中定义的choose函数。
后面的global导出了函数入口,_start和在c文件中没有定义的myprint函数,myprint在汇编代码中完成了定义。
_start中调用了choose,choose中又调用了myprint函数。
这样这两个代码文件内容就很清晰了吧。
在Linux终端下查看结果:
1 nasm -f elf foo.asm -o foo.o
2 gcc -c bar.c -o bar.o
3 ld -s hello.o bar.o -o foobar
4 ./foobar
2. 从Loader到内核
加载内核到内存和引导扇区的工作很相似,只是处理内核时我们要根据ELF文件结构中的值将内核中相应段放入相应位置。
fat12hdr.inc :
1 BS_OEMName DB 'Antz__Os'
2
3 BPB_BytsPerSec DW 512
4 BPB_SecPerClus DB 1
5 BPB_RsvdSecCnt DW 1
6 BPB_NumFATs DB 2
7 BPB_RootEntCnt DW 224
8 BPB_TotSec16 DW 2880
9 BPB_Media DB 0xF0
10 BPB_FATSz16 DW 9
11 BPB_SecPerTrk DW 18
12 BPB_NumHeads DW 2
13 BPB_HiddSec DD 0
14 BPB_TotSec32 DD 0
15
16
17 BS_DrvNum DB 0
18 BS_Reserved1 DB 0
19 BS_BootSig DB 29h
20 BS_VolID DD 0
21 BS_VolLab DB 'Tinix0.01 '
22 BS_FileSysType DB 'FAT12 '
23
24 FATSz equ 9
25 RootDirSectors equ 14
26
27 SectorNoOfRootDirectory equ 19
28 SectorNoOfFAT1 equ 1
29 DeltaSectorNo equ 17
30
boot.asm :
1 org 07c00h
2
3 BaseOfStack equ 07c00h
4 BaseOfLoader equ 09000h
5 OffsetOfLoader equ 0100h
6
7 jmp short LABEL_START
8 nop
9
10
11 %include "fat12hdr.inc"
12
13 LABEL_START:
14 mov ax, cs
15 mov ds, ax
16 mov es, ax
17 mov ss, ax
18 mov sp, BaseOfStack
19
20
21 mov ax, 0600h
22 mov bx, 0700h
23 mov cx, 0
24 mov dx, 0184fh
25 int 10h
26
27 mov dh, 0
28 call DispStr
29
30 xor ah, ah
31 xor dl, dl
32 int 13h
33
34 mov word [wSectorNo], SectorNoOfRootDirectory
35 LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
36 cmp word [wRootDirSizeForLoop], 0
37 jz LABEL_NO_LOADERBIN
38 dec word [wRootDirSizeForLoop]
39 mov ax, BaseOfLoader
40 mov es, ax
41 mov bx, OffsetOfLoader
42 mov ax, [wSectorNo]
43 mov cl, 1
44 call ReadSector
45
46 mov si, LoaderFileName
47 mov di, OffsetOfLoader
48 cld
49 mov dx, 10h
50 LABEL_SEARCH_FOR_LOADERBIN:
51 cmp dx, 0
52 jz LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR
53 dec dx
54 mov cx, 11
55 LABEL_CMP_FILENAME:
56 cmp cx, 0
57 jz LABEL_FILENAME_FOUND
58 dec cx
59 lodsb
60 cmp al, byte [es:di]
61 jz LABEL_GO_ON
62 jmp LABEL_DIFFERENT
63
64 LABEL_GO_ON:
65 inc di
66 jmp LABEL_CMP_FILENAME
67
68 LABEL_DIFFERENT:
69 and di, 0FFE0h
70 add di, 20h
71 mov si, LoaderFileName
72 jmp LABEL_SEARCH_FOR_LOADERBIN
73
74 LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR:
75 add word [wSectorNo], 1
76 jmp LABEL_SEARCH_IN_ROOT_DIR_BEGIN
77
78 LABEL_NO_LOADERBIN:
79 mov dh, 2
80 call DispStr
81 %ifdef _BOOT_DEBUG_
82 mov ax, 4c00h
83 int 21h
84 %else
85 jmp $
86 %endif
87
88 LABEL_FILENAME_FOUND:
89 mov ax, RootDirSectors
90 and di, 0FFE0h
91 add di, 01Ah
92 mov cx, word [es:di]
93 push cx
94 add cx, ax
95 add cx, DeltaSectorNo
96 mov ax, BaseOfLoader
97 mov es, ax
98 mov bx, OffsetOfLoader
99 mov ax, cx
100
101 LABEL_GOON_LOADING_FILE:
102 push ax
103 push bx
104 mov ah, 0Eh
105 mov al, '.'
106 mov bl, 0Fh
107 int 10h
108 pop bx
109 pop ax
110
111 mov cl, 1
112 call ReadSector
113 pop ax
114 call GetFATEntry
115 cmp ax, 0FFFh
116 jz LABEL_FILE_LOADED
117 push ax
118 mov dx, RootDirSectors
119 add ax, dx
120 add ax, DeltaSectorNo
121 add bx, [BPB_BytsPerSec]
122 jmp LABEL_GOON_LOADING_FILE
123 LABEL_FILE_LOADED:
124
125 mov dh, 1
126 call DispStr
127
128
129 jmp BaseOfLoader:OffsetOfLoader
130
131
132 wRootDirSizeForLoop dw RootDirSectors
133 wSectorNo dw 0
134 bOdd db 0
135
136
137 LoaderFileName db "LOADER BIN", 0
138
139 MessageLength equ 9
140 BootMessage: db "Booting ";
141 Message1 db "Ready. ";
142 Message2 db "No LOADER";
143
144
145 DispStr:
146 mov ax, MessageLength
147 mul dh
148 add ax, BootMessage
149 mov bp, ax
150 mov ax, ds
151 mov es, ax
152 mov cx, MessageLength
153 mov ax, 01301h
154 mov bx, 0007h
155 mov dl, 0
156 int 10h
157 ret
158
159
160 ReadSector:
161 push bp
162 mov bp, sp
163 sub esp, 2
164
165 mov byte [bp-2], cl
166 push bx
167 mov bl, [BPB_SecPerTrk]
168 div bl
169 inc ah
170 mov cl, ah
171 mov dh, al
172 shr al, 1
173 mov ch, al
174 and dh, 1
175 pop bx
176
177 mov dl, [BS_DrvNum]
178 .GoOnReading:
179 mov ah, 2
180 mov al, byte [bp-2]
181 int 13h
182 jc .GoOnReading
183
184 add esp, 2
185 pop bp
186
187 ret
188
189 GetFATEntry:
190 push es
191 push bx
192 push ax
193 mov ax, BaseOfLoader
194 sub ax, 0100h
195 mov es, ax
196 pop ax
197 mov byte [bOdd], 0
198 mov bx, 3
199 mul bx
200 mov bx, 2
201 div bx
202 cmp dx, 0
203 jz LABEL_EVEN
204 mov byte [bOdd], 1
205 LABEL_EVEN:
206 xor dx, dx
207 mov bx, [BPB_BytsPerSec]
208 div bx
209
210 push dx
211 mov bx, 0
212 add ax, SectorNoOfFAT1
213 mov cl, 2
214 call ReadSector
215 pop dx
216 add bx, dx
217 mov ax, [es:bx]
218 cmp byte [bOdd], 1
219 jnz LABEL_EVEN_2
220 shr ax, 4
221 LABEL_EVEN_2:
222 and ax, 0FFFh
223
224 LABEL_GET_FAT_ENRY_OK:
225
226 pop bx
227 pop es
228 ret
229
230 times 510-($-$$) db 0
231 dw 0xaa55
loader.asm:
1 org 0100h
2
3 BaseOfStack equ 0100h
4
5 BaseOfKernelFile equ 08000h
6 OffsetOfKernelFile equ 0h
7
8 jmp LABEL_START
9
10
11 %include "fat12hdr.inc"
12
13
14 LABEL_START:
15 mov ax, cs
16 mov ds, ax
17 mov es, ax
18 mov ss, ax
19 mov sp, BaseOfStack
20
21 mov dh, 0
22 call DispStr
23
24
25 mov word [wSectorNo], SectorNoOfRootDirectory
26 xor ah, ah
27 xor dl, dl
28 int 13h
29 LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
30 cmp word [wRootDirSizeForLoop], 0
31 jz LABEL_NO_KERNELBIN
32 dec word [wRootDirSizeForLoop]
33 mov ax, BaseOfKernelFile
34 mov es, ax
35 mov bx, OffsetOfKernelFile
36
37 mov ax, [wSectorNo]
38 mov cl, 1
39 call ReadSector
40
41 mov si, KernelFileName
42 mov di, OffsetOfKernelFile
43 cld
44 mov dx, 10h
45 LABEL_SEARCH_FOR_KERNELBIN:
46 cmp dx, 0
47 jz LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR
48 dec dx
49 mov cx, 11
50 LABEL_CMP_FILENAME:
51 cmp cx, 0
52 jz LABEL_FILENAME_FOUND
53 dec cx
54 lodsb
55 cmp al, byte [es:di]
56 jz LABEL_GO_ON
57 jmp LABEL_DIFFERENT
58 LABEL_GO_ON:
59 inc di
60 jmp LABEL_CMP_FILENAME
61
62 LABEL_DIFFERENT:
63 and di, 0FFE0h
64 add di, 20h
65 mov si, KernelFileName
66 jmp LABEL_SEARCH_FOR_KERNELBIN
67
68 LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR:
69 add word [wSectorNo], 1
70 jmp LABEL_SEARCH_IN_ROOT_DIR_BEGIN
71
72 LABEL_NO_KERNELBIN:
73 mov dh, 2
74 call DispStr
75 %ifdef _LOADER_DEBUG_
76 mov ax, 4c00h
77 int 21h
78 %else
79 jmp $
80 %endif
81
82 LABEL_FILENAME_FOUND:
83 mov ax, RootDirSectors
84 and di, 0FFF0h
85
86 push eax
87 mov eax, [es : di + 01Ch]
88 mov dword [dwKernelSize], eax
89 pop eax
90
91 add di, 01Ah
92 mov cx, word [es:di]
93 push cx
94 add cx, ax
95 add cx, DeltaSectorNo
96 mov ax, BaseOfKernelFile
97 mov es, ax
98 mov bx, OffsetOfKernelFile
99 mov ax, cx
100
101 LABEL_GOON_LOADING_FILE:
102 push ax
103 push bx
104 mov ah, 0Eh
105 mov al, '.'
106 mov bl, 0Fh
107 int 10h
108 pop bx
109 pop ax
110
111 mov cl, 1
112 call ReadSector
113 pop ax
114 call GetFATEntry
115 cmp ax, 0FFFh
116 jz LABEL_FILE_LOADED
117 push ax
118 mov dx, RootDirSectors
119 add ax, dx
120 add ax, DeltaSectorNo
121 add bx, [BPB_BytsPerSec]
122 jmp LABEL_GOON_LOADING_FILE
123 LABEL_FILE_LOADED:
124
125 call KillMotor
126
127 mov dh, 1
128 call DispStr
129
130 jmp $
131
132
133
134 wRootDirSizeForLoop dw RootDirSectors
135 wSectorNo dw 0
136 bOdd db 0
137 dwKernelSize dd 0
138
139
140 KernelFileName db "KERNEL BIN", 0
141 MessageLength equ 9
142 LoadMessage: db "Loading "
143 Message1 db "Ready. "
144 Message2 db "No KERNEL"
145
146 DispStr:
147 mov ax, MessageLength
148 mul dh
149 add ax, LoadMessage
150 mov bp, ax
151 mov ax, ds
152 mov es, ax
153 mov cx, MessageLength
154 mov ax, 01301h
155 mov bx, 0007h
156 mov dl, 0
157 add dh, 3
158 int 10h
159 ret
160
161 ReadSector:
162
163 push bp
164 mov bp, sp
165 sub esp, 2
166
167 mov byte [bp-2], cl
168 push bx
169 mov bl, [BPB_SecPerTrk]
170 div bl
171 inc ah
172 mov cl, ah
173 mov dh, al
174 shr al, 1
175 mov ch, al
176 and dh, 1
177 pop bx
178
179 mov dl, [BS_DrvNum]
180 .GoOnReading:
181 mov ah, 2
182 mov al, byte [bp-2]
183 int 13h
184 jc .GoOnReading
185
186 add esp, 2
187 pop bp
188
189 ret
190
191 GetFATEntry:
192 push es
193 push bx
194 push ax
195 mov ax, BaseOfKernelFile
196 sub ax, 0100h
197 mov es, ax
198 pop ax
199 mov byte [bOdd], 0
200 mov bx, 3
201 mul bx
202 mov bx, 2
203 div bx
204 cmp dx, 0
205 jz LABEL_EVEN
206 mov byte [bOdd], 1
207 LABEL_EVEN:
208 xor dx, dx
209 mov bx, [BPB_BytsPerSec]
210 div bx
211
212 push dx
213 mov bx, 0
214 add ax, SectorNoOfFAT1
215 mov cl, 2
216 call ReadSector
217 pop dx
218 add bx, dx
219 mov ax, [es:bx]
220 cmp byte [bOdd], 1
221 jnz LABEL_EVEN_2
222 shr ax, 4
223 LABEL_EVEN_2:
224 and ax, 0FFFh
225
226 LABEL_GET_FAT_ENRY_OK:
227
228 pop bx
229 pop es
230 ret
231
232 KillMotor:
233 push dx
234 mov dx, 03F2h
235 mov al, 0
236 out dx, al
237 pop dx
238 ret
加载功能已经有了,但是还没有内核给以上程序拿来加载。
我们来实现一个最简单的内核,以后会基于此扩展。
kernel.asm :
此处的K不会打印,因为这里只是假设gs指向了显存。
1 [section .text]
2
3 global _start
4
5 _start:
6 mov ah, 0Fh ; 0000: 黑底 1111: 白字
7 mov al, 'K'
8 mov [gs:((80 * 1 + 39) * 2)], ax ; 屏幕第 1 行, 第 39 列。
9 jmp $
出现了Ready,说明我们的kernel内核已经加载成功了。