[SOS] Pagination

KAISER Edouard edouard.kaiser at gmail.com
Jeu 20 Oct 18:44:34 CEST 2005


Salut à tous !
Bon bah il faut bien s'y résoudre, j'ai pas l'impréssion qu'on est les
outils pour faire du Multi-Segment, alors plutot que faire de la
bidouille avec la segmentation et bien je me met à la pagination,
comme tout le monde :D
Comme l'indique les tutoriaux de SOS il faut être sur qu'avant
d'activer le bit 31 de CR0 le Repertoire des tables et les tables sont
valides sinon ça va donner n'importe quoi.
Pour ne pas prendre des risques, j'ai donc fait pareil : De L'identity
mapping des 8 premiers Mo de la mémoire vive, ce qui est amplement
suffisant pour l'instant, c'est surtout histoire de tester...
Plutôt que de faire un bête copier-coller des fonctions SOS j'ai
souhaité implémenter moi même ma fonction d'Identity mapping.
J'en suis arrivé à un stade ou je pensais que c'était ok, et bien non
impossible de me dépatouiller de de CPULOOP(1) dans bochs, que nous
avons du tous avoir.
Cela se passe bien sur au moment d'activer le bit 31 de CR0.
Je pourrais vous filer un tarball mais je doute que quelqun aura le
courage et le temps de s'y pencher, alors je préfère vous filer mes
deux fonctions qui se battent en duel, peut etre que quelque chose m'a
échappé et qui sera flagrant pour un autre ! :D

/* Structure d'une entree dans le "Repertoire des tables des pages" */
struct x86_page_directory_entry
{
	u8 Present0 : 1;
	u8 Read_Write1 : 1;
	u8 User_Supervisor2 : 1;
	u8 Write_Through3 : 1;
	u8 Cache_Disabled4 : 1;
	u8 Accessed5 : 1;
	u8 Reserved6 : 1;
	u8 PageSize7 : 1;
	u8 GlobalPage8 : 1;
	u8 Avail9_11 : 3;
	u32 PageTable_Address : 20;
} __attribute__ ((packed));

/* Structure d'une entree dans la "Table des pages" */
struct x86_page_table_entry
{
	u8 Present0 : 1;		
	u8 Read_Write1 : 1;
	u8 User_Supervisor2 : 1;
	u8 Write_Through3 : 1;
	u8 Cache_Disabled4 : 1;
	u8 Accessed5 : 1;
	u8 Dirty6 : 1;
	u8 Attribute_Index7 : 1;
	u8 GlobalPage8 : 1;
	u8 Avail9_11 : 3;
	u32 Page_Address : 20;
} __attribute__ ((packed));

static struct x86_page_directory_entry* Page_Directory;
static struct x86_page_table_entry* Page_Table_1;
static struct x86_page_table_entry* Page_Table_2;

/* Initialisation de la pagination */
errno init_paging(void)
{
	int i;
	unsigned int Page_Table_Address;
	struct x86_page_table_entry* Address_Table;
			
	Page_Directory = (struct x86_page_directory_entry*)(0x0);
	Page_Table_1 = (struct x86_page_table_entry*)(0x1000);
	Page_Table_2 = (struct x86_page_table_entry*)(0x2000);
	
	/* Page Direcory 1 */
	Page_Directory->Present0 = 1;
	Page_Directory->Read_Write1 = 0;
	Page_Directory->User_Supervisor2 = 0;
	Page_Directory->Write_Through3 = 0;
	Page_Directory->Cache_Disabled4 = 1;
	Page_Directory->Accessed5 = 0;
	Page_Directory->Reserved6 = 0;
	Page_Directory->PageSize7 = 0;
	Page_Directory->GlobalPage8 = 0;
        /* 20 bits de poid fort */
        Page_Table_Address = (unsigned int)Page_Table_1;
        Page_Table_Address = Page_Table_Address & 0xfffff000;
	Page_Table_Address = Page_Table_Address >> 12;
        /*----------------------*/
	Page_Directory->PageTable_Address = Page_Table_Address;
	
	/* Page Directory 2 */
	(Page_Directory+1)->Present0 = 1;
	(Page_Directory+1)->Read_Write1 = 0;
	(Page_Directory+1)->User_Supervisor2 = 0;
	(Page_Directory+1)->Write_Through3 = 0;
	(Page_Directory+1)->Cache_Disabled4 = 1;
	(Page_Directory+1)->Accessed5 = 0;
	(Page_Directory+1)->Reserved6 = 0;
	(Page_Directory+1)->PageSize7 = 0;
	(Page_Directory+1)->GlobalPage8 = 0;
	/* 20 bits de poid fort */
        Page_Table_Address = (unsigned int)Page_Table_2;
        Page_Table_Address = Page_Table_Address & 0xfffff000;
	Page_Table_Address = Page_Table_Address >> 12;
        /*----------------------*/
        (Page_Directory+1)->PageTable_Address = Page_Table_Address;

	/* On mappe les 8 premiers megaoctets avec la pagination */	
	for(i=0;i<2048;i++)
		insert_identity_translation(i*0x1000);
	
    /* Activation de la pagination */
    __asm__("xor %eax,%eax \n \
                   movl %eax,%cr3 \n \
                   movl %cr0,%eax \n \
                   orl $0x80000000,%eax \n \
                   movl %eax,%cr0");
	
	return OS_SUCCESS;
}

