Page 1 of 1

Checking if A20 has been enabled...

Posted: Sun Jun 23, 2002 7:22 pm
by Peter_Vigren
Hello you all! A little question... Does this code to detect whether or not A20 was enabled work? I haven't had any problems with it but I just want to be sure...

;;;;; Check if A20 was enabled ;;;;;

Mov Ebx,[0]
Mov Eax,Ebx
Not Ebx
Mov Dword [1048576],Ebx
Mov Ebx,[0]

Cmp Eax,Ebx
Je A20WasEnabled

Re:Checking if A20 has been enabled...

Posted: Sun Jun 23, 2002 8:43 pm
by crazybuddha
Maybe it's late and I'm not grokking this.

1) put all 0's in eax
2) put all 1's in ebx
3) write all 1's to offset 0x10000
4) put all 0's in ebx
5) see if ebx and eax are the same

This doesn't appear to do anything. Can you describe what you were aiming for?

Re:Checking if A20 has been enabled...

Posted: Sun Jun 23, 2002 10:18 pm
by Schol-R-LEA
I believe what is meant is to test whether he can write to FFFF:0010 (absolute address 0x100000, the first memory location of the HMA), and read it back correctly.

The problem with this is (aside for the invalid use of an absolute address in real mode), this approach doesn't work. The test will always give a false positive if the A20 line is disabled, because the default is for the addresses between FFFF:0010-FFFF:FFFF to wrap around to 0000:0000-0000:FFFF anyway.

This was, after all, the whole reason the HMA exists as a specific region in real mode at all. The 8088 had only 20 physical address lines, A0-A19; but since the A20 address line existing on the 80286 and could be accessed even in real mode (since the segment:offset combination could produce addresses in the 0x10000-0x10FFEF range even though the 8088 wrapped around at 0x10000), it caused memory to wrap 0xFFEF addresses higher than in the 8088, which broke some PC software.

The practical upshot is that writing to FFFF:0010 with the a20 disabled is the sam effect as writing to 0000:0000, which is perfectly allowable, if rather dangerous as it trashes the start of the interrupt table (!).

Obviously, the goal should be to differentiate between writing to the actual address FFFF:0010 and the address 0000:0000. While I haven't tried this code yet, I would imagine something like the function below might be closer to the mark.

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;  a20ok - checks if the a20 line has been enabled
;  modifies AX
;  return value in AL: 00 if failure, 01 if success

a20ok:
   cli     ; clear interrupts first, as you'll be messing around
           ; with the interrupt table
   xor al, al
   mov ah. al
   inc ah                ; al == 0, ah == 1
   push [0000:0000]     ; save address of address zero
   mov [0000:0000], ah  ; set the value of address zero to 1
   mov [FFFF:0010], al  ; set first addr in HMA to zero
   mov ah, [0000:0000]  ; get the value of address zero again
   cmp ah, al             ; check value of addr. zero
   jz  .value          ; a20 not set, return zero
   inc al                 ; a20 set, return one

.value:
   pop [0000:0000]      ; restore value of addr zero
   sti                  ; reset interrupts
   ret
This is only a rough draft, and needs to be tested and debugged, but it should be close to the desired function. As always, corrections of any mistakes are welcome.

Reference: http://www.pcguide.com/ref/ram/logicHMA-c.html

Re:Checking if A20 has been enabled...

Posted: Mon Jun 24, 2002 5:05 am
by Tim
Schol-R-LEA has got the same method I'd recommend, except that it's better to use 10101010 (0AAh) and 01010101 (55h) as your bit patterns: that is, write 10101010, read it back and check, then do the same with 010101010. The reason for this being that it checks every bit of the memory byte. It might look like overkill, but hardware does strange things. :)

Re:Checking if A20 has been enabled...

Posted: Mon Jun 24, 2002 9:38 am
by f2
Instead of doing it that way, use what you would do to enable the A20 but instead of enabling, test it. So, just read from port 0x92 and test the 1st bit to see if it's enabled.

Re:Checking if A20 has been enabled...

Posted: Tue Jun 25, 2002 11:43 am
by Peter_Vigren
Schol-R-LEA wrote: The problem with this is (aside for the invalid use of an absolute address in real mode), this approach doesn't work. The test will always give a false positive if the A20 line is disabled, because the default is for the addresses between FFFF:0010-FFFF:FFFF to wrap around to 0000:0000-0000:FFFF anyway.
I don't really understand what you are saying here... The memory will wrap around if A20 is disabled? That I know... why else would my code use that knowledge? And the code is supposed to check if A20 is disabled or not...

The code is by the way running in Protected Mode.

Re:Checking if A20 has been enabled...

Posted: Tue Jun 25, 2002 4:40 pm
by Schol-R-LEA
Peter_Vigren wrote: I don't really understand what you are saying here... The memory will wrap around if A20 is disabled? That I know... why else would my code use that knowledge? And the code is supposed to check if A20 is disabled or not...
The point I was making was that you're code did not appear to be comparing the value of 0x100000 with that of 0x000000, which are what need to be differentiated.

