Maybe a Stupid Question
Maybe a Stupid Question
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.
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.
-
- Member
- Posts: 1600
- Joined: Wed Oct 18, 2006 11:59 am
- Location: Vienna/Austria
- Contact:
Re:Maybe a Stupid Question
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
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
BlueillusionOS iso image
Re:Maybe a Stupid Question
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
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
-
- Member
- Posts: 1600
- Joined: Wed Oct 18, 2006 11:59 am
- Location: Vienna/Austria
- Contact:
Re:Maybe a Stupid Question
If you want to clear a given bit in a bitmask, use this:
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
Code: Select all
variable&=~BIT_TO_CLEAR;
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
BlueillusionOS iso image
Re:Maybe a Stupid Question
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?
What's going on here?
Re:Maybe a Stupid Question
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.
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.
-
- Member
- Posts: 1600
- Joined: Wed Oct 18, 2006 11:59 am
- Location: Vienna/Austria
- Contact:
Re:Maybe a Stupid Question
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.
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
BlueillusionOS iso image
Re:Maybe a Stupid Question
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?
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?
-
- Member
- Posts: 1600
- Joined: Wed Oct 18, 2006 11:59 am
- Location: Vienna/Austria
- Contact:
Re:Maybe a Stupid Question
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?
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
BlueillusionOS iso image
Re:Maybe a Stupid Question
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+
-
- Member
- Posts: 1600
- Joined: Wed Oct 18, 2006 11:59 am
- Location: Vienna/Austria
- Contact:
Re:Maybe a Stupid Question
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
BlueillusionOS iso image
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Maybe a Stupid Question
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...
Re:Maybe a Stupid Question
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 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.
Re:Maybe a Stupid Question
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?
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?