mirror of
https://github.com/joncampbell123/dosbox-x.git
synced 2025-10-15 03:48:24 +08:00
Some code cleanup in paging.cpp. Add separate struct definition for PDE vs PTE. Add notes regarding D (Dirty) bit in PDEs on Pentium and higher CPUs. It seems while 386/486 defined a D bit for PTE and PDE, the Pentium gave up on the D bit for PDE, though for PSE 4MB pages the PDE still has a D bit.
This commit is contained in:
@@ -223,23 +223,24 @@ void MEM_SetPageHandler(Bitu phys_page, Bitu pages, PageHandler * handler);
|
|||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma pack (1)
|
#pragma pack (1)
|
||||||
#endif
|
#endif
|
||||||
struct X86_PageEntryBlock{ // TODO: This is not exactly a page table entry, this is a mismash of both page table and page directory entry
|
|
||||||
|
struct X86_PageEntryBlock{ // Page Table Entry, though it keeps the PageEntryBlock name to avoid breaking all this code
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
uint32_t base:20; // [31:12] PTE+PDE
|
uint32_t base:20; // [31:12]
|
||||||
uint32_t avl:3; // [11: 9] PTE=[11:9] PDE=[11:8]
|
uint32_t avl:3; // [11: 8]
|
||||||
uint32_t g:1; // [ 8: 8] PDE
|
uint32_t g:1; // [ 8: 8]
|
||||||
uint32_t pat:1; // [ 7: 7] PTE PDE=PS(PageSize)
|
uint32_t pat:1; // [ 7: 7]
|
||||||
uint32_t d:1; // [ 6: 6] PTE PDE=AVL
|
uint32_t d:1; // [ 6: 6]
|
||||||
uint32_t a:1; // [ 5: 5] PTE+PDE
|
uint32_t a:1; // [ 5: 5]
|
||||||
uint32_t pcd:1; // [ 4: 4] PTE+PDE
|
uint32_t pcd:1; // [ 4: 4]
|
||||||
uint32_t pwt:1; // [ 3: 3] PTE+PDE
|
uint32_t pwt:1; // [ 3: 3]
|
||||||
uint32_t us:1; // [ 2: 2] PTE+PDE
|
uint32_t us:1; // [ 2: 2]
|
||||||
uint32_t wr:1; // [ 1: 1] PTE+PDE
|
uint32_t wr:1; // [ 1: 1]
|
||||||
uint32_t p:1; // [ 0: 0] PTE+PDE
|
uint32_t p:1; // [ 0: 0]
|
||||||
#else
|
#else
|
||||||
uint32_t p:1; // [ 0: 0]
|
uint32_t p:1; // [ 0: 0]
|
||||||
uint32_t wr:1; // [ 1: 1]
|
uint32_t wr:1; // [ 1: 1] R/W
|
||||||
uint32_t us:1; // [ 2: 2]
|
uint32_t us:1; // [ 2: 2] U/S
|
||||||
uint32_t pwt:1; // [ 3: 3]
|
uint32_t pwt:1; // [ 3: 3]
|
||||||
uint32_t pcd:1; // [ 4: 4]
|
uint32_t pcd:1; // [ 4: 4]
|
||||||
uint32_t a:1; // [ 5: 5]
|
uint32_t a:1; // [ 5: 5]
|
||||||
@@ -250,6 +251,47 @@ struct X86_PageEntryBlock{ // TODO: This is not exactly a page table entry, this
|
|||||||
uint32_t base:20; // [31:12]
|
uint32_t base:20; // [31:12]
|
||||||
#endif
|
#endif
|
||||||
} GCC_ATTRIBUTE(packed);
|
} GCC_ATTRIBUTE(packed);
|
||||||
|
|
||||||
|
struct X86_PageDirEntryBlock{
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
uint32_t base:20; // [31:12]
|
||||||
|
uint32_t avl:3; // [11: 9]
|
||||||
|
uint32_t g:1; // [ 8: 8]
|
||||||
|
uint32_t ps:1; // [ 7: 7]
|
||||||
|
uint32_t avl6:1; // [ 6: 6]
|
||||||
|
uint32_t a:1; // [ 5: 5]
|
||||||
|
uint32_t pcd:1; // [ 4: 4]
|
||||||
|
uint32_t pwt:1; // [ 3: 3]
|
||||||
|
uint32_t us:1; // [ 2: 2]
|
||||||
|
uint32_t wr:1; // [ 1: 1]
|
||||||
|
uint32_t p:1; // [ 0: 0]
|
||||||
|
#else
|
||||||
|
uint32_t p:1; // [ 0: 0]
|
||||||
|
uint32_t wr:1; // [ 1: 1] R/W
|
||||||
|
uint32_t us:1; // [ 2: 2] U/S
|
||||||
|
uint32_t pwt:1; // [ 3: 3]
|
||||||
|
uint32_t pcd:1; // [ 4: 4]
|
||||||
|
uint32_t a:1; // [ 5: 5]
|
||||||
|
uint32_t avl6:1; // [ 6: 6] See Note [*1], this bit changed meaning between the 486 and Pentium!
|
||||||
|
uint32_t ps:1; // [ 7: 7] Page Size Extension (Pentium), even though Intel didn't document it until later
|
||||||
|
uint32_t g:1; // [ 8: 8]
|
||||||
|
uint32_t avl:3; // [11: 9]
|
||||||
|
uint32_t base:20; // [31:12]
|
||||||
|
#endif
|
||||||
|
} GCC_ATTRIBUTE(packed);
|
||||||
|
/* Note [*1]: The i386 defined just the Page Table Entry to represent the PDE and PTE, because they had the same layout.
|
||||||
|
*
|
||||||
|
* The i486 lists the PDE and PTE, even though they have the same bit layout.
|
||||||
|
*
|
||||||
|
* The Pentium however, seems to have decided that bit 6 of the PDE is no longer the "dirty" bit and is redefined as AVL.
|
||||||
|
* Although, if PSE is enabled and the PDE is the 4MB format, bit 6 is once again a "dirty" but.
|
||||||
|
*
|
||||||
|
* FIXME: This codebase still always sets the D bit for PDE regardless of CPU type.
|
||||||
|
*
|
||||||
|
* Ref: [http://hackipedia.org/browse.cgi/Computer/Platform/PC%2c%20IBM%20compatible/CPU/80386/Intel/386DX%20Microprocessor%20Programmer%27s%20Reference%20Manual%20%281990%29%2epdf]
|
||||||
|
* Ref: [http://hackipedia.org/browse.cgi/Computer/Platform/PC%2c%20IBM%20compatible/CPU/80486/Intel/i486%20Microprocessor%20%281989%2d04%29%2epdf]
|
||||||
|
* Ref: [http://hackipedia.org/browse.cgi/Computer/Platform/PC%2c%20IBM%20compatible/CPU/Pentium/Pentium%20Processor%20Family%20Developer%27s%20Manual%20%2d%20Volume%203%3a%20Architecture%20and%20Programming%20Manual%20%281995%2d07%29%2epdf] */
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma pack ()
|
#pragma pack ()
|
||||||
#endif
|
#endif
|
||||||
@@ -258,6 +300,7 @@ struct X86_PageEntryBlock{ // TODO: This is not exactly a page table entry, this
|
|||||||
union X86PageEntry {
|
union X86PageEntry {
|
||||||
uint32_t load;
|
uint32_t load;
|
||||||
X86_PageEntryBlock block;
|
X86_PageEntryBlock block;
|
||||||
|
X86_PageDirEntryBlock dirblock;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if !defined(USE_FULL_TLB)
|
#if !defined(USE_FULL_TLB)
|
||||||
|
@@ -116,7 +116,7 @@ Bits PageFaultCore(void) {
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
if (!pf_queue.used) E_Exit("PF Core without PF");
|
if (!pf_queue.used) E_Exit("PF Core without PF");
|
||||||
const PF_Entry* entry = &pf_queue.entries[pf_queue.used - 1];
|
const PF_Entry* entry = &pf_queue.entries[pf_queue.used - 1];
|
||||||
X86PageEntry pentry;
|
X86PageEntry pentry;
|
||||||
pentry.load=phys_readd((PhysPt)entry->page_addr);
|
pentry.load=phys_readd((PhysPt)entry->page_addr);
|
||||||
if (pentry.block.p && entry->cs == SegValue(cs) && entry->eip==reg_eip) {
|
if (pentry.block.p && entry->cs == SegValue(cs) && entry->eip==reg_eip) {
|
||||||
@@ -380,9 +380,10 @@ private:
|
|||||||
// replace this handler with the real thing
|
// replace this handler with the real thing
|
||||||
if (handler->getFlags() & PFLAG_WRITEABLE)
|
if (handler->getFlags() & PFLAG_WRITEABLE)
|
||||||
paging.tlb.write[lin_page] = handler->GetHostWritePt(phys_page) - (lin_page << 12);
|
paging.tlb.write[lin_page] = handler->GetHostWritePt(phys_page) - (lin_page << 12);
|
||||||
else paging.tlb.write[lin_page]=nullptr;
|
else
|
||||||
paging.tlb.writehandler[lin_page]=handler;
|
paging.tlb.write[lin_page]=nullptr;
|
||||||
|
|
||||||
|
paging.tlb.writehandler[lin_page]=handler;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -807,7 +808,7 @@ initpage_retry:
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LOG_CPU,LOG_WARN)("Page table entry access beyond end of memory, page %08x >= %08x",
|
LOG(LOG_CPU,LOG_WARN)("Page table entry access beyond end of memory, page %08x >= %08x",
|
||||||
(unsigned int)(tableEntryAddr>>12u),(unsigned int)MEM_TotalPages());
|
(unsigned int)(tableEntryAddr>>12u),(unsigned int)MEM_TotalPages());
|
||||||
table_entry.load=0xFFFFFFFF;
|
table_entry.load=0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -821,7 +822,7 @@ initpage_retry:
|
|||||||
if (!table_entry.block.p) {
|
if (!table_entry.block.p) {
|
||||||
// physpage pointer is not present, do a page fault
|
// physpage pointer is not present, do a page fault
|
||||||
PAGING_NewPageFault(lin_addr, tableEntryAddr, prepare_only,
|
PAGING_NewPageFault(lin_addr, tableEntryAddr, prepare_only,
|
||||||
(writing ? 2u : 0u) | (isUser ? 4u : 0u));
|
(writing ? 2u : 0u) | (isUser ? 4u : 0u));
|
||||||
|
|
||||||
if (prepare_only) return true;
|
if (prepare_only) return true;
|
||||||
else goto initpage_retry;
|
else goto initpage_retry;
|
||||||
@@ -841,7 +842,7 @@ initpage_retry:
|
|||||||
// exception error code format:
|
// exception error code format:
|
||||||
// bit0 - protection violation, bit1 - writing, bit2 - user mode
|
// bit0 - protection violation, bit1 - writing, bit2 - user mode
|
||||||
PAGING_NewPageFault(lin_addr, tableEntryAddr, prepare_only,
|
PAGING_NewPageFault(lin_addr, tableEntryAddr, prepare_only,
|
||||||
1u | (writing ? 2u : 0u) | (isUser ? 4u : 0u));
|
1u | (writing ? 2u : 0u) | (isUser ? 4u : 0u));
|
||||||
|
|
||||||
if (prepare_only) return true;
|
if (prepare_only) return true;
|
||||||
else goto initpage_retry; // unlikely to happen?
|
else goto initpage_retry; // unlikely to happen?
|
||||||
|
Reference in New Issue
Block a user