自制os开发记(一)——启动部分

将自制的操作系统命名为BlackPoint

基本是按照《自己动手写os》中的步骤来的,从软盘启动,调入Loader再调入Kernel
没有完全复制书中的代码,而是按照其中的思路来自己写一遍,收获颇丰啊。

第一步先构造软盘的启动扇区boot.asm,使用NASM在XP下开发:
 1 %include "address.inc"
 2  %include "macro.inc"
 3 
 4  org 0x7c00
 5  TOP_OF_STACK EQU 0x7c00
 6 
 7  jmp short LAB_boot
 8  nop
 9 
10  %include "fat12hdr"
11 
12  LAB_boot:
13          mov ax, cs
14          mov ds, ax
15          mov es, ax
16          mov ss, ax
17          mov sp, TOP_OF_STACK
18 
19          RESET_FLOPPY
20 
21          ;load FAT1
22          LOAD_SEC SBASE_FAT, START_FAT1, LENGTH_FAT1
23 
24          ;load Root Entry Table
25          LOAD_SEC SBASE_RET, START_RET, LENGTH_RET
26 
27          ;load loader
28          LOAD_FILE SBASE_loader, OFFSET_loader, loader_filename
29 
30          jmp SBASE_loader:OFFSET_loader
31 
32 
33  ;strings
34  loader_filename        DB        `LOADER  BIN`, 0
35 
36  %include "floppy.asm"
37 
38  TIMES (510 - ($ - $$)) DB 0
39  DW 0xaa55
启动扇区包含了四个文件:address是系统的内存布局安排,macro是我为了偷懒定义的一些宏。
fat12hdr是fat12格式软盘的头信息。
而floppy.asm是一些写好的过程,因为loader中也要用到,所以干脆做成了一个文件。

下面是floppy.asm的代码,他跟fat12hdr的依赖度很高:
  1  %include "address.inc"
  2 
  3  ;---------------------------------------------------------------------
  4 
  5  ;subroutine ReadSector
  6  ;read bl Sections start from Section ax
  7  ;result will be in es:di
  8  ReadSector:
  9 
 10          mov cl, 18
 11          div cl
 12          inc ah
 13          mov cl, ah            ;get Section
 14          mov ch, al
 15          shr ch, 1            ;get Cylinder
 16          mov dh, al
 17          and dh, 1            ;get Head
 18          xor dl, dl            ;disk0
 19          
 20          mov bh, 0x2
 21          push bp
 22          push bx
 23          mov bp, sp
 24          mov bx, di
 25  .1:
 26          mov ax, word [bp]
 27          int 0x13
 28          test ah, ah
 29          jnz .1
 30          pop bx
 31          pop bp
 32          ret
 33          
 34  ;---------------------------------------------------------------------
 35 
 36  ;subroutine SearchFile        
 37  ;search file in root entry table (SBASE_RET:0)
 38  ;input: filename should be stored in ds:si
 39  ;output: ax will be the first cluster no. of the file 
 40  SearchFile:
 41          mov bx, si            ;ds:bx -> filename
 42          mov ax, SBASE_RET
 43          mov es, ax
 44          xor di, di            ;es:0 -> the first Root Entry
 45          mov dx, 224
 46  .search:
 47          mov cx, 11
 48  .compare:
 49          mov al, byte [ds:bx]
 50          cmp al, byte [es:di]
 51          jne .next_entry
 52          inc bx
 53          inc di
 54          loop .compare
 55          jmp .ok
 56  .next_entry:
 57          mov bx, si        ;ds:bx -> filename
 58          and di, 0xffe0
 59          add di, 32        ;es:di -> next Root Entry
 60          dec dx
 61          jnz .search
 62  .fail:
 63          mov ax, cs
 64          mov ds, ax
 65          mov si, .msg_fail
 66  .print:
 67          mov al, byte [ds:si]
 68          test al, al
 69          jz $
 70          mov ah, 0x0e
 71          int 0x10
 72          inc si
 73          jmp .print
 74  .ok:
 75          and di, 0xffe0
 76          mov ax, word [es:di + 0x1a]        ;get cluster no.
 77          ret
 78 
 79  ;strings
 80  .msg_fail        DB        ` file is missing\n\r`, 0
 81 
 82  ;---------------------------------------------------------------------
 83 
 84  ;subroutine LoadFile
 85  ;load file started from cluster ax to es:di
 86  LoadFile:
 87  .1:
 88          cmp ax, 0xff8
 89          jae .end
 90          push ax
 91          add ax, 31
 92          mov bl, 1
 93          call ReadSector
 94          pop ax
 95          call GetNextClus
 96          add di, 512
 97          jmp .1
 98  .end:
 99          ret
