|
|
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:
1.1.1.4 ! root 213: subq.w #1,d1 ; correct for first time through loop
! 214:
1.1 root 215: bcint: move.w (a1)+,(a2)+ ; copy CPU internal state
216:
217: bcover: dbf d1,bcint
218:
219: short1:
220:
221: move.l a1,C_SSP(a0) ; a1 now points above the state frame
222:
223: move.l usp,a1 ; save user stack pointer
224:
225: move.l a1,C_USP(a0)
226:
227: btst #13,d0 ; check for supervisor mode
228:
229: beq.s L_CONT1 ; user mode; we already have stack in a1
230:
231: L_SUPER1:
232:
233: ; moving from the save state buffer
234:
235: ; means not testing longframe again. (AKP)
236:
237: move.l C_SSP(a0),a1 ; was using super stack pointer before interrupt
238:
239: ;
240:
241: L_CONT1:
242:
243: move.l ($408).w,C_TERM(a0) ; save GEMDOS terminate vector
244:
245: move.l (sp)+,C_A0(a0) ; save old register a0
246:
247: rts
248:
249:
250:
1.1.1.2 root 251:
252:
1.1 root 253: _save_context:
254:
255: move.l a0,-(sp) ; save a0
256:
257: move.l 8(sp),a0 ; get address of context save area
258:
259:
260:
1.1.1.2 root 261: tst.w _no_mem_prot
262:
263: bne.s noprot2
264:
265: pmove crp,C_CRP(a0) ; save the CRP from the MMU
266:
267: pmove tc,C_TC(a0) ; save the TC from the MMU
268:
269: noprot2:
270:
271:
272:
1.1 root 273: ; if running with a true coprocessor we need to save the FPU state
274:
275: tst.w _fpu ; is there a true FPU in the system
276:
277: beq.s nofpu2
278:
279: fsave C_FSTATE(a0) ; save internal state frame
280:
281: tst.b C_FSTATE(a0) ; if NULL frame then the FPU is not in use
282:
283: beq.s nofpu2 ; skip programmer's model save
284:
285: fmovem.x fp0-fp7,C_FREGS(a0) ; save data registers
286:
287: fmovem.l fpcr/fpsr/fpiar,C_FCTRL(a0) ; and control registers
288:
289: nofpu2:
290:
291: ; note: I am somewhat unsure of this assumption, viz that save_context
292:
293: ; can never be called in a situation where a co-processor
294:
295: ; mid-instruction stack frame would be required. I suspect this is a
296:
297: ; valid assumption, in which case the above FPU code is redundant, the
298:
299: ; next line is not however!
300:
301:
302:
303: clr.w C_SFMT(a0) ; mark as a 4 word stack frame
304:
305: clr.b C_PTRACE(a0) ; no pending traces, thanks!
306:
307:
308:
309: movem.l d0-d7/a0-a6,(a0) ; save D0-D7/A0-A6
310:
311: lea 8(sp),a1
312:
313: move.l a1,C_SSP(a0) ; save supervisor stack pointer
314:
315: ; note that it should be pointing above the PC
316:
317: move.l -4(a1),C_PC(a0) ; save PC
318:
319: move.l usp,a1
320:
321: move.l a1,C_USP(a0) ; save user stack pointer
322:
1.1.1.3 root 323: move.w sr,C_SR(a0) ; save status register
1.1 root 324:
325: move.l ($408).w,C_TERM(a0) ; save GEMDOS terminate vector
326:
327: move.l (sp)+,C_A0(a0) ; save old a0
328:
329: moveq.l #0,d0 ; return 0
330:
331: rts
332:
333:
334:
335: _restore_context:
336:
337: ori.w #$0700,sr ; mask interrupts
338:
339: move.l 4(sp),a0 ; address of context save area
340:
1.1.1.2 root 341:
342:
343: ; Switch stacks now - starting now ssp is in the memory space of
344:
345: ; the process we're switching to. Thus, we can change memory context
346:
347: ; to there.
348:
349:
350:
1.1.1.3 root 351: move.l C_SSP(a0),a1 ; get supervisor stack pointer
352:
353: tst.b (a1) ; touch the page for virtual memory programs
354:
1.1.1.4 ! root 355: tst.b -63(a1) ; make sure stack can grow
1.1.1.3 root 356:
357: move.l a1,sp
1.1 root 358:
359: move.l C_USP(a0),a1
360:
361: move.l a1,usp ; set user stack pointer
362:
363: move.l C_TERM(a0),($408).w ; restore GEMDOS terminate vector
364:
365:
366:
1.1.1.2 root 367: ; Set memory context now: actually, this isn't necessary, since
368:
369: ; we're coming back to a context in the same process as is running
370:
371: ; now.
372:
373: ; tst.w _no_mem_prot
374:
375: ; bne.s noprot3
376:
377: ; pmove C_CRP(a0),crp ; restore MMU root pointer
378:
379: ; pmove C_TC(a0),tc ; restore MMU control register
380:
381: noprot3:
382:
383:
384:
385: %ifndef ONLY030
386:
1.1 root 387: tst.w ($59e).w ; test longframe (AKP)
388:
389: beq.s short3
390:
1.1.1.2 root 391: %endif
392:
393: ; was moveq.l #0,d0, but I don't think that's what was desired */
394:
395: moveq.l #0,d1
1.1 root 396:
397: lea C_SFMT(a0),a1
398:
399: move.w (a1)+,d0 ; fetch frame format word
400:
401: move.w d0,d1 ; copy it for later
402:
403: lsr.w #8,d1 ; isolate the frame format identifier
404:
405: lsr.w #4,d1
406:
407: lea _framesizes,a2
408:
409: move.b 0(a2,d1.w),d1
410:
1.1.1.3 root 411: beq.s rcovernc ; if no data to copy, skip the copy
412:
1.1 root 413: sub.w d1,sp
414:
415: sub.w d1,sp
416:
417: move.l sp,a2
418:
419: bra.s rcover
420:
1.1.1.4 ! root 421: subq.w #1,d1 ; correct for first time through loop
! 422:
1.1 root 423: rcint: move.w (a1)+,(a2)+
424:
425: rcover: dbf d1,rcint
426:
1.1.1.3 root 427: rcovernc:
428:
1.1 root 429: move.w d0,-(sp) ; frame format identifier
430:
431: ; if running with a true coprocessor we need to restore the FPU state
432:
433:
434:
435: tst.w _fpu ; is there a true FPU in the system
436:
437: beq.s short3
438:
439: tst.b C_FSTATE(a0) ; if NULL frame then the FPU is not in use
440:
1.1.1.2 root 441: beq.s short4 ; skip programmer's model restore
1.1 root 442:
443: fmovem.l C_FCTRL(a0),fpcr/fpsr/fpiar ; restore control registers
444:
445: fmovem.x C_FREGS(a0),fp0-fp7 ; and data registers
446:
1.1.1.2 root 447: short4: frestore C_FSTATE(a0) ; finally the internal state
1.1 root 448:
449: short3:
450:
451: move.l C_PC(a0),-(sp) ; push the PC
452:
1.1.1.3 root 453: move.w C_SR(a0),-(sp) ; push the status register
1.1 root 454:
455: tst.b C_PTRACE(a0) ; check for a pending trace
456:
457: movem.l (a0),d0-d7/a0-a6 ; restore registers d0-d7/a0-a6
458:
459: beq.s notrace
460:
461: jmp _new_trace
462:
463: notrace:
464:
465: rte ; jump back to old context
466:
467:
468:
1.1.1.2 root 469:
470:
471: _change_context:
472:
473: ori.w #$0700,sr ; mask interrupts
474:
475: move.l 4(sp),a0 ; address of context save area
476:
477:
478:
479: ; Switch stacks now - starting now ssp is in the memory space of
480:
481: ; the process we're switching to. Thus, we can change memory context
482:
483: ; to there.
484:
485:
486:
1.1.1.3 root 487: move.l C_SSP(a0),a1 ; get supervisor stack pointer
488:
489: tst.b (a1) ; touch the page for virtual memory programs
490:
1.1.1.4 ! root 491: tst.b -63(a1) ; make sure stack can grow
1.1.1.3 root 492:
493: move.l a1,sp
1.1.1.2 root 494:
495: move.l C_USP(a0),a1
496:
497: move.l a1,usp ; set user stack pointer
498:
499: move.l C_TERM(a0),($408).w ; restore GEMDOS terminate vector
500:
501:
502:
503: ; Set memory context now
504:
505: tst.w _no_mem_prot
506:
507: bne.s noprot4
508:
509: pmove C_CRP(a0),crp ; restore MMU root pointer
510:
511: pmove C_TC(a0),tc ; restore MMU control register
512:
513: noprot4:
514:
515: %ifndef ONLY030
516:
517: tst.w ($59e).w ; test longframe (AKP)
518:
519: beq.s short6
520:
521: %endif
522:
523: ; was moveq.l #0,d0, but I don't think that's what was desired */
524:
525: moveq.l #0,d1
526:
527: lea C_SFMT(a0),a1
528:
529: move.w (a1)+,d0 ; fetch frame format word
530:
531: move.w d0,d1 ; copy it for later
532:
533: lsr.w #8,d1 ; isolate the frame format identifier
534:
535: lsr.w #4,d1
536:
537: lea _framesizes,a2
538:
539: move.b 0(a2,d1.w),d1
540:
1.1.1.3 root 541: beq.s rcover2nc ; if no data to copy, skip it
542:
1.1.1.2 root 543: sub.w d1,sp
544:
545: sub.w d1,sp
546:
547: move.l sp,a2
548:
1.1.1.4 ! root 549: subq.w #1,d1 ; correct for first time through loop
! 550:
1.1.1.2 root 551: rcint2: move.w (a1)+,(a2)+
552:
553: rcover2: dbf d1,rcint2
554:
1.1.1.3 root 555: rcover2nc:
556:
1.1.1.2 root 557: move.w d0,-(sp) ; frame format identifier
558:
559: ; if running with a true coprocessor we need to restore the FPU state
560:
561:
562:
563: tst.w _fpu ; is there a true FPU in the system
564:
1.1.1.3 root 565: beq.s short6
1.1.1.2 root 566:
567: tst.b C_FSTATE(a0) ; if NULL frame then the FPU is not in use
568:
569: beq.s short5 ; skip programmer's model restore
570:
571: fmovem.l C_FCTRL(a0),fpcr/fpsr/fpiar ; restore control registers
572:
573: fmovem.x C_FREGS(a0),fp0-fp7 ; and data registers
574:
575: short5: frestore C_FSTATE(a0) ; finally the internal state
576:
577: short6:
578:
579: move.l C_PC(a0),-(sp) ; push the PC
580:
1.1.1.3 root 581: move.w C_SR(a0),-(sp) ; push status register
1.1.1.2 root 582:
583: tst.b C_PTRACE(a0) ; check for a pending trace
584:
585: movem.l (a0),d0-d7/a0-a6 ; restore registers d0-d7/a0-a6
586:
587: beq.s notrace2
588:
589: jmp _new_trace
590:
591: notrace2:
592:
593: rte ; jump back to old context
594:
595:
596:
1.1 root 597: END
598:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.