| 
118
 | 
     1 ---
 | 
| 
 | 
     2 layout: post
 | 
| 
 | 
     3 author: Paper
 | 
| 
 | 
     4 title: 'The Open Music System, part 1 - initialization'
 | 
| 
 | 
     5 nowplaying: 'The Radio Dept. - Brobygatan'
 | 
| 
 | 
     6 ---
 | 
| 
 | 
     7 <span>
 | 
| 
 | 
     8 	Applications wanting to interact with OMS must first call into
 | 
| 
 | 
     9 	<code>Gestalt</code> with the first parameter being the magic
 | 
| 
 | 
    10 	bytes <code>" OMS"</code> (<code>0x204F3D53</code>) and the
 | 
| 
 | 
    11 	second parameter being a pointer to a 32-bit variable that
 | 
| 
 | 
    12 	receives the magic pointer.
 | 
| 
 | 
    13 </span>
 | 
| 
 | 
    14 {% comment %}
 | 
| 
 | 
    15 	is there was a way to do this with newlines? this is ugly
 | 
| 
 | 
    16 {% endcomment %}
 | 
| 
 | 
    17 <figure><pre class="code-block"><code>UniversalProcPtr OMS_GetGestaltPtr(void)
 | 
| 
 | 
    18 {
 | 
| 
 | 
    19 	OSErr err;
 | 
| 
 | 
    20 	uint32_t x;
 | 
| 
 | 
    21 
 | 
| 
 | 
    22 	err = Gestalt(0x204F3D53 /* " OMS" */, &x);
 | 
| 
 | 
    23 	if (err != noErr)
 | 
| 
 | 
    24 		return NULL;
 | 
| 
 | 
    25 
 | 
| 
 | 
    26 	return (UniversalProcPtr)x;
 | 
| 
 | 
    27 }</code></pre></figure>
 | 
| 
 | 
    28 <span>
 | 
| 
 | 
    29 	From here, applications must retrieve an array of functions
 | 
| 
 | 
    30 	through calling that magic pointer. Note that users cannot
 | 
| 
 | 
    31 	simply call this pointer directly, unless they are specifically
 | 
| 
 | 
    32 	only targeting 68k. You must use the <code>CallUniversalProc</code>
 | 
| 
 | 
    33 	function to safely call into 68k code.
 | 
| 
 | 
    34 </span>
 | 
| 
 | 
    35 <figure><pre class="code-block"><code>UniversalProcPtr oms_table[0x5e];
 | 
| 
 | 
    36 
 | 
| 
 | 
    37 #define OMS_GESTALT_PROC_TYPE \
 | 
| 
 | 
    38 	(kThinkCStackBased \
 | 
| 
 | 
    39 		| RESULT_SIZE(kFourByteCode) \
 | 
| 
 | 
    40 		| STACK_ROUTINE_PARAMETER(1, kTwoByteCode) \
 | 
| 
 | 
    41 		| STACK_ROUTINE_PARAMETER(2, kFourByteCode))
 | 
| 
 | 
    42 
 | 
| 
 | 
    43 int32_t OMS_Init(void)
 | 
| 
 | 
    44 {
 | 
| 
 | 
    45 	uint32_t functable;
 | 
| 
 | 
    46 	UniversalProcPtr omsptr;
 | 
| 
 | 
    47 
 | 
| 
 | 
    48 	omsptr = OMS_GetGestaltPtr();
 | 
| 
 | 
    49 	if (!omsptr)
 | 
| 
 | 
    50 		return -1;
 | 
| 
 | 
    51 
 | 
| 
 | 
    52 	functable = CallUniversalProc(omsptr, OMS_GESTALT_PROC_TYPE, 4, 0);
 | 
| 
 | 
    53 	if (functable != (uint32_t)-1) {
 | 
| 
 | 
    54 		memcpy(oms_table, (const void *)functable, sizeof(oms_table));
 | 
| 
 | 
    55 	} else {
 | 
| 
 | 
    56 		/* very old OMS */
 | 
| 
 | 
    57 		uint32_t i;
 | 
| 
 | 
    58 
 | 
| 
 | 
    59 		functable = CallUniversalProc(omsptr, OMS_GESTALT_PROC_TYPE, 1, 0);
 | 
| 
 | 
    60 		if (!functable)
 | 
| 
 | 
    61 			return -1;
 | 
| 
 | 
    62 
 | 
| 
 | 
    63 		for (i = 0; i < ARRAY_SIZE(oms_table); i++, functable += 4)
 | 
| 
 | 
    64 			oms_table[i] = (UniversalProcPtr)functable;
 | 
| 
 | 
    65 	}
 | 
| 
 | 
    66 
 | 
| 
 | 
    67 	return 0;
 | 
| 
 | 
    68 }</code></pre></figure>
 | 
| 
 | 
    69 <span>
 | 
| 
 | 
    70 	At this point, you can now call into any of the pointers in
 | 
| 
 | 
    71 	<code>oms_table</code>, provided that you know what the parameters
 | 
| 
 | 
    72 	are. The easiest way I've found to find the parameters is to open an
 | 
| 
 | 
    73 	OMS-capable program in a reverse-engineering tool, search for uses of
 | 
| 
 | 
    74 	<code>CallUniversalProc</code> that look roughly like the initialization
 | 
| 
 | 
    75 	code above, and mark the offset they are copied to as the OMS table with
 | 
| 
 | 
    76 	the correct size and type. You can then find other uses of
 | 
| 
 | 
    77 	<code>CallUniversalProc</code> that use the pointers in the OMS table,
 | 
| 
 | 
    78 	and mark down the procedure type (the second parameter to
 | 
| 
 | 
    79 	<code>CallUniversalProc</code>). To decode the procedure type, I've
 | 
| 
 | 
    80 	written a simple utility to do the heavy lifting
 | 
| 
 | 
    81 	<a class="prettylink" href="https://hg.tflc.us/codedump/file/tip/decode-mixed-mode.c">here</a>.
 | 
| 
 | 
    82 	Do take note that it does not support register-based calling yet.
 | 
| 
 | 
    83 	Feel free to send me any patches if you add support for it ;)
 | 
| 
 | 
    84 </span>
 |