sys7.1-doc-wip/OS/HwPriv.a

2289 lines
81 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; Hacks to match MacOS (most recent first):
;
; <Sys7.1> 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):
;
; <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 wont 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 its 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, dont use is32BitClean conditional - all future
; ROMs will be.
; <18> 8/30/91 DTY Define isUniversal here since its 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
; doesnt 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
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 its not a valid selector
move.w Vects(d0*HwVecSize),d0 ; get offset to selectors 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 ; <Sys7.1> Vectors for non-68000 non-TERROR (0 means use ROM version)
dcImportResident SwapICache ; <Sys7.1> 0 SwapICache
dcImportResident FlushICache ; <Sys7.1> 1 FlushICache
dcImportResident SwapDCache ; <Sys7.1> 2 SwapDCache
dcImportResident FlushDCache ; <Sys7.1> 3 FlushDCache
dcImportResident EnableExtCache ; <Sys7.1> 4 EnableExtCache
dcImportResident DisableExtCache ; <Sys7.1> 5 DisableExtCache
dcImportResident FlushExtCache ; <Sys7.1> 6 FlushExtCache
dcImportResident SwapSerialClock ; <Sys7.1> 7 SwapSerialClock
dc.l 0 ; <Sys7.1> 8 Protect/Unprotect EDisk (new to TERROR, left unimplemented)
dcImportResident FlushICache ; <Sys7.1> 9 FlushCRange (new to TERROR, backported here)
dcImportResident WaitForSCSIDevs ; <Sys7.1> 10 WaitForSCSIDevs (new to TERROR, backported here)
EndProc
MaxSelector equ 10
HwPrivVectsTerror Proc Export ; <Sys7.1> Vectors for TERROR (0 means use ROM version)
dc.l 0 ; <Sys7.1> 0 SwapICache
dc.l 0 ; <Sys7.1> 1 FlushICache
dc.l 0 ; <Sys7.1> 2 SwapDCache
dc.l 0 ; <Sys7.1> 3 FlushDCache
dc.l 0 ; <Sys7.1> 4 EnableExtCache
dc.l 0 ; <Sys7.1> 5 DisableExtCache
dc.l 0 ; <Sys7.1> 6 FlushExtCache
dcImportResident SwapSerialClock ; <Sys7.1> 7 SwapSerialClock
dc.l 0 ; <Sys7.1> 8 Protect/Unprotect EDisk (new to TERROR, ROM version fine)
dc.l 0 ; <Sys7.1> 9 FlushCRange (new to TERROR, ROM version fine)
dc.l 0 ; <Sys7.1> 10 WaitForSCSIDevs (new to TERROR, ROM version fine)
EndProc
MaxSelectorTerror equ 10
PatchHwPriv68000 InstallProc (Plus,SE,Portable) ; <Sys7.1> Reconstructed from <29>
IMPORT InitHwPrivVects, VectsSize ; <Sys7.1>
cmp.b #cpu68020,CpuFlag ; <Sys7.1> Use table above for 020/030 accelerators,
blo.s @exit ; <Sys7.1> but not for real 68000s.
cmp.b #cpu68030,CpuFlag ; <Sys7.1>
bhi.s @exit ; <Sys7.1>
leaResident CmpMaxHwPrivSelector,a0 ; <Sys7.1>
move.w #MaxSelector,d2 ; <Sys7.1>
move.w d2,2(a0) ; <Sys7.1>
leaResident HwPrivVects,a2 ; <Sys7.1> Set up our vector table in ExpandMem
jsr InitHwPrivVects ; <Sys7.1>
@exit rts ; <Sys7.1>
EndProc
PatchHwPrivII InstallProc (II,IIci,notTERROR) ; <Sys7.1> Reconstructed from <5>
IMPORT InitHwPrivVects, VectsSize ; <Sys7.1>
leaResident CmpMaxHwPrivSelector,a0 ; <Sys7.1> Highest selector on non-overpatch IIci/II = 10
move.w #MaxSelector,d2 ; <Sys7.1>
move.w d2,2(a0) ; <Sys7.1>
leaResident HwPrivVects,a2 ; <Sys7.1> Set up our vector table in ExpandMem
jsr InitHwPrivVects ; <Sys7.1>
rts ; <Sys7.1>
EndProc
PatchHwPrivTerror InstallProc (IIci,hasTERROR) ; <Sys7.1> Reconstructed from <5>
IMPORT InitHwPrivVects ; <Sys7.1>
leaResident CmpMaxHwPrivSelector,a0 ; <Sys7.1>
move.w #MaxSelectorTerror,d2 ; <Sys7.1>
move.w d2,2(a0) ; <Sys7.1>
leaResident HwPrivVectsTerror,a2 ; <Sys7.1> Set up our vector table in ExpandMem
jsr InitHwPrivVects ; <Sys7.1>
rts ; <Sys7.1>
EndProc
InitHwPrivVects Proc Export ; <Sys7.1> Fill gaps in the table (passed in a2) and save it in ExpandMem
move.w #$A198,d0 ; <Sys7.1> Original trap (a0) is used to fill in zeros
_GetOSTrapAddress ; <Sys7.1>
move.l a2,a1 ; <Sys7.1> a1 = Table base, a2 = Table counter
@loop move.l (a2)+,d1 ; <Sys7.1> Loop over HwPrivVects
beq.s @fillgap ; <Sys7.1> Replace a 0 with the original _HwPriv handler
@filldone dbra d2,@loop ; <Sys7.1>
move.l ExpandMem,a0 ; <Sys7.1> Save to ExpandMem
move.l a1,ExpandMemRec.emHwPrivTable(a0) ; <Sys7.1>
rts ; <Sys7.1>
@fillgap move.l a0,-4(a2) ; <Sys7.1>
bra.s @filldone ; <Sys7.1>
EndProc
HWPrivTrap PatchProc _HWPriv,(Plus,SE,II,Portable,IIci) ; <Sys7.1> Vector the call through ExpandMem
EXPORT CmpMaxHwPrivSelector ; <Sys7.1>
IMPORT SwapSerialClock ; <Sys7.1>
cmp.b #cpu68020,CpuFlag ; <Sys7.1> Unless on 68000, which only handles SwapSerialClock
blo.s on000 ; <Sys7.1>
CmpMaxHwPrivSelector ; <Sys7.1> CMP edited to test for highest selector
cmp.w #0,d0 ; <Sys7.1>
bhi.s @jmprom ; <Sys7.1>
lea -4(sp),sp ; <Sys7.1> Jump to
move.l a0,-(sp) ; <Sys7.1>
move.l ExpandMem,a0 ; <Sys7.1>
move.l ExpandMemRec.emHwPrivTable(a0),a0 ; <Sys7.1>
move.l (a0,d0.w*4),4(sp) ; <Sys7.1>
move.l (sp)+,a0 ; <Sys7.1>
rts ; <Sys7.1>
@jmprom jmpOld ; <Sys7.1>
ReturnErr move.l #hwParamErr,d0 ; <Sys7.1>
rts ; <Sys7.1>
on000 cmp.w #7,d0 ; <Sys7.1>
bne.s ReturnErr ; <Sys7.1>
jmp SwapSerialClock ; <Sys7.1>
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<<CACR_EI_020_030)|\ ; set enable,
(1<<CACR_CI_020_030)),d0 ; flush I-Cache flags
@dontTurnOn
bra.s @SetCACR ; go set the desired cache state
@handle040
movec CACR,d0 ; get current cache state
bfextu d0{16:1},d1 ; get cache enable bit into LSbit of d1
bclr #CACR_IE_040,d0 ; assume we're disabling
move.l a0,d2 ; are we enabling the I-Cache?
beq.s @SetCACR ; NO ... go turn in OFF
MACHINE MC68040 ;
cpusha ic
MACHINE MC68030 ;
bset #CACR_IE_040,d0 ; set IE=1 to enable I-Cache
@SetCACR
move.l d1,a0 ; save the previous I-Cache state
movec d0,CACR ; set the Cache to desired state
moveq #noErr,d0 ; signal all's well
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
cmp.b #cpu68040,CpuFlag ; are we on an 040-based machine?
bge.s @handle040
movec CACR,d0 ; get current cache state
bset #CACR_CI_020_030,d0 ; set enable flag
movec d0,CACR ; set cache state
bra.s @Coherent
@handle040
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
cmp.b #cpu68040,CpuFlag ; are we on an 040-based machine?
bge.s @handle040
@handle030
movec CACR,d0 ; get current cache state
bfextu d0{23:1},d1 ; get cache enable bit into LSbit of d1.l
bclr #CACR_ED_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.w #((1<<CACR_ED_030)|\ ; set enable,
(1<<CACR_CD_030)),d0 ; flush D-Cache flags
@dontTurnOn
bra.s @SetCACR ; set cache to the desired state
@handle040
movec CACR,d0 ; get current D-Cache state
bfextu d0{0:1},d1 ; put cache enable bit into LSbit of d1.l
bclr #CACR_DE_040,d0 ; assume we're enabling
move.l a0,d2 ; check what we are really doing
beq.s @SetCACR ; if we are disabling the caches
MACHINE MC68040 ;
nop ; required by D43B CPUSHA DC errata item
cpusha dc ; push dirty D-Cache data items to memory
MACHINE MC68030 ;
bset #CACR_DE_040,d0 ; set DE=0 to disable D-Cache
@SetCACR
move.l d1,a0 ; save the previous D-Cache state
movec d0,CACR ; update D-Cache status value
moveq #noErr,d0 ; signal all's well
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
cmp.b #cpu68040,CpuFlag ; are we on an 040-based machine?
bge.s @handle040
@handle030
movec CACR,d0 ; get current cache state
bset #CACR_CD_030,d0 ; set 'clear data cache' flag
movec d0,CACR ; set cache state
bra.s @flushDCacheExit
@handle040
MACHINE MC68040
nop ; required by DD43B CPUSHA DC errata item
cpusha dc ; flush the D-Cache
MACHINE MC68030
@flushDCacheExit
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
move.w sr,-(sp) ; save int mask
ori.w #HiIntMask,sr ; disable all interrupts
movea.l UnivInfoPtr,a0 ; point to the product info
cmpi.b #DecoderKinds.MDUDecoder,\
ProductInfo.DecoderKind(a0) ; see if we have an MDU
bne.s @noMDU ; if not, nothing to enable
; enable the external MDU cache as follows:
; Toggle the RvCFlush bit 1 - 0 - 1, to flush the cache
; set the RvCDis bit to 0, to enable the cache (special restriction, can't access cacheable
; memory for some amount of time after enableing the cache. By executing this code in
; a loop, it will be executing out of the instruction cache, and not accessing memory)
movea.l VIA2RBV,a0 ; get the VIA2 or RBV base address
lea vBufB|RvDataB(a0),a0 ; point to the cache register
moveq.l #~(1<<RvCFlush),d0 ; mask to clear flush bit (active low)
and.b (a0),d0 ; get the register, clear flush
btst.l #RvCDis,d0 ; test the cache disable bit (active high)
beq.s @flushDone ; if already enabled, nothing to do
move.b d0,(a0) ; flush the cache
bset.l #RvCFlush,d0 ; setup to un-flush the cache
@loop move.b d0,(a0) ; 1st time, un-flush, 2nd time, enable cache
move.b (a0),(a0) ; kill time accessing the RBV/VIA2
move.b (a0),(a0) ; kill some more time
bclr.l #RvCDis,d0 ; enable the cache (active high)
bne.s @loop ; loop if first time through
@noMDU
@flushDone move.w (sp)+,sr ; restore int mask
@extCacheDone
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
movea.l UnivInfoPtr,a0 ; point to the product info
cmpi.b #DecoderKinds.MDUDecoder,\
ProductInfo.DecoderKind(a0) ; see if we have an MDU
bne.s @noMDU ; if not, nothing to enable
movea.l VIA2RBV,a0 ; get the VIA2 or RBV base address
lea vBufB|RvDataB(a0),a0 ; point to the cache register
ori.b #(1<<RvCDis),(a0) ; disable cache
@noMDU
@extCacheDone
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
;----------
;
; WaitForSCSIDevs (_HWPriv Selector 10)
;
; On Entry:
; -> 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 = <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
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 ; <Sys7.1>
lea irIOPNumber(a0),a0 ; <Sys7.1>
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.
;
; Its 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
;
; 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>
LastVec MemDispSelector UnWriteProtectProc ; 7 <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
@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 <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*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>
cmpi.b #EMMU1,MMUType ; is this an Emulated MMU? <SM17>
beq.s @done ; -> Yes, no need to flush anything <SM17>
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 <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*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*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 (_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 <T4>
bhi.s @loop ; keep looping <T4>
cmpi.b #EMMU1,MMUType ; is this an Emulated MMU? <SM17> <SM17>
beq.s @done ; -> Yes, no ATC or Data cache to flush <SM17>
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 <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 (_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
cmpi.b #EMMU1,MMUType ; do we have an EMMU? <SM17>
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 <end>
rts ; <T4>
EndWith
EndProc
;-----
;
; UnWriteProtectProc (_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*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
;
; 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? <SM17>
bhi.s @hasMMU ; -> Yes, do the init!
MOVE.W #@UnimplementedTrap,d0 ; _Unimplemented <SM17>
_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 <SM17>
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>
@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 ; <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 - 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
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? <SM17>
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 ; <SM17>
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 ; <SM17>
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 <end>
ENDIF
@regDone movem.l (sp)+,@saveRegs ; restore registers <T4>
@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. <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
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 ; <SM17>
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 <T4>
_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 <T4>
moveq.l #true32b,d0 ; go to 32-bit mode <T4>
_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 <T3>
IF Supports24Bit THEN ; <SM17>
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 <T4>
bsr.s MMUSetCacheMode ; go whack the page descriptor <T3>
@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) <T4>
; <T3>
; Destroys: None. <start>
;
; 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) <T7>
bset.l #@cacheBit,d1 ; inhibit caching
bclr.l #@cm0bit,d1 ; make it non-serialized <T7>
move.l d1,(a0) ; update page descriptor
bra.s @exit
@enableCaching
clr.l d1 ; clear 68040 mask <T7>
bfextu CacheFlags{31-bCopybackMode:1},d1 ; get current cache mode <T7>
lsl.l #@cm0bit,d1 ; make a mask for a 68040 page descriptor <T7>
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 <T3>
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 <SM17>
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