In MS-DOS systems, the 64K - 16 bytes located at linear addresses 000FFFF0-001FFFEF. These addresses have the property that they can be accessed from the processor's real mode, if a piece of compatibility hardware is disabled. TSR programs, device driver modules, or MS-DOS itself can be loaded here without affecting conventional memory usage.

The first (64K - 16 bytes) that occurs after the top of the first MB of memory space on Intel x86 systems, which can, as erbo mentions, be accessed from real mode. But everybody knows that real mode only allows access to the first MB... so how come?

It turns out that this is due to a bug in the way the processor handles memory segments. Essentially, lots of memory segments overlap. If we look at memory as a "segment" and an "offset", we appear to have 65536 segments, and within each segment, 65536 offsets (actual addresses). Like this (written in decimal to make it look easier)

      Segment     Offset

            0          0
            0          1
            .
            .
            0      65534
            0      65535
            1          0
            1          1

And so on.

But there's a flaw here. If that was the case, we'd have a total of 65536 x 65536 bytes of memory = 4 GB (the amount available in protected mode). So how come we only have 1 MB?

As I say above, segments overlap. The first 16 bytes in each segment - seg:0 to seg:15 are "that segment's". The 17th byte, while still accessable in that segment - seg:16 - is also accessable as nextseg:0. And so on.

      Segment     Offset

            0          0
            0          1
            .
            .
            0         14
            0         15
            1          0   (also 0:16)
            1          1   (also 0:17)
            .
            .
            1         14   (also 0:30)
            1         15   (also 0:31)
            2          0   (also 0:32 AND 1:16)
            2          1   (also 0:33 AND 1:17)

And so on.

This is why we only have 1 MB of memory - each segment is basically only 16 bytes. 65536 x 16 = 1 MB.

As an aside, old Borland C compilers had two memory models to access the full 1 MB of memory - LARGE and HUGE. The difference was that HUGE rewrote all pointers to ensure the offset was no higher than 15. This meant you could compare pointers, but took a performance hit. Under the LARGE model, you could have two pointers, say 0:17 and 1:1 (which we saw above are the same) but if you compared them (as opposed to their contents), they wouldn't appear equal.

Back to the High Memory Area. When we hit the top of memory, something funny happens. This is what you would expect

      Segment     Offset

        65535         14
        65535         15  (the last byte in memory)
        65535         16  (also 0:0 - or is it!)

But this isn't what happens. When you get past the 16th byte in the last segment (65535:15), the processor should wrap round and start at the beginning. But it doesn't. Instead, it keeps going in memory.

This means that from 65535:16 to 65535:65535 is an additional 64k - 16 bytes (65535:0 to 65535:15 which are in the first 1 MB) that can be accessed while in real mode. This is the high memory area. As erbo says, it can be used for DOS itself or for drivers. It's actually best used for drivers, as only one program can use it at a time and DOS doesn't fill it. Decent memory managers (eg QEMM) keep DOS in the upper memory blocks and move drivers into the HMA to fill it more efficiently.

More modern, true protected mode operating systems such as Linux and Windows NT (2000 and XP) don't have this issue as they run the processor in protected mode and have continuous access to all memory.

Log in or register to write something here or to contact authors.