/* SetCPU V1.60 by Dave Haynie, April 13, 1990 Released to the Public Domain MMU.C MODULE This module is responsible for some of the MMU table creation functions. */ #include "setcpu.h" /* ====================================================================== */ /* This function maps the phantom area for a given memory location. */ void Phantom(tag,loc) struct systag *tag; ULONG loc; { ULONG xindex = loc/ROMROUND; if (xindex < 60) tag->maintable[xindex] = PD_ADDR(0x00800000)|PD_DT_PAGE; else tag->maintable[xindex] = PD_ADDR(0x00ce0000)|PD_DT_PAGE; } /* This table contains a list of the blocks of memory that should be cache-inhibited. */ static ULONG InTable[] = { 0x00000000,0x00200000,0x00b00000,0x00f00000,0L,0L }; /* This function fills the basic MMU table and other standard tag itemd from an allocated image. Some tables may need additional information in the table. The basic table consists of one table level and uses direct page translation on a grain of 128K per entry. Everything's directly mapped except for the last two entries, which are for the $FC0000-$FFFFFF area. */ void FillBasicTable(tag,phantoms) struct systag *tag; LONG phantoms; { register ULONG i, image, j; ULONG page,size,loc; tag->tagsize = SizeOf(struct systag); tag->progver = PROGRAM_VERSION; tag->patches = 0; tag->patchlist = tag->devs = NULL; tag->config = 1; tag->BerrSize = 0L; tag->OldBerr = tag->BerrHandler = NULL; tag->sysstack = NULL; tag->sysstksize = 0; tag->OldReset = tag->ResetCode = NULL; tag->ResetSize = 0; /* Here I make a table that maps everything straight through. */ for (i = 0; i < tag->tablesize/sizeof(ULONG); i++) tag->maintable[i] = PD_ADDR(i<<17)|PD_DT_PAGE; tag->maintable[i] = IV_ADDR(tag)|PD_DT_INVALID; /* Mark the inhibited pages. */ for (i = 0; InTable[i+1]; i += 2) for (j = InTable[i]/PAGESIZE; j < InTable[i+1]/PAGESIZE; ++j) tag->maintable[j] |= PD_CI; /* Here I map the ROM image to the ROM location. */ image = (ULONG)tag->romlo; loc = tag->romloc/PAGESIZE; if (image) { if (phantoms) Phantom(tag,image); tag->maintable[loc++] = PD_ADDR(image)|PD_WP|PD_DT_PAGE; if (phantoms) Phantom(tag,image+PAGESIZE); tag->maintable[loc++] = PD_ADDR(image+PAGESIZE)|PD_WP|PD_DT_PAGE; } image = (ULONG)tag->romhi; if (phantoms) Phantom(tag,image); tag->maintable[loc++] = PD_ADDR(image)|PD_WP|PD_DT_PAGE; if (phantoms) Phantom(tag,image+PAGESIZE); tag->maintable[loc] = PD_ADDR(image+PAGESIZE)|PD_WP|PD_DT_PAGE; /* Here I look for Bridge Cards, which are known to have problems with the data cache enabled, so I always disable it, reguardless of whether caching is actually enabled in the CACR. */ if (Bridge.Addr && Bridge.Size) { page = Bridge.Addr/PAGESIZE; size = max((ULONG)Bridge.Size/PAGESIZE,1); while (size-- && page < tag->tablesize) if ((tag->maintable[page] & PD_DT_TYPE) == PD_DT_PAGE) tag->maintable[page++] |= PD_CI; } } /* This routine sets up the MMU registers (shadowed in tag fields) in the standard SetCPU fashion. The CPU Root Pointer tells the MMU about the table I've set up, and all that's left to do is bang the Translation Control Register to turn the thing on. Note that the first half of the CRP is control data, the second the address of my table. */ void SetMMURegs(tag) struct systag *tag; { tag->CRP[0] = CRP_LIMIT(tag->tablesize/sizeof(ULONG)-1)|CRP_SG|CRP_DT_V4BYTE; tag->CRP[1] = (ULONG)(tag->maintable); tag->TC = TC_PS(0x0a)|TC_IS(tag->wrapup)| TC_TIA(0x0f-tag->wrapup)|TC_TIB(0x03)|TC_TIC(0x04)|TC_TID(0); } /* ====================================================================== */ /* This function frees all MMU tables. */ void FreeMMUTable(tag) struct systag *tag; { ULONG i,j, *subtab; for (i = 0; i < 128; ++i) if ((tag->maintable[i] & PD_DT_TYPE) == PD_DT_V4BYTE) { for (subtab = (ULONG *)PD_ADDR(tag->maintable[i]), j = 0; j < 8; ++j) if ((subtab[j] & PD_DT_TYPE) == PD_DT_V4BYTE) FreeMem((char *)PD_ADDR(subtab[j]),STKTABSIZE); FreeMem((char *)subtab,SUBTABSIZE); } FreeMem((char *)tag->maintable,tag->tablesize); } /* ====================================================================== */ /* This function makes subtables for CardROMFile I/O devices. */ void MakeExpTable(tag) struct systag *tag; { ULONG i, *SUBTable, iospace; struct ExpROMData *er; while (er = GetExpROM()) { er->next = tag->devs; tag->devs = er; iospace = ((ULONG)er->ROMbase)/ROMROUND; /* If necessary, modify the table */ if (tag->maintable[iospace] == PD_ADDR(iospace<<17)|PD_DT_PAGE) { if (SUBTable = AllocAligned(SUBTABSIZE,TABROUND)) { for (i = 0; i < 8; ++i) SUBTable[i] = PD_ADDR((iospace<<17)+(i<<14))|PD_CI|PD_DT_PAGE; tag->maintable[iospace] = PD_ADDR(SUBTable)|PD_DT_V4BYTE; } } else SUBTable = (ULONG *)PD_ADDR(tag->maintable[iospace]); if (SUBTable) { er->imagebase = (ULONG)AllocAligned(er->ROMsize,DEVROUND); er->tablebase = (ULONG)&SUBTable[0]; MemCopy(er->ROMbase,er->imagebase,er->ROMsize); iospace = (er->ROMbase - (iospace * ROMROUND))/DEVROUND; for (i = 0; i < er->ROMsize/DEVROUND; ++i) SUBTable[iospace+i] = PD_ADDR(er->imagebase+(DEVROUND*i))|PD_CI|PD_DT_PAGE; } } } /* ====================================================================== */ /* This function hunts down the system stack and translates it into a block of 32 bit memory if it's found to be located in Chip RAM. Note that this routine must only be called when the MMU is turned on. The current functions used to turn the MMU on make use of the supervisor stack. This code must be run in user mode to insure that the supervisor stack image and the actual stack are the same during the transfer of control. */ void MakeFastStack(tag) struct systag *tag; { struct ExecBase *eb = *((struct ExecBase **)4L); ULONG i, *SUBTable, *STKTable, tabndx, subndx, stkndx, tmem, base; base = (((ULONG)eb->SysStkLower)/STKROUND)*STKROUND; if (base >= 0x00200000L) return; tag->sysstksize = (((ULONG)eb->SysStkUpper - (ULONG)eb->SysStkLower + 1)/STKROUND)*STKROUND; tabndx = base/ROMROUND; tmem = tabndx * ROMROUND; /* Make the I/O level subtable (level 2). Most entries are going to be a straight translation. */ if (!(SUBTable = AllocAligned(SUBTABSIZE,TABROUND)) || !(STKTable = AllocAligned(STKTABSIZE,TABROUND))) return; for (i = 0; i < 8; ++i) SUBTable[i] = PD_ADDR(tmem+(i*DEVROUND))|PD_DT_PAGE; tag->maintable[tabndx] = PD_ADDR(SUBTable)|PD_DT_V4BYTE; /* Make the Stack level subtable (level 3). Fill all 16 entries with a straight translation. */ subndx = (base - tmem)/DEVROUND; tmem += subndx * DEVROUND; for (i = 0; i < 16; ++i) STKTable[i] = PD_ADDR((tmem)+(i*STKROUND))|PD_DT_PAGE; SUBTable[subndx] = PD_ADDR(STKTable)|PD_DT_V4BYTE; /* Now take care of the actual stack translation. */ tag->sysstack = (char *)AllocAligned(tag->sysstksize,STKROUND); MemCopy(base,tag->sysstack,tag->sysstksize); stkndx = (base - tmem)/STKROUND; for (i = 0; i < tag->sysstksize/STKROUND && i < 16; ++i) STKTable[i+stkndx] = PD_ADDR(tag->sysstack+(STKROUND*i))|PD_DT_PAGE; FlushATC(); } /* This function removes the fast stack translation. Like the fast stack creation routine, this must be called with the MMU turned on, in user mode, so that both stack images can be identical when the switch is made. This routine doesn't clean up the MMU tables, it just deals with the stack image. */ void FreeFastStack(tag) struct systag *tag; { struct ExecBase *eb = *((struct ExecBase **)4L); ULONG *SUBTable, *STKTable, tabndx, subndx, tmem, base; base = (((ULONG)eb->SysStkLower)/STKROUND)*STKROUND; /* Find the stack's translation table. */ tabndx = base/ROMROUND; tmem = tabndx * ROMROUND; SUBTable = (ULONG *)PD_ADDR(tag->maintable[tabndx]); subndx = (base - tmem)/DEVROUND; /* Set things back the way they were. */ Disable(); STKTable = (ULONG *)PD_ADDR(SUBTable[subndx]); MemCopy(tag->sysstack,base,tag->sysstksize); SUBTable[subndx] = PD_ADDR(tmem+(subndx*DEVROUND))|PD_DT_PAGE; FlushATC(); Enable(); /* Get rid of the fast image stuff. */ FreeMem((char *)STKTable,STKTABSIZE); FreeMem((char *)tag->sysstack,tag->sysstksize); } /* ====================================================================== */ /* This routine knows the best way to reset the system, in an attempt to avoid MMU-based troubles. */ void CleverReset() { geta4(); CleanBoot(); }