Author Topic: FAT patch  (Read 5306 times)

Offline OS923

  • Platinum Member
  • *****
  • Posts: 888
FAT patch
« on: August 14, 2018, 04:50:49 AM »
I search a working source code example of a FAT patch.

I looked it up in 7 books. I got 7 different answers and nothing works. Their examples even don't compile.

Offline Daniel

  • Gold Member
  • *****
  • Posts: 300
  • Programmer, Hacker, Thinker
Re: FAT patch
« Reply #1 on: August 14, 2018, 08:18:39 AM »

I imagine compiler directives would be needed to make the code work. I know that shared libraries require you to explicitly export everything except the main, init, and termination entry points. This has to be done from the makefile or in a export control file pointed to from the makefile (in MPW, at least. CodeWarrior and others might be different).

What kind of FAT patch? I can imagine two kinds of them: one that chooses whether to go ppc or 68k at boot, and one that chooses its mode at runtime depending one what the mode of the caller is.

If you want the boot time one, I believe the 'cput' gestalt will indicate what model of processor is in the machine. The value returned will be less than 0x100 if the cpu is 68k, and >= 0x100 if it is ppc.

If you want the runtime one, I would suggest building the UPP in the patching code, using the function pointers from the 68k and ppc versions of it. It's recommended that you select the data pack mode to use 68k conventions for both of the versions of the routines.

I suppose you could also go the FAT code resource route, though I don't know how to actually do that.

Offline OS923

  • Platinum Member
  • *****
  • Posts: 888
Re: FAT patch
« Reply #2 on: August 16, 2018, 06:03:22 AM »
I mean: a FAT patch of a toolbox trap or OS trap.

A FAT code resource won't work here because I need to get multiple symbols from the PPC part while a FAT resource has only one entry point.

Offline Naiw

  • Veteran Member
  • ****
  • Posts: 126
  • new to the forums
Re: FAT patch
« Reply #3 on: August 17, 2018, 08:06:27 PM »
As Daniel says the only sane way is to install the patch for the architecture that's running the OS.

UPPs won't help, they're for mixedmode (ie PowerPCs running the 68k emulator), 68k Mac OS doesn't understand or care about UPPs. 

Offline OS923

  • Platinum Member
  • *****
  • Posts: 888
Re: FAT patch
« Reply #4 on: August 23, 2018, 06:30:25 AM »
I found a clue about what I'm doing wrong:

https://archive.info-mac.org/_Periodical/csmp/csmp-digest-v3-021.txt

Quote
Leonard responded to me:

"That's because your code has a SINGLE entry point and you built it with a MixedMode Header on the resource. If you DON'T do that, and you resolve (FindSymbol) at runtime, the connection ID's are not valid across processes."

Now, he is right, I have a single entry point. Maybe there is more to it with multiple entry points. I don't know since I've not had to deal with that yet.

Offline OS923

  • Platinum Member
  • *****
  • Posts: 888
Re: FAT patch
« Reply #5 on: August 23, 2018, 06:33:55 AM »
I found only one extension that installs FAT patches (Conflict Catcher) and no working source code example. That suggests that it's not as easy as it was presented.

Offline OS923

  • Platinum Member
  • *****
  • Posts: 888
Re: FAT patch
« Reply #6 on: September 04, 2018, 07:00:21 AM »
I found an example of a FAT patch in the source code of Emacs 1.17 but this is from 1995 and doesn't work with CW Pro 6.2.

I found an example of a FAT patch in "A fragment of your imagination" Chapter 4 - Sys Extensions - MenuScript INIT. But this never uses the code that makes the FAT patch. It installs a PPC patch.

I found 2 similar problems: FAT gestalt selector and FAT completion procedure.

Unfortunately, no working example.

One of the problems is that NewFatRoutineDescriptor is not available in an extension because the header defines it only if TARGET_RT_MAC_CFM is true. Some get around this by undefining TARGET_RT_MAC_CFM, including the header and then redefining TARGET_RT_MAC_CFM.

When TARGET_RT_MAC_CFM is false then you get NewFatRoutineDescriptorTrap instead, but this function is undocumented. I tried to use it like NewFatRoutineDescriptor but it crashes.

Offline Naiw

  • Veteran Member
  • ****
  • Posts: 126
  • new to the forums
Re: FAT patch
« Reply #7 on: September 06, 2018, 07:16:41 AM »
I found an example of a FAT patch in the source code of Emacs 1.17 but this is from 1995 and doesn't work with CW Pro 6.2.

I found an example of a FAT patch in "A fragment of your imagination" Chapter 4 - Sys Extensions - MenuScript INIT. But this never uses the code that makes the FAT patch. It installs a PPC patch.

I found 2 similar problems: FAT gestalt selector and FAT completion procedure.

Unfortunately, no working example.

One of the problems is that NewFatRoutineDescriptor is not available in an extension because the header defines it only if TARGET_RT_MAC_CFM is true. Some get around this by undefining TARGET_RT_MAC_CFM, including the header and then redefining TARGET_RT_MAC_CFM.

When TARGET_RT_MAC_CFM is false then you get NewFatRoutineDescriptorTrap instead, but this function is undocumented. I tried to use it like NewFatRoutineDescriptor but it crashes.

