启用保护模式时屏幕闪烁

时间:2019-06-21 10:39:48

标签: assembly kernel nasm protected-mode

我正在为学校项目编写一个小型演示内核,并在我的内核中启用A20线,加载GDT,然后启用保护模式。当我注释掉保护模式部分时,一切正常,启用A20线并加载GDT,但是当我尝试跳转到保护模式时,屏幕(QEMU)开始闪烁。如果我将jmp注释掉,一切正常。 这是代码:

[bits 16]               ;16-bit binary format

;KERNEL
os_main:
    mov ax, cs      ;CS is segment where we were loaded
    cli
    mov ss, ax
    xor sp, sp
    sti
    cld
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov si, hello   ;print welcome
    call print
    call A20_line
    call load_gdt
    call set_mode
    cli
    hlt
    ;jmp 08h:ENTER_PROTECTED_MODE

;SUBROUTINES
A20_line:
    in al, 0xee
    mov si, A20_enable_str
    call print
    ret
load_gdt:
    cli
    lgdt [toc]
    sti
    mov si, load_gdt_str
    call print
    ret
set_mode:
    mov si, set_mode_str
    call print
    cli
    mov eax, cr0
    or al, 1
    mov cr0, eax
    ret
print:
    mov ah, 0x0e
.next:
    lodsb
    cmp al,0
    je .done
    int 0x10
    jmp .next
.done:
    ret

;DATA
hello db 'Hello',13,10,0
A20_enable_str db 'A20 Line enabled',13,10,0
load_gdt_str db 'Loading GDT',13,10,0
set_mode_str db 'Entering Protected Mode',13,10,0

;GLOBAL DESCRIPTOR TABLE
gdt_data:
    dd 0    ;null descriptor
    dd 0
    dw 0FFFFh    ;code descriptor
    dw 0
    dw 0
    db 10011010b
    db 11001111b
    db 0
    dw 0FFFFh    ;data descriptor
    dw 0
    dw 0
    db 10011010b
    db 11001111b
    db 0
end_of_gdt:
toc:
    dw end_of_gdt - gdt_data - 1
    dd gdt_data

;PROTECTED MODE
[bits 32]
ENTER_PROTECTED_MODE:
    ;VIDMEM equ 0xB8000
    ;mov ax, 0x10
    ;mov es, ax
    ;mov ds, ax
    ;mov fs, ax
    ;mov gs, ax
    ;mov esp, cs
    ;mov eax, 0x0f54
    ;mov [VIDMEM], eax
    cli
    hlt

我注释掉了视频记忆和在保护模式下打印的部分,因为从jmp到保护模式似乎无法正常工作。

这是装载机:

%define BUFFER_OFF 0x8000
%define BUFFER_SEG 0x0000
%define LOAD_SEG 0x0000
%define LOAD_OFF 0x8000

[bits 16]
[org 0x7c00]

jmp short start
nop

;DISK DESCRIPTION(BIOS PARAMETER BLOCK)
OEMLabel        db "BOOT    "
BytesPerSector      dw 512
SectorsPerCluster   db 1
ReservedForBoot     dw 1
NumberOfFats        db 2
RootDirEntries      dw 224     ; Number of entries in root dir
                               ; (224 * 32 = 7168 = 14 sectors to read)
LogicalSectors      dw 2880
MediumByte      db 0F0h
SectorsPerFat       dw 9
SectorsPerTrack     dw 18      ; Sectors per track (36/cylinder)
Sides           dw 2
HiddenSectors       dd 0
LargeSectors        dd 0
DriveNo         dw 0
Signature       db 0x29
VolumeID        dd 00000000h
VolumeLabel     db "myOS       "
FileSystem      db "FAT12   "

;BOOTLOADER
start:
    xor ax, ax
    mov ds, ax
    cli
    mov ss, ax
    mov sp, 0x7c00
    sti
    cld
    mov [drive], dl

    mov si, BUFFER_SEG         ; ES=buffer segment. Only has to be set once
    mov es, si
    mov bx, BUFFER_OFF

load_root:
    mov ax, 19                 ; Root directory starts at LBA 19
    call lba_to_hts
    mov ax, (2<<8) | 14        ; Root directory for this media fits in 14 sectors
                               ; Combine 2 moves (AH/AL) into one
                               ; same as 'mov ah, 2' and 'mov al, 14'
    int 13h
    jc reset
    mov si, load_root_str
    call print

search_file:
    mov di, BUFFER_OFF
    mov cx, word [RootDirEntries]
    xor ax, ax
.loop_search:
    xchg cx, dx
    mov si, filename
    mov cx, 11
    rep cmpsb
    je file_found
    add ax, 32
    mov di, BUFFER_OFF
    add di, ax
    xchg dx, cx
    loop .loop_search
    jmp file_not_found

file_found:
    mov ax, word [di+15]       ; Buffer and Bootloader now in same segment DS
                               ; Don't need ES:
    mov [cluster], ax
    mov ax, 1
    call lba_to_hts
    mov bx, BUFFER_OFF
    mov ax, (2<<8) | 9         ; Combine 2 moves (AH/AL) into one
                               ; same as 'mov ah, 2' and 'mov al, 9'    

