; ; Hacks to match MacOS (most recent first): ; ; 8/3/92 Elliot make this change ; 9/2/94 SuperMario ROM source dump (header preserved below) ; ; ; File: HwPriv.a ; ; Contains: This file holds the implementation of the HwPriv trap. ; ; Copyright: © 1987-1994 by Apple Computer, Inc. All rights reserved. ; ; Change History (most recent first): ; ; 2/7/94 chp Extensive housecleaning in the HwPriv implementations, including ; the elimination of separate RISC and 68K dispatch tables. ; 12/23/93 PN Take out overpatches on LockMemoryproc, LockMemoryContigousProc ; and also take out IsUniversal conditionals. ; 12/13/93 PN Roll in KAOs and Horror changes to support Malcom and AJ ; machines. ; 11/9/93 KW added some eieioSTP macros. Only expands for CygnusX1 ROM ; 10/14/93 pdw . ; 10/11/93 CCH Separated Edisk protect routine into one for PowerPC and one for ; 68k. ; 10/10/93 CCH Turned on EDisk support for PowerPC machines. ; 9/13/93 SAM Replaced the alternate dispatch table that was inadvertently ; removed in the last rev. ; 9/1/93 chp DMADispatch is no more. This eliminates the _DMAIntInstall and ; frees up selector 11. All clients have been modified to use more ; efficient inline code instead. ; 8/19/93 chp Fix the dispatcher so it won’t barf on a selector of 13. (BHI -> ; BHS) ; 8/4/93 GMR Added code to SlotBlockXferCtl to support block transfers ; for BART machines (PDM,CF). ; 6/14/93 SAM Reenabled the "DMADispatch" selector for PDM. ; 6/14/93 kc Roll in Ludwig. ; 3/24/93 mal Added SlotBlockXferCtl to rom build. For system builds, updated ; LastVec, changed dispatch to BHS, and added cacheflushes to the ; self-modifying code. ; 4/22/93 CSS Changed emDMADispGlobs to emDMADispatchGlobals which matches ; Reality. ; 4/8/93 KW (LW7 KW) fixing Radar bug #1073805 and Radar bug #1075450. If ; RAM disk was on and using up lots of memory, Finder duplication ; would hang the System. MacWrite Pro would not install very well ; either. Routine chkContig was not initializing local var ; physAddr before use. Also calls to GetRealProc would trash A2 ; which was holding a pointer to Memory Dispatch Globals. ; 4/2/93 GMR Changed the parameters to _DMAIntInstall for PDM, to take a ; param block ptr in A0. This fixes the problem where a2 was used ; to pass in the refCon and was getting trashed. ; 3/11/93 SAM Added a refCon field to the PDM DMA irq handler installer. ; 2/20/93 SAM Changed every Page Table Entry/MMU whacking routine to work with ; EMMUs. Removed a few more slow things from GetPhysical - it ; shouldn't call any traps any more (rah!). Removed all the TST.W ; that followed every call to GetRealProc. Updated ; InitMemoryDispatch to know about EMMUs. Removed the separate ; code that Unimplements memorydispatch and put its functionality ; into InitMemDispatch. ; 2/11/93 PW Added passing of drivers' "don't munge heaps" bit into SCSILoad. ; 2/9/93 rab Sync up with Horror. Comments follow. ;

7/13/92 NJV Fixed bug in LockMemory and LockMemoryContiguous that ; crashed when the page containing the current stack was locked. ; Fixed it by turning off the data cache between modifying page ; descriptors and flushing the ATC. ; 2/6/93 RC Fixed last fix (sorry) ; 2/6/93 RC Fixed InitMemDispatchTrap for Quadra ; 2/5/93 SAM Added PDM build specific vectors for MemoryDispatch and have ; changed the code that unimplements MemDisp if you don't have a ; known MMU type. ; 12/11/92 SWC Moved the code to disable the MemoryDispatch trap here from ; StartInit. Put a hasMDU conditional around the EnableExtCache ; code. ; 11/3/92 SWC Changed SCSIEqu.a->SCSI.a. ; 10/30/92 chp I universalized DMADispatch by making it appear to be ; unimplemented (return paramErr) on machines with no PSC. ; DMADispatchNub should not be link patched for non-universal ROMs ; because it makes a TestFor. SwapSerialClock is broken on ; non-universal ROMs for exactly this reason. ; 6/19/92 RB Added the selector for the DMADispatch code. ; 5/17/92 kc Roll in Horror changes. Comments follow. ; 4/22/92 kc Changed MemoryDispatch to use word offsets instead of long ; offsets. Stubed out the routine LockMemoryContiguousProc in ; order to get the flasher to work. ; 7/11/91 CCH Fixed a bug in GetPhysical. ; 6/27/91 djw (pdw) Add new selector _WaitForSCSIDevs to wait for SCSI devices ; and load their drivers. Just added nub code here. ; 6/14/91 RP Changed length parameter for FlushCacheRange to be passed in A1 ; instead of D1. ; 5/10/91 RP Added selector to HwPriv for flush cache range. ; 5/10/91 CCH Added selector to HwPriv for Edisk protection. ;
2/18/91 JK Added WriteProtect selectors to MemoryDispatch ;
1/24/91 JK Added LockMemory calls that use a page-lock table. ;

1/24/91 CCH Moved LastEnt label to include new selectors. ;

1/24/91 CCH Significantly modified MemoryDispatch code. Removed translate ; routine in favor of _GetReal call, modified _GetPhysical to use ; GetRealProc instead. Added _GetReal and _GetPageDesc selectors. ; Removed _LockMemory code since it will change anyway. Also added ; padding at end of file. ;

