Maybe a Stupid Question

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.
ich_will

Maybe a Stupid Question

Post by ich_will »

I've the following problem:

Currently I'm writing my memory manager and all seems to work fine except for one thing: I can't lock pages again, if they're present one time.

Here is my function for setting page attributes:

unsigned int paging_set_pages(unsigned long from_addr, unsigned long to_addr, unsigned short flags)
{
unsigned long i, limit;
// round addresses
from_addr = MAKE_4K_ALIGN_DOWN(from_addr);
to_addr = MAKE_4K_ALIGN_DOWN(to_addr);

if(from_addr > to_addr || VIRTUAL_ADDRESS_TO_PAGE_INDEX(to_addr) > glb_pages_count)
{
puts("\tpaging_set_pages: invalid address range");
return to_addr;
}

for(i = VIRTUAL_ADDRESS_TO_PAGE_INDEX(from_addr),
limit = VIRTUAL_ADDRESS_TO_PAGE_INDEX(to_addr); i <= limit; i++)
{
PAGE_TABLES = CLR_L12_BITS(PAGE_TABLES);
PAGE_TABLES |= (flags ^ CLR_L12_BITS(flags));
}

PAGE_DIRECTORY[i/PAGES_PER_DIR] = CLR_L12_BITS(PAGE_DIRECTORY[i/PAGES_PER_DIR]);
PAGE_DIRECTORY[i/PAGES_PER_DIR] |= flags|PAGE_FLAG_PRESENT; // <--this is only for this time, later i will check if any page in the directory is present, and if not, i will disable the dir
// <-- is that the mistake?

return 0;
}

I think you haven't to disable the pagedirs for disable one page. So where is the mistake? --> I also have a function which prints a map of present and non present pages. If I can trust this function all should work fine. But it doesn't.

I test it with this loop:

for(i = 0; i > 4096; i++)
{
*((char*)(0x617000 + i)) = '1'; // 0x617000 is the first avaible page after kernel loading and memmanger initializing
}

if i run this loop before i allocate anything a page fault happens, but after i allocate and free some memory it doesn't. Though my print function for the memmap say the page isn't present.
distantvoices
Member
Member
Posts: 1600
Joined: Wed Oct 18, 2006 11:59 am
Location: Vienna/Austria
Contact:

Re:Maybe a Stupid Question

Post by distantvoices »

Hm ... what do you mean with "disabling a page". Freeing it?
And what is "locking a page"?

If you wanna free a page - set the corresponging slot in the pagetable/pagedir(if freeing a page table) to zero - or clear the present-flag. Then you should get a pagefault as is due upon access of a not-mapped-in area.

then you mark the page as available in your bookkeeping structures for physical memory.

hth and no, there ain't no stupid questions
... the osdever formerly known as beyond infinity ...
BlueillusionOS iso image
ich_will

Re:Maybe a Stupid Question

Post by ich_will »

thx,

disabling a page = set the PRESENT_BIT to 0
locking a page = protect a page --> equal to disabling in this case

thats what I do, i clear the PRESENT_BIT but I get no page fault
distantvoices
Member
Member
Posts: 1600
Joined: Wed Oct 18, 2006 11:59 am
Location: Vienna/Austria
Contact:

Re:Maybe a Stupid Question

Post by distantvoices »

If you want to clear a given bit in a bitmask, use this:

Code: Select all

variable&=~BIT_TO_CLEAR;
the tilde causes the BIT_TO_CLEAR come along inverted:

say a given bit 00000010 (0x02)
will become 11111101. AND this with any bitmask and every bit except bit Nr. 2 will remain untouched - this one will be set to Zero. 1 AND 0 = 0. (refer to your average truth tables *gg*)

HtH
... the osdever formerly known as beyond infinity ...
BlueillusionOS iso image
ich_will

Re:Maybe a Stupid Question

Post by ich_will »

I don't know why and I think that's not normal but, I only get pagefaults, if the PAGE_PRESENT_BIT of the PAGE_DIR is zero. I can access a PAGE in this PAGE_DIR even though the PAGE_PRESENT_BIT of the page i try to access is zero.

What's going on here?
mystran

Re:Maybe a Stupid Question

Post by mystran »

Also remember to invalidate TLB entries for pages you remove, unless you know you will be reloading the page directory before you need it to page fault. Otherwise the old entry might be in a TLB and the page tables might not be checked at all.

TLB invalidation problems have the nasty feature that sometimes everything might work fine, while other times the page table modications don't seem to have any effect.
ich_will

Re:Maybe a Stupid Question

Post by ich_will »

srry but what are TLBs, i think you don't mean TBL=Table
distantvoices
Member
Member
Posts: 1600
Joined: Wed Oct 18, 2006 11:59 am
Location: Vienna/Austria
Contact:

