在保护模式下打印字符到屏幕的汇编代码

4
我正在尝试进入保护模式并打印出“Hi”。 但是实际上,它只是从我的bios中断调用中打印出“Loading OS”(这发生在进入pmode之前),然后什么也没有发生。 我的Bootloader.asm文件:
%DEFINE KERNEL_LOAD_OFFSET 0x1000

org 0x7c00

bits 16

xor ax, ax
mov ds, ax

start: jmp main

Print:
 .print:
  lodsb
  or al, al
  je .done

  mov ah, 0x0E
  int 0x10

  .repeat:
   jmp .print

 .done:
  ret

ResetFloppy:
 mov ah, 0x0

 int 0x13
 jc ErrorFloppy
 .done:
  ret

ReadFloppy:

 mov ah, 0x02
 int 0x13

 jc ErrorFloppy

 .done:
  ret

ErrorFloppy:

 mov si, msgErrorFloppy
 call Print

 jmp hang


main: 
 .print:

  mov si, msg
  call Print

 .loadFile:
  mov al, 0xF
  mov ch, 0x0
  mov cl, 0x02
  mov dh, 0x0
  mov dl, 0x0
  mov bx, KERNEL_LOAD_OFFSET

  call ResetFloppy
  call ReadFloppy


 .loadGDT:
   lgdt [gdtr]
 .pM_start:
  cli
  pusha

  mov eax, cr0
  or al, 1
  mov cr0, eax

  popa

  jmp 0x08:ljmp_pM


 bits 32
 ljmp_pM: 
  mov ax, 0x10
  mov ds, ax
  mov ss, ax
  mov fs, ax
  mov es, ax
  mov gs, ax

  jmp KERNEL_LOAD_OFFSET

hang:
 jmp $

gdt:
NULL_DESC:
    dd 0            ; null descriptor
    dd 0

CODE_DESC:
    dw 0xFFFF       ; limit low
    dw 0            ; base low
    db 0            ; base middle
    db 10011010b    ; access
    db 11001111b    ; granularity
    db 0            ; base high

DATA_DESC:
    dw 0xFFFF       ; data descriptor
    dw 0            ; limit low
    db 0            ; base low
    db 10010010b    ; access
    db 11001111b    ; granularity
    db 0            ; base high

gdtr:
    Limit dw 24         ; length of GDT
    Base dd NULL_DESC   ; base of GDT

msg db "Loading OS", 13, 10, 0
msgErrorFloppy db "There was an error with the floppy", 13, 10, 0

FILL:
 times 510-($-$$) db 0

BOOTSECTOR:
 dw 0xAA55

Kernel.asm

bits 32

mov dword [0xB8000], 0x07690748

jmp $

编译.bat文件

nasm -f bin Dev/BootLoader.asm -o Bin/BootLoader.bin
nasm -f bin Dev/Kernel.asm -o Bin/Kernel.bin

dd if=Bin/BootLoader.bin of=Image/Image.img seek=0
dd if=Bin/Kernel.bin of=Image/Image.img seek=1 conv=notrunc

pause

我使用Bochs,但是我只得到了这个:http://prntscr.com/d24wmm

9
哦,"Hi" 就在左上角那里呀? - Jester
哦,我的天啊,我真是太愚蠢了:D 谢谢 :D 将此作为答案发布。 - Jiří Velek
1个回答

2

在32位保护模式下,由于BIOS是使用16位实模式的代码编写的,因此无法使用BIOS。所以,您需要像这样访问视频内存:

    mov ebx,0xb8000    ; The video address
    mov al,'!'         ; The character to be print
    mov ah,0x0F        ; The color: white(F) on black(0)
    mov [ebx],ax        ; Put the character into the video memory

然后您可能会在屏幕开头看到一个!。如果您想要在光标位置打印,请按如下方式获取光标偏移量:

    mov dx,0x3D4       ; Tell the control I/O port to get the lower byte of
    mov al,0x0F        ; the cursor offset
    out dx,al
    mov dx,0x3D5       ; Switch to data I/O port
    in  al,dx          ; Get the cursor offset's lower byte

    mov dx,0x3D5       ; Tell the control I/O port to get the higher byte of
    mov al,0x0E        ; the cursor offset
    out dx,al
    mov dx,0x3D5       ; Switch to data I/O port
    in  al,dx          ; Get the higher byte

    imul ax,2           ; Because a character in video memory costs 2 bytes
                       ; (i.e character and attribute), we need to twice the cursor offset

在32位保护模式下,为提高代码效率,你可以使用一些高级语言(如C语言)来创建函数。这真正提高了代码的可读性。

你的第一个代码块没有存储到内存。我认为你忘记了 mov [ebx], ax,因为你假设分页已禁用或为直接映射。另外,你可以这样写:mov word [0xb8000], (0x0F << 8) | '!' - Peter Cordes
另外,“mul ax,2”不是x86指令。 “imul ax,2”是有效的,但使用它来乘以一个愚蠢的幂是不明智的。使用“shl ax,1”。别忘了在写入“al”和移位之前将“eax”清零。 - Peter Cordes
使用shl ax,1。这里没有理由使用imul来进行2的幂运算。 - Peter Cordes
@PeterCordes 我认为移位可能会有一些错误。作为程序员,你应该知道第一个比特确定了符号,所以最好不要使用shl。 - TravorLZH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接