/* Permet d'associer une adresse lineaire "lAddr" a une adresse
virtuelle "vAddr" */
errno insert_identity_translation(lAddr Linear_Address)
{
	unsigned int PDE, PTE, Offset, Page;
	struct x86_page_table_entry* Page_Table_Address;
	
	/* Informations decortiquees de l'adresse lineaire */
	PDE = get_index_PDE(Linear_Address);
	PTE = get_index_PTE(Linear_Address);
	Page = PAGE_ALIGN_INF(Linear_Address);
	Offset = Linear_Address - Page;
	
	/* On recupere l'adresse de la table des pages correspondantes */
	Page_Table_Address = (struct
x86_page_table_entry*)((Page_Directory+PDE)->PageTable_Address);
	
	/*
	 * Initialisation des champs dans la table des pages selon l'index dans
     * l'adresse lineaire.
	 */
	(Page_Table_Address+PTE)->Present0 = 1;
	(Page_Table_Address+PTE)->Read_Write1 = 0;
	(Page_Table_Address+PTE)->User_Supervisor2 = 0;
	(Page_Table_Address+PTE)->Write_Through3 = 0;
	(Page_Table_Address+PTE)->Cache_Disabled4 = 1;
	(Page_Table_Address+PTE)->Accessed5 = 0;
	(Page_Table_Address+PTE)->Dirty6 = 0;
	(Page_Table_Address+PTE)->Attribute_Index7 = 0;
	(Page_Table_Address+PTE)->GlobalPage8 = 0;
	/*
	 * !!! On depasse les 20 bits a partir de Linear_Address = 0x100000 !!!
	 * Il faut donc seulement recuperer les 20bits de poid fort de l'adresse
         * physique comme l'exige la norme Intel.	
	 */
	Page = Page & 0xfffff000;
	Page = Page >> 12;
	(Page_Table_Address+PTE)->Page_Address = Page;
	/*-------------------------------------------------------------*/
	
	return OS_SUCCESS;
}

/* Recupere l'index dans le repertoire des pages a partir d'une
adresse lineaire */
u32 get_index_PDE(lAddr Linear_Address)
{
	return (Linear_Address >> 22);
}

/* Recupere l'index dans la table des pages a partir d'une adresse lineaire */
u32 get_index_PTE(lAddr Linear_Address)
{
	unsigned int Temp;
	
	Temp = (Linear_Address >> 12);

	Temp = Temp & 0x000003ff;	
	
	return Temp;
}

/* Recupere l'offset dans une page a partir d'une adresse lineaire */
u16 get_offset(lAddr Linear_Address)
{
	return (Linear_Address & 0x00000fff);
}


Voila désolés de donner du code comme cela, si vraiment certain
veulent un tarball, je le donnerai =)
Merci !
--
KAISER Edouard.
Wiki-Blog : http://kaiser.edouard.free.fr/
BesOS : http://besos.mtp.epsi.fr/


Plus d'informations sur la liste de diffusion Sos