From 93c6c0c803a1d31142dc110e8a08481921592f2a Mon Sep 17 00:00:00 2001 From: Sjoerd van der Berg Date: Mon, 14 Jul 2003 08:32:39 +0000 Subject: [PATCH] Main paging handler. Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@1119 --- src/cpu/paging.cpp | 250 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 src/cpu/paging.cpp diff --git a/src/cpu/paging.cpp b/src/cpu/paging.cpp new file mode 100644 index 00000000..d8fdc8fa --- /dev/null +++ b/src/cpu/paging.cpp @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2002-2003 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +#include "dosbox.h" +#include "mem.h" +#include "paging.h" +#include "../hardware/vga.h" + + +#define LINK_TOTAL (64*1024) + +static PageLink link_list[LINK_TOTAL]; +struct PagingBlock paging; + +class PageDirChange : public PageChange { +public: + PageDirChange(PageDirectory * mydir) { dir=mydir;} + void Changed(PageLink * link,Bitu start,Bitu end) { + start>>=2;end>>=2; + for (;start<=end;start++) { + dir->InvalidateTable(start); + } + } +private: + PageDirectory * dir; +}; + +class PageTableChange : public PageChange { +public: + PageTableChange(PageDirectory * mydir) { dir=mydir;} + void Changed(PageLink * link,Bitu start,Bitu end) { + start>>=2;end>>=2; + for (;start<=end;start++) { + dir->InvalidateLink(link->data.table,start); + } + } +private: + PageDirectory * dir; +}; + + + +PageDirectory::PageDirectory() { + entry_init.data.dir=this; + entry_init.type=ENTRY_INIT; + link_init.read=0; + link_init.write=0; + link_init.entry=&entry_init; + table_change = new PageTableChange(this); + dir_change = new PageDirChange(this); +} +PageDirectory::~PageDirectory() { + delete table_change; + delete dir_change; +} +void PageDirectory::ClearDirectory(void) { + Bitu i; + for (i=0;i<1024*1024;i++) links[i]=&link_init; + for (i=0;i<1024;i++) { + tables[i]=0; + } +} +void PageDirectory::SetBase(PhysPt page) { + base_page=page; + ClearDirectory(); + /* Setup handler for PageDirectory changes */ + link_dir=MEM_LinkPage(base_page,0); + if (!link_dir) E_Exit("PageDirectory setup on illegal address"); + link_dir->data.dir=this; + link_dir->change=dir_change; + MEM_CheckLinks(link_dir->entry); +} +void PageDirectory::LinkPage(Bitu lin_page,Bitu phys_page) { + if (links[lin_page] != &link_init) MEM_UnlinkPage(links[lin_page]); + PageLink * link=MEM_LinkPage(phys_page,lin_page*4096); + if (link) links[lin_page]=link; + else links[lin_page]=&link_init; +} + +bool PageDirectory::InitPage(Bitu lin_address) { + Bitu lin_page=lin_address >> 12; + Bitu table=lin_page >> 10; + Bitu index=lin_page & 0x3ff; + /* Check if there already is table linked */ + if (!tables[table]) { + X86PageEntry table_entry; + table_entry.load=phys_page_readd(base_page,0); + if (!table_entry.block.p) { + LOG(LOG_PAGING,LOG_ERROR)("NP TABLE"); + return false; + } + PageLink * link=MEM_LinkPage(table_entry.block.base,table_entry.block.base); + if (!link) return false; + link->data.table=table; + link->change=table_change; + MEM_CheckLinks(link->entry); + tables[table]=link; + } + X86PageEntry entry; + entry.load=phys_page_readd(tables[table]->lin_base,index); + if (!entry.block.p) { + LOG(LOG_PAGING,LOG_ERROR)("NP PAGE"); + return false; + } + PageLink * link=MEM_LinkPage(entry.block.base,lin_page*4096); + if (!link) return false; + links[lin_page]=link; + return true; +} + + +bool PageDirectory::InitPageLinear(Bitu lin_address) { + Bitu phys_page=lin_address >> 12; + PageLink * link=MEM_LinkPage(phys_page,phys_page*4096); + if (link) { + /* Set the page entry in our table */ + links[phys_page]=link; + return true; + } + return false; +} + + +void PageDirectory::InvalidateTable(Bitu table) { + if (tables[table]) { + MEM_UnlinkPage(tables[table]); + tables[table]=0; + for (Bitu i=(table*1024);i<(table+1)*1024;i++) { + if (links[i]!=&link_init) { + MEM_UnlinkPage(links[i]); + links[i]=&link_init; + } + } + } +} + +void PageDirectory::InvalidateLink(Bitu table,Bitu index) { + Bitu i=(table*1024)+index; + if (links[i]!=&link_init) { + MEM_UnlinkPage(links[i]); + links[i]=&link_init; + } +} + + +Bitu PAGING_GetDirBase(void) { + return paging.cr3; +} + +void PAGING_SetDirBase(Bitu cr3) { + paging.cr3=cr3; + Bitu base_page=cr3 >> 12; + LOG_MSG("CR3:%X Base %X",cr3,base_page); + if (paging.enabled) { + /* Check if we already have this one cached */ + PageDirectory * dir=paging.cache; + while (dir) { + if (dir->base_page==base_page) { + paging.dir=dir; + return; + } + dir=dir->next; + } + /* Couldn't find cached directory, make a new one */ + dir=new PageDirectory(); + dir->next=paging.cache; + paging.cache=dir; + dir->SetBase(base_page); + paging.dir=dir; + } +} + +void PAGING_Enable(bool enabled) { + /* If paging is disable we work from a default paging table */ + if (paging.enabled==enabled) return; + paging.enabled=enabled; + if (!enabled) { + LOG_MSG("Paging disabled"); + paging.dir=MEM_DefaultDirectory(); + } else { + LOG_MSG("Paging enabled"); + PAGING_SetDirBase(paging.cr3); + } +} + +bool PAGING_Enabled(void) { + return paging.enabled; +} + + +void PAGING_FreePageLink(PageLink * link) { + MEM_UnlinkPage(link); + PAGING_AddFreePageLink(link); +} + +void PAGING_LinkPage(PageDirectory * dir,Bitu lin_page,Bitu phys_page) { + PageLink * link=MEM_LinkPage(phys_page,lin_page*4096); + /* Only replace if we can */ + if (link) { + PAGING_FreePageLink(dir->links[lin_page]); + dir->links[lin_page]=link; + } +} + +void PAGING_AddFreePageLink(PageLink * link) { + link->read=0; + link->write=0; + link->change=0; + link->next=paging.free_link; + link->entry=0; + paging.free_link=link; +} + +PageLink * PAGING_GetFreePageLink(void) { + PageLink * ret; + if (paging.free_link) ret=paging.free_link; + else E_Exit("PAGING:Ran out of PageEntries"); + paging.free_link=ret->next; + ret->next=0; + return ret; +} + +void PAGING_Init(Section * sec) { + Bitu i; + /* Setup the free pages tables for fast page allocation */ + paging.cache=0; + paging.free_link=0; + for (i=0;i