[SOS] Pagination

Thomas Petazzoni thomas.petazzoni at enix.org
Sam 22 Oct 14:16:54 CEST 2005


Salut,

[ Le mail est long, mais je crois que la solution est au milieu ;-) ]

On Thu, 20 Oct 2005 18:44:34 +0200
KAISER Edouard <edouard.kaiser at gmail.com> wrote:

> /* 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));

À tout hasard, tu as vérifié que sizeof(struct x86_page_table_entry)
est bien égal à 4 ?

> 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;

À mon avis ici, ça serait plus simple de supposer que Page_Table_1 est
forcément alignée sur une frontière de 4k octets. Je ne pense pas que
ce soit la peine de faire l'alignement toi-même: si elle n'est pas
alignée, c'est qu'il y a un problème dans ton code. Autant ne pas le
cacher.

>         /*----------------------*/
> 	Page_Directory->PageTable_Address = Page_Table_Address;
> 	
> 	/* Page Directory 2 */
> 	(Page_Directory+1)->Present0 = 1;

Tu peux aussi écrire 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;

Pareil ici.

>         /*----------------------*/
>         (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;

Pareil ici: suppose que Linear_Address est aligné sur une frontière de
4 Ko. Tu peux mettre un truc du genre:

 ASSERT (PAGE_ALIGN_INF (Linear_Address) == Linear_Address);

> 	/* On recupere l'adresse de la table des pages
> correspondantes */ 


> Page_Table_Address = (struct
> x86_page_table_entry*)((Page_Directory+PDE)->PageTable_Address);

Je pense que le problème est ici. Le champ PageTable_Address ne
contient que les 20 bits de poids fort de l'adresse de la table de
pages. Je verrais plutôt un truc du genre:

Page_Table_Address = 
   (struct x86_page_table_entry *)
   (Page_Directory[PDE].PageTable_Address << 12);

> 	/*
> 	 * Initialisation des champs dans la table des pages selon
> l'index dans
>      * l'adresse lineaire.
> 	 */
> 	(Page_Table_Address+PTE)->Present0 = 1;

Tu peux aussi écrire 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 !!!

Le problème là, ce n'est pas vraiment qu'à partir de 0x100000 on
dépasse les 20 bits. C'est surtout que le processeur veut _seulement_
les 20 bits de poids fort, car de toute façon, les 12 bits de poids
faible sont forcément à 0, puisqu'on est aligné sur 4 Ko (2^12 = 4096 =
4 Ko).

> 	 * 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;
> }

> Voila désolés de donner du code comme cela, si vraiment certain
> veulent un tarball, je le donnerai =)

Dans tous les cas, c'est mieux de donner un tarball (enfin l'URL d'un
tarball posé sur un FTP quelconque). Ça permet de tester, de débugger,
etc. Parfois, juste en lisant le code, ce n'est pas évident de trouver
le problème.

Bonne journée,

Thomas
-- 
PETAZZONI Thomas - thomas.petazzoni at enix.org 
http://{thomas,sos,kos}.enix.org - Jabber: thomas.petazzoni at jabber.dk
http://{agenda,livret}dulibre.org
Fingerprint : 0BE1 4CF3 CEA4 AC9D CC6E  1624 F653 CB30 98D3 F7A7
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://the-doors.enix.org/pipermail/sos/attachments/20051022/690c7338/attachment.pgp


Plus d'informations sur la liste de diffusion Sos