OSDev.org

The Place to Start for Operating System Developers
It is currently Fri Mar 29, 2024 5:38 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 11 posts ] 
Author Message
 Post subject: [solved] Page fault cause - present and write
PostPosted: Wed May 02, 2018 4:23 pm 
Offline
Member
Member

Joined: Tue Apr 24, 2018 9:46 pm
Posts: 74
I don't understand why my code triggers a page fault with the write and present bits set.

I am following James Molloy's tutorial. The fault occurs when I am initializing paging. The problem seems to be when the function create_heap makes a call to orderedArray_place:
Code:
heap_t *create_heap ( u32int start, u32int end, u32int max, u8int supervisor, u8int readonly )
{
   //
   heap_t *heap = ( heap_t * ) kmalloc( sizeof( heap_t ) );

   ...

   // Initialize the index
   heap -> index = orderedArray_place( ( void * ) start, HEAP_INDEX_SIZE, &header_t_less_than );  // <---
   ...


create_heap is called by initialise_paging as follows:
Code:
   // Initialise the kernel heap.
   kheap = create_heap( KHEAP_START, KHEAP_START + KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0 );


And the values of the constants are:
Code:
#define KHEAP_START         0xC0000000  // arbitrary
#define KHEAP_INITIAL_SIZE  0x100000    // arbitrary
#define HEAP_INDEX_SIZE     0x20000     // arbitrary


The fault appears when a call to memset in orderedArray_place tries to write zeros to the given location...
Code:
// Create an ordered array (uses given start location)
ordered_array_t orderedArray_place ( void *address, u32int max_size, lessthan_predicate_t less_than )
{
   ordered_array_t a;

   a.array = ( type_t * ) address;
   memset( ( u32int * ) address, 0, max_size * sizeof( type_t ) );  // fill with zeros <---

   ...


I.e. during a write to the range KHEAP_START to (KHEAP_START + HEAP_INDEX_SIZE * sizeof( type_t )). What is preventing me from writing here?

My full code is here. The relevant files (I think) are kernelHeap, orderedArray, and paging.

By the way, type_t is declared as follows:
Code:
typedef void* type_t;


Last edited by quadrant on Fri May 04, 2018 1:10 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Page fault cause - present and write
PostPosted: Thu May 03, 2018 1:34 am 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4591
Location: Chichester, UK
Have you tried single-stepping through the offending code in a debugger? This should give you an insight into the error.

It is really a very good idea to practise this sort of debugging whilst the code is still relatively simple. You will then be in a good position to investigate more serious errors.

For starters, you may want to look closely at your memset() function. Could you be making the very common C error with regard to pointer arithmetic?


Top
 Profile  
 
 Post subject: Re: Page fault cause - present and write
PostPosted: Thu May 03, 2018 2:50 pm 
Offline
Member
Member

Joined: Tue Apr 24, 2018 9:46 pm
Posts: 74
Thank you for taking the time to look at my code!

I did try stepping (stepi) through memset but it took too long to trigger the fault. Also, memset was called several times before this with no problems, which made me think the error was elsewhere.

Which common pointer arithmetic error do you mean? I've googled around for sometime and I can't spot what's wrong with my memset code:
Code:
void memset ( u32int *dest, u8int val, u32int len )  // byte-addressable
{
   u32int *temp = dest;

   for ( ; len != 0; len -= 1 )
   {
      *temp = val;

      temp += 1;
   }
}

Thanks


Top
 Profile  
 
 Post subject: Re: Page fault cause - present and write
PostPosted: Thu May 03, 2018 4:07 pm 
Offline
Member
Member
User avatar

Joined: Sat Dec 27, 2014 9:11 am
Posts: 901
Location: Maadi, Cairo, Egypt
quadrant wrote:
Which common pointer arithmetic error do you mean? I've googled around for sometime and I can't spot what's wrong with my memset code

The most common C pointer arithmetic error is incrementing/decrementing pointers expecting it to increment/decrement by one. When you perform any addition or subtraction on a pointer, it actually adds/subtracts the size of the data pointed to. In your case, incrementing a uint32_t pointer actually increments the pointer by four bytes.
On top of that, your memset() is not the way the C standard defined it. I know that's not required inside the kernel, but it makes your life easier in the long run. Here's my memset().
Code:
void *memset(void *dest, int value, size_t count)
{
   uint8_t val = (uint8_t)(value & 0xFF);
   uint8_t *dest2 = (uint8_t*)(dest);

   size_t i = 0;

   while(i < count)
   {
      dest2[i] = val;
      i++;
   }

   return dest;
}

_________________
You know your OS is advanced when you stop using the Intel programming guide as a reference.


Top
 Profile  
 
 Post subject: Re: Page fault cause - present and write
PostPosted: Thu May 03, 2018 7:51 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

quadrant wrote:
I don't understand why my code triggers a page fault with the write and present bits set.


For page fault, the CPU tells the page fault handler the address that caused the fault (in CR2) and the reason for the page fault (in the error code) and a few other things (the address of the instruction that caused the fault, etc).

If the CPU says that the reason for a page fault was a write but the page table entry has the "writeable" bit set, then the problem is that the page directory entry (or PDPT entry or PML4 entry) doesn't have the "writable" bit set.


Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
 Post subject: Re: Page fault cause - present and write
PostPosted: Thu May 03, 2018 11:41 pm 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4591
Location: Chichester, UK
If you still don't get it, have a look at the address that is faulting. Do you expect that address to be mapped in your page table?


Top
 Profile  
 
 Post subject: Re: Page fault cause - present and write
PostPosted: Fri May 04, 2018 1:10 am 
Offline
Member
Member

Joined: Tue Apr 24, 2018 9:46 pm
Posts: 74
omarrx024 wrote:
The most common C pointer arithmetic error is incrementing/decrementing pointers expecting it to increment/decrement by one. When you perform any addition or subtraction on a pointer, it actually adds/subtracts the size of the data pointed to. In your case, incrementing a uint32_t pointer actually increments the pointer by four bytes.
:shock: I had no idea! I had changed from u8int to u32int because I thought you could access a larger address space by doing so. Thank you for the explanation, and thank you @iansjack for pointing this out. Changing the dest type accordingly resolved the issue!


iansjack wrote:
If you still don't get it, have a look at the address that is faulting. Do you expect that address to be mapped in your page table?
Brendan wrote:
If the CPU says that the reason for a page fault was a write but the page table entry has the "writeable" bit set, then the problem is that the page directory entry (or PDPT entry or PML4 entry) doesn't have the "writable" bit set.
Ah, I see. The range I expected was 0xC0000000 (KHEAP_START) up to but not including 0xC0100000 (KHEAP_START + KHEAP_INITIAL_SIZE), and the faulting address was 0xC0100000. So the fault was triggered the moment memset tried to write outside this range...
Attachment:
fault.png
fault.png [ 3.74 KiB | Viewed 2164 times ]


omarrx024 wrote:
On top of that, your memset() is not the way the C standard defined it. I know that's not required inside the kernel, but it makes your life easier in the long run.
I will keep this in mind.

Thanks everyone for all the help!


Top
 Profile  
 
 Post subject: Re: [solved] Page fault cause - present and write
PostPosted: Fri May 04, 2018 1:32 am 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4591
Location: Chichester, UK
I'm sure that nearly everyone has made that mistake at least once.

I managed it in exactly the same context as you - clearing a newly allocated page. :oops:

(BTW - worth bearing in mind for further use - when using the debugger you could have inserted a breakpoint at the start of your page-fault handler to catch the exact moment that the fault occurs. An alternative is to insert an infinite loop to effectively stop the program at that point. If you are using gdb you can then go up a frame and examine the various variables at the point of failure.)


Top
 Profile  
 
 Post subject: Re: [solved] Page fault cause - present and write
PostPosted: Fri May 04, 2018 1:39 pm 
Offline
Member
Member

Joined: Tue Apr 24, 2018 9:46 pm
Posts: 74
Ah lol. I have been spoiled by Python.

A question then, if memset can only use byte pointers, how does it set the memory of an address greater than 255? For example, in this code I am using memset for address 0xC0000000 (KHEAP_START). Why does this address not become zero when I cast it to u8int*?


iansjack wrote:
BTW - worth bearing in mind for further use - when using the debugger you could have inserted a breakpoint at the start of your page-fault handler to catch the exact moment that the fault occurs.
I forgot I could set breakpoints on assembly labels!
iansjack wrote:
If you are using gdb you can then go up a frame and examine the various variables at the point of failure.
I will look into that. I haven't heard much luck with using gdb's record feature, but I think its because my breakpoints are too far in between (and I ran out of memory).


Top
 Profile  
 
 Post subject: Re: [solved] Page fault cause - present and write
PostPosted: Fri May 04, 2018 2:05 pm 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4591
Location: Chichester, UK
I think you're a bit confused about pointers. A pointer is always the same size (32 bits for a 32-bit OS, 64 bits for a 64-bit one). So it can identify any location in the address space. The size of the variable that it points to is another matter. A byte pointer points to a single 8-bit value (one byte), a word pointer to a 16-bit value (2 bytes), etc.

When adding a number to a pointer, it actually adds the size of the object pointed to multiplied by the number you are adding. That way, pointers and arrays can be treated similarly. if pointer p points to the start of an array a then *p == a[0], *(p + 1) == a[1], etc.

The memset function doesn't have to rely just on byte pointers; an efficient implementation would use a combination of long pointers, then smaller pointers - as necessary - to reach the final total. That would be more complicated than the simple memset functions here, but it would be much faster. Personally, I'd stick with the simple implementation unless you do a lot of memsets and speed is paramount.

Now to gdb. When you go up the stack, using the up command, it hasn't actually recorded the execution of the program, it's just looking at the stack frames that lead to the current state. All the information is there on the stack, including the local variables, without having to record anything. As an aside, another useful facility in gdb is watchpoints, which allow you to break into the program when the value of a variable or memory location changes. Very useful when you know that something is overwriting a particular bit of memory but you've no idea where in the program it is happening.


Top
 Profile  
 
 Post subject: Re: [solved] Page fault cause - present and write
PostPosted: Fri May 04, 2018 3:43 pm 
Offline
Member
Member

Joined: Tue Apr 24, 2018 9:46 pm
Posts: 74
Ohhh, I see! Thank you for the clarification, that makes a whole lot more sense.
I didn't know about the up and watchpoint commands. Thank you for the info! :)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 11 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], cloudapio, DotBot [Bot], Google [Bot], Majestic-12 [Bot] and 133 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group