Page 1 of 2

problem changing page table in bochs

Posted: Wed Jun 06, 2012 10:22 pm
by vjain20
Hi,

I am trying to copy the contents of two arrays to two different pages allocated by physical memory manager.
I have a function - vmmgr_temp_map_page() which maps any physical address to a fixed virtual address - 0xC0000000
so that I can write to that page using the fixed virtual address.
Now the problem is that at one point, when vmmgr_temp_map_page() is called, the page table entry is not getting modified.

Here is the code :

Code: Select all

char[] code_array = { ... }
char[] data_array = { ... }

void* code_frame = pmmgr_alloc_block();                       //Allocate a page 
void* code_virt = vmmgr_temp_map_page(code_frame);   //Map page to 0xC000 0000 << WORKS
char* dest = (char*)code_virt;

int j, k = 0;
//Copy contents of code_array to page
for(j = 0; j < 0x23 ; j ++)
{
  dest[j] =  code_array[j];
}

void* data_frame = pmmgr_alloc_block();                        //Allocate a page 
void* data_virt = vmmgr_temp_map_page(data_frame);     //Map page to 0xC000 0000    << DOESNT WORK
dest  = (char*)data_virt;

//Copy contents of data_array to page
for(k =0 ; k < 0x31; k++)
  {
    dest[k] = data_array[k];
  }
[/size]


Here the first call to vmmgr_temp_map_page() works but the second one doesn't.
The physical address of code_frame is 0x8000 and that of data frame is 0x116000.
I am using the command 'info tab' on bochs debugger to check the mappings. After the firs call to vmmgr_temp_map_page()
info tab shows the entry

Code: Select all

0xc0000000-0xc0000fff -> 0x0000000000008000-0x0000000000008fff
[/size]

but after second call also it shows the same entry.
Now the strange thing here is that when I check the page table entry using the physical address of the page table
it shows that the entry is changed after the second call but 'info tab' still shows the old entry.

Code: Select all

<bochs:5> xp /4bx 0x2000
[bochs]:
0x00002000 <bogus+       0>:	0x67	0x60	0x11	0x00
[/size]

This is PTE of the page table at physical address 0x2000 which maps addresses starting from 0xC0000000. It clearly shows that
the physical address mapped to 0xC0000000 is 0x116000
But the output from info tab differs :

Code: Select all

<bochs:6> info tab
cr3: 0x0a8fb5c800003000
0x00000000-0x003fffff -> 0x0000000000000000-0x00000000003fffff
0xc0000000-0xc0000fff -> 0x0000000000008000-0x0000000000008fff     <<<<<<<<<<<<<<<<
0xc0001000-0xc03fffff -> 0x0000000000101000-0x00000000004fffff
0xd0000000-0xd00fffff -> 0x0000000000009000-0x0000000000108fff
0xffc00000-0xffc00fff -> 0x0000000000001000-0x0000000000001fff
0xfff00000-0xfff00fff -> 0x0000000000002000-0x0000000000002fff
0xfff40000-0xfff40fff -> 0x0000000000006000-0x0000000000006fff
0xfffff000-0xffffffff -> 0x0000000000003000-0x0000000000003fff
[/size]

When I continue, the code fails as the frame at 0x8000 is modified again in place of the frame at 0x116000.
What is more confusing is that once in a while info tab shows correct mappings and the code runs correctly but mostly it is
failing. I have been debugging this for a few hours now and don't know what else to do.


-Thanks
Vaibhav Jain

Re: problem changing page table in bochs

Posted: Wed Jun 06, 2012 11:18 pm
by Combuster
Look up "TLB" in the intel manuals

Re: problem changing page table in bochs

Posted: Thu Jun 07, 2012 12:13 am
by vjain20
Look up "TLB" in the intel manuals
I guess you are referring to invalidating a TLB entry.
The function vmmgr_temp_map_page calls another function to invalidate a TLB entry

Code: Select all

void vmmgr_flush_tlb_entry(void* addr)
{
    asm volatile("cli");
    asm volatile("invlpg %0":: "m"((uint32)addr));
    asm volatile("sti");
}
-Thanks

Re: problem changing page table in bochs

Posted: Thu Jun 07, 2012 12:18 am
by vjain20
I found that a full tlb flush is working while invalidating a single entry using the invlpg instruction is not.
But this seems to be an overhead.





-Thanks

Re: problem changing page table in bochs

Posted: Thu Jun 07, 2012 12:47 am
by iansjack
Have a look at: http://wiki.osdev.org/Inline_Assembly/Examples . The correct use of the "invlpg" instruction can be a little tricky.

Re: problem changing page table in bochs

