Page 1 of 1

A20 Line is already enabled

Posted: Mon Jan 28, 2013 8:46 pm
by tarcisiofischer
Hello everyone.

Making some tests at home, I found that line a20 seems to be already enabled on some newer PCs and VMs.
I tested the following code on qemu, bochs, virtualbox, my (real) eee-pc 701 and my not old home pc. I assume the BIOS version are relevant here, but I don't know how I see their versions.

(WARNING: Code in AT&T syntax)

Code: Select all

	mov $0x0000, %ax
	mov %ax, %ds

	movw $0xAA55, %ax
	movw $0x7DFE, %bx
	movw (%bx), %bx
	cmpw %ax, %bx
	jnz not_equal
	movw $equal_str, %si
	call print_msg
	jmp done
not_equal:
	movw $not_equal_str, %si
	call print_msg
done:
This code (I hope) tests if the value from memory 0x0000:0x7DFE = 0x7DFE is 0xAA55 (boot flag), if so, it prints "equal", else it prints "not equal".
Print procedure is not shown here, but is just the basic BIOS interrupt 0x10.
The result here is "equal" to all tested machines and VMs.
Then, if I run this code:

Code: Select all

	movw $0xFFFF, %ax
	movw %ax, %ds
	movw $0x7E0E, %bx
	movw (%bx), %bx
	movw $0x0000, %ax
	movw %ax, %ds

	movw $0xAA55, %ax
	cmpw %ax, %bx
	jnz not_equal2
	movw $equal_str, %si
	call print_msg
	jmp done2
not_equal2:
	movw $not_equal_str, %si
	call print_msg
done2:
This code (I hope) compares the value of memory 0xFFFF:0x7E0E = 0x107DFE with 0xAA55, if so print "equal" else print "not equal".
The result here is "not equal" to all tested machines and VMs.

First, I thought my code was wrong, but in a quick test, I add this "disable a20 line" code:

Code: Select all

	mov $0x2400, %ax
	int $0x15
And for my surprise the result was "equal" and "equal" (so now it seems to wrap around the memory!).
Could someone else test those codes in some other PCs? Or can someone point what I'm doing wrong?
My theory is that newer PCs come with a BIOS that already set um a20 for us, so this is not necessary anymore.

Re: A20 Line is already enabled

Posted: Tue Jan 29, 2013 1:03 am
by Brendan
Hi,
tarcisiofischer wrote:My theory is that newer PCs come with a BIOS that already set um a20 for us, so this is not necessary anymore.
Once upon a time the 8086 would wrap at 1 MiB, and some people wrote software that assumed the CPU would wrap at 1 MiB. Later CPUs didn't wrap and this created compatibility problems, so to ensure backward compatibility the A20 gate was invented.

Now (over 30 years later); you can't assume that the BIOS correctly ensures backward compatible behaviour (and can't assume A20 is disabled), and you also can't assume that the BIOS doesn't ensure backward compatible behaviour (and can't assume that A20 is enabled). Basically, assumptions are bad.

This isn't just for determining if A20 is enabled or not though. Some computers don't support the "enable/disable A20" BIOS function. Some computers don't have a keyboard controller and attempting to use the old "enable A20 using the keyboard controller" method will crash the machine. Some computers don't support the "fast A20" method. Some computers support both the keyboard controller and the fast A20 methods, but one or the other will cause problems for ACPI (e.g. hybernate).

Assumptions are bad, and good code will try to minimise risk. To minimise risk:
  • Test if A20 is already enabled, and if it is don't touch anything else.
  • Otherwise, use the BIOS function and then test if A20 became enabled, and if that worked don't touch anything else.
  • Otherwise, use the keyboard controller, and then repeatedly test if A20 became enabled in a loop with a timeout (it may take a little while for A20 to actually become enabled after you've enabled it), and if that worked don't touch anything else.
  • Otherwise, try the "fast A20" method, and then repeatedly test if A20 became enabled in a loop with a timeout; and if that worked don't touch anything else.
  • Otherwise, nothing worked - either display an error message and refuse to boot, or design an OS that's capable of running with A20 disabled so that you can display a warning and continue booting ;).

Cheers,

Brendan

Re: A20 Line is already enabled

Posted: Tue Jan 29, 2013 6:33 am
by Antti
A20 address line is surprisingly interesting even though it has been discussed many times. Little hacks back then caused very long-term effects. After 30 years we are still scratching our heads and thinking the most reliable way to make sure A20 address line is enabled. Does anyone know a program that actually uses the wrap at 1 MiB "feature?" As an history reference, it would be a nice to know at least one.
Brendan wrote:Some computers don't have a keyboard controller and attempting to use the old "enable A20 using the keyboard controller" method will crash the machine.
You listed methods in this order: BIOS, Keyboard Controller, and Fast A20. I was thinking of this order a while when I made my new EnableA20Line procedure. I ended up using Fast A20 before the keyboard controller method "because it is newer." Otherwise I used almost the same logic you listed in your post. However, it is not tested very well. I almost should have a TDD method for "xor ax, ax" kind of code because I continually find very simple bugs.

Re: A20 Line is already enabled

Posted: Tue Jan 29, 2013 6:35 am
by Combuster
Antti wrote:Does anyone know a program that actually uses the wrap at 1 MiB "feature?"
Excluding all the sane bootloaders out there? :mrgreen:

Re: A20 Line is already enabled

Posted: Tue Jan 29, 2013 6:36 am
by Antti
Combuster wrote:All the sane bootloaders out there?
That was a good one.

Re: A20 Line is already enabled

Posted: Tue Jan 29, 2013 6:49 am
by Brendan
Hi,
Antti wrote:Does anyone know a program that actually uses the wrap at 1 MiB "feature?" As an history reference, it would be a nice to know at least one.
You might be surprised, but...


Cheers,

Brendan