Antz系统更新地址: https://www.cnblogs.com/LexMoon/category/1262287.html
Linux内核源码分析地址:https://www.cnblogs.com/LexMoon/category/1267413.htmlGithub地址:https://github.com/CasterWx
在前几天的任务中,我们已经简单实现了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内核已经加载成功了。