ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/thunks.cpp
Revision: 1.9
Committed: 2004-04-22T22:54:46Z (20 years ago) by gbeauche
Branch: MAIN
Changes since 1.8: +6 -6 lines
Log Message:
Extend NativeOp count to 64 (6-bit value), aka fix NATIVE_FILLRECT opcpdes.
Translate NQD_{bitblt,fillrect,invrect} to direct native calls.
Use Mac2HostAddr() for converting Mac base address to native.

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_DISABLE_INTERRUPT:
59 case NATIVE_ENABLE_INTERRUPT:
60 case NATIVE_CHECK_LOAD_INVOC:
61 opcode = POWERPC_NATIVE_OP(0, selector);
62 break;
63 case NATIVE_PATCH_NAME_REGISTRY:
64 case NATIVE_VIDEO_INSTALL_ACCEL:
65 case NATIVE_VIDEO_VBL:
66 case NATIVE_VIDEO_DO_DRIVER_IO:
67 case NATIVE_ETHER_IRQ:
68 case NATIVE_ETHER_INIT:
69 case NATIVE_ETHER_TERM:
70 case NATIVE_ETHER_OPEN:
71 case NATIVE_ETHER_CLOSE:
72 case NATIVE_ETHER_WPUT:
73 case NATIVE_ETHER_RSRV:
74 case NATIVE_SERIAL_NOTHING:
75 case NATIVE_SERIAL_OPEN:
76 case NATIVE_SERIAL_PRIME_IN:
77 case NATIVE_SERIAL_PRIME_OUT:
78 case NATIVE_SERIAL_CONTROL:
79 case NATIVE_SERIAL_STATUS:
80 case NATIVE_SERIAL_CLOSE:
81 case NATIVE_GET_RESOURCE:
82 case NATIVE_GET_1_RESOURCE:
83 case NATIVE_GET_IND_RESOURCE:
84 case NATIVE_GET_1_IND_RESOURCE:
85 case NATIVE_R_GET_RESOURCE:
86 case NATIVE_MAKE_EXECUTABLE:
87 case NATIVE_SYNC_HOOK:
88 case NATIVE_BITBLT_HOOK:
89 case NATIVE_FILLRECT_HOOK:
90 case NATIVE_BITBLT:
91 case NATIVE_INVRECT:
92 case NATIVE_FILLRECT:
93 opcode = POWERPC_NATIVE_OP(1, selector);
94 break;
95 default:
96 abort();
97 }
98 return opcode;
99 }
100 #endif
101
102
103 /*
104 * Generate PowerPC thunks for GetResource() replacements
105 */
106
107 #if EMULATED_PPC
108 static uint32 get_resource_func;
109 static uint32 get_1_resource_func;
110 static uint32 get_ind_resource_func;
111 static uint32 get_1_ind_resource_func;
112 static uint32 r_get_resource_func;
113
114 static void generate_powerpc_thunks(void)
115 {
116 static uint32 get_resource_template[] = {
117 PL(0x7c0802a6), // mflr r0
118 PL(0x90010008), // stw r0,8(r1)
119 PL(0x9421ffbc), // stwu r1,-68(r1)
120 PL(0x90610038), // stw r3,56(r1)
121 PL(0x9081003c), // stw r4,60(r1)
122 PL(0x00000000), // lwz r0,XLM_GET_RESOURCE(r0)
123 PL(0x80402834), // lwz r2,XLM_RES_LIB_TOC(r0)
124 PL(0x7c0903a6), // mtctr r0
125 PL(0x4e800421), // bctrl
126 PL(0x90610040), // stw r3,64(r1)
127 PL(0x80610038), // lwz r3,56(r1)
128 PL(0xa881003e), // lha r4,62(r1)
129 PL(0x80a10040), // lwz r5,64(r1)
130 PL(0x00000001), // <check_load_invoc>
131 PL(0x80610040), // lwz r3,64(r1)
132 PL(0x8001004c), // lwz r0,76(r1)
133 PL(0x7c0803a6), // mtlr r0
134 PL(0x38210044), // addi r1,r1,68
135 PL(0x4e800020) // blr
136 };
137 const uint32 get_resource_template_size = sizeof(get_resource_template);
138
139 int xlm_index = -1, check_load_invoc_index = -1;
140 for (int i = 0; i < get_resource_template_size/4; i++) {
141 uint32 opcode = ntohl(get_resource_template[i]);
142 switch (opcode) {
143 case 0x00000000:
144 xlm_index = i;
145 break;
146 case 0x00000001:
147 check_load_invoc_index = i;
148 break;
149 }
150 }
151 assert(xlm_index != -1 && check_load_invoc_index != -1);
152
153 uint32 check_load_invoc_opcode = NativeOpcode(NATIVE_CHECK_LOAD_INVOC);
154 uintptr base;
155
156 // GetResource()
157 get_resource_func = base = SheepMem::Reserve(get_resource_template_size);
158 Host2Mac_memcpy(base, get_resource_template, get_resource_template_size);
159 WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_GET_RESOURCE);
160 WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode);
161
162 // Get1Resource()
163 get_1_resource_func = base = SheepMem::Reserve(get_resource_template_size);
164 Host2Mac_memcpy(base, get_resource_template, get_resource_template_size);
165 WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_GET_1_RESOURCE);
166 WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode);
167
168 // GetIndResource()
169 get_ind_resource_func = base = SheepMem::Reserve(get_resource_template_size);
170 Host2Mac_memcpy(base, get_resource_template, get_resource_template_size);
171 WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_GET_IND_RESOURCE);
172 WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode);
173
174 // Get1IndResource()
175 get_1_ind_resource_func = base = SheepMem::Reserve(get_resource_template_size);
176 Host2Mac_memcpy(base, get_resource_template, get_resource_template_size);
177 WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_GET_1_IND_RESOURCE);
178 WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode);
179
180 // RGetResource()
181 r_get_resource_func = base = SheepMem::Reserve(get_resource_template_size);
182 Host2Mac_memcpy(base, get_resource_template, get_resource_template_size);
183 WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_R_GET_RESOURCE);
184 WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode);
185 }
186 #endif
187
188
189 /*
190 * Initialize the thunks system
191 */
192
193 struct native_op_t {
194 uint32 tvect;
195 uint32 func;
196 SheepRoutineDescriptor *desc;
197 };
198 static native_op_t native_op[NATIVE_OP_MAX];
199
200 bool ThunksInit(void)
201 {
202 #if EMULATED_PPC
203 for (int i = 0; i < NATIVE_OP_MAX; i++) {
204 uintptr base = SheepMem::Reserve(12);
205 WriteMacInt32(base + 0, base + 8);
206 WriteMacInt32(base + 4, 0); // Fake TVECT
207 WriteMacInt32(base + 8, NativeOpcode(i));
208 native_op[i].tvect = base;
209 native_op[i].func = base + 8;
210 }
211 #if POWERPC_GET_RESOURCE_THUNKS
212 generate_powerpc_thunks();
213 native_op[NATIVE_GET_RESOURCE].func = get_resource_func;
214 native_op[NATIVE_GET_1_RESOURCE].func = get_1_resource_func;
215 native_op[NATIVE_GET_IND_RESOURCE].func = get_ind_resource_func;
216 native_op[NATIVE_GET_1_IND_RESOURCE].func = get_1_ind_resource_func;
217 native_op[NATIVE_R_GET_RESOURCE].func = r_get_resource_func;
218 #endif
219 #else
220 #if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__))
221 #define DEFINE_NATIVE_OP(ID, FUNC) do { \
222 uintptr base = SheepMem::Reserve(8); \
223 WriteMacInt32(base + 0, (uint32)FUNC); \
224 WriteMacInt32(base + 4, 0); /*Fake TVECT*/ \
225 native_op[ID].tvect = base; \
226 native_op[ID].func = (uint32)FUNC; \
227 } while (0)
228 #elif defined(__BEOS__)
229 #define DEFINE_NATIVE_OP(ID, FUNC) do { \
230 native_op[ID].tvect = FUNC; \
231 native_op[ID].func = ((uint32 *)FUNC)[0]; \
232 } while (0)
233 #else
234 #error "FIXME: define NativeOp for your platform"
235 #endif
236 // FIXME: add GetResource() and friends for completeness
237 DEFINE_NATIVE_OP(NATIVE_PATCH_NAME_REGISTRY, DoPatchNameRegistry);
238 DEFINE_NATIVE_OP(NATIVE_VIDEO_INSTALL_ACCEL, VideoInstallAccel);
239 DEFINE_NATIVE_OP(NATIVE_VIDEO_VBL, VideoVBL);
240 DEFINE_NATIVE_OP(NATIVE_VIDEO_DO_DRIVER_IO, VideoDoDriverIO);
241 DEFINE_NATIVE_OP(NATIVE_ETHER_IRQ, EtherIRQ);
242 DEFINE_NATIVE_OP(NATIVE_ETHER_INIT, InitStreamModule);
243 DEFINE_NATIVE_OP(NATIVE_ETHER_TERM, TerminateStreamModule);
244 DEFINE_NATIVE_OP(NATIVE_ETHER_OPEN, ether_open);
245 DEFINE_NATIVE_OP(NATIVE_ETHER_CLOSE, ether_close);
246 DEFINE_NATIVE_OP(NATIVE_ETHER_WPUT, ether_wput);
247 DEFINE_NATIVE_OP(NATIVE_ETHER_RSRV, ether_rsrv);
248 DEFINE_NATIVE_OP(NATIVE_SERIAL_NOTHING, SerialNothing);
249 DEFINE_NATIVE_OP(NATIVE_SERIAL_OPEN, SerialOpen);
250 DEFINE_NATIVE_OP(NATIVE_SERIAL_PRIME_IN, SerialPrimeIn);
251 DEFINE_NATIVE_OP(NATIVE_SERIAL_PRIME_OUT, SerialPrimeOut);
252 DEFINE_NATIVE_OP(NATIVE_SERIAL_CONTROL, SerialControl);
253 DEFINE_NATIVE_OP(NATIVE_SERIAL_STATUS, SerialStatus);
254 DEFINE_NATIVE_OP(NATIVE_SERIAL_CLOSE, SerialClose);
255 DEFINE_NATIVE_OP(NATIVE_MAKE_EXECUTABLE, MakeExecutable);
256 DEFINE_NATIVE_OP(NATIVE_SYNC_HOOK, NQD_sync_hook);
257 DEFINE_NATIVE_OP(NATIVE_BITBLT_HOOK, NQD_bitblt_hook);
258 DEFINE_NATIVE_OP(NATIVE_FILLRECT_HOOK, NQD_fillrect_hook);
259 DEFINE_NATIVE_OP(NATIVE_BITBLT, NQD_bitblt);
260 DEFINE_NATIVE_OP(NATIVE_INVRECT, NQD_invrect);
261 DEFINE_NATIVE_OP(NATIVE_FILLRECT, NQD_fillrect);
262 #undef DEFINE_NATIVE_OP
263 #endif
264
265 // Initialize routine descriptors (if TVECT exists)
266 for (int i = 0; i < NATIVE_OP_MAX; i++) {
267 uint32 tvect = native_op[i].tvect;
268 if (tvect)
269 native_op[i].desc = new SheepRoutineDescriptor(0, tvect);
270 }
271
272 return true;
273 }
274
275
276 /*
277 * Delete generated thunks
278 */
279
280 void ThunksExit(void)
281 {
282 for (int i = 0; i < NATIVE_OP_MAX; i++) {
283 SheepRoutineDescriptor *desc = native_op[i].desc;
284 if (desc)
285 delete desc;
286 }
287 }
288
289
290 /*
291 * Return the native function descriptor (TVECT)
292 */
293
294 uint32 NativeTVECT(int selector)
295 {
296 assert(selector < NATIVE_OP_MAX);
297 const uint32 tvect = native_op[selector].tvect;
298 assert(tvect != 0);
299 return tvect;
300 }
301
302
303 /*
304 * Return the native function address
305 */
306
307 uint32 NativeFunction(int selector)
308 {
309 assert(selector < NATIVE_OP_MAX);
310 const uint32 func = native_op[selector].func;
311 assert(func != 0);
312 return func;
313 }
314
315
316 /*
317 * Return the routine descriptor address of the native function
318 */
319
320 uint32 NativeRoutineDescriptor(int selector)
321 {
322 assert(selector < NATIVE_OP_MAX);
323 SheepRoutineDescriptor * const desc = native_op[selector].desc;
324 assert(desc != 0);
325 return desc->addr();
326 }
327
328
329 /*
330 * Execute native code from EMUL_OP routine (real mode switch)
331 */
332
333 void ExecuteNative(int selector)
334 {
335 M68kRegisters r;
336 Execute68k(NativeRoutineDescriptor(selector), &r);
337 }