100 
101  ;---------------------------------------------------------------------
102 
103  ;subroutine GetNextClus
104  ;get next clus_num of current clus(stored in ax)
105  ;FAT must be loaded in SBASE_FAT:0
106  ;result will be in ax
107  ;none of regs will be changed besides ax
108  GetNextClus:
109          push ds
110          push si
111          push bx
112 
113          mov bx, SBASE_FAT
114          mov ds, bx
115          mov bx, ax        ;let bx be the cluster no.
116          shr ax, 1
117          imul ax, 3
118          mov si, ax
119          test bx, 1        ;test cluster no. whether even or odd
120          jnz .odd
121  .even:
122          mov ax, word [ds:si]
123          and ax, 0xfff
124          jmp .end
125  .odd:
126          mov ax, word [ds:si + 1]
127          shr ax, 4
128  .end:
129          pop bx
130          pop si
131          pop ds
132          ret

下面是fat12hdr的内容,抄自《自己动手写os》
 1  BS_OEMName            DB        'bpt     '
 2  BPB_BytsPerSec        DW        512
 3  BPB_SecPerClus        DB        1
 4  BPB_RsvdSecCnt        DW        1
 5  BPB_NumFATs            DB        2
 6  BPB_RootEntCnt        DW        224
 7  BPB_TotSec16        DW        2880
 8  BPB_Media            DB        0xF0
 9  BPB_FATSz16            DW        9
10  BPB_SecPerTrk        DW        18
11  BPB_NumHeads        DW        2
12  BPB_HiddSec            DD        0
13  BPB_TotSec32        DD        0
14  BS_DrvNum            DB        0
15  BS_Reserved1        DB        0
16  BS_BootSig            DB        29h
17  BS_VolID            DD        0
18  BS_VolLab            DB        'BlackPoint '
19  BS_FileSysType        DB        'FAT12   '
20 
21  %ifndef __FAT12HDR
22  %define __FAT12HDR
23 
24  START_FAT1        EQU        1    ;BPB_RsvdSecCnt
25  LENGTH_FAT1        EQU        9    ;BPB_FATSz16
26  START_RET        EQU        19    ;BPB_RsvdSecCnt + BPB_NumFATs * BPB_FATSz16
27  LENGTH_RET        EQU        14    ;BPB_RootEntCnt * 32 / BPB_BytsPerSec
28 
29  %endif

下面是address.inc,其中的内容是启动时os的内存安排
 1  %ifndef __ADDRESS_INC
 2  %define __ADDRESS_INC
 3 
 4  SBASE_FAT        EQU        0x8000
 5  SBASE_RET        EQU        0x8500
 6 
 7  SBASE_loader    EQU        0x1000
 8  OFFSET_loader    EQU        0x00100
 9  BASE_loader        EQU        0x10000
10 
11  SBASE_mem        EQU        0x9000
12  BASE_mem        EQU        0x90000
13      ;name                ;offset        length        note
14      mem_size    EQU        0            ;4            memory size
15      num_ards    EQU        4            ;4            number of ards
16      mem_info    EQU        8            ;20 x 50    memory block info
17 
18  SBASE_elf        EQU        0x2000
19  OFFSET_elf        EQU        0x0
20  BASE_elf        EQU        0x20000
21 
22  BASE_kernel        EQU        0x30000
23  KERNEL_ENTRY    EQU        0x30400
24 
25  BASE_page_dir    EQU        0x100000
26  BASE_page_table    EQU        0x101000
27 
28  %endif

在下面就是我用来偷懒的macro.inc
 1  %ifndef __MACRO_INC
 2  %define __MACRO_INC
 3 
 4  ;---------------------------------------------------------------------
 5 
 6  %macro RESET_FLOPPY 0
 7          xor ah, ah
 8          xor dl, dl
 9          int 0x13
