1
0
Fork 0

Paging tables/functions changed somewhat

Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@1356
This commit is contained in:
Sjoerd van der Berg 2003-10-22 14:30:57 +00:00
parent 708eee4f86
commit e712e7dc9c
2 changed files with 282 additions and 640 deletions

View file

@ -23,169 +23,165 @@
#include "dosbox.h"
#include "mem.h"
#include "paging.h"
#include "../hardware/vga.h"
#include "regs.h"
#define LINK_TOTAL (64*1024)
static PageLink link_list[LINK_TOTAL];
struct PagingBlock paging;
PagingBlock paging;
static Bit32u mapfirstmb[LINK_START];
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;
Bitu PageHandler::readb(PhysPt addr) {
E_Exit("No byte handler for read from %d",addr);
return 0;
}
Bitu PageHandler::readw(PhysPt addr) {
return
(readb(addr+0) << 0) |
(readb(addr+1) << 8);
}
Bitu PageHandler::readd(PhysPt addr) {
return
(readb(addr+0) << 0) |
(readb(addr+1) << 8) |
(readb(addr+2) << 16) |
(readb(addr+3) << 24);
}
void PageHandler::writeb(PhysPt addr,Bitu val) {
E_Exit("No byte handler for write to %d",addr);
};
class PageTableChange : public PageChange {
void PageHandler::writew(PhysPt addr,Bitu val) {
writeb(addr+0,(Bit8u) (val >> 0));
writeb(addr+1,(Bit8u) (val >> 8));
}
void PageHandler::writed(PhysPt addr,Bitu val) {
writeb(addr+0,(Bit8u) (val >> 0));
writeb(addr+1,(Bit8u) (val >> 8));
writeb(addr+2,(Bit8u) (val >> 16));
writeb(addr+3,(Bit8u) (val >> 24));
};
HostPt PageHandler::GetHostPt(Bitu phys_page) {
return 0;
}
class InitPageHandler : public PageHandler {
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);
}
InitPageHandler() {flags=0;}
void AddPageLink(Bitu lin_page, Bitu phys_page) {
assert(0);
}
Bitu readb(PhysPt addr) {
InitPage(addr);
return mem_readb(addr);
}
Bitu readw(PhysPt addr) {
InitPage(addr);
return mem_readw(addr);
}
Bitu readd(PhysPt addr) {
InitPage(addr);
return mem_readd(addr);
}
void writeb(PhysPt addr,Bitu val) {
InitPage(addr);
mem_writeb(addr,val);
}
void writew(PhysPt addr,Bitu val) {
InitPage(addr);
mem_writew(addr,val);
}
void writed(PhysPt addr,Bitu val) {
InitPage(addr);
mem_writed(addr,val);
}
void InitPage(Bitu addr) {
Bitu lin_page=addr >> 12;
Bitu phys_page;
if (paging.enabled) {
E_Exit("No paging support");
} else {
if (lin_page<LINK_START) phys_page=mapfirstmb[lin_page];
else phys_page=lin_page;
}
PAGING_LinkPage(lin_page,phys_page);
}
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("PAGING:Directory 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;
}
}
static InitPageHandler init_page_handler;
Bitu PAGING_GetDirBase(void) {
return paging.cr3;
}
void PAGING_ClearTLB(void) {
LOG(LOG_PAGING,LOG_NORMAL)("Clearing TLB");
Bitu i;
for (i=0;i<LINK_START;i++) {
paging.tlb.read[i]=0;
paging.tlb.write[i]=0;
paging.tlb.handler[i]=&init_page_handler;
}
MEM_UnlinkPages();
}
void PAGING_InitTLB(void) {
for (Bitu i=0;i<TLB_SIZE;i++) {
paging.tlb.read[i]=0;
paging.tlb.write[i]=0;
paging.tlb.handler[i]=&init_page_handler;
}
}
void PAGING_ClearTLBEntries(Bitu pages,Bit32u * entries) {
for (;pages>0;pages--) {
Bitu page=*entries++;
paging.tlb.read[page]=0;
paging.tlb.write[page]=0;
paging.tlb.handler[page]=&init_page_handler;
}
}
void PAGING_LinkPage(Bitu lin_page,Bitu phys_page) {
PageHandler * handler=MEM_GetPageHandler(phys_page);
Bitu lin_base=lin_page << 12;
HostPt host_mem=handler->GetHostPt(phys_page);
paging.tlb.phys_page[lin_page]=phys_page;
if (handler->flags & PFLAG_READABLE) paging.tlb.read[lin_page]=host_mem-lin_base;
else paging.tlb.read[lin_page]=0;
if (handler->flags & PFLAG_WRITEABLE) paging.tlb.write[lin_page]=host_mem-lin_base;
else paging.tlb.write[lin_page]=0;
handler->AddPageLink(lin_page,phys_page);
paging.tlb.handler[lin_page]=handler;
}
void PAGING_MapPage(Bitu lin_page,Bitu phys_page) {
if (lin_page<LINK_START) {
mapfirstmb[lin_page]=phys_page;
paging.tlb.read[lin_page]=0;
paging.tlb.write[lin_page]=0;
paging.tlb.handler[lin_page]=&init_page_handler;
} else {
PAGING_LinkPage(lin_page,phys_page);
}
}
void PAGING_SetDirBase(Bitu cr3) {
paging.cr3=cr3;
Bitu base_page=cr3 >> 12;
LOG(LOG_PAGING,LOG_NORMAL)("CR3:%X Base %X",cr3,base_page);
paging.base.page=cr3 >> 12;
paging.base.addr=cr3 & ~4095;
LOG(LOG_PAGING,LOG_NORMAL)("CR3:%X Base %X",cr3,paging.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;
PAGING_ClearTLB();
}
}
@ -195,7 +191,6 @@ void PAGING_Enable(bool enabled) {
paging.enabled=enabled;
if (!enabled) {
LOG(LOG_PAGING,LOG_NORMAL)("Disabled");
paging.dir=MEM_DefaultDirectory();
} else {
LOG(LOG_PAGING,LOG_NORMAL)("Enabled");
#if !(C_DEBUG)
@ -203,51 +198,20 @@ void PAGING_Enable(bool enabled) {
#endif
PAGING_SetDirBase(paging.cr3);
}
PAGING_ClearTLB();
}
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_Init(Section * sec) {
/* Setup default Page Directory, force it to update */
paging.enabled=false;
PAGING_InitTLB();
Bitu i;
for (i=0;i<LINK_START;i++) {
mapfirstmb[i]=i;
}
}
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<LINK_TOTAL;i++) PAGING_AddFreePageLink(&link_list[i]);
/* Setup default Page Directory, force it to update */
paging.enabled=true;PAGING_Enable(false);
}