Re:Maybe a Stupid Question

Post by distantvoices »

tlb = transaction lookaside buffer

that's an area in the cpu/mmu where already resolved pages are stored for quick lookup.

So to say: first resolving a virtual address to the physical page -> store the page in the TLB.

having to fiddle with a virtual address area again - first look it up in the TLB and only resolve via pagedir->pagetable->offset if not found there.

invalidating an entry in the TLB means nothing else than throwing it away.
... the osdever formerly known as beyond infinity ...
BlueillusionOS iso image
ich_will

Re:Maybe a Stupid Question

Post by ich_will »

ok, should i simply do the following after every change?:

mov cr3, page_dir ; this flushes the complete tlb or? --> also if its the same value than before?

or how can I invalidate a single entry of the tlb?
distantvoices
Member
Member
Posts: 1600
Joined: Wed Oct 18, 2006 11:59 am
Location: Vienna/Austria
Contact:

Re:Maybe a Stupid Question

Post by distantvoices »

Have to correct myself: tlb = translation lookaside buffer. stupid me.

Have googled for it: invlpg ebx f. ex. where in ebx you store the address of the physical page you wanna drop outta tlb.

Maybe our wiki has more indepth information about this command.

Concerning your question about reloading cr3 upon each change: I wouldna do this as it trashes the complete TLB and is a kinda ritus in itself: loading the register and doing an absolute jump to flush the tlb. invlpg is rather quick at hand it seems, so, I'd do it the invlpg way as long as the address space remains the same.

Pype? Mystran? D'ya have some input about this?
... the osdever formerly known as beyond infinity ...
BlueillusionOS iso image
ich_will

Re:Maybe a Stupid Question

Post by ich_will »

thanks, i'll try it --> but what should i do on a 386 (or have is there cpu no tlb?) because this instruction exists only for 468+
distantvoices
Member
Member
Posts: 1600
Joined: Wed Oct 18, 2006 11:59 am
Location: Vienna/Austria
Contact:

Re:Maybe a Stupid Question

Post by distantvoices »

on an i386, I think, you reload cr3 and make that jump in order to flush tlb. Hm ... gonna look it up myself. I don't know it for sure.
... the osdever formerly known as beyond infinity ...
BlueillusionOS iso image
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Maybe a Stupid Question

Post by Pype.Clicker »

page mappings that have been resolved once by the CPU are kept in the Translation Lookaside Buffer ... If you change the mapping or "disable" the translation, you should clear the corresponding TLB entry with "invlpg" instruction, otherwise the CPU simply continues using the (now obsolete) cache content...
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:Maybe a Stupid Question

Post by Brendan »

Hi,

For an 80386 you must reload CR3 (which does trash the entire TLB, but this doesn't matter too much because the difference in speed between the TLB and RAM isn't that high for these old computers). For 80486 or higher you should use INVLPG.

For Pentium (I think) and above there's a "global page" flag in the page table entries which should be used. This flag (when set) prevents the page from being flushed from the TLB when CR3 is reloaded. By enabling global pages and setting all of the kernel's pages to global you can improve the cost of context switches (changing address spaces) a fair bit. Support for global pages is detected via. CPUID and it's enabled using the PGE flag in CR4 (bit 7).

If you do use global pages then you must use INVLPG (at least for the kernel's pages), as reloading CR3 won't flush the TLB's anymore.

IMHO using global pages and INVLPG is very important for performance now, especially for Pentium IV where accessing RAM is incredibly slow compared to the CPU's TLB.

To make things easier I don't bother supporting 80386's anymore - I searched for a working second hand 80386 for about 6 months but couldn't find one.


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.
ich_will

Re:Maybe a Stupid Question

Post by ich_will »

thx

srry, but how does this invplg instruction work?

i tried the following:

__invlpg
push ebp
mov ebp, esp
push ebx

mov ebx, [ebp + 8]???; page_dir
invlpg [ebx] ; Invalidate Translation Look-Aside Buffer Entry: WARNING 486+ only

pop ebx
pop ebp
ret

and call it from C in the loop from the function at the top at that thread:

for(i = VIRTUAL_ADDRESS_TO_PAGE_INDEX(from_addr),
limit = VIRTUAL_ADDRESS_TO_PAGE_INDEX(to_addr); i <= limit; i++)
{
PAGE_TABLES = CLR_L12_BITS(PAGE_TABLES);
PAGE_TABLES |= (flags ^ CLR_L12_BITS(flags));
_invlpg(PAGE_TABLES);
}

but the cpu only resets with an page fault --> shouldn't i call invlpg if the cpu has paging disabled?
Post Reply