next up previous contents
Next: 4.0.6 Memory banks for Up: 4. Exporting the hardware Previous: 4.0.4 Multiple page size

4.0.5 Memory banks for ix86 based architectures

Machine dependent memory banks are structures used to know how many memory banks are installed, and also to carry out some simple machine dependent tasks.

<Off machine dependent memory bank. >= (U->)
// A machine dependent memory bank.
//
class off_mdepMBank {
private:
  // Things known by the boot procedure about this memory bank
  //
  static vm_offset_t m_base;    // first valid address in this node
  static vm_offset_t m_end;     // last valid address in this node.
  vm_offset_t m_first;          // first valid address in this memory bank.
  vm_offset_t m_last;           // last valid address in this memory bank.
  unsigned8_t m_flags;          // capabilities (MF_DMA,MF_IOM,MF_PER)
  vm_size_t   m_pgsz[OFF_NPGSZ_MAX]; // Preferred page sizes for this m.bank.
  vm_size_t   m_npgs;           // # of page frames installed.
  unsigned8_t m_mat;            // mean access time.
public:
  // Accessors to tell users...
  vm_offset_t get_base(void) const { return m_base; }
  vm_offset_t get_end(void)  const { return m_end; }
  vm_offset_t get_first(void)const { return m_first; }
  vm_offset_t get_last(void) const { return m_last; }
  unsigned8_t get_flags(void)const { return m_flags; }
  vm_size_t   get_pgsz(int i)const { return m_pgsz[i]; }
  vm_size_t   get_npgs(void) const { return m_npgs; }
  unsigned8_t get_mat(void)  const { return m_mat; }

  <Other public methods of off_mdepMBank. >
};

Defines off_mdepMBank (links are to index).

<Off machine dependent memory bank dependencies. >= (U->) [D->]
#include <flux/types.h>         // for boolean_t natural_t et al.
#include <klib/limits.h>        // for OFF_NPGSZ_MAX et al.

<Off machine dependent memory bank static members. >= (U->)
vm_offset_t off_mdepMBank::m_base; // first valid address in this node
vm_offset_t off_mdepMBank::m_end;  // last valid address in this node.

Machine dependent memory banks are created from their memory bank number.

<Other public methods of off_mdepMBank. >= (<-U) [D->]
// Creates the i-th mdepMBank
off_mdepMBank(natural_t i);

To know how many memory banks are installed this method is provided.

<Other public methods of off_mdepMBank. >+= (<-U) [<-D->]
// # of memory banks on intels. 
static natural_t how_many(void);

The number of memory banks is determined according to the last valid memory address, known by looking into the OSKit multiboot information. On intels, we define three memory banks: the IO map and DMA capable first Mbyte, the DMA capable region up to the first 16 Mbytes, and remaining core memory.

<off_mdepMBank::how_many implementation. >= (U->)
// # of memory banks on intels. 
natural_t off_mdepMBank::how_many(void)
{
  extern struct multiboot_info *boot_info;
  extern vm_offset_t            phys_mem_max;

  <Ensure multiboot information is available. >  
  boot_info->mem_upper=phys_mem_max;
  if (boot_info->mem_upper < 1*MBYTE)
    return 1;
  else if (boot_info->mem_upper < 16*MBYTE)
    return 2;
  else 
    return 3;
}

<Off machine dependent memory bank implementation dependencies. >= (U->) [D->]
#include <flux/machine/multiboot.h> // for multiboot_{info,module} et al.
#include <flux/magnitudes.h>    // for KBYTE et al.

\subsubsection{Boot time memory information}

To create a machine dependent memory bank we ask for any boot information and fill it up. We first check that multiboot memory information is available.

<Ensure multiboot information is available. >= (<-U U->)
if (boot_info->flags & MULTIBOOT_MEMORY ==0)
  panic("Unable to determine installed memory.");

<Off machine dependent memory bank implementation dependencies. >+= (U->) [<-D->]
#include <flux/debug.h>         // for panic et al.

As we can see, it depends on the multiboot module information.

After that we set predefined settings depending on the memory bank requested. Finally such settings are adjusted according to the installed memory.

<off_mdepMBank::off_mdepMBank implementation. >= (U->)
off_mdepMBank::off_mdepMBank(natural_t i)
{
  extern struct multiboot_info *boot_info;

  <Ensure multiboot information is available. >
  <Set predefined values for ith bank. >
  <Adjust memory limits according to installed memory. >
}

On intels, we define three memory banks: the IO map and DMA capable first Mbyte, the DMA capable region up to the first 16 Mbytes, and remaining core memory. For each memory bank we define its first valid address (m_first), its last valid address (m_last), the capabilities for the memory being contained (m_flags with bits MF_DMA if DMA is suported, MF_IOM if IO-map is supported), the preferred page sizes (m_pgsz), and the mean access time (m_mat). Besides, we set in m_base and m_end the first and last valid physical addresses.

