mac-rom/OS/HwPriv.a

1539 lines
54 KiB
Plaintext

;
; 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):
;
; <SM32> 2/7/94 chp Extensive housecleaning in the HwPriv implementations, including
; the elimination of separate RISC and 68K dispatch tables.
; <SM31> 12/23/93 PN Take out overpatches on LockMemoryproc, LockMemoryContigousProc
; and also take out IsUniversal conditionals.
; <SM30> 12/13/93 PN Roll in KAOs and Horror changes to support Malcom and AJ
; machines.
; <SM29> 11/9/93 KW added some eieioSTP macros. Only expands for CygnusX1 ROM
; <SM28> 10/14/93 pdw <MC3><MC4>.
; <MC4> 10/11/93 CCH Separated Edisk protect routine into one for PowerPC and one for
; 68k.
; <MC3> 10/10/93 CCH Turned on EDisk support for PowerPC machines.
; <SM27> 9/13/93 SAM Replaced the alternate dispatch table that was inadvertently
; removed in the last rev.
; <SM26> 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.
; <SM25> 8/19/93 chp Fix the dispatcher so it wonÕt barf on a selector of 13. (BHI ->
; BHS)
; <SM24> 8/4/93 GMR <RC> Added code to SlotBlockXferCtl to support block transfers
; for BART machines (PDM,CF).
; <SM23> 6/14/93 SAM Reenabled the "DMADispatch" selector for PDM.
; <SM22> 6/14/93 kc Roll in Ludwig.
; <LW6> 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.
; <SM21> 4/22/93 CSS Changed emDMADispGlobs to emDMADispatchGlobals which matches
; Reality.
; <SM20> 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.
; <SM19> 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.
; <SM18> 3/11/93 SAM Added a refCon field to the PDM DMA irq handler installer.
; <SM17> 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.
; <LW3> 2/11/93 PW Added passing of drivers' "don't munge heaps" bit into SCSILoad.
; <SM15> 2/9/93 rab Sync up with Horror. Comments follow.
; <H2> 7/13/92 NJV <SES> 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.
; <SM14> 2/6/93 RC Fixed last fix (sorry)
; <SM13> 2/6/93 RC Fixed InitMemDispatchTrap for Quadra
; <SM12> 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.
; <SM11> 12/11/92 SWC Moved the code to disable the MemoryDispatch trap here from
; StartInit. Put a hasMDU conditional around the EnableExtCache
; code.
; <SM10> 11/3/92 SWC Changed SCSIEqu.a->SCSI.a.
; <SM9> 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.
; <SM8> 6/19/92 RB Added the selector for the DMADispatch code.
; <SM7> 5/17/92 kc Roll in Horror changes. Comments follow.
; <SM6> 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.
; <H11> 7/11/91 CCH Fixed a bug in GetPhysical.
; <H10> 6/27/91 djw (pdw) Add new selector _WaitForSCSIDevs to wait for SCSI devices
; and load their drivers. Just added nub code here.
; <H9> 6/14/91 RP Changed length parameter for FlushCacheRange to be passed in A1
; instead of D1.
; <H8> 5/10/91 RP Added selector to HwPriv for flush cache range.
; <H7> 5/10/91 CCH Added selector to HwPriv for Edisk protection.
; <H6> 2/18/91 JK Added WriteProtect selectors to MemoryDispatch
; <H5> 1/24/91 JK Added LockMemory calls that use a page-lock table.
; <H4> 1/24/91 CCH Moved LastEnt label to include new selectors.
; <H3> 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.
; <H2> 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 <cache(s)>. 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 <SMN29> 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 <JDR> 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 <xyz>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
dc.w $d8b8 ; HARDCODED due to unhappy linker, must remove
HwPrivSelector FlushCRange ; 9 FlushCRange
HwPrivSelector ReturnErr ; 10 WaitForSCSIDevs
HwPrivSelector ReturnErr ; 11 Unused
HwPrivSelector SlotBlockXferCtl ; 12 - enable block xfers to a slot
HwPrivSelector ReturnErr ; 13 - Get Ethernet ID from serial ROM
HwPrivSelector ReturnErr ; 14
HwPrivSelector ReturnErr ; 15
HwPrivSelector MakeSomethingWriteThrough ; 16
LastVec
ALIGN 8
HWPrivSwitch
cmpi.w #(LastVec-Vects)/HwVecSize,d0 ; check if selector in range
bcc.s 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
;----------
;
; 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
@EmuFake lea 1,a0 ; do nothing and report that caches were enabled
moveq #noErr,d0
rts
ENDPROC
;----------
;
; FlushICache (_HWPriv Selector 1)
;
; This routine flushes the 020/030/040...'s instruction cache.
;
; On 040s, it also causes a flush of the data cache. This is because previous uses
; of _FlushInstructionCache were to make sure that memory and caches were in sync if
; either self-modifying or newly read-in code (from wherever).
;
; Destroys: none
;
;----------
FlushICache PROC EXPORT
btst.b #2,$240a
bnz.b @Coherent
jsr ([jCacheFlush]) ; invalidate both caches
@Coherent
moveq #noErr,d0 ; signal all's well
rts
ENDPROC
;----------
;
; SwapDCache (_HWPriv Selector 2)
;
; This routine turns the 020/030/040... data cache off or on. If the cache is being
; turned on, it is also flushed.
;
; Entry:
;
; A0 (long) - zero to turn data cache off, non-zero to turn it on
;
; Exit:
;
; A0 (long) - has previous state of data cache (zero = off, non-zero = on)
;
; Destroys: D1, D2
;
;----------
SwapDCache PROC EXPORT
@EmuFake lea 1,a0 ; do nothing and report that caches were enabled
moveq #noErr,d0
rts
ENDPROC
;----------
;
; FlushDCache (_HWPriv Selector 3)
;
; This routine flushes the 030/040...'s data cache. It has no effect on an 020.
;
; Destroys: none
;
;----------
FlushDCache PROC EXPORT
moveq #noErr,d0 ; signal all's well
rts
ENDPROC
;----------
;
; EnableExtCache (_HWPriv Selector 4)
;
; This routine turns the external Cache on.
; Entry: none
; EXit: none
;
;----------
EnableExtCache PROC EXPORT
moveq #noErr,d0 ; signal all's well
rts
ENDPROC
;----------
;
; DisableExtCache (_HWPriv Selector 5)
;
; This routine turns the external Cache off.
; Entry: none
; EXit: none
;
;----------
DisableExtCache PROC EXPORT
moveq #noErr,d0 ; signal all's well
rts
ENDPROC
;----------
;
; FlushExtCache (_HWPriv Selector 6)
;
; This routine flushes the external Cache by disabling external Cache and
; enabling external cache.
; Entry: none
; EXit: none
;
;----------
FlushExtCache PROC EXPORT
JSR DisableExtCache ; call routine directly
JSR EnableExtCache ; call routine directly
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 = <SCC number>.B <port number>.B <enable/disable ext clock>.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 = <SCC number>.B <port number>.B <last state of external clock>.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 = <external clk value>.w <scc>.b <port>.b
tst.w d2 ; check SCC and port number
bne ReturnErr ; only port A supported
@BuiltinSCC
TestFor VIA1Exists
beq.s @Done ; no via - nothing to do now
tst.w d1 ; get state to set from low word
snz d2 ; set or clear D2.B accordingly
movea.l VIA,a1
clr.w d1
btst #vSync,vBufA(a1) ; test current value
snz d1 ; set or clear D1.B accordingly
eor.b d1,d2 ; setting already the same as old ?
beq.s @FixResult ; already set to correct state - done
bchg #vSync,vBufA(a1) ; change the clock setting
@FixResult neg.b d1
moveq #noErr,d0 ; set good error return
; 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
;----------
;
; 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
FlushCRange
move.l a1,d0
dc.w $FC16
@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 #paramErr,D0
rts
ENDPROC
;----------
;
; MakeSomethingWriteThrough
;
;----------
MakeSomethingWriteThrough PROC EXPORT
Move.L ([$1FF4],$8), D2
Move.L A0, D0
LsR.L D2, D0
MoveA.L D0, A0
Move.L A1, D0
SubQ.L #$1, D0
LsR.L D2, D0
Move.L D0, D2
@loop
_nkMakePageWriteThrough
Tst.L D0
BMI.B @exit
AddQ #$1, A0
DBF D2, @loop
MoveQ.L #$0, D0
@exit
Rts
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. <T2>
; This to provide support for Sonic onboard Ethernet. <start>
;
; To support write-protect, the lock counter behavior has been altered to include <T4>
; a write-protect bit. The high bit in each lock counter indicates that the page <T4>
; is write-protected. No count is kept of the number of lock/unlock calls that <T4>
; have been made. <T4>
;-----
;----------
;
; 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 <SM6>
ENDM
MdVecSize EQU 2
ELSE
MACRO
MemDispSelector &addr
dcImportResident &addr ; ADDRESS of routine
ENDM
MdVecSize EQU 4
ENDIF
;---------------
;
; MemoryDispatch a590
;
; 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 <T6>
MemDispSelector UnWriteProtectProc ; 7 <T6>
dc.w badSelect-Vects ; 8 <T6>
dc.w badSelect-Vects ; 9 <T6>
LastVec MemDispSelector LockMemoryProc ; 10 <T6>
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
badSelect2
badSelect3
badSelect move.l #hwParamErr,d0 ; abort: return error code
rts
EndProc
;-----
;
; HoldMemoryProc a5c0 (_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 a5d0 (_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 a5e0 (_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 <T2>
; lock count for the page. <T2>
;
; 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.l*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 <T4>
bhi.s @loop ; keep looping <T4>
@done moveq.l #noErr,d0 ; no error
@error
movem.l (sp)+,@saveRegs ; restore registers
rts
EndWith
EndProc
;-----
;
; UnLockMemoryProc a610 (_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 <T2>
; count is zero, markd the page as cacheable. <T2>
;
; 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.l*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 <T4>
bhi.s @lockCheckLoop ; keep looping <T4>
lea.l mdLockTable(a2,d1.l*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 <T4>
bhi.s @unlockLoop ; keep looping <T4>
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 a660 (_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.l*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 <T4>
bhi.s @loop ; keep looping <T4>
@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 a6c0 (_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 <v2.1>
move.l a0,-(sp) ; save pointer to table on stack
move.l a0,a4 ; get table entry pointer in a4 <T3>
Move.L A1,D3 ; get table entry number <T3>
MOVE.L (A4)+,D2 ; get virtual address in d2 <T3>
@NoSwap
move.l d2,a0 ; put virtual address in a0 <T3>
ADD.L (A4),D2 ; get end of buffer <T3>
CMP.L realMemtop,D2 ; does it exceed available RAM <v1.3>
BHI.S @BadAddress ; >>EXIT if it exceeds top of RAM <v2.1>
BSR.L GetRealProc ; get physical address in a0 <T3>
BMI.S @BadAddress ; branch if bad address
MOVE.L A0,A3 ; save physical address in A3
MOVE.L D2,A0 ; get end of buffer <T3>
SUBQ.L #1,A0 ; convert to end address <T3>
BSR.L GetRealProc ; get physical address in a0 <T3>
BMI.S @BadAddress ; branch if bad address
SUB.L A3,A0 ; calculate distance between addresses <T3>
ADDQ.L #1,A0 ; convert to byte count <T3>
CMP.L (A4),A0 ; are they the same size <T3>
BNE.S @NonContig ; branch, if memory is not contiguous
TST.L d3 ; d3 = 0?? <T3>
BEQ.S @return1 ; branch, if yes
MOVE.L (A4)+,D0 ; save buffer size <T3>
ADD.L D0,VAddr(A4) ; update virtual address <T3>
MOVE.L #0,BuffSize(A4) ; update buffer size <T3>
MOVE.L A3,(A4)+ ; save physcial address in table <T3>
MOVE.L D0,(A4) ; save size in table <T3>
@return1
MOVE.L #1,A0 ; return with 1 entry <v1.3>
MOVE.W #0,D2 ; and with no error
@GPEXit
MOVE.L D2,D0 ; set final error code <v1.6>
MOVE.L (SP)+,A1 ; restore pointer <v1.3>
MOVEM.L (SP)+,GetPhysRegs ; restore registers <v2.1>
RTS
@BadAddress
MOVEQ #0,A0 ; when error, return zero entry <v1.3>
MOVE.W #paramErr,D2 ; return paramErr
BRA.S @GPExit
@NonContig
MOVE.L (SP),A4 ; A0 gets pointer to table <T3>
MOVE.L (A4),A0 ; get logical address in A0 <v2.1>
ADD.L #8,A4 ; A4 = points to table entry
MOVE.L D3,D1 ; D1 = number of table entry or 0 <T11>
BSR ChkContig ; check contiguous physical
TST.W D2 ; are there error
BMI.S @BadAddress
MOVE.L D1,A0 ; get number of entries in A0 <v1.3>
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 <v2.1>
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 <T3>
MOVE.L Buffsize(a4),OSize(A6) ; save original size <T3>
BSR.L GetRealProc ; convert addr in a0 to physical addr <T3>
BMI @BadAddress ; branch if bad address
MOVE.L A0,PhysAddr(A6) ; save physical address <LW7>
MOVE.L LockMemCt,A2 ; point to MemoryDispatch globals <LW7>
move.l mdPageSize(A2),D2 ; point to MemoryDispatch globals
; Removed a ¥Gestalt¥ call to get the page size! Sheeze! <SM17>
; to calculate amount of memory in the first page
SUBQ #1,d2 ; create mask to get bytes in 1st page <T3>
MOVE.L PhysAddr(A6),D3 ; get physical address <T11>
NEG.L D3 ; negate the address <T11>
AND.L D3,D2 ; get remaining bytes in first page <T11>
MOVE.L D2,ContigSize(A6) ; save memory size
MOVE.L OVaddr(A6),A3 ; get original logical address <T11>
ADD.L D2,A3 ; get logical address on page boundary <T11>
@loop
MOVE.L A3,A0 ; get logical address into A0 <T11>
BSR.L GetRealProc ; convert addr in A0 to physical addr <T3>
BMI @BadAddress ; branch if bad address
MOVE.L LockMemCt,A2 ; restore A2,points toMemoryDispatch globals <LW7>
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<T3>
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 <SM17>
CMP.L BuffSize(a4),D3 ; is it end yet? <T3>
BCC.S @Done ; yes, branch
MOVE.L D3,ContigSize(A6) ; update contiguous size
ADD.L mdPageSize(a2),A3 ; get new virtual address <T11><SM17>
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 <T3>
MOVE.L ContigSize(A6),(4,a4,D3.L*8); store contiguous size <T3>
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 <T3>
SUB.L D3,BuffSize(a4) ; update buffer size <T3>
Move.L A0,PhysAddr(A6) ; update new physical address <T11>
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 <T3>
MOVE.L OSize(A6),BuffSize(a4) ; restore original size <T3>
BRA.S @ExitB
@GetResult
MOVE.L EntryIndex(A6),D3 ; get entry index
MOVE.L PhysAddr(A6),(0,a4,D3.L*8) ; store physical address <T3>
MOVE.L BuffSize(a4),(4,a4,D3.L*8) ; store size <T3>
MOVE.L BuffSize(a4),D2 ; save remaining buffsize <T3>
Add.L D2,VAddr(a4) ; update virtual address <T3>
MOVE.L #0,BuffSize(a4) ; indicate complete translation <T3>
AddQ.L #1,D3 ; convert index to entry count
@ExitA
MOVE.L D3,D1 ; return entry count
@ExitB
MOVEQ #0,D2 ; no error <v1.6>
@ExitC
MOVEM.L (SP)+,D3-D7 ; restore registers <v2.1>
UNLK A6
ENDWITH
RTS
@BadAddress
MOVE.W #-1,D2 ; return paramErr <v1.6>
BRA.S @ExitC
EndWith
EndProc
;-----
;
; WriteProtectProc a850 (_MemoryDispatch Selector 6) <T4>
; <start>
; 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
@NoFlush lea.l mdLockTable(a2,d1.l*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 <end>
rts ; <T4>
EndWith
EndProc
;-----
;
; UnWriteProtectProc a88c (_MemoryDispatch Selector 7) <T4>
; <start>
; 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.l*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 <end>
rts ; <T4>
EndWith
EndProc
;-------------------------------------------------------------------
;
; InitMemoryDispatch a8e0
;
; 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)
@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 ?)
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. <SM17>
@countBits asr.l #1,D0 ; Shift bit zero into the carry. <SM17>
bcs.s @gotPageSize ; -> Bail out at the first bit set w/bit # in d1 <SM17>
addq #1,d1
bra.s @countBits ; Keep shifting till we find one <SM17>
@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 a980 - 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 ; <SM17>
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 a9c0 - Set W (Write Protect) bit for a page <T4>
; <start>
; 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
movem.l @saveRegs,-(sp) ; save registers
move.l d0,d4 ; remember write-protect mask
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
@regDone movem.l (sp)+,@saveRegs ; restore registers <T4>
@noPages
rts
EndWith
EndProc
;-------------------------------------------------------------------
; MMUSetCacheInhibit a9e0 - 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. <T4>
;
; 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
movem.l @saveRegs,-(sp) ; save registers
btst.b #7,$240A
bne.s @RegDone
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
@RegDone movem.l (sp)+,@saveRegs ; restore registers
@noPages
rts
EndWith
EndProc
;-------------------------------------------------------------------
;
; MMUFlushATC aa00 - Flush all entries in the MMU's Address Translation Cache
;
;-------------------------------------------------------------------
MMUFlushATC Proc Export
rts
EndProc
END