assembly 转换到保护模式时的一个奇怪问题

nzrxty8p  于 2023-08-06  发布在  其他
关注(0)|答案(1)|浏览(74)

我试图切换到保护模式后,玩了一点真正的模式,但奇怪的事情发生了。在真实的模式下,我创建了一个简单的欢迎屏幕,要求用户输入他们的名字。之后,应该会切换到保护模式,但实际上是这样的:


的数据
正如您所看到的,我按下Enter键,字符的背景开始改变,然后QEMU(我正在使用的模拟器)重新启动并重新显示欢迎屏幕。
代码如下:

section startUp vstart=0x7f00

; clearing the screen 
    mov ah,0x00
    mov al,0x03   
    int 0x10
; disabling the cursor
    mov ah,0x01
    mov ch,0x3f 
    int 0x10
; using Bios to print character
    mov ah,0x0e
    mov al,'C'
    mov cx,0x01
    int 0x10
; printing a string 
    mov ax,msg
    mov bx,0x00
    mov cl,0x0f
    mov dx,0x00
    call printMsg
; print warning 
    mov ax,warning
    mov bx,0x00
    mov cl,0x04
    mov dx,0x3a
    call printMsg
; print message
    mov ax,msg2
    mov bx,0x00
    mov cl,0x0f
    mov dx,0x0140
    call printMsg
; input 
    mov si,keypress
    mov bx,0x00
    call input


; switching to protected mode 
    cli           ; disabling interrupts 
    lgdt [GDT_Descriptor]     
    mov eax,cr0
    or eax,0x01
    mov cr0,eax   ; here we are in 32 bit protected mode

    jmp protectedMode





; printing a string function 
printMsg:
    pusha 

    ; ax ==> offset , bx ==> segment , dl ==> Line a0*lineNumber - 1, cl ==> color 

    mov es,bx
    
    mov bx,0xB000
    mov ds,bx 

    mov si,ax
    
    mov di,0x8000
    add di,dx

    mov byte[es:0x7e00],0x00 
    jmp loopThrough

    
    loopThrough:
        mov al,byte[es:si]
        mov byte[ds:di], al

        add di,0x01
        mov byte[ds:di],cl
        sub di,0x01

        add si,0x01

        mov bl,byte[es:si]
        cmp bl,0x00
            
        je quit

        add di,0x02
        jmp loopThrough
            

    quit :
        popa
        ret


; input function kjjj
input:
    pusha
    ; si ==> offset , bx ==> segment 
    mov di,si 
    mov es,bx 

    jmp loopinterupt

    loopinterupt :
        mov ah,0x00
        int 0x16

        cmp al,0x20

        je quitInput

        mov byte[es:si],al
        add si,0x01
        mov byte[es:si],0x00

        mov ax,di
        mov dx,0x172
        mov cl,0x0f
        call printMsg

        
        jmp loopinterupt

    quitInput :
        popa 
        ret



; Data

; Setting Up the GDT
GDT :

times 8 db 0x00

; base : 0x100000   ; Limit : 0x00700
dw 0x0700  ; limit 1 
dw 0x0000  ; base 1 
db 0x10    ; base 2
db 0x9a    ; access Byte 
db 0xc0    ; limit + flags
db 0x00d    ; base 3

; base : 0x800000  ; limit : 0x00700 
dw 0x0700  ; limit 1 
dw 0x0000  ; base 1 
db 0x80    ; base 2
db 0x96    ; access Byte 
db 0xc0    ; limit + flags
db 0x00    ; base 3

GDT_Descriptor :
dw GDT_Descriptor - GDT - 1
dd GDT 



msg db 'Welcome to the OS fdffdfgd',0x00
msg2 db 'Please write your name : ',0x00
keypress db 'K',0x00
warning db ""

[bits 32]
protectedMode:
    jmp $

times 1024-($-$$) db 0

字符串
因此,正如您所看到的,在执行jmp protectedMode之前,代码执行得很好。

dy1byipe

dy1byipe1#

Protected Mode guide on OSDev之后,可以看到涉及到3个步骤。
1.禁用中断
您在代码中使用cli指令正确地做到了这一点。
1.使能A20门
由于horrible history,硬件在访问内存时清除每个地址的位20。您很可能不希望这样,因为这意味着您的地址空间有一半无法访问。关于如何禁用此行为的完整指南在OSDev上,但只是为了在QEMU上进行快速测试,这应该可以工作:

mov ax, 0x2401
int 0x15

字符串
1.创建并加载GDT
如果要切换到32位保护模式,您最可能希望以以下两个段描述符开头:代码和数据。由于您可能希望访问完整的4GB地址空间,因此应该为它们指定0基址和4GB限制。因此,它们之间唯一不同的位是代码/数据位:

; Setting Up the GDT
GDT :

times 8 db 0x00

; code segment: base=0; limit=0xFFFFFFFF
; present, non-system, executable, non-conforming, read+exec
dw 0xFFFF  ; limit 1 
dw 0x0000  ; base 1 
db 0x00    ; base 2
db 0x9a    ; access Byte
db 0xcf    ; limit + flags
db 0x00    ; base 3

; data segment: base=0; limit=0xFFFFFFFF
; present, non-system, data segment, expand-up, read+write
dw 0xFFFF  ; limit 1 
dw 0x0000  ; base 1 
db 0x00    ; base 2
db 0x92    ; access Byte 
db 0xcf    ; limit + flags
db 0x00    ; base 3

GDT_Descriptor :
dw GDT_Descriptor - GDT - 1
dd GDT


这些段将允许您使用32位寄存器(如eax)来寻址高达4GB标记的任何内存位置。
最后,确保您实际上正在使用这些段(通过将它们加载到段寄存器中),否则可能会导致纯粹的混乱。
全模式切换代码:

; enable the A20 gate
mov ax, 0x2401
int 0x15

; disable interrupts
cli
 ; we do it after the BIOS call
 ; who knows what sort of buggy BIOS may execute STI and not restore our flags properly

; load the GDT
lgdt [GDT_Descriptor]

; enter protected mode (set bit 0 in cr0)
mov eax, cr0
or eax, 1
mov cr0, eax

; jump to protected mode entry point
jmp 0x08:protectedMode
 ; Here we use an absolute FAR JUMP, which reloads CS
 ; If we don't reload CS, the CPU will continue executing Protected Mode code using the old CS descriptor => chaos
 ; CS=0x08 because that is the offset of the code descriptor in the GDT

; ...

; protected mode entry point
[bits 32]
protectedMode:

; reload the other segment registers with the data descriptor
mov eax, 0x10
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax

; VERY IMPORTANT: set up the stack
mov ss, eax
mov esp, you_decide_the_place

相关问题