View file

@ -30,20 +30,26 @@
#define PAGES_IN_BLOCK ((1024*1024)/MEM_PAGE_SIZE)
#define MAX_MEMORY 64
#define MAX_PAGE_ENTRIES (MAX_MEMORY*1024*1024/4096)
#define LFB_PAGES 512
static Bit8u controlport_data;
static bool a20_enabled;
#define MAX_LINKS ((MAX_MEMORY*1024/4)+4096) //Hopefully enough
struct AllocBlock {
Bit8u data[PAGES_IN_BLOCK*4096];
AllocBlock * next;
};
struct LinkBlock {
Bit8u used;
Bit32u pages[MAX_LINKS];
};
static struct MemoryBlock {
Bitu pages;
Bitu free_pages;
PageEntry * entries;
Bitu pages;
PageHandler * * phandlers;
HostPt * hostpts;
MemHandle * mhandles;
LinkBlock links;
struct {
Bitu pages;
HostPt cur_page;
@ -54,172 +60,94 @@ static struct MemoryBlock {
Bitu end_page;
Bitu pages;
HostPt address;
PageEntry entries[LFB_PAGES];
} lfb;
struct {
HostPt ram_bases[128/4];
HostPt map_base;
VGA_RANGES range;
} vga;
PageDirectory dir;
bool enabled;
Bit8u controlport;
} a20;
} memory;
Bit8u ENTRY_readb(PageEntry * pentry,PhysPt address) {
switch(pentry->type) {
case ENTRY_VGA:
return (*vga.config.readhandler)(pentry->data.vga_base+(address & 4095));
case ENTRY_NA:
if (pentry->data.dir->InitPageLinear(address)) return mem_readb(address);
break;
case ENTRY_INIT:
if (pentry->data.dir->InitPage(address)) return mem_readb(address);
break;
class IllegalPageHandler : public PageHandler {
public:
void AddPageLink(Bitu lin_page, Bitu phys_page) {
default:
LOG(LOG_PAGING,LOG_ERROR)("Entry read from %X with illegal type %d",address,pentry->type);
}
IllegalPageHandler() {
flags=0;
}
};
class RAMPageHandler : public PageHandler {
public:
void AddPageLink(Bitu lin_page, Bitu phys_page) {
/* Always clear links in first MB on TLB change */
if (lin_page<LINK_START) return;
if (memory.links.used<MAX_LINKS) {
memory.links.pages[memory.links.used++]=lin_page;
} else E_Exit("MEM:Ran out of page links");
}
RAMPageHandler() {
flags=PFLAG_READABLE|PFLAG_WRITEABLE;
}
HostPt GetHostPt(Bitu phys_page) {
if (!memory.hostpts[phys_page]) {
memory.hostpts[phys_page]=MEM_GetBlockPage();
}
return memory.hostpts[phys_page];
}
};
class ROMPageHandler : public RAMPageHandler {
public:
ROMPageHandler() {
flags=PFLAG_READABLE|PFLAG_HASROM;
}
};
class LFBPageHandler : public RAMPageHandler {
public:
LFBPageHandler() {
flags=PFLAG_READABLE|PFLAG_WRITEABLE|PFLAG_NOCODE;
}
HostPt GetHostPt(Bitu phys_page) {
return memory.lfb.address+(phys_page-memory.lfb.start_page)*4096;
}
};
static IllegalPageHandler illegal_page_handler;
static RAMPageHandler ram_page_handler;
static ROMPageHandler rom_page_handler;
static LFBPageHandler lfb_page_handler;
void MEM_SetLFB(Bitu page,Bitu pages,HostPt pt) {
memory.lfb.address=pt;
memory.lfb.start_page=page;
memory.lfb.end_page=page+pages;
memory.lfb.pages=pages;
PAGING_ClearTLB();
}
PageHandler * MEM_GetPageHandler(Bitu phys_page) {
if (phys_page<memory.pages) {
return memory.phandlers[phys_page];
} else if ((phys_page>=memory.lfb.start_page) && (phys_page<memory.lfb.end_page)) {
return &lfb_page_handler;
}
return 0;
}
Bit16u ENTRY_readw(PageEntry * pentry,PhysPt address) {
switch(pentry->type) {
case ENTRY_VGA:
{
VGA_ReadHandler * handler=vga.config.readhandler;
address=pentry->data.vga_base + (address & 4095);
return (*handler)(address) |
((*handler)(address+1) << 8);
}
case ENTRY_NA:
if (pentry->data.dir->InitPageLinear(address)) return mem_readw(address);
break;
case ENTRY_INIT:
if (pentry->data.dir->InitPage(address)) return mem_readw(address);
break;
default:
LOG(LOG_PAGING,LOG_ERROR)("Entry read from %X with illegal type %d",address,pentry->type);
}
return 0;
}
Bit32u ENTRY_readd(PageEntry * pentry,PhysPt address) {
switch(pentry->type) {
case ENTRY_VGA:
{
VGA_ReadHandler * handler=vga.config.readhandler;
address=pentry->data.vga_base + (address & 4095);
return (*handler)(address) |
((*handler)(address+1) << 8) |
((*handler)(address+2) << 16) |
((*handler)(address+3) << 24);
}
case ENTRY_NA:
if (pentry->data.dir->InitPageLinear(address)) return mem_readd(address);
break;
case ENTRY_INIT:
if (pentry->data.dir->InitPage(address)) return mem_readd(address);
break;
default:
LOG(LOG_PAGING,LOG_ERROR)("Entry read from %X with illegal type %d",address,pentry->type);
}
return 0;
}
void ENTRY_writeb(PageEntry * pentry,PhysPt address,Bit8u val) {
switch(pentry->type) {
case ENTRY_VGA:
(*vga.config.writehandler)(pentry->data.vga_base+(address&4095),val);
break;
case ENTRY_NA:
if (pentry->data.dir->InitPageLinear(address)) mem_writeb(address,val);
break;
case ENTRY_INIT:
if (pentry->data.dir->InitPage(address)) mem_writeb(address,val);
break;
case ENTRY_ROM:
LOG(LOG_PAGING,LOG_WARN)("Write %X to ROM at %X",val,address);
break;
case ENTRY_CHANGES:
writeb(pentry->data.mem+(address&4095),val);
{
Bitu start=address&4095;Bitu end=start;
for (PageLink * link=pentry->links;link;link=link->next)
if (link->change) link->change->Changed(link,start,end);
}
break;
default:
LOG(LOG_PAGING,LOG_ERROR)("Entry write %X to %X with illegal type %d",val,address,pentry->type);
void MEM_SetPageHandler(Bitu phys_page,Bitu pages,PageHandler * handler) {
for (;pages>0;pages--) {
memory.phandlers[phys_page]=handler;
phys_page++;
}
}
void ENTRY_writew(PageEntry * pentry,PhysPt address,Bit16u val) {
switch(pentry->type) {
case ENTRY_VGA:
{
VGA_WriteHandler * handler=vga.config.writehandler;
address=pentry->data.vga_base+(address&4095);
(*handler)(address,(Bit8u)val);
(*handler)(address+1,(Bit8u)(val>>8));
}
break;
case ENTRY_NA:
if (pentry->data.dir->InitPageLinear(address)) mem_writew(address,val);
break;
case ENTRY_INIT:
if (pentry->data.dir->InitPage(address)) mem_writew(address,val);
break;
case ENTRY_ROM:
LOG(LOG_PAGING,LOG_WARN)("Write %X to ROM at %X",val,address);
break;
case ENTRY_CHANGES:
writew(pentry->data.mem+(address&4095),val);
{
Bitu start=address&4095;Bitu end=start+1;
for (PageLink * link=pentry->links;link;link=link->next)
if (link->change) link->change->Changed(link,start,end);
}
break;
default:
LOG(LOG_PAGING,LOG_ERROR)("Entry write %X to %X with illegal type %d",val,address,pentry->type);
}
void MEM_UnlinkPages(void) {
PAGING_ClearTLBEntries(memory.links.used,memory.links.pages);
}
void ENTRY_writed(PageEntry * pentry,PhysPt address,Bit32u val) {
switch(pentry->type) {
case ENTRY_VGA:
{
VGA_WriteHandler * handler=vga.config.writehandler;
address=pentry->data.vga_base+(address&4095);
(*handler)(address,(Bit8u)val);
(*handler)(address+1,(Bit8u)(val>>8));
(*handler)(address+2,(Bit8u)(val>>16));
(*handler)(address+3,(Bit8u)(val>>24));
}
break;
case ENTRY_NA:
if (pentry->data.dir->InitPageLinear(address)) mem_writed(address,val);
break;
case ENTRY_INIT:
if (pentry->data.dir->InitPage(address)) mem_writed(address,val);
break;
case ENTRY_ROM:
LOG(LOG_PAGING,LOG_WARN)("Write %X to ROM at %X",val,address);
break;
case ENTRY_CHANGES:
writed(pentry->data.mem+(address&4095),val);
{
Bitu start=address&4095;Bitu end=start+3;
for (PageLink * link=pentry->links;link;link=link->next)
if (link->change) link->change->Changed(link,start,end);
}
break;
default:
LOG(LOG_PAGING,LOG_ERROR)("Entry write %X to %X with illegal type %d",val,address,pentry->type);
}
}
Bitu mem_strlen(PhysPt pt) {
Bitu x=0;
while (x<1024) {
@ -270,193 +198,11 @@ Bitu MEM_TotalPages(void) {
return memory.pages;
}
void MEM_UnlinkPage(PageLink * plink) {
PageLink * checker=plink->entry->links;
PageLink * * last=&plink->entry->links;
while (checker) {
if (checker == plink) {
*last=plink->next;
PAGING_AddFreePageLink(plink);
return;
}
last=&checker->next;
checker=checker->next;
}
E_Exit("Unlinking unlinked link");
}
PageLink * MEM_LinkPage(Bitu phys_page,PhysPt lin_base) {
PageEntry * entry;
/* Check if it's in a valid memory range */
if (phys_page<memory.pages) {
entry=&memory.entries[phys_page];
/* Check if it's in the lfb range */
} else if (phys_page>=memory.lfb.start_page && phys_page<memory.lfb.end_page) {
entry=&memory.lfb.entries[phys_page-memory.lfb.start_page];
} else {
/* Invalid memory */
LOG(LOG_PAGING,LOG_NORMAL)("Trying to link invalid page %X",phys_page);
return 0;
}
PageLink * link=PAGING_GetFreePageLink();
link->lin_base=lin_base;
link->change=0;
/* Check what kind of handler we need to give the page */
switch (entry->type) {
case ENTRY_RAM:
link->read=entry->data.mem - lin_base;
link->write=link->read;
break;
case ENTRY_ROM:
link->read=entry->data.mem - lin_base;
link->write=0;
break;
case ENTRY_VGA:
link->read=0;
link->write=0;
break;
case ENTRY_LFB:
link->read=entry->data.mem - lin_base;
link->write=link->read;
break;
case ENTRY_ALLOC:
entry->type=ENTRY_RAM;
entry->data.mem=MEM_GetBlockPage();
link->read=entry->data.mem - lin_base;
link->write=link->read;
break;
case ENTRY_CHANGES:
link->read=entry->data.mem - lin_base;
link->write=0;
break;
default:
E_Exit("LinkPage:Illegal type %d",entry->type);
}
/* Place the entry in the link */
link->entry=entry;
link->next=entry->links;
entry->links=link;
return link;
}
void MEM_CheckLinks(PageEntry * theentry) {
if (theentry->type!=ENTRY_RAM && theentry->type!=ENTRY_CHANGES) {
LOG(LOG_PAGING,LOG_NORMAL)("Checking links on type %d",theentry->type);
return;
}
bool haschange=false;PageLink * link;
for (link=theentry->links;link;link=link->next) {
if (link->change) {
haschange=true;break;
}
}
if (haschange) {
theentry->type=ENTRY_CHANGES;
for (link=theentry->links;link;link=link->next) {
link->read=theentry->data.mem - link->lin_base;
link->write=0;
}
} else {
theentry->type=ENTRY_RAM;
for (link=theentry->links;link;link=link->next) {
link->read=theentry->data.mem - link->lin_base;
link->write=link->read;
}
}
}
void MEM_AllocLinkMemory(PageEntry * theentry) {
//TODO Maybe check if this is a LINK_ALLOC type
HostPt themem=MEM_GetBlockPage();
theentry->data.mem=themem;
theentry->type=ENTRY_RAM;
theentry->links=0;
}
void MEM_SetLFB(Bitu page,Bitu pages,HostPt pt) {
if (pages>LFB_PAGES) E_Exit("MEM:LFB to large");
LOG(LOG_PAGING,LOG_NORMAL)("LFB Base at address %X,page %X",page*4096,page);
memory.lfb.pages=pages;
memory.lfb.start_page=page;
memory.lfb.end_page=page+pages;
memory.lfb.address=pt;
for (Bitu i=0;i<pages;i++) {
memory.lfb.entries[i].data.mem=pt+(i*4096);
memory.lfb.entries[i].type=ENTRY_LFB;
}
//TODO Maybe free the linked pages, but doubht that will be necessary
}
void MEM_SetupVGA(VGA_RANGES range,HostPt base) {
Bitu i;
memory.vga.map_base=base;
/* If it's another range, first clear the old one */
if (memory.vga.range!=range) {
Bitu start,end;
switch (memory.vga.range) {
case VGA_RANGE_A000:start=0;end=16;break;
case VGA_RANGE_B000:start=16;end=24;break;
case VGA_RANGE_B800:start=24;end=32;break;
}
for (i=start;i<end;i++) {
PageEntry * theentry=&memory.entries[i+0xa0];
HostPt themem=memory.vga.ram_bases[i];
theentry->data.mem=themem;
theentry->type=ENTRY_LFB;
PageLink * link=theentry->links;
while (link) {
link->read=themem - link->lin_base;
link->write=link->read;
link=link->next;
}
}
memory.vga.range=range;
}
/* Setup the new range, check if it's gonna handler based */
Bitu start,end;
switch (range) {
case VGA_RANGE_A000:start=0;end=16;break;
case VGA_RANGE_B000:start=16;end=24;break;
case VGA_RANGE_B800:start=24;end=32;break;
}
if (base) {
/* If it has an address it's a mapping */
for (i=start;i<end;i++) {
PageEntry * theentry=&memory.entries[i+0xa0];
HostPt themem=base+(i-start)*4096;
theentry->type=ENTRY_LFB;
theentry->data.mem=themem;
PageLink * link=theentry->links;
while (link) {
link->read=themem - link->lin_base;
link->write=link->read;
link=link->next;
}
}
} else {
/* No address, so it'll be a handler */
for (i=start;i<end;i++) {
PageEntry * theentry=&memory.entries[i+0xa0];
theentry->type=ENTRY_VGA;
PhysPt thebase=(i-start)*4096;
PageLink * link=theentry->links;
theentry->data.vga_base=thebase;
while (link) {
link->read=0;
link->write=0;
link=link->next;
}
}
}
}
Bitu MEM_FreeLargest(void) {
Bitu size=0;Bitu largest=0;
Bitu index=XMS_START;
while (index<memory.pages) {
if (!memory.entries[index].next_handle) {
if (!memory.mhandles[index]) {
size++;
} else {
if (size>largest) largest=size;
@ -472,7 +218,7 @@ Bitu MEM_FreeTotal(void) {
Bitu free=0;
Bitu index=XMS_START;
while (index<memory.pages) {
if (!memory.entries[index].next_handle) free++;
if (!memory.mhandles[index]) free++;
index++;
}
return free;
@ -483,7 +229,7 @@ Bitu MEM_AllocatedPages(MemHandle handle)
Bitu pages = 0;
while (handle>0) {
pages++;
handle=memory.entries[handle].next_handle;
handle=memory.mhandles[handle];
}
return pages;
}
@ -499,12 +245,12 @@ INLINE Bitu BestMatch(Bitu size) {
/* Check if we are searching for first free page */
if (!first) {
/* Check if this is a free page */
if (!memory.entries[index].next_handle) {
if (!memory.mhandles[index]) {
first=index;
}
} else {
/* Check if this still is used page */
if (memory.entries[index].next_handle) {
if (memory.mhandles[index]) {
Bitu pages=index-first;
if (pages==size) {
return first;
@ -535,7 +281,7 @@ MemHandle MEM_AllocatePages(Bitu pages,bool sequence) {
MemHandle * next=&ret;
while (pages) {
*next=index;
next=&memory.entries[index].next_handle;
next=&memory.mhandles[index];
index++;pages--;
}
*next=-1;
@ -545,9 +291,9 @@ MemHandle MEM_AllocatePages(Bitu pages,bool sequence) {
while (pages) {
Bitu index=BestMatch(1);
if (!index) E_Exit("MEM:corruption during allocate");
while (pages && (!memory.entries[index].next_handle)) {
while (pages && (!memory.mhandles[index])) {
*next=index;
next=&memory.entries[index].next_handle;
next=&memory.mhandles[index];
index++;pages--;
}
*next=-1; //Invalidate it in case we need another match
@ -558,8 +304,8 @@ MemHandle MEM_AllocatePages(Bitu pages,bool sequence) {
void MEM_ReleasePages(MemHandle handle) {
while (handle>0) {
MemHandle next=memory.entries[handle].next_handle;
memory.entries[handle].next_handle=0;
MemHandle next=memory.mhandles[handle];
memory.mhandles[handle]=0;
handle=next;
}
}
@ -580,22 +326,22 @@ bool MEM_ReAllocatePages(MemHandle & handle,Bitu pages,bool sequence) {
while (index>0) {
old_pages++;
last=index;
index=memory.entries[index].next_handle;
index=memory.mhandles[index];
}
if (old_pages == pages) return true;
if (old_pages > pages) {
/* Decrease size */
pages--;index=handle;old_pages--;
while (pages) {
index=memory.entries[index].next_handle;
index=memory.mhandles[index];
pages--;old_pages--;
}
MemHandle next=memory.entries[index].next_handle;
memory.entries[index].next_handle=-1;
MemHandle next=memory.mhandles[index];
memory.mhandles[index]=-1;
index=next;
while (old_pages) {
next=memory.entries[index].next_handle;
memory.entries[index].next_handle=0;
next=memory.mhandles[index];
memory.mhandles[index]=0;
index=next;
old_pages--;
}
@ -606,17 +352,17 @@ bool MEM_ReAllocatePages(MemHandle & handle,Bitu pages,bool sequence) {
if (sequence) {
index=last+1;
Bitu free=0;
while ((index<memory.pages) && !memory.entries[index].next_handle) {
while ((index<(MemHandle)memory.pages) && !memory.mhandles[index]) {
index++;free++;
}
if (free>=need) {
/* Enough space allocate more pages */
index=last;
while (need) {
memory.entries[index].next_handle=index+1;
memory.mhandles[index]=index+1;
need--;index++;
}
memory.entries[index].next_handle=-1;
memory.mhandles[index]=-1;
return true;
} else {
/* Not Enough space allocate new block and copy */
@ -630,63 +376,38 @@ bool MEM_ReAllocatePages(MemHandle & handle,Bitu pages,bool sequence) {
} else {
MemHandle rem=MEM_AllocatePages(need,false);
if (!rem) return false;
memory.entries[last].next_handle=rem;
memory.mhandles[last]=rem;
return true;
}
}
return 0;
}
void MEM_UnmapPages(Bitu phys_page,Bitu pages) {
for (;pages;pages--) {
memory.dir.LinkPage(phys_page,phys_page);
phys_page++;
}
}
void MEM_MapPagesHandle(Bitu lin_page,MemHandle mem,Bitu mem_page,Bitu pages) {
for (;mem_page;mem_page--) {
if (mem<=0) E_Exit("MEM:MapPages:Fault in memory tables");
mem=memory.entries[mem].next_handle;
}
for (;pages;pages--) {
if (mem<=0) E_Exit("MEM:MapPages:Fault in memory tables");
memory.dir.LinkPage(lin_page++,mem);
mem=memory.entries[mem].next_handle;
}
}
void MEM_MapPagesDirect(Bitu lin_page,Bitu phys_page,Bitu pages) {
for (;pages;pages--) {
memory.dir.LinkPage(lin_page++,phys_page++);
}
}
MemHandle MEM_NextHandle(MemHandle handle) {
return memory.entries[handle].next_handle;
return memory.mhandles[handle];
}
MemHandle MEM_NextHandleAt(MemHandle handle,Bitu where) {
while (where) {
where--;
handle=memory.mhandles[handle];
}
return handle;
}
/*
A20 line handling,
Basically maps the 4 pages at the 1mb to 0mb in the default page directory
*/
bool MEM_A20_Enabled(void) {
return a20_enabled;
return memory.a20.enabled;
}
void MEM_A20_Enable(bool enabled) {
a20_enabled=enabled;
Bitu i;
if (!enabled) {
for (i=0x0;i<0x10;i++) {
memory.dir.LinkPage(0x100+i,i);
}
} else {
for (i=0x0;i<0x10;i++) {
memory.dir.LinkPage(0x100+i,0x100+i);
}
}
Bitu phys_base=enabled ? (1024/4) : 0;
for (Bitu i=0;i<16;i++) PAGING_MapPage((1024/4)+i,phys_base+i);
memory.a20.enabled=enabled;
}
@ -742,20 +463,11 @@ void mem_writed(PhysPt address,Bit32u val) {
}
void phys_writeb(PhysPt addr,Bit8u val) {
Bitu page=addr>>12;
if (page>=memory.pages) E_Exit("physwrite:outside of physical range");
PageEntry * theentry=&memory.entries[page];
switch (theentry->type) {
case ENTRY_ALLOC:
MEM_AllocLinkMemory(theentry);
break;
case ENTRY_RAM:
case ENTRY_ROM:
break;
default:
E_Exit("physwrite:illegal type %d",theentry->type);
HostPt block=memory.hostpts[addr >> 12];
if (!block) {
block=memory.hostpts[addr >> 12]=MEM_GetBlockPage();
}
writeb(theentry->data.mem+(addr & 4095),val);
host_writeb(block+(addr & 4095),val);
}
void phys_writew(PhysPt addr,Bit16u val) {
@ -771,17 +483,6 @@ void phys_writed(PhysPt addr,Bit32u val) {
}
Bit32u phys_page_readd(Bitu page,Bitu index) {
if (page>=memory.pages) E_Exit("physwrite:outside of physical range");
PageEntry * theentry=&memory.entries[page];
switch (theentry->type) {
case ENTRY_CHANGES:
case ENTRY_RAM:
case ENTRY_ROM:
return readd(memory.entries[page].data.mem+index*4);
break;
default:
E_Exit("pageread:illegal type %d",theentry->type);
}
return 0;
}
@ -789,19 +490,15 @@ Bit32u phys_page_readd(Bitu page,Bitu index) {
static void write_p92(Bit32u port,Bit8u val) {
// Bit 0 = system reset (switch back to real mode)
if (val&1) E_Exit("XMS: CPU reset via port 0x92 not supported.");
controlport_data = val & ~2;
memory.a20.controlport = val & ~2;
MEM_A20_Enable((val & 2)>0);
}
static Bit8u read_p92(Bit32u port) {
return controlport_data | (a20_enabled ? 0x02 : 0);
return memory.a20.controlport | (memory.a20.enabled ? 0x02 : 0);
}
PageDirectory * MEM_DefaultDirectory(void) {
return &memory.dir;
}
HostPt MEM_GetBlockPage(void) {
HostPt ret;
if (memory.block.pages) {
@ -847,36 +544,17 @@ void MEM_Init(Section * sec) {
memsize=MAX_MEMORY;
}
memory.pages=(memsize*1024*1024)/4096;
if (memory.pages>0x110) memory.free_pages=memory.pages-0x110;
else memory.free_pages=0;
memory.entries= new PageEntry[memory.pages];
/* Allocate the data for the different page information blocks */
memory.hostpts=new HostPt[memory.pages];
memory.phandlers=new PageHandler * [memory.pages];
memory.mhandles=new MemHandle [memory.pages];
for (i=0;i<memory.pages;i++) {
memory.entries[i].type=ENTRY_ALLOC;
memory.entries[i].data.mem=0;
memory.entries[i].links=0;
memory.entries[i].next_handle=0; //Set to 0 for memory allocation
}
/* Setup 128kb of memory for the VGA segments */
for (i=0;i<128/4;i++) {
memory.vga.ram_bases[i]=MEM_GetBlockPage();
memory.entries[0xa0+i].type=ENTRY_LFB;
memory.entries[0xa0+i].data.mem=memory.vga.ram_bases[i];
}
memory.vga.range=VGA_RANGE_B800;
/* Setup the default page mapping */
memory.dir.entry_init.type=ENTRY_NA; //Setup to use NA by default
memory.dir.ClearDirectory();
/* All pages now pointing to NA handler that will check on first access */
/* Setup the ROM Areas */
for (i=0xc0;i<0xd0;i++) {
MEM_AllocLinkMemory(&memory.entries[i]);
memory.entries[i].type=ENTRY_ROM;
}
for (i=0xf0;i<0x100;i++) {
MEM_AllocLinkMemory(&memory.entries[i]);
memory.entries[i].type=ENTRY_ROM;
memory.hostpts[i]=0; //0 handler is allocate memory
memory.phandlers[i]=&ram_page_handler;
memory.mhandles[i]=0; //Set to 0 for memory allocation
}
/* Reset some links */
memory.links.used=0;
// A20 Line - PS/2 system control port A
IO_RegisterWriteHandler(0x92,write_p92,"Control Port");
IO_RegisterReadHandler(0x92,read_p92,"Control Port");