You have enabled ProtectedMode or UnrealMode and still weird things occurs when you try to load your kernel above 1MB barrier ... Or maybe you just read about HighMemoryArea and found that you could be loading a small kernel just above 1MB because 0xFFFF*16 + 0x1234 == 0x101224 (see perica's tutorial about RealMode for details)...

but it doesn't work.

The main reason you can't access all your memory (or only "odd" megabytes) is because you need to enable the A20 line on your bus.

Note: This should not happen if you are using a modern (circa 1997 or later) machine. The modern IBM PC and compatibles do not have all those separate chips physically on-board (keyboard controller, interrupt controller and friends); they actually have one chip which emulates all these IBM PC and compatible chips called the Super I/O chip. The Super I/O chip enables the A20 line for you.

What is the A20 line ?

Included from A20Line

The A20 line takes a bit of explaining.

When the IBM-AT was introduced, it was able to access up to sixteen megabytes of memory (instead of the 1 MByte of the IBM-XT). But to remain compatible with the IBM-XT, a quirk in the XT architecture (memory wraparound) had to be duplicated in the AT. To achieve this, the 20th line on the address bus (A20) was turned off.

Some programs (and bioses) were indeed expecting that 0xFFFF * 16 + 0x1234 would be 0x001224.

The A20 line is controlled by the keyboard controller unit, which is usually a derivative of the 8042 chip. By programming that chip accurately, you can either enable or disable bit #20 on the address bus.

When your PC boots, the A20 gate is always disabled, but some BIOSes do enable it for you, as do some high-memory managers (HIMEM.SYS) or bootloaders (GRUB).


This is a Glossary page, see Why cant I access all my memory? for more info.

How do i enable the A20 gate (Pre Pentium)

To enable the A20 line, you have to use some hardware IO using the Keyboard Controller chip (8042 chip) and enable it. Good documentation exists for the 8042 chip but here is my source for enabling the A20 in C code.

The flow chart for this is;

   1. Disable interrupts
   2. Wait until the keyboard buffer is empty
   3. Send command to disable the keyboard
   4. Wait until the keyboard buffer is empty
   5. Send command to read output port
   6. Wait until the keyboard buffer is empty
   7. Save byte from input port
   8. Wait until the keyboard buffer is empty
   9. Send command Write output port
  10. Wait until the keyboard buffer is empty
  11. Send saved byte OR by 2 (GATE A20 to ON)
  12. Wait until the keyboard buffer is empty
  13. Enable the keyboard
  14. Enable interrupts

It's especially important to wait for the 8042 everytime the flowchart tells it. Going too fast may lead to discarded command/data bytes on some chipsets.

Here is my C source;

/* Init the A20 by Dark Fiber */
void init_A20(void)
{
        UCHAR   a;

        disable_ints();

        kyb_wait_until_done();
        kyb_send_command(0xAD);         // disable keyboard

        kyb_wait_until_done();
        kyb_send_command(0xD0);         // Read from input

        kyb_wait_until_done();
        a=kyb_get_data();

        kyb_wait_until_done();
        kyb_send_command(0xD1);         // Write to output

        kyb_wait_until_done();
        kyb_send_data(a|2);

        kyb_wait_until_done();
        kyb_send_command(0xAE);         // enable keyboard

        enable_ints();
}

Or in ASM if you wish

;;
;; NASM 32bit assembler
;;

[bits 32]
[section .text]

enable_A20:
        cli

        call    a20wait
        mov     al,0xAD
        out     0x64,al

        call    a20wait
        mov     al,0xD0
        out     0x64,al

        call    a20wait2
        in      al,0x60
        push    eax

        call    a20wait
        mov     al,0xD1
        out     0x64,al

        call    a20wait
        pop     eax
        or      al,2
        out     0x60,al

        call    a20wait
        mov     al,0xAE
        out     0x64,al

        call    a20wait
        sti
        ret

a20wait:
.l0:    in      al,0x64
        test    al,2
        jz      .l2
        jmp     .l0
.l2:    ret


a20wait2:
.l0:    in      al,0x64
        test    al,1
        jnz     .l2
        jmp     .l0
.l2:    ret

According to The Undocumented PC (Frank Van Gilluwe) the AT keyboard controller can also accept a Disable and Enable A20 line command directly (using the A20 wait subroutine from above)-

call a20wait
out 0x64,  0xDD         ; Disable A20
ret

call a20wait
out 0x64,  0xDF         ; Enable A20
ret

How do i enable the A20 gate (Post Pentium)

Fortunately with the Pentium onwards, the processor has a FAST A20 option that bypasses the A20 line altogether. To set the A20 line, there is no need for delay loops or polling, just 3 simple instructions.

        in al, 0x92
        or al, 2
        out 0x92, al

However, this is not supported everywhere and there is no reliable way to tell if it will have some effect or not on a given system. Even worse, on some systems, it may actually do something else like blanking the screen, so imvho, you shouldn't use that unless you learned by the BIOS that FAST A20 is available... and you still have to write down the code for systems that do not support FAST A20. The good news is that enabling A20 line is one of the things GRUB can do for you, and it does it well :)


This is a TroubleShooting and HowTo page about HardWareMemory