Access physical memory in MS-DOS

MS-DOS operating system (and the other "clones" like OpenDOS and so on)  is dead for the majority of users so do not make much sense write a post about this argument. However in the companies producing embedded hardware the DOS operating system is still used some time. Obviously not as main operating system but as tool for check if there is some problem on the new hardware board they are working on.



DOS systems have some big advantage that allow to use it as testing tool for not working hardware or in a lot of other situations where, for various reasons, is not possible to run a newer operating system like Windows or Linux. Basically DOS is able to start with a very few amount of memory, a VGA compatible graphic card and a storage space to boot from (that, in majority of cases, is an USB key). On the opposite side the disadvantage of using this operating system is the impossibility to have access over the first 640KB of system memory. This limit come from historical reasons but can be easily get over using some free libraries allowing to have access to the whole memory (called Extended Memory).

Let's go to see how to make this possible. The most used solution for access extended memory is a tool called DOS4GW. This tool have a lot of good features but two main disadvantages. First you have to pay for have the complete version (it exist also a free version with limited capabilities) and second you need to include a separate executable file (the tool itself) together with your distributed application. The solution we'll use in this example is based to a different tool that is free, open-source and, more important, allow to create a unique executable file that incorporate the extender memory tool and your main application code. This tool is called DOS/32A. You can download the binaries or the full source code and use it with your application. Anyway, first of all, we need to choose a compiler able to create DOS application and, in this case, the choices are really few. The last Microsoft compiler able to generate DOS executable is the very old Visual C++ 1.52 but this is quite rare to find. Other DOS compilers are available and, selecting one of them, I strongly suggest to use the Open Watcom product (also because in the official page on the DOS/32A is indicated Watcom compiler as totally compatible with the tool). This compiler come with a very simply IDE and is able to generate executable files for Windows and DOS 32 and 16 bit version. More important, the IDE can automatically create project based to the DOS/32A tool. This is very important since this feature allow us to don't loose time for integrate the tool inside our project. Keep in mind, if you are accustomed to modern IDE interface, you can find the IDE available with this compiler very poor. However you are not forced to use the editor provided with this IDE. Personally I use the compiler IDE only for compile my code and manage the files in the project. For edit the code you can choose your preferred editor, no problem from this side.

Once installed the Open Watcom run the main IDE window, select from menu File and New Project.... After chosen the project file name you'll have to select the executable type you want to generate. In our case we need to select DOS - 32-bit application target and the DOS/32A extender image type as show in the image below:


The DOS32/A option is proposed in two different variants. LE Executable and LX Executable. The differences between these two formats are very minor. The LE format was the first one defined. LX adds a small efficiency improvement that was desired for OS/2. Since our application will run under DOS operating system we'll choose the first one as selected in the screenshot above.

Before start to check the code is better to talk a little about the working of DOS/32A tool. Once your program is executed the DOS/32A extender is automatically loaded in the system. Basically, for try to simplify, it "create" new interrupt services that allow access to extended memory region. The interrupt to use for have access to the DOS/32A feature is the INT 31h. Calling this interrupt with special command codes give access to the additional functionalities connected with the tool. If you are interested to have more explanation regarding how this tool work you can check the official web site documentation. Many new features are available once loaded this extender but, for our purposed, we need to use only two of them.

Now let's go see the code allowing to access physical memory. First of all we need to get the pointer to the memory address we are interested to read or write. We can easily obtain this pointer using the code below:

#include <conio.h>
#include <i86.h>
#include <stdio.h>

uint32_t MemoryAddress = [memory address];
uint32_t MemorySize = [memory size];
uint32_t MemPointer;
uint8_t* pMem;
REGS Regs;

Regs.w.ax = 0x0800;
Regs.w.bx = (MemoryAddress >> 16);
Regs.w.cx = (MemoryAddress & 0xFFFF);
Regs.w.si = (MemorySize >> 16);
Regs.w.di = (MemorySize & 0xFFFF);

int386(0x31, &Regs, &Regs);

if(Regs.w.cflag & INTR_CF) return FALSE;

MemPointer = Regs.w.bx;
MemPointer <<= 16;
MemPointer &= 0xFFFF0000;
MemPointer |= Regs.w.cx;

pMem = (uint8_t*)MemPointer;

Basically this code converts physical address into linear address and give full access to the memory starting from the [memory address] to the maximum limit of [memory address]+[memory size]. At the end of the code you have the pMem pointer you can use for read or write the memory.

Once you have finished your operation in the memory you need to free the pointer using the code below:

Regs.w.ax = 0x0801;
Regs.w.bx = (MemPointer >> 16);
Regs.w.cx = (MemPointer & 0xFFFF);

int386(0x31, &Regs, &Regs);

As you can see following the suggestion regarding the compiler to use there are no additional problems to face. The code proposed can be used as it is without know nothing more regarding the functionalities used. If you are interested to have more info about there are a lot of good tutorials discussing about x86 CPU registries, DPMI interface used by the extender and so on, simply google and find it.



Comments

Popular posts from this blog

Access GPIO from Linux user space

Android: adb push and read-only file system error

Tree in SQL database: The Nested Set Model