Page 2 of 2

Posted: Tue Jul 31, 2007 1:23 am
by AndrewAPrice
gmoney wrote:i have paging working i just dont use it cause im not getting how virtural mem works
Do you know what a page table/page directory is? Well, give each process a page directory. A directory is a list of 1024 pointers to page tables. Each page table is a list of 1024 pointers to pages. Look in the Intel manuals or one of the hundreds of online references for the specifics (it's really quiet easy once you know what you're doing).

Then to enable paging, set the paging bit of CR0 to 1.

Then when you switch between processes, set CR3 to the physical address of the page directory.

But remember to keep the kernel always mapped (I use physical mapping for this). You don't need to keep the page tables/directories mapped (unless you want to modify it), just floating around somewhere out in the void. Just store the address of it.

Posted: Tue Jul 31, 2007 3:05 am
by enrico_granata
maybe this is too stupid.. : cry :
I would like to setup paging in such a way that all addresses that exist in physical memory reference themselves as linear addresses and all addressed beyond the end of physical memory cause a page fault
Is this possible? And if so, would it make my paging transparent (example, address 0xABCDEF goes to physical address 0xABCDEF if physical RAM is big enough, otherwise it just causes a page fault)?

Thanks

Posted: Tue Jul 31, 2007 3:36 am
by AJ
Yes, that is certainly possible although I would suggest it has limited value.

Simply page-in all physical RAM and do not page in any ram that does not exist.

Cheers,
Adam

Posted: Tue Jul 31, 2007 5:04 am
by AndrewAPrice
enrico_granata wrote:maybe this is too stupid..
Nothing's too stupid
enrico_granata wrote:: cry :
Aww.. it's okay, we were all in this position once aswell.
enrico_granata wrote: I would like to setup paging in such a way that all addresses that exist in physical memory reference themselves as linear addresses and all addressed beyond the end of physical memory cause a page fault
Is this possible? And if so, would it make my paging transparent (example, address 0xABCDEF goes to physical address 0xABCDEF if physical RAM is big enough, otherwise it just causes a page fault)?
What you need to do is the following:

Code: Select all

 - Find out how much memory you have.
 - Allocate 4kb somewhere in memory to story the page directory.
 - Loop from 0 to the amount of memory you have in 4096 byte increments
    - Is the current page table full? (Or does not one exist?)
            - Yes
                  - Allocate 4kb in memory for the page table.
                  - Set the next position in the page directory to this table's location.
                  - Set the page directory entry bit for so the MMU knows it exists.
     - Set the next page table entry to the location of the memory pointer (the one that is incrementing through the memory).
 - Move the page directory's address to CR3.
 - Set the paging bit in CR0 to true.
EDIT: In code tags so it doesn't mess up the formatting.
To link a 4kb memory address to an entry, use the following: (make sure entries, page table/directory locations are aligned to the nearest 4KB)

Code: Select all

m_pageTable[i] = address | 31;
Where m_pageTable points to the area in memory where your page table exists (each entry it 4 bytes long, 1 int = 4 kbytes, so make it a pointer to an int). The "| 131" does a binary OR to enable bits 1 and 0 (meaning supervisor, r/w, present) of the entry.

In C/C++, to enable the paging bit of CR0 use:

Code: Select all

write_cr0(read_cr0() | 0x80000000);
In this example, write_cr0 sets the value of cr0 to the parameter in assembly, and read_cr0 returns the value of cr0.

Posted: Tue Jul 31, 2007 2:15 pm
by gmoney

Code: Select all

#include <types.h>
#include <mm/mm.h>
#include <port.h>


/***************************************/
//Structs
typedef struct tagMemBlock {
	uint32_t	*adress;
	uint32_t	size;
	
	struct tagMemBlock *next;

} __attribute__ ((packed)) MemBlock;

typedef struct tagMemList {
	MemBlock *head;
	MemBlock *tail;
} __attribute ((packed)) MemList;

/***************************************/
//Global Variables
uint32_t *PageDirectory;
uint32_t *PageTable;

//For the Heap
MemList FreeBlocks;
MemList UsedBlocks;
uint32_t HeapTail;
uint32_t HeapStart;