10 
11  %endmacro
12 
13  ;---------------------------------------------------------------------
14 
15  %macro CLOSE_FLOPPY 0
16          mov dx, 0x3f2
17          xor al, al
18          out dx, al
19  %endmacro
20 
21  ;---------------------------------------------------------------------
22 
23  ;load %3 sectors from %2 to %1:0
24  %macro LOAD_SEC 3
25          push es
26          mov ax, %1
27          mov es, ax
28          xor di, di
29          mov ax, %2
30          mov bl, %3
31          call ReadSector
32          pop es
33  %endmacro
34 
35  ;---------------------------------------------------------------------
36 
37  ;load file(ds:%3) to %1:%2
38  %macro LOAD_FILE 3
39          mov si, %3
40          call SearchFile
41          push es
42          mov bx, %1
43          mov es, bx
44          mov di, %2
45          call LoadFile
46          pop es
47  %endmacro
48 
49  ;---------------------------------------------------------------------
50 
51  ;PRINT row(byte), col(byte), char(byte)
52  %macro PRINT 3
53          mov edi, (80 * (%1) + (%2)) * 2
54          mov ah, 0x0c
55          mov al, (%3)
56          mov [gs:edi], ax
57  %endmacro
58 
59  ;---------------------------------------------------------------------
60 
61  %endif

折腾了这么多,软盘启动扇区算是开发完了。一路下来算是会用NASM了。记得刚开始用NASM时那个难啊。其实万事开头难,在暴风雨中坚持住,阳光自己来。

接下来是Loader的开发,更是让我叫苦不迭,每走一步都是荆棘遍野。通常是后面的bug调好了又发现了前面的bug,甚至多次重写。好在loader功能不多,可以一个一个小模块的开发,再组合起来。
先亮出一个重要的头文件,与保护模式有关的宏和定义都放置在x86.inc中:
  1  %ifndef __X86_INC
  2  %define __X86_INC
  3 
  4  %define BIT(X) (1  < < (X ))
  5 
  6  ; ===============================================================================
  7 
  8  ;despcritor des_t base(dword), limit(dword), attribute(word)
  9  ;
 10  ;attribute:
 11  ;    11    10    9    8        7    6    5    4        3    2    1    0
 12  ;    G    D    0    0        P    <DPL >     S         <  type     >     A
 13  %macro des_t 3
 14      DW        ((%2) & 0xffff)            ;limit 15~0
 15      DW        ((%1) & 0xffff)            ;base 15~0
 16      DB        (((%1) >> 16) & 0xff)    ;base 23~16
 17      DB        ((%3) & 0xff)            ;P, DPL, S, type, A
 18      DB        ((((%2) >> 16) & 0xf) | (((%3) >> 4) & 0xf0))
 19                                      ;G, D, 0, 0, limit 19~16
 20      DB        (((%1) >> 24) & 0xff)    ;base 31~24
 21  %endmacro
 22 
 23  ;descriptor attribute
 24  DA_G            EQU        BIT(11)            ;granularity 4KB
 25  DA_4G            EQU        DA_G
 26  DA_D            EQU        BIT(10)            ;default operation size 32bits
 27  DA_B            EQU        DA_D
 28  DA_P            EQU        BIT(7)            ;segment present
 29  DA_S            EQU        BIT(4)
 30  DA_DATA            EQU        DA_S            ;data segment
 31  DA_E            EQU        BIT(2)
 32  DA_W            EQU        BIT(1)            ;(data segment)writable
 33  DA_CODE            EQU        DA_S | BIT(3)    ;code segment
 34  DA_C            EQU        BIT(2)            ;(code segment)readable
 35  DA_R            EQU        BIT(1)            ;(code segment)conforming
 36  DA_A            EQU        BIT(0)            ;Accessed
 37 
 38  DA_LDT            EQU        0x2 | DA_P
 39  DA_TSS            EQU        0x9 | DA_P
 40  DA_CODE16        EQU        DA_CODE | DA_P
 41  DA_CODE32        EQU        DA_CODE | DA_D | DA_P
 42  DA_CODE32C        EQU        DA_CODE32 | DA_C
 43  DA_CODE32R        EQU        DA_CODE32 | DA_R
 44  DA_CODE32CR        EQU        DA_CODE32C | DA_R
 45  DA_CODE32RC        EQU        DA_CODE32CR
 46  DA_DATA16        EQU        DA_DATA | DA_P
 47  DA_DATA16W        EQU        DA_DATA16 | DA_W
 48  DA_DATA32        EQU        DA_DATA | DA_B | DA_P
 49  DA_DATA32W        EQU        DA_DATA32 | DA_W
 50  DA_STACK16        EQU        DA_DATA | DA_W | DA_P
 51  DA_STACK32        EQU        DA_DATA | DA_W | DA_B | DA_P
 52 
 53  DA_DPL0            EQU        0000_0000b        ;descriptor privilege level
 54  DA_DPL1            EQU        0010_0000b
 55  DA_DPL2            EQU        0100_0000b
 56  DA_DPL3            EQU        0110_0000b
 57 
 58 
 59  ;FILL_DES_BASE        descriptor, segment(word), offset(word)
 60  ;fill descriptor's dase with segment:offset
 61  ;eax will be modified
 62  %macro FILL_DES_BASE 3
 63          xor eax, eax
 64          mov ax, %2
 65          shl eax, 4
 66          add eax, %3
 67          mov word [%1 + 2], ax
 68          shr eax, 16
 69          mov byte [%1 + 4], al
 70          mov byte [%1 + 7], ah
 71  %endmacro
 72 
 73  ;FILL_DES_LIMIT        descriptor, limit(dword)
 74  ;fill descriptor's limit
 75  ;eax will be modified
 76  %macro FILL_DES_LIMIT 2
 77          mov eax, %2
 78          mov word [%1], ax
 79          shr eax, 16
 80          and al, 0xf
 81          or byte [(%1) + 6], al
 82  %endmacro
 83 
 84  ;===============================================================================
 85 
 86  ;gate_t selector(word), offset(dword), param_count(byte), attribute(byte)
 87  %macro gate_t 4
 88      DW        ((%2) & 0xffff)            ;offset 15~0
 89      DW        ((%1) & 0xffff)            ;selector
 90      DB        ((%3) & 0x11111b)        ;param count
 91      DB        ((%4) & 0xff)            ;P, DPL, S, type
 92      DW        (((%2) >> 16) & 0xffff)    ;offset 31~24
 93  %endmacro
 94 
 95  ;gate attribute
 96  GA_P            EQU        BIT(7)            ;gate present
 97 
 98  GA_CALL32        EQU        0xc | GA_P
 99  GA_INT32        EQU        0xe | GA_P
