|
|
1.1 root 1: #include "task.h"
2:
3: // MC68000 frame fudger
4:
5: /* careful -- stack frame not self-describing */
6: // STACK GROWS DOWN
7: #define FP(p) ( (int*)(&p+1) )
8: #define AP() 0 /* unnecessary on mc68000 */
9: #define OLD_AP(fp) 0 /* unnecessary on mc68000 */
10: #define OLD_FP(fp) (*fp)
11:
12: struct FrameLayout {
13: short offset; // of top of frame from fp (size of locals + regs)
14: unsigned short mask; // of registers saved in frame
15: FrameLayout(int*); // called with frame pointer
16: };
17:
18: /*
19: * This code figures out the layout of the frame of the user's constructor. Note
20: * the user's class is directly derived from class task and the call to the
21: * constructor is automatically generated.
22: */
23: FrameLayout::FrameLayout(int* fp)
24: {
25: unsigned short* ret_addr = (unsigned short*)*(fp+1);
26: /*
27: * find the starting address of the function. The idea is that the instruction
28: * immediately before the return address must be the function call. Only works
29: * if the function was called by name.
30: */
31: /*
32: * On the 68000, the four forms of function call generated by the compiler are
33: * 047271 jsr followed by the function address (long)
34: * 060777 bsrl followed by the function offset (long) (68020 only)
35: * 060400 bsr followed by the function offset (short)
36: * 0x61NN bsrb low order byte is the offset (not actually seen or tested)
37: */
38: unsigned short* func_addr =
39: (ret_addr[-3] == 047271) ?
40: (unsigned short*)*(int*)(ret_addr-2) :
41: (ret_addr[-3] == 060777) ?
42: (unsigned short*) ((char*)(ret_addr-2) + *(int*)(ret_addr-2)) :
43: (ret_addr[-2] == 060400) ?
44: (unsigned short*) ((char*)(ret_addr-1) + *(short*)(ret_addr-1)) :
45: (*(char*)(ret_addr-1) == 0x61) ?
46: (unsigned short*) ((char*)ret_addr + *((char*)ret_addr-1)) :
47: (unsigned short*)((object*)0)->task_error(E_FUNCS);
48: /*
49: * the first instruction in the function is linkw a6,xxx
50: * if -O was used, xxx is the frame size in bytes, otherwise
51: * xxx is 0 and the next instruction is addl #yyy, sp
52: * where yyy is the frame size
53: */
54: if (*func_addr == 047126) { // linkw instruction
55: if ((offset = (short)*++func_addr / 4) == 0)
56: if (*++func_addr == 0157774) // addl
57: offset = (short)*(func_addr += 2) / 4;
58: } else ((object*)0)->task_error(E_FRAMES);
59: /*
60: * The next instruction saves the registers in the frame. The possibilities are
61: * movem mask,@sp | save the register specified by the mask word
62: * movl a5,@sp | just save a5
63: * movl d7,@sp | just save d7
64: * The mask uses the standard 68000 layout
65: */
66: switch (*++func_addr) {
67: case 027215: // movl a5,sp@
68: mask = 020000; // just a5
69: break;
70: case 044327: // movem mask,@sp
71: mask = *++func_addr; // mask word
72: break;
73: case 027207: // movl d7,sp@
74: mask = 0200; // just d7
75: break;
76: default: // no saved registers is also possible
77: mask = 0;
78: break;
79: }
80: }
81:
82: /*
83: * fix a frame so that it returns like the arg
84: * The idea is that task_fp points to the task::task() stack frame which
85: * contains all the saved registers. t_framep points to the stack frame
86: * that contains the return address and old fp (and perhaps some registers).
87: * fill the frame pointed to by t_framep with the registers from task_fp.
88: */
89: void
90: task::fudge_return(int* task_fp, int offset, task* next)
91: {
92: int* fp = t_framep + offset;
93: task_fp += offset; // in case this is SHARED
94: FrameLayout this_lo(fp);
95: FrameLayout task_lo(task_fp);
96: // copy any saved registers from this to task frame
97: register int* task_rp = task_fp + task_lo.offset;
98: register int* this_rp = fp + this_lo.offset;
99: register int reg_count = 0;
100: for (register mask = 1; mask != 0x10000; mask <<= 1) {
101: if (mask & task_lo.mask) {
102: reg_count++;
103: if (mask & this_lo.mask)
104: *task_rp++ = *this_rp++;
105: else task_rp++;
106: } else if (mask & this_lo.mask)
107: task_error(E_FUDGE);
108: }
109: // next copy all the registers from the task frame to this (using task offset)
110: task_rp = task_fp + task_lo.offset + reg_count;
111: this_rp = fp + task_lo.offset + reg_count;
112: while (reg_count--)
113: *--this_rp = *--task_rp;
114: if (next) next->restore();
115: }
116:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.