/**************************************************************************************************************************/
/**************************************************************************************************************************/
/**************************************************************************************************************************/
/**************************************************************************************************************************/
void SetupPaging()
{
	
	
	PageDirectory 	= (uint32_t *) 0x200000;
	PageTable 		= (uint32_t *) 0x201000;

	uint32_t i = 0;
	uint32_t j = 0;
	
	for (; i < 1024; i++)
	{
		PageDirectory[i] 	= 	(uint32_t)(PageTable + (4096 * i));
		PageDirectory[i] 	= 	PageDirectory[i] | PAGE_RW | PAGE_PRE;
	}
	
	MapMemory( 0, 0, (1024*1024), PAGE_PRE | PAGE_RW);
	
	//Kernel + BIOS + RM-VT ETC.. -> 0 - 0xFFFFF = 0x100 Pages
	MapMemory( 0, 							0, 							0x200, 	PAGE_RW | PAGE_PRE);
	
	//PageDirectory -> 0x100000 - 0x100FFF (1024 Entrys of 4 bytes) = 1 Page
	MapMemory( (uint32_t)PageDirectory, 	(uint32_t)PageDirectory, 	1, 		PAGE_RW | PAGE_PRE);
	
	//PageTable -> 0x101000 - 0x500FFF (1024 DirEntrys * 1024 TblEntry of 4 bytes) = 1024 Pages
	MapMemory( (uint32_t)PageTable, 		(uint32_t)PageTable, 		1024, 	PAGE_RW | PAGE_PRE);

	LoadPageDirectory((uint32_t)PageDirectory);
	
	FreeBlocks.head = NULL;
	FreeBlocks.tail = NULL;
	
	UsedBlocks.head = NULL;
	UsedBlocks.tail = NULL;
	
	HeapStart	= 0x601000;
	HeapTail 	= 0;
	
	
};

/**************************************************************************************************************************/
/**************************************************************************************************************************/
/**************************************************************************************************************************/
/**************************************************************************************************************************/
uint8_t LoadPageDirectory(uint32_t _pd)
{
	if (_pd & 0xFFF) return 0;
	WriteCr( _pd, 3);
	WriteCr( (ReadCr(0) | 0x80000000) , 0);
	
	return 1;
}


/**************************************************************************************************************************/
/**************************************************************************************************************************/
/**************************************************************************************************************************/
/**************************************************************************************************************************/
uint8_t SetPage ( uint32_t _vAdress, uint32_t _phyAdress, uint32_t _opt)
{

	_vAdress 	= _vAdress 		& 0xFFFFF000;
	_phyAdress 	= _phyAdress 	& 0xFFFFF000;
	
	uint32_t table 	= _vAdress >> 22;
	uint32_t entry  = (_vAdress << 10) >> 22;
	
	if (table < 1024 && entry < 1024)
	{
		uint32_t *PT = (uint32_t *)(PageDirectory[table] & 0xFFFFF000);
		PT[entry] = _phyAdress | _opt;
		return 1;
	}
	return 0;
};



/**************************************************************************************************************************/
/**************************************************************************************************************************/
/**************************************************************************************************************************/
/**************************************************************************************************************************/
uint8_t MapMemory ( uint32_t _vAdress, uint32_t _phyAdress, uint32_t _lenght, uint32_t _opt)
{
	while (_lenght > 0)
	{
		uint8_t state = SetPage(_vAdress, _phyAdress, _opt);
		_vAdress 	+= 0x1000;
		_phyAdress 	+= 0x1000;
		_lenght--;
		
		if (!state)
			return 0;
	}
	return 1;
};

/**************************************************************************************************************************/
/**************************************************************************************************************************/
/**************************************************************************************************************************/
/**************************************************************************************************************************/
int32_t GetEmptyPDE()
{
	uint32_t i;
	for (i = 0; i < 1024; i++)
	{
		if (PageDirectory[i] == 0) return i;
	
	}
	return -1;
};

/**************************************************************************************************************************/
/**************************************************************************************************************************/
/**************************************************************************************************************************/
/**************************************************************************************************************************/
int32_t GetEmptyPTE(uint32_t _pde)
{
	uint32_t *ptbl = (uint32_t *)(PageDirectory[_pde] & 0xFFFFF000);
	uint32_t i;
	for (i = 0; i < 1024; i++)
	{
		if (ptbl[i] == 0) return i;
	
	}
	return -1;
};


/**************************************************************************************************************************/
/**************************************************************************************************************************/
/**************************************************************************************************************************/
/**************************************************************************************************************************/
void *realloc(void *_adress, uint32_t _more)
{

	return (void *) 0;
};