100  GA_TRAP32        EQU        0xf | GA_P
101 
102  GA_DPL0            EQU        0000_0000b        ;gate privilege level
103  GA_DPL1            EQU        0010_0000b
104  GA_DPL2            EQU        0100_0000b
105  GA_DPL3            EQU        0110_0000b
106 
107  ;===============================================================================
108 
109  ;DEFINE_SELECTOR    name, offset(word), attribute(byte)
110  %macro DEFINE_SELECTOR 3
111      %1 EQU (((%2) & 1111_1000b) | (%3))
112  %endmacro
113 
114  ;selector attribute
115  SA_TI            EQU        BIT(2)
116  SA_GDT            EQU        0
117  SA_LDT            EQU        SA_TI
118 
119  SA_RPL0            EQU        0
120  SA_RPL1            EQU        1
121  SA_RPL2            EQU        2
122  SA_RPL3            EQU        3
123 
124  ;===============================================================================
125 
126  ;Page Directory/Table Entry
127  PG_P    EQU        BIT(0)
128  PG_R    EQU        0
129  PG_W    EQU        BIT(1)
130  PG_S    EQU        0
131  PG_U    EQU        BIT(2)
132  ;not complete
133 
134  ;===============================================================================
135 
136  %undef BIT
137 
138  %endif
刚开始接触保护模式时,被成堆的资料雷住了... 其实后来发现我接触的保护模式并不难,因为我只用了其中一小部分,只要能把参考文档看懂,都是死东西。主要内容按照《自己动手写os》第3章各节的内容练一遍,再准备好汇编黑皮书和Intel的开发者手册,基本上可以过关。

