implementing paging

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
redDot
Member
Member
Posts: 29
Joined: Sat Jan 26, 2008 2:48 am

implementing paging

Post by redDot »

hello friends,
have been following the james molly os tutorial (to develop my own kernel for acadamics purpose. I am trying to implement paging, but am facing several problems in this regards. after some debugging of the code given in the tutorial, and reading the source code, i finally could do things to some extent. i tried INT $0xE after initializing the page fault n the result was as expected. however, in the tutorial there is a test to check the page fault, which is to write the code...

Code: Select all

u32int *ptr = (u32int*)0xA0000000;
   u32int do_page_fault = *ptr;
which is suppose to cause a page fault by reading the location 0xA0000000. But nothing like this happens. There is no message of page fault displayed on the screen.
could you please tell me why should a page fault occur by the above code ?
we have written functions..

Code: Select all

void alloc_frame(page_t* page, int is_kernel, int is_writeable);
void free_frame(page_t* page);
void initialise_paging();
void switch_page_directory(page_directory_t* dir);
page_t* get_page(u32int address, int make, page_directory_t* dir);
void page_fault(struct regs reg1);


out of which only page_fault is being used. whats the need to write the rest ??? also at one place alloc_frame function is used for identity map ..

Code: Select all

while (i < placement_address)
   {
       // Kernel code is readable but not writeable from userspace.
       alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
       i += 0x1000;
   }
could you please tell me why is that required.
I am all very confused, and it would be gr8 if you could summarise what exactly is happening. how is paging implemented. I have done a course on operating systems, so am familiar with the theory of paging.

Enabled BBcode to make the post more readable - Combuster
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Post by AJ »

Hi,

The reason your first code snippet:

Code: Select all

 
u32int *ptr = (u32int*)0xA0000000; 
u32int do_page_fault = *ptr;


should cause a page fault is because 0xA0000000 is not paged in and you attempt to read from it (you assign the value stored at this location to 'do_page_fault'). You will only get a message printed on the screen if your PFE handler fires, which will only happen a) if you have a propertly installed IDT and b) if this location is definitely not paged in already. If you do not have an IDT, the CPU will triple fault. If the area is already paged, you will see nothing. If GCC is optimising, I believe you sometimes have to use the variable for anything to happen (try adding do_page_fault++).

Those other functions you have given the prototypes for are fairly essential to your paging system whether or not you have used them to date. You will need to allocate and free physical frames and so on. You will possibly only use switch_page_directory when you have multitasking enabled. Maybe molly :twisted: can help expand on this as I haven't read this tutorial thoroughly...
I am all very confused, and it would be gr8 if you could summarise what exactly is happening. how is paging implemented. I have done a course on operating systems, so am familiar with the theory of paging.
In which case, most of this stuff should be fairly bread and butter to you. I'm sorry to end with a RTFM-type answer (I try not to do it too much), but please see the wiki (link at top of page), http://www.osdever.net and last but definitely not least, the Intel manuals which are freely available in hard copy or for download.

Cheers,
Adam
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post by JamesM »

Hi,

BEGIN COPY PASTE OF THE REPLY I JUST SPENT 20 MINUTES CRAFTING AFTER YOU EMAILED ME PERSONALLY AND I DIDN'T KNOW YOU HAD CROSS POSTED AS WELL. <--- I hope you notice that this is in caps and bold.

--------------------------------------------------------------------------------------

Hi Tushar,

First of all I'd like to thank you for reading my tutorials, and I hope they are helping you learn.

The purpose of identity mapping is to allow the processor to still access the kernel when paging is enabled. Consider that paging is enabled, but no identity mapping has occurred.
The processor tries to read the next instruction, for example at 0x100004. This gets treated as a virtual address, and is sent to the MMU for translation to a physical address. The MMU has no
knowledge of how to convert 0x100004 to a physical address, so a page fault occurs. In this case the interrupt service routines will also be virtual addresses that the MMU will fail to translate,
and so the system will triple-fault and reset.
The answer is to map. That is - tell the MMU that the virtual address area from 0x100000 to for example 0x200000 should map to some physical address region such as 0x100000 to 0x200000. Then,
the MMU can translate virtual addresses to physical addresses and the processor can execute instructions in the kernel.
Now, why *identity* map? Well, if you compile with -fPIC (Position Independent Code), there is no need to! but if you don't, your code will contain references to *absolute* addresses, such as
mov eax, [0x100008] .
So the virtual addresses for areas in your kernel *must* map to the *same* physical addresses, or your code will crash!

I'll try to explain the uses of each function one by one.

Code: Select all

void alloc_frame(page_t* page, int is_kernel, int is_writeable);
void free_frame(page_t* page);

These functions allocate and free *frames*. Depending on how you were taught at university, you may not have used the term 'frame' before, so I will quickly explain what they are here.
A (normally 4 kilobyte) section of *virtual memory* is called a 'page'. A (normally 4 kb) section of *physical memory* is called a 'frame'. So when one maps virtual addresses to physical addresses, one
is really "putting a page in a frame". When you need to allocate one or more pages of virtual memory, you therefore need one or more frames available to map them to. In order to ensure that frames are
not allocated twice accidentally (resulting in data getting trampled), these routines are provided.
The first one takes a page that you want mapped into physical memory, and 0/1 values saying whether the
mapping should be available to all levels of code, or just kernel mode code, and whether the mapping should be read-only (only takes effect in user-mode code).
The second frees an allocated mapping of a page to a frame.

Code: Select all