Allow me to demonstrate. Let us assume that, as you said, the CPU is in p-mode, CR0. Now then, assume you set address zero to 0xAA, and then set address 0x100000 to 0x55. If the A20 line is disabled, the values for address zero would then be 0x55, not 0xAA.

Obvious? Yes, but your code seemed to neither set nor check the value of address zero anywhere, which is what puzzled both me and CrazyBuddha. It looked as if you were checking to see if address 0x100000 could be set at all, which would hold true regardless of the A20 gate status (it just would wrap to 0 if A20 were disabled).

As for why I assumed that you would be doing this in real mode, well, generally you try to enable the a20 and check it first, before going to p-mode; in the case of boot loaders like GRUB which set p-mode before bootstrapping your code, they usually check it for you; GRUB in particular can be interrogated for the memory status and size. It is unusual to need to checl the A20 line after entering p-mode.

Re:Checking if A20 has been enabled...

Posted: Tue Jun 25, 2002 5:11 pm
by Peter_Vigren
I can understand if you didn't understand... When I looked on my post, I saw that the [0] had been left out... Probably some smiley-thingy the board supports...

Mov Ebx,[0] ; Save the value at byte 0

Mov Eax,Ebx
Not Ebx ; Invert Ebx which contains the byte found at byte 0
Mov Dword [1048576],Ebx
Mov Ebx,[0]

Cmp Eax,Ebx ; Compare byte 0 before and after
Je A20WasEnabled

Re:Checking if A20 has been enabled...

Posted: Tue Jun 25, 2002 9:17 pm
by Chris Giese
verify_a20:
push ax
push ds
push es
xor ax,ax
mov ds,ax
dec ax
mov es,ax
mov ax,[es:10h] ; read word at FFFF:0010 (1 meg)
not ax ; 1's complement
push word [0] ; save word at 0000:0000 (0)
mov [0],ax ; word at 0 = NOT(word at 1 meg)
mov ax,[0] ; read it back
cmp ax,[es:10h] ; fail if word at 0 == word at 1 meg
pop word [0]
pop es
pop ds
pop ax
ret ; if ZF=1, the A20 gate is NOT enabled

Re:Checking if A20 has been enabled...

Posted: Tue Jun 25, 2002 9:44 pm
by Chris Giese
Ugh. Evidently, this board treats
"left-square-bracket, zero, right-square-bracket" as
some kind of tag. Trying HTML entities:

verify_a20:
push ax
push ds
push es
xor ax,ax
mov ds,ax
dec ax
mov es,ax
mov ax,[es:10h] ; read word at FFFF:0010 (1 meg)
not ax ; 1's complement
push word [ 0 ] ; save word at 0000:0000 (0)
mov [ 0 ],ax ; word at 0 = ~(word at 1 meg)
mov ax,[ 0 ] ; read it back
cmp ax,[es:10h] ; fail if word at 0 == word at 1 meg
pop word [ 0 ]
pop es
pop ds
pop ax
ret ; if ZF=1, the A20 gate is NOT enabled

Re:Checking if A20 has been enabled...

Posted: Tue Jun 25, 2002 9:47 pm
by Chris Giese
ARRGGGHHH, MAKE IT STOP


ZERO EQU 0

verify_a20:
push ax
push ds
push es
xor ax,ax
mov ds,ax
dec ax
mov es,ax
mov ax,[es:10h] ; read word at FFFF:0010 (1 meg)
not ax ; 1's complement
push word [ZERO] ; save word at 0000:0000 (0)
mov [ZERO],ax ; word at 0 = ~(word at 1 meg)
mov ax,[ZERO] ; read it back
cmp ax,[es:10h] ; fail if word at 0 == word at 1 meg
pop word [ZERO]
pop es
pop ds
pop ax
ret ; if ZF=1, the A20 gate is NOT enabled

Re:Checking if A20 has been enabled...

Posted: Tue Jun 25, 2002 9:54 pm
by Schol-R-LEA
Disabling smilies in this case doesn't help; the message board is still showing [[0]] as a circle in your code like this: [0]

The message board tries to interpret everything between brackets as BBcode, and shows it as such when it finds a match. The solutions are
  • Use a [

    Code: Select all

    ] ... [
    ] block

    Code: Select all

    like this: [0]
  • Double up every left and right bracket to escape them, like this: [[[[0]]]]
    or
  • Consistently use either 0x00 or 00h for zero.
I'd suggest the latter option anyway, as it clearly distinguished it from the capitalized letter O and makes the numbering more consistent overall. For code fragments longer than two lines I recommend code blocks, even though the color scheme and the smaller font make it rather hard to read (one of the advantages of using Opera is that the 'Zoom In/Zoom Out' feature makes this a minor issue).

See http://www.squid.org/phpBB/bbcode_ref.html for more information on BBcode. While this reference is not, strictly speaking, for the version used on this board, it is close enough to make little difference.

BTW, you can edit the postings, as well, using the "modify" button at the top of the message. This might cut down on the repeated posts of the same material while you're trying to get it right ;)