有了保护模式的一些知识,就开始着手写loader:
  1  %include "address.inc"
  2  %include "macro.inc"
  3  %include "x86.inc"
  4 
  5  org 0x100
  6  TOP_OF_STACK    EQU        0x100
  7 
  8  ;===============================================================================
  9  LAB_loader:
 10          mov ax, cs
 11          mov ds, ax
 12          mov es, ax
 13          mov ss, ax
 14          mov sp, TOP_OF_STACK
 15          
 16          RESET_FLOPPY
 17          LOAD_FILE SBASE_elf, OFFSET_elf, kernel_filename
 18          CLOSE_FLOPPY
 19 
 20          call CheckMem
 21          shr eax, 20
 22          call PrintEAX
 23          mov si, msg_RAM
 24          call PrintString
 25 
 26          lgdt [gdtr]
 27 
 28          cli
 29 
 30          in al, 0x92
 31          or al, 0000_0010b
 32          out 0x92, al
 33 
 34          mov eax, cr0
 35          or eax, 1
 36          mov cr0, eax
 37 
 38          jmp dword gsel_flat_code:(BASE_loader + section.SEG_code32.start)
 39 
 40  ;strings
 41  kernel_filename        DB        "KERNEL  BIN", 0
 42  msg_RAM                DB        `MB Memory\n\r`, 0
 43 
 44  ;---------------------------------------------------------------------
 45 
 46  ;subroutine CheckMem
 47  ;none of segment regs will be modified
 48  CheckMem:
 49          push ds
 50          push es
 51 
 52          mov ax, SBASE_mem
 53          mov ds, ax
 54          mov es, ax
 55          xor ebx, ebx
 56          mov edi, mem_info
 57  .info:
 58          mov eax, 0xe820
 59          mov ecx, 20
 60          mov edx, 0x534D4150
 61          int 0x15
 62          jc .fail
 63          add edi, 20
 64          inc dword [num_ards]
 65          test ebx, ebx
 66          jnz .info
 67          jmp .ok
 68  .fail:
 69          mov ax, cs
 70          mov ds, ax
 71          mov si, .msg_fail
 72  .print:
 73          mov al, byte [ds:si]
 74          test al, al
 75          jz $
 76          mov ah, 0x0e
 77          int 0x10
 78          inc si
 79          jmp .print
 80  .ok:
 81          mov ecx, dword [num_ards]
 82          mov si, mem_info
 83  .count:
 84          cmp dword [si + 16], 1
 85          jne .next
 86          mov eax, dword [si]
 87          add eax, dword [si + 8]
 88          cmp eax, dword [mem_size]
 89          jna .next
 90          mov dword [mem_size], eax
 91  .next:
 92          add si, 20
 93          loop .count
 94 
 95          mov eax, dword [mem_size]
 96          pop es
 97          pop ds
 98          ret
 99 
