Before the 286, x86 CPUs can only access 1MiB, so the only way to use memory beyond 1MiB is to use some form of bank switching. The de facto standard for that is Lotus/Intel/Microsoft EMS, which provides access to expanded memory by switching into a “page frame” (typically located in the UMA, between 640KiB and 1MiB). EMS requires hardware on CPUs before the 386, but many 286 chipsets provide support (along with the appropriate driver). On 386 and later, drivers such as
EMM386.EXE provide expanded memory. The EMS API is available via interrupt 67h, services 40h to 5Dh. See the full specification for details.
On the 286 and above, the XMS API (implemented for example by
HIMEM.SYS) provides access to extended memory, along with UMBs and the HMA. For real mode programs, this is used by copying blocks of memory from conventional to extended and back. The XMS API is accessed through a control function; first use interrupt 2Fh service 4300h to check whether XMS is available, then service 4310h to obtain the control function’s address. See the full specification for details.
286 PCs introduced another API, provided by the BIOS, which is less often encountered in practice: interrupt 15h, service 87h copies memory specified by 24-bit linear addresses (so it can be used to copy conventional to extended and back, but also extended to extended, or conventional to conventional). Memory can be “allocated” by reducing the amount returned by service 88h which indicates the size of extended memory; this is how the
VDISK.SYS RAM drive allocates memory for its drives (when extended memory is available).
On the 286 and later, it is also possible to switch to protected mode (using an API such as DPMI, or not) and access extended memory directly, but it’s important to still use APIs to allocate memory. Another approach is to use
LOADALL. Many large DOS programs use a DOS extender, which takes care of handling all that for them.