Posted: Thu Jun 07, 2012 1:12 am
by vjain20
Have a look at: http://wiki.osdev.org/Inline_Assembly/Examples . The correct use of the "invlpg" instruction can be a little tricky.
Thanks for the link but I couldn't quite understand what is given in the article.
The 'm' pointer points to a logical address, not a physical or virtual one: an offset for your ds segment. Note '*m' is used, not just 'm': if you use 'm' here, you invalidate the address of the 'm' variable (not what you want!).

static inline
void pgFlushOneTlb( void * m )
{
asm volatile( "invlpg %0"
: // no output
: "m"(*m) //
: "memory" // clobber memory to avoid optimizer re-ordering access before invlpg, which may cause nasty bug.
);
}
Could you please tell what should I pass to this method if I want to invalidate a virtual address X ?
I added the clobber memory to my function which provides a virtual address as an operand to invlpg but it did not work.

Code: Select all

void vmmgr_flush_tlb_entry(void* addr)
{
    asm volatile("cli");
    asm volatile("invlpg %0":: "m"((uint32)addr) : "clobber");
    asm volatile("sti");
}

I looked up the intel manual which only says :
Invalidates (flushes) the translation lookaside buffer (TLB) entry specified with the source
operand. The source operand is a memory address. The processor determines the page that
contains that address and flushes the TLB entry for that page
.

Re: problem changing page table in bochs

Posted: Thu Jun 07, 2012 1:51 am
by iansjack
It's a question of which address you want to invalidate. m is a variable that holds a pointer to an address. *m is the pointer to that address (which is what variable m contains).

So which address do you want to invalidate, the address of the variable containing the pointer (m) or the pointer that the variable contains (*m)?

Re: problem changing page table in bochs

Posted: Thu Jun 07, 2012 3:01 am
by vjain20
Thanks! I still don't understand it but it started working.
Here is my function to invalidate TLB entry

Code: Select all

void vmmgr_flush_tlb_entry(void* addr)
{
    asm volatile("cli");
    asm volatile("invlpg %0":: "m"(*((uint32*)addr)): "memory");
    asm volatile("sti");
}
[/size]

And to invalidate any virtual address say 0xC0000000 I am directly calling vmmgr_flush_tlb_entry(0xC0000000).
So it seems that the instruction invlpg is taking the value at address which is to be invalidated as input. :?

Re: problem changing page table in bochs

Posted: Thu Jun 07, 2012 4:30 am
by iansjack
You should think about it more and try to understand exactly what is happening. It might help if you were to look at the assembler code generated when you compile that function, or even single-step through the assembler code to see what exactly is happening.

This is fairly basic pointer stuff and you need to understand it to successfully interface between C code and assembler code.

Re: problem changing page table in bochs

Posted: Thu Jun 07, 2012 4:48 am
by Griwes
Tip: what does the following do?

Code: Select all

*((uint32*)addr)

Re: problem changing page table in bochs

Posted: Thu Jun 07, 2012 8:12 am
by Griwes
berkus wrote:
Griwes wrote:Tip: what does the following do?

Code: Select all

*((uint32*)addr)
It uses a non-standard typedef for 32-bits unsigned integer, perhaps.
I mean the syntax, not the uint32 part:
vjain20 wrote:So it seems that the instruction invlpg is taking the value at address which is to be invalidated as input.

Re: problem changing page table in bochs

Posted: Thu Jun 07, 2012 8:31 am
by Griwes
berkus, once again: he is taking the address, dereferencing it as pointer to 32bit value, and feeding the value to the invlpg and doesn't know why invlpg is executed with the value at address, not the address...

Re: problem changing page table in bochs

Posted: Thu Jun 07, 2012 8:40 am
by Griwes
Nah, seems that I've used all my trollcasting mana recently :F

Re: problem changing page table in bochs

Posted: Thu Jun 07, 2012 8:41 am
by iansjack
I think this is all getting a little complicated and is obfuscating the OP's problem. It's a simple matter of understanding the difference between the address of a variable and the contents of that variable. Especially in the case when the contents of the variable are a pointer to a memory address.

Forget all the crap about casts; that's not the OP's conceptual problem.

I still think the best way that he will understand is to single-step through the generated assemble and watch what happens to registers and memory contents; you can't beat seeing the CPU in action.

Re: problem changing page table in bochs

Posted: Thu Jun 07, 2012 9:01 am
by iansjack
berkus wrote:Explicit cast however shows the intention more noticeably.
It certainly does, and just checking my own code I see that I do use explicit casts in this situation (although you'll have to forgive the fact that I use good old-fashioned C-style casts), once you understand why you are doing it. And it's very useful as a reminder when you are looking at the code after you wrote it.

But I think the OP is having difficulty grasping that why. Watch it in action in a debugger and he'd soon realise why and what was wrong with his original code.