ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/thunks.cpp
Revision: 1.18
Committed: 2006-05-14T07:21:10Z (18 years ago) by gbeauche
Branch: MAIN
Changes since 1.17: +9 -8 lines
Log Message:
Optimize generated code to NQD & CheckLoad functions. They don't call into
68k or MacOS code, so they don't need to be a termination point. i.e. don't
split into two basic blocks and thus avoid a full hash search.

Also add missing NQD_unknown_hook NativeOp from previous commit.

File Contents

# User Rev Content
1 gbeauche 1.1 /*
2     * thunks.cpp - Thunks to share data and code with MacOS
3     *
4     * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig
5     *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include "sysdeps.h"
22     #include "thunks.h"
23     #include "emul_op.h"
24     #include "cpu_emulation.h"
25 gbeauche 1.6 #include "xlowmem.h"
26 gbeauche 1.1
27     // Native function declarations
28     #include "main.h"
29     #include "video.h"
30     #include "name_registry.h"
31     #include "serial.h"
32     #include "ether.h"
33 gbeauche 1.2 #include "macos_util.h"
34 gbeauche 1.1
35 gbeauche 1.6 // Generate PowerPC thunks for GetResource() replacements?
36     #define POWERPC_GET_RESOURCE_THUNKS 1
37    
38 gbeauche 1.1
39     /* NativeOp instruction format:
40 gbeauche 1.9 +------------+-------------------------+--+-----------+------------+
41     | 6 | |FN| OP | 2 |
42     +------------+-------------------------+--+-----------+------------+
43     0 5 |6 18 19 20 25 26 31
44 gbeauche 1.1 */
45    
46 gbeauche 1.9 #define POWERPC_NATIVE_OP(FN, OP) \
47     (POWERPC_EMUL_OP | ((FN) << 12) | (((uint32)OP) << 6) | 2)
48 gbeauche 1.1
49 gbeauche 1.2 /*
50     * Return the fake PowerPC opcode to handle specified native code
51     */
52    
53 gbeauche 1.1 #if EMULATED_PPC
54     uint32 NativeOpcode(int selector)
55     {
56     uint32 opcode;
57     switch (selector) {
58 gbeauche 1.6 case NATIVE_CHECK_LOAD_INVOC:
59 gbeauche 1.16 case NATIVE_NAMED_CHECK_LOAD_INVOC:
60 gbeauche 1.18 case NATIVE_NQD_SYNC_HOOK:
61     case NATIVE_NQD_BITBLT_HOOK:
62     case NATIVE_NQD_FILLRECT_HOOK:
63     case NATIVE_NQD_UNKNOWN_HOOK:
64     case NATIVE_NQD_BITBLT:
65     case NATIVE_NQD_INVRECT:
66     case NATIVE_NQD_FILLRECT:
67 gbeauche 1.1 opcode = POWERPC_NATIVE_OP(0, selector);
68     break;
69     case NATIVE_PATCH_NAME_REGISTRY:
70     case NATIVE_VIDEO_INSTALL_ACCEL:
71     case NATIVE_VIDEO_VBL:
72     case NATIVE_VIDEO_DO_DRIVER_IO:
73 gbeauche 1.14 case NATIVE_ETHER_AO_GET_HWADDR:
74     case NATIVE_ETHER_AO_ADD_MULTI:
75     case NATIVE_ETHER_AO_DEL_MULTI:
76     case NATIVE_ETHER_AO_SEND_PACKET:
77 gbeauche 1.1 case NATIVE_ETHER_IRQ:
78     case NATIVE_ETHER_INIT:
79     case NATIVE_ETHER_TERM:
80     case NATIVE_ETHER_OPEN:
81     case NATIVE_ETHER_CLOSE:
82     case NATIVE_ETHER_WPUT:
83     case NATIVE_ETHER_RSRV:
84     case NATIVE_SERIAL_NOTHING:
85     case NATIVE_SERIAL_OPEN:
86     case NATIVE_SERIAL_PRIME_IN:
87     case NATIVE_SERIAL_PRIME_OUT:
88     case NATIVE_SERIAL_CONTROL:
89     case NATIVE_SERIAL_STATUS:
90     case NATIVE_SERIAL_CLOSE:
91     case NATIVE_GET_RESOURCE:
92     case NATIVE_GET_1_RESOURCE:
93     case NATIVE_GET_IND_RESOURCE:
94     case NATIVE_GET_1_IND_RESOURCE:
95     case NATIVE_R_GET_RESOURCE:
96 gbeauche 1.16 case NATIVE_GET_NAMED_RESOURCE:
97     case NATIVE_GET_1_NAMED_RESOURCE:
98 gbeauche 1.1 case NATIVE_MAKE_EXECUTABLE:
99     opcode = POWERPC_NATIVE_OP(1, selector);
100     break;
101     default:
102     abort();
103     }
104     return opcode;
105     }
106     #endif
107    
108 gbeauche 1.2
109     /*
110 gbeauche 1.6 * Generate PowerPC thunks for GetResource() replacements
111     */
112    
113     #if EMULATED_PPC
114     static uint32 get_resource_func;
115     static uint32 get_1_resource_func;
116     static uint32 get_ind_resource_func;
117     static uint32 get_1_ind_resource_func;
118     static uint32 r_get_resource_func;
119 gbeauche 1.16 static uint32 get_named_resource_func;
120     static uint32 get_1_named_resource_func;
121 gbeauche 1.6
122     static void generate_powerpc_thunks(void)
123     {
124 gbeauche 1.16 // check_load_invoc() thunk
125     uint32 check_load_invoc_opcode = NativeOpcode(NATIVE_CHECK_LOAD_INVOC);
126     uint32 base;
127    
128 gbeauche 1.6 static uint32 get_resource_template[] = {
129     PL(0x7c0802a6), // mflr r0
130     PL(0x90010008), // stw r0,8(r1)
131     PL(0x9421ffbc), // stwu r1,-68(r1)
132     PL(0x90610038), // stw r3,56(r1)
133     PL(0x9081003c), // stw r4,60(r1)
134     PL(0x00000000), // lwz r0,XLM_GET_RESOURCE(r0)
135     PL(0x80402834), // lwz r2,XLM_RES_LIB_TOC(r0)
136     PL(0x7c0903a6), // mtctr r0
137     PL(0x4e800421), // bctrl
138     PL(0x90610040), // stw r3,64(r1)
139     PL(0x80610038), // lwz r3,56(r1)
140     PL(0xa881003e), // lha r4,62(r1)
141     PL(0x80a10040), // lwz r5,64(r1)
142     PL(0x00000001), // <check_load_invoc>
143     PL(0x80610040), // lwz r3,64(r1)
144     PL(0x8001004c), // lwz r0,76(r1)
145     PL(0x7c0803a6), // mtlr r0
146     PL(0x38210044), // addi r1,r1,68
147     PL(0x4e800020) // blr
148     };
149     const uint32 get_resource_template_size = sizeof(get_resource_template);
150    
151     int xlm_index = -1, check_load_invoc_index = -1;
152     for (int i = 0; i < get_resource_template_size/4; i++) {
153     uint32 opcode = ntohl(get_resource_template[i]);
154     switch (opcode) {
155     case 0x00000000:
156     xlm_index = i;
157     break;
158     case 0x00000001:
159     check_load_invoc_index = i;
160     break;
161     }
162     }
163     assert(xlm_index != -1 && check_load_invoc_index != -1);
164    
165     // GetResource()
166     get_resource_func = base = SheepMem::Reserve(get_resource_template_size);
167     Host2Mac_memcpy(base, get_resource_template, get_resource_template_size);
168     WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_GET_RESOURCE);
169     WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode);
170    
171     // Get1Resource()
172     get_1_resource_func = base = SheepMem::Reserve(get_resource_template_size);
173     Host2Mac_memcpy(base, get_resource_template, get_resource_template_size);
174     WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_GET_1_RESOURCE);
175     WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode);
176    
177     // GetIndResource()
178     get_ind_resource_func = base = SheepMem::Reserve(get_resource_template_size);
179     Host2Mac_memcpy(base, get_resource_template, get_resource_template_size);
180     WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_GET_IND_RESOURCE);
181     WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode);
182    
183     // Get1IndResource()
184     get_1_ind_resource_func = base = SheepMem::Reserve(get_resource_template_size);
185     Host2Mac_memcpy(base, get_resource_template, get_resource_template_size);
186     WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_GET_1_IND_RESOURCE);
187     WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode);
188    
189     // RGetResource()
190     r_get_resource_func = base = SheepMem::Reserve(get_resource_template_size);
191     Host2Mac_memcpy(base, get_resource_template, get_resource_template_size);
192     WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_R_GET_RESOURCE);
193     WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode);
194 gbeauche 1.16
195     // named_check_load_invoc() thunk
196     check_load_invoc_opcode = NativeOpcode(NATIVE_NAMED_CHECK_LOAD_INVOC);
197    
198     static uint32 get_named_resource_template[] = {
199     PL(0x7c0802a6), // mflr r0
200     PL(0x90010008), // stw r0,8(r1)
201     PL(0x9421ffbc), // stwu r1,-68(r1)
202     PL(0x90610038), // stw r3,56(r1)
203     PL(0x9081003c), // stw r4,60(r1)
204     PL(0x00000000), // lwz r0,XLM_GET_NAMED_RESOURCE(r0)
205     PL(0x80402834), // lwz r2,XLM_RES_LIB_TOC(r0)
206     PL(0x7c0903a6), // mtctr r0
207     PL(0x4e800421), // bctrl
208     PL(0x90610040), // stw r3,64(r1)
209     PL(0x80610038), // lwz r3,56(r1)
210     PL(0x8081003c), // lwz r4,60(r1)
211     PL(0x80a10040), // lwz r5,64(r1)
212     PL(0x00000001), // <named_check_load_invoc>
213     PL(0x80610040), // lwz r3,64(r1)
214     PL(0x8001004c), // lwz r0,76(r1)
215     PL(0x7c0803a6), // mtlr r0
216     PL(0x38210044), // addi r1,r1,68
217     PL(0x4e800020) // blr
218     };
219     const uint32 get_named_resource_template_size = sizeof(get_named_resource_template);
220    
221     xlm_index = -1, check_load_invoc_index = -1;
222     for (int i = 0; i < get_resource_template_size/4; i++) {
223     uint32 opcode = ntohl(get_resource_template[i]);
224     switch (opcode) {
225     case 0x00000000:
226     xlm_index = i;
227     break;
228     case 0x00000001:
229     check_load_invoc_index = i;
230     break;
231     }
232     }
233     assert(xlm_index != -1 && check_load_invoc_index != -1);
234    
235     // GetNamedResource()
236     get_named_resource_func = base = SheepMem::Reserve(get_named_resource_template_size);
237     Host2Mac_memcpy(base, get_named_resource_template, get_named_resource_template_size);
238     WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_GET_NAMED_RESOURCE);
239     WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode);
240    
241     // Get1NamedResource()
242     get_1_named_resource_func = base = SheepMem::Reserve(get_named_resource_template_size);
243     Host2Mac_memcpy(base, get_named_resource_template, get_named_resource_template_size);
244     WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_GET_1_NAMED_RESOURCE);
245     WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode);
246 gbeauche 1.6 }
247     #endif
248    
249    
250     /*
251 gbeauche 1.2 * Initialize the thunks system
252     */
253    
254 gbeauche 1.1 struct native_op_t {
255     uint32 tvect;
256     uint32 func;
257 gbeauche 1.3 SheepRoutineDescriptor *desc;
258 gbeauche 1.1 };
259     static native_op_t native_op[NATIVE_OP_MAX];
260    
261     bool ThunksInit(void)
262     {
263     #if EMULATED_PPC
264     for (int i = 0; i < NATIVE_OP_MAX; i++) {
265 gbeauche 1.18 uintptr base = SheepMem::Reserve(16);
266 gbeauche 1.1 WriteMacInt32(base + 0, base + 8);
267     WriteMacInt32(base + 4, 0); // Fake TVECT
268     WriteMacInt32(base + 8, NativeOpcode(i));
269 gbeauche 1.18 WriteMacInt32(base + 12, POWERPC_BLR);
270 gbeauche 1.1 native_op[i].tvect = base;
271     native_op[i].func = base + 8;
272     }
273 gbeauche 1.6 #if POWERPC_GET_RESOURCE_THUNKS
274     generate_powerpc_thunks();
275     native_op[NATIVE_GET_RESOURCE].func = get_resource_func;
276     native_op[NATIVE_GET_1_RESOURCE].func = get_1_resource_func;
277     native_op[NATIVE_GET_IND_RESOURCE].func = get_ind_resource_func;
278     native_op[NATIVE_GET_1_IND_RESOURCE].func = get_1_ind_resource_func;
279     native_op[NATIVE_R_GET_RESOURCE].func = r_get_resource_func;
280 gbeauche 1.16 native_op[NATIVE_GET_NAMED_RESOURCE].func = get_named_resource_func;
281     native_op[NATIVE_GET_1_NAMED_RESOURCE].func = get_1_named_resource_func;
282 gbeauche 1.6 #endif
283 gbeauche 1.1 #else
284 gbeauche 1.12 #if defined(__linux__) || defined(__NetBSD__) || (defined(__APPLE__) && defined(__MACH__))
285 gbeauche 1.1 #define DEFINE_NATIVE_OP(ID, FUNC) do { \
286     uintptr base = SheepMem::Reserve(8); \
287     WriteMacInt32(base + 0, (uint32)FUNC); \
288 gbeauche 1.13 WriteMacInt32(base + 4, (uint32)TOC); \
289 gbeauche 1.1 native_op[ID].tvect = base; \
290     native_op[ID].func = (uint32)FUNC; \
291     } while (0)
292     #elif defined(__BEOS__)
293     #define DEFINE_NATIVE_OP(ID, FUNC) do { \
294     native_op[ID].tvect = FUNC; \
295     native_op[ID].func = ((uint32 *)FUNC)[0]; \
296     } while (0)
297     #else
298     #error "FIXME: define NativeOp for your platform"
299     #endif
300 gbeauche 1.4 // FIXME: add GetResource() and friends for completeness
301 gbeauche 1.2 DEFINE_NATIVE_OP(NATIVE_PATCH_NAME_REGISTRY, DoPatchNameRegistry);
302     DEFINE_NATIVE_OP(NATIVE_VIDEO_INSTALL_ACCEL, VideoInstallAccel);
303     DEFINE_NATIVE_OP(NATIVE_VIDEO_VBL, VideoVBL);
304     DEFINE_NATIVE_OP(NATIVE_VIDEO_DO_DRIVER_IO, VideoDoDriverIO);
305 gbeauche 1.14 DEFINE_NATIVE_OP(NATIVE_ETHER_AO_GET_HWADDR, AO_get_ethernet_address);
306     DEFINE_NATIVE_OP(NATIVE_ETHER_AO_ADD_MULTI, AO_enable_multicast);
307     DEFINE_NATIVE_OP(NATIVE_ETHER_AO_DEL_MULTI, AO_disable_multicast);
308 gbeauche 1.15 DEFINE_NATIVE_OP(NATIVE_ETHER_AO_SEND_PACKET, AO_transmit_packet);
309 gbeauche 1.2 DEFINE_NATIVE_OP(NATIVE_ETHER_IRQ, EtherIRQ);
310     DEFINE_NATIVE_OP(NATIVE_ETHER_INIT, InitStreamModule);
311     DEFINE_NATIVE_OP(NATIVE_ETHER_TERM, TerminateStreamModule);
312     DEFINE_NATIVE_OP(NATIVE_ETHER_OPEN, ether_open);
313     DEFINE_NATIVE_OP(NATIVE_ETHER_CLOSE, ether_close);
314     DEFINE_NATIVE_OP(NATIVE_ETHER_WPUT, ether_wput);
315     DEFINE_NATIVE_OP(NATIVE_ETHER_RSRV, ether_rsrv);
316 gbeauche 1.1 DEFINE_NATIVE_OP(NATIVE_SERIAL_NOTHING, SerialNothing);
317     DEFINE_NATIVE_OP(NATIVE_SERIAL_OPEN, SerialOpen);
318     DEFINE_NATIVE_OP(NATIVE_SERIAL_PRIME_IN, SerialPrimeIn);
319     DEFINE_NATIVE_OP(NATIVE_SERIAL_PRIME_OUT, SerialPrimeOut);
320     DEFINE_NATIVE_OP(NATIVE_SERIAL_CONTROL, SerialControl);
321     DEFINE_NATIVE_OP(NATIVE_SERIAL_STATUS, SerialStatus);
322     DEFINE_NATIVE_OP(NATIVE_SERIAL_CLOSE, SerialClose);
323     DEFINE_NATIVE_OP(NATIVE_MAKE_EXECUTABLE, MakeExecutable);
324 gbeauche 1.17 DEFINE_NATIVE_OP(NATIVE_NQD_SYNC_HOOK, NQD_sync_hook);
325     DEFINE_NATIVE_OP(NATIVE_NQD_BITBLT_HOOK, NQD_bitblt_hook);
326     DEFINE_NATIVE_OP(NATIVE_NQD_FILLRECT_HOOK, NQD_fillrect_hook);
327     DEFINE_NATIVE_OP(NATIVE_NQD_UNKNOWN_HOOK, NQD_unknown_hook);
328     DEFINE_NATIVE_OP(NATIVE_NQD_BITBLT, NQD_bitblt);
329     DEFINE_NATIVE_OP(NATIVE_NQD_INVRECT, NQD_invrect);
330     DEFINE_NATIVE_OP(NATIVE_NQD_FILLRECT, NQD_fillrect);
331 gbeauche 1.1 #undef DEFINE_NATIVE_OP
332     #endif
333 gbeauche 1.3
334 gbeauche 1.4 // Initialize routine descriptors (if TVECT exists)
335     for (int i = 0; i < NATIVE_OP_MAX; i++) {
336     uint32 tvect = native_op[i].tvect;
337     if (tvect)
338     native_op[i].desc = new SheepRoutineDescriptor(0, tvect);
339     }
340 gbeauche 1.3
341 gbeauche 1.1 return true;
342     }
343    
344 gbeauche 1.2
345     /*
346 gbeauche 1.3 * Delete generated thunks
347     */
348    
349     void ThunksExit(void)
350     {
351     for (int i = 0; i < NATIVE_OP_MAX; i++) {
352     SheepRoutineDescriptor *desc = native_op[i].desc;
353     if (desc)
354     delete desc;
355     }
356     }
357    
358    
359     /*
360 gbeauche 1.2 * Return the native function descriptor (TVECT)
361     */
362    
363 gbeauche 1.1 uint32 NativeTVECT(int selector)
364     {
365     assert(selector < NATIVE_OP_MAX);
366     const uint32 tvect = native_op[selector].tvect;
367     assert(tvect != 0);
368 gbeauche 1.2 return tvect;
369 gbeauche 1.1 }
370    
371 gbeauche 1.2
372     /*
373     * Return the native function address
374     */
375    
376 gbeauche 1.1 uint32 NativeFunction(int selector)
377     {
378     assert(selector < NATIVE_OP_MAX);
379     const uint32 func = native_op[selector].func;
380     assert(func != 0);
381 gbeauche 1.2 return func;
382     }
383    
384    
385     /*
386 gbeauche 1.3 * Return the routine descriptor address of the native function
387     */
388    
389     uint32 NativeRoutineDescriptor(int selector)
390     {
391     assert(selector < NATIVE_OP_MAX);
392     SheepRoutineDescriptor * const desc = native_op[selector].desc;
393     assert(desc != 0);
394     return desc->addr();
395     }
396    
397    
398     /*
399 gbeauche 1.2 * Execute native code from EMUL_OP routine (real mode switch)
400     */
401    
402     void ExecuteNative(int selector)
403     {
404     M68kRegisters r;
405 gbeauche 1.3 Execute68k(NativeRoutineDescriptor(selector), &r);
406 gbeauche 1.1 }