Really? The fact you have to hack around in header files to get it work your way is obviously a clear indication of that you're doing something SERIOUSLY wrong, isn't it?

Once again why on earth would anyone want to install a patch as a FAT code resource? The CPU isn't changing on the machine past boot. If you want a CPU native version of the patch depending on the CPU running on Mac OS you would as already been mentioned multiple times determine that upon boot and only install the relevant code fragment.

Technically you can do exactly what you want...as 68k system calls are traps... while the powerpc uses tvectors, But what exactly is the use case?

Offline OS923

  • Platinum Member
  • *****
  • Posts: 888
Re: FAT patch
« Reply #8 on: September 08, 2018, 02:46:18 AM »
It's not a FAT code resource. You have a 68K function in your 68K INIT. You have a PPC code fragment in a resource from which you get a symbol (function). You make a routine descriptor that contains a descriptor to the 68K function and the PPC function. According to a technote of which I forgot the number, you need to use NewFatRoutineDescriptorTrap to make that routine descriptor.

You need to make the difference between old 68K and CFM68K. NewFatRoutineDescriptorTrap works different on 68K Macs and PPC Macs. On a 68K Macs it takes an old 68K function and a CFM68K function. On PPC Macs it takes an old 68K function and a PPC function from a PPC code fragment.

But I saw that there's also a problem with the prototypes. In the documentation they give an example of how to patch NewPtr.

http://mirror.informatimago.com/next/developer.apple.com/documentation/mac/PPCSoftware/PPCSoftware-16.html

Code: [Select]
enum {      /*procedure information for NewPtr function*/
   kNewPtrProcInfo = kRegisterBased |
      RESULT_SIZE(kFourByteCode) |
      REGISTER_RESULT_LOCATION(kRegisterA0) |
      REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, kTwoByteCode) |
      REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, kFourByteCode)
};

pascal Ptr MyNewPtrPatch(unsigned short trapWord, Size byteCount)
{
   /*Your patch code goes here.*/

   return (long) CallOSTrapUniversalProc(gOriginalNewPtr,
                        kNewPtrProcInfo, trapWord, byteCount);
}

It's register based and it gets an additional parameter. I found it impossible to guess which patches require which additional parameters and in which registers the parameters need to go.

I think that this means that a general solution won't be possible here.

I found the solution for the PPC version of my extensions and I want to leave it here. I'm glad that I got this far.

Offline Daniel

  • Gold Member
  • *****
  • Posts: 300
  • Programmer, Hacker, Thinker
Re: FAT patch
« Reply #9 on: September 08, 2018, 07:43:37 AM »
D1 is part of the Trap Dispatcher calling conventions for OS Traps. Here's a comment from Apple's code for the Trap Dispatcher. Taken from https://github.com/elliotnunn/mac-rom/blob/master/OS/TrapDispatcher/Dispatch.a
Quote
;  An A-line trap has the form:  1010 tabc nnnn nnnn
;
;  t=1 ==> Toolbox;  t=0 ==> OS.  They differ mainly in register saving conventions.
;
;  ToolBox:
;      These calls follow Pascal parameter-passing conventions, receiving and returning
;      values on the stack, and saving all but D0-D2/A0-A1.
;      All registers are preserved up to the time the target routine is reached; the
;      stack is as though a JSR had been executed.
;      a=1 ==> an extra return address was on the stack when the trap was executed
;         (e.g. a dumb compiler required a JSR to the A-line trap).  This superfluous
;         address will be removed by the dispatcher.
;      bcnnnnnnnn = trap number
;
;  OS:
;      All parameters are passed in registers.  Routine must follow Pascal
;      conventions about D3-D7/A2-A7.   D0/A0-A1 are passed through to the
;      routine unchanged.   D1.W is the actual A-line instruction.
;      c=1 ==> D1-D2/A1 are preserved by the dispatcher (so values can be returned
;         in D0/A0).
;      c=0 ==> D1-D2/A0-A1 are preserved by the dispatcher (so D0 can be returned).
;      a,b = don't care, but are used by the traps to indicate, say, SYS/APPL,
;         SYNC/ASYNC, DIACRITICALS/NOT, . . .
;      nnnnnnnn = trap number

So D1 contains the instruction that triggered the Trap Dispatcher. It is used by the OS Trap to determine what flag bits are set. _NewPtr and _NewPtr, SYS, CLEAR have different flag bits set but have the same trap word number and call the same routine.

Offline OS923

  • Platinum Member
  • *****
  • Posts: 888
Re: FAT patch
« Reply #10 on: September 11, 2018, 04:32:51 AM »
http://mirror.informatimago.com/next/developer.apple.com/documentation/mac/PPCSoftware/PPCSoftware-16.html

Quote
Because you cannot in general know what kind of code implements a particular system software routine, you should install a fat patch, which addresses both PowerPC and 680x0 versions of your code. To install a fat patch, you need to create a routine descriptor with two embedded routine records, one record describing the PowerPC routine and one record describing the 680x0 routine. Then you pass the address of that routine descriptor--that is, a universal procedure pointer--to an appropriate Trap Manager routine, which installs that universal procedure pointer into the trap dispatch table. When the patched routine is called, the Mixed Mode Manager inspects the routine descriptor addressed by the universal procedure pointer and selects the patch code that has the smallest impact on performance.