assembly - 切换到 32 位保护模式导致 QEMU 循环重启

标签 assembly x86 qemu

boot.asm:

[org 0x7c00]
[BITS 16]
boot:
    mov bp, 0x9000 ; set the stack
    mov sp, bp

    mov bx, MSG_REAL_MODE
    call print_string

    call switch_to_pm

    jmp $

%include "print/print.asm"
%include "gdt.asm"
%include "print_32.asm"
%include "switch_to_pm.asm"

[BITS 32]

; We're in 32-bit Protected Mode
BEGIN_PM:
    mov ebx, MSG_PROT_MODE
    call print_string_pm

    jmp $

MSG_REAL_MODE:
    db "Started in 16-bit Real Mode", 0

MSG_PROT_MODE:
    db "Sucessfully landed in 32-bit Protected Mode", 0

; Bootsector padding
times 510-($-$$) db 0
dw 0xAA55

gdt.asm:

[BITS 16]
align 4

gdtr:
    dw gdt_end-gdt_start-1
    dd gdt_start
; GDT
gdt_start:
    dd 0x0 ; 'dd' means define double word (4 bytes)
    dd 0x0

gdt_code: ; the code segment descriptor
    ; base=0x0, limit=0 xfffff,
    ; 1st flags: (present)1 (privilege)00 (descriptor type)1 -> 1001b
    ; type flags: (code)1 (conforming)0 (readable)1 (accessed)0 -> 1010b
    ; 2nd flags: (granularity)1 (32 - bit default)1 (64 - bit seg)0 (AVL)0 -> 1100b
    dw 0xffff ; Limit (bits 0-15)
    dw 0x0 ; base (bits 0-15)
    db 0x0 ; base (bits 16-23)
    db 0x9A ; 1st flags, type flags
    db 11001111b ; 2nd flags, linit (bits 16-19)
    db 0x0 ; base (bits 24-31)

gdt_data: ; the data segment descriptor
    ; same as code segment execpt for the type flags:
    ; type flags: (code)0 (expand down)0 (writable)1 (accessed)0 = 0010b
    dw 0xffff ; Limit (bits 0-15)
    dw 0x0 ; base (bits 0-15)
    db 0x0 ; base (bits 16-23)
    db 0x92 ; 1st flags, type flags
    db 11001111b ; 2nd flags, linit (bits 16-19)
    db 0x0 ; base (bits 24-31)

gdt_end: ; the reason for putting a label at the end of the
         ; GDT is so we can have the assembly calculate
         ; the size of the GDT for the GDT descriptor (below)

; GDT descriptor
gdt_descriptor:
    dw gdt_end - gdt_start - 1 ; size of the GDT, always less one
                               ; of the true size

    dd gdt_start ; start address of the GDT

    ; define some handy constants for the GDT segment descriptor offsets, which
    ; are what segment registers must contain when in protected mode
    ; (0x0 = NULL; 0x08 = CODE; 0x10 = DATA)
    CODE_SEG equ gdt_code - gdt_start
    DATA_SEG equ gdt_data - gdt_start

print_32.asm:

[BITS 32]
; Define some constants
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f

; prints a null-terminated string pointed to by edx
print_string_pm:
    pusha
    mov ah, WHITE_ON_BLACK ; Set edx to the start of video memory

print_string_pm_loop:
    mov al, [ebx] ; store the char at ebx in al
    mov al, WHITE_ON_BLACK ; store the attributes in ah

    cmp al, 0 ; if (al == 0), at end of string, so
    je print_string_pm_done; jump to print_string_pm_done

    mov [edx], ax ; store char and attributes at current character cell

    add ebx, 1 ; increment ebx to the next char in the string
    add edx, 2 ; move to next character cell in video memory

    jmp print_string_pm_loop

print_string_pm_done:
    popa
    ret ; return from the function