load_FAT:
    mov si, FAT_str
    call print
    int 13h
    jnc load_file
    call reset
    jnc load_FAT
    jmp disk_error

load_file:
    mov si, load_file_str
    call print
    mov ax, LOAD_SEG           ; ES=load segment for kernel
    mov es, ax

load_sector:
    mov ax, word [cluster]     ; Get cluster number to read
    add ax, 33-2               ; Add 31 to cluster since FAT data area
                               ; starts at Logical Block Address (LBA) 33
                               ; and we need to subtract 2 since valid
                               ; cluster numbers start at 2
    call lba_to_hts
    xor bx, bx                 ; Always read a kernel sector to offset 0

    mov ax, (2<<8) | 1         ; AH=2 is read, AL=1 read 1 sector
                               ; Combine 2 moves (AH/AL) into one
                               ; same as 'mov ah, 2' and 'mov al, 1'
    int 13h
    jnc next_cluster
    call reset
    jmp load_sector

next_cluster:
    mov bx, [cluster]          ; BX = current cluster number
    mov ax, bx                 ; AX = copy of cluster number
    shl bx, 1                  ; BX = BX * 2
    add bx, ax                 ; BX = BX + AX (BX now contains BX * 3)
    shr bx, 1                  ; Divide BX by 2
    mov ax, [bx+BUFFER_OFF]    ; Get cluster entry from FAT table
    jnc .even                  ; If carry not set by SHR then result was even
.odd:
    shr ax, 4                  ; If cluster entry is odd then cluster number is AX >> 4
    jmp short finish_load
.even:
    and ah, 0Fh                ; If cluster entry is even then cluster number is AX & 0fffh
                               ; We just need to and AH with 0fh to achieve the same result
finish_load:
    mov word [cluster], ax
    cmp ax, 0FF8h
    jae .jump_to_file
    mov ax, es
    add ax, 32                 ; Increasing segment by 1 advances 16 bytes (paragraph)
                               ; in memory. Adding 32 is same advancing 512 bytes (32*16)
    mov es, ax                 ; Advance ES to point at next 512 byte block to read into
    jmp load_sector            ; Go back and load the next sector
.jump_to_file:
    mov dl, byte [drive]
    jmp LOAD_SEG:LOAD_OFF

;SUBROUTINES
file_not_found:
    mov si, not_found_str
    call print
    jmp reboot
print:
    pusha
    mov ah, 0x0E
.next:
    lodsb
    cmp al,0
    je .done
    int 0x10
    jmp .next
.done:
    popa
    ret
lba_to_hts:
    div byte [SectorsPerTrack] ; 16-bit by 8-bit DIV : LBA / SPT
    mov cl, ah                 ; CL = S = LBA mod SPT
    inc cl                     ; CL = S = (LBA mod SPT) + 1
    xor ah, ah                 ; Upper 8-bit of 16-bit value set to 0 for DIV
    div byte [Sides]           ; 16-bit by 8-bit DIV : (LBA / SPT) / HEADS
    mov ch, al                 ; CH = C = (LBA / SPT) / HEADS
    mov dh, ah                 ; DH = H = (LBA / SPT) mod HEADS
    mov dl, [drive]            ; boot device, not necessary to set but convenient
    ret
reset:
    mov ah, 0
    int 13h                    ;reset disk
    jc disk_error              ;if failed jump to search fail
    ret
disk_error:
    mov si, disk_error_str
    call print
reboot:
    mov si, reboot_pmpt
    call print
    mov ax, 0
    int 16h
    mov ax, 0
    int 19h

;DATA
load_root_str db 'Loading Root',13,10,0
disk_error_str db 'Disk Error!',13,10,0
reboot_pmpt db 'PRESS A KEY TO REBOOT',13,10,0
not_found_str db 'KERNEL NOT FOUND',13,10,0
FAT_str db 'Loading FAT',13,10,0
load_file_str db 'Loading KERNEL',13,10,0
drive dw 0
cluster dw 0
filename db 'KERNEL  BIN',0
;PADDING AND SIGNATURE
times (510-($-$$)) db 0x00
dw 0AA55h

LOAD_SEG和LOAD_OFF设置为0x0000和0x8000,尽管相对于原始内核(检查注释)应该设置为0x1000和0x0000。

内部版本:(MacOS)

#! bin/bash
cd image
hdiutil create -fs MS-DOS -sectors 2880 floppy
cd ../system
nasm -f bin bootloader.asm -o boot.bin
nasm -f bin kernel.asm -o kernel.bin
cd ..
dd conv=notrunc if=system/boot.bin of=image/floppy.dmg
dev=`hdid -nomount image/floppy.dmg`
sudo mkdir tmp-loop
sudo mount -t msdos ${dev} tmp-loop
sudo cp system/kernel.bin tmp-loop/
diskutil umount tmp-loop
hdiutil detach ${dev}
sudo rm -rf tmp-loop
hdiutil convert image/floppy.dmg -format UDTO -o image/image.iso

0 个答案:

没有答案