Note how we forbid 4 Mbyte super-pages on the first 16 Mbytes. They are too precious to allow internal fragmentation (i.e. a single application allocating a super-page and using simply a few pages).

<Set predefined values for ith bank. >= (<-U)
m_base=0x00000000;
m_end =0xfeffffff;
switch(i){
case 0:
  m_first=0x00000000;
  m_last= 1*MBYTE;
  m_flags= OFF_MF_DMA|OFF_MF_IOM;
  m_pgsz[0]= PAGE_SIZE;
  m_pgsz[1]= m_pgsz[2]=m_pgsz[3]=0;
  m_mat=128;
  break;
case 1:
  m_first=1*MBYTE;
  m_last= 16*MBYTE;
  m_flags= OFF_MF_DMA;
  m_pgsz[0]= PAGE_SIZE;
  m_pgsz[1]= m_pgsz[2]=m_pgsz[3]=0;
  m_mat=128;
  break;
case 2:
  m_first=16*MBYTE;
  m_last= 2*GBYTE;
  m_flags= 0;
  m_pgsz[0]= PAGE_SIZE;
  m_pgsz[1]= 4*MBYTE;
  m_pgsz[2]=m_pgsz[3]=0;
  m_mat=128;
  break;
default:
  m_first=m_last=0;
}

<Off machine dependent memory bank implementation dependencies. >+= (U->) [<-D->]
#include <flux/page.h>          // for PAGE_SIZE

We have to define the flags used before.

<Off machine dependent memory bank flag bits. >= (U->)
// flag bits for off_mdepMBanks.
// They are compatible with resource flag bits. 
const unsigned8_t OFF_MF_DMA    = 0x10; // Supports DMA?
const unsigned8_t OFF_MF_IOM    = 0x20; // Supports IO mapping?
const unsigned8_t OFF_MF_PER    = 0x40; // Persists?

%def OFF_MF_DMA OFF_MF_IOM OFF_MF_PER

Finally we ensure that m_first and m_last lie in the range of installed memory can compute the number of page frames installed.

<Adjust memory limits according to installed memory. >= (<-U)
if (boot_info->mem_upper < m_first) 
  m_first=m_last=0;
else if (boot_info->mem_upper < m_last)
  m_last=boot_info->mem_upper;
if (boot_info->mem_upper < m_end)
  m_end=boot_info->mem_upper;

m_npgs= a2p(m_last) - a2p(m_first); // # of pages of the min. page size.

The routine a2p converts an address (or offset) into a PFN (or PFN range).

At any time, the static method get_core_npgs (used before in set_core) can be used to determine the size of the installed physical memory, no matter how many memory banks there are.

<Other public methods of off_mdepMBank. >+= (<-U) [<-D->]
// Returns number of physical page frames installed. 
// 
static vm_size_t   get_core_npgs(void);

Its implementation simply returns the information found in boot_info.

<off_mdepMBank::get_core_npgs implementation. >= (U->)
// Returns number of physical page frames installed. 
// 
vm_size_t   off_mdepMBank::get_core_npgs(void)
{
  extern struct multiboot_info *boot_info;

  return a2p(boot_info->mem_upper);
}

\subsubsection{Conversion routines}

Machine dependent memory banks provide these routines to convert addresses to page frame numbers and vice-versa. They use the minimum preferred page size. A function returning a mask to extract page offsets is provided too.

<Other public methods of off_mdepMBank. >+= (<-U) [<-D->]
// Address to PFN.
static vm_offset_t a2p(vm_offset_t va){ return atop(va); }
// PFN to address. 
static vm_offset_t p2a(vm_offset_t va){ return ptoa(va); }
// Returns the mask for page offsets.
static vm_offset_t pmask(void) { return PAGE_MASK; }
// Returns the minimum preferred page size. 
static vm_size_t get_pgsz(void) { return PAGE_SIZE;}

They rely on \oskit{} routines atop and ptoa.

<Off machine dependent memory bank dependencies. >+= (U->) [<-D]
#include <flux/page.h>          // for atop and ptoa

\subsubsection{Machine dependent mode bits}

Every page frame has a set of bits representing valid access modes supported by the hardware. Actually, those bits are borrowed from the machine dependent address translation machinery.

<Off machine dependent mode bits. >= (U->)
// Mode bits for page frames 
typedef off_mdep_mod_t off_mdep_pgf_t;

<Off machine dependent page frame dependencies. >= (U->)
//#include <dmm/mdep/mAddrTr.h>   // for off_mdep_mod_t XXX fix this.
typedef int off_mdep_mod_t;

\subsubsection{Kernel pages, reserved pages, and malloc pages #2731#>NOTE: Will need to redefined free to free the primary pages, and also redefine every page operation to forward it to every primary page frame. A private iterator over primary pages will be handy. }


next up previous contents
Next: 4.0.6 Memory banks for Up: 4. Exporting the hardware Previous: 4.0.4 Multiple page size
Francisco J. Ballesteros
1998-05-25