据我所知,导致 QEMU 在循环中重新启动的唯一原因是三重故障,但我不知道这是从哪里来的。

我尝试使用 -d int 记录 QEMU 中断,但我不知道它意味着什么。这是输出日志文件:

SMM: enter
EAX=00000001 EBX=0000000b ECX=02000000 EDX=02000628
ESI=00000000 EDI=02000000 EBP=07fa84c0 ESP=00006c80
EIP=000ebad0 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00cf9b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000f6070 00000037
IDT=     000f60ae 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00007113 CCD=00000001 CCO=LOGICB  
EFER=0000000000000000
SMM: after RSM
EAX=00000001 EBX=0000000b ECX=02000000 EDX=02000628
ESI=00000000 EDI=02000000 EBP=07fa84c0 ESP=00006c80
EIP=000ebad0 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000f6070 00000037
IDT=     000f60ae 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000000 CCD=00000000 CCO=EFLAGS  
EFER=0000000000000000
SMM: enter
EAX=000000b5 EBX=000f7cd9 ECX=00001234 EDX=0000db80
ESI=07fbdb3b EDI=00006c40 EBP=00006c00 ESP=00006c00
EIP=00007cd8 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =db80 000db800 ffffffff 008f9300
CS =f000 000f0000 ffffffff 008f9b00
SS =0000 00000000 ffffffff 008f9300
DS =0000 00000000 ffffffff 008f9300
FS =0000 00000000 ffffffff 008f9300
GS =0000 00000000 ffffffff 008f9300
LDT=0000 00000000 0000ffff 00008200
TR =0000 00000000 0000ffff 00008b00
GDT=     00000000 00000000
IDT=     00000000 000003ff
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000004 CCD=00006c00 CCO=EFLAGS  
EFER=0000000000000000
SMM: after RSM
EAX=000000b5 EBX=000f7cd9 ECX=00001234 EDX=0000db80
ESI=07fbdb3b EDI=00006c40 EBP=00006c00 ESP=00006c00
EIP=000f7cd9 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000f6070 00000037
IDT=     000f60ae 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000000 CCD=00000000 CCO=EFLAGS  
EFER=0000000000000000
SMM: enter
EAX=000000b5 EBX=00007cf3 ECX=00005678 EDX=000eac40
ESI=07fbdb3b EDI=000eac40 EBP=00006c00 ESP=00006c00
EIP=000f7cf2 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000f6070 00000037
IDT=     000f60ae 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000000 CCD=00006bec CCO=EFLAGS  
EFER=0000000000000000
SMM: after RSM
EAX=000000b5 EBX=00007cf3 ECX=00005678 EDX=000eac40
ESI=07fbdb3b EDI=000eac40 EBP=00006c00 ESP=00006c00
EIP=00007cf3 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =db80 000db800 ffffffff 00809300
CS =f000 000f0000 ffffffff 00809b00
SS =0000 00000000 ffffffff 00809300
DS =0000 00000000 ffffffff 00809300
FS =0000 00000000 ffffffff 00809300
GS =0000 00000000 ffffffff 00809300
LDT=0000 00000000 0000ffff 00008200
TR =0000 00000000 0000ffff 00008b00
GDT=     00000000 00000000
IDT=     00000000 000003ff
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000004 CCD=00000001 CCO=EFLAGS  
EFER=0000000000000000
SMM: enter
EAX=000000b5 EBX=000f7cd9 ECX=00001234 EDX=0000db80
ESI=07fbdb3b EDI=0000692e EBP=000068ee ESP=000068ee
EIP=00007cd8 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =db80 000db800 ffffffff 008f9300
CS =f000 000f0000 ffffffff 008f9b00
SS =0000 00000000 ffffffff 008f9300
DS =0000 00000000 ffffffff 008f9300
FS =0000 00000000 ffffffff 008f9300
GS =ca00 000ca000 ffffffff 008f9300
LDT=0000 00000000 0000ffff 00008200
TR =0000 00000000 0000ffff 00008b00
GDT=     00000000 00000000
IDT=     00000000 000003ff
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000004 CCD=000068ee CCO=EFLAGS  
EFER=0000000000000000
SMM: after RSM
EAX=000000b5 EBX=000f7cd9 ECX=00001234 EDX=0000db80
ESI=07fbdb3b EDI=0000692e EBP=000068ee ESP=000068ee
EIP=000f7cd9 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000f6070 00000037
IDT=     000f60ae 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000000 CCD=00000000 CCO=EFLAGS  
EFER=0000000000000000
SMM: enter
EAX=000000b5 EBX=00007cf3 ECX=00005678 EDX=00000005
ESI=07fbdb3b EDI=00000000 EBP=000068ee ESP=000068ee
EIP=000f7cf2 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000f6070 00000037
IDT=     000f60ae 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000000 CCD=000068da CCO=EFLAGS  
EFER=0000000000000000
SMM: after RSM
EAX=000000b5 EBX=00007cf3 ECX=00005678 EDX=00000005
ESI=07fbdb3b EDI=00000000 EBP=000068ee ESP=000068ee
EIP=00007cf3 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =db80 000db800 ffffffff 00809300
CS =f000 000f0000 ffffffff 00809b00
SS =0000 00000000 ffffffff 00809300
DS =0000 00000000 ffffffff 00809300
FS =0000 00000000 ffffffff 00809300
GS =ca00 000ca000 ffffffff 00809300
LDT=0000 00000000 0000ffff 00008200
TR =0000 00000000 0000ffff 00008b00
GDT=     00000000 00000000
IDT=     00000000 000003ff
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000004 CCD=00000001 CCO=EFLAGS  
EFER=0000000000000000