/**************************************************************************************************************************/
/**************************************************************************************************************************/
/**************************************************************************************************************************/
/**************************************************************************************************************************/
void *malloc(uint32_t _size)
{
	/*********************************/
	/* Search for Blocks which have 
	   exact the same size as the 
	   requestet one.
	*/
	MemBlock *tmp 	= FreeBlocks.head;
	MemBlock *last	= NULL;
	
	if (tmp != NULL)	//If min. one Freeblock exists
	{	
		while (tmp->next != NULL && tmp->size != _size)
		{
			last = tmp;
			tmp = tmp->next;
		} 
		
		/*********************************/
		/* If not found search one which
		   is bigger wheter the requestet
		   one.
		*/
		if (tmp->size != _size)
		{
			tmp = FreeBlocks.head;
			last = NULL;
			while (tmp->next != NULL && tmp->size < _size)
			{
				last = tmp;
				tmp = tmp->next;
			} 
		}
		
		/*********************************/
		/* If a block is found which
		   is bigger or which has the
		   same size take it from the
		   FreeBlockList and put that
		   in the UsedBlockList.
		*/
		if (tmp->size >= _size)
		{
			if (last == NULL) //<-- If its the first entry
			{
				FreeBlocks.head = tmp->next;
				
				if (tmp->next == NULL)
				{
					FreeBlocks.tail = last;
					FreeBlocks.tail->next = NULL;
				}
			}
			else if (tmp->next == NULL) //<-- If its the last entry
			{
				FreeBlocks.tail = last;
				FreeBlocks.tail->next = NULL;
			}
			else						//<<- if its in the middle of the list
			{
				last->next = tmp->next;
			}
			
			if (UsedBlocks.tail != NULL) UsedBlocks.tail->next = tmp;
			if (UsedBlocks.head == NULL) UsedBlocks.head = tmp;
			
			UsedBlocks.tail = tmp;
			tmp->next = NULL;
			
			//make something if the free space is bigger wheter the requestet place...
			return (void *)tmp->adress;
		}
	
	}
	/*********************************/
	/* If no block was found make a new
	   one at the end of UsedBlocks.
	*/
	tmp = (MemBlock *) HeapStart + HeapTail;
	HeapTail += sizeof(MemBlock) + _size;
	
	if (UsedBlocks.tail != NULL) UsedBlocks.tail->next = tmp;
	if (UsedBlocks.head == NULL) UsedBlocks.head = tmp;
	
	UsedBlocks.tail = tmp;
	tmp->next = NULL;
	tmp->size = _size;
	tmp->adress = (uint32_t*)((uint32_t)tmp + sizeof(MemBlock));
	
	return (void *)tmp->adress;
};
note that my kernel is loaded at the 1meg mark thanks to grub. now how would i implement a v memory management with the code above.

Posted: Wed Aug 01, 2007 12:20 am
by enrico_granata
8) thanks a lot... I am going to try and see how much I can figure out of this code
I can even see why setting up this kind of paging is not very worthy, but I just want to type in addresses (at kernel-level) and know where they "go" in memory..I guess I will have to change this and remap pages when I start loading ELF binaries (which is why I am dealing with paging at all :!: )

Posted: Wed Aug 01, 2007 3:26 am
by enrico_granata
just some feedback, to know if I am getting things right (please) :wink:

Code: Select all

   for (; i < 1024; i++) 
   { 
      PageDirectory[i]    =    (uint32_t)(PageTable + (4096 * i)); 
      PageDirectory[i]    =    PageDirectory[i] | PAGE_RW | PAGE_PRE; 
   } 
this code sets each entry of the page directory to find its page table at 4KB after the previous one (the first one goes at PageTable, the second at PageTable + 4K, ... and so forth) and sets the i-th page table to be present and available for r/w

Code: Select all

MapMemory( 0, 0, (1024*1024), PAGE_PRE | PAGE_RW);
this call is meant to map the 1st 1024*1024 pages so that linear and physical addresses match

Code: Select all

uint8_t SetPage ( uint32_t _vAdress, uint32_t _phyAdress, uint32_t _opt) 
{ 

   _vAdress    = _vAdress       & 0xFFFFF000; 
   _phyAdress    = _phyAdress    & 0xFFFFF000; 
    
   uint32_t table    = _vAdress >> 22; 
   uint32_t entry  = (_vAdress << 10) >> 22; 
    
   if (table < 1024 && entry < 1024) 
   { 
      uint32_t *PT = (uint32_t *)(PageDirectory[table] & 0xFFFFF000); 
      PT[entry] = _phyAdress | _opt; 
      return 1; 
   } 
   return 0; 
}; 
and eventually this maps the page at _vAdress to physical address _phyAdress

Code: Select all

   _vAdress    = _vAdress       & 0xFFFFF000; 
   _phyAdress    = _phyAdress    & 0xFFFFF000; 
    
   uint32_t table    = _vAdress >> 22; 
   uint32_t entry  = (_vAdress << 10) >> 22; 
and here it chooses the correct page directory entry the correct page entry to store the pointers? So, the memory I have to reserve for the page directory/tables is as large as required by the largest address I map (4MB if I want to map the whole address space, right?)

Thanks in advance :!:

Posted: Wed Aug 01, 2007 6:06 am
by gmoney
U GOT IT