Someone recently posted a question to the Platform Builder newsgroup (microsoft.public.windowsce.platbuilder on the NNTP server) asking about how to set up noncontiguous RAM.  Seemed like the answers were going okay until someone replied with:
“Besides OEMGetExtensionDRAM function, you can also map the two separate physical memory sections into single one virtual memory in From system view, it has only one memory section and the only thing you need to do is to configure the ram start address and ram size in config.bib.”
That started an interesting discussion as many of us began to question what we know and don’t know. If this answer was correct, then it would change what we thought we knew about setting up RAM for Windows CE. So I thought that I would give it a try.
NOTE: The following applies to CPUs that use OEMAddressTable.  Some do not, but I haven't worked on any of them so I can't tell you much about them.
 I have a board with 64 MBs of RAM that are set up as contiguous. I decided to take a few MB out of the middle and see if worked. So first I:
1.       Divided the RAM into two in OEMAddressTable by changing
 DCD 0x80000000, 0xA0000000, 64
 DCD 0x80000000, 0xA0000000, 32
 DCD 0x82000000, 0xA2000000, 32
And tested that this boots up okay
2.       Subtract 4 MB from ram in config.bib changing
RAM    81300000    02A00000
RAM    81300000    02600000
3.       Leave the start virtual address the same, so that it is contiguous, Add 4 MB to the physical address so that it is noncontiguous and Subtract 4 MB from the total size. Changing:
      DCD 0x82000000, 0xA2000000, 32
      DCD 0x82000000, 0xA2400000, 28
4.       I tested this, but it did not boot up. It stopped when the ObjectStore was initialized.
So I concluded that the suggestion in the newsgroup does not actually work. That is what several us originally thought, although I did start to think that it might work. So that leaves us with two options
·         OEMGetExtensionDRAM – This function can be used by the OEM in the OAL to add one section of RAM to the system RAM.
·         OEMEnumExtensionDRAM – This function can be used by the OEM in the OAL to add multiple sections of RAM to the system RAM.
With the same idea in mind the following solves the problem using OEMGetExtensionDRAM(). OEMGetExtensionDRAM() has two parameters passed in; LPDWORD lpMemStart and LPDWORD lpMemLen.   The OEM then set the value pointed to by lpMemStart to the cached virtual address of the RAM to add and the value pointed to by lpMemLen to the size of the RAM.
Here are the changes that I made:
1.       Remove the top 32 MB ram in config.bib changing
RAM    81300000    02A00000
RAM    81300000    00800000
My system uses some RAM at the top for something unique, so the numbers here may not make sense with your system.
2.       Implement OEMGetExtensionDRAM() as:
BOOL OEMGetExtensionDRAM(LPDWORD lpMemStart, LPDWORD lpMemLen)
                *lpMemStart = 0x82000000;
                *lpMemLen = 0x01900000;
                return *lpMemStart != NULL ? TRUE : FALSE;
3.       Left the changes that I made to OEMAddressTable in step 3 above.
4.       Tested. The system boots up and the ObjectStore reflects the settings that I made.
Then solving the same problem with OEMEnumExtensionDRAM(). This is a little trickier than OEMGetExtensionDRAM() because the trick is that in OEMInit() you must set the function pointer pNKEnumExtensionDRAM to the address of your implementation of OEMEnumExtensionDRAM(). Setting pNKEnumExtensionDRAM does two things; tell the kernel that you have OEMEnumExtensionDRAM() implemented and that you don’t want the kernel to call OEMGetExtensionDRAM().
The changes that I made are:
1.       Implement OEMEnumExtensionDRAM()
DWORD OEMEnumExtensionDRAM(PMEMORY_SECTION pMemSections,DWORD cMemSections)
                DWORD AddedSections = 0;
                if( AddedSections < cMemSections )
                                pMemSections->dwStart = 0x82000000;
                                pMemSections->dwLen   = 0x01900000;
                return AddedSections; 
2.       Set pNKEnumExtensionDRAM in OEMInit()
pNKEnumExtensionDRAM = OEMEnumExtensionDRAM;
But that won’t compile unless we tell the compiler about pNKEnumExtensionDRAM and the new OEMEnumExtensionDRAM().   So, add the following before setting the pointer:
extern DWORD (*pNKEnumExtensionDRAM)(PMEMORY_SECTION pMemSections,DWORD cMemSections);
DWORD                OEMEnumExtensionDRAM(PMEMORY_SECTION pMemSections,DWORD cMemSections);
3.       Then test it.
Of course OEMEnumExtensionDRAM() can add multiple sections, but not more than the value passed in cMemSections. To implement that, just copy the if condition and its body, then change the address and size.
Now we have two ways to add noncontiguous RAM sections, and one that doesn’t work.
You may also want to look at my Summary of BIB File Posts
Copyright © 2008 – Bruce Eitman
All Rights Reserved