不知道出了什么问题。日志文件只是一遍又一遍地重复该文本 block (这是有道理的,因为它在循环中重新启动)

最佳答案

print_string_pm 有多个问题!

mov ah, WHITE_ON_BLACK ; Set edx to the start of video memory

代码没有在EDX中设置视频输出地址。根据 EDX 中预先存在的值,您可能会破坏一些重要的东西!


mov al, WHITE_ON_BLACK ; store the attributes in ah
cmp al, 0 ; if (al == 0), at end of string, so
je  print_string_pm_done

更糟糕的是,这些行将使循环永远不会结束(WHITE_ON_BLACK 不为零)。所以上面提到的破坏肯定会发生(我相信)。

尝试下一个代码:

VIDEO_MEMORY equ 0xB8000
WHITE_ON_BLACK equ 0x0F

; prints a null-terminated string pointed to by EBX
print_string_pm:
    pusha
    mov   edx, VIDEO_MEMORY
    mov   ah, WHITE_ON_BLACK
print_string_pm_loop:
    mov   al, [ebx]
    cmp   al, 0
    je    print_string_pm_done
    mov   [edx], ax
    add   ebx, 1
    add   edx, 2
    jmp print_string_pm_loop
print_string_pm_done:
    popa
    ret

关于assembly - 切换到 32 位保护模式导致 QEMU 循环重启,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69573387/

相关文章:

c - shellcode执行/bin/sh但不执行./abcde

c - 如何使用GDB调试带SMP(对称多处理器)的QEMU?

linux-kernel - 远程 gdb 调试不会在断点处停止

c++ - 存储指令是否在高速缓存未命中时阻止后续指令?

performance - 复杂的寻址模式是否对从内存加载有额外的开销?

c - 有没有办法在进入功能之前保存寄存器?

linux - 为什么我不能使用 int 0x80 从指向堆栈内存的指针进行 sys_write?

android - 在 Android Studio 中启动 AVD 时出现错误 1073741819

gcc - gcc 链接器选项可以更改已编译二进制文件中的汇编器指令吗?

assembly - Intel 8085 程序集中的位移操作有什么作用?