|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * exec.library emulation
5: *
6: * Copyright 1996 Bernd Schmidt
7: */
8:
9: #undef USE_EXECLIB
10:
11: #include "sysconfig.h"
12: #include "sysdeps.h"
13:
14: #include <assert.h>
15: #include <signal.h>
16: #ifdef USE_EXECLIB
17: #include <setjmp.h>
18: #endif
19:
20: #include "config.h"
21: #include "options.h"
22: #include "memory.h"
23: #include "custom.h"
24: #include "newcpu.h"
25: #include "xwin.h"
26: #include "autoconf.h"
27: #include "osemu.h"
28:
29: static CPTR sysbase;
30:
31: /*
32: * Exec list management
33: */
34:
35: void EXEC_NewList(CPTR list)
36: {
37: put_long(list, list + 4);
38: put_long(list + 4, 0);
39: put_long(list + 8, list);
40: }
41:
42: void EXEC_Insert(CPTR list, CPTR node, CPTR pred)
43: {
44: CPTR succ;
45: if (pred == 0)
46: pred = list;
47: put_long(node, succ = get_long(pred));
48: put_long(pred, node);
49: put_long(succ + 4, node);
50: put_long(node + 4, pred);
51: }
52:
53: void EXEC_Enqueue(CPTR list, CPTR node)
54: {
55: int pri = (BYTE)get_byte (node + 9);
56: CPTR lnode = get_long(list); /* lh_Head */
57: CPTR prev = 0, next;
58:
59: for (;(next = get_long(lnode)) != 0 && (BYTE)get_byte(lnode + 9) >= pri;) {
60: prev = lnode;
61: lnode = next;
62: }
63: EXEC_Insert(list, node, prev);
64: }
65:
66: void EXEC_Remove(CPTR node)
67: {
68: CPTR pred = get_long(node + 4), succ = get_long(node);
69: put_long(pred, succ);
70: put_long(succ + 4, pred);
71: }
72:
73: ULONG EXEC_RemHead(CPTR list)
74: {
75: CPTR head = get_long(list);
76: if (get_long(head) == 0)
77: return 0;
78: EXEC_Remove(head);
79: return head;
80: }
81:
82: ULONG EXEC_RemTail(CPTR list)
83: {
84: CPTR tail = get_long(list + 8);
85: if (get_long(tail + 4) == 0)
86: return 0;
87:
88: EXEC_Remove(tail);
89: return tail;
90: }
91:
92: void EXEC_AddTail(CPTR list, CPTR node)
93: {
94: EXEC_Insert(list, node, get_long(list + 8));
95: }
96:
97: CPTR EXEC_FindName(CPTR start, char *name)
98: {
99: CPTR node = start;
100: if (name == NULL)
101: return 0;
102:
103: for (;;) {
104: CPTR nnp;
105: char *nn;
106:
107: node = get_long(start);
108:
109: if (node == 0)
110: break;
111: nnp = get_long(node + 10);
112: if (nnp != 0 && (nn = get_real_address(nnp)) != NULL)
113: if (strcmp(nn, name) == 0)
114: return node;
115: start = node;
116: }
117: return 0;
118: }
119:
120: static ULONG execl_Enqueue(void) { EXEC_Enqueue(regs.a[0], regs.a[1]); return 0; }
121: static ULONG execl_Insert(void) { EXEC_Insert(regs.a[0], regs.a[1], regs.a[2]); return 0; }
122: static ULONG execl_AddHead(void) { EXEC_Insert(regs.a[0], regs.a[1], 0); return 0; }
123: static ULONG execl_AddTail(void) { EXEC_Insert(regs.a[0], regs.a[1], get_long(regs.a[0] + 8)); return 0; }
124: static ULONG execl_Remove(void) { EXEC_Remove(regs.a[1]); return 0; }
125: static ULONG execl_RemHead(void) { return EXEC_RemHead(regs.a[0]); }
126: static ULONG execl_RemTail(void) { return EXEC_RemTail(regs.a[0]); }
127: static ULONG execl_FindName(void) { CPTR n = EXEC_FindName(regs.a[0], get_real_address(regs.a[1])); ZFLG = n == 0; return n; }
128:
129: /*
130: * Miscellaneous
131: */
132:
133: void EXEC_InitStruct(CPTR inittable, CPTR memory, unsigned long size)
134: {
135: CPTR dptr = memory;
136: UBYTE *mem = get_real_address(memory);
137: if (memory == 0 || mem == NULL || !valid_address(memory, size)) {
138: fprintf(stderr, "Foo\n");
139: return;
140: }
141: memset(mem, 0, size);
142: fprintf(stderr, "InitStruct\n");
143: for (;;) {
144: UBYTE command;
145: int count, desttype, srcloc;
146: ULONG offset;
147:
148: /* Read commands from even bytes */
149: inittable = (inittable + 1) & ~1;
150:
151: command = get_byte(inittable);
152: if (command == 0)
153: break;
154: desttype = (command >> 6) & 3;
155: srcloc = (command >> 4) & 3;
156: count = (command & 15) + 1;
157:
158: if (desttype == 3) {
159: dptr = memory + (get_long(inittable) & 0xFFFFFF);
160: inittable += 4;
161: } else if (desttype == 2) {
162: dptr = memory + get_byte(inittable+1), inittable += 2;
163: } else
164: inittable++;
165:
166: if (srcloc != 0)
167: inittable = (inittable + 1) & ~1;
168:
169: if (desttype != 1) {
170: for(; count > 0; count--) {
171: switch (srcloc) {
172: case 0: put_long(dptr, get_long(inittable)); dptr += 4; inittable += 4; break;
173: case 1: put_word(dptr, get_word(inittable)); dptr += 2; inittable += 2; break;
174: case 2: put_byte(dptr, get_byte(inittable)); dptr += 1; inittable += 1; break;
175: }
176: }
177: } else {
178: ULONG data;
179: switch (srcloc) {
180: case 0: data = get_byte(inittable); inittable += 1; break;
181: case 1: data = get_word(inittable); inittable += 2; break;
182: case 2: data = get_long(inittable); inittable += 4; break;
183: default: data = 0; /* Alert */ break;
184: }
185: for(; count > 0; count--) {
186: switch (srcloc) {
187: case 0: put_long(dptr, data); dptr += 4; break;
188: case 1: put_word(dptr, data); dptr += 2; break;
189: case 2: put_byte(dptr, data); dptr += 1; break;
190: }
191: }
192: }
193: }
194: }
195: /* The size parameter sometimes seems to contain garbage in the top 16 bit */
196: static ULONG execl_InitStruct(void) { EXEC_InitStruct(regs.a[1], regs.a[2], regs.d[0] & 0xFFFF); return 0; }
197:
198: /*
199: * Interrupts
200: * This is all very confusing. As I see things, the IntVects field of the
201: * ExecBase is set up as follows:
202: * One interrupt may either be assigned an IntServer, or an IntHandler.
203: * PORTS, COPER, VERTB EXTER and NMI are set up as Servers (at least that's
204: * what the AutoDocs say), the others as IntHandlers.
205: * An IntServer field has a pointer to an Exec list in the iv_Data field,
206: * the list contains all the server Interrupt nodes in a nice chain. The
207: * iv_Node field is zero. For an IntHandler, the iv_Node field contains a
208: * pointer to the node that was passed in SetIntVector.
209: */
210:
211: CPTR EXEC_SetIntVector(int number, CPTR interrupt)
212: {
213: CPTR oldvec = get_long(sysbase + 84 + 12*number + 8);
214: if (interrupt == 0) {
215: put_long(sysbase + 84 + 12*number, 0);
216: put_long(sysbase + 84 + 12*number + 4, 0);
217: put_long(sysbase + 84 + 12*number + 8, 0);
218: } else {
219: put_long(sysbase + 84 + 12*number, get_long(interrupt + 14));
220: put_long(sysbase + 84 + 12*number + 4, get_long(interrupt + 18));
221: put_long(sysbase + 84 + 12*number + 8, interrupt);
222: }
223: return oldvec;
224: }
225:
226: void EXEC_RemIntServer(ULONG nr, CPTR interrupt)
227: {
228: CPTR list = get_long(sysbase + 84 + nr*12);
229:
230: EXEC_Remove(interrupt);
231: /* Disable interrupt if necessary */
232: if (get_long(get_long(list)) == 0)
233: put_word(0xDFF09A, 1 << nr);
234: }
235:
236: void EXEC_AddIntServer(ULONG nr, CPTR interrupt)
237: {
238: CPTR list = get_long(sysbase + 84 + nr*12);
239: int was_empty;
240:
241: /* Disable interrupt if necessary */
242: was_empty = get_long(get_long(list)) == 0;
243:
244: EXEC_Enqueue(list, interrupt);
245: if (was_empty)
246: put_word(0xDFF09A, 0x8000 | (1 << nr));
247:
248: }
249:
250: static ULONG execl_SetIntVector(void) { return EXEC_SetIntVector(regs.d[0], regs.a[1]); }
251: static ULONG execl_AddIntServer(void) { EXEC_AddIntServer(regs.d[0] & 15, regs.a[1]); return 0; }
252: static ULONG execl_RemIntServer(void) { EXEC_RemIntServer(regs.d[0] & 15, regs.a[1]); return 0; }
253:
254: /*
255: * Memory functions
256: */
257:
258: #define MEMF_PUBLIC 1
259: #define MEMF_CHIP 2
260: #define MEMF_FAST 4
261: #define MEMF_LOCAL 256
262: #define MEMF_24BITDMA 512
263: #define MEMF_CLEAR (1<<16)
264: #define MEMF_LARGEST (1<<17)
265: #define MEMF_REVERSE (1<<18)
266: #define MEMF_TOTAL (1<<19)
267:
268: CPTR EXEC_Allocate(CPTR memheader, unsigned long size)
269: {
270: CPTR chunk, chunkpp;
271: unsigned long avail;
272:
273: size = (size + 7) & ~7;
274:
275: if (size == 0 || size > get_long(memheader + 28))
276: return 0;
277:
278: for (chunk = get_long(chunkpp = memheader + 16); chunk != 0; chunkpp = chunk, chunk = get_long(chunk))
279: if ((avail = get_long(chunk + 4)) >= size) {
280: CPTR nextchunk = get_long(chunk);
281: if (avail-size == 0)
282: put_long(chunkpp, nextchunk);
283: else {
284: put_long(chunkpp, chunk + size);
285: put_long(chunk + size, nextchunk);
286: put_long(chunk + size + 4, avail - size);
287: }
288: put_long(memheader + 28, get_long(memheader + 28) - size);
289: return chunk;
290: }
291: return 0;
292: }
293:
294: void EXEC_Deallocate(CPTR memheader, CPTR addr, unsigned long size)
295: {
296: CPTR chunk, chunkpp;
297: CPTR areaend;
298:
299: if (addr == 0)
300: return;
301:
302: size = (size + 7) & ~7;
303: areaend = addr + size;
304:
305: put_long(memheader + 28, get_long(memheader + 28) + size);
306:
307: for (chunk = get_long(chunkpp = memheader + 16); chunk != 0; chunkpp = chunk, chunk = get_long(chunk)) {
308: if (chunk + get_long(chunk + 4) == addr) {
309: /* Merge with this and go ahead so we can also merge with the next */
310: put_long(chunkpp, get_long(chunk));
311: addr = chunk; size += get_long(chunk + 4);
312: chunk = chunkpp;
313: continue;
314: }
315: if (areaend == chunk) {
316: /* Merge with previous */
317: put_long(chunkpp, addr);
318: put_long(addr, get_long(chunk));
319: put_long(addr + 4, get_long(chunk + 4) + size);
320: return;
321: }
322: if (chunk > addr)
323: break;
324: }
325: put_long(chunkpp, addr);
326: put_long(addr, chunk);
327: put_long(addr + 4, size);
328: }
329:
330: CPTR EXEC_AllocMem(unsigned long size, ULONG requirements)
331: {
332: CPTR nextmh, memheader = get_long(sysbase + 322);
333: ULONG attrs = requirements & (MEMF_PUBLIC | MEMF_CHIP | MEMF_FAST);
334: CPTR result = 0;
335:
336: size = (size + 7) & ~7;
337:
338: for (;(nextmh = get_long(memheader)) != 0; memheader = nextmh) {
339: if ((get_word(memheader + 14) & attrs) != attrs)
340: continue;
341: result = EXEC_Allocate(memheader, size);
342: if (result != 0)
343: break;
344: }
345: if (result) {
346: if (requirements & MEMF_CLEAR)
347: memset(get_real_address(result), 0, size);
348: }
349: return result;
350: }
351:
352: CPTR EXEC_AllocEntry(CPTR ml)
353: {
354: CPTR newml = EXEC_AllocMem(16 + 8*get_word(ml + 14), MEMF_PUBLIC|MEMF_CLEAR);
355: int i;
356:
357: if (newml == 0)
358: return 0x80000000|MEMF_PUBLIC;
359: for (i = 0; i < get_word(ml + 14); i++) {
360: ULONG reqs = get_long(ml + 16 + 8*i);
361: ULONG addr = EXEC_AllocMem(get_long(ml + 16 + 8*i + 4), reqs);
362: if (addr == 0)
363: /* Thank god for SetPatch */
364: return 0x80000000 | reqs;
365: put_long(newml + 16 + 8*i, addr);
366: put_long(newml + 16 + 8*i + 4, reqs);
367: }
368: return newml;
369: }
370:
371: void EXEC_FreeMem(CPTR addr, unsigned long size)
372: {
373: CPTR nextmh, memheader = get_long(sysbase + 322);
374:
375: size = (size + 7) & ~7;
376: if (addr == 0)
377: return;
378:
379: for (;(nextmh = get_long(memheader)) != 0; memheader = nextmh) {
380: if (get_long(memheader + 20) <= addr
381: && get_long(memheader + 24) > addr) {
382: EXEC_Deallocate(memheader, addr, size);
383: return;
384: }
385: }
386: }
387:
388: unsigned long EXEC_AvailMem(ULONG requirements)
389: {
390: ULONG attrs = requirements & (MEMF_PUBLIC | MEMF_CHIP | MEMF_FAST);
391: CPTR nextmh, memheader = get_long(sysbase + 322);
392: CPTR result = 0;
393:
394: for (;(nextmh = get_long(memheader)) != 0; memheader = nextmh) {
395: if ((get_word(memheader + 14) & attrs) != attrs)
396: continue;
397: if (attrs & MEMF_LARGEST) {
398: unsigned long maxsize = 0;
399: CPTR chunk;
400: for (chunk = get_long(memheader + 16); chunk != 0; chunk = get_long(chunk))
401: if (get_long(chunk+4) > maxsize)
402: maxsize = get_long(chunk + 4);
403: result += maxsize;
404: } else if (attrs & MEMF_TOTAL) {
405: result += get_long(memheader + 24) - get_long(memheader + 20);
406: } else result += get_long(memheader + 28);
407: }
408: return result;
409: }
410:
411: void EXEC_AddMemList(unsigned long size, ULONG attrs, int pri, CPTR base,
412: CPTR name)
413: {
414: put_byte(base + 8, 0);
415: put_byte(base + 9, pri);
416: put_long(base + 10, name);
417: put_word(base + 14, attrs);
418: put_long(base + 16, base + 32);
419: put_long(base + 20, base + 32);
420: put_long(base + 36, size - 32);
421: put_long(base + 28, size - 32);
422: put_long(base + 24, base + size);
423: EXEC_Enqueue(sysbase + 322, base);
424: }
425:
426: static ULONG execl_AddMemList(void)
427: {
428: EXEC_AddMemList(regs.d[0], regs.d[1], (LONG)regs.d[2], regs.a[0], regs.a[1]);
429: return 0;
430: }
431:
432: static ULONG execl_CopyMem(void)
433: {
434: UBYTE *src = get_real_address(regs.a[0]);
435: UBYTE *dst = get_real_address(regs.a[1]);
436:
437: if (src != NULL && dst != NULL
438: && valid_address(regs.a[0], regs.d[0])
439: && valid_address(regs.a[1], regs.d[0]))
440: memcpy(dst, src, regs.d[0]);
441: else
442: fprintf(stderr, "CopyMem with bogus parameters\n");
443: return 0;
444: }
445:
446: static ULONG execl_AllocMem(void) { return EXEC_AllocMem(regs.d[0], regs.d[1]); }
447: static ULONG execl_AllocEntry(void) { return EXEC_AllocEntry(regs.a[0]); }
448: static ULONG execl_Allocate(void) { return EXEC_Allocate(regs.a[0], regs.d[0]); }
449: static ULONG execl_FreeMem(void) { EXEC_FreeMem(regs.a[1], regs.d[0]); return 0; }
450: static ULONG execl_AvailMem(void) { return EXEC_AvailMem(regs.d[1]); }
451: static ULONG execl_Deallocate(void) { EXEC_Deallocate(regs.a[0], regs.a[1], regs.d[0]); return 0; }
452:
453: /*
454: * Scheduling
455: */
456:
457: #define TS_RUN 2
458: #define TS_READY 3
459: #define TS_WAIT 4
460: #define TS_EXCEPT 5
461:
462: struct NewTask {
463: struct NewTask *next, *prev;
464: CPTR exectask;
465: #ifdef USE_EXECLIB
466: jmp_buf j;
467: #endif
468: void *stack;
469: struct regstruct regs;
470: struct flag_struct flags;
471: };
472:
473: static struct NewTask idle_task;
474: static int intr_count, need_resched;
475:
476: static struct NewTask *find_newtask(CPTR task)
477: {
478: /* Ugh, this is ugly */
479: struct NewTask *t = &idle_task;
480: do {
481: if (t->exectask == task)
482: return t;
483: t = t->next;
484: } while (t != &idle_task);
485: fprintf(stderr, "Uh oh. Task list corrupt\n");
486: }
487:
488: static void schedule(void)
489: {
490: #ifdef USE_EXECLIB
491: CPTR readylist = sysbase + 406;
492: CPTR readytask = get_long(readylist);
493: CPTR runtask = get_long(sysbase + 276);
494: struct NewTask *runtask_nt, *readytask_nt;
495: unsigned long oldflags;
496:
497: int idis;
498:
499: need_resched = 0;
500: /* Any ready tasks? */
501: if (get_long(readytask) == 0)
502: return;
503:
504: /* If the running task is going to sleep, don't check priorities*/
505: if (get_byte(runtask + 15) != TS_WAIT) {
506: /* Has the running task a higher priority than any ready tasks? */
507: if ((BYTE)get_byte(runtask + 9) > (BYTE)get_byte(readytask + 9))
508: return;
509: /* We should only preempt a task of the same priority if the quantum
510: * has expired. Hmmm... */
511: }
512: if (get_byte(runtask + 15) == TS_RUN)
513: put_byte(runtask + 15, TS_READY);
514: if (get_byte(runtask + 15) == TS_WAIT)
515: EXEC_Enqueue(sysbase + 420, runtask);
516: else
517: EXEC_Enqueue(readylist, runtask);
518: put_byte(readytask + 15, TS_RUN);
519: EXEC_Remove(readytask);
520:
521: readytask_nt = find_newtask(readytask);
522: runtask_nt = find_newtask(runtask);
523:
524:
525: oldflags = regs.spcflags;
526: runtask_nt->regs = regs;
527: runtask_nt->flags = regflags;
528: regs = readytask_nt->regs;
529: regflags = readytask_nt->flags;
530: regs.spcflags = (regs.spcflags & ~PRESERVED_FLAGS) | (oldflags & PRESERVED_FLAGS);
531:
532: put_byte(runtask + 16, get_byte(sysbase + 294));
533: put_byte(runtask + 17, get_byte(sysbase + 295));
534: put_byte(sysbase + 294, idis = get_byte(readytask + 16));
535: put_byte(sysbase + 295, get_byte(readytask + 17));
536: put_long(sysbase + 276, readytask);
537: /* Set INTENA according to new interrupt enable status */
538: if (idis == 0xFF)
539: put_word(0xDFF09A, 0xC000);
540: else
541: put_word(0xDFF09A, 0x4000);
542: /* Whee... */
543: fprintf(stderr, "Task switch: new task %s\n", get_real_address(get_long(readytask + 10)));
544: if (setjmp(runtask_nt->j) == 0)
545: longjmp(readytask_nt->j, 1);
546: regs.spcflags &= ~SPCFLAG_BRK;
547: #endif
548: }
549:
550: static __inline__ void maybe_schedule(void)
551: {
552: /* @@@ Should we avoid a schedule when supervisor bit is set?
553: * Definitely not if the running task is the idle task */
554: if (intr_count == 0 && get_byte(sysbase + 294) == 0xFF && get_byte(sysbase + 295) == 0xFF && need_resched)
555: schedule();
556: }
557:
558: /*
559: * Signals
560: */
561:
562: int EXEC_AllocSignal(int signum)
563: {
564: CPTR thistask = get_long(sysbase + 276);
565: ULONG sigalloc = get_long(thistask + 18);
566: if (signum == -1)
567: for (signum = 0; signum < 32; signum++)
568: if ((sigalloc & (1 << signum)) == 0)
569: break;
570:
571: if ((sigalloc & (1 << signum)) == 0) {
572: put_long(thistask + 18, sigalloc | (1 << signum));
573: } else
574: signum = -1;
575:
576: return signum;
577: }
578:
579: void EXEC_FreeSignal(int signum)
580: {
581: CPTR thistask = get_long(sysbase + 276);
582: if (signum != -1)
583: return;
584: put_long(thistask + 18, get_long(thistask + 18) & ~(1 << signum));
585: }
586:
587: ULONG EXEC_SetSignal(ULONG newsig, ULONG exec_sigmask)
588: {
589: CPTR task = get_long(sysbase + 276);
590: ULONG signals = get_long(task + 26);
591: /* @@@ check SigExcept here */
592: put_long(task + 26, (signals & ~exec_sigmask) | (newsig & exec_sigmask));
593: return signals;
594: }
595:
596: void EXEC_Signal(CPTR task, ULONG exec_sigmask)
597: {
598: ULONG exec_sigs = get_long(task + 26);
599: ULONG sigwait = get_long(task + 22);
600: put_long(task + 26, exec_sigs | exec_sigmask);
601: if (get_byte(task + 15) == TS_WAIT && (sigwait & exec_sigmask) != 0) {
602: EXEC_Remove(task);
603: EXEC_Enqueue(sysbase + 406, task);
604: need_resched = 1;
605: maybe_schedule();
606: }
607: }
608:
609: ULONG EXEC_Wait(ULONG exec_sigmask)
610: {
611: CPTR task = get_long(sysbase + 276);
612: ULONG exec_sigs = get_long(task + 26);
613: if ((exec_sigs & exec_sigmask) != 0) {
614: put_long(task + 26, exec_sigs & ~exec_sigmask);
615: return exec_sigs & exec_sigmask;
616: }
617: if (get_byte(sysbase + 294) != 0xFF || get_byte(sysbase + 295) != 0xFF)
618: {
619: fprintf(stderr, "Arrgh, task Wait()ing when it shouldn't\n");
620: }
621: if (intr_count || regs.s) {
622: fprintf(stderr, "Arrgh, task Wait()ing when it _really_ shouldn't\n");
623: }
624:
625: put_byte(task + 15, TS_WAIT);
626: put_long(task + 22, exec_sigmask);
627: schedule();
628: exec_sigs = get_long(task + 26);
629: if ((exec_sigs & exec_sigmask) != 0) {
630: put_long(task + 26, exec_sigs & ~exec_sigmask);
631: return exec_sigs & exec_sigmask;
632: }
633: fprintf(stderr, "Bug: task woke up without signals\n");
634: return 0;
635: }
636:
637: static ULONG execl_SetSignal(void) { return EXEC_SetSignal(regs.d[0], regs.d[1]); }
638: static ULONG execl_Signal(void) { EXEC_Signal(regs.a[1], regs.d[0]); return 0; }
639: static ULONG execl_Wait(void) { return EXEC_Wait(regs.d[0]); }
640: static ULONG execl_AllocSignal(void) { return EXEC_AllocSignal((BYTE)regs.d[0]); }
641: static ULONG execl_FreeSignal(void) { EXEC_FreeSignal((BYTE)regs.d[0]); return 0; }
642:
643: /*
644: * Semaphores
645: */
646:
647: void EXEC_InitSemaphore(CPTR exec_sigsem)
648: {
649: EXEC_NewList(exec_sigsem + 16);
650: put_word(exec_sigsem + 14, 0);
651: put_word(exec_sigsem + 44, 0xFFFF);
652: }
653:
654: ULONG EXEC_AttemptSemaphore(CPTR exec_sigsem)
655: {
656: CPTR task = get_long(sysbase + 276);
657: UWORD count = get_word(exec_sigsem + 44);
658: if (count == 0xFFFF) {
659: /* Semaphore free -> lock it */
660: put_word(exec_sigsem + 44, 0);
661: put_long(exec_sigsem + 40, task);
662: put_word(exec_sigsem + 14, 1);
663: return 1;
664: }
665: if (get_long(exec_sigsem + 40) == task) {
666: /* Locked by same task -> Increment NestCount */
667: put_word(exec_sigsem + 14, get_word(exec_sigsem + 14) + 1);
668: return 1;
669: }
670: return 0;
671: }
672:
673: void EXEC_ObtainSemaphore(CPTR exec_sigsem)
674: {
675: CPTR task = get_long(sysbase + 276);
676: UWORD count = get_word(exec_sigsem + 44);
677: if (count == 0xFFFF) {
678: /* Semaphore free -> lock it */
679: put_word(exec_sigsem + 44, 0);
680: put_long(exec_sigsem + 40, task);
681: put_word(exec_sigsem + 14, 1);
682: return;
683: }
684: if (get_long(exec_sigsem + 40) == task) {
685: /* Locked by same task -> Increment NestCount */
686: put_word(exec_sigsem + 14, get_word(exec_sigsem + 14) + 1);
687: return;
688: }
689: /* Need to wait. */
690: /* @@@ None of the predefined signals in exec/tasks.h seem to be used
691: * for this. We use 0x8000, which appears not to be used otherwise */
692: put_word(exec_sigsem + 44, count + 1);
693: EXEC_AddTail(exec_sigsem + 16, task);
694: if (EXEC_Wait(0x8000) != 0x8000)
695: fprintf(stderr, "BUG\n");
696:
697: /* Now it's mine, all mine! */
698: put_long(exec_sigsem + 40, task);
699: put_word(exec_sigsem + 14, 1);
700: }
701:
702: void EXEC_ReleaseSemaphore(CPTR exec_sigsem)
703: {
704: UWORD nest = get_word(exec_sigsem + 14);
705: put_word(exec_sigsem + 14, nest - 1);
706: if (nest == 1) {
707: /* We're losing it. Signal the first task on the wait queue
708: * (that one will in turn wake the next, etc.) */
709: CPTR task = EXEC_RemHead(exec_sigsem + 16);
710: UWORD count = get_word(exec_sigsem + 44);
711: put_word(exec_sigsem + 44, count - 1);
712: if (task) {
713: EXEC_Signal(task, 0x8000);
714: }
715: }
716: }
717:
718: static ULONG execl_ObtainSemaphore(void) { EXEC_ObtainSemaphore(regs.a[0]); return 0; }
719: static ULONG execl_ReleaseSemaphore(void) { EXEC_ReleaseSemaphore(regs.a[0]); return 0; }
720: static ULONG execl_FindSemaphore(void) { return EXEC_FindName(sysbase + 532, get_real_address(regs.a[1])); }
721: static ULONG execl_InitSemaphore(void) { EXEC_InitSemaphore(regs.a[0]); return 0; }
722: static ULONG execl_AttemptSemaphore(void) { return EXEC_AttemptSemaphore(regs.a[0]); }
723: static ULONG execl_AddSemaphore(void) { put_byte(regs.a[1] + 8, 15); EXEC_Enqueue(sysbase + 532, regs.a[1]); return 0; }
724:
725: /*
726: * Messages and ports
727: */
728:
729: CPTR EXEC_GetMsg(CPTR port)
730: {
731: return EXEC_RemHead(port + 20);
732: }
733:
734: /* This is shared between PutMsg and ReplyMsg */
735: static void EXEC_doputmsg(CPTR port, CPTR msg)
736: {
737: UBYTE flags = get_byte (port + 14);
738: EXEC_AddTail(port + 20, msg);
739: if (flags == 0)
740: EXEC_Signal(get_long(port + 16), 1 << get_byte(port + 15));
741: else if (flags == 1)
742: fprintf(stderr, "PA_SOFTINT unsupported\n");
743:
744: }
745:
746: void EXEC_PutMsg(CPTR port, CPTR msg)
747: {
748: put_byte(msg + 8, 5);
749: EXEC_doputmsg(port, msg);
750: }
751:
752: void EXEC_ReplyMsg(CPTR msg)
753: {
754: put_byte(msg + 8, 7);
755: EXEC_doputmsg(get_long(msg + 14), msg);
756: }
757:
758: CPTR EXEC_WaitPort(CPTR port)
759: {
760: for (;;) {
761: CPTR msg = get_long(port + 20);
762: if (get_long(msg) != 0)
763: return msg;
764: if (get_byte(port + 14) != 0)
765: fprintf(stderr, "Don't know how to WaitPort()\n");
766: EXEC_Wait(1 << get_byte(port + 15));
767: }
768: }
769:
770: static ULONG execl_GetMsg(void) { return EXEC_GetMsg(regs.a[0]); }
771: static ULONG execl_PutMsg(void) { EXEC_PutMsg(regs.a[0], regs.a[1]); return 0; }
772: static ULONG execl_ReplyMsg(void) { EXEC_ReplyMsg(regs.a[1]); return 0; }
773: static ULONG execl_WaitPort(void) { return EXEC_WaitPort(regs.a[0]); }
774: static ULONG execl_FindPort(void) { return EXEC_FindName(sysbase + 392, get_real_address(regs.a[1])); }
775: static ULONG execl_AddPort(void) { put_byte(regs.a[1] + 8, 4); EXEC_Enqueue(sysbase + 392, regs.a[1]); return 0; }
776:
777: /*
778: * I/O
779: */
780:
781: LONG EXEC_WaitIO(CPTR ioreq)
782: {
783: /* The device is supposed to clear the IO_QUICK bit if it's going to
784: * reply to the command */
785: if ((get_byte(ioreq + 30) & 1) == 1)
786: return (LONG)(BYTE)get_byte(ioreq + 31);
787:
788: for (;;) {
789: if (get_byte(ioreq + 8) == 7) /* NT_REPLYMSG? */
790: break;
791: /* We'll just hope that this a) has a ReplyPort and b) that port
792: * is of type PA_SIGNAL
793: * Don't WaitPort() here: WaitPort() returns a message, and we
794: * aren't sure it's for us. */
795:
796: EXEC_Wait(1 << get_byte(get_long(ioreq + 14) + 15));
797: }
798: EXEC_Remove(ioreq);
799: return (LONG)(BYTE)get_byte(ioreq + 31);
800: }
801:
802: static void EXEC_BeginIO(CPTR ioreq)
803: {
804: CPTR dev = get_long(ioreq + 20);
805: regs.a[6] = dev;
806: regs.a[1] = ioreq;
807: Call68k(dev - 30, 1);
808: }
809:
810: void EXEC_DoIO(CPTR ioreq)
811: {
812: put_byte(ioreq + 30, 1);
813: EXEC_BeginIO(ioreq);
814: EXEC_WaitIO(ioreq);
815: }
816:
817: void EXEC_SendIO(CPTR ioreq)
818: {
819: put_byte(ioreq + 30, 0);
820: EXEC_BeginIO(ioreq);
821: }
822:
823: CPTR EXEC_CheckIO(CPTR ioreq)
824: {
825: if ((get_byte(ioreq + 30) & 1) == 1)
826: return ioreq;
827: if (get_byte(ioreq + 8) == 7)
828: return ioreq;
829: return 0;
830: }
831:
832: static ULONG execl_WaitIO(void) { return EXEC_WaitIO(regs.a[1]); }
833: static ULONG execl_DoIO(void) { EXEC_DoIO(regs.a[1]); return 0; }
834: static ULONG execl_SendIO(void) { EXEC_SendIO(regs.a[1]); return 0; }
835: static ULONG execl_CheckIO(void) { return EXEC_CheckIO(regs.a[1]); }
836:
837: /*
838: * Libraries
839: */
840:
841: void EXEC_SumLibrary(CPTR lib)
842: {
843: CPTR start = lib - get_word(lib + 16);
844: int len = get_word(lib + 16) + get_word(lib + 18);
845: ULONG sum = 0;
846: UWORD flags = get_word(lib + 14);
847:
848: if (flags & 1) /* SUMMING? */
849: return;
850: if (!(flags & 4)) /* SUMUSED? */
851: return;
852: put_word(lib + 14, flags & ~2); /* mark as not changed */
853: /* Pretend the checksum is OK, I don't care enough */
854: }
855:
856: CPTR EXEC_SetFunction(CPTR lib, int funcOffset, CPTR function)
857: {
858: CPTR oldfunc = get_long(lib + funcOffset + 2);
859: put_word(lib + funcOffset, 0x4EF9);
860: put_long(lib + funcOffset + 2, function);
861: put_word(lib + 14, get_word(lib + 14) | 2);
862: EXEC_SumLibrary(lib);
863: return oldfunc;
864: }
865:
866: void EXEC_AddLibrary(CPTR lib)
867: {
868: EXEC_Enqueue(sysbase + 378, lib);
869: put_word(lib + 14, 2); /* mark as changed */
870: EXEC_SumLibrary(lib);
871: }
872:
873: CPTR EXEC_OpenLibrary(char *name, int version)
874: {
875: CPTR lib = EXEC_FindName(sysbase + 378, name);
876: if (lib != 0) {
877: regs.a[6] = lib;
878: regs.d[0] = version;
879: lib = Call68k(lib - 6, 1);
880: }
881: return lib;
882: }
883:
884: CPTR EXEC_OpenDevice(char *name, ULONG unit, CPTR ioRequest, ULONG flags)
885: {
886: CPTR dev = EXEC_FindName(sysbase + 350, name);
887: CPTR replyport = get_long(ioRequest + 14);
888: put_long(ioRequest + 20, dev);
889: put_byte(ioRequest + 31, 0);
890: put_byte(ioRequest + 30, flags); /* is this right? */
891: if (replyport == 0)
892: fprintf(stderr, "ioRequest has no ReplyPort\n");
893: else {
894: CPTR rtask = get_long(replyport + 16);
895: if (rtask == 0)
896: fprintf(stderr, "replyTask == 0\n");
897: else if (rtask != get_long(sysbase + 276))
898: fprintf(stderr, "replyTask != current\n");
899: /* put_long(replyport + 16, get_long(sysbase + 276));*/
900: }
901: if (dev != 0) {
902: regs.a[6] = dev;
903: regs.a[1] = ioRequest;
904: regs.d[0] = unit;
905: regs.d[1] = flags;
906: dev = Call68k(dev - 6, 1);
907: }
908: return (LONG)(BYTE)get_byte(ioRequest + 31);
909: }
910:
911: void EXEC_AddDevice(CPTR lib)
912: {
913: EXEC_Enqueue(sysbase + 350, lib);
914: }
915:
916: void EXEC_AddResource(CPTR lib)
917: {
918: EXEC_Enqueue(sysbase + 336, lib);
919: }
920:
921: CPTR EXEC_OpenResource(char *name)
922: {
923: CPTR lib = EXEC_FindName(sysbase + 336, name);
924: return lib;
925: }
926:
927: void EXEC_MakeFunctions(CPTR target, CPTR funcarray, CPTR funcdispb)
928: {
929: if (funcdispb != 0) {
930: WORD tmp;
931: for (;;) {
932: tmp = get_word(funcarray); funcarray += 2;
933: if (tmp == -1)
934: break;
935: target -= 6;
936: put_word(target, 0x4EF9); /* JMP.L */
937: put_long(target + 2, funcdispb + tmp);
938: }
939: } else {
940: CPTR tmp;
941: for (;;) {
942: tmp = get_long(funcarray); funcarray += 4;
943: if (tmp == (CPTR)-1)
944: break;
945: target -= 6;
946: put_word(target, 0x4EF9); /* JMP.L */
947: put_long(target + 2, tmp);
948: }
949: }
950: }
951:
952: /* This doesn't work yet */
953: CPTR EXEC_MakeLibrary(CPTR vectors, CPTR structure, CPTR init,
954: unsigned long dsize, ULONG seglist_b)
955: {
956: CPTR seglist = seglist_b << 2;
957: int vec_cnt = 0;
958: unsigned long negsize;
959: CPTR base, fdispb = 0, funcarray = vectors;
960: ULONG retval = 0;
961:
962: fprintf(stderr, "MakeLibrary\n");
963: if (get_word (vectors) == (UWORD)-1) {
964: int offs = 2;
965: fdispb = vectors;
966: funcarray += 2;
967: while (get_word (vectors+offs) != (UWORD)-1) {
968: offs += 2;
969: vec_cnt++;
970: }
971: } else {
972: int offs = 0;
973: while (get_long (vectors+offs) != (LONG)-1) {
974: offs += 4;
975: vec_cnt++;
976: }
977: }
978: negsize = (vec_cnt * 6 + 3) & ~3;
979: dsize = (dsize + 3) & ~3;
980:
981: base = EXEC_AllocMem(negsize + dsize, MEMF_PUBLIC|MEMF_CLEAR);
982: if (base == 0) /* Uh oh */
983: return 0;
984: EXEC_MakeFunctions(base + negsize, funcarray, fdispb);
985: base += negsize;
986: put_word(base + 16, negsize);
987: put_word(base + 18, dsize);
988: if (structure != 0) {
989: /* Size is set to 0 so we won't clear it again */
990: EXEC_InitStruct(structure, base, 0);
991: }
992: if (init != 0) {
993: regs.a[6] = sysbase;
994: regs.a[0] = seglist_b; /* BCPL seglist here? */
995: regs.d[0] = base;
996: /* call it */
997: retval = Call68k(init, 0);
998: } else
999: retval = base;
1000:
1001: return retval;
1002: }
1003:
1004: CPTR EXEC_InitResident(CPTR resident, ULONG segList)
1005: {
1006: UBYTE flags = get_byte(resident + 10);
1007:
1008: if (flags & 0x80) {
1009: CPTR autoinit = get_long(resident + 22);
1010: return EXEC_MakeLibrary(get_long(autoinit + 4), get_long(autoinit + 8),
1011: get_long(autoinit + 12), get_long(autoinit), segList >> 4);
1012: }
1013:
1014: regs.d[0] = 0; regs.a[0] = segList; regs.a[6] = sysbase;
1015: return Call68k(get_long(resident + 22), 0);
1016: }
1017:
1018: static ULONG execl_MakeFunctions(void) { EXEC_MakeFunctions(regs.a[0], regs.a[1], regs.a[2]); return 0; }
1019: static ULONG execl_SumLibrary(void) { EXEC_SumLibrary(regs.a[1]); return 0; }
1020: static ULONG execl_SetFunction(void) { return EXEC_SetFunction(regs.a[1], (WORD)regs.a[0], regs.d[0]); }
1021: static ULONG execl_AddLibrary(void) { EXEC_AddLibrary(regs.a[1]); return 0; }
1022: static ULONG execl_AddDevice(void) { EXEC_AddDevice(regs.a[1]); return 0; }
1023: static ULONG execl_AddResource(void) { EXEC_AddResource(regs.a[1]); return 0; }
1024: static ULONG execl_OpenLibrary(void) { return EXEC_OpenLibrary(get_real_address(regs.a[1]), regs.d[0]); }
1025: static ULONG execl_OpenDevice(void) { return EXEC_OpenDevice(get_real_address(regs.a[0]), regs.d[0], regs.a[1], regs.d[1]); }
1026: static ULONG execl_OpenResource(void) { return EXEC_OpenResource(get_real_address(regs.a[1])); }
1027: static ULONG execl_MakeLibrary(void) { return EXEC_MakeLibrary(regs.a[0], regs.a[1], regs.a[2], regs.d[0], regs.d[1]); }
1028:
1029: /*
1030: * Tasks
1031: */
1032:
1033: static void task_startup(void)
1034: {
1035: m68k_setpc(regs.pc);
1036: Call68k_retaddr(regs.pc, 0, get_long(regs.a[7] - 4));
1037: fprintf(stderr, "Task fell through at the end\n");
1038: }
1039:
1040: CPTR EXEC_AddTask(CPTR task, CPTR initPC, CPTR finalPC)
1041: {
1042: #ifdef USE_EXECLIB
1043: struct NewTask *nt = (struct NewTask *)malloc(sizeof (struct NewTask));
1044: nt->exectask = task;
1045: nt->prev = &idle_task;
1046: nt->next = idle_task.next;
1047: idle_task.next->prev = nt;
1048: idle_task.next = nt;
1049: memset(&nt->regs, 0, sizeof (nt->regs));
1050: nt->regs.pc = initPC;
1051: nt->regs.a[7] = get_long(task + 54);
1052:
1053: if (finalPC == 0)
1054: finalPC = 0xF0FFF0; /* standard "return from 68k mode" calltrap */
1055: put_byte(task + 16, 0xFF);
1056: put_byte(task + 17, 0xFF);
1057: put_long(nt->regs.a[7] - 4, finalPC);
1058: nt->stack = malloc(65536); /* @@@ make this smaller after checking that
1059: * no parts of the emulator need much stack
1060: * space */
1061: nt->j[0].__sp = nt->stack + 65536;
1062: nt->j[0].__pc = &task_startup;
1063: put_byte(task + 15, TS_READY);
1064: put_long(task + 18,0x0000FFFF); /* all tasks have the lower 16 signals allocated */
1065: EXEC_Enqueue(sysbase + 406, task);
1066: need_resched = 1;
1067: maybe_schedule();
1068: return task;
1069: #endif
1070: }
1071:
1072: CPTR EXEC_FindTask(char *name)
1073: {
1074: char *n;
1075: CPTR v;
1076:
1077: if (name == NULL || ((n = get_real_address(get_long(get_long(sysbase + 276) + 10))) != NULL
1078: && strcmp(n, name) == 0))
1079: return get_long(sysbase + 276);
1080:
1081: v = EXEC_FindName(sysbase + 406, name); /* ready tasks */
1082: if (v != 0)
1083: return v;
1084: return EXEC_FindName(sysbase + 420, name); /* waiting tasks */
1085: }
1086:
1087: static ULONG execl_FindTask(void) { return EXEC_FindTask(regs.a[1] == 0 ? NULL : get_real_address(regs.a[1])); }
1088: static ULONG execl_AddTask(void) { return EXEC_AddTask(regs.a[1], regs.a[2], regs.a[3]); }
1089:
1090: ULONG EXEC_Forbid(void)
1091: {
1092: int count = (BYTE)get_byte(sysbase + 295);
1093: count++;
1094: put_byte(sysbase + 295, count);
1095: return 0;
1096: }
1097: ULONG EXEC_Permit(void)
1098: {
1099: int count = (BYTE)get_byte(sysbase + 295);
1100: if (count == -1)
1101: fprintf(stderr, "Too many Permit() calls\n");
1102: else
1103: count--;
1104: put_byte(sysbase + 295, count);
1105: maybe_schedule();
1106: return 0;
1107: }
1108:
1109: ULONG EXEC_Disable(void)
1110: {
1111: int count = (BYTE)get_byte(sysbase + 294);
1112: count++;
1113: put_byte(sysbase + 294, count);
1114: put_word(0xDFF09A, 0x4000);
1115: return 0;
1116: }
1117:
1118: ULONG EXEC_Enable(void)
1119: {
1120: int count = (BYTE)get_byte(sysbase + 294);
1121: if (count == -1)
1122: fprintf(stderr, "Too many Enable() calls\n");
1123: else
1124: count--;
1125: if (count == -1)
1126: put_word(0xDFF09A, 0xC000);
1127: put_byte(sysbase + 294, count);
1128: maybe_schedule();
1129: return 0;
1130: }
1131: /*
1132: * Initialization
1133: */
1134: static ULONG execlib_init(void)
1135: {
1136: sysbase = get_long(4);
1137:
1138: /* CopyMem and CopyMemQuick */
1139: libemu_InstallFunction(execl_CopyMem, sysbase, -630);
1140: libemu_InstallFunction(execl_CopyMem, sysbase, -624);
1141: libemu_InstallFunction(execl_Allocate, sysbase, -186);
1142: libemu_InstallFunction(execl_AllocMem, sysbase, -198);
1143: libemu_InstallFunction(execl_Deallocate, sysbase, -192);
1144: libemu_InstallFunction(execl_FreeMem, sysbase, -210);
1145: libemu_InstallFunction(execl_AvailMem, sysbase, -216);
1146:
1147: /* List management */
1148: libemu_InstallFunction(execl_Insert, sysbase, -234);
1149: libemu_InstallFunction(execl_AddHead, sysbase, -240);
1150: libemu_InstallFunction(execl_AddTail, sysbase, -246);
1151: libemu_InstallFunction(execl_Enqueue, sysbase, -270);
1152: libemu_InstallFunction(execl_RemHead, sysbase, -258);
1153: libemu_InstallFunction(execl_RemTail, sysbase, -264);
1154: libemu_InstallFunction(execl_Remove, sysbase, -252);
1155: libemu_InstallFunction(execl_FindName, sysbase, -276);
1156:
1157: /* Signals */
1158: libemu_InstallFunction(execl_AllocSignal, sysbase, -330);
1159: libemu_InstallFunction(execl_FreeSignal, sysbase, -336);
1160:
1161: /* Semaphores */
1162: libemu_InstallFunction(execl_FindSemaphore, sysbase, -594);
1163: libemu_InstallFunction(execl_InitSemaphore, sysbase, -558);
1164: libemu_InstallFunction(execl_AddSemaphore, sysbase, -600);
1165:
1166: /* Messages/Ports */
1167: libemu_InstallFunction(execl_FindPort, sysbase, -390);
1168: libemu_InstallFunction(execl_GetMsg, sysbase, -372);
1169:
1170: /* Libraries */
1171: libemu_InstallFunction(execl_MakeFunctions, sysbase, -90);
1172: libemu_InstallFunction(execl_SumLibrary, sysbase, -426);
1173: libemu_InstallFunction(execl_SetFunction, sysbase, -420);
1174:
1175: /* Tasks */
1176: libemu_InstallFunction(execl_FindTask, sysbase, -294);
1177:
1178: /* Interrupts */
1179: libemu_InstallFunction(execl_SetIntVector, sysbase, -162);
1180: libemu_InstallFunction(execl_AddIntServer, sysbase, -168);
1181: libemu_InstallFunction(execl_RemIntServer, sysbase, -174);
1182:
1183: /* Miscellaneous */
1184: libemu_InstallFunction(execl_InitStruct, sysbase, -78);
1185:
1186: return 0;
1187: }
1188:
1189: static ULONG execlib_init2(void)
1190: {
1191: sysbase = get_long(4);
1192:
1193: libemu_InstallFunction(execl_AllocEntry, sysbase, -222);
1194:
1195: libemu_InstallFunction(execl_AddLibrary, sysbase, -396);
1196: libemu_InstallFunction(execl_AddDevice, sysbase, -432);
1197: libemu_InstallFunction(execl_AddResource, sysbase, -486);
1198: libemu_InstallFunction(execl_OpenLibrary, sysbase, -552);
1199: libemu_InstallFunction(execl_OpenDevice, sysbase, -444);
1200: libemu_InstallFunction(execl_OpenResource, sysbase, -498);
1201: libemu_InstallFunction(execl_MakeLibrary, sysbase, -84);
1202:
1203: libemu_InstallFunctionFlags(EXEC_Disable, sysbase, -120, TRAPFLAG_NORETVAL);
1204: libemu_InstallFunctionFlags(EXEC_Enable, sysbase, -126, TRAPFLAG_NORETVAL);
1205: libemu_InstallFunctionFlags(EXEC_Permit, sysbase, -138, TRAPFLAG_NORETVAL);
1206: libemu_InstallFunctionFlags(EXEC_Forbid, sysbase, -132, TRAPFLAG_NORETVAL);
1207:
1208: libemu_InstallFunction(execl_AddTask, sysbase, -282);
1209:
1210: libemu_InstallFunction(execl_SetSignal, sysbase, -306);
1211: libemu_InstallFunction(execl_Signal, sysbase, -324);
1212: libemu_InstallFunction(execl_Wait, sysbase, -318);
1213:
1214: libemu_InstallFunction(execl_PutMsg, sysbase, -366);
1215: libemu_InstallFunction(execl_ReplyMsg, sysbase, -378);
1216: libemu_InstallFunction(execl_WaitPort, sysbase, -384);
1217:
1218: libemu_InstallFunction(execl_WaitIO, sysbase, -474);
1219: libemu_InstallFunction(execl_DoIO, sysbase, -456);
1220: libemu_InstallFunction(execl_SendIO, sysbase, -462);
1221: libemu_InstallFunction(execl_CheckIO, sysbase, -468);
1222:
1223: libemu_InstallFunctionFlags(execl_ObtainSemaphore, sysbase, -564, TRAPFLAG_NORETVAL);
1224: libemu_InstallFunctionFlags(execl_ReleaseSemaphore, sysbase, -570, TRAPFLAG_NORETVAL);
1225: libemu_InstallFunction(execl_AttemptSemaphore, sysbase, -576);
1226:
1227: return 0;
1228: }
1229:
1230: /*
1231: * These functions are one day going to bootstrap the emulated Exec
1232: */
1233:
1234: #define NR_EXEC_FUNCTIONS 105 /* V34 (1.3) maximum */
1235:
1236: static ULONG EXEC_ENOSYS(void)
1237: {
1238: fprintf(stderr, "Not a system call\n");
1239: return 0;
1240: }
1241:
1242: static ULONG EXEC_StandardIntVec(void)
1243: {
1244: int num = regs.a[1];
1245: /* Call the IntHandlers */
1246: return 0;
1247: }
1248:
1249: static ULONG EXEC_IntTrap(void)
1250: {
1251: UWORD intsreq = get_word(0xDFF01E) & get_word(0xDFF01C);
1252: int i;
1253: intr_count++;
1254:
1255: for (i = 13; i >= 0; i--) {
1256: if ((intsreq & (1 << i)) != 0) {
1257: /* Is this a server chain? */
1258: if (i == 3 || i == 4 || i == 5 || i == 13 || i == 15) {
1259: CPTR slist = get_long(sysbase + 84 + 12*i);
1260: CPTR snode = get_long(slist);
1261: for (;;) {
1262: if (get_long(snode) == 0)
1263: break;
1264: regs.a[0] = 0xDFF000;
1265: regs.a[5] = get_long(snode + 18);
1266: regs.a[1] = get_long(snode + 14);
1267: Call68k(regs.a[5], 0);
1268: if (ZFLG == 0)
1269: break;
1270: snode = get_long(snode);
1271: }
1272: put_word(0xDFF09C, 1 << i);
1273: } else {
1274: CPTR intnode = get_long(sysbase + 84 + 12*i + 8);
1275: regs.d[1] = intsreq;
1276: regs.a[1] = get_long(intnode + 14);
1277: regs.a[0] = 0xDFF000;
1278: regs.a[5] = get_long(intnode + 18);
1279: regs.a[6] = sysbase;
1280: Call68k(regs.a[5], 0);
1281: }
1282: break;
1283: }
1284: }
1285: if (i < 0)
1286: fprintf(stderr, "So what interrupt am I supposed to serve?\n");
1287: intr_count--;
1288: maybe_schedule();
1289: }
1290:
1291: void execlib_sysinit(void)
1292: {
1293: CPTR tmp, tmp2;
1294: CPTR enosys = deftrap(EXEC_ENOSYS);
1295: CPTR intvec = deftrap(EXEC_StandardIntVec);
1296: CPTR inttrap = deftrap2(EXEC_IntTrap, TRAPFLAG_NORETVAL);
1297: CPTR sysstack;
1298: int i;
1299:
1300: tmp = here();
1301: calltrap2(enosys); dw(RTS);
1302:
1303: /* why 0x400? */
1304: sysbase = 0x400 + NR_EXEC_FUNCTIONS*6;
1305: memset(get_real_address(sysbase), 0, 558);
1306: put_long(4, sysbase);
1307:
1308: /* Build vectors. We initialize SetFunction so we can call execlib_Init() */
1309: tmp2 = here();
1310: calltrap(deftrap(execl_SetFunction));
1311: dw(RTS);
1312: for (i = 0; i < NR_EXEC_FUNCTIONS; i++) {
1313: put_word(sysbase - 6*(i+1), 0x4EF9);
1314: put_long(sysbase - 6*(i+1) + 2, i == 69 ? tmp2 : tmp);
1315: }
1316:
1317: /* Build syslists */
1318: EXEC_NewList(sysbase + 322); /* MemList */
1319: EXEC_NewList(sysbase + 336); /* ResourceList */
1320: EXEC_NewList(sysbase + 350); /* ResourceList */
1321: EXEC_NewList(sysbase + 364); /* List */
1322: EXEC_NewList(sysbase + 378); /* LibList */
1323: EXEC_NewList(sysbase + 392); /* PortList */
1324: EXEC_NewList(sysbase + 406); /* TaskReady */
1325: EXEC_NewList(sysbase + 420); /* TaskWait */
1326: EXEC_NewList(sysbase + 434); /* SoftInts[5] */
1327: EXEC_NewList(sysbase + 450);
1328: EXEC_NewList(sysbase + 466);
1329: EXEC_NewList(sysbase + 482);
1330: EXEC_NewList(sysbase + 498);
1331: EXEC_NewList(sysbase + 532); /* SemaphoreList */
1332:
1333: tmp = sysbase + 558; /* sizeof struct V34 execbase */
1334: /* We put the supervisor stack at the end, the user stack for our new
1335: * task at the end - 0x800, and build the ResModules array at the bottom
1336: * of the stack */
1337: sysstack = chipmem_size - 0x2000;
1338:
1339: /* Don't mess with Fast or Bogo for now, just set up Chip */
1340: EXEC_AddMemList(sysstack - tmp, MEMF_CHIP|MEMF_PUBLIC, -10, tmp,
1341: ds("Chip Memory"));
1342:
1343: /* Set up the CPU */
1344: regs.usp = chipmem_size - 0x800;
1345: regs.isp = chipmem_size; /* What about MSP? */
1346: regs.a[7] = regs.usp;
1347: regs.s = 0; regs.m = 0;
1348: regs.vbr = 0;
1349: regs.t0 = regs.t1 = 0;
1350: regs.intmask = 0;
1351: put_word(0xDFF09A, 0x7FFF);
1352: put_word(0xDFF096, 0x7FFF);
1353: put_word(0xDFF09C, 0x7FFF);
1354: put_word(0xDFF09A, 0xC000);
1355: put_word(0xDFF096, 0xE100);
1356: /* Initialize our supported functions */
1357: execlib_init();
1358: execlib_init2();
1359:
1360: /* Initialize interrupts */
1361: intr_count = 0;
1362: put_byte(sysbase + 294, 0xFF);
1363: put_byte(sysbase + 295, 0xFF);
1364:
1365: tmp = here();
1366: calltrap2(inttrap);
1367: dw(RTE);
1368: for (i = 0; i < 8; i++)
1369: put_long((24+i)*4, tmp);
1370:
1371: tmp = here();
1372: calltrap2(intvec); dw(RTS);
1373: for (i = 0; i < 16; i++) {
1374: tmp2 = 0;
1375: /* Is this a server chain? */
1376: if (i == 3 || i == 4 || i == 5 || i == 13 || i == 15)
1377: EXEC_NewList(tmp2 = EXEC_AllocMem(14, MEMF_PUBLIC));
1378: put_long(sysbase + 84 + i*12, tmp2);
1379: put_long(sysbase + 84 + i*12 + 4, tmp);
1380: put_long(sysbase + 84 + i*12 + 8, 0);
1381: }
1382: put_word(0xDFF09A, 0xAFC3); /* Enable everything but the server chains */
1383: /* Set up the init task. We don't really set it up properly. */
1384: tmp = EXEC_AllocMem(92, MEMF_CLEAR);
1385: put_long(sysbase + 276, tmp);
1386: put_byte(tmp + 8, 1);
1387: put_byte(tmp + 9, -127);
1388: put_long(tmp + 10, ds("init"));
1389: put_byte(tmp + 16, 0xFF);
1390: put_byte(tmp + 17, 0xFF);
1391: put_long(tmp + 54, chipmem_size - 0x804);
1392: put_long(tmp + 58, chipmem_size - 0x1800);
1393: put_long(tmp + 62, chipmem_size - 0x800);
1394: put_byte(tmp + 15, TS_RUN);
1395: put_long(tmp + 18,0x0000FFFF);
1396: EXEC_NewList(tmp + 74);
1397: idle_task.next = idle_task.prev = &idle_task;
1398: idle_task.exectask = tmp;
1399: idle_task.stack = NULL; /* we have a stack for this one already */
1400:
1401: /* Set up an idle task */
1402: tmp2 = here();
1403: dw (0x4E72); dw(0x2000); dw (0x4eF9); dl (tmp2);
1404:
1405: tmp = EXEC_AllocMem(92, MEMF_CLEAR);
1406: put_byte(tmp + 8, 1);
1407: put_byte(tmp + 9, -128);
1408: put_long(tmp + 10, ds("idle"));
1409: put_long(tmp + 58, chipmem_size - 0x2000);
1410: put_long(tmp + 62, chipmem_size - 0x1800);
1411: put_long(tmp + 54, chipmem_size - 0x1804);
1412: EXEC_NewList(tmp + 74);
1413: EXEC_AddTask(tmp, tmp2, 0); /* This won't start executing yet */
1414: find_newtask(tmp)->regs.s = 1;
1415:
1416:
1417: /* Grep Kickstart for resident modules */
1418: regs.a[7] -= 4;
1419: put_long(regs.a[7], 0);
1420: tmp2 = regs.a[7];
1421: for (tmp = 0xF80000; tmp < 0xFFFFFF; tmp += 2) {
1422: if (get_word(tmp) == 0x4AFC && get_long(tmp + 2) == tmp) {
1423: regs.a[7] -= 4; put_long(regs.a[7], tmp);
1424: }
1425: }
1426: put_long(sysbase + 300, regs.a[7]);
1427: /* Bubble me do */
1428: for (tmp = regs.a[7]; tmp < tmp2; tmp += 4) {
1429: CPTR tmp3;
1430: for (tmp3 = tmp2 - 4; tmp3 > tmp; tmp3 -= 4) {
1431: if ((BYTE)get_byte(get_long(tmp3) + 13) > (BYTE)get_byte(get_long(tmp3 - 4) + 13)) {
1432: CPTR tmp4 = get_long(tmp3);
1433: put_long(tmp3, get_long(tmp3 - 4));
1434: put_long(tmp3 - 4, tmp4);
1435: }
1436: }
1437: }
1438:
1439: /* Initialize them and watch everything blow up. */
1440: for (tmp = regs.a[7]; (tmp2 = get_long(tmp)) != 0; tmp += 4) {
1441: UBYTE flags = get_byte(tmp2 + 10);
1442: if (!(flags & 1)) /* RTF_COLDSTART? */
1443: continue;
1444: if (strncmp("alert", get_real_address(get_long(tmp2 + 18)), 5) == 0)
1445: /*continue*/;
1446: fprintf(stderr, "Initializing %s\n", get_real_address(get_long(tmp2 + 18)));
1447: EXEC_InitResident(tmp2, /* ? */ 0);
1448: }
1449: /* Idle task */
1450: for(;;) {
1451: Call68k(0xF0FFF0 - 4, 0);
1452: schedule();
1453: }
1454: }
1455:
1456: /*
1457: * Install the gfx-library-replacement
1458: */
1459: void execlib_install(void)
1460: {
1461: ULONG begin, end, resname, resid;
1462: int i;
1463:
1464: if (!use_gfxlib)
1465: return;
1466:
1467: resname = ds("UAEexeclib.resource");
1468: resid = ds("UAE execlib 0.1");
1469:
1470: begin = here();
1471: dw(0x4AFC); /* RTC_MATCHWORD */
1472: dl(begin); /* our start address */
1473: dl(0); /* Continue scan here */
1474: dw(0x0101); /* RTF_COLDSTART; Version 1 */
1475: dw(0x0805); /* NT_RESOURCE; pri 5 */
1476: dl(resname); /* name */
1477: dl(resid); /* ID */
1478: dl(here() + 4); /* Init area: directly after this */
1479:
1480: calltrap(deftrap(execlib_init)); dw(RTS);
1481:
1482: end = here();
1483: org(begin + 6);
1484: dl(end);
1485:
1486: org(end);
1487:
1488: intr_count = 1; /* So we don't try to schedule if we don't emulate
1489: * all of Exec */
1490: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.