|
|
1.1 root 1: #include "task.h"
2: #include <assert.h>
3: #include <stdio.h>
4:
5: // 3B frame fudger
6:
7: //Frames not self-describing!
8: //STACK GROWS UP
9:
10: typedef unsigned char MACHINE_BYTE;
11:
12: #ifdef u3b
13:
14: #define OLD_FP(fp) ( *( (int*)(fp) - 11 ) )
15: #define OLD_AP(fp) ( *( (int*)(fp) - 12 ) )
16: #define OLD_PC(fp) ( *( (int*)(fp) - 13 ) )
17: #define FIRST_SAVED_REG_P(fp) ( (int*)(fp) - 6 )
18:
19: const CALL_OPCODE = ((MACHINE_BYTE)0x78);
20: /* SAK: really: 0x78 | 0x79 | 0xB9 | 0x77 */
21: const SAVE_OPCODE = ((MACHINE_BYTE)0x7A);
22: const BYTE_DISPL = 0xC0; /* SAK: WRONG for u3b! */
23: const HALFWORD_DISPL = 0xA0; /* SAK: WRONG for u3b! */
24: const WORD_DISPL = 0x80; /* SAK: WRONG for u3b! */
25: const ABSOLUTE = 0x70; /* SAK: WRONG for u3b! */
26:
27: const N_CALL_INSTR_SIZES = 6; /* SAK: WRONG for u3b! */
28: short call_size[N_CALL_INSTR_SIZES] = {5, 6, 7, 8, 9, 11}; /* SAK: WRONG for u3b! */
29:
30: /* SAK: SAVE_OPERAND(instr) not needed for u3b */
31:
32: /* Given a pointer to a save instruction, yield the number of registers saved */
33: #define N_SAVED_REGS(instr) (((char *)(instr))[1] >> 4)
34:
35: /* CALL's src operand descriptor needed to determine size of src operand */
36: #define SRC_OP_DESC(instr) (((char *)(instr))[1] & 0xf0)
37: #define SRC_OP_SIZE(desc) /* assumes sp-relative displacement */\
38: (((desc) == BYTE_DISPL) ? 2 : \
39: ((desc) == HALFWORD_DISPL) ? 3 : \
40: ((desc) == WORD_DISPL) ? 5 : \
41: ((((object*)0)->task_error(E_FRAMES))) \
42: )
43: const OPCODE_SIZE = 1;
44: const DESC_SIZE = 1;
45:
46: /* SAK: WRONG for u3b! */
47: #define DST_OP_DESC(instr) \
48: (((char *)(instr))[OPCODE_SIZE + SRC_OP_SIZE(SRC_OP_DESC(instr))] & 0xf0)
49:
50: /* SAK: WRONG for u3b! */
51: #define IS_LEGAL_SRC_OP(desc) \
52: (((desc) == BYTE_DISPL) || \
53: ((desc) == HALFWORD_DISPL) || \
54: ((desc) == WORD_DISPL) \
55: )
56: /* SAK: WRONG for u3b! */
57: #define IS_LEGAL_DST_OP(desc) \
58: (((desc) == BYTE_DISPL) || \
59: ((desc) == HALFWORD_DISPL) || \
60: ((desc) == WORD_DISPL) || \
61: ((desc) == ABSOLUTE) \
62: )
63:
64:
65: #else /* m32: u3b2, u3b5, u3b15 */
66: #define OLD_FP(fp) ( *( (int*)(fp) - 7 ) )
67: #define OLD_AP(fp) ( *( (int*)(fp) - 8 ) )
68: #define OLD_PC(fp) ( *( (int*)(fp) - 9 ) )
69: #define FIRST_SAVED_REG_P(fp) ( (int*)(fp) - 6 )
70: /*
71: * On the 3B2, the call instruction is CALL src,dst
72: * where src is the address of the new ap (where the args were
73: * already pushed on the stack) and dst is the address of the
74: * called function. src and dst can be various lengths:
75: * src will be a byte, halfword, or word displacement
76: * and dst will be absolute, or be a byte, halfword, or word displacement.
77: * Byte displacement = 2 bytes, halfword = 3, word = 5; the opcode = 1 byte;
78: * absolute = 5 bytes--12 possible combinations and 6 possible instr lengths.
79: */
80:
81:
82: const CALL_OPCODE = ((MACHINE_BYTE)0x2c);
83: const SAVE_OPCODE = ((MACHINE_BYTE)0x10);
84: const BYTE_DISPL = 0xC0;
85: const HALFWORD_DISPL = 0xA0;
86: const WORD_DISPL = 0x80;
87: const ABSOLUTE = 0x70;
88:
89: const N_CALL_INSTR_SIZES = 6;
90: short call_size[N_CALL_INSTR_SIZES] = {5, 6, 7, 8, 9, 11};
91:
92: #define SAVE_OPERAND(instr) (((char *)(instr))[1] & 0xf)
93:
94: /* Given a pointer to a save instruction, yield the number of registers saved */
95: #define N_SAVED_REGS(instr) (8 - SAVE_OPERAND(instr) + 1)
96:
97: /* CALL's src operand descriptor needed to determine size of src operand */
98: #define SRC_OP_DESC(instr) (((char *)(instr))[1] & 0xf0)
99: #define SRC_OP_SIZE(desc) /* assumes sp-relative displacement */\
100: (((desc) == BYTE_DISPL) ? 2 : \
101: ((desc) == HALFWORD_DISPL) ? 3 : \
102: ((desc) == WORD_DISPL) ? 5 : \
103: ((((object*)0)->task_error(E_FRAMES))) \
104: )
105: const OPCODE_SIZE = 1;
106: const DESC_SIZE = 1;
107:
108: #define DST_OP_DESC(instr) \
109: (((char *)(instr))[OPCODE_SIZE + SRC_OP_SIZE(SRC_OP_DESC(instr))] & 0xf0)
110:
111: #define IS_LEGAL_SRC_OP(desc) \
112: (((desc) == BYTE_DISPL) || \
113: ((desc) == HALFWORD_DISPL) || \
114: ((desc) == WORD_DISPL) \
115: )
116: #define IS_LEGAL_DST_OP(desc) \
117: (((desc) == BYTE_DISPL) || \
118: ((desc) == HALFWORD_DISPL) || \
119: ((desc) == WORD_DISPL) || \
120: ((desc) == ABSOLUTE) \
121: )
122:
123: /* Given a pointer to a call instruction, yield a pointer to the called function */
124: unsigned int
125: call_dst_ptr(unsigned char* callp)
126: {
127: int sop_size = SRC_OP_SIZE(SRC_OP_DESC(callp));
128: unsigned char* dst_op_p = /* points past the dst desc, to addr or offset */
129: callp + OPCODE_SIZE + sop_size + DESC_SIZE;
130: int offset; // offset for displacement modes
131: switch(DST_OP_DESC(callp)) {
132: case BYTE_DISPL:
133: offset = dst_op_p[0];
134: if(*dst_op_p & 0x80) { /* negative--do sign extension for offset */
135: offset |= 0xffffff00;
136: }
137: return (unsigned int)(callp + offset);
138: case HALFWORD_DISPL:
139: // bytes are in reverse order, must flip positions
140: offset = dst_op_p[0] | dst_op_p[1] << 8;
141: if(dst_op_p[1] & 0x80) { /* negative--do sign extension for offset */
142: offset |= 0xffff0000;
143: }
144: return (unsigned int)(callp + offset);
145: case WORD_DISPL:
146: // bytes are in reverse order, must flip positions
147: offset = dst_op_p[0] |
148: dst_op_p[1] << 8 |
149: dst_op_p[2] << 16 |
150: dst_op_p[3] << 24;
151: /* don't need sign extension */
152: return (unsigned int)(callp + offset);
153: case ABSOLUTE:
154: return
155: dst_op_p[0] |
156: dst_op_p[1] << 8 |
157: dst_op_p[2] << 16 |
158: dst_op_p[3] << 24;
159: default:
160: ((object*)0)->task_error(E_FRAMES);
161: }
162: }
163:
164:
165: #endif
166:
167:
168: struct FrameLayout {
169: short n_saved; // number of registers saved in this frame.
170: // (3B's don't have masks of regs saved)
171: FrameLayout(int*); // called with frame pointer
172: };
173:
174: FrameLayout::FrameLayout(int* fp)
175: {
176: /*
177: * Given a frame pointer, find the number of regs saved in the frame.
178: * The idea is that the instruction immediately before the return pc
179: * is the function call, and contains a pointer to the first instruction
180: * in the function denoted by the fp, which will be a save instruction.
181: * We can decode the save instruction to find how many registers
182: * were saved.
183: */
184:
185: int* return_pc = (int*)OLD_PC(fp);
186:
187: char* callp = NULL;
188: /* Because this method is nondeterministic, try all combinations
189: instead of stopping when one fits */
190: for(int i = 0; i < N_CALL_INSTR_SIZES; i++) {
191: char* poss_callp = (char *)return_pc - call_size[i];
192: if ((*poss_callp == CALL_OPCODE)
193: && IS_LEGAL_SRC_OP((SRC_OP_DESC(poss_callp)))
194: && IS_LEGAL_DST_OP((DST_OP_DESC(poss_callp)))) {
195: if(!callp) callp = poss_callp;
196: else ((object*)0)->task_error(E_FRAMES); //ambiguous; can't tell which
197: //is real call.
198: }
199: }
200: if (callp == NULL) ((object*)0)->task_error(E_FRAMES); //No match!
201: assert( *(char *)(call_dst_ptr(callp)) == SAVE_OPCODE);
202: n_saved = N_SAVED_REGS(call_dst_ptr(callp));
203: }
204:
205: /*
206: * fix a frame so that it returns like the arg
207: * The idea is that task_fp points to the task::task() stack frame which
208: * contains all the saved registers. t_framep points to the stack frame
209: * that contains the return address and old fp (and perhaps some registers).
210: * fill the frame pointed to by t_framep with the registers from task_fp.
211: */
212: void
213: task::fudge_return(int* task_fp, int offset, task* next)
214: {
215: int* fp = t_framep + offset;
216: task_fp += offset; // in case this is SHARED
217: FrameLayout this_lo(fp);
218: FrameLayout task_lo(task_fp);
219: if (task_lo.n_saved != 6) // task::task() saves all regs
220: task_error(E_FUDGE);
221: // copy any saved registers from this to task frame
222: register int* task_rp = FIRST_SAVED_REG_P(task_fp) +
223: task_lo.n_saved - this_lo.n_saved;
224: register int* this_rp = FIRST_SAVED_REG_P(fp);
225: register int count;
226: for (count = this_lo.n_saved; count--; )
227: *task_rp++ = *this_rp++;
228: // next copy all the registers from the task frame to this
229: task_rp = FIRST_SAVED_REG_P(task_fp);
230: this_rp = FIRST_SAVED_REG_P(fp);
231: for (count = task_lo.n_saved; count--; )
232: *this_rp++ = *task_rp++;
233: if (next) next->restore();
234: }
235:
236:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.