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. >
};
Definesoff_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_mdepMBankimplementation. >= (U->) off_mdepMBank::off_mdepMBank(natural_t i) { extern struct multiboot_info *boot_info; <Ensure multiboot information is available. > <Set predefined values forith 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
We must provide two methods to detect memory allocation status at boot time. The first one detects available memory.
<Other public methods of off_mdepMBank. >+= (<-U) [<-D]
// Finds the next contiguous set of free pages at or after va.
// If no such block is found in this container
// va is set to the last valid address and size to zero.
void find_free(vm_offset_t &va, vm_size_t &size) const;
We search the malloc_lmm (already initialized by the OSKit to
reflect the state of core memory) for any free pages.
<off_mdepMBank::find_freeimplementation. >= (U->) // Finds the next contiguous set of free pages at or after va. // If no such block is found in this container // va is set to the last valid address and size to zero. void off_mdepMBank::find_free(vm_offset_t &va, vm_size_t &size) const { lmm_flags_t flags; // flags for free area do { lmm_find_free(&malloc_lmm,&va,&size,&flags); // size==0 when not found if (size) if (size > PAGE_SIZE ){ <Remove any partial free page from chunk atvasizedsize. > } else va += size; } while (size && size < PAGE_SIZE && va < m_last); if (!size || va >= m_last){ va=m_last; size=0; } else { <Remove free space atvasizedsizefrom themalloc_lmm. > } }
<Off machine dependent memory bank implementation dependencies. >+= (U->) [<-D] #include <flux/lmm.h> // for lmm_find_free et al. #include <malloc.h> // for malloc_lmm
The tricky part is to remove any partial free page at the start or end
of the free memory detected by lmm_find_free. First we take the
page offset from va and subtract remaining bytes (past that
offset) from the size. Then we round va to the next page
boundary if the offset was non-null. Finally we truncate size to a
multiple of the page size to ignore any trailing partial free page.
<Remove any partial free page from chunk atvasizedsize. >= (<-U) size -= (PAGE_SIZE-(va&PAGE_MASK)); va=trunc_page(va)+ptoa((va&PAGE_MASK)?1:0); size=trunc_page(size);
Besides, we will allocate any free page frame in the \oskit{}
malloc_lmm. In that way the OSKit implementation of malloc
will not have free memory. Thus it will not mess up page allocation.
<Remove free space atvasizedsizefrom themalloc_lmm. >= (<-U) lmm_remove_free(&malloc_lmm, (void*)va, size);
\subsubsection{Machine dependent memory banks \cpp{} source files}
We maintain it all in hw/mdep/mMBank.h and hw/mdep/mMBank.C.
<mdep mMBank.h*>= <Read the literate code instead warning. > #ifndef __OFF_MDEP_MBANK_H #define __OFF_MDEP_MBANK_H 1 <Off machine dependent memory bank dependencies. > <Off machine dependent memory bank flag bits. > #ifdef __KERNEL__ <Off machine dependent memory bank. > #endif // __KERNEL__ #endif // __OFF_MDEP_MBANK_H
<mdep mMBank.C*>= <Read the literate code instead warning. > #include <hw/mdep/mMBank.h> // Exported interface. <Off machine dependent memory bank implementation dependencies. > <Off machine dependent memory bank static members. > <off_mdepMBank::off_mdepMBankimplementation. > <off_mdepMBank::how_manyimplementation. > <off_mdepMBank::find_freeimplementation. > <off_mdepMBank::get_core_npgsimplementation. >
Machine dependent page frame data types are kept in
mdep/mPFrame.h.
<mdep mPFrame.h*>= <Read the literate code instead warning. > #ifndef __OFF_MDEP_PFRAME_H #define __OFF_MDEP_PFRAME_H 1 <Off machine dependent page frame dependencies. > <Off machine dependent mode bits. > #endif // !__OFF_MDEP_PFRAME_H
va to fva. >: U1, D2
off_CompResource::make_available. >: U1
off_BankNav. >: U1, D2
off_MBank. >: U1, D2, D3
mbank inspector attribute array initializer. >: D1, U2
mbank inspector attribute array length. >: D1, U2
pframe inspector attribute array initializer. >: D1, U2
off_BankNav::get_next implementation. >: D1, U2
off_BankNav::operator[] implementation. >: D1, D2, U3
off_BankNav::reset implementation. >: D1, U2
off_Magic::nameof case for m_numbers. >: D1, D2
off_MBank::alloc and free implementation. >: D1, U2
off_MBank::allocate_kmem implementation. >: D1, U2
off_MBank::can_melt implementation. >: D1, U2
off_MBank::cleanup implementation. >: D1, U2
off_MBank::copy_state implementation. >: D1, U2
off_MBank::freeze_state implementation. >: D1, U2
off_MBank::get_inspector implementation. >: D1, U2
off_MBank::get_kend implementation. >: D1, U2
off_MBank::get_navigator implementation. >: D1, U2
off_MBank::get_pgsize implementation. >: D1, U2
off_MBank::get_url implementation. >: D1, U2
off_MBank::melt_state implementation. >: D1, U2
off_MBank::nameof implementation. >: D1, U2
off_MBank::notify implementation. >: D1, U2
off_MBank::operator<< implementation. >: D1, U2
off_MBank::operator= implementation. >: D1, U2
off_MBank::restore_state implementation. >: D1, U2
off_MBank::set_core implementation. >: D1, U2
off_MBank::start implementation. >: D1, U2
off_mdepMBank::find_free implementation. >: D1, U2
off_mdepMBank::get_core_npgs implementation. >: D1, U2
off_mdepMBank::how_many implementation. >: D1, U2
off_mdepMBank::off_mdepMBank implementation. >: D1, U2
off_PFrame::copy_state implementation. >: D1, U2
off_PFrame::get_inspector implementation. >: D1, U2
off_PFrame::get_url_holder implementation. >: D1, U2
off_PFrame::off_PFrame implementation. >: D1, U2
off_PFrame::operator delete implementation. >: D1, U2
off_PFrame::operator<< implementation. >: D1, U2
off_PFrame::operator new implementation. >: D1, U2
off_PFrame::restore_state implementation. >: D1, U2
off_PgAllocator::off_PgAllocator implementation. >: D1, U2
off_PgAllocator::set_core implementation. >: D1, U2
off_SMBank::alloc implementation. >: D1
off_SMBank::get_pgsize implementation. >: D1
off_SMBank::off_SMBank implementation. >: D1
off_SMBank::operator+,a2p,p2a and pmask implementation. >: D1
off_BankNav. >: U1, D2
off_MBank. >: U1, D2, D3, D4, D5, D6
off_PFrame. >: U1, D2
off_PgAllocator. >: U1, D2, D3
off_MBank. >: U1, D2, D3
off_MBank. >: U1, D2, D3, D4, D5
off_PFrame. >: U1, D2, D3
off_LPFrame. >: U1, D2, D3
off_MBank. >: U1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, D16, D17, D18, D19, D20, D21, D22, D23
off_mdepMBank. >: U1, D2, D3, D4, D5, D6
off_PFrame. >: U1, D2, D3, D4, D5, D6, D7, D8, D9
off_PgAllocator. >: U1, D2, D3, D4, D5
off_SMBank. >: U1, D2, D3, D4
va sized size. >: U1, D2
va sized size from the malloc_lmm. >: U1, D2
ith bank. >: U1, D2
off_MBank according to mdep. >: U1, D2, D3, D4, D5
%% --------------------------------------------------------------
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%