Annotation of MiNT/src/context.spp, revision 1.1.1.4

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.