void initialise_paging();

This function initialises paging. It sets up a new page directory and identity maps the area where the kernel lives (see above). *This function MUST be called for paging to be enabled*! If you
don't call this, your code will *not* be running in paged mode! (this could explain why you weren't recieving page faults - 0xA0000000 in physical memory is normally mapped to the VESA graphics framebuffer).
This function calls alloc_frame, get_page, and switch_directory.

Code: Select all

void switch_page_directory(page_directory_t* dir);

This function changes virtual memory space. It writes 'dir' into the control register 'CR3', which changes the virtual->physical mappings. It is called once from initialise_paging().

Code: Select all

page_t* get_page(u32int address, int make, page_directory_t* dir);

This function, given a page directory, will attempt to find a pointer to a Page Table Entry for the given virtual address. It is used when creating mappings for virtual to physical addresses. The
'make' parameter tells the function what to do if the Page Table the requested Page Table Entry resides in has not been created. If '1', it will create the Page Table, if '0' it will not and return NULL.

Code: Select all

void page_fault(struct regs reg1);

Handles a page fault. Should be mapped to interrupt 14.


So in conclusion,

Make sure that you are calling "initialise_paging" before attempting a page fault.

In response to:
could you please tell me why should a page fault occur by the above code ?

Simple. When initialise_paging is called, it identity maps the first, e.g. 2MB of memory. 0xA0000000 is about 3GB into addressable RAM, and has not been mapped. So the MMU shouldn't know how to handle
an access to it, and should throw a page fault.

Any more questions, do ask,

James

EDIT: JamesM: Added BBCode and swore at AJ for his "molly" comment ;)
redDot
Member
Member
Posts: 29
Joined: Sat Jan 26, 2008 2:48 am

Post by redDot »

I found the bug, It was in the page_t structure, I had to write u32int present :1 ; instead of u32int present ; so that that field would be of 1 bit.
But there is now another problem. Its causing triple fault, and the VM gets reset. I traced out the code, putting an infinite loop after each line in the initialise_paging(), and finally got the culprit. Its in

[code]

void switch_page_directory(page_directory_t *dir)
{
current_directory = dir;
__asm__ __volatile__("mov %0, %%cr3":: "r"(&dir->tablesPhysical));

u32int cr0;
__asm__ __volatile__("mov %%cr0, %0": "=r"(cr0));
cr0 |= 0x80000000; // Enable paging!
for(;;);
__asm__ __volatile__("mov %0, %%cr0":: "r"(cr0));

}
[\code]

the line after the for(;;); is causing the triple fault...
please help...
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

the line after the for(;;); is causing the triple fault...
it means your page tables are still borked :roll:

Have you tried using the bochs debugger to see what's exactly in the page tables?
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
redDot
Member
Member
Posts: 29
Joined: Sat Jan 26, 2008 2:48 am

Post by redDot »

the error was in the kheap.c file, i had wrongly written the code as

Code: Select all

u32int kmalloc_a(u32int sz)
{
    return kmalloc_int(sz, 0, 0);
}
and hence the alignment problem was there.
i have changed it to

Code: Select all

u32int kmalloc_a(u32int sz)
{
    return kmalloc_int(sz, 1, 0);
}
now no more triple faults are ocurring, but i am back to square 1 now.
The page fault is still not happening ???
bpaterni
Posts: 12
Joined: Sat May 30, 2009 4:38 pm

Re: implementing paging

Post by bpaterni »

I'm also stuck on this part of James' tutorial... with the same symptom as well.

The page fault is simply not occurring as it should with these two lines of code:

Code: Select all

	unsigned int *ptr = (unsigned int *)0xA0000000;
	unsigned int do_page_fault = *ptr;
I've added 'do_page_fault++;' as AJ suggests, but my screen still comes up empty in bochs as well as on my test machine.

I can get the interrupt to register by issuing 'int $0xE' so my IDT is not the problem.

This post is over a year old so I'm hoping somebody found an answer as to why the interrupt isn't being raised when it should.

Thank you for any help.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: implementing paging

Post by Combuster »

Have you even enabled paging?
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
bpaterni
Posts: 12
Joined: Sat May 30, 2009 4:38 pm

Re: implementing paging

Post by bpaterni »

Well I believe so:

00162600000i[CPU0 ] | CR0=0xe0000011 CR2=0x0000000000000000
00162600000i[CPU0 ] | CR3=0x00108000 CR4=0x00000000
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Re: implementing paging

Post by JamesM »

bpaterni wrote:I'm also stuck on this part of James' tutorial... with the same symptom as well.

The page fault is simply not occurring as it should with these two lines of code:

Code: Select all

	unsigned int *ptr = (unsigned int *)0xA0000000;
	unsigned int do_page_fault = *ptr;
I've added 'do_page_fault++;' as AJ suggests, but my screen still comes up empty in bochs as well as on my test machine.

I can get the interrupt to register by issuing 'int $0xE' so my IDT is not the problem.

This post is over a year old so I'm hoping somebody found an answer as to why the interrupt isn't being raised when it should.

Thank you for any help.
Try writing to the pointer instead of reading from it. Or declaring the pointer volatile. GCC will sometimes kill reads that don't do anything as part of dead code elimination.
bpaterni
Posts: 12
Joined: Sat May 30, 2009 4:38 pm

Re: implementing paging

Post by bpaterni »

Ha, that did the trick. I was starting to wonder if all this memory protection talk was some kind of joke. :)

Thanks for the help James.
Post Reply