【问题标题】:Printing characters to screen ASM in protected mode在保护模式下将字符打印到屏幕 ASM
【发布时间】:2023-03-24 05:06:01
【问题描述】:

我正在尝试进入保护模式,然后打印出“Hi”

但它只是从我的 bios 中断调用(在进入 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 $

还有Compile.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

我使用博克斯。我得到的只是:http://prntscr.com/d24wmm

【问题讨论】:

  • 嗯,Hi 就在左上角吗?
  • 哦,天哪,我真的很愚蠢 :D 谢谢 :D 将此作为答案发布

标签: assembly x86 nasm vga bochs


【解决方案1】:

在 32 位保护模式下,您无法使用 BIOS,因为它是用 16 位实模式代码编写的。因此,您必须像这样访问视频内存:

    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) | '!'
  • 另外,mul ax, 2 不是 x86 指令。 imul ax, 2 是有效的,但是用它来乘以愚蠢的力量。使用shl ax, 1。并且不要忘记在写al 和转移之前将eax 归零。
  • 使用shl ax, 1。这里没有理由使用 imul 来表示 2 的幂。
  • @PeterCordes 我相信 shift 可能会有一些错误。作为程序员,你应该知道第一位决定了符号,所以不使用 shl 会更安全。
猜你喜欢
  • 2020-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-04
  • 1970-01-01
相关资源
最近更新 更多