100  ;strings
101  .msg_fail        DB        `memeory check error\n\r`, 0
102 
103  ;---------------------------------------------------------------------
104 
105  ;subroutine PrintEAX
106  ;none of regs will be modified
107  PrintEAX:
108          push eax
109          push ebx
110          push ecx
111          push edx
112 
113          xor ecx, ecx
114  .cal:
115          xor edx, edx
116          mov ebx, 10
117          div ebx
118          push edx
119          inc ecx
120          test eax, eax
121          jnz .cal
122  .print:
123          pop eax
124          add al, '0'
125          call PrintAL
126          loop .print
127 
128          pop edx
129          pop ecx
130          pop ebx
131          pop eax
132          ret
133 
134  ;---------------------------------------------------------------------
135 
136  ;subroutine PrintString
137  ;ds:si should be the address of the string end of 0
138  ;none of regs will be modified
139  PrintString:
140          push si
141          push ax
142  .1:
143          mov al, byte [ds:si]
144          test al, al
145          jz .end
146          call PrintAL
147          inc si
148          jmp .1
149  .end:
150          pop ax
151          pop si
152          ret
153 
154  ;---------------------------------------------------------------------
155 
156  PrintAL:
157      push ax
158      mov ah, 0xe
159      int 0x10
160      pop ax
161      ret
162 
163  ;----------------------------------------------------------------------
164 
165  %include "floppy.asm"
166 
167  ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
168 
169  ;===============================================================================
170  SECTION SEG_gdt align=8
171 
172  gdes_null            des_t        0, 0, 0
173  gdes_flat_code        des_t        0, 0xfffff, DA_CODE32R | DA_4G | DA_DPL0
174  gdes_flat_data        des_t        0, 0xfffff, DA_DATA32W | DA_4G | DA_DPL0
175  gdes_video            des_t        0xb8000, 0xffff, DA_DATA16W | DA_DPL3
176 
177  gdtr            DW        $ - $$ - 1
178                  DD        BASE_loader + $$
179 
180  DEFINE_SELECTOR        gsel_flat_code, gdes_flat_code - $$, SA_GDT | SA_RPL0
181  DEFINE_SELECTOR        gsel_flat_data, gdes_flat_data - $$, SA_GDT | SA_RPL0
182  DEFINE_SELECTOR        gsel_video, gdes_video - $$, SA_GDT | SA_RPL0
183  ;SECTION SEG_gdt^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
184 
185  ;===============================================================================
186  SECTION SEG_code32 align=16
187  BITS 32
188 
189          mov ax, gsel_flat_data
190          mov ds, ax
191          mov es, ax
192          mov fs, ax
193          mov ss, ax
194          mov esp, TOP_stack
195 
196          mov ax, gsel_video
197          mov gs, ax
198 
199          PRINT 10, 3, 'P'
200          
201          call SetupPaging
202 
203          PRINT 10, 4, 'P'
204 
205          call InitKernel
206 
207          PRINT 10, 5, 'P'
208 
209          jmp gsel_flat_code:KERNEL_ENTRY
210 
211  ;---------------------------------------------------------------------
212 
213  ;subroutine SetupPaging
214  SetupPaging:
215 
216          mov ecx, dword [BASE_mem]
217          test ecx, 00000_00000_11111_11111_11111_11111_11b
218          jnz .another_pde
219          shr ecx, 22
220          jmp .init_pd
221  .another_pde:
222          shr ecx, 22
223          inc ecx
224  .init_pd:
225          push ecx
226          mov edi, BASE_page_dir
227          mov eax, BASE_page_table | PG_U | PG_W | PG_P
228  .1:
229          mov dword [edi], eax
230          add edi, 4
231          add eax, 4 * 1024
232          loop .1
233  .init_pt:
234          mov edi, BASE_page_table
235          mov eax, 0 | PG_U | PG_W | PG_P
236          pop ecx
237          shl ecx, 10        ;ecx *= 1024
238  .2:
239          mov dword [edi], eax
240          add edi, 4
241          add eax, 4 * 1024
242          loop .2
243 
244          mov eax, BASE_page_dir
245          mov cr3, eax
246 
247          mov eax, cr0
248          or eax, 1  < < 31
249           mov cr0, eax
250 
251          ret
252 
253  ;---------------------------------------------------------------------
254 
255  ;subroutine InitKernel
256  InitKernel:
257 
258          xor ebx, ebx
259          mov bx, word [BASE_elf + 0x2a]    ;ebx  = size  of one entry in the pht
260          xor edx, edx
261          mov dx, word [BASE_elf + 0x2c]    ;edx  = number  of entries in the pht
262          mov esi, dword [BASE_elf + 0x1c];esi  = offset  of the pht
263          add esi, BASE_elf                ;esi  = address  of the pht
264  .loop_edx:
265          test edx, edx
266          jz .endloop_edx
267          cmp dword [esi], 1
268          jne .2                            ;the seg can be loaded if type  = 1
269           push esi                        ;backup esi
270          mov edi, dword [esi + 0x8]        ;edi  = virtual  address
271          xor ecx, ecx
272          mov cx, word [esi + 0x10]        ;ecx  = size
273           mov esi, dword [esi + 0x4]        ;esi  = offset  of program
274          add esi, BASE_elf                ;esi  = address  of program
275  .loop_ecx:
276          test ecx, ecx
277          jz .endloop_ecx
278          mov al, byte [esi]
279          mov byte [edi], al
280          inc esi
281          inc edi
282          dec ecx
283          jmp .loop_ecx
284  .endloop_ecx:
285          pop esi                ;restore esi
286  .2:
287          add esi, ebx        ;esi + = pht_entry_size
288           dec edx
289          jmp .loop_edx
290  .endloop_edx:
291 
292          ret
293 
294  ;---------------------------------------------------------------------
295 
296  LEN_code32    EQU        $ - $$
297  ;SECTION SEG_code32^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
298 
299  ; ===============================================================================
300  SECTION SEG_stack
301  ALIGN 4
302 
303  TIMES 2048 DB 0        ;2KB
304 
305  TOP_stack    EQU        BASE_loader + $
306  ;SECTION SEG_stack^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
loader中要做下面几件事:
1.将elf格式的kernel.bin调入内存。
2.检查内存情况,启动分页机制。
3.切换到保护模式,转移控制到kernel

对1来说,有了boot的经验,这个应该不成问题。
对2来说,我仅仅实现了算出该PC上内存上限,并无考虑内存存在空洞。
对3来说,识别elf格式的地方曾经出了一些问题,因为我用ubuntu下的ld链接出来的elf格式的kernel.bin比书中的代码要多一个program。后来我仔细阅读了elf格式的文档之后修正了这个bug。这个bug是我进入kernel之前的最后一只拦路虎,突破之后就可以开始用C写一些东西了。

最后贴个图,是我在vmware中用软盘启动后的情况:
自制os开发记(一)——启动部分_第1张图片

你可能感兴趣的:(自制os开发记(一)——启动部分)