Page 1 of 1
Setting a Page's attribute (bitmasking)?
Posted: Wed Aug 02, 2006 5:40 pm
by mike13
Hey, I'm making slow progress on my memory manager and I have come to the point where I would like to re-set the attribute for a page and this is what I have:
Code: Select all
void set_page_attribute(SLONG page_number, UCHAR attribute)
{
// Perform a bitmask to all zeros
page_table[page_number] = page_table[page_number] & ~attribute;
// Set the actual attribute
page_table[page_number] = page_table[page_number] | attribute;
}
The above code does not work the way I would like it to, I want it to first mask the first few bits of the page and THEN write the new attribute value to the page, but I can't seem to figure out how to mask those bits, I googled for some time, and I peiced together the following line:
Code: Select all
page_table[page_number] = page_table[page_number] & ~attribute;
How should I go about this? and I would imagine there would be a more efficient way to go about setting the attribute of a range of pages... could I possibly write some code that skips through the 4KB aligned pages and re-sets those bits? without having to call this function more than once?
Posted: Thu Aug 03, 2006 3:15 am
by Mikae
Why do you think, that your code doesn't work? It seems to me that such code:
page_table[page_number] |= attribute;
is enough to set page's attributes.
And I think that if you want to set up attribute for range of pages there is no other way except cycle.
Also, do not forget to update changed attribute in TLB-cache.
Posted: Thu Aug 03, 2006 9:15 am
by gaf
Hi mike,
the code you provided is already quite fine in my opinion. All you really have to do is to split up your procedure:
Code: Select all
void set_page_attribute(SLONG page_number, UCHAR attribute)
{
// OR simply sets the bit, the prior state doesn't matter
page_table[page_number] = page_table[page_number] | attribute;
}
void reset_page_attribute(SLONG page_number, UCHAR attribute)
{
// ~ inverts the attribute (0001000 -> 1110111)
// & only sets a bit to one when both operants are one
// -> attribute gets cleared
page_table[page_number] = page_table[page_number] &(~attribute);
}
static const ulong global 256
static const ulong write 2
set_page_attribute(0, global); // Page 0 is now global
...
reset_page_attribute(0, global); // Page 0 is no longer global
Note that bifields can sometimes be a much cleaner alternative, as they allow you access the bits of a variable just like members of a structure. The compiler then takes care of all the low-level boolean logic..
I would imagine there would be a more efficient way to go about setting the attribute of a range of pages.
In real-life it's seldomply necessary to set a special flag for a range of arbitrary pages: The much more common case is that you have to change a block of memory (..consisting of several pages..) that was allocated by an application. Such blocks are - of course - homogenious, so that the flags are the same for all pages. It's thus safe if you only read the flags of the first page, set the attribute bit and then commit the changed settings to all pages of the block.
cheers,
gaf
Posted: Thu Aug 03, 2006 4:05 pm
by mike13
Mikae wrote:Why do you think, that your code doesn't work? It seems to me that such code:
page_table[page_number] |= attribute;
is enough to set page's attributes.
And I think that if you want to set up attribute for range of pages there is no other way except cycle.
Also, do not forget to update changed attribute in TLB-cache.
Yes, that part of the code does want I want it to, but it simply adds the new attribute over the old one, which means that using that method I could not set a page's attribute to an attribute lower than the original.... however I did manage to figure it out:
Code: Select all
void set_page_attribute(ULONG page_number, UCHAR new_attribute)
{
char current_attribute = page_table[page_number] & 0xF;
page_table[page_number] -= current_attribute;
page_table[page_number] = page_table[page_number] | new_attribute;
}
I'm also going to read up a little on bitfields, thanks guys, I really appriciate it.
Posted: Thu Aug 03, 2006 4:20 pm
by Mikae
Well, if I understood you right, you want reset page attributes, discarding previous?
The simpliest (and the fastest) way is to use bitwise operations:
Code: Select all
page_table[page_number] &= ~0xF; //4 lowest bits are cleared.
page_table[page_number] |= new_attribute; //new attribute set.
Posted: Thu Aug 03, 2006 5:00 pm
by mike13
Ok, yeah that works great, thanks