/* File: MixedMode.r Contains: Mixed Mode Manager Interfaces. Version: Technology: Mac OS 8 Release: QuickTime 4.0 Copyright: © 1992-1998 by Apple Computer, Inc., all rights reserved. Bugs?: For bug reports, consult the following page on the World Wide Web: http://developer.apple.com/bugreporter/ */ #ifndef __MIXEDMODE_R__ #define __MIXEDMODE_R__ #ifndef __CONDITIONALMACROS_R__ #include "ConditionalMacros.r" #endif #define kRoutineDescriptorVersion 7 #define _MixedModeMagic 0xAAFE #define kCurrentMixedModeStateRecord 1 #define kPascalStackBased 0 #define kCStackBased 1 #define kRegisterBased 2 #define kD0DispatchedPascalStackBased 8 #define kD1DispatchedPascalStackBased 12 #define kD0DispatchedCStackBased 9 #define kStackDispatchedPascalStackBased 14 #define kThinkCStackBased 5 #define kM68kISA 0 #define kPowerPCISA 1 #define kOld68kRTA 0x00 #define kPowerPCRTA 0x00 #define kCFM68kRTA 0x10 #define kRegisterD0 0 #define kRegisterD1 1 #define kRegisterD2 2 #define kRegisterD3 3 #define kRegisterD4 8 #define kRegisterD5 9 #define kRegisterD6 10 #define kRegisterD7 11 #define kRegisterA0 4 #define kRegisterA1 5 #define kRegisterA2 6 #define kRegisterA3 7 #define kRegisterA4 12 #define kRegisterA5 13 #define kRegisterA6 14 /* A7 is the same as the PowerPC SP */ #define kCCRegisterCBit 16 #define kCCRegisterVBit 17 #define kCCRegisterZBit 18 #define kCCRegisterNBit 19 #define kCCRegisterXBit 20 #define kNoByteCode 0 #define kOneByteCode 1 #define kTwoByteCode 2 #define kFourByteCode 3 #define kProcDescriptorIsAbsolute 0x00 #define kProcDescriptorIsRelative 0x01 #define kFragmentIsPrepared 0x00 #define kFragmentNeedsPreparing 0x02 #define kUseCurrentISA 0x00 #define kUseNativeISA 0x04 #define kPassSelector 0x00 #define kDontPassSelector 0x08 #define kRoutineIsNotDispatchedDefaultRoutine 0x00 #define kRoutineIsDispatchedDefaultRoutine 0x10 #define kProcDescriptorIsProcPtr 0x00 #define kProcDescriptorIsIndex 0x20 #define kSelectorsAreNotIndexable 0x00 #define kSelectorsAreIndexable 0x01 /* Calling Convention Offsets */ #define kCallingConventionWidth 4 #define kCallingConventionPhase 0 #define kCallingConventionMask 0x0F /* Result Offsets */ #define kResultSizeWidth 2 #define kResultSizePhase 4 #define kResultSizeMask 0x30 /* Parameter offsets & widths */ #define kStackParameterWidth 2 #define kStackParameterPhase 6 #define kStackParameterMask 0xFFFFFFC0 /* Register Result Location offsets & widths */ #define kRegisterResultLocationWidth 5 #define kRegisterResultLocationPhase 6 /* Register Parameter offsets & widths */ #define kRegisterParameterWidth 5 #define kRegisterParameterPhase 11 #define kRegisterParameterMask 0x7FFFF800 #define kRegisterParameterSizePhase 0 #define kRegisterParameterSizeWidth 2 #define kRegisterParameterWhichPhase 2 #define kRegisterParameterWhichWidth 3 /* Dispatched Stack Routine Selector offsets & widths */ #define kDispatchedSelectorSizeWidth 2 #define kDispatchedSelectorSizePhase 6 /* Dispatched Stack Routine Parameter offsets */ #define kDispatchedParameterPhase 8 /* Special Case offsets & widths */ #define kSpecialCaseSelectorWidth 6 #define kSpecialCaseSelectorPhase 4 #define kSpecialCaseSelectorMask 0x03F0 #define kSpecialCase 0x000F /* (CallingConventionType) */ /* all of the special cases enumerated. The selector field is 6 bits wide */ #define kSpecialCaseHighHook 0 #define kSpecialCaseCaretHook 0 /* same as kSpecialCaseHighHook */ #define kSpecialCaseEOLHook 1 #define kSpecialCaseWidthHook 2 #define kSpecialCaseTextWidthHook 2 /* same as kSpecialCaseWidthHook */ #define kSpecialCaseNWidthHook 3 #define kSpecialCaseDrawHook 4 #define kSpecialCaseHitTestHook 5 #define kSpecialCaseTEFindWord 6 #define kSpecialCaseProtocolHandler 7 #define kSpecialCaseSocketListener 8 #define kSpecialCaseTERecalc 9 #define kSpecialCaseTEDoText 10 #define kSpecialCaseGNEFilterProc 11 #define kSpecialCaseMBarHook 12 #define GoMixedModeTrapType unsigned hex integer #define VersionType byte #define SelectorsAreIndexableType boolean #define Reserved1Type fill long #define Reserved2Type fill byte #define SelectorInfoType hex byte #define RoutineCountType integer #define ProcInfoType binary longint #define Reserved3Type fill byte #define ISAType byte #define ProcDescriptorIsRelativeType boolean #define FragmentNeedsPreparingType boolean #define UseNativeISAType boolean #define DontPassSelectorType boolean #define RoutineIsDispatchedDefaultType boolean #define ProcDescriptorType longint #define Reserved4Type fill long #define SelectorType longint /* Use the 'rdes' template to define a Ònative resourceÓ which starts with a routine descriptor. Such resources contain just PowerPC code. Note that such resources can only be executed on PowerPC machines. Executing them on a 68K machine will result in a crash. To create a Ònative resourceÓ, you should first build the executable code just as you normally do, placing the code in a PEF container in the data fork of a file. You would then use something like the following: #include "MixedMode.r" type 'BDef' as 'rdes'; resource 'BDef' (1) { $1, // ProcInfo $$Read("MyCode.pef") // Specify name of PEF file }; */ type 'rdes' { Top: /* Routine Descriptor */ GoMixedModeTrapType = _MixedModeMagic; VersionType = kRoutineDescriptorVersion; fill bit [7]; SelectorsAreIndexableType = FALSE; Reserved1Type; Reserved2Type; SelectorInfoType = 0; RoutineCountType = 0; /* Routine Record */ ProcInfoType; Reserved3Type; ISAType = kPowerPCISA; fill bit [11]; RoutineIsDispatchedDefaultType = FALSE; DontPassSelectorType = FALSE; UseNativeISAType = TRUE; FragmentNeedsPreparingType = TRUE; ProcDescriptorIsRelativeType = TRUE; ProcDescriptorType = (BeginningOfPowerPCCode-Top) / 8; Reserved4Type; SelectorType = 0; Align LONG; BeginningOfPowerPCCode: hex string; // The PEF container starts here }; /* Use the 'fdes' template to define a Òfat resourceÓ which starts with a routine descriptor and contains both 68K and PowerPC code. Note that such resources can only be executed on a machine with MixedMode installed. To create Òsafe fat resourcesÓ which will run on all machines, use the 'sdes' template defined below. To create a Òfat resourceÓ, you should first build the executable code just as you normally do, placing the PowerPC code in a PEF container in the data fork of a file. The 68k executable would be built as a stand-alone code resource, as has historically been done. You would then use something like the following: #include "MixedMode.r" type 'BDef' as 'fdes'; resource 'BDef' (1) { $1, // 68K ProcInfo $1, // PowerPC ProcInfo $$Resource("My68KCode.rsrc", 'oCod', 128), // Specify file name, type and ID of resource // containing 68k code $$Read("MyPPCCode.pef") // Specify file containing PPC code in PEF format }; */ /* Fat Routines */ type 'fdes' { Top: /* Routine Descriptor */ GoMixedModeTrapType = _MixedModeMagic; VersionType = kRoutineDescriptorVersion; fill bit [7]; SelectorsAreIndexableType = FALSE; Reserved1Type; Reserved2Type; SelectorInfoType = 0; RoutineCountType = 1; /* 68k Routine Record */ ProcInfoType; Reserved3Type; ISAType = kM68kISA; fill bit [11]; RoutineIsDispatchedDefaultType = FALSE; DontPassSelectorType = FALSE; UseNativeISAType = TRUE; FragmentNeedsPreparingType = FALSE; ProcDescriptorIsRelativeType = TRUE; ProcDescriptorType = (BeginningOf68KCode-Top) / 8; Reserved4Type; SelectorType = 0; /* PowerPC Routine Record 1 */ ProcInfoType; Reserved3Type; ISAType = kPowerPCISA; fill bit [11]; RoutineIsDispatchedDefaultType = FALSE; DontPassSelectorType = FALSE; UseNativeISAType = TRUE; FragmentNeedsPreparingType = TRUE; ProcDescriptorIsRelativeType = TRUE; ProcDescriptorType = (BeginningOfPowerPCCode-Top) / 8; Reserved4Type; SelectorType = 0; Align LONG; BeginningOf68kCode: hex string; // The code starts here Align LONG; BeginningOfPowerPCCode: hex string; // The PEF container starts here }; /* Use the 'sdes' template to define a Òsafe fat resourceÓ which contains both 68K and PowerPC code. A safe fat resource starts with 68K code which is executed the first time the resource is called. This code determines if MixedMode is present. If so, a routine descriptor is moved to the beginning of the resource. If not, a branch instruction to the 68K portion of the code is placed at the beginning of the resource. Therefore, the first time the resource is executed, there is some overhead incurred. However, subsequent calls will be fast. Note: This template cannot currently be used for resources containing code with register-based calling conventions because the 68K code at the beginning of the resource uses D0, A0, and A1. To create a Òsafe fat resourceÓ, you should first build the executable code just as you normally do, placing the PowerPC code in a PEF container in the data fork of a file. The 68k executable would be built as a stand-alone code resource, as has historically been done. You would then use something like the following: #include "MixedMode.r" type 'BDef' as 'sdes'; resource 'BDef' (1) { $1, // 68K ProcInfo $1, // PowerPC ProcInfo $$Resource("My68KCode.rsrc", 'oCod', 128), // Specify file name, type and ID of resource // containing 68k code $$Read("MyPPCCode.pef") // Specify file containing PPC code in PEF format }; */ /* Safe Fat Resources */ type 'sdes' { Top: hex string = $"4E56 FFF0" // SafeFatRsrc LINK A6, #-sysEnv1Size ; Allocate a sysEnvRec $"41EE FFF0" // LEA -sysEnv1Size(A6), A0 $"7001" // MOVEQ #1, D0 ; On 6.X, Gestalt not be implemented... $"A090" // _SysEnvirons $"4A40" // TST.W D0 $"6640" // BNE.S Install68K_60 ; if call fails, load up the 68K without FlushCache $"0C68 0700 0004" // CMPI #$0700,systemVersion(A0) $"6D38" // BLT.S Install68K_60 ; if pre- 7.0, assume no cache $"303C A89F" // MOVE.W #$A89F, D0 ; We have larger trap tables. Is MixedMode installed? $"A746" // _GetToolBoxTrapAddress ; Leave _Unimplemented on the top of the stack... $"2F08" // MOVE.L A0, -(SP) ; Unlk will clean this up $"303C AAFE" // MOVE.W #$AAFE, D0 $"A746" // _GetToolBoxTrapAddress $"B1D7" // CMPA.L (SP), A0 $"663E" // BNE.S InstallPPCCode $"41FA FFD4" // Install68K_70 LEA SafeFatRsrc, A0 $"30FC 6000" // MOVE.W #$6000, (A0)+ ; Generate a BRA instruction $"43FA 0044" // LEA FatRD, A1 $"2029 0014" // MOVE.L 20(A1), D0 ; Get 68K code offset $"5580" // SUBQ.L #2, D0 $"3080" // MOVE.W D0, (A0) ; Fill in the second word of the BRA $"303C A198" // MOVE.W #$A198, D0 ; Is _HWPriv implemented? $"A346" // _GetOSTrapAddress $"B1D7" // CMPA.L (SP), A0 $"4E5E" // UNLK A6 $"67B6" // BEQ.S SafeFatRsrc $"7001 A198" // _FlushInstructionCache $"60B0" // BRA.S SafeFatRsrc $"4E5E" // Install68K_60 UNLK A6 ; Old machine, FlushCache not supported $"41FA FFAC" // LEA SafeFatRsrc, A0 $"30FC 6000" // MOVE.W #$6000, (A0)+ ; Generate a BRA instruction $"43FA 001C" // LEA FatRD, A1 $"2029 0014" // MOVE.L 20(A1), D0 ; Get 68K code offset $"5580" // SUBQ.L #2, D0 $"3080" // MOVE.W D0, (A0) ; Fill in the second word of the BRA $"6098" // BRA.S SafeFatRsrc $"4E5E" // InstallPPCCode UNLK A6 $"43FA FF94" // LEA SafeFatRsrc, A1 $"41FA 0008" // LEA FatRD, A0 $"7034" // MOVE.L #52, D0 $"A02E" // _BlockMove ; Move R.D. to top of rsrc $"6088"; // BRA.S SafeFatRsrc // FatRD /* Routine Descriptor */ GoMixedModeTrapType = _MixedModeMagic; VersionType = kRoutineDescriptorVersion; fill bit [7]; SelectorsAreIndexableType = FALSE; Reserved1Type; Reserved2Type; SelectorInfoType = 0; RoutineCountType = 1; /* Routine Record */ ProcInfoType; Reserved3Type; ISAType = kM68kISA; fill bit [11]; RoutineIsDispatchedDefaultType = FALSE; DontPassSelectorType = FALSE; UseNativeISAType = TRUE; FragmentNeedsPreparingType = FALSE; ProcDescriptorIsRelativeType = TRUE; ProcDescriptorType = (BeginningOf68KCode-Top) / 8; Reserved4Type; SelectorType = 0; /* PowerPC Routine Record 1 */ ProcInfoType; Reserved3Type; ISAType = kPowerPCISA; fill bit [11]; RoutineIsDispatchedDefaultType = FALSE; DontPassSelectorType = FALSE; UseNativeISAType = TRUE; FragmentNeedsPreparingType = TRUE; ProcDescriptorIsRelativeType = TRUE; ProcDescriptorType = (BeginningOfPowerPCCode-Top) / 8; Reserved4Type; SelectorType = 0; Align LONG; BeginningOf68KCode: hex string; // The 68k code starts here Align LONG; BeginningOfPowerPCCode: hex string; // The PEF container starts here }; #endif /* __MIXEDMODE_R__ */