在这个引导程序中,我试图为内核代码和用户代码设置单独的全局描述符表条目(尽管有一些简化,请参阅注释)。创建不相交的段会导致三重错误,即使这些段具有相同的权限级别(环0)。
以下代码按预期运行。它定义了单个代码段和单个数据段,因此不提供保护。源文件的1024个字节被写入虚拟软盘,因此"软盘"这是"这个文件的同义词"。
;***BEGIN SECTOR 1 OF FLOPPY***
BITS 16
ORG 0x7C00 ; standard bootloader location
main:
CLI
XOR AX, AX ; zero the segments (relative to ORG)
MOV DS, AX
MOV ES, AX
MOV AX, 0x9000 ; stack begins at 0x9000-0xFFFF
MOV SS, AX
MOV SP, 0xFFFF
STI
; Load the second sector of this floppy into memory at 0x07C0:0x0200 (deliberately lacks error checking)
MOV AH, 0x02 ; BIOS INT 0x13 "read sector" function
MOV AL, 1 ; Number of sectors to read
MOV CH, 0 ; Cylinder/track
MOV CL, 2 ; Sector of floppy to read
MOV DH, 0 ; Head
MOV DL, 0 ; Disk number (here, the floppy disk) (unnecessary since DL defaults to boot disk)
MOV BX, 0x07C0 ; Segment containing the destination buffer (i.e. the current segment)
MOV ES, BX
MOV BX, 0x0200 ; Destination buffer offset
INT 0x13
CALL installGdt ; Create the global descriptor table and load its pointer into GDTR
CLI
MOV EAX, CR0
OR EAX, 1
MOV CR0, EAX
JMP 0x08:protected_mode
; Offset 0 in GDT: Descriptor code=0x00
gdt_data:
DD 0 ; null descriptor
DD 0
; Offset 8 bytes from start of GDT: descriptor code 0x08
; kernel code:
DW 0xFFFF ; bits 0-15 (segment limit)
DW 0x0000 ; bits 16-31 (low 2 bytes of base address)
DB 0x00 ; bits 32-39 (middle byte of base address)
DB 10011010B ; bits 40-47 ("segment in memory" bit, privilege bits, descriptor bit, descriptor type, virtual memory access bit)
DB 01000000B ; bits 48-55 (granularity, segment type, bits 16-19 of segment limit)
DB 0x00 ; bits 56-63 (high byte of base address)
; Offset 16 bytes from start of GDT: descriptor code 0x10
; kernel data:
DW 0xFFFF ; bits 0-15 (segment limit)
DW 0x0000 ; bits 16-31 (low 2 bytes of base address)
DB 0x00 ; bits 32-39 (middle byte of base address)
DB 10010010B ; bits 40-47 ("segment in memory" bit, privilege bits, descriptor bit, descriptor type, virtual memory access bit)
DB 01000000B ; bits 48-55 (granularity, segment type, bits 16-19 of segment limit)
DB 0x00 ; bits 56-63 (high byte of base address)
end_of_gdt:
gdt_description:
DW end_of_gdt - gdt_data - 1 ; size of GDT minus 1 (for GDTR)
DD gdt_data ; base of GDT
installGdt:
CLI
PUSHA
LGDT [gdt_description]
STI
POPA
RET
times 510-($-$$) DB 0 ; pad rest of sector
DW 0xAA55 ; add bootloader signature
;***END SECTOR 1 OF FLOPPY***
;***BEGIN SECTOR 2 OF FLOPPY***
BITS 32
protected_mode:
MOV AX, 0x10 ; set data segments to kernel data
MOV DS, AX
MOV SS, AX
MOV ES, AX
MOV ESP, 0x90000 ; stack begins from 0x90000
MOV EAX, 5 ; a test to use in qemu register dump, to see if code reached this point
JMP $
times 1024-($-$$) DB 0 ; pad rest of sector
;***END SECTOR 2 OF FLOPPY***
另一方面,当更改为以下时,会导致三重故障。请注意,我希望第二个扇区在0x07C0:0x0200加载到内存中,所以我将内核段的限制设置为0x01FF,而用户段从0x0200开始。
;***BEGIN SECTOR 1 OF FLOPPY***
BITS 16
ORG 0x7C00 ; standard bootloader location
main:
CLI
XOR AX, AX ; zero the segments (relative to ORG)
MOV DS, AX
MOV ES, AX
MOV AX, 0x9000 ; stack begins at 0x9000-0xFFFF
MOV SS, AX
MOV SP, 0xFFFF
STI
; Load the second sector of this floppy into memory at 0x07C0:0x0200 (deliberately lacks error checking)
MOV AH, 0x02 ; BIOS INT 0x13 "read sector" function
MOV AL, 1 ; Number of sectors to read
MOV CH, 0 ; Cylinder/track
MOV CL, 2 ; Sector of floppy to read
MOV DH, 0 ; Head
MOV DL, 0 ; Disk number (here, the floppy disk) (unnecessary since DL defaults to boot disk)
MOV BX, 0x07C0 ; Segment containing the destination buffer (i.e. the current segment)
MOV ES, BX
MOV BX, 0x0200 ; Destination buffer offset
INT 0x13
CALL installGdt ; Create the global descriptor table in RAM
CLI
MOV EAX, CR0
OR EAX, 1
MOV CR0, EAX
JMP 0x18:protected_mode
; Offset 0 in GDT: Descriptor code=0x00
gdt_data:
DD 0 ; null descriptor
DD 0
; Offset 8 bytes from start of GDT: descriptor code 0x08
; kernel code:
DW 0x01FF ; bits 0-15 (segment limit)
DW 0x0000 ; bits 16-31 (low 2 bytes of base address)
DB 0x00 ; bits 32-39 (middle byte of base address)
DB 10011010B ; bits 40-47 ("segment in memory" bit, privilege bits, descriptor bit, descriptor type, virtual memory access bit)
DB 01000000B ; bits 48-55 (granularity, segment type, bits 16-19 of segment limit)
DB 0x00 ; bits 56-63 (high byte of base address)
; Offset 16 bytes from start of GDT: descriptor code 0x10
; kernel data:
DW 0x01FF ; bits 0-15 (segment limit)
DW 0x0000 ; bits 16-31 (low 2 bytes of base address)
DB 0x00 ; bits 32-39 (middle byte of base address)
DB 10010010B ; bits 40-47 ("segment in memory" bit, privilege bits, descriptor bit, descriptor type, virtual memory access bit)
DB 01000000B ; bits 48-55 (granularity, segment type, bits 16-19 of segment limit)
DB 0x00 ; bits 56-63 (high byte of base address)
; Descriptor code 0x18
; user code: ; (see immediately above for descriptions of bit fields)
DW 0xFFFF ; bits 0-15
DW 0x0200 ; bits 16-31
DB 0x00 ; bits 32-39
DB 10011010B ; bits 40-47 (privilege set to ring 0 for simplicity)
DB 01000000B ; bits 48-55
DB 0x00 ; bits 56-63
; Descriptor code 0x20
; user data: ; (see immediately above for descriptions of bit fields)
DW 0xFFFF ; bits 0-15
DW 0x0200 ; bits 16-31
DB 0x00 ; bits 32-39
DB 10010010B ; bits 40-47 (privilege set to ring 0 for simplicity)
DB 01000000B ; bits 48-55
DB 0x00 ; bits 56-63
end_of_gdt:
gdt_description:
DW end_of_gdt - gdt_data - 1 ; size of GDT minus 1 (for GDTR)
DD gdt_data ; base of GDT
installGdt:
CLI
PUSHA
LGDT [gdt_description]
STI
POPA
RET
times 510-($-$$) DB 0 ; pad rest of sector
DW 0xAA55 ; add bootloader signature
;***END SECTOR 1 OF FLOPPY***
;***BEGIN SECTOR 2 OF FLOPPY***
BITS 32
protected_mode:
MOV AX, 0x20 ; set data segments to user data
MOV DS, AX
MOV SS, AX
MOV ES, AX
MOV ESP, 0x90000 ; stack begins from 0x90000
MOV EAX, 5 ; a test to use in qemu register dump, to see if code reached this point
JMP $
times 1024-($-$$) DB 0 ; pad rest of sector
;***END SECTOR 2 OF FLOPPY***