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, 5 months 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

# Content
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 #include "xlowmem.h"
26
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 #include "macos_util.h"
34
35 // Generate PowerPC thunks for GetResource() replacements?
36 #define POWERPC_GET_RESOURCE_THUNKS 1
37
38
39 /* NativeOp instruction format:
40 +------------+-------------------------+--+-----------+------------+
41 | 6 | |FN| OP | 2 |
42 +------------+-------------------------+--+-----------+------------+
43 0 5 |6 18 19 20 25 26 31
44 */
45
46 #define POWERPC_NATIVE_OP(FN, OP) \
47 (POWERPC_EMUL_OP | ((FN) << 12) | (((uint32)OP) << 6) | 2)
48
49 /*
50 * Return the fake PowerPC opcode to handle specified native code
51 */
52
53 #if EMULATED_PPC
54 uint32 NativeOpcode(int selector)
55 {
56 uint32 opcode;
57 switch (selector) {
58 case NATIVE_CHECK_LOAD_INVOC:
59 case NATIVE_NAMED_CHECK_LOAD_INVOC:
60 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 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 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 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 case NATIVE_GET_NAMED_RESOURCE:
97 case NATIVE_GET_1_NAMED_RESOURCE:
98 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
109 /*
110 * 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 static uint32 get_named_resource_func;
120 static uint32 get_1_named_resource_func;
121
122 static void generate_powerpc_thunks(void)
123 {
124 // check_load_invoc() thunk
125 uint32 check_load_invoc_opcode = NativeOpcode(NATIVE_CHECK_LOAD_INVOC);
126 uint32 base;
127
128 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
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 }
247 #endif
248
249
250 /*
251 * Initialize the thunks system
252 */
253
254 struct native_op_t {
255 uint32 tvect;
256 uint32 func;
257 SheepRoutineDescriptor *desc;
258 };
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 uintptr base = SheepMem::Reserve(16);
266 WriteMacInt32(base + 0, base + 8);
267 WriteMacInt32(base + 4, 0); // Fake TVECT
268 WriteMacInt32(base + 8, NativeOpcode(i));
269 WriteMacInt32(base + 12, POWERPC_BLR);
270 native_op[i].tvect = base;
271 native_op[i].func = base + 8;
272 }
273 #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 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 #endif
283 #else
284 #if defined(__linux__) || defined(__NetBSD__) || (defined(__APPLE__) && defined(__MACH__))
285 #define DEFINE_NATIVE_OP(ID, FUNC) do { \
286 uintptr base = SheepMem::Reserve(8); \
287 WriteMacInt32(base + 0, (uint32)FUNC); \
288 WriteMacInt32(base + 4, (uint32)TOC); \
289 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 // FIXME: add GetResource() and friends for completeness
301 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 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 DEFINE_NATIVE_OP(NATIVE_ETHER_AO_SEND_PACKET, AO_transmit_packet);
309 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 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 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 #undef DEFINE_NATIVE_OP
332 #endif
333
334 // 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
341 return true;
342 }
343
344
345 /*
346 * 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 * Return the native function descriptor (TVECT)
361 */
362
363 uint32 NativeTVECT(int selector)
364 {
365 assert(selector < NATIVE_OP_MAX);
366 const uint32 tvect = native_op[selector].tvect;
367 assert(tvect != 0);
368 return tvect;
369 }
370
371
372 /*
373 * Return the native function address
374 */
375
376 uint32 NativeFunction(int selector)
377 {
378 assert(selector < NATIVE_OP_MAX);
379 const uint32 func = native_op[selector].func;
380 assert(func != 0);
381 return func;
382 }
383
384
385 /*
386 * 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 * Execute native code from EMUL_OP routine (real mode switch)
400 */
401
402 void ExecuteNative(int selector)
403 {
404 M68kRegisters r;
405 Execute68k(NativeRoutineDescriptor(selector), &r);
406 }