自制操作系统Antz day07——实现内核 (上)

  Antz系统更新地址: https://www.cnblogs.com/LexMoon/category/1262287.html

  Linux内核源码分析地址:https://www.cnblogs.com/LexMoon/category/1267413.html

  Github地址: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编译。

  自制操作系统Antz day07——实现内核 (上)

  -f elf 指定了输出文件的格式为ELF格式。

  编译完成之后要进行链接,链接指令如下:

  自制操作系统Antz day07——实现内核 (上)

    (出现警告,在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    $

  自制操作系统Antz day07——实现内核 (上)

  出现了Ready,说明我们的kernel内核已经加载成功了。

 

上一篇:自制操作系统Antz day01——Boot Sector


下一篇:C++彩色数据流动界面