mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2025-01-19 21:30:04 +00:00
0ba83392d4
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
772 lines
31 KiB
Plaintext
772 lines
31 KiB
Plaintext
;-----------------------------------------------------------------------------------
|
|
;
|
|
; File: GetReal.a
|
|
;
|
|
; Written by: Carl C. Hewitt
|
|
;
|
|
; Copyright: © 1991-1993 by Apple Computer, Inc., all rights reserved.
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <SM10> 10/14/93 pdw (CCH) Split PowerPC EDiskProtect code into seperate routine.
|
|
; Added EDisk support for PDM.
|
|
; <SM9> 6/21/93 kc Fix vm test in GetMMUInfo.
|
|
; <SM8> 6/14/93 SAM Clarified the comments related to the isVMRunnning check in
|
|
; GetMMUInfo.
|
|
; <SM7> 6/14/93 kc Roll in Ludwig.
|
|
; <LW5> 4/23/93 MR Add code to check VMInstalled flag inside VM's globals. This
|
|
; fixes bug #1076279. Reviewed by Clinton Bauder
|
|
; <LW4> 3/25/93 MR Remove GetMMUInfoQ. Instead put a hack inside VM to set
|
|
; VMGlobals($B78) to -1 when calling GetPhysical at VM
|
|
; initialization time.
|
|
; <LW3> 3/16/93 MR Created GetMMUInfoQ which is identical to GetMMUInfo except it
|
|
; does not check for VM. This is an EMERGENCY FIX for the
|
|
; RAMDISK/VM bug that broke Ludwig B3. Will be merged in the
|
|
; future with GetMMUInfo. GetMMUInfoQ is only called by
|
|
; MemoryDispatch routines (i.e. LockMemory,GetPhysical etc).
|
|
; <SM6> 2/23/93 kc Fix bug introduced in last check in.
|
|
; <SM5> 2/20/93 SAM Added LogicalToPhysical code for EMMU machines. Placed a few
|
|
; Supports24Bit's around some things. Removed a trap call or two
|
|
; where possible. If it works at all, it should be faster for
|
|
; everyone.
|
|
; <SM4> 2/5/93 SAM Adjusted PDMs temporary Log2Phys. Removed several Gestalt calls
|
|
; from GetReal. Removed all the 24bit stuff for ROM builds of
|
|
; this file in GetReal.
|
|
; <SM3> 10/18/92 CCH Fixed EDiskProtect to abort if an MMU is not present.
|
|
; <SM2> 5/17/92 kc Roll in Horror sources.
|
|
; <SM0> 5/17/92 kc Fix bug in translate040. We were puting phisical address into the wrong register.
|
|
; <H3> 12/12/91 CCH Changed method of checking for VM in GetMMUInfo, since VM calls
|
|
; GetPageDesc after it sets up it's globals, but before taking
|
|
; over the MMU.
|
|
; <H2> 11/14/91 jmp (CCH) Removed redundant physical-to-logical conversion in
|
|
; translate030 routine. Made EDiskProtect return a result. Also
|
|
; removed Gestalt calls in favor of checks of lo-mem. This is
|
|
; necessary since, in ROM, this routine can get called before
|
|
; Gestalt is.
|
|
; <SM2> 2/12/92 JSM Moved this file to MMU folder, keeping all the old revisions;
|
|
; remove some unused equates.
|
|
; <SM1> 12/31/91 RB first checked in
|
|
; <T10> 7/11/91 CCH Fixed a bug in translate040, and saved D1 in GetReal.
|
|
; <T9> 7/9/91 HJR Added overpatch space
|
|
; <T8> 5/29/91 CCH Moved the call to getMMUInfo to ensure it will always be called
|
|
; in 32-bit mode.
|
|
; <T7> 5/24/91 CCH Added call to enter supervisor mode, if necessary, and flushed
|
|
; the ATC in the EDiskProtect routine.
|
|
; <T6> 5/10/91 CCH Added the EDiskProtect routine.
|
|
; <T5> 4/2/91 djw fixed GetRealProc trashing reg D4. This is crashing A/ROSE on
|
|
; Tim.
|
|
; <T4> 3/18/91 CCH Changed check for Gestalt to check for existence of ExpandMem
|
|
; instead of trap address.
|
|
; <T3> 3/18/91 CCH Fixed to not call Gestalt if it's not around. Also made 040
|
|
; translation routine aware of non logical = physical memory.
|
|
; <T2> 1/24/91 CCH Ensured a logical 32-bit mode address for page descriptors on
|
|
; 030's.
|
|
; <T1> 1/24/91 CCH first checked in
|
|
;
|
|
;----------------------------------------------------------------------------------
|
|
|
|
MACHINE MC68030
|
|
PRINT OFF
|
|
LOAD 'StandardEqu.d'
|
|
INCLUDE 'HardwareEqu.a'
|
|
INCLUDE 'MMUEqu.a'
|
|
INCLUDE 'GestaltEqu.a'
|
|
PRINT ON
|
|
|
|
;----------------
|
|
; Misc Equates
|
|
;----------------
|
|
TTEnable EQU 15 ; transparent translation enable bit
|
|
VMTrap EQU $A05C ; VM trap number
|
|
VMGlobals EQU $0B78 ; VM globals ptr
|
|
VMInstalled equ $0101 ; VMInstalled offset inside VM's globals <LW5>
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; GetReal - Translates a logical address into a physical address. The address
|
|
; translation is performed in the MMU mode at the time of the call.
|
|
;
|
|
; input: a0.l = logical address to be translated
|
|
;
|
|
; output: a0.l = corresponding physical address
|
|
; d0.w = result code
|
|
;
|
|
; destroys: a1-a2
|
|
;----------------------------------------------------------------------------------
|
|
GetRealRegs REG d1-d4 ; <t5> djw <t10> cch
|
|
|
|
GetRealVars RECORD 0,decrement
|
|
oldA6 ds.l 1 ; old A6 value
|
|
theTC ds.l 1 ; TC reg (32-bit for 851/030, 16-bit for 040)
|
|
theSRP ds.l 1 ; root pointer of tables to use
|
|
theCRP ds.l 1 ; limit and flags long for 68851 and 68030 MMUs
|
|
myPhys2Log ds.l 1 ; offset to convert root ptr to logical addr
|
|
initShift ds.b 1 ; initial shift bits (IS)
|
|
levelFour ds.b 1 ; width of fourth level offset field (TID)
|
|
levelThree ds.b 1 ; width of third level offset field (TIC)
|
|
levelTwo ds.b 1 ; width of second level offset field (TIB)
|
|
levelOne ds.b 1 ; width of first level offset field (TIA)
|
|
ds.b 1 ; padding
|
|
GetRealSize equ *
|
|
ENDR
|
|
|
|
GetRealProc PROC EXPORT
|
|
WITH GetRealVars,MemDispGlobals
|
|
EXPORT GetPageDescProc
|
|
EXPORT GetMMUInfo
|
|
EXPORT checkTTRegs
|
|
|
|
; Note: We dont support "GetPageDesc Address"
|
|
cmpi.b #EMMU1,MMUType ; Do we have an Emulated MMU?
|
|
bne.s GetRealAddr ; -> No, OSW (old slow way).
|
|
|
|
; Do Logical to Physical Translation for machines with EMMUs. <SM5> SAM
|
|
|
|
MOVEM.L A2/D1/D2,-(SP) ; Save some regs
|
|
|
|
MOVE.L LockMemCt,A2 ; Get the MemDispatch globals
|
|
MOVE.L mdLog2PageSize(A2),D1 ; Get the Log2 page size
|
|
|
|
MOVE.L A0,D0 ; Copy the log addr
|
|
MOVE.L A0,D2 ; Make another copy (Shitty addressing modes)
|
|
|
|
LSR.L D1,D0 ; Turn the Addr into a logical page number
|
|
MOVE.L D0,A0 ; Put the page number back into A0
|
|
|
|
_nkMMUGetPhysicalPage ; Get the physical page in D0
|
|
|
|
LSL.L D1,D0 ; Turn the Phys page number into an Address
|
|
MOVE.L mdPageSize(A2),D1 ; Get the page size
|
|
SUBQ.L #1,D1 ; Turn the log2 page size into a mask
|
|
AND.L D1,D2 ; Mask out the upper 12 bits of the logical addr
|
|
OR.L D2,D0 ; Combine the phys page & logcal offset to make phys addr
|
|
|
|
MOVE.L D0,A0 ; Put the physical address into A0
|
|
MOVEQ #0,D0 ; Signal no error
|
|
|
|
MOVEM.L (SP)+,A2/D1/D2 ; Restore regs
|
|
* BRA.S @Done ; -> Exit
|
|
RTS
|
|
|
|
GetRealAddr
|
|
move.w #getReal,-(sp) ; indicate we want physical address in a0
|
|
bra.s walkTable ; go walk table <SM6>
|
|
|
|
GetPageDescProc
|
|
move.w #getpageDesc,-(sp) ; indicate we want page descriptor ptr in a0
|
|
|
|
walkTable movem.l GetRealRegs,-(sp) ; save working registers
|
|
link a6,#GetRealSize ; allocate some room for our locals
|
|
cmpi.b #PMMU851,MMUType ; check to see if we have an MMU
|
|
bhs.s @haveAnMMU ; IF we do not have an MMU THEN
|
|
move.w #noMMUErr,d0 ; return an error
|
|
bra.s @exitGetReal ; >>EXIT routine
|
|
@haveAnMMU ; ENDIF
|
|
move.l a0,d2 ; get logical address into d2
|
|
jsr GetMMUInfo ; fill our globals with MMU info
|
|
IF Supports24Bit THEN
|
|
move.b MMU32Bit,-(sp) ; save current MMU mode
|
|
bne.s @in32BitMode ; IF we're in 24-bit mode THEN
|
|
moveq #true32b,d0 ; we want to go to 32 bit addressing
|
|
_SwapMMUMode ; switch the MMU mode
|
|
and.l Lo3Bytes,d2 ; clean up the 24-bit address
|
|
bra.s @doTranslation ; go do the translation
|
|
ENDIF
|
|
@in32BitMode ; ELSE
|
|
jsr checkTTRegs ; check transparent translation regs
|
|
bne.s @doTranslation ; IF we matched a TT register THEN
|
|
move.l d2,a0 ; put the original address into a0
|
|
move.l #0,a2 ; return null for page descriptor address
|
|
moveq #noErr,d3 ; return good status
|
|
bra.s @cleanupGetReal ; >>EXIT with easy translation
|
|
; ENDIF
|
|
@doTranslation ; ENDIF
|
|
cmp.b #PMMU040,MMUType ; check MMU type
|
|
beq.s @trans68040 ; IF we're on a 68030 THEN
|
|
jsr translate030 ; do the translation for an 851/030
|
|
bra.s @cleanupGetReal ; ELSE
|
|
@trans68040 jsr translate040 ; do the translation for a 68040
|
|
; ENDIF
|
|
|
|
;------------
|
|
; a2.w = address of page descriptor, if any
|
|
; d3.w = result code
|
|
; a0.l = physical address if successful
|
|
;------------
|
|
@cleanupGetReal
|
|
IF Supports24Bit THEN ; SM is always in 32 bit mode <SM4>
|
|
move.b (sp)+,d0 ; get original MMU mode
|
|
bne.s @returnResult ; IF we were originally in 24-bit mode THEN
|
|
_SwapMMUMode ; swap back to it
|
|
ENDIF
|
|
@returnResult ; ENDIF
|
|
move.w d3,d0 ; return result in d0
|
|
@exitGetReal
|
|
unlk a6 ; restore registers
|
|
movem.l (sp)+,GetRealRegs ; save working registers
|
|
cmp.w #getpageDesc,(sp)+ ; check for page getPageDesc call
|
|
bne.s @getRealDone ; IF this is the getPageDesc call THEN
|
|
move.l a2,a0 ; return page descriptor pointer
|
|
@getRealDone ; ENDIF
|
|
tst.w d3
|
|
@done rts
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; GetMMUInfo - Fills the global area with MMU-specific table information.
|
|
;
|
|
; input: a6.l = pointer to global area
|
|
;
|
|
; output: none (globals are set up)
|
|
;
|
|
; destroys: a0-a1/d0/d3-d4
|
|
;----------------------------------------------------------------------------------
|
|
ISOffset equ 12 ; bit offset into 851/030 TC of IS field
|
|
pageSizeBit equ 14 ; bit number of page size bit in 68040 TC
|
|
|
|
GetMMUInfo
|
|
cmpi.b #EMMU1,MMUType ; Do we have an Emulated MMU
|
|
beq @VMisOn ; -> Yes, just clear the Log2Phys field & Exit
|
|
cmp.b #PMMU040,MMUType ; check MMU type
|
|
beq.s @get040Info ; IF the MMU is an 851/030 THEN
|
|
pmove crp,theCRP(a6) ; get the 64-bit CRP value
|
|
pmove tc,theTc(a6) ; get TC value
|
|
move.l theTc(a6),d4 ; put TC into d4
|
|
move.l #ISOffset,d3 ; get offset into TC of IS field
|
|
bfextu d4{d3:4},d0 ; get IS value
|
|
move.b d0,initShift(a6) ; save IS value in globals
|
|
add.l #4,d3 ; get offset into TC of TIA field
|
|
bfextu d4{d3:4},d0 ; get TIA value
|
|
move.b d0,levelOne(a6) ; save level one index width in globals
|
|
add.l #4,d3 ; get offset into TC of TIB field
|
|
bfextu d4{d3:4},d0 ; get TIB value
|
|
move.b d0,levelTwo(a6) ; save level one index width in globals
|
|
add.l #4,d3 ; get offset into TC of TIC field
|
|
bfextu d4{d3:4},d0 ; get TIC value
|
|
move.b d0,levelThree(a6) ; save level one index width in globals
|
|
add.l #4,d3 ; get offset into TC of TID field
|
|
bfextu d4{d3:4},d0 ; get TID value
|
|
move.b d0,levelFour(a6) ; save level one index width in globals
|
|
bra.s @gotInfo ; go check for log2Phys offset
|
|
@get040Info ; ELSE
|
|
MACHINE MC68040 ; use 68040 instructions
|
|
movec srp,d0 ; get 68040 srp
|
|
move.l d0,theSRP(a6) ; save the root ptr
|
|
move.l #0,theCRP(a6) ; 68040 only has a 32-bit root pointer <T6>
|
|
move.b #7,levelOne(a6) ; 68040 always uses 7 bits for first level
|
|
move.b #7,levelTwo(a6) ; 68040 always uses 7 bits for second level
|
|
move.b #5,levelThree(a6) ; assume 5 bits for 8k pages in third level
|
|
movec tc,d0 ; get 68040 tc
|
|
move.w d0,theTC(a6) ; store it in globals
|
|
btst #pageSizeBit,d0 ; check which page size we're using
|
|
bne.s @not4kPages ; IF we're using 4k pages
|
|
move.b #6,levelThree(a6) ; use 6 bits for 4k pages in third level
|
|
@not4kPages ; ENDIF
|
|
move.b #0,levelFour(a6) ; 68040 never has a fourth level
|
|
move.b #0,initShift(a6) ; 68040 never has an initial shift
|
|
MACHINE MC68030 ; switch back to 68030 instructions
|
|
@gotInfo ; ENDIF
|
|
move.l phys2log,myPhys2Log(a6) ; get our phys2log translation offset (Assume no vm) <SM4>
|
|
|
|
IF not forROM THEN ; Supermario is always 32bit capable <SM4>
|
|
cmp.l #-1,ExpandMem ; is gestalt unimplemented? <T3>
|
|
beq.s @done ; IF gestalt is implemented THEN <T3>
|
|
move.l #gestaltAddressingModeAttr,d0 ; we need to find out 32-bit cleanliness
|
|
_Gestalt ; call Gestalt
|
|
tst.w d0 ; check for errors
|
|
bne.s @VMisOn ; >>EXIT on error
|
|
move.l a0,d0 ; get response in d0
|
|
btst #gestalt32BitCapable,d0 ; check if phys2Log globals exists
|
|
beq.s @VMisOn ; >>EXIT on error
|
|
ENDIF
|
|
|
|
; Some history: Since GetMMUInfo cannot be making lengthy Gestalt calls to determine if VM is on
|
|
; we would (previously) test the lomem where VM puts its globals to see it it had been initialized.
|
|
; A problem arises when VM has saved its globals ptr in VMGlobals but has not yet whacked the MMU
|
|
; tables and someone (VM) calls GetPhysical. An additional flag inside the VMGlobals has been added
|
|
; that is set at the very end of VMs initalization. We now check it to determine if the MMU world
|
|
; has been changed on us. <SM8> SAM
|
|
;
|
|
|
|
; Determine if VM is installed an running <LW5>
|
|
|
|
move.l VMGlobals,d0 ; Has VM installed its globals ptr (is it installed?) <SM4>
|
|
ble.s @done ; -> No. Leave with Phys2Log offset set.
|
|
|
|
move.l d0,a0 ; Globals in. Is VM actually running yet?
|
|
tst.b VMInstalled(a0) ; VM's Gestalt inited? <LW5>
|
|
beq.s @done ; -> Nope, leave the offset alone <LW5>
|
|
|
|
@VMisOn clr.l myPhys2log(a6) ; VM is on. No phys2log translation
|
|
@done rts ; return
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; checkTTRegs - Checks a logical address against the MMU's transparent
|
|
; translation registers. This routine assumes that the
|
|
; instruction and data TT registers contain identical information
|
|
; on the 68040.
|
|
;
|
|
; input: d2.l = logical address to check
|
|
;
|
|
; output: ccr.z is set if the address would be transparently translated
|
|
;
|
|
; destroys: d0-d1/d3-d4
|
|
;----------------------------------------------------------------------------------
|
|
checkTTRegs
|
|
cmp.b #PMMU040,MMUType ; check MMU type
|
|
beq.s @get040Regs ; IF the MMU is an 851/030 THEN
|
|
subq #4,sp ; create room on stack for tt values
|
|
pmove tt0,(sp) ; get tt0 value
|
|
move.l (sp),d0 ; store in d0
|
|
pmove tt1,(sp) ; get tt1 value
|
|
move.l (sp),d1 ; store in d1
|
|
addq #4,sp ; restore stack
|
|
bra.s @checkTTs ; continue with check
|
|
@get040Regs ; ELSE
|
|
MACHINE MC68040 ; use 68040 instructions
|
|
movec dtt0,d0 ; store tt0 in d0
|
|
movec dtt1,d1 ; store tt1 in d1
|
|
MACHINE MC68030 ; switch back to 68030
|
|
@checkTTs ; ENDIF
|
|
btst #TTEnable,d0 ; see if tt0 is on
|
|
beq.s @checkTT1 ; IF tt0 is enabled THEN
|
|
move.l d2,d3 ; make a copy of the logical address
|
|
eor.l d0,d3 ; exclusive OR to leave ones in different bits
|
|
rol.l #8,d3 ; move upper 8-bits into low byte
|
|
swap d0 ; put logical address mask in low byte
|
|
not.b d0 ; invert logical address mask
|
|
and.b d0,d3 ; isolate bits we care about
|
|
beq.s @checkDone ; >>EXIT if we found a match
|
|
@checkTT1 ; ENDIF
|
|
btst #TTEnable,d1 ; see if tt1 is on
|
|
beq.s @notEnabled ; IF tt1 is enabled THEN
|
|
move.l d2,d3 ; make a copy of the logical address
|
|
eor.l d1,d3 ; exclusive OR to leave ones in different bits
|
|
rol.l #8,d3 ; move upper 8-bits into low byte
|
|
swap d1 ; put logical address mask in low byte
|
|
not.b d1 ; invert logical address mask
|
|
and.b d1,d3 ; isolate bits we care about
|
|
bra.s @checkDone ; go exit
|
|
; ELSE
|
|
@notEnabled andi #$fffb,sr ; clear zero bit
|
|
@checkDone ; ENDIF
|
|
rts
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; translate030 - Translates a logical address to its corresponding physical
|
|
; address on a 68030.
|
|
;
|
|
; input: a6.l = pointer to globals
|
|
; d2.l = logical address to translate
|
|
;
|
|
; output: a0.l = physical address
|
|
; a2.l = ptr to page descriptor for translated address
|
|
; d3.w = result code
|
|
;
|
|
; destroys: d0-d1
|
|
;----------------------------------------------------------------------------------
|
|
tcSRE EQU 25 ; SRP Enable in TC for 851/030
|
|
tcFCL EQU 24 ; Function code Lookup in TC for 851/030
|
|
tcEnable030 EQU 31 ; MMU enable bit in TC on 851/030
|
|
pageDesc EQU 1 ; page descriptor
|
|
valid4 EQU 2 ; valid 4 byte
|
|
valid8 EQU 3 ; valid 8 byte
|
|
|
|
transRegs REG d4-d7
|
|
|
|
translate030
|
|
movem.l transRegs,-(sp) ; save working registers
|
|
move.l theSRP(a6),d1 ; get root ptr
|
|
move.l theCRP(a6),d7 ; get limit in d7
|
|
move.b d7,d3 ; get descriptor type in d3
|
|
and.b #3,d3 ; isolate it
|
|
move.l theTC(a6),d0 ; get a copy of the TC in d0
|
|
btst #tcSRE,d0 ; check for SRP mode
|
|
bne @paramErr ; >>EXIT if on
|
|
btst #tcFCL,d0 ; check for FCL mode
|
|
bne @paramErr ; >>EXIT if on
|
|
btst #tcEnable030,d0 ; check if MMU is on
|
|
bne.s @startTranslate ; IF MMU is off THEN
|
|
move.l d2,a1 ; return logical address unchanged
|
|
clr.l d1 ; return null for page descriptor addr
|
|
moveq #noErr,d3 ; return good status
|
|
bra.s @xlatDone ; >>EXIT with physical address
|
|
@startTranslate ; ENDIF
|
|
clr.l d4 ; clear offset into logical address
|
|
move.b initShift(a6),d4 ; add in initial shift
|
|
lea levelOne(a6),a1 ; point a1 at width of first field
|
|
clr.l d5 ; get a clear longword
|
|
move.b (a1)+,d5 ; get width of next field
|
|
|
|
;-----------------
|
|
; a1.l = pointer to width of next field
|
|
; d1.l = current descriptor entry
|
|
; d2.l = logical address to translate
|
|
; d3.b = descriptor type of current descriptor
|
|
; d4.l = offset into logical address of index field
|
|
; d5.l = width of index field
|
|
; d7.l = limit of current descriptor
|
|
;-----------------
|
|
@xlatLoop ; LOOP (to walk an MMU table)
|
|
cmp.b #pageDesc,d3 ; is this a page descriptor?
|
|
beq.s @getPage ; >>BREAK on page descriptor
|
|
bfextu d2{d4:d5},d6 ; get index into next table
|
|
tst.l d7 ; is there a limit for this table?
|
|
beq.s @noLimit ; IF there is a limit THEN
|
|
jsr checkLimit ; check the index against the limit
|
|
bcs.s @paramErr ; >>EXIT on a limit overflow
|
|
@noLimit ; ENDIF
|
|
and.l #$fffffff0,d1 ; remove unused bottom byte
|
|
cmp.b #valid4,d3 ; check for 4-byte descriptor
|
|
bne.s @not4byte ; IF this is a four byte descriptor THEN
|
|
add.l myPhys2Log(a6),d1 ; convert current descriptor to logical addr
|
|
move.l d1,a2 ; get pointer to next table
|
|
lsl.w #2,d6 ; multiple index by four
|
|
add.l d6,a2 ; get address of next descriptor
|
|
move.l (a2),d1 ; get next descriptor
|
|
clr.l d7 ; no limit on this descriptor
|
|
move.b d1,d3 ; get a copy of descriptor
|
|
bra.s @doNext ; look at next descriptor
|
|
@not4byte ; ELSE
|
|
cmp.b #valid8,d3 ; check for 8-byte descriptor
|
|
bne.s @paramErr ; >>EXITLOOP on invalid descriptors
|
|
add.l myPhys2Log(a6),d1 ; convert current descriptor to logical addr
|
|
move.l d1,a2 ; get pointer to next table
|
|
lsl.w #3,d6 ; multiple index by eight
|
|
add.l d6,a2 ; get address of next descriptor
|
|
move.l 4(a2),d1 ; get lower word of next descriptor
|
|
move.l 0(a2),d7 ; get upper word of next descriptor
|
|
move.b d7,d3 ; get a copy of descriptor
|
|
|
|
@doNext ; ENDIF
|
|
add.l d5,d4 ; update d4 to contain number of bytes decoded
|
|
move.b (a1)+,d5 ; get width of next field
|
|
and.b #3,d3 ; isolate descriptor type
|
|
bra.s @xlatLoop ; ENDLOOP
|
|
@getPage
|
|
move.l #32,d5 ; total number of bits in address
|
|
sub.l d4,d5 ; get number of bits not yet decoded
|
|
bfextu d1{0:d4},d0 ; get top bits of address of physical page
|
|
bfextu d2{d4:d5},d6 ; get offset into physical page
|
|
lsl.l d5,d0 ; make a base address out of it
|
|
add.l d6,d0 ; get physical address
|
|
move.l d0,a0 ; put address into a1
|
|
moveq #noErr,d3 ; return no error
|
|
@xlatDone
|
|
movem.l (sp)+,transRegs ; restore registers
|
|
rts
|
|
|
|
@paramErr
|
|
move.w #paramErr,d3
|
|
bra.s @xlatDone
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; translate040 - Translates a logical address to its corresponding physical
|
|
; address on a 68040.
|
|
;
|
|
; input: a6.l = pointer to globals
|
|
; d2.l = logical address to translate
|
|
;
|
|
; output: a0.l = physical address
|
|
; a2.l = ptr to page descriptor for translated address
|
|
; d3.w = result code
|
|
;
|
|
; destroys: d0-d1
|
|
;----------------------------------------------------------------------------------
|
|
tcEnable040 EQU 15 ; MMU enable bit in TC on 68040
|
|
UDTResident EQU 1 ; UDT resident bit in table descriptor
|
|
PDTResident EQU 1 ; PDT field value for a resident page
|
|
PDTIndirect EQU 2 ; PDT field value for an indirect page desc
|
|
|
|
translate040
|
|
movem.l transRegs,-(sp) ; save working registers
|
|
move.l theSRP(a6),d1 ; get root ptr in a2
|
|
move.w theTC(a6),d0 ; get a copy of the TC in d0
|
|
btst #tcEnable040,d0 ; check if MMU is on
|
|
bne.s @startTranslate ; IF MMU is off THEN
|
|
move.l d2,a0 ; return logical address unchanged <SM0>
|
|
clr.l d1 ; return null for page descriptor addr
|
|
moveq #noErr,d3 ; return good status
|
|
bra.s @xlatDone ; >>EXIT with physical address
|
|
; ENDIF
|
|
@startTranslate
|
|
clr.l d4 ; clear offset into logical address
|
|
clr.w d3 ; clear level counter
|
|
clr.l d5 ; get a clear longword
|
|
lea levelOne(a6),a1 ; init pointer to field widths
|
|
;-----------------
|
|
; a1.l = pointer to field width info
|
|
; d1.l = current descriptor entry
|
|
; d2.l = logical address to translate
|
|
; d3.w = level counter
|
|
; d4.l = offset into logical address of index field
|
|
;-----------------
|
|
@walkLoop ; LOOP (to walk 68040 table)
|
|
move.b (a1)+,d5 ; get width of first index field
|
|
move.l #(32-2),d0 ; get total bits in descriptor (table pointer/4)
|
|
sub.l d5,d0 ; get number of significant bits in table ptr
|
|
bfextu d1{0:d0},d1 ; get pointer to next table
|
|
lsl.l d5,d1 ; almost make a base address out of it
|
|
lsl.l #2,d1 ; make a base address out of it
|
|
bfextu d2{d4:d5},d6 ; get index into next table
|
|
lsl.w #2,d6 ; multiple index by four
|
|
add.l d6,d1 ; get address of next descriptor
|
|
add.l myPhys2Log(a6),d1 ; convert pointer to logical addr <T3>
|
|
move.l d1,a2 ; put into an address register
|
|
move.l (a2),d1 ; get next descriptor
|
|
cmp.w #2,d3 ; is this the third level
|
|
beq.s @getPage ; >>EXITLOOP if so
|
|
btst #UDTResident,d1 ; is it resident?
|
|
beq.s @paramErr ; >>EXIT if not
|
|
add.l d5,d4 ; update d4 to contain number of bytes decoded
|
|
add.w #1,d3 ; bump level count
|
|
bra.s @walkLoop ; ENDLOOP
|
|
@getPage
|
|
move.b d1,d0 ; get a copy of the page descriptor
|
|
and.b #3,d0 ; isolate PDT field
|
|
cmp.b #PDTResident,d0 ; is this page resident?
|
|
beq.s @residentPage ; IF it is not resident THEN
|
|
cmp.b #PDTIndirect,d0 ; check for indirect pointer
|
|
bne.s @paramErr ; >>EXIT if invalid
|
|
and.l #$fffffffc,d1 ; clear PDT field from indirect descriptor
|
|
add.l myPhys2Log(a6),d1 ; convert pointer to logical addr <T3>
|
|
move.l d1,a2 ; get address of page descriptor
|
|
move.l (a2),d1 ; get page descriptor
|
|
@residentPage ; ENDIF
|
|
add.l d5,d4 ; update d4 to contain number of bytes decoded <t10> cch
|
|
move.l #32,d5 ; total number of bits in address
|
|
sub.l d4,d5 ; get number of bits not yet decoded
|
|
bfextu d1{0:d4},d0 ; get address of physical page
|
|
bfextu d2{d4:d5},d6 ; get offset into physical page
|
|
lsl.l d5,d0 ; make a base address out of it
|
|
add.l d6,d0 ; get physical address
|
|
move.l d0,a0 ; put address into a0
|
|
moveq #noErr,d3 ; return no error
|
|
@xlatDone
|
|
movem.l (sp)+,transRegs ; restore registers
|
|
rts
|
|
|
|
@paramErr
|
|
move.w #paramErr,d3
|
|
bra.s @xlatDone
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; checkLimit - Checks an index against a limit for an 8-byte descriptor.
|
|
;
|
|
; input: d6.l = index to be checked
|
|
; d7.l = upper word of descriptor
|
|
;
|
|
; output: ccr.c set on invalid index
|
|
; ccr.c clear on valid index
|
|
;
|
|
; destroys: d7
|
|
;----------------------------------------------------------------------------------
|
|
|
|
checkLimit swap d7 ; get limit into low word
|
|
btst #15,d7 ; check type of limit
|
|
bne.s @lower ; IF it is an upper limit THEN
|
|
cmp.w d6,d7 ; compare upper limit
|
|
bra.s @limitExit ; ELSE
|
|
@lower and.w #$7fff,d7 ; remove l/u bit
|
|
cmp.w d7,d6 ; compare lower limit
|
|
@limitExit ; ENDIF
|
|
rts
|
|
|
|
|
|
ENDWITH
|
|
ENDP
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; EDiskProtectPPC - Protects or unprotects the EDisk as specified for PowerPC.
|
|
;
|
|
; input: d0[15:0] = HwPriv selector #8
|
|
; d0[16] = set to protect specified area, clear to unprotect it
|
|
; a0.l = 32-bit base address of area to protect/unprotect
|
|
; a1.l = length of area to protext/unprotect
|
|
;
|
|
; output: a0.l = pointer to the 1st-level table descriptor for the eDisk
|
|
; d0.w = result code
|
|
;
|
|
; destroys: d1/a1
|
|
;----------------------------------------------------------------------------------
|
|
EMMUWrProtBit EQU 16
|
|
EMMUWrProtMask EQU $00010000
|
|
wrBit EQU 2
|
|
|
|
ProtectRegsPPC REG d2-d4
|
|
|
|
EDiskProtectPPC PROC EXPORT
|
|
WITH GetRealVars
|
|
|
|
cmp.b #EMMU1,MMUType ; check to see if we have a PowerPC MMU
|
|
bne @paramErr ; >>EXIT if not
|
|
|
|
movem.l ProtectRegsPPC,-(sp) ; save working registers
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; PowerPC EDisk Write Protect Code
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
move.l #12,d4 ; number of bits in page size
|
|
move.l a1,d2 ; get byte length in d2
|
|
lsr.l d4,d2 ; convert byte length to page count
|
|
addq.l #1,d2 ; always round up by one
|
|
|
|
move.l a0,d1 ; get the base address in d1
|
|
lsr.l d4,d1 ; convert base address to page number
|
|
|
|
move.l d0,d3 ; get a copy of the protect bit into d3
|
|
and.l #EMMUWrProtMask,d3 ; isolate write protect flag
|
|
move.l #EMMUWrProtBit-wrBit,d4 ; number of bits to shift protect bit
|
|
lsr.l d4,d3 ; shift the bit into place so we can OR.L it in
|
|
|
|
@protectLoop ; LOOP (to protect/unprotect pages in Edisk)
|
|
move.l d1,a0 ; Put the page number in A0
|
|
_nkGetPTEntryGivenPage ; Get the 030+ PTE from the nk
|
|
|
|
bclr #wrBit,d0 ; Clear the W bit
|
|
or.l d3,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
|
|
|
|
addq.l #1,d1 ; bump the page number by 1
|
|
dbra d2,@protectLoop ; END
|
|
|
|
moveq #noErr,d0 ; return successful
|
|
movem.l (sp)+,ProtectRegsPPC ; restore working registers
|
|
@return rts
|
|
|
|
@paramErr move.w #paramErr,d0 ; return paramErr
|
|
bra.s @return
|
|
|
|
ENDWITH
|
|
|
|
ENDP
|
|
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; EDiskProtect - Protects or unprotects the EDisk as specified.
|
|
;
|
|
; NOTE: This algorithm assumes that the Edisk space is the only space
|
|
; mapped by it's 1st level descriptor.
|
|
;
|
|
; input: d0.w = HwPriv selector #8
|
|
; a0.l = 32-bit base address of EDisk
|
|
; a1.w = flag to protect or unprotect Edisk (1=protect)
|
|
;
|
|
; output: a0.l = pointer to the 1st-level table descriptor for the eDisk
|
|
; d0.w = result code
|
|
;
|
|
; destroys: d1/a1
|
|
;----------------------------------------------------------------------------------
|
|
ProtectRegs REG d2-d4/a2
|
|
|
|
EDiskProtect PROC EXPORT
|
|
IMPORT GetMMUInfo
|
|
IMPORT checkTTRegs
|
|
WITH GetRealVars
|
|
|
|
cmp.b #PMMU851,MMUType ; check to see if we have an MMU <SM3>
|
|
blo @bailNoMMU ; >>EXIT if not <SM3>
|
|
|
|
movem.l ProtectRegs,-(sp) ; save working registers
|
|
link a6,#GetRealSize ; allocate some room for our locals
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; 68K EDisk Write Protect Code
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
@noEMMU move.l a0,d2 ; get base address of Edisk
|
|
move.w a1,a2 ; save protect flag in a2
|
|
|
|
Move SR,D0 ; Get and save the SR. <T7>
|
|
Btst #13,D0 ; Are we in Supervisor mode?
|
|
Bne.s @noVM ; Yes? Then don't call _EnterSupervisorMode.
|
|
_EnterSupervisorMode ; Must be in supervisor mode (SR returned in D0).
|
|
@noVM
|
|
move.w d0,-(sp) ; save status register value <T7>
|
|
IF Supports24Bit THEN
|
|
move.b MMU32Bit,-(sp) ; save current MMU mode
|
|
bne.s @in32BitMode ; IF we're in 24-bit mode THEN
|
|
moveq #true32b,d0 ; we want to go to 32 bit addressing
|
|
_SwapMMUMode ; switch the MMU mode
|
|
bra.s @doTranslation ; go do the translation
|
|
@in32BitMode ; ELSE
|
|
ENDIF
|
|
jsr checkTTRegs ; check transparent translation regs
|
|
bne.s @doTranslation ; IF we matched a TT register THEN
|
|
move.l d2,a0 ; put the original address into a0
|
|
moveq #paramErr,d3 ; return bad status
|
|
bra.s @cleanup ; >>EXIT with easy translation
|
|
; ENDIF
|
|
@doTranslation ; ENDIF
|
|
jsr GetMMUInfo ; set up globals <T8>
|
|
clr.l d0 ; clear starting bit value
|
|
clr.l d1 ; clear bit field length
|
|
move.b initShift(a6),d0 ; get bit to start at, with initial shift, if any
|
|
move.b levelOne(a6),d1 ; get bit field length
|
|
bfextu d2{d0:d1},d0 ; get index into 1st-level table
|
|
lsl.l #2,d0 ; convert to a 4-byte entry pointer index
|
|
btst.b #0,theCRP+3(a6) ; is this an 8-byte table?
|
|
beq.s @is4Byte ; IF this is a 8-byte entry table THEN
|
|
lsl.l #1,d0 ; convert to an 8-byte entry pointer index
|
|
@is4Byte ; ENDIF
|
|
add.l theSRP(a6),d0 ; get the physical address of the 1st-level entry
|
|
add.l myPhys2Log(a6),d0 ; convert to a logical address
|
|
move.l d0,a0 ; save in a0
|
|
|
|
;------------
|
|
; Change RAM disk protection
|
|
;------------
|
|
|
|
move.w #noErr,d3 ; return good result if we get here. <Z11><H2>
|
|
bset #writeProtectBit,3(a0) ; set the write-protect bit
|
|
tst.w a2 ; check if protect flag is set
|
|
bne.s @protect ; IF we want to unprotect THEN
|
|
bclr #writeProtectBit,3(a0) ; clear the write-protect bit
|
|
@protect ; ENDIF
|
|
cmp.b #cpu68040,CPUFlag ; check for processor type <T7>
|
|
bne.s @not040 ; IF on a 68040 THEN
|
|
MACHINE MC68040 ;
|
|
pflusha ; flush the ATC regs
|
|
bra.s @cleanup ; ELSE
|
|
MACHINE MC68030 ;
|
|
@not040 jsr ([jCacheFlush]) ; flush caches since they're logical <Z11><H2>
|
|
pflusha ; flush the ATC regs
|
|
; ENDIF <T7>
|
|
|
|
;------------
|
|
; d3.w = result code
|
|
; a0.l = physical address if successful
|
|
;------------
|
|
@cleanup
|
|
IF Supports24Bit THEN
|
|
move.b (sp)+,d0 ; get original MMU mode
|
|
bne.s @skipMMUSwap ; IF we were originally in 24-bit mode THEN
|
|
_SwapMMUMode ; swap back to it
|
|
@skipMMUSwap ; ENDIF
|
|
ENDIF
|
|
move.w (sp)+,d0 ; get status register value <T7>
|
|
move d0,sr ; restore status register <T7>
|
|
move.w d3,d0 ; return result in d0
|
|
@return unlk a6
|
|
movem.l (sp)+,ProtectRegs ; restore working registers
|
|
@bailNoMMU
|
|
rts
|
|
|
|
ENDWITH
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; That's all folks.
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
|
|
|
|
ENDP
|
|
|
|
|
|
END
|