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编译。

  Antz系统更新地址:&nbsp;<a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.cnblogs.com%2FLexMoon%2Fcategory%2F1262287.html" target="_blank" rel="nofollow">https://www.cnblogs.com/LexMoon/category/1262287.html</a>-LMLPHP

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

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

  Antz系统更新地址:&nbsp;<a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.cnblogs.com%2FLexMoon%2Fcategory%2F1262287.html" target="_blank" rel="nofollow">https://www.cnblogs.com/LexMoon/category/1262287.html</a>-LMLPHP

    (出现警告,在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系统更新地址:&nbsp;<a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.cnblogs.com%2FLexMoon%2Fcategory%2F1262287.html" target="_blank" rel="nofollow">https://www.cnblogs.com/LexMoon/category/1262287.html</a>-LMLPHP

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

04-02 15:16