【问题标题】:How do you enable a20 in nasm?你如何在nasm中启用a20?
【发布时间】:2019-06-24 02:45:22
【问题描述】:

我正在尝试在我的引导加载程序中进入长模式,现在我在启用 a20 线的第一部分,但我遇到了一个问题,那就是我制作的代码刚刚完全显示了屏幕黑色和应该说它是否有效的数字甚至没有显示

我在互联网上尝试了许多不同的 a20 功能,但对我来说还没有任何效果。

函数的代码是:

check_a20:
    pushf
    push ds
    push es
    push di
    push si
    cli
    xor ax, ax ; ax = 0
    mov es, ax
    not ax ; ax = 0xFFFF
    mov ds, ax
    mov di, 0x0500
    mov si, 0x0510
    mov al, byte [es:di]
    push ax
    mov al, byte [ds:si]
    push ax
    mov byte [es:di], 0x00
    mov byte [ds:si], 0xFF
    cmp byte [es:di], 0xFF
    pop ax
    mov byte [ds:si], al
    pop ax
    mov byte [es:di], al
    mov ax, 0
    je check_a20_exit
    mov ax, 1
    check_a20_exit:
    pop si
    pop di
    pop es
    pop ds
    popf
ret

seta20: ;Enable the a20 line if it worked then ax = 1 else 0
    pusha
    call check_a20 ;Check a20
    cmp ax, 1
    je .end ;If it worked then end function else:
    .keyboard: ;Test the 8042 keyboard controller
        call .empty_8042
        mov al, 0xd1 ;command write
        out 0x64, al
        call .empty_8042
        mov al, 0xdf ; A20 on
        out 0x60, al
        call .empty_8042 ;wait
    .empty_8042: ;For the 8042 function over this
        in al, 0x64
        test al, 2
        jnz .empty_8042
    ret
    call check_a20  ;Check a20
    cmp ax, 1
    je .end ;If it worked then end function else:
    .fasta20:
    in al, 0x92
    or al, 2
    out 0x92, al
    .end:
    popa
    call check_a20
ret

在这些函数之后,我有了一个将 ax 打印为十六进制的函数:

main:

    ;Stack, video and other setups(not important)

    call seta20 ;Set a20

    mov dl, 00h ;Set cursor for a print a20 check
    mov dh, 01h 
    mov bh, 00h
    mov ah, 02h
    int 10h

    call check_a20 ;Check a20
    mov dl, al
    mov bl, 02h
    call printhex ;Print dl

    jmp $   ;Infinite loop

printhex: ;print hex input(dl=value, bl=color) 8 bit
    pusha
    mov dh, 0x00
    mov ch, dl ;unshifted (for next hex)
    shr dl, 4 ; get high 4 bits(HEX)
    cmp dl, 9
    jna .1to9 
    .atof: ;if the number is a to f
        add dl, 55
        jmp .next
    .1to9:
        add dl, 48 ;add 48 to make it into a number
    .next:
        mov ah, 0Eh ;print char mode
        mov bh, 0
        mov al, dl
        int 10h ;Print 1st number of the two
    shl ch, 4
    mov dl, ch
    shr dl, 4 ; get high 4 bits(HEX)
    cmp dl, 9
    jna .1to92 
    .atof2: ;if the number is a to f
        add dl, 55
        jmp .print2
    .1to92:
        add dl, 48 ;add 48 to make it into a number
    .print2:
        mov ah, 0Eh ;print char mode
        mov bh, 0
        mov al, dl
        int 10h ;Print 1st number of the two
     popa
ret

我已经知道我的打印结果功能有效,因为我已经测试了很多次,但应该发生的是它应该用我的printhex16 打印一个十六进制数字 我有的功能

【问题讨论】:

  • 你有 out 0x60, al call .empty_8042 .empty_8042: 。我认为您在调用跳过 empty_8042 函数后缺少 JMP?
  • 不,我在empty_8042 函数中有一个ret

标签: assembly x86 nasm x86-16 bootloader


【解决方案1】:

您的 A20 代码背后的方法看起来不错,但您的实现方式似乎存在错误。你有这个seta20的代码:

seta20: ;Enable the a20 line if it worked then ax = 1 else 0
    pusha
    call check_a20 ;Check a20
    cmp ax, 1
    je .end ;If it worked then end function else:
    .keyboard: ;Test the 8042 keyboard controller
        call .empty_8042
        mov al, 0xd1 ;command write
        out 0x64, al
        call .empty_8042
        mov al, 0xdf ; A20 on
        out 0x60, al
        call .empty_8042 ;wait
    .empty_8042: ;For the 8042 function over this
        in al, 0x64
        test al, 2
        jnz .empty_8042
    ret
    call check_a20  ;Check a20
    cmp ax, 1
    je .end ;If it worked then end function else:
    .fasta20:
    in al, 0x92
    or al, 2
    out 0x92, al
    .end:
    popa
    call check_a20
ret

问题是您将一个函数放在另一个函数中,并且无意中让您的代码落入了该函数中。特别是这些代码行是问题:

        out 0x60, al
        call .empty_8042 ;wait
    .empty_8042: ;For the 8042 function over this
        in al, 0x64
        test al, 2
        jnz .empty_8042
        ret
    call check_a20  ;Check a20

call .empty_8042会调用函数.empty_8042,8042会被刷新; ret 将返回到call .empty_8042 之后的指令,然后开始执行.empty_8042 中的代码。问题是它第二次没有被作为函数调用,所以没有正确的返回地址。当它到达ret 时,它将尝试返回堆栈顶部的任何值。这可能会导致您的代码挂起、重新启动系统或执行其他意外操作。

一个快速的解决方法是放置一个 JMP 指令来跳过.empty_8042 中的代码。这样的事情会做:

        out 0x60, al
        call .empty_8042 ;wait
        jmp .skip_function
    .empty_8042: ;For the 8042 function over this
        in al, 0x64
        test al, 2
        jnz .empty_8042
        ret
.skip_function:
    call check_a20  ;Check a20

最好将.empty_8042 函数与seta20 函数分开,这样您就不需要跳过.empty_8042。您的代码可能如下所示:

empty_8042:
    in al, 0x64
    test al, 2
    jnz empty_8042
    ret

seta20: ;Enable the a20 line if it worked then ax = 1 else 0
    pusha
    call check_a20 ;Check a20
    cmp ax, 1
    je .end ;If it worked then end function else:
    .keyboard: ;Test the 8042 keyboard controller
        call empty_8042
        mov al, 0xd1 ;command write
        out 0x64, al
        call empty_8042
        mov al, 0xdf ; A20 on
        out 0x60, al
        call empty_8042 ;wait

    call check_a20  ;Check a20
    cmp ax, 1
    je .end ;If it worked then end function else:
    .fasta20:
    in al, 0x92
    or al, 2
    out 0x92, al
    .end:
    popa
    call check_a20
    ret

【讨论】:

  • 感谢它的工作,现在屏幕上输出了 1
猜你喜欢
  • 2020-01-04
  • 2012-12-03
  • 2016-01-16
  • 2016-02-22
  • 1970-01-01
  • 2020-04-27
  • 2012-06-13
  • 2018-08-27
  • 2015-12-01
相关资源
最近更新 更多