The RAM is banked. This presents quite a challenge to Linux, which expects a linear stretch of RAM to allocate from. I have had to perform some high wizardry to make it play with the banked RAM.
The banks are laid out as follows.
Single sided SIMMS have the undesirable attribute of mapping the only side into both of the banks for that SIMM, so we have to detect that and cope. While the illusion of having more RAM than you do might be nice, the dream is shattered when your system unknowingly walks all over itself. My board has one 4MB bank of onboard RAM. Some models have none.
What I have done is to modify the definitions of the MAP_NR
and ADDRESS
macros in <asm/page.h>
and mmnommu/page_alloc.c
, respectively so that they take the banking into account in their translations between addresses and page numbers. I also had to track down and change static inline unsigned long page_address(struct page * page)
in <linux/pagemap.h>
in a way similar to what I had to do to ADDRESS
, since it does something very similar. If there are other pieces of code in the kernel which erroneously think that they know how to do these conversions, they will have to be fixed too. I don't know why ADDRESS
, or something like it, isn't defined in <asm/page.h>
. Done right, it would have saved me from having to hunt down the code in <linux/pagemap.h>
.
The heart of the conversion is a table of RAM bank information which is initially populated with memory sizes (in bytes) in the stage 1 boot loader, and converted to numbers of pages in the kernel startup code, with page offsets (also in pages) filled in. The structure is as follows.
struct { unsigned long offset; unsigned long size; } ram_bank[NR_RAM_BANKS];