10/2/90 CCH Patched out cache manipulation routines to HwPrivPatch.a. ; • from HwPrivPatch.a ; <13> 7/11/91 HJR Change return result from SCSIDrvrs to success/failed. ; <12> 7/10/91 RP Changed FlushCacheRange to round count to be quad-word aligned. ; <11> 6/27/91 djw (pdw) Add WaitForSCSIDevs to wait for SCSI devices and load ; their drivers. ; <10> 6/25/91 CCH Fixed _SwapDataCache to flush the data cache before disabling it ; on 68040's. Also jump through jCacheFlush instead of using a ; CPUSH instruction in _FlushInstructionCache and ; _SwapInstructionCache. ; <9> 6/14/91 RP Changed length parameter for FlushCacheRange to be passed in A1 ; instead of D1. ; <8> 5/10/91 RP Added support to flush a range of cache lines from the 040 ; cache. ; <7> 5/10/91 CCH Made _ProtectMemory and _UnProtectMemory use the CacheFlush ; low-mem. ; <6> 4/22/91 BG Modified 040 cache flushing routines to add a NOP before the ; CPUSHA . This is required because of Motorola's xD43B ; errata item E19. This should be removed when the 040 processor ; base is D50D. Changed _FlushInstructionCache to jump to ; ([jCacheFlush]) so that if/when we have to fix/unfix flushing ; ALL caches, we only have to do it in one place. ; <5> 4/18/91 BG Changed the 040 part of _FlushInstructionCache to flush both ; caches. People are probably calling this becasuse they just ; read in some code/resource/driver/whatever that they want to ; execute and they want to make sure whatever it is in memory and ; the instruction cache is synchronized with memory. On the 040, ; the best way to do this is to flush both caches. ; <4> 2/18/91 JK Added WriteProtect and UnWriteProtect code ; <3> 1/24/91 JK MMUSetCacheMode whacks page descriptor in 32-bit mode. ; <2> 1/24/91 JK Added LockMemory calls that use a page-lock table. ; <1> 10/3/90 CCH first checked in ; ; <4> 3/31/92 FM Merged in changes from Reality. ; <3> 3/31/92 FM Rolled changes into reality. ; <2> 2/13/92 RB When I rolled in the new HWPriv selector for Flush cache range, ; I put the wrong label in the table. That label is used only by ; the 040 Blockmove, which passes parameters in the stack. ; Correcting the label will fix the stack. ; <29> 2/20/92 DTY #1021830: The Regatta version of _HWPriv totally breaks ; accelerators for 68000 CPUs because a selector number is not put ; in place for these machines. What winds up happening is on ; accelerated 68000s, every selector returns an error because ; _HWPriv thinks it’s an invalid selector. Add a new InstallProc ; which initializes the valid selector range for the Plus, SE, and ; Portable ROMs if CPUFlag is a 68020 or 68030. ; <28> 1/24/92 KC Fix bug introduced in last revision (replace missing semicolon). ; <27> 1/23/92 KC Added InitMemoryDispatch from Zydeco:HWPrivPatch.a. ; <26> 1/3/92 RB Added the Flush cache range routine for 68040's from Terror to ; the ROM build. The system table is unchanged (uses Flush ; instruction cache instead). ; <25> 1/3/92 RB Added the EDiskProtection routine to the ROM hwPriv table. ; Terror changes in HWPrivPatch.a (Terror file) need to be looked ; at before modifying this file. ; <24> 11/16/91 DTY More BandAids® to get the ROM build working again. Re-export ; EnableExtCache (called by StartInit), put back MemoryDispatch ; code (referenced from DispTable), and add the HWPriv label back ; (also referenced from DispTable). ; <23> 10/29/91 SAM This file will now generate the correct code for the ROM build ; (it even works and doesnt change the System build code - rah). ; Everything changed in this rev is enclosed in forROM ; conditionals. ; <22> 10/29/91 SAM Removed the ‘stupid conditionals’ again. Sorry about that Jeff. ; <21> 10/28/91 SAM/KSM Rolled in Regatta file. Undid Changes <17>-<20>. ; ; 7.0.1 Change History: ; ; <6> 7/17/91 SAM Removed the commented out MemoryDispatch patch stuff. Added ; Paul Wolf's WaitForSCSI to hwPriv's list o' routines. ; <5> 6/14/91 SAM The hwPriv install procs that set up the ExpandMem set of ; vectors now only load on II ROMs or IIci ROMs. ; <3> 5/28/91 SAM Rewrote all of the HwPriv patcher/dispatcher. Now we have ; relocatable tables of vectors to the hwPriv routines that get ; installed by the LinkedPatch Loader. Non-TERROR ROM 020/030 ; Machines get their own table (that includes all of the routines ; in this file) and TERROR machines get a table of zeroes (which ; means call the ROM). This way all the code in this file is not ; loaded when not needed and also there is now an easy way to ; patch the vectors via expandMem. ; <2> 5/23/91 SAM Rewrote the hwPriv dispatcher. Now more LinkedPatch friendly ; than ever! Will now jump to ROM on a selector that is out of ; range. Made the table of hwPrivSelectors a separate resident ; proc. Added a new macro for the table of selectors called ; HwPrivSelectorInROM that acts as a placeholder for selectors ; that are implemented in ROM. ; <1> 5/22/91 SAM Split off from 7.0 GM sources. Changed hwPriv to call the ROM hwPriv ; for all selectors that this file doesnt know about. ; ; 7.0 Change History: ; ; <20> 10/18/91 JSM Get rid of all the stupid conditionals. ; <19> 9/30/91 JSM Cleanup header, don’t use is32BitClean conditional - all future ; ROMs will be. ; <18> 8/30/91 DTY Define isUniversal here since it’s no longer an available ; feature in BBSStartup. ; <17> 6/12/91 LN removed #include 'HardwareEqu.a' ; <16> 3/11/91 gbm stb, bbm: Take out the bogus GetPhysical patch, in preparation ; of loading the new one. ; <15> 2/6/91 eh (djw) Fix SwapSerialClock routine to wait for IOP request ; completion before returning. ; <14> 1/3/91 gbm (dnf) Fix last addition made by SAM. One of these days, he'll ; actually build the files he checks in. ; <13> 1/3/91 SAM Changed the LinkedPatch install conditional so that the patch to ; _MemoryDispatch for getPhysical is not installed if VM is ; running. ; <12> 12/14/90 dba get rid of include of VMCalls.a ; <11> 8/22/90 SAM Adding fixes to GetPhysical so it works correctly with the ; 8•24•GC. ; <10> 8/21/90 csd Changed the condition for the MemoryDispatch patch so that it ; doesn’t install where MemoryDispatch is not implemented. (Elsie) ; <9> 7/30/90 BG Fixed 040 CACR-related problems. ; <8> 7/24/90 EMT NEEDED FOR SIXPACK: Fixed 68000 code and eliminated unecessary ; table. ; <7> 7/23/90 CCH NEEDED FOR SIXPACK: Patched the GetPhysical selector on ; _MemoryDispatch on $67c based ROMs to return physical addresses ; for non-RAM logical addrs. ; <6> 7/21/90 BG Removed unnecessary EclipseNOPs. Also changed s to <5>s ; (yer welcome, Carl). ; <5> 7/19/90 CCH NEEDED FOR SIXPACK: Rolled in SwapSerialClock selector from PTCH ; file and converted to linked patches. ; <4> 6/19/90 CCH Changed two occurences of CINVA IC to CPUSHA BC to hopefully ; prevent incompatibility problems with the 68040 copyback cache ; mode. Also added some NOPs for flaky 68040's. ; <3> 2/18/90 BG Added 040 versions of the machine-dependent routines for ; manipulating the I&D caches. ; <2> 1/11/90 CCH Added include of “HardwarePrivateEqu.a”. ; <2.1> 7/16/89 CSL cleaned up lockMemoryCont, GetPhysical, Translate. ; <2.0> 6/30/89 CSL disable data cache and increment LockMemCt when LockMemory and ; LockMemoryContiguous is performed successfully, increment ; lockMemCt when UnLockMemory is called, if LockMemCt becomes ; zero, enable data cache. Also removed selector for ; GetSystemMemoryInfo. ; <1.9> 6/15/89 CSL Added FlushExtCache selector. ; <1.8> 5/31/89 CSL Use register D2 for error code for chkcontiguous. ; <1.7> 5/30/89 GGD Added missing ".b" to DisableExtCache RBV access. Added code to ; return noErr for EnableExtCache and DisableExtCache. ; <1.6> 5/30/89 CSL For getPhysical and LockMemoryContiguous, always switched to 32 ; bit ; <1.5> 5/24/89 GGD Converted to feature based conditionals, No code changes. ; <1.4> 5/16/89 CSL changed using EQU Frmbufbase to lowMem Phys2log. ; <1.3> 4/28/89 CSL Changed Interface for GetPhysical. ; <1.2> 4/17/89 CSL update _MemoryDispatch with VM spec. ; <1.1> 2/28/89 CSL Added MemoryDispatch trap for address translation for hafmac. ; <1.0> 2/24/89 rwh rolled in today from Mac IIx ROM ; MACHINE MC68030 PRINT PUSH,OFF LOAD 'StandardEqu.d' INCLUDE 'hardwarePrivateEqu.a' INCLUDE 'GestaltEqu.a' INCLUDE 'InternalMacros.a' INCLUDE 'UniversalEqu.a' INCLUDE 'MMUEqu.a' INCLUDE 'IOPEqu.a' INCLUDE 'LinkedPatchMacros.a' INCLUDE 'SCSI.a' INCLUDE 'PowerPrivEqu.a' INCLUDE 'DockingEqu.a' PRINT POP ;---------- ; ; HwPrivSelector Macro ; ;---------- MACRO HwPrivSelector &addr IMPORT &addr dc.w &addr-Vects ; OFFSET of routine ENDM HwVecSize EQU 2 ;---------- ; ; HWPriv (_HWPriv trap) ; ; The _HWPriv trap was created to export some low level hardware control capabilites to ; the (user mode) world at large. A selector passed in D0 determines which specific ; transistor to twiddle. ; ; The selector mechanism makes the trap expandable - as we add more strange hardware, ; we can define new selectors (and write new routines) to control it. Each selector ; is almost like a new trap. If we want to be really gross, the parameter passing ; conventions can be different for each selector. At the expense of a non-uniform ; interface to the trap, this avoids having to invent some cumbersome huge extendable ; parameter block that covers all present and future possibilities. ; ; The selectors currently defined are: ; ; 0 - SwapInstructionCache (turn off/on the 020/030/... instruction cache) ; 1 - FlushInstructionCache ; 2 - SwapDataCache (turn off/on the 030/... data cache) ; 3 - FlushDataCache ; 4 - EnableExtCache ; 5 - DisableExtCache ; 6 - FlushExtCache ; 7 - SwapSerialClock ; 8 - EDiskProtect (in TERROR ROM) ; 9 - FlushRange (in TERROR ROM) ; 10 - WaitForSCSIDevs (in TERROR ROM) ; 11 - UnusedSelector (in SuperMario) ; 12 - SlotBlockXferCtl (in SuperMario) ; 13 - GetENetID (in SuperMario/KAOS ROM) ; ; Entry: ; D0 (low order word) holds routine selector ; A0 holds parameter (optional for some selectors) ; D1-D2/A1 saved by trap dispatcher ; ; Exit: ; D0 (long) zero if all went well, non-zero if selector out of range ; A0 (long) returned value (optional for some selectors) ; ; Destroys: D0, plus whatever registers the selector routines use ; ;---------- HWPriv PROC EXPORT ; KISS (Keep it simple and easy to patch) bra.b HWPrivSwitch ALIGN 8 Vects ;table of offsets to selector routines HwPrivSelector SwapICache ; 0 SwapICache HwPrivSelector FlushICache ; 1 FlushICache HwPrivSelector SwapDCache ; 2 SwapDCache HwPrivSelector FlushDCache ; 3 FlushDCache HwPrivSelector EnableExtCache ; 4 EnableExtCache HwPrivSelector DisableExtCache ; 5 DisableExtCache HwPrivSelector FlushExtCache ; 6 FlushExtCache HwPrivSelector SwapSerialClock ; 7 SwapSerialClock HwPrivSelector ProtectEDisk ; 8 Protect/Unprotect EDisk HwPrivSelector FlushCRange ; 9 FlushCRange HwPrivSelector WaitForSCSIDevs ; 10 WaitForSCSIDevs HwPrivSelector ReturnErr ; 11 Unused HwPrivSelector SlotBlockXferCtl ; 12 - enable block xfers to a slot HwPrivSelector GetENetID ; 13 - Get Ethernet ID from serial ROM LastVec ALIGN 8 HWPrivSwitch cmpi.w #(LastVec-Vects)/HwVecSize,d0 ; check if selector in range bhs ReturnErr ; abort if it’s not a valid selector move.w Vects(d0*HwVecSize),d0 ; get offset to selector’s routine jmp Vects(d0) ; go to the routine ENDPROC ReturnErr PROC ENTRY move.l #hwParamErr,d0 ; abort: return error code rts ENDPROC HwPrivVects Proc Export ; Vectors for non-68000 non-TERROR (0 means use ROM version) dcImportResident SwapICache ; 0 SwapICache dcImportResident FlushICache ; 1 FlushICache dcImportResident SwapDCache ; 2 SwapDCache dcImportResident FlushDCache ; 3 FlushDCache dcImportResident EnableExtCache ; 4 EnableExtCache dcImportResident DisableExtCache ; 5 DisableExtCache dcImportResident FlushExtCache ; 6 FlushExtCache dcImportResident SwapSerialClock ; 7 SwapSerialClock dc.l 0 ; 8 Protect/Unprotect EDisk (new to TERROR, left unimplemented) dcImportResident FlushICache ; 9 FlushCRange (new to TERROR, backported here) dcImportResident WaitForSCSIDevs ; 10 WaitForSCSIDevs (new to TERROR, backported here) EndProc MaxSelector equ 10 HwPrivVectsTerror Proc Export ; Vectors for TERROR (0 means use ROM version) dc.l 0 ; 0 SwapICache dc.l 0 ; 1 FlushICache dc.l 0 ; 2 SwapDCache dc.l 0 ; 3 FlushDCache dc.l 0 ; 4 EnableExtCache dc.l 0 ; 5 DisableExtCache dc.l 0 ; 6 FlushExtCache dcImportResident SwapSerialClock ; 7 SwapSerialClock dc.l 0 ; 8 Protect/Unprotect EDisk (new to TERROR, ROM version fine) dc.l 0 ; 9 FlushCRange (new to TERROR, ROM version fine) dc.l 0 ; 10 WaitForSCSIDevs (new to TERROR, ROM version fine) EndProc MaxSelectorTerror equ 10 PatchHwPriv68000 InstallProc (Plus,SE,Portable) ; Reconstructed from <29> IMPORT InitHwPrivVects, VectsSize ; cmp.b #cpu68020,CpuFlag ; Use table above for 020/030 accelerators, blo.s @exit ; but not for real 68000s. cmp.b #cpu68030,CpuFlag ; bhi.s @exit ; leaResident CmpMaxHwPrivSelector,a0 ; move.w #MaxSelector,d2 ; move.w d2,2(a0) ; leaResident HwPrivVects,a2 ; Set up our vector table in ExpandMem jsr InitHwPrivVects ; @exit rts ; EndProc PatchHwPrivII InstallProc (II,IIci,notTERROR) ; Reconstructed from <5> IMPORT InitHwPrivVects, VectsSize ; leaResident CmpMaxHwPrivSelector,a0 ; Highest selector on non-overpatch IIci/II = 10 move.w #MaxSelector,d2 ; move.w d2,2(a0) ; leaResident HwPrivVects,a2 ; Set up our vector table in ExpandMem jsr InitHwPrivVects ; rts ; EndProc PatchHwPrivTerror InstallProc (IIci,hasTERROR) ; Reconstructed from <5> IMPORT InitHwPrivVects ; leaResident CmpMaxHwPrivSelector,a0 ; move.w #MaxSelectorTerror,d2 ; move.w d2,2(a0) ; leaResident HwPrivVectsTerror,a2 ; Set up our vector table in ExpandMem jsr InitHwPrivVects ; rts ; EndProc InitHwPrivVects Proc Export ; Fill gaps in the table (passed in a2) and save it in ExpandMem move.w #$A198,d0 ; Original trap (a0) is used to fill in zeros _GetOSTrapAddress ; move.l a2,a1 ; a1 = Table base, a2 = Table counter @loop move.l (a2)+,d1 ; Loop over HwPrivVects beq.s @fillgap ; Replace a 0 with the original _HwPriv handler @filldone dbra d2,@loop ; move.l ExpandMem,a0 ; Save to ExpandMem move.l a1,ExpandMemRec.emHwPrivTable(a0) ; rts ; @fillgap move.l a0,-4(a2) ; bra.s @filldone ; EndProc HWPrivTrap PatchProc _HWPriv,(Plus,SE,II,Portable,IIci) ; Vector the call through ExpandMem EXPORT CmpMaxHwPrivSelector ; IMPORT SwapSerialClock ; cmp.b #cpu68020,CpuFlag ; Unless on 68000, which only handles SwapSerialClock blo.s on000 ; CmpMaxHwPrivSelector ; CMP edited to test for highest selector cmp.w #0,d0 ; bhi.s @jmprom ; lea -4(sp),sp ; Jump to move.l a0,-(sp) ; move.l ExpandMem,a0 ; move.l ExpandMemRec.emHwPrivTable(a0),a0 ; move.l (a0,d0.w*4),4(sp) ; move.l (sp)+,a0 ; rts ; @jmprom jmpOld ; ReturnErr move.l #hwParamErr,d0 ; rts ; on000 cmp.w #7,d0 ; bne.s ReturnErr ; jmp SwapSerialClock ; EndProc ;---------- ; ; SwapICache (_HWPriv Selector 0) ; ; This routine turns the 020/030/040 instruction cache off or on. If the cache is being ; turned on, it is also flushed. ; ; Entry: ; ; A0 (long) - zero to turn instruction cache off, non-zero to turn it on ; ; Exit: ; ; A0 (long) - has previous state of instruction cache (zero = off, non-zero = on) ; ; Destroys: D1, D2 ; ;---------- SwapICache PROC EXPORT cmp.b #cpu68040,CpuFlag ; are we on an 040-based machine? bge.s @handle040 @handle030 movec CACR,d0 ; get current cache state bfextu d0{31:1},d1 ; get cache enable bit into LSbit of d1 bclr #CACR_EI_020_030,d0 ; assume we're disabling (clear enable flag) move.l a0,d2 ; see what we want to do beq.s @dontTurnOn ; if we want to turn it on ori.b #((1< A0[7-0] = bit map of SCSI IDs to wait for ; -> A0[23-16] = bit map of SCSI IDs to search for ; ; On Exit: ; <- A0 = result (0=found wait_for drives, -1=didn't find them) ; ; Register Usage: ; D0 = temp ; D1 = bitmap of devices to wait for ; D2 = bitmap of devices to search for ; D3 = OS Type (for SCSILoad) ; D4 = Ticks at timeout ; ;---------- WaitForSCSIDevs PROC EXPORT SCSILoad RomBind (Plus,$7d40),(SE,$404c),(II,$7ad4),(Portable,$7316),(IIci,$71f0) trashedRegs REG D2-D4 DefaultTimeOut EQU 20 ; Number of seconds timeout if PRAM is pristine PollDelay EQU 15 ; Delay (in ticks) between SCSILoads movem.l trashedRegs, -(sp) ; save registers that we're going to trash ; Get bitmap parameters into D1 and D2 move.l A0, D1 ; D1 = bitmap of devices to wait for move.l D1, D2 ; swap D2 ; D2 = bitmap of devices to search for or.b D1, D2 ; make sure that we search for the drive(s) ; that we are waiting for ; SCSILoad expects OS type in high word of D3 subq.w #2, sp ; Make room for parameters. move.l sp, A0 ; Point to the parameter block. _GetOSDefault ; Get info about the default device. ; leave OS results on stack for a second ; Get PRAM time out value and convert it to ticks and keep in D4 _GetTimeOut ; Get the timeout parameter. bne.s @UseGivenTime ; Branch if not using default. moveq.l #DefaultTimeOut, D0 ; Use default timeout. @UseGivenTime mulu #60, D0 ; Convert timeout to ticks. move.l D0, D4 ; Save timeout in our final reg. move.w (sp)+, D3 ; Get OS type off of stack swap D3 ; put in high word (where SCSILoad expects it) ; SCSILoad polling loop ------- @TopO_TheLoop move.l D2, D0 ; Try to load drivers for the "search" disks jsrROM SCSILoad move.b SCSIDrvrs, D0 and.b D1, D0 ; look only at bits we are waiting for cmp.b D1, D0 ; if all are 1 then beq.s @goodexit ; we got what we were waiting for - exit ; Check for timeout, wait for PollDelay more ticks, check timeout again, then do the SCSILoad again move.l Ticks, D0 cmp.l D4, D0 ; is current ticks higher than our time_out ticks? bhi @fldexit ; yes - timed out, exit add.l #PollDelay, D0 ; wait till Ticks+PollDelay before polling @1 cmp.l Ticks, D0 ; if polldelay timeout is higher than current ticks, bhi @1 ; then loop cmp.l D4, D0 ; is current ticks higher than our time_out ticks? blo @TopO_TheLoop ; no - repeat SCSILoad ; yes - timed out, exit @fldexit move.w #-1, A0 bra.s @exit @goodexit sub.l A0, A0 @exit movem.l (sp)+, trashedRegs ; restore registers that we trashed rts ENDPROC ;---------- ; ; SwapSerialClock (_HWPriv Selector 7) ; ; This routine enables or disables external clocking to the SCC. The external clock ; comes to the SCC through the RTxC signal, which is connected to the GPi pin on the ; serial port connector. External clocking is currently switched by the vSync bit ; on VIA 1, or through a call to the SCC IOP. The interface is left open-ended to ; allow external clock control on any number of SCC's or serial ports. Current CPU's ; only support one SCC and port A external clocking. ; ; NOTE: this call is supported for the fx in BYPASS mode only. (although we still call ; the IOP to execute the call) ; ; Entry: ; D0.L = routine selector ; A0.L = .B .B .W ; bits 31-24: SCC number currently 0 for future expansion ; 23-16: port number 0=port A, 1=port B,... for future expansion ; 15-0 : 0=internal clocking, 1=external clocking ; Exit: ; D0.L = zero if good, -1 if error ; A0.L = .B .B .W ; ;---------- SwapSerialClock PROC EXPORT moveq #-1,d0 ; assume an error return move.l a0,d1 ; d1 will hold the return value move.l d1,d2 swap d2 ; d2 = .w .b .b TestFor SCCIOPExists beq.s @BuiltinSCC ; no IOP hardware btst.b #0,SCCIOPFlag ; are we in bypass mode ? beq @Done ; no, so can't make the call, so exit cmp.w #1,d2 bhs.s @Done ; Call SCC IOP kernel to set the external clock mode. WITH IOPRequestInfo, SCCCtlMsg, SCCCtlReply @IOPSCC suba.w #irReqInfoSize+SCCCtlMsgSize,sp ; SP = ptr to request msg movea.l sp,a0 ; lea irIOPNumber(a0),a0 ; move.b #SCCIOPNum,(a0)+ ; set iop number assert irRequestKind=(irIOPNumber+1) move.b #irSendXmtMessage,(a0)+ ; a send xmit message kind assert irMsgNumber=(irRequestKind+1) assert irMessageLen=(irMsgNumber+1) assert irReplyLen=(irMessageLen+1) assert irReqActive=(irReplyLen+1) move.l #(1<<24)+\ ; irMsgNumber = 1 (SCCCtlMsgSize<<16)+\ ; irMessageLen = SCCCtlMsgSize (SCCCtlMsgSize<<8)+\ ; irReplyLen = SCCCtlMsgSize (0),(a0)+ ; irReqActive = 0 movea.l sp,a1 adda.w #irReqInfoSize,a1 ; point to SCCCtlMsg assert irMessagePtr=(irReqActive+1) move.l a1,(a0)+ ; irMessagePtr = SCCCtlMsg assert irReplyPtr=(irMessagePtr+4) move.l a1,(a0)+ ; irReplyPtr = SCCCtlMsg assert irHandler=(irReplyPtr+4) clr.l (a0) ; irHandler = nil (no completion routine) move.b #6,msgNum(a1) ; message to change external clocking move.b d2,Driver(a1) ; set port to change swap d2 ; get ext clk state in low word move.b d2,GPI(a1) ; set state of external clocking movea.l sp,a0 ; a0 = ptr IOPRequestInfo _IOPMsgRequest bne.s @1 ; error in request @waitloop tst.b irReqActive(a0) ; wait for request to complete bne.s @waitloop movea.l irReplyPtr(a0),a0 ; get reply move.b errNum(a0),d0 ; error code from reply @1 adda.w #irReqInfoSize+SCCCtlMsgSize,sp bra.s @Done ENDWITH ; Bang on the VIA vSync bit directly. @BuiltinSCC TestFor VIA1Exists beq.s @Done ; no via - nothing to do now tst.w d2 bne.s @Done moveq #0,d0 movea.l VIA,a1 move.b vBufA(a1),d1 and.b #8,d1 lsr.b #3,d1 swap d2 cmp.b d2,d1 beq.s @Done bchg #vSync,vBufA(a1) ; change the clock setting ; Done - return the old external clock state. ; To do: This does not return valid information in the IOP case! ; To do: This does not return valid information when VIA1 is missing! @Done movea.l d1,a0 ; return previous state in A0 rts ENDPROC ;---------- ; ; ProtectEDisk (_HWPriv Selector 8) ; ; This stub merely selects what version of the primitive routine to use. ; EDisk protection is handled differently on 68K Macs than it is on PPC Macs. ; ;---------- ProtectEDisk PROC EXPORT IMPORT EDiskProtect, EDiskProtectPPC TestFor has68kEmulator ; are we on a PPC-based machine? bnz.b @UsePPCVersion @Use68KVersion bra EDiskProtect @UsePPCVersion bra EDiskProtectPPC ENDPROC ;---------- ; ; FlushCRange (_HWPriv Selector 9) ; ; This routine flushes a range of addresses from the 040 caches ; (or the whole cache on non 040 machines). ; ; Entry: ; ; A0 (long) - Starting logical address. ; A1 (long) - Count. ; ; Exit: ; ; Destroys: D1, D2 ; ; FlushCRangeForBM is glue for BlockMove ; ;---------- FlushCRangeForBM PROC EXPORT EXPORT FlushCRange Move.l (Sp)+,A0 ; Address. Move.l (Sp)+,A1 ; Count. FlushCRange TestFor has68kEmulator ; are we on a PPC-based machine? bnz @EmuFake Cmpi.b #cpu68040,CPUFlag ; Are we less than an 040? Blo @Non040 ; Yes? Then do an 030 style flush. MACHINE MC68040 Adda.w #15,A1 ; Round length. Move.l A1,D1 ; Length in D1 And.w #$FFF0,D1 ; Round to nearest cache line. Move SR,D0 ; Get and save the SR. Btst #13,D0 ; Are we in Supervisor mode? Bne.s @CheckCnt ; Yes? Then don't call _EnterSupervisorMode. Moveq #8,D0 ; Selector for "EnterSupervisorMode". _DebugUtil ; Must be in supervisor mode (SR returned in D0). @CheckCnt Cmpi.l #$0C00,D1 ; Less than 3/4 the size of the cache? ***Tune*** Blo.s @KillInterrupts ; Yes? Then flush line by line. @0 Nop ; Sync up pipeline. ***TEMP*** Cpusha BC ; No? Then flush everything and be done with it. Bra.s @Exit1 ; Outta here. @KillInterrupts Movem.l D3-D5/A0-A1,-(Sp) ; Save registers. Ori.w #$0700,SR ; Disable interrupts till we exit. Moveq #5,D2 ; Set the DFC value. Movec D2,DFC ; Set the Destination Function Code to 5. Move.w #$D000,D4 ; Build a mask based on the page size from bit #14 of TC. Movec TC,D2 ; Get Translation Control (Bit 14 set:8K, clear:4K). Lsr.w #2,D2 ; Move the TC bits (enable/page size) over 2 Eor.w D2,D4 ; Eor in the bits to make the mask ($F000 for 4K, $E000 for 8K). Move.w D4,D5 ; Copy physical mask. Not.w D5 ; Make 1's complement mask for logical address. @LetsGetPhysical Move.l A0,A1 ; Set scratch register (A1) with logical address. Ptestr (A1) ; Get translated physical address. Movec MMUSR,D3 ; Address is in high 19 or 20 bits of MMUSR. And.w D4,D3 ; Clear off bottom n bits. Move.w A1,D2 ; Logical address in D2. And.w D5,D2 ; Grab low n bits of original address. Or.w D2,D3 ; Build complete physical address. Move.l D3,A1 ; Physical address. Eor.w D5,D2 ; Calculate number of bytes left in this page. Addq.w #1,D2 Sub.w D2,D1 ; Subtract from total buffer size. Bpl.s @FlushIt ; Still pos? Then D2 has correct byte count. Add.w D1,D2 ; No? Then almost done…correct the count. @FlushIt Adda.w D2,A0 ; Logical address of next page. Asr.w #4,D2 ; Lines to flush. Cmp.w #16,D2 ; More than 16 lines? ***TUNE*** Blt.s @LineByLine ; No? Then do it line by line. Nop ; Sync up pipeline. ***TEMP*** Cpushp BC,(A1) ; Invalidate the whole page. Bra.s @NextPage ; Do next page. @LineByLine Cpushl BC,(A1) ; Invalidate the cache line. Add.w #$10,A1 ; Bump logical address to the next cache line. Dbra D2,@LineByLine ; Loop till page is done. @NextPage Tst.w D1 ; Are we done? Bgt.s @LetsGetPhysical ; No? Then do next page. @Exit Movem.l (Sp)+,D3-D5/A0-A1 ; Restore registers. @Exit1 Move D0,SR ; Restore status register (interrupts and user/supervisor mode). Moveq #noErr,D0 ; No Error. Rts ; Adios. MACHINE MC68030 @Non040 Movec CACR,D0 ; Cache control register. Bset #3,D0 ; Set flag to flush instruction cache. Movec D0,CACR ; Flush it. Moveq #noErr,D0 ; No Error. Rts ; Adios. @EmuFake moveq #noErr,d0 rts ENDPROC ;---------- ; ; SlotBlockXferCtl (_HWPriv Selector 12) ; ; This routine enables/disables MUNI's, Cyclone/Tempest Nubus Controller, ability to ; block xfer TO a Nubus slot. Note: MUNI is always able to recv a block xfer FROM a ; Nubus slot. ; ; Entry: ; A0 (long) - (bits 31-9) reserved ; - (bit 8) zero to disable block xfer to a slot , one to turn it on ; - (bits 7-0) slot number, 1 - 14 ; ; Exit: ; D0 (long) - 0 if we're on a MUNI-based system & good slot value, paramErr if not ; A0 (long) - if noerr, previous state of block xfer for each slot (1=on, 0=off) ; (Bits 31-15 reserved, Bit 14 = slot 14, ... bit 1 = slot 1, bit 0 reserved) ; ; Destroys: D1, D2, A1 ; ;---------- SlotBlockXferCtl PROC EXPORT MoveQ.l #paramErr, D0 ; assume don't have MUNI or bad slot value passed Testfor BARTExists ; are we on a ColdFusion or PDM bne.s @bart TestFor MUNIExists ; Do we have the MUNI Nubus controller Beq.s @exit ; No, we're done. MoveA.l UnivInfoPtr, A1 ; point to the product info Add.l ProductInfo.DecoderInfoPtr(A1), A1 ; get decoder info ptr MoveA.l DecoderInfo.MUNIAddr(A1), A1 ; get MUNI base address Move.l A0, D1 ; get user parm MoveQ #0, D2 Move.l MUNI_BlkAttmpt(A1), D2 ; get previous state of slots 1-14 Lsl.w #1, D2 ; make bit x match slot x, bit 1 = slot 1 MoveA.l D2, A0 ; return previous state bit mask in A0 MoveQ #0, D2 Move.b D1, D2 ; Get slot # SubQ.b #1, D2 ; adjust slot # for bit offset Bmi.s @exit ; bad slot value, < 1 Cmp.b #14, D2 Bhs.s @exit ; bad slot value, > 14 Move.l MUNI_BlkAttmpt(A1), D0 ; get current state of slots 1-14 BTst #8, D1 ; Turn blk xfer on or off? Bne.s @on BClr D2, D0 ; turn if off Bra.s @doit @on BSet D2, D0 ; turn if on @doit Move.l D0, MUNI_BlkAttmpt(A1) ; setup block xfers for slot # in D2 bra.s @done @bart MoveA.l UnivInfoPtr, A1 ; point to the product info Add.l ProductInfo.DecoderInfoPtr(A1),A1 ; get decoder info ptr MoveA.l DecoderInfo.BARTAddr(A1),A1 ; get Bart base address Move.l A0, D1 ; get user parm MoveQ #0, D2 Move.b D1, D2 ; Get slot # SubQ.b #1, D2 ; adjust slot # for bit offset Bmi.s @exit ; bad slot value, < 1 Cmp.b #14, D2 Bhs.s @exit ; bad slot value, > 14 BTst #8, D1 ; Turn blk xfer on or off? Bne.s @Bon moveq #BARTBurstRegOff, d0 mulu.l d2, d0 adda.l #BARTBurstReg,a1 suba.l d0, a1 bclr.b #BARTBurstBit, (A1) ; turn off block xfers for slot # in D2 Bra.s @done @Bon moveq #BARTBurstRegOff, d0 mulu.l d2, d0 adda.l #BARTBurstReg,a1 suba.l d0, a1 bset.b #BARTBurstBit, (A1) ; turn on block xfers for slot # in D2 @done MoveQ #noErr,D0 ; signal all's well @exit Rts ENDPROC ;---------- ; ; GetENetID (_HWPriv Selector 13) ; ; This routine gets the EtherNet ID from a serial-interface EtherNet ID ROM. ; On all machines except Blackbird (so far), the Ethernet ID is in a memory-mapped ; parallel ROM. When this routine runs on those machines, a0 should already ; contain a valid address at which to read the ethernet ID, so this routine ; will just exit for those machines. If there is no address in a0, we double check ; here to make sure we are on a Blackbird (by checking for Pratt), and then ; go ahead and try to get the Ethernet ID from the serial ROM. ; ; Entry: ; ; A0.l - ENetPROM field of the EtherNet Driver (address of ID ROM, or ; zero for an ID ROM that is not memory-mapped). ; ; Exit: ; ; A0.l - non-zero pointer to EtherNet ID ; - ID = 0 if we can't get address from ID ROM ; ; Destroys: D1, D2, A1 ; ;---------- GetENetID PROC EXPORT IMPORT X24c01aGetID WITH PMgrRec, PmgrPrimitivesRec IF hasPratt THEN TestFor PrattExists ; do we have a Pratt? beq.s @exit ; no, so exit move.l a4, -(sp) ; save our macro register bigjsr X24c01aGetID,a4 ; get the ID from the serial ROM move.l (sp)+, a4 ; restore our macro register ENDIF @exit moveq #noErr,d0 ; everything always fine rts ENDWITH ENDPROC ;==================================================================================================== ; ; Everything above was HwPriv. Everything below is MemoryDispatch. ; ; It’s not exactly clear why all this got thrown into one file. ; ;==================================================================================================== ;----- ; Adding new MemoryDispatch routines that work on a page basis. ; This to provide support for Sonic onboard Ethernet. ; ; To support write-protect, the lock counter behavior has been altered to include ; a write-protect bit. The high bit in each lock counter indicates that the page ; is write-protected. No count is kept of the number of lock/unlock calls that ; have been made. ;----- ;---------- ; ; MemDispSelector Macro - This macro allows us to build the selector jump table correctly, ; regardless of whether compiling for ROM or System. When compiling ; as a System patch, absolute addresses are generated, and offsets are ; used when compiling for ROM. ; ;----- IF ForROM THEN ; <5> MACRO MemDispSelector &addr import &addr dc.w &addr-Vects ; OFFSET of routine ENDM MdVecSize EQU 2 ELSE MACRO MemDispSelector &addr dcImportResident &addr ; ADDRESS of routine ENDM MdVecSize EQU 4 ENDIF ;--------------- ; ; MemoryDispatch ; ; Provides services for Virtual Memory access to the hardware ; ;------------------- MemoryDispatch PROC Export bra.s MemoryDispatchCode Vects ;table of offset to selector routines MemDispSelector HoldMemoryProc ; 0 MemDispSelector UnHoldMemoryProc ; 1 MemDispSelector LockMemoryProc ; 2 MemDispSelector UnLockMemoryProc ; 3 MemDispSelector LockMemoryContiguousProc ; 4 MemDispSelector GetPhysicalProc ; 5 MemDispSelector WriteProtectProc ; 6 LastVec MemDispSelector UnWriteProtectProc ; 7 MemoryDispatchCode cmp.w #(LastVec-Vects)/MdVecSize,d0 ; check if selector in range bhi.s @badSelect ; abort if its not a valid selector move.w Vects(d0.w*MdVecSize),d0 ; get offset to selector's routine jmp Vects(d0) ; go to the routine @badSelect move.l #hwParamErr,d0 ; abort: return error code rts EndProc ;----- ; ; HoldMemoryProc (_MemoryDispatch Selector 0) ; ; This routine makes the address space resident in real memory and ineligible for paging. ; ; Destroys: none ; ;----- HoldMemoryProc PROC Export Moveq #0,D0 ; no error Rts EndProc ;----- ; ; UnHoldMemoryProc (_MemoryDispatch Selector 1) ; ; This routine makes the address space eligible for paging. ; ; Destroys: none ; ;----- UnHoldMemoryProc PROC Export Moveq #0,D0 ; no error Rts EndProc ;----- ; ; LockMemoryProc (_MemoryDispatch Selector 2) ; ; This routine makes the address space immovable in real memory and ineligible for paging. ; It also marks the corresponding page frames as non-cacheable, and increments the ; lock count for the page. ; ; After calling GetPageRange, d1 contains the page number of the first logical page, ; and d2 contains the page count. ; ; Destroys: none ; ; Calls: GetPageRange, MMUMakePageNonCacheable, MMUFlushATC, MMUFlushDataCache ; ;----- LockMemoryProc PROC Export Import GetPageRange,MMUFlushATC,MMUSetCacheInhibit WITH MemDispGlobals @saveRegs REG d1-d4/a0-a2 movem.l @saveRegs,-(sp) ; save registers movea.l LockMemCt,a2 ; point to MemoryDispatch globals bsr GetPageRange ; check input arguments bne.s @error ; get out lea.l mdLockTable(a2,d1*2),a1 ; point to lock counter for first page moveq.l #1,d0 ; flag to MMUSetCacheInhibit to inhibit caching @loop addq.w #1,(a1)+ ; bump the lock count bsr MMUSetCacheInhibit ; mark page as noncacheable addq.l #1,d1 ; increment page number subq.l #1,d2 ; one less page to go bhi.s @loop ; keep looping cmpi.b #EMMU1,MMUType ; is this an Emulated MMU? beq.s @done ; -> Yes, no need to flush anything bsr MMUFlushATC ; flush ATC's _FlushDataCache ; flush data cache @done moveq.l #noErr,d0 ; no error @error movem.l (sp)+,@saveRegs ; restore registers rts EndWith EndProc ;----- ; ; UnLockMemoryProc (_MemoryDispatch Selector 3) ; ; This routine makes the address space movable in real memory and eligible for paging again. ; It also decrements the lock count for the corresponding page frames, and if the ; count is zero, markd the page as cacheable. ; ; Destroys: none ; ;----- UnLockMemoryProc PROC Export Import GetPageRange,MMUSetCacheInhibit,MMUFlushATC With MemDispGlobals @saveRegs REG d1-d4/a0-a2 movem.l @saveRegs,-(sp) ; save registers movea.l LockMemCt,a2 ; point to MemoryDispatch globals bsr GetPageRange ; check input arguments bne.s @error ; get out lea.l mdLockTable(a2,d1*2),a1 ; point to lock counter for first page move.l d2,d3 ; copy of the count move.w #notLockedErr,d0 ; assume a nonlocked page @lockCheckLoop tst.w (a1)+ ; check the page lock counter beq.s @error ; if zero, page was not locked previously subq.l #1,d3 ; one less page to go bhi.s @lockCheckLoop ; keep looping lea.l mdLockTable(a2,d1*2),a1 ; point to lock counter for first page move.l d2,d3 ; copy of the count moveq.l #0,d0 ; flag to MMUSetCacheInhibit to enable caching moveq.l #0,d4 ; assume ATC will not need to be cleared @unlockLoop subq.w #1,(a1)+ ; decrement the lock count for this page bne.s @stillLocked ; if count != 0, page will remain locked bsr MMUSetCacheInhibit ; mark page as cacheable moveq.l #1,d4 ; ATC will need to be cleared (a PTE changed) @stillLocked addq.l #1,d1 ; move on to next page subq.l #1,d3 ; one less page to go bhi.s @unlockLoop ; keep looping tst.l d4 ; do we need to flush the ATC beq.s @noFlush ; if not, don't do it bsr MMUFlushATC ; flush ATC's @noFlush moveq.l #noErr,d0 ; return noErr @error movem.l (sp)+,@saveRegs ; restore registers rts EndWith EndProc ;------------------------------------------------------------------- ; ; LockMemoryContiguousProc (_MemoryDispatch Selector 4) ; ; This routine provides the service of making a virtual address range contiguous in ; physical address space. ; ; Destroys: none ; on Entry: ; A0.L = start of logical address ; D0.W = 4, selector ; A1.L = number of bytes in buffer ; ; on Exit: ; D0.W = error code ; ;------------------------------------------------------------------- LockMemoryContiguousProc PROC Export Import GetPageRange,GetRealProc,MMUSetCacheInhibit,MMUFlushATC With MemDispGlobals @saveRegs REG a0-a3/d1-d4 @moreRegs REG d1/a1-a2 movem.l @saveRegs,-(sp) ; save registers movea.l LockMemCt,a2 ; point to MemoryDispatch globals bsr GetPageRange ; check input arguments bne.s @error ; get out (returns paramErr) movea.l a0,a3 ; copy starting logical address movem.l @moreRegs,-(sp) ; save registers that GetReal destroys bsr GetRealProc ; get the starting physical address movem.l (sp)+,@moreRegs ; restore registers that GetReal destroys exg.l a0,a3 ; hold on to starting physical address adda.l a1,a0 ; add length of buffer - 1 subq.l #1,a0 movem.l @moreRegs,-(sp) ; save registers that GetReal destroys bsr GetRealProc ; get the ending physical address movem.l (sp)+,@moreRegs ; restore registers that GetReal destroys suba.l a3,a0 ; get the distance between the addresses addq.l #1,a0 ; adjust calculation cmpa.l a1,a0 ; compare the results bne.s @notContigError ; range crosses a non-contiguous bank boundary lea.l mdLockTable(a2,d1*2),a1 ; point to lock counter for first page moveq.l #1,d0 ; flag to MMUSetCacheInhibit to inhibit caching @loop addq.w #1,(a1)+ ; bump the lock count bsr MMUSetCacheInhibit ; mark page as noncacheable addq.l #1,d1 ; increment page number subq.l #1,d2 ; one less page to go bhi.s @loop ; keep looping cmpi.b #EMMU1,MMUType ; is this an Emulated MMU? beq.s @done ; -> Yes, no ATC or Data cache to flush bsr MMUFlushATC ; flush ATC's _FlushDataCache ; flush data cache @done moveq.l #noErr,d0 ; no error @error movem.l (sp)+,@saveRegs ; restore registers rts @notContigError move.w #cannotMakeContiguousErr,d0 ; addresses are not contiguous bra.s @error EndWith EndProc ;------------------------------------------------------------------- ; ; GetPhysicalProc (_MemoryDispatch Selector 5) ; ; This routine translates virtual addressess to corresponding physical addresses. ; ; Destroys: none ; ; on Entry: ; A0.L = pointer to translation table ; D0.W = 5, selector ; A1.L = number of entries in table ; A1.L = 0, if caller want to get number of entries required ; ; on Exit: ; D0.W = error code ; A0.L = number of pairs returned/required ; A1.L = pointer to translation table ; ;------------------------------------------------------------------- VAddr EQU -8 ; offset to virtual address from A0 BuffSize EQU -4 ; offset to buffer size SavedPtr EQU 2 ; offset to saved ptr in stack GetPhysicalProc PROC Export Import GetRealProc,ChkContig GetPhysRegs REG d3/a3-a4 MOVEM.L GetPhysRegs,-(SP) ; save register move.l a0,-(sp) ; save pointer to table on stack move.l a0,a4 ; get table entry pointer in a4 Move.L A1,D3 ; get table entry number MOVE.L (A4)+,D2 ; get virtual address in d2 @NoSwap move.l d2,a0 ; put virtual address in a0 ADD.L (A4),D2 ; get end of buffer CMP.L realMemtop,D2 ; does it exceed available RAM BHI.S @BadAddress ; >>EXIT if it exceeds top of RAM BSR.L GetRealProc ; get physical address in a0 BMI.S @BadAddress ; branch if bad address MOVE.L A0,A3 ; save physical address in A3 MOVE.L D2,A0 ; get end of buffer SUBQ.L #1,A0 ; convert to end address BSR.L GetRealProc ; get physical address in a0 BMI.S @BadAddress ; branch if bad address SUB.L A3,A0 ; calculate distance between addresses ADDQ.L #1,A0 ; convert to byte count CMP.L (A4),A0 ; are they the same size BNE.S @NonContig ; branch, if memory is not contiguous TST.L d3 ; d3 = 0?? BEQ.S @return1 ; branch, if yes MOVE.L (A4)+,D0 ; save buffer size ADD.L D0,VAddr(A4) ; update virtual address MOVE.L #0,BuffSize(A4) ; update buffer size MOVE.L A3,(A4)+ ; save physcial address in table MOVE.L D0,(A4) ; save size in table @return1 MOVE.L #1,A0 ; return with 1 entry MOVE.W #0,D2 ; and with no error @GPEXit MOVE.L D2,D0 ; set final error code MOVE.L (SP)+,A1 ; restore pointer MOVEM.L (SP)+,GetPhysRegs ; restore registers RTS @BadAddress MOVEQ #0,A0 ; when error, return zero entry MOVE.W #paramErr,D2 ; return paramErr BRA.S @GPExit @NonContig MOVE.L (SP),A4 ; A0 gets pointer to table MOVE.L (A4),A0 ; get logical address in A0 ADD.L #8,A4 ; A4 = points to table entry MOVE.L D3,D1 ; D1 = number of table entry or 0 BSR ChkContig ; check contiguous physical TST.W D2 ; are there error BMI.S @BadAddress MOVE.L D1,A0 ; get number of entries in A0 BRA.S @GPEXit EndProc ;------------------------------------------------------------------- ; ; ChkContig:- ; Check for contiguous address space for buffer ; This code is written in a rush, and should be rewritten ; in the future. ; ; on entry: ; A0 = logical address ; A4 = pointer to table ; D1 = number of table entries or 0 ; on exit: ; D1 = number of table entries ; D2 = error code ; ; destroys: A3 ;------------------------------------------------------------------- StkFrame record {a6link},decr a6link DS.L 1 ; old link pointer PhysAddr DS.L 1 ; physical address PageAddr DS.L 1 ; physical page address ContigSize DS.L 1 ; contiguous memory size EntryNum DS.L 1 ; number of entry EntryReq DS.L 1 ; entry required EntryIndex DS.L 1 ; current entry Index OVAddr DS.L 1 ; original virtual address OSize DS.L 1 ; original size StkSize equ * ; size of locals endr ChkContig PROC Export Import GetRealProc With MemDispGlobals WITH StkFrame LINK A6,#StkSize ; define a stack frame for local variable Movem.L D3-D7,-(SP) ; save registers MOVE.L D1,EntryNum(A6) ; save number of entry MOVE.L #1,EntryReq(A6) ; initialize entry required to 1 MOVE.L #0,EntryIndex(A6) ; initialize current entry index to 0 MOVE.L VAddr(a4),OVaddr(A6) ; save original virtual address MOVE.L Buffsize(a4),OSize(A6) ; save original size BSR.L GetRealProc ; convert addr in a0 to physical addr BMI @BadAddress ; branch if bad address MOVE.L A0,PhysAddr(A6) ; save physical address MOVE.L LockMemCt,A2 ; point to MemoryDispatch globals move.l mdPageSize(A2),D2 ; point to MemoryDispatch globals ; Removed a •Gestalt• call to get the page size! Sheeze! ; to calculate amount of memory in the first page SUBQ #1,d2 ; create mask to get bytes in 1st page MOVE.L PhysAddr(A6),D3 ; get physical address NEG.L D3 ; negate the address AND.L D3,D2 ; get remaining bytes in first page MOVE.L D2,ContigSize(A6) ; save memory size MOVE.L OVaddr(A6),A3 ; get original logical address ADD.L D2,A3 ; get logical address on page boundary @loop MOVE.L A3,A0 ; get logical address into A0 BSR.L GetRealProc ; convert addr in A0 to physical addr BMI @BadAddress ; branch if bad address MOVE.L LockMemCt,A2 ; restore A2,points toMemoryDispatch globals MOVE.L PhysAddr(A6),D3 ; get saved start physical address Add.L ContigSize(A6),D3 ; added length of contiguous address CMP.L D3,a0 ; Does it match the new physical address BNE.S @NotContig ; branch if not contiguous MOVE.L ContigSize(A6),D3 ; get contiguous size @common ADD.L mdPageSize(a2),D3 ; update Contiguous memory size CMP.L BuffSize(a4),D3 ; is it end yet? BCC.S @Done ; yes, branch MOVE.L D3,ContigSize(A6) ; update contiguous size ADD.L mdPageSize(a2),A3 ; get new virtual address BRA.S @loop @NotContig TST.L EntryNum(A6) ; test number of entries BEQ.S @justCount ; just count MOVE.L EntryIndex(A6),D3 ; get entry index MOVE.L PhysAddr(A6),(0,a4,D3.L*8) ; store physical address MOVE.L ContigSize(A6),(4,a4,D3.L*8); store contiguous size Add.L #1,D3 ; advance current entry CMP.L EntryNum(A6),D3 ; end of table yet? BCC.S @ExitA ; if yes, done MOVE.L D3,EntryIndex(A6) ; update index @justCount ADDQ.L #1,EntryReq(A6) ; update entry required MOVE.L ContigSize(A6),D3 ; get ContigSize ADD.L D3,VAddr(a4) ; update virtual address SUB.L D3,BuffSize(a4) ; update buffer size Move.L A0,PhysAddr(A6) ; update new physical address MOVEQ #0,D3 ; initial to zero memory BRA.S @common ; branch back inside loop @Done TST.L EntryNum(A6) ; test number of entries BNE.S @GetResult ; branch, if not zero Move.L EntryReq(A6),D1 ; get entry required MOVE.L OVaddr(A6),VAddr(a4) ; restore original virtual address MOVE.L OSize(A6),BuffSize(a4) ; restore original size BRA.S @ExitB @GetResult MOVE.L EntryIndex(A6),D3 ; get entry index MOVE.L PhysAddr(A6),(0,a4,D3.L*8) ; store physical address MOVE.L BuffSize(a4),(4,a4,D3.L*8) ; store size MOVE.L BuffSize(a4),D2 ; save remaining buffsize Add.L D2,VAddr(a4) ; update virtual address MOVE.L #0,BuffSize(a4) ; indicate complete translation AddQ.L #1,D3 ; convert index to entry count @ExitA MOVE.L D3,D1 ; return entry count @ExitB MOVEQ #0,D2 ; no error @ExitC MOVEM.L (SP)+,D3-D7 ; restore registers UNLK A6 ENDWITH RTS @BadAddress MOVE.W #-1,D2 ; return paramErr BRA.S @ExitC EndWith EndProc ;----- ; ; WriteProtectProc (_MemoryDispatch Selector 6) ; ; This routine protects the address space from write accesses. ; It also sets the high bit in the lock counter for each page in the range. ; ; The address range must start at a page boundary, and must be a multiple of ; page size in length. If either of these conditions are not true, then ; the call returns "paramErr". ; ; After calling GetPageRange, d1 contains the page number of the first logical page, ; and d2 contains the page count. ; ; Destroys: none ; ; Entry: A0.L = logical start address (must be at the start of a page) ; A1.L = number of bytes (must be a multiple of page size) ; D0.W = 6, selector ; ; Exit: D0.W = error code ; ; Calls: GetPageRange, MMUSetWriteProtect, MMUFlushATC, MMUFlushDataCache ; ;----- WriteProtectProc Proc Export Import GetRealProc,GetPageRange,MMUSetWriteProtect,MMUFlushATC With MemDispGlobals @saveRegs REG d1/d2/a0-a2 @setW EQU (1<<2) ; set Write protect mask (used as a flag) @setWMask EQU $8000 ; mask to set write-protect bit at top of lock count movem.l @saveRegs,-(sp) ; save registers movea.l LockMemCt,a2 ; point to MemoryDispatch globals moveq.l #paramErr,d0 ; assume it won't work move.l mdPageSize(a2),d2 ; get the page size subq.l #1,d2 ; mask for page boundary alignment check move.l a0,d1 ; get the start address and.l d2,d1 ; is the start address page-aligned ? bne.s @error ; start address must be page-aligned move.l a1,d1 ; is the range a multiple of page size ? and.l d2,d1 ; is the range a multiple of page size ? bne.s @error ; range must be a multiple of page size bsr GetPageRange ; check input arguments bne.s @error ; get out cmpi.b #EMMU1,MMUType ; do we have an EMMU? beq.s @NoFlush ; -> Yes, no need for this crap _FlushDataCache ; flush data cache (flush data before write protecting) _FlushInstructionCache ; flush instruction cache (just for grins) bsr MMUFlushATC ; flush ATC's @NoFlush lea.l mdLockTable(a2,d1*2),a1 ; point to lock counter for first page moveq.l #@setW,d0 ; flag to MMUSetWriteProtect to write-protect @loop ori.w #@setWMask,(a1)+ ; set the write-protect flag bsr MMUSetWriteProtect ; mark page as write-protected addq.l #1,d1 ; increment page number subq.l #1,d2 ; one less page to go bhi.s @loop ; keep looping moveq.l #noErr,d0 ; no error @error movem.l (sp)+,@saveRegs ; restore registers rts ; EndWith EndProc ;----- ; ; UnWriteProtectProc (_MemoryDispatch Selector 7) ; ; This routine allows write accesses to the address space. ; It also clears the high bit in the lock counter for each page in the range. ; ; The address range must start at a page boundary, and must be a multiple of ; page size in length. If either of these conditions are not true, then ; the call returns "paramErr". ; ; After calling GetPageRange, d1 contains the page number of the first logical page, ; and d2 contains the page count. ; ; Destroys: none ; ; Entry: A0.L = logical start address (must be at the start of a page) ; A1.L = number of bytes (must be a multiple of page size) ; D0.W = 7, selector ; ; Exit: D0.W = error code ; ; Calls: GetPageRange, MMUMakePageNonCacheable, MMUFlushATC, MMUFlushDataCache ; ;----- UnWriteProtectProc Proc Export Import GetPageRange,MMUSetWriteProtect,MMUFlushATC With MemDispGlobals @saveRegs REG d1/d2/a0-a2 @clearW EQU (0<<2) ; clear Write protect mask (used as a flag) @clearWMask EQU $7fff ; mask to clear write-protect bit at top of lock count movem.l @saveRegs,-(sp) ; save registers movea.l LockMemCt,a2 ; point to MemoryDispatch globals moveq.l #paramErr,d0 ; assume it won't work move.l mdPageSize(a2),d2 ; get the page size subq.l #1,d2 ; mask for page boundary alignment check move.l a0,d1 ; get the start address and.l d2,d1 ; is the start address page-aligned ? bne.s @error ; start address must be page-aligned move.l a1,d1 ; is the range a multiple of page size ? and.l d2,d1 ; is the range a multiple of page size ? bne.s @error ; range must be a multiple of page size bsr GetPageRange ; check input arguments bne.s @error ; get out lea.l mdLockTable(a2,d1*2),a1 ; point to lock counter for first page moveq.l #@clearW,d0 ; flag to MMUSetWriteProtect to clear write-protect @loop andi.w #@clearWMask,(a1)+ ; clear the write-protect flag bsr MMUSetWriteProtect ; mark page as writeable addq.l #1,d1 ; increment page number subq.l #1,d2 ; one less page to go bhi.s @loop ; keep looping bsr MMUFlushATC ; flush ATC's (to allow writes to previously protected pages) moveq.l #noErr,d0 ; no error @error movem.l (sp)+,@saveRegs ; restore registers rts ; EndWith EndProc ;------------------------------------------------------------------- ; ; InitMemoryDispatch ; ; This routine allocates and initializes the MemoryDispatch globals. ; ;------------------------------------------------------------------- InitMemoryDispatch Proc Export With MemDispGlobals @UnimplementedTrap EQU $A89F @MemoryDispatchTrap EQU $A05C @saveRegs REG a0-a3/d0-d4 @localSize EQU -4 ; storage for the TC register @cm0bit EQU 5 ; CM[0] bit in 040 page descriptor link a6,#@localSize ; allocate space for the TC register movem.l @saveRegs,-(sp) ; save registers clr.l LockMemCt ; clear ptr to globals (assume failure) cmpi.b #HMMU,MMUType ; Do we have an MMU? bhi.s @hasMMU ; -> Yes, do the init! MOVE.W #@UnimplementedTrap,d0 ; _Unimplemented _GetTrapAddress ,newTool ; Get its address MOVE.W #@MemoryDispatchTrap,d0 ; Select MemoryDispatch trap _SetTrapAddress ,newOS ; Set it to point to Unimplemented bra @NoPages ; -> All done @hasMMU move.b CPUFlag,d1 ; get the CPU type moveq.l #0,d2 ; assume no page size move.l PhysMemTop,d3 ; get actual amount of physical RAM cmpi.b #cpu68040,d1 ; are we on an '040 ? bne.s @not040 ; if not, handle its MMU differently MACHINE MC68040 moveq.l #12,d1 ; assume 4K pages ( 12 = log2(4096) ) movec TC,d0 ; get the TC register btst.l #14,d0 ; are we in 8K page mode ? beq.s @gotPageSize ; if not, we have the page size addq.l #1,d1 ; page size is 8K ( 13 = log2(8192) ) bra.s @gotPageSize ; continue MACHINE MC68030 @not040 cmpi.b #cpu68020,d1 ; are we at least an '020 ? blo.w @noPages ; bail without allocating globals ??? (Use old code ?) cmpi.b #PMMU851,MMUType ; do we have a real MMU ? blo.w @noPages ; bail without allocating globals ??? (Use old code ?) cmpi.b #EMMU1,MMUType ; do we have an emulated MMU? bne.s @mustbe030 ; -> No, must be an 030 moveq #0,D1 ; clear D1 move.l ([ProcessorInfoPtr],ProcessorInfo.PageSize),D0 ; Get the Page size from the nano-k beq.w @NoPages ; 0 Page size. Can't happen. @countBits asr.l #1,D0 ; Shift bit zero into the carry. bcs.s @gotPageSize ; -> Bail out at the first bit set w/bit # in d1 addq #1,d1 bra.s @countBits ; Keep shifting till we find one @mustbe030 pmove.l TC,-4(a6) ; get the '030 TC register contents bfextu -4(a6){8,4},d1 ; get log2 of page size @gotPageSize bset.l d1,d2 ; get the page size lsr.l d1,d3 ; get number of page frames move.l d3,d4 ; remember number of page frames move.l d3,d0 ; set up to allocate page lock table asl.l #1,d0 ; each lock counter is a word addi.w #mdGlobalSize,d0 ; size of additional globals move.l d0,d3 ; remember size of globals _NewPtr ,Sys ,Clear ; allocate MemoryDispatch globals bne.w @noPages ; we're dead (bail, or use old code ???) move.l a0,LockMemCt ; save ptr to MemoryDispatch globals move.l d3,mdSize(a0) ; size of entire MemoryDispatch globals move.l d2,mdPageSize(a0) ; save page size move.l d1,mdLog2PageSize(a0) ; save log2 of page size move.l d4,mdPages32(a0) ; save number of logical pages in 32-bit mode move.l d4,mdPageFrames(a0) ; save number of page frames move.l #$800000,d3 ; max of 8MB addressable in 24-bit mode cmp.l PhysMemTop,d3 ; check amount of physical memory blo.s @use8meg ; if physical memory > 8MB, only 8MB available move.l PhysMemTop,d3 ; else use physical memory @use8meg lsr.l d1,d3 ; get number of logical pages in 24-bit mode move.l d3,mdPages24(a0) ; save number of pages in 24-bit mode @noPages movem.l (sp)+,@saveRegs ; restore registers unlk a6 rts EndWith EndProc ;------------------------------------------------------------------- ; GetPageRange - Sanity check on the logical address and count ; ; Destroys: a0/d1/d2 ; ; On entry: ; a0.l = logical address ; a1.l = logical count ; a2.l = ptr to MemoryDispatch globals ; ; On exit: ; d0.w = error code ; d1.l = first page ; d2.l = number of pages in range ; a0.l = clean logical address ; a1.l = logical count (unchanged) ; a2.l = ptr to MemoryDispatch globals (unchanged) ; ;------------------------------------------------------------------- GetPageRange Proc Export With MemDispGlobals @saveRegs REG a1/a2 movem.l @saveRegs,-(sp) ; save registers move.l a0,d0 ; get logical address IF Supports24Bit THEN ; tst.b MMU32Bit ; check if in 32-bit mode bne.s @noStrip ; if 32-bit mode, assume clean address _StripAddress ; clean the address @noStrip ENDIF movea.l d0,a0 ; save clean logical address cmpa.w #0,a1 ; check the count beq.s @error ; if zero count, return paramErr move.l d0,d1 ; copy the start address move.l d0,d2 ; copy the start address add.l a1,d2 ; get end of buffer subq.l #1,d2 ; last = start + count - 1 cmp.l realMemtop,d2 ; check against available RAM bhs.s @error ; if last >= realMemTop, return paramErr move.l mdLog2PageSize(a2),d0 ; get log2 of page size lsr.l d0,d1 ; get page number of start address lsr.l d0,d2 ; get page number of last address sub.l d1,d2 ; page count = lastPage - firstPage + 1 addq.l #1,d2 moveq.l #noErr,d0 ; it worked @exit movem.l (sp)+,@saveRegs ; restore registers rts @error moveq.l #paramErr,d0 ; it failed bra.s @exit EndWith EndProc ;------------------------------------------------------------------- ; MMUSetWriteProtect - Set W (Write Protect) bit for a page ; ; Destroys: none. ; ; On entry: d0.l = write protect mask: 0=clear write protect bit ; 4=set write protect bit (bit 2) ; d1.l = logical page number ; a2.l = ptr to MemoryDispatch globals ; ; Calls: GetPageDescProc ; ;------------------------------------------------------------------- MMUSetWriteProtect Proc Export Import GetPageDescProc With MemDispGlobals @saveRegs REG d0-d4/a0/a1 @moreRegs REG d1/a1/a2 @wBit EQU 2 ; write protect bit in all page descriptors cmp.b #PMMU851,MMUType ; do we have at least a 68851 PMMU ? blo.w @noPages ; if not, no pages to write protect (020 or less) @hasPages movem.l @saveRegs,-(sp) ; save registers move.l d0,d4 ; remember write-protect mask CMPI.B #EMMU1,MMUType ; Do we have an EMMU? BNE.S @RealMMU ; -> Nope, sorry MOVE.L D1,A0 ; Put the page number in A0 _nkGetPTEntryGivenPage ; Get the 030+ PTE from the nk BCLR #@wBit,D0 ; Clear the W bit OR.L D4,D0 ; Clear/set the write-protect flag MOVE.L D0,A0 ; Move the PTE to A0 MOVE.L D1,A1 ; Put the page number in A1 _nkSetPTEntryGivenPage ; Set the 030+ PTE BRA.S @RegDone ; -> Exit @RealMMU move.l mdLog2PageSize(a2),d0 ; get the log2 of the page size asl.l d0,d1 ; turn logical page number into a logical address IF Supports24Bit THEN ; cmp.l mdPages24(a2),d1 ; check if page is in the 24-bit address space slo d3 ; if it is, be sure to whack the 24-bit table moveq.l #false32b,d0 ; first go to 24-bit mode _SwapMMUMode ; go to 24-bit mode move.l d0,d2 ; remember the caller's MMU mode movea.l d1,a0 ; set up logical address to get page descriptor movem.l @moreRegs,-(sp) ; save registers that GetPageDesc destroys bsr GetPageDescProc ; ptr to page descriptor given logical address movem.l (sp)+,@moreRegs ; restore registers that GetPageDesc destroys movea.l a0,a1 ; save ptr to 24-bit page descriptor moveq.l #true32b,d0 ; go to 32-bit mode _SwapMMUMode ; go to 32-bit, return caller's MMU mode ENDIF movea.l d1,a0 ; set up logical address to get page descriptor movem.l @moreRegs,-(sp) ; save registers that GetPageDesc destroys bsr GetPageDescProc ; ptr to page descriptor given logical address movem.l (sp)+,@moreRegs ; restore registers that GetPageDesc destroys bclr.b #@wBit,3(a0) ; clear the W bit or.l d4,(a0) ; clear/set the write-protect flag IF Supports24Bit THEN ; tst.b d3 ; should we whack the 24-bit table ? beq.s @exit ; if not, we're done bclr.b #@wBit,3(a1) ; clear the W bit or.l d4,(a1) ; clear/set the write-protect flag @exit move.l d2,d0 ; caller's MMU mode _SwapMMUMode ; restore the MMU mode ENDIF @regDone movem.l (sp)+,@saveRegs ; restore registers @noPages rts EndWith EndProc ;------------------------------------------------------------------- ; MMUSetCacheInhibit - Set CI (Cache Inhibit) bit for a page ; ; NOTE: On the 040, it is assumed that bit 5 of the page descriptor (CM[0]) is ; meaningful, since it is used to select write-through/copyback when ; caching is enabled. For this reason, only bit 6 (CM[1]) is set to ; disable caching. This will cause some pages to be marked noncachable ; serialized, and some to be non-serialized. Eventually, we need to ; maintain globally what the overall caching mode is so that the cache ; enabling code can set the CM[1:0] bits appropriately. ; ; Changed to get both page descriptors first, then whack them in 32-bit mode. ; ; Destroys: none. ; ; On entry: d0.l = cache inhibit flag: 0=clear cache inhibit bit(s) ; 1=set cache inhibit bit(s) ; d1.l = logical page number ; a2.l = ptr to MemoryDispatch globals ; ; Calls: GetPageDescProc ;------------------------------------------------------------------- MMUSetCacheInhibit Proc Export Import GetPageDescProc,MMUSetCacheMode With MemDispGlobals @saveRegs REG d0-d4/a0/a1 @moreRegs REG d1/a1/a2 cmp.b #PMMU851,MMUType ; do we have at least a 68851 PMMU ? blo.w @noPages ; if not, we can't control data caching (020 or less) @hasPages movem.l @saveRegs,-(sp) ; save registers cmpi.b #EMMU1,MMUType ; Do we have an EMMU? bne.s @RealMMU ; -> Nope, sorry MOVE.L D1,A0 ; Put the page number in A0 ADDI.W #mmuMakePageCacheable,D0 ; Turn the cache mode flag into a nKernel selector _KernelVMDispatch ; Set the cache status & flush the ATC BRA.S @RegDone ; -> Exit @RealMMU move.l d0,d4 ; remember inhibit flag move.l mdLog2PageSize(a2),d0 ; get the log2 of the page size asl.l d0,d1 ; turn logical page number into a logical address IF Supports24Bit THEN ; cmp.l mdPages24(a2),d1 ; check if page is in the 24-bit address space slo d3 ; if it is, be sure to whack the 24-bit table moveq.l #false32b,d0 ; first go to 24-bit mode _SwapMMUMode ; go to 24-bit mode move.l d0,d2 ; remember the caller's MMU mode movea.l d1,a0 ; set up logical address to get page descriptor movem.l @moreRegs,-(sp) ; save registers that GetPageDesc destroys bsr GetPageDescProc ; ptr to page descriptor given logical address movem.l (sp)+,@moreRegs ; restore registers that GetPageDesc destroys movea.l a0,a1 ; save ptr to 24-bit page descriptor moveq.l #true32b,d0 ; go to 32-bit mode _SwapMMUMode ENDIF movea.l d1,a0 ; set up logical address to get page descriptor movem.l @moreRegs,-(sp) ; save registers that GetPageDesc destroys bsr GetPageDescProc ; ptr to page descriptor given logical address movem.l (sp)+,@moreRegs ; restore registers that GetPageDesc destroys bsr.s MMUSetCacheMode ; go whack the page descriptor IF Supports24Bit THEN ; tst.b d3 ; should we whack the 24-bit table ? beq.s @exit ; if not, we're done movea.l a1,a0 ; point to the 24-bit page descriptor bsr.s MMUSetCacheMode ; go whack the page descriptor @exit move.l d2,d0 ; caller's MMU mode _SwapMMUMode ; restore the MMU mode ENDIF @RegDone movem.l (sp)+,@saveRegs ; restore registers @noPages rts EndWith EndProc ;------------------------------------------------------------------- ; MMUSetCacheMode - code to actually whack the page table entry (Called in 32-bit mode) ; ; Destroys: None. ; ; On entry: d4.l = cache inhibit flag: 0=clear cache inhibit bit(s) ; 1=set cache inhibit bit(s) ; a0.l = logical address of page descriptor ; a2.l = ptr to MemoryDispatch globals ;------------------------------------------------------------------- MMUSetCacheMode Proc Export @saveRegs REG d0/d1 @cacheBit EQU 6 ; C bit for 851/030, CM[1] for 040 (CM[0] untouched) @cm0bit EQU 5 ; CM[0] bit in 040 page descriptor movem.l @saveRegs,-(sp) ; save registers tst.b d4 ; check the cache inhibit flag beq.s @enableCaching ; if clear, enable caching for the page move.l (a0),d1 ; get page desc (forces serialization on 040) bset.l #@cacheBit,d1 ; inhibit caching bclr.l #@cm0bit,d1 ; make it non-serialized move.l d1,(a0) ; update page descriptor bra.s @exit @enableCaching clr.l d1 ; clear 68040 mask bfextu CacheFlags{31-bCopybackMode:1},d1 ; get current cache mode lsl.l #@cm0bit,d1 ; make a mask for a 68040 page descriptor or.l (a0),d1 ; get page descriptor (forces copyback on 040) bclr.l #@cacheBit,d1 ; enable caching move.l d1,(a0) ; update page descriptor @exit movem.l (sp)+,@saveRegs ; restore registers rts EndProc ;------------------------------------------------------------------- ; ; MMUFlushATC - Flush all entries in the MMU's Address Translation Cache ; ;------------------------------------------------------------------- MMUFlushATC Proc Export cmpi.b #EMMU1,MMUType ; do we have an Emulated MMU? beq.s @exit ; -> Yes, do nothing cmp.b #PMMU851,MMUType ; do we have at least a 68851 PMMU ? blo.s @exit ; if not, we're done cmp.b #PMMU040,MMUType ; do we have an 040 PMMU? beq.s @handle040 ; if so, use 040 PFLUSHA pflusha ; use 851 & 030 PFLUSHA @exit rts ; done @handle040 MACHINE MC68040 pflusha ; flush the ATC MACHINE MC68030 rts EndProc END