我正在编写一个简单的引导程序。它的主要任务是加载内核,并将处理器切换到虚幻模式。我的问题是当我打开虚幻模式时,处理器崩溃了。这是我的代码(一些代码来自MikeOS)。我使用NASM。
BITS 16
jmp short bootloader_start ; Jump past disk description section
nop ; Pad out before disk description
; ------------------------------------------------------------------
; Disk description table, to make it a valid floppy
; Note: some of these values are hard-coded in the source!
; Values are those used by IBM for 1.44 MB, 3.5" diskette
OEMLabel db "16DOSRUN" ; Disk label
BytesPerSector dw 512 ; Bytes per sector
SectorsPerCluster db 1 ; Sectors per cluster
ReservedForBoot dw 1 ; Reserved sectors for boot record
NumberOfFats db 2 ; Number of copies of the FAT
RootDirEntries dw 224 ; Number of entries in root dir
; (224 * 32 = 7168 = 14 sectors to read)
LogicalSectors dw 2880 ; Number of logical sectors
MediumByte db 0F0h ; Medium descriptor byte
SectorsPerFat dw 9 ; Sectors per FAT
SectorsPerTrack dw 18 ; Sectors per track (36/cylinder)
Sides dw 2 ; Number of sides/heads
HiddenSectors dd 0 ; Number of hidden sectors
LargeSectors dd 0 ; Number of LBA sectors
DriveNo dw 0 ; Drive No: 0
Signature db 41 ; Drive signature: 41 for floppy
VolumeID dd 00000000h ; Volume ID: any number
VolumeLabel db "16DOS "; Volume Label: any 11 chars
FileSystem db "FAT12 " ; File system type: don't change!
; ------------------------------------------------------------------
; Main bootloader code
bootloader_start:
xor ax, ax ; make it zero
mov ds, ax ; DS=0
mov ss, ax ; stack starts at seg 0
mov sp, 0x9c00 ; 2000h past code start,
; making the stack 7.5k in size
;***********HERE I TRY TO SWITCH INTO "UNREAL" MODE***********;
cli ; no interrupts
push ds ; save real mode
lgdt [gdtinfo] ; load gdt register
mov eax, cr0 ; switch to pmode by
or al,1 ; set pmode bit
mov cr0, eax
jmp $+2 ; tell 386/486 to not crash
mov bx, 0x08 ; select descriptor 1
mov ds, bx ; 8h = 1000b
and al,0xFE ; back to realmode
mov cr0, eax ; by toggling bit again
pop ds ; get back old segment
sti
;***********END***********;
mov ax, 07C0h ; Set up 4K of stack space above buffer
add ax, 544 ; 8k buffer = 512 paragraphs + 32 paragraphs (loader)
cli ; Disable interrupts while changing stack
mov ss, ax
mov sp, 4096
sti ; Restore interrupts
mov ax, 07C0h ; Set data segment to where we're loaded
mov ds, ax
; NOTE: A few early BIOSes are reported to improperly set DL
cmp dl, 0
je no_change
mov [bootdev], dl ; Save boot device number
mov ah, 8 ; Get drive parameters
int 13h
jc fatal_disk_error
and cx, 3Fh ; Maximum sector number
mov [SectorsPerTrack], cx ; Sector numbers start at 1
movzx dx, dh ; Maximum head number
add dx, 1 ; Head numbers start at 0 - add 1 for total
mov [Sides], dx
no_change:
mov eax, 0 ; Needed for some older BIOSes
; First, we need to load the root directory from the disk. Technical details:
; Start of root = ReservedForBoot + NumberOfFats * SectorsPerFat = logical 19
; Number of root = RootDirEntries * 32 bytes/entry / 512 bytes/sector = 14
; Start of user data = (start of root) + (number of root) = logical 33
floppy_ok: ; Ready to read first block of data
mov ax, 19 ; Root dir starts at logical sector 19
call l2hts
mov si, buffer ; Set ES:BX to point to our buffer (see end of code)
mov bx, ds
mov es, bx
mov bx, si
mov ah, 2 ; Params for int 13h: read floppy sectors
mov al, 14 ; And read 14 of them
pusha ; Prepare to enter loop
read_root_dir:
popa ; In case registers are altered by int 13h
pusha
stc ; A few BIOSes do not set properly on error
int 13h ; Read sectors using BIOS
jnc search_dir ; If read went OK, skip ahead
call reset_floppy ; Otherwise, reset floppy controller and try again
jnc read_root_dir ; Floppy reset OK?
search_dir:
popa
mov ax, ds ; Root dir is now in [buffer]
mov es, ax ; Set DI to this info
mov di, buffer
mov cx, word [RootDirEntries] ; Search all (224) entries
mov ax, 0 ; Searching at offset 0
next_root_entry:
xchg cx, dx ; We use CX in the inner loop...
mov si, kern_filename ; Start searching for kernel filename
mov cx, 11
rep cmpsb
je found_file_to_load ; Pointer DI will be at offset 11
add ax, 32 ; Bump searched entries by 1 (32 bytes per entry)
mov di, buffer ; Point to next entry
add di, ax
xchg dx, cx ; Get the original CX back
loop next_root_entry
mov si, file_not_found ; If kernel is not found, bail out
call print_string
found_file_to_load: ; Fetch cluster and load FAT into RAM
mov ax, word [es:di+0Fh] ; Offset 11 + 15 = 26, contains 1st cluster
mov word [cluster], ax
mov ax, 1 ; Sector 1 = first sector of first FAT
call l2hts
mov di, buffer ; ES:BX points to our buffer
mov bx, di
mov ah, 2 ; int 13h params: read (FAT) sectors
mov al, 9 ; All 9 sectors of 1st FAT
pusha ; Prepare to enter loop
read_fat:
popa ; In case registers are altered by int 13h
pusha
stc
int 13h ; Read sectors using the BIOS
jnc read_fat_ok ; If read went OK, skip ahead
call reset_floppy ; Otherwise, reset floppy controller and try again
jnc read_fat ; Floppy reset OK?
; ******************************************************************
fatal_disk_error:
; ******************************************************************
mov si, disk_error
read_fat_ok:
popa
mov ax, 2000h ; Segment where we'll load the kernel
mov es, ax
mov bx, 0
mov ah, 2 ; int 13h floppy read params
mov al, 1
push ax ; Save in case we (or int calls) lose it
; Now we must load the FAT from the disk. Here's how we find out where it starts:
; FAT cluster 0 = media descriptor = 0F0h
; FAT cluster 1 = filler cluster = 0FFh
; Cluster start = ((cluster number) - 2) * SectorsPerCluster + (start of user)
; = (cluster number) + 31
load_file_sector:
mov ax, word [cluster] ; Convert sector to logical
add ax, 31
call l2hts ; Make appropriate params for int 13h
mov ax, 2000h ; Set buffer past what we've already read
mov es, ax
mov bx, word [pointer]
pop ax ; Save in case we (or int calls) lose it
push ax
stc
int 13h
jnc calculate_next_cluster ; If there's no error...
call reset_floppy ; Otherwise, reset floppy and retry
jmp load_file_sector
; In the FAT, cluster values are stored in 12 bits, so we have to
; do a bit of maths to work out whether we're dealing with a byte
; and 4 bits of the next byte -- or the last 4 bits of one byte
; and then the subsequent byte!
calculate_next_cluster:
mov ax, [cluster]
mov dx, 0
mov bx, 3
mul bx
mov bx, 2
div bx ; DX = [cluster] mod 2
mov si, buffer
add si, ax ; AX = word in FAT for the 12 bit entry
mov ax, word [ds:si]
or dx, dx ; If DX = 0 [cluster] is even; if DX = 1 then it's odd
jz even ; If [cluster] is even, drop last 4 bits of word
; with next cluster; if odd, drop first 4 bits
odd:
shr ax, 4 ; Shift out first 4 bits (they belong to another entry)
jmp short next_cluster_cont
even:
and ax, 0FFFh ; Mask out final 4 bits
next_cluster_cont:
mov word [cluster], ax ; Store cluster
cmp ax, 0FF8h ; FF8h = end of file marker in FAT12
jae end
add word [pointer], 512 ; Increase buffer pointer 1 sector length
jmp load_file_sector
end: ; We've got the file to load!
pop ax ; Clean up the stack (AX was pushed earlier)
mov dl, byte [bootdev] ; Provide kernel with boot device info
jmp 2000h:0000h ; Jump to entry point of loaded kernel!
; ------------------------------------------------------------------
; BOOTLOADER SUBROUTINES
print_string: ; Output string in SI to screen
pusha
mov ah, 0Eh ; int 10h teletype function
.repeat:
lodsb ; Get char from string
cmp al, 0
je .done ; If char is zero, end of string
int 10h ; Otherwise, print it
jmp short .repeat
.done:
popa
ret
reset_floppy: ; IN: [bootdev] = boot device; OUT: carry set on error
push ax
push dx
mov ax, 0
mov dl, byte [bootdev]
stc
int 13h
pop dx
pop ax
ret
l2hts: ; Calculate head, track and sector settings for int 13h
; IN: logical sector in AX, OUT: correct registers for int 13h
push bx
push ax
mov bx, ax ; Save logical sector
mov dx, 0 ; First the sector
div word [SectorsPerTrack]
add dl, 01h ; Physical sectors start at 1
mov cl, dl ; Sectors belong in CL for int 13h
mov ax, bx
mov dx, 0 ; Now calculate the head
div word [SectorsPerTrack]
mov dx, 0
div word [Sides]
mov dh, dl ; Head/side
mov ch, al ; Track
pop ax
pop bx
mov dl, byte [bootdev] ; Set correct device
ret
; ------------------------------------------------------------------
; STRINGS AND VARIABLES
kern_filename db "KERNEL SYS" ; MikeOS kernel filename
disk_error db "Error.", 0
file_not_found db "Error.", 0
bootdev db 0 ; Boot device number
cluster dw 0 ; Cluster of the file we want to load
pointer dw 0 ; Pointer into Buffer, for loading kernel
gdtinfo:
dw gdt_end - gdt - 1 ;last byte in table
dd gdt ;start of table
gdt dd 0,0 ; entry 0 is always unused
flatdesc db 0xff, 0xff, 0, 0, 0, 10010010b, 11001111b, 0
gdt_end:
; ------------------------------------------------------------------
; END OF BOOT SECTOR AND BUFFER START
times 510-($-$$) db 0 ; Pad remainder of boot sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
buffer: ; Disk buffer begins (8k after this, stack starts)
; ==================================================================
那么如何修复这段代码呢?如果切换到"虚幻"在我的情况下模式是不可能的,我怎样才能在实模式下访问整个内存(4GiB会持续)?我在内核代码中打开了A20。 几年后:发现SmallerC支持进入虚幻模式,所以所有的程序集实际上并不需要,我只能用C语言编写。
答案 0 :(得分:3)
MikeOS附带一个引导加载程序,它假设一段0x07c0,偏移量为0x0000(0x07c0:0x0000)。偏移部分也是 NASM 中的原点(ORG
值)。在20-bit segment:offset addressing中:0x07c0的一段和0x0000的偏移量是物理地址0x07c00(0x07c0<< 4 + 0x0000 = 0x07c00),这是引导加载程序应该在内存中的位置。
当您使用MikeOS时,您拼接了某些unreal mode code from OSDev Wiki,假设原点基于段:偏移地址0x0000:0x7c00。这也表示物理地址0x07c00(0x0000 <&lt;&lt; 4 + 0x7c00 = 0x7c00)。在这种情况下, NASM 代码中需要ORG
0x7c00。
使用-f bin
选项与 NASM 组合时(如果未指定输出格式,则为默认选项):如果您未指定{{ 1}}指令默认为ORG
。
您需要使用其中一个,而不是两个。由于大多数MikeOS引导加载程序代码依赖于0x07c0的一段和0x0000的偏移量,因此更容易将代码更改为类似于最初使用的MikeOS引导加载程序。以下代码
ORG 0x0000
可以更改为:
bootloader_start:
xor ax, ax ; make it zero
mov ds, ax ; DS=0
mov ss, ax ; stack starts at seg 0
mov sp, 0x9c00 ; 2000h past code start,
; making the stack 7.5k in size
;***********HERE I TRY TO SWITCH INTO "UNREAL" MODE***********;
cli ; no interrupts
然后,您可以删除设置完虚幻模式后出现的所有重复代码。需要消除这些线:
bootloader_start:
; Modify all segment setup code to assume an ORG of 0x0000
mov ax, 07C0h ; Set data segment to where we're loaded
mov ds, ax
add ax, 544 ; 8k buffer = 512 paragraphs + 32 paragraphs (loader)
cli ; Disable interrupts while changing stack and entering
; protected mode, turn them on after when in unreal mode
mov ss, ax
mov sp, 4096
通常,虚幻模式将所有数据寄存器设置为平面内存模型。您可以设置 DS / ES / FS / GS 寄存器,而不仅仅是将 DS 更新为指向扁平4gb选择器。修改代码:
mov ax, 07C0h ; Set up 4K of stack space above buffer
add ax, 544 ; 8k buffer = 512 paragraphs + 32 paragraphs (loader)
cli ; Disable interrupts while changing stack
mov ss, ax
mov sp, 4096
sti ; Restore interrupts
mov ax, 07C0h ; Set data segment to where we're loaded
mov ds, ax
完成此操作后,需要对mov bx, 0x08 ; select descriptor 1
mov ds, bx ; 8h = 1000b
mov es, bx ; 8h = 1000b
mov fs, bx ; 8h = 1000b
mov gs, bx ; 8h = 1000b
结构进行一次更改。您将其放入引导程序:
gdtinfo
现在的问题是我们正在使用一段0x07c0,而GDT的基数现在相对于0x0000(不是0x7c00)的偏移量。我们加载到GDT register的gdtinfo:
dw gdt_end - gdt - 1 ;last byte in table
dd gdt ;start of table
gdt dd 0,0 ; entry 0 is always unused
flatdesc db 0xff, 0xff, 0, 0, 0, 10010010b, 11001111b, 0
gdt_end:
结构中的基址是线性地址(不是段:偏移地址)。在实模式中,线性地址和物理地址是相同的。要将gdtinfo
转换为线性地址,我们将0x7c00添加到gdt
。我们修改了这一行:
gdt
现在它写着:
dd gdt ;start of table
您文件的修订版可能是:
dd gdt+0x7c00 ;start of table
在赏金中,你这样说:
我希望赏金获胜者向我解释为什么这样的代码是错误的并帮助我修复它(使它工作,通过切换到虚幻模式也称为平实模式并加载名为KERNEL.SYS的内核文件并执行它。内核将使用中断,所以保护模式aint选项。)
保护模式支持软件和硬件中断。我相信你的意思是你的内核将使用BIOS中断。除非您创建VM86任务或切换回实模式,否则在受保护模式下运行时BIOS中断不可用。
可以制作真实/虚幻模式内核,但是由于缺少虚拟内存,内存保护和在保护模式下可用的分页机制,它们会受到限制。
进入虚幻模式需要暂时进入保护模式;使用选择器设置 DS / ES / GS / FS ,该选择器指向具有4gb限制(而不是64k)的16位数据描述符;然后关闭保护模式。在切换到保护模式期间,必须禁用中断,因为没有设置保护模式中断向量。
MikeOS引导加载程序需要将名为KERNEL.SYS的文件放入格式为FAT12的磁盘映像的根目录中。我会假设你知道如何做到这一点。执行此操作的方法在Windows和Linux之间是不同的,并且超出了本答案的范围。一个示例 BITS 16
jmp short bootloader_start ; Jump past disk description section
nop ; Pad out before disk description
; ------------------------------------------------------------------
; Disk description table, to make it a valid floppy
; Note: some of these values are hard-coded in the source!
; Values are those used by IBM for 1.44 MB, 3.5" diskette
OEMLabel db "16DOSRUN" ; Disk label
BytesPerSector dw 512 ; Bytes per sector
SectorsPerCluster db 1 ; Sectors per cluster
ReservedForBoot dw 1 ; Reserved sectors for boot record
NumberOfFats db 2 ; Number of copies of the FAT
RootDirEntries dw 224 ; Number of entries in root dir
; (224 * 32 = 7168 = 14 sectors to read)
LogicalSectors dw 2880 ; Number of logical sectors
MediumByte db 0F0h ; Medium descriptor byte
SectorsPerFat dw 9 ; Sectors per FAT
SectorsPerTrack dw 18 ; Sectors per track (36/cylinder)
Sides dw 2 ; Number of sides/heads
HiddenSectors dd 0 ; Number of hidden sectors
LargeSectors dd 0 ; Number of LBA sectors
DriveNo dw 0 ; Drive No: 0
Signature db 41 ; Drive signature: 41 for floppy
VolumeID dd 00000000h ; Volume ID: any number
VolumeLabel db "16DOS "; Volume Label: any 11 chars
FileSystem db "FAT12 " ; File system type: don't change!
; ------------------------------------------------------------------
; Main bootloader code
bootloader_start:
; Modify all segment setup code to assume an ORG of 0x0000
mov ax, 07C0h ; Set up 4K of stack space above buffer
mov ds, ax ; Set DS segment to where we're loaded
add ax, 544 ; 8k buffer = 512 paragraphs + 32 paragraphs (loader)
cli ; Disable interrupts while changing stack
mov ss, ax
mov sp, 4096
; Enter unreal mode
; Keep interrupts off while we switch to real mode
push ds ; Switch to real mode detroys DS. We need to save it
lgdt [gdtinfo] ; load gdt register
mov eax, cr0 ; switch to pmode by
or al,1 ; set pmode bit
mov cr0, eax
jmp $+2 ; Clear the instruction pre-fetch queue
; Set DS=ES=FS=GS to descriptor with 4gb limit
mov bx, 0x08 ; select descriptor 1
mov ds, bx ; 8h = 1000b
mov es, bx ; 8h = 1000b
mov fs, bx ; 8h = 1000b
mov gs, bx ; 8h = 1000b
and al,0xFE ; back to realmode
mov cr0, eax ; by toggling bit again
sti ; enable interrupts
pop ds ; Retsore DS to original value
;***********END OF UNREAL MODE SWITCH ***********;
; NOTE: A few early BIOSes are reported to improperly set DL
cmp dl, 0
je no_change
mov [bootdev], dl ; Save boot device number
mov ah, 8 ; Get drive parameters
int 13h
jc fatal_disk_error
and cx, 3Fh ; Maximum sector number
mov [SectorsPerTrack], cx ; Sector numbers start at 1
movzx dx, dh ; Maximum head number
add dx, 1 ; Head numbers start at 0 - add 1 for total
mov [Sides], dx
no_change:
mov eax, 0 ; Needed for some older BIOSes
; First, we need to load the root directory from the disk. Technical details:
; Start of root = ReservedForBoot + NumberOfFats * SectorsPerFat = logical 19
; Number of root = RootDirEntries * 32 bytes/entry / 512 bytes/sector = 14
; Start of user data = (start of root) + (number of root) = logical 33
floppy_ok: ; Ready to read first block of data
mov ax, 19 ; Root dir starts at logical sector 19
call l2hts
mov si, buffer ; Set ES:BX to point to our buffer (see end of code)
mov bx, ds
mov es, bx
mov bx, si
mov ah, 2 ; Params for int 13h: read floppy sectors
mov al, 14 ; And read 14 of them
pusha ; Prepare to enter loop
read_root_dir:
popa ; In case registers are altered by int 13h
pusha
stc ; A few BIOSes do not set properly on error
int 13h ; Read sectors using BIOS
jnc search_dir ; If read went OK, skip ahead
call reset_floppy ; Otherwise, reset floppy controller and try again
jnc read_root_dir ; Floppy reset OK?
search_dir:
popa
mov ax, ds ; Root dir is now in [buffer]
mov es, ax ; Set DI to this info
mov di, buffer
mov cx, word [RootDirEntries] ; Search all (224) entries
mov ax, 0 ; Searching at offset 0
next_root_entry:
xchg cx, dx ; We use CX in the inner loop...
mov si, kern_filename ; Start searching for kernel filename
mov cx, 11
rep cmpsb
je found_file_to_load ; Pointer DI will be at offset 11
add ax, 32 ; Bump searched entries by 1 (32 bytes per entry)
mov di, buffer ; Point to next entry
add di, ax
xchg dx, cx ; Get the original CX back
loop next_root_entry
mov si, file_not_found ; If kernel is not found, bail out
call print_string
found_file_to_load: ; Fetch cluster and load FAT into RAM
mov ax, word [es:di+0Fh] ; Offset 11 + 15 = 26, contains 1st cluster
mov word [cluster], ax
mov ax, 1 ; Sector 1 = first sector of first FAT
call l2hts
mov di, buffer ; ES:BX points to our buffer
mov bx, di
mov ah, 2 ; int 13h params: read (FAT) sectors
mov al, 9 ; All 9 sectors of 1st FAT
pusha ; Prepare to enter loop
read_fat:
popa ; In case registers are altered by int 13h
pusha
stc
int 13h ; Read sectors using the BIOS
jnc read_fat_ok ; If read went OK, skip ahead
call reset_floppy ; Otherwise, reset floppy controller and try again
jnc read_fat ; Floppy reset OK?
; ******************************************************************
fatal_disk_error:
; ******************************************************************
mov si, disk_error
read_fat_ok:
popa
mov ax, 2000h ; Segment where we'll load the kernel
mov es, ax
mov bx, 0
mov ah, 2 ; int 13h floppy read params
mov al, 1
push ax ; Save in case we (or int calls) lose it
; Now we must load the FAT from the disk. Here's how we find out where it starts:
; FAT cluster 0 = media descriptor = 0F0h
; FAT cluster 1 = filler cluster = 0FFh
; Cluster start = ((cluster number) - 2) * SectorsPerCluster + (start of user)
; = (cluster number) + 31
load_file_sector:
mov ax, word [cluster] ; Convert sector to logical
add ax, 31
call l2hts ; Make appropriate params for int 13h
mov ax, 2000h ; Set buffer past what we've already read
mov es, ax
mov bx, word [pointer]
pop ax ; Save in case we (or int calls) lose it
push ax
stc
int 13h
jnc calculate_next_cluster ; If there's no error...
call reset_floppy ; Otherwise, reset floppy and retry
jmp load_file_sector
; In the FAT, cluster values are stored in 12 bits, so we have to
; do a bit of maths to work out whether we're dealing with a byte
; and 4 bits of the next byte -- or the last 4 bits of one byte
; and then the subsequent byte!
calculate_next_cluster:
mov ax, [cluster]
mov dx, 0
mov bx, 3
mul bx
mov bx, 2
div bx ; DX = [cluster] mod 2
mov si, buffer
add si, ax ; AX = word in FAT for the 12 bit entry
mov ax, word [ds:si]
or dx, dx ; If DX = 0 [cluster] is even; if DX = 1 then it's odd
jz even ; If [cluster] is even, drop last 4 bits of word
; with next cluster; if odd, drop first 4 bits
odd:
shr ax, 4 ; Shift out first 4 bits (they belong to another entry)
jmp short next_cluster_cont
even:
and ax, 0FFFh ; Mask out final 4 bits
next_cluster_cont:
mov word [cluster], ax ; Store cluster
cmp ax, 0FF8h ; FF8h = end of file marker in FAT12
jae end
add word [pointer], 512 ; Increase buffer pointer 1 sector length
jmp load_file_sector
end: ; We've got the file to load!
pop ax ; Clean up the stack (AX was pushed earlier)
mov dl, byte [bootdev] ; Provide kernel with boot device info
jmp 2000h:0000h ; Jump to entry point of loaded kernel!
; ------------------------------------------------------------------
; BOOTLOADER SUBROUTINES
print_string: ; Output string in SI to screen
pusha
mov ah, 0Eh ; int 10h teletype function
.repeat:
lodsb ; Get char from string
cmp al, 0
je .done ; If char is zero, end of string
int 10h ; Otherwise, print it
jmp short .repeat
.done:
popa
ret
reset_floppy: ; IN: [bootdev] = boot device; OUT: carry set on error
push ax
push dx
mov ax, 0
mov dl, byte [bootdev]
stc
int 13h
pop dx
pop ax
ret
l2hts: ; Calculate head, track and sector settings for int 13h
; IN: logical sector in AX, OUT: correct registers for int 13h
push bx
push ax
mov bx, ax ; Save logical sector
mov dx, 0 ; First the sector
div word [SectorsPerTrack]
add dl, 01h ; Physical sectors start at 1
mov cl, dl ; Sectors belong in CL for int 13h
mov ax, bx
mov dx, 0 ; Now calculate the head
div word [SectorsPerTrack]
mov dx, 0
div word [Sides]
mov dh, dl ; Head/side
mov ch, al ; Track
pop ax
pop bx
mov dl, byte [bootdev] ; Set correct device
ret
; ------------------------------------------------------------------
; STRINGS AND VARIABLES
kern_filename db "KERNEL SYS" ; MikeOS kernel filename
disk_error db "Error.", 0
file_not_found db "Error.", 0
bootdev db 0 ; Boot device number
cluster dw 0 ; Cluster of the file we want to load
pointer dw 0 ; Pointer into Buffer, for loading kernel
gdtinfo:
dw gdt_end - gdt - 1 ;last byte in table
dd gdt+0x7c00 ;start of table
gdt dd 0,0 ; entry 0 is always unused
flatdesc db 0xff, 0xff, 0, 0, 0, 10010010b, 11001111b, 0
gdt_end:
; ------------------------------------------------------------------
; END OF BOOT SECTOR AND BUFFER START
times 510-($-$$) db 0 ; Pad remainder of boot sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
buffer: ; Disk buffer begins (8k after this, stack starts)
; ==================================================================
,用于测试是否启用了虚幻模式并且工作如下:
kernel.asm
可以使用以下内容汇总到bits 16
; MikeOS bootloader loads our code at 0x2000:0x0000 so we need org of 0x0000
; for the kernel code to work properly.
org 0x0000
kernel_start:
; Set DS, ES, FS, GS to 0x0000. In Unreal mode these segment registers
; are not limited to 64kb. We can address full 4gb of memory
xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; This code will not work in normal real mode. We emit instructions
; that use 0xb8000 as an offset. This offset is >= 65536 and normally
; isn't addressable directly in real mode. This should display MDP white
; on purple to upper left of screen. 0xb8000 is pointer to first cell
; of the text mode video display
;
; In Real AND Unreal mode on a 386 you are allowed to use 32-bit registers
; and memory operands. Real mode is limited to an offset that computes
; to a value below 64kb (65536) unlike unreal mode with a 4gb limit
mov edi, 0xb8000
mov word [edi], 0x57<<8 | 'M';
mov word [edi+2], 0x57<<8 | 'D';
mov word [edi+4], 0x57<<8 | 'P';
cli
.endloop:
hlt
jmp .endloop
KERNEL.SYS
当生成具有此引导加载程序和KERNEL.SYS文件的磁盘映像并在QEMU中运行(Bochs将类似)时,输出将类似于:
如果处理器未处于虚幻模式,则不会出现写在左上角的字符,或者硬件/仿真器可能会达到某种其他类型的未定义状态。