Page 1 of 1

486 vs Pentium: WT bit in CR0

Posted: Sun Dec 16, 2012 12:21 pm
by suslik
I read some design decisions of microkernel L4: http://i30www.ira.uka.de/~neider/edu/mk ... index.html. And I was interested in:
0-Mapping-Trick

The TCB (Thread Control Block) array with its 256k entries of 2 kByte each requires 512 MB of memory. For obvious reasons, the microkernel should not claim 512 MB of physical memory from the start on but should rather grow only on demand. Thus the TCB array is allocated only in virtual memory. The first access to a page in the TCB array will cause a pagefault, which is handled specially by the kernel:

* on reads, a shared 0-filled page (the so-called "0-page") is mapped read-only; this allows the access to complete after pagefault resolution and guarantees that the mandatory thread ID validation fails (thread ID 0 is reserved by the kernel and represents no thread at all (the nilthread ID))
* on writes, a newly allocated 0-filled page is mapped writable; this guarantees that all TCBs on the page are initialized with an invalid thread ID (0), so that future access still correctly report them as invalid while allowing to fill in TCB data should a new thread be created

This is a variant of the copy-on-write scheme, which saves memory even if a malicious user-level thread probes every thread ID in the system; there will only be a single physical frame mapped multiple times into the TCB array. The initial pagefaults can be avoided by premapping the 0-filled page to back the whole TCB array. Afterwards, only the first TCB modification on each page will cause a pagefault.
Is it possible to make CPU raise page fault when kernel tries to write into kernel read-only page? I looked through Intel manuals:
Intel 486 Programmer's Reference Manual, 1992

4.1.3 Control Registers:
"WP (Write Protect, bit 16)
When set, this bit write-protects user-level pages against supervisor-level writes. When
this bit is clear, read-only user-level pages can be written by a supervisor process. This
feature is useful for implementing the copy-on-write method of creating a new process
(forking) used by some operating systems, such as UNIX".

6.8.1.2 TYPE CHECKING:
"Unlike the Intel386 DX processor, the Intel486 processor allows user-mode pages to be
write-protected against supervisor mode access. Setting the WP bit in the CR0 register
enables supervisor-mode sensitivity to user-mode, write-protected pages.
This feature is
useful for implementing the copy-on-write strategy used by some operating systems, such
as UNIX, for task creation"
So, I can't make 486 to raise page fault when supervisor tries to write into SUPERVISOR (not user!) read-only page.
Pentium Processor Family Developer’s Manual Volume 3, 1995:

10.1.3. Control Registers:
"WP (Write Protect, bit 16 of CR0)
When set, this bit write-protects pages against supervisor-level writes. When this bit is clear,
read-only pages can be written by a supervisor process"

12.8.1.2. TYPE CHECKING:
"Setting the WP bit in the CR0 register enables supervisor-mode sensitivity to write-protected
pages"
Hmm, no mentions about user pages...
Intel 64 and IA-32 Architectures Software Developers Manual, 2012:

5.11.3 Page Type:
"Starting with the P6 family, Intel processors allow user-mode pages to be write-protected against supervisor-mode access. Setting CR0.WP = 1 enables supervisor-mode sensitivity to write protected pages. If CR0.WP = 1, readonly pages are not writable from any privilege level. This supervisor write-protect feature is useful for implementing a “copy-on-write” strategy used by some operating systems, such as UNIX*, for task creation"
Also, no mentions about user pages... So, I can make Pentium+ raise page fault when supervisor tries to write into SUPERVISOR READ-ONLY pages.
From BOCHS source, bochs/cpu/paging.cc:
CR0:
37 // bit 31: PG, Paging (386+)
38 // bit 16: WP, Write Protect (486+)
39 // 0: allow supervisor level writes into user level RO pages
40 // 1: inhibit supervisor level writes into user level RO pages
41 //
Damn! Why? Why, only for user level pages?

Last: I tried in Bochs to set WP in CR0 and in kernel mode to write into read-only kernel page... NO PAGE FAULT. :(

Re: 486 vs Pentium: WT bit in CR0

Posted: Sun Dec 16, 2012 12:59 pm
by Combuster
Did you flush the relevant TLB entries?

Re: 486 vs Pentium: WT bit in CR0

Posted: Sun Dec 16, 2012 1:08 pm
by Brendan
Hi,
suslik wrote:Damn! Why? Why, only for user level pages?
Because kernels are supposed to be smart enough to check the page directory entry and page table entry, and avoid a (much more expensive) page fault.

However, in most cases there'd be ways to simplify the check. For example, you could just have an "allocated_thread_IDs" variable and do things like:

Code: Select all

int check_thread_ID(threadID) {
    if(threadID > allocated_thread_IDs) return INVALID;       // TCB_array currently too small
    if(TCB_array[threadID].something != TRUE) return INVALID;
    return VALID;
}

void create_thread_ID(threadID) {
    while(threadID > allocated_thread_IDs) {         // TCB_array currently too small
        alloc_page_for_TCB_array();
        allocated_thread_IDs += 4096 / sizeof(TCB);
    }
    TCB_array[threadID].something = TRUE;
}

Cheers,

Brendan

Re: 486 vs Pentium: WT bit in CR0

Posted: Sun Dec 16, 2012 4:19 pm
by rdos
suslik wrote:I read some design decisions of microkernel L4: http://i30www.ira.uka.de/~neider/edu/mk ... index.html. And I was interested in:
Interesting lecture. I think I'll borrow some ideas from there in my 64-bit implementations.