User:Johnburger/Demo/Boot/RAM
Another piece of information needed by the Protected Mode code is just exactly how much RAM the system has - and where. At Boot time, the BIOS knows, so now would be a good time to get it and save it away for future reference.
Of course, as the PC evolved the question "How much memory is there anyway?" got harder and harder to answer, so a number of methods evolved with it. And of course, being implemented by various manufacturers, they each had their own idiosyncrasies...
I use two:
- The first one is the original. It merely gives the top of conventional RAM (less the Extended BIOS Data Area - woohoo! I now have a value for
0009_F???h
in my Memory Map!). - The second is the most up-to-date one. It categorises the different blocks of address space into different types (Reserved, Present, Missing, Faulty etc.)
Having gone to all that effort, however, in the rest of the Demonstrator I ignore the values for the RAM Map returned by the BIOS in the second step above. I'll leave it as an exercise for the reader...
Memory Map
After this code, the Memory Map will look like this:
Address | Usage |
---|---|
0000_0000h
|
Interrupt Vector Table |
0000_0400h
|
BIOS Data Area |
0000_0500h
|
Protected Mode Data |
0000_0518h
|
RAM Map from BIOS |
0000_0800h
|
Moved IDT-to-be |
0000_1000h
|
Loaded Protected Mode code |
0000_2070h
|
Available |
0000_7C00h
|
SS:SP Stack Top
|
0000_7C00h
|
BIOS-loaded Boot Sector |
0000_7E00h
|
Available |
0009_F###h
|
Extended BIOS Data Area |
000A_0000h
|
Adapter / ROM Area |
000B_8000h
|
Text Video Memory |
000F_0000h
|
BIOS ROM |
0010_0000h
|
High Memory *
|
*
Note that this memory is only accessible in Protected Mode - except for the first 64 kiB (less 16 bytes), which you can access with a Segment Register set to 0FFFFh
as long as the A20 Gate is off. By the way: DON'T DO THIS!
Demo/Boot/RAM.inc
;
; Boot/RAM.inc
;
; This module uses the BIOS to determine how much RAM the system has.
; It saves the information away for the system to process after it has entered
; Protected Mode - BIOS functions aren't available then.
Boot.RAM:
XOR EAX,EAX ; Zero high part of EAX
MOV AX,Data.Base >> 4 ; Point to global Data
MOV DS,AX
MOV ES,AX ; With both Segments
INT BIOS.RAMTop.Int ; Get size of Low RAM in kiB
SHL EAX,10 ; Turn into number of bytes
MOV [Data.RAMTop],EAX ; Top of (Real) RAM
XOR EBX,EBX ; Start with beginning of RAM
MOV DI,Data.RAMMap ; Store records here
.Loop:
MOV EAX,BIOS.RAMMap.Fn ; Function call
MOV CX,BIOS.RAMMap_size
MOV EDX,BIOS.RAMMap.Magic
MOV [DI+BIOS.RAMMap.Flags],BYTE BIOS.RAMMap.Flags.DontIgnore
INT BIOS.RAMMap.Int ; Call BIOS
JC .End ; Carry? Finished
CMP EAX,BIOS.RAMMap.Magic ; BIOS function supported?
JNE .End ; Nope.
CMP CL,BIOS.RAMMap.Flags ; Don't mind optional Flags DWORD
JB .Skip ; Ignore if too small
JE .Test ; No .Flags entry, so valid
TEST [DI+BIOS.RAMMap.Flags],BYTE BIOS.RAMMap.Flags.DontIgnore
JZ .Skip ; Ignore if told to
.Test:
MOV EAX,[DI+BIOS.RAMMap.Length+0]
OR EAX,[DI+BIOS.RAMMap.Length+4]
JZ .Skip ; Zero-length entry?
INC WORD [Data.RAMMap.Num] ; One more Map entry
ADD DI,BIOS.RAMMap_size ; Next record
CMP DI,Data.Size-BIOS.RAMMap_size ; Any more room?
JA .End ; Nope. Leave
.Skip:
TEST EBX,EBX ; End of sequence?
JNZ .Loop ; Not yet...
.End: