|
|
1.1.1.2 root 1: ;
2:
3: ; Copyright 1992 Eric R. Smith
4:
1.1.1.3 ! root 5: ; Copyright 1992,1993 Atari Corporation
1.1.1.2 root 6:
7: ; All rights reserved.
8:
9:
10:
1.1 root 11: %include "magic.i"
12:
13: ;
14:
15: ; routines for saving/restoring user contexts
16:
17: ;
18:
19: ; long build_context(struct context *sav, short fmt):
20:
21: ; Called from an interrupt handler (such as the trap #1 routine
22:
23: ; for system calls) saves the context of the interrupted
24:
25: ; routine. Assumes that no user registers have been changed
26:
27: ; since the interrupt, and that the PC and status register
28:
29: ; are still on the stack. Returns the stack pointer being used
30:
31: ; at the time of the interrupt **in register a1**.
32:
33: ; The fmt parameter is used on the 68000 to communicate the exception
34:
35: ; vector number; on >=68010 we use the vector offset from the frame.
36:
37: ;
38:
39: ; long save_context(struct context *sav):
40:
41: ; Saves the context of the calling routine in the area pointed
42:
43: ; to by sav. Save_context always returns 0 when initially called;
44:
45: ; this is so processes can (by suitably manipulating the
46:
47: ; saved registers) tell when the return from save_context is
48:
49: ; actually caused by restoring the context, e.g.:
50:
51: ; if (save_context(sav) == 0) { <<-- L1
52:
53: ; /* do some stuff */
54:
55: ; sav.regs[D0] = 1; /* for restore context */
56:
57: ; restore_context(sav); /* goes back to L1 */
58:
59: ; }
60:
61: ; else /* this is the second time through */
62:
63: ;
64:
65: ; void restore_context(struct context *sav):
66:
67: ; Restores a context previously saved by build_context or save_context.
68:
69: ; Since the program counter is part of the context, this function
70:
1.1.1.2 root 71: ; will never return (it's like longjmp()). NOTE: this function should
72:
73: ; be used only to change contexts _within_ the same program, since
74:
75: ; it does NOT flush the ATC. See change_context
1.1 root 76:
77: ;
78:
1.1.1.2 root 79: ; void change_context(struct context *sav):
80:
81: ; Restores a context previously saved by build_context or save_context
82:
83: ; for a different process. Unlike restore_context, this one *does*
84:
85: ; flush the ATC.
86:
87:
88:
1.1 root 89: TEXT
90:
91:
92:
93: XDEF _build_context
94:
95: XDEF _save_context
96:
97: XDEF _restore_context
98:
1.1.1.2 root 99: XDEF _change_context
100:
101:
102:
1.1 root 103: XREF _fpu
104:
105: XREF _framesizes
106:
107: XREF _new_trace ; from intr.s
108:
1.1.1.2 root 109: XREF _no_mem_prot
110:
111:
112:
113: TEXT
114:
1.1 root 115: _build_context:
116:
117: move.l a0,-(sp) ; save a0; we'll use it for scratch
118:
119: move.l 8(sp),a0 ; get address of save area
120:
1.1.1.2 root 121:
122:
123: tst.w _no_mem_prot ; is there memory protection?
124:
125: bne.s noprot1
126:
127: pmove crp,C_CRP(a0) ; save CRP from MMU
128:
129: pmove tc,C_TC(a0) ; save TC from MMU
130:
131: noprot1:
132:
1.1 root 133: movem.l d0-d7/a0-a6,(a0) ; save registers D0-D7/A0-A6
134:
135: clr.b C_PTRACE(a0) ; no pending traces, thanks!
136:
137: lea 12(sp),a1 ; start of the interesting stack area
138:
139: move.w (a1)+,d0 ; 68000 fake frame format
140:
1.1.1.2 root 141:
142:
143: %ifndef ONLY030
144:
1.1 root 145: move.w ($59e).w,d7 ; get process frame flag
146:
147: bne.s nojunk ; we have some junk on the stack
148:
149: move.w d0,C_SFMT(a0) ; save fake frame format
150:
1.1.1.3 ! root 151: subq.w #$8,d0 ; if bus error (note: subq is faster than
1.1 root 152:
1.1.1.3 ! root 153: beq.s group0 ; cmp, and we won't need d0 later)
1.1 root 154:
1.1.1.3 ! root 155: subq.w #$4,d0 ; or address error ($C==$8+$4)
1.1 root 156:
157: bne.s nojunk
158:
159: group0: move.l (a1)+,C_INTERNAL(a0) ; stash it in the internal area
160:
161: move.l (a1)+,C_INTERNAL+4(a0) ; if a debugger's interested
162:
163: nojunk:
164:
1.1.1.2 root 165: %endif
166:
1.1 root 167: move.w (a1)+,d0 ; get SR of context
168:
169: move.w d0,C_SR(a0) ; save it
170:
171: move.l (a1)+,C_PC(a0) ; save PC of context
172:
1.1.1.2 root 173: %ifndef ONLY030
174:
1.1 root 175: tst.w d7 ; test longframe (AKP)
176:
177: beq.s short1 ; short
178:
1.1.1.2 root 179: %endif
180:
1.1 root 181: tst.w _fpu ; is there a true FPU in the system
182:
183: beq.s nofpu
184:
185: fsave C_FSTATE(a0) ; save internal state frame
186:
187: tst.b C_FSTATE(a0) ; if NULL frame then the FPU is not in use
188:
189: beq.s nofpu ; skip programmer's model save
190:
191: fmovem.x fp0-fp7,C_FREGS(a0) ; save data registers
192:
193: fmovem.l fpcr/fpsr/fpiar,C_FCTRL(a0) ; and control registers
194:
195: nofpu:
196:
197: lea C_SFMT(a0),a2
198:
199: move.w (a1)+,d1 ; fetch frame format word
200:
201: move.w d1,(a2)+ ; and stash it away for later
202:
203: lsr.w #8,d1 ; isolate the frame format identifier
204:
205: lsr.w #4,d1
206:
207: lea _framesizes,a3
208:
209: move.b 0(a3,d1.w),d1
210:
1.1.1.3 ! root 211: beq.s short1 ; if no data to save, skip this
1.1 root 212:
213: bcint: move.w (a1)+,(a2)+ ; copy CPU internal state
214:
215: bcover: dbf d1,bcint
216:
217: short1:
218:
219: move.l a1,C_SSP(a0) ; a1 now points above the state frame
220:
221: move.l usp,a1 ; save user stack pointer
222:
223: move.l a1,C_USP(a0)
224:
225: btst #13,d0 ; check for supervisor mode
226:
227: beq.s L_CONT1 ; user mode; we already have stack in a1
228:
229: L_SUPER1:
230:
231: ; moving from the save state buffer
232:
233: ; means not testing longframe again. (AKP)
234:
235: move.l C_SSP(a0),a1 ; was using super stack pointer before interrupt
236:
237: ;
238:
239: L_CONT1:
240:
241: move.l ($408).w,C_TERM(a0) ; save GEMDOS terminate vector
242:
243: move.l (sp)+,C_A0(a0) ; save old register a0
244:
245: rts
246:
247:
248:
1.1.1.2 root 249:
250:
1.1 root 251: _save_context:
252:
253: move.l a0,-(sp) ; save a0
254:
255: move.l 8(sp),a0 ; get address of context save area
256:
257:
258:
1.1.1.2 root 259: tst.w _no_mem_prot
260:
261: bne.s noprot2
262:
263: pmove crp,C_CRP(a0) ; save the CRP from the MMU
264:
265: pmove tc,C_TC(a0) ; save the TC from the MMU
266:
267: noprot2:
268:
269:
270:
1.1 root 271: ; if running with a true coprocessor we need to save the FPU state
272:
273: tst.w _fpu ; is there a true FPU in the system
274:
275: beq.s nofpu2
276:
277: fsave C_FSTATE(a0) ; save internal state frame
278:
279: tst.b C_FSTATE(a0) ; if NULL frame then the FPU is not in use
280:
281: beq.s nofpu2 ; skip programmer's model save
282:
283: fmovem.x fp0-fp7,C_FREGS(a0) ; save data registers
284:
285: fmovem.l fpcr/fpsr/fpiar,C_FCTRL(a0) ; and control registers
286:
287: nofpu2:
288:
289: ; note: I am somewhat unsure of this assumption, viz that save_context
290:
291: ; can never be called in a situation where a co-processor
292:
293: ; mid-instruction stack frame would be required. I suspect this is a
294:
295: ; valid assumption, in which case the above FPU code is redundant, the
296:
297: ; next line is not however!
298:
299:
300:
301: clr.w C_SFMT(a0) ; mark as a 4 word stack frame
302:
303: clr.b C_PTRACE(a0) ; no pending traces, thanks!
304:
305:
306:
307: movem.l d0-d7/a0-a6,(a0) ; save D0-D7/A0-A6
308:
309: lea 8(sp),a1
310:
311: move.l a1,C_SSP(a0) ; save supervisor stack pointer
312:
313: ; note that it should be pointing above the PC
314:
315: move.l -4(a1),C_PC(a0) ; save PC
316:
317: move.l usp,a1
318:
319: move.l a1,C_USP(a0) ; save user stack pointer
320:
1.1.1.3 ! root 321: move.w sr,C_SR(a0) ; save status register
1.1 root 322:
323: move.l ($408).w,C_TERM(a0) ; save GEMDOS terminate vector
324:
325: move.l (sp)+,C_A0(a0) ; save old a0
326:
327: moveq.l #0,d0 ; return 0
328:
329: rts
330:
331:
332:
333: _restore_context:
334:
335: ori.w #$0700,sr ; mask interrupts
336:
337: move.l 4(sp),a0 ; address of context save area
338:
1.1.1.2 root 339:
340:
341: ; Switch stacks now - starting now ssp is in the memory space of
342:
343: ; the process we're switching to. Thus, we can change memory context
344:
345: ; to there.
346:
347:
348:
1.1.1.3 ! root 349: move.l C_SSP(a0),a1 ; get supervisor stack pointer
! 350:
! 351: tst.b (a1) ; touch the page for virtual memory programs
! 352:
! 353: tst.b -1023(a1) ; make sure stack can grow
! 354:
! 355: move.l a1,sp
1.1 root 356:
357: move.l C_USP(a0),a1
358:
359: move.l a1,usp ; set user stack pointer
360:
361: move.l C_TERM(a0),($408).w ; restore GEMDOS terminate vector
362:
363:
364:
1.1.1.2 root 365: ; Set memory context now: actually, this isn't necessary, since
366:
367: ; we're coming back to a context in the same process as is running
368:
369: ; now.
370:
371: ; tst.w _no_mem_prot
372:
373: ; bne.s noprot3
374:
375: ; pmove C_CRP(a0),crp ; restore MMU root pointer
376:
377: ; pmove C_TC(a0),tc ; restore MMU control register
378:
379: noprot3:
380:
381:
382:
383: %ifndef ONLY030
384:
1.1 root 385: tst.w ($59e).w ; test longframe (AKP)
386:
387: beq.s short3
388:
1.1.1.2 root 389: %endif
390:
391: ; was moveq.l #0,d0, but I don't think that's what was desired */
392:
393: moveq.l #0,d1
1.1 root 394:
395: lea C_SFMT(a0),a1
396:
397: move.w (a1)+,d0 ; fetch frame format word
398:
399: move.w d0,d1 ; copy it for later
400:
401: lsr.w #8,d1 ; isolate the frame format identifier
402:
403: lsr.w #4,d1
404:
405: lea _framesizes,a2
406:
407: move.b 0(a2,d1.w),d1
408:
1.1.1.3 ! root 409: beq.s rcovernc ; if no data to copy, skip the copy
! 410:
1.1 root 411: sub.w d1,sp
412:
413: sub.w d1,sp
414:
415: move.l sp,a2
416:
417: bra.s rcover
418:
419: rcint: move.w (a1)+,(a2)+
420:
421: rcover: dbf d1,rcint
422:
1.1.1.3 ! root 423: rcovernc:
! 424:
1.1 root 425: move.w d0,-(sp) ; frame format identifier
426:
427: ; if running with a true coprocessor we need to restore the FPU state
428:
429:
430:
431: tst.w _fpu ; is there a true FPU in the system
432:
433: beq.s short3
434:
435: tst.b C_FSTATE(a0) ; if NULL frame then the FPU is not in use
436:
1.1.1.2 root 437: beq.s short4 ; skip programmer's model restore
1.1 root 438:
439: fmovem.l C_FCTRL(a0),fpcr/fpsr/fpiar ; restore control registers
440:
441: fmovem.x C_FREGS(a0),fp0-fp7 ; and data registers
442:
1.1.1.2 root 443: short4: frestore C_FSTATE(a0) ; finally the internal state
1.1 root 444:
445: short3:
446:
447: move.l C_PC(a0),-(sp) ; push the PC
448:
1.1.1.3 ! root 449: move.w C_SR(a0),-(sp) ; push the status register
1.1 root 450:
451: tst.b C_PTRACE(a0) ; check for a pending trace
452:
453: movem.l (a0),d0-d7/a0-a6 ; restore registers d0-d7/a0-a6
454:
455: beq.s notrace
456:
457: jmp _new_trace
458:
459: notrace:
460:
461: rte ; jump back to old context
462:
463:
464:
1.1.1.2 root 465:
466:
467: _change_context:
468:
469: ori.w #$0700,sr ; mask interrupts
470:
471: move.l 4(sp),a0 ; address of context save area
472:
473:
474:
475: ; Switch stacks now - starting now ssp is in the memory space of
476:
477: ; the process we're switching to. Thus, we can change memory context
478:
479: ; to there.
480:
481:
482:
1.1.1.3 ! root 483: move.l C_SSP(a0),a1 ; get supervisor stack pointer
! 484:
! 485: tst.b (a1) ; touch the page for virtual memory programs
! 486:
! 487: tst.b -1023(a1) ; make sure stack can grow
! 488:
! 489: move.l a1,sp
1.1.1.2 root 490:
491: move.l C_USP(a0),a1
492:
493: move.l a1,usp ; set user stack pointer
494:
495: move.l C_TERM(a0),($408).w ; restore GEMDOS terminate vector
496:
497:
498:
499: ; Set memory context now
500:
501: tst.w _no_mem_prot
502:
503: bne.s noprot4
504:
505: pmove C_CRP(a0),crp ; restore MMU root pointer
506:
507: pmove C_TC(a0),tc ; restore MMU control register
508:
509: noprot4:
510:
511: %ifndef ONLY030
512:
513: tst.w ($59e).w ; test longframe (AKP)
514:
515: beq.s short6
516:
517: %endif
518:
519: ; was moveq.l #0,d0, but I don't think that's what was desired */
520:
521: moveq.l #0,d1
522:
523: lea C_SFMT(a0),a1
524:
525: move.w (a1)+,d0 ; fetch frame format word
526:
527: move.w d0,d1 ; copy it for later
528:
529: lsr.w #8,d1 ; isolate the frame format identifier
530:
531: lsr.w #4,d1
532:
533: lea _framesizes,a2
534:
535: move.b 0(a2,d1.w),d1
536:
1.1.1.3 ! root 537: beq.s rcover2nc ; if no data to copy, skip it
! 538:
1.1.1.2 root 539: sub.w d1,sp
540:
541: sub.w d1,sp
542:
543: move.l sp,a2
544:
545: rcint2: move.w (a1)+,(a2)+
546:
547: rcover2: dbf d1,rcint2
548:
1.1.1.3 ! root 549: rcover2nc:
! 550:
1.1.1.2 root 551: move.w d0,-(sp) ; frame format identifier
552:
553: ; if running with a true coprocessor we need to restore the FPU state
554:
555:
556:
557: tst.w _fpu ; is there a true FPU in the system
558:
1.1.1.3 ! root 559: beq.s short6
1.1.1.2 root 560:
561: tst.b C_FSTATE(a0) ; if NULL frame then the FPU is not in use
562:
563: beq.s short5 ; skip programmer's model restore
564:
565: fmovem.l C_FCTRL(a0),fpcr/fpsr/fpiar ; restore control registers
566:
567: fmovem.x C_FREGS(a0),fp0-fp7 ; and data registers
568:
569: short5: frestore C_FSTATE(a0) ; finally the internal state
570:
571: short6:
572:
573: move.l C_PC(a0),-(sp) ; push the PC
574:
1.1.1.3 ! root 575: move.w C_SR(a0),-(sp) ; push status register
1.1.1.2 root 576:
577: tst.b C_PTRACE(a0) ; check for a pending trace
578:
579: movem.l (a0),d0-d7/a0-a6 ; restore registers d0-d7/a0-a6
580:
581: beq.s notrace2
582:
583: jmp _new_trace
584:
585: notrace2:
586:
587: rte ; jump back to old context
588:
589:
590:
1.1 root 591: END
592:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.