Checking if A20 has been enabled...
Checking if A20 has been enabled...
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
;;;;; 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...
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?
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...
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 0000FFFF 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.
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
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 0000FFFF 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
Reference: http://www.pcguide.com/ref/ram/logicHMA-c.html
Re:Checking if A20 has been enabled...
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...
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...
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...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 0000FFFF anyway.
The code is by the way running in Protected Mode.
Re:Checking if A20 has been enabled...
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.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...
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...
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
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...
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
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...
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
"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...
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
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...
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
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
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 [] block
Code: Select all
] ... [
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.
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