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

1.1.1.2 ! root        1: ;
        !             2: 
        !             3: ; Copyright 1992 Eric R. Smith
        !             4: 
        !             5: ; Copyright 1992 Atari Corporation
        !             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:        XDEF    _set_mmu
        !           102: 
        !           103: 
        !           104: 
1.1       root      105:        XREF    _fpu
                    106: 
                    107:        XREF    _framesizes
                    108: 
                    109:        XREF    _new_trace      ; from intr.s
                    110: 
1.1.1.2 ! root      111:        XREF    _no_mem_prot    
        !           112: 
        !           113: ;
        !           114: 
        !           115: ; set_mmu(crp,tc): called once, the first time a page table is built, to 
        !           116: 
        !           117: ; switch away from the MMU setup that came from the ROM and into the setup 
        !           118: 
        !           119: ; that we just built.  The CRP is actually on the stack, and it's 8 bytes.
        !           120: 
        !           121: ; The TC is four bytes at sp@(0xc).  "Nulls" is here because we need to
        !           122: 
        !           123: ; shove zeros into a few places.
        !           124: 
        !           125: ;
        !           126: 
        !           127: ; nulltc is in the data segment because otherwise GAS assembles PC-relative
        !           128: 
        !           129: ; and that's not legal on 68030.
        !           130: 
        !           131: ;
        !           132: 
        !           133:        DATA
        !           134: 
        !           135: nulltc:        dc.l    0
        !           136: 
        !           137: 
        !           138: 
        !           139:        TEXT
        !           140: 
        !           141: _set_mmu:
        !           142: 
        !           143:        pmove   nulltc,tc               ; turn off mmu
        !           144: 
        !           145:        dc.l    $f0390800,nulltc        ; pmove nulltc,tt0
        !           146: 
        !           147:        dc.l    $f0390c00,nulltc        ; pmove nulltc,tt1
        !           148: 
        !           149:        pmove   4(sp),crp               ; caution: crp is 8 bytes
        !           150: 
        !           151:        pmove   $c(sp),tc
        !           152: 
        !           153:        rts
        !           154: 
        !           155: 
1.1       root      156: 
                    157: _build_context:
                    158: 
                    159:        move.l  a0,-(sp)        ; save a0; we'll use it for scratch
                    160: 
                    161:        move.l  8(sp),a0        ; get address of save area
                    162: 
1.1.1.2 ! root      163: 
        !           164: 
        !           165:        tst.w   _no_mem_prot    ; is there memory protection?
        !           166: 
        !           167:        bne.s   noprot1
        !           168: 
        !           169:        pmove   crp,C_CRP(a0)   ; save CRP from MMU
        !           170: 
        !           171:        pmove   tc,C_TC(a0)     ; save TC from MMU
        !           172: 
        !           173: noprot1:
        !           174: 
1.1       root      175:        movem.l d0-d7/a0-a6,(a0)        ; save registers D0-D7/A0-A6
                    176: 
                    177:        clr.b   C_PTRACE(a0)    ; no pending traces, thanks!
                    178: 
                    179:        lea     12(sp),a1       ; start of the interesting stack area
                    180: 
                    181:        move.w  (a1)+,d0        ; 68000 fake frame format
                    182: 
1.1.1.2 ! root      183: 
        !           184: 
        !           185: %ifndef ONLY030
        !           186: 
1.1       root      187:        move.w  ($59e).w,d7     ; get process frame flag
                    188: 
                    189:        bne.s   nojunk          ; we have some junk on the stack
                    190: 
                    191:        move.w  d0,C_SFMT(a0)   ; save fake frame format
                    192: 
                    193:        cmp.w   #$8,d0          ; if bus error
                    194: 
                    195:        beq.s   group0
                    196: 
                    197:        cmp.w   #$c,d0          ; or address error
                    198: 
                    199:        bne.s   nojunk
                    200: 
                    201: group0:        move.l  (a1)+,C_INTERNAL(a0)    ; stash it in the internal area
                    202: 
                    203:        move.l  (a1)+,C_INTERNAL+4(a0)  ; if a debugger's interested
                    204: 
                    205: nojunk:
                    206: 
1.1.1.2 ! root      207: %endif
        !           208: 
1.1       root      209:        move.w  (a1)+,d0        ; get SR of context
                    210: 
                    211:        move.w  d0,C_SR(a0)     ; save it
                    212: 
                    213:        move.l  (a1)+,C_PC(a0)  ; save PC of context
                    214: 
1.1.1.2 ! root      215: %ifndef ONLY030
        !           216: 
1.1       root      217:        tst.w   d7              ; test longframe (AKP)
                    218: 
                    219:        beq.s   short1          ; short
                    220: 
1.1.1.2 ! root      221: %endif
        !           222: 
1.1       root      223:        tst.w   _fpu            ; is there a true FPU in the system
                    224: 
                    225:        beq.s   nofpu
                    226: 
                    227:        fsave   C_FSTATE(a0)            ; save internal state frame
                    228: 
                    229:        tst.b   C_FSTATE(a0)            ; if NULL frame then the FPU is not in use
                    230: 
                    231:        beq.s   nofpu           ; skip programmer's model save
                    232: 
                    233:        fmovem.x        fp0-fp7,C_FREGS(a0)             ; save data registers
                    234: 
                    235:        fmovem.l        fpcr/fpsr/fpiar,C_FCTRL(a0)     ; and control registers
                    236: 
                    237: nofpu:
                    238: 
                    239:        lea     C_SFMT(a0),a2
                    240: 
                    241:        move.w  (a1)+,d1        ; fetch frame format word
                    242: 
                    243:        move.w  d1,(a2)+        ; and stash it away for later
                    244: 
                    245:        lsr.w   #8,d1           ; isolate the frame format identifier
                    246: 
                    247:        lsr.w   #4,d1
                    248: 
                    249:        lea     _framesizes,a3
                    250: 
                    251:        move.b  0(a3,d1.w),d1
                    252: 
                    253:        bra.s   bcover
                    254: 
                    255: bcint: move.w  (a1)+,(a2)+     ; copy CPU internal state
                    256: 
                    257: bcover:        dbf     d1,bcint
                    258: 
                    259: short1:
                    260: 
                    261:        move.l  a1,C_SSP(a0)    ; a1 now points above the state frame
                    262: 
                    263:        move.l  usp,a1          ; save user stack pointer
                    264: 
                    265:        move.l  a1,C_USP(a0)
                    266: 
                    267:        btst    #13,d0          ; check for supervisor mode
                    268: 
                    269:        beq.s   L_CONT1         ; user mode; we already have stack in a1
                    270: 
                    271: L_SUPER1:
                    272: 
                    273: ; moving from the save state buffer 
                    274: 
                    275: ; means not testing longframe again. (AKP)
                    276: 
                    277:        move.l  C_SSP(a0),a1    ; was using super stack pointer before interrupt
                    278: 
                    279:                                ; 
                    280: 
                    281: L_CONT1:
                    282: 
                    283:        move.l  ($408).w,C_TERM(a0) ; save GEMDOS terminate vector
                    284: 
                    285:        move.l  (sp)+,C_A0(a0)  ; save old register a0
                    286: 
                    287:        rts
                    288: 
                    289: 
                    290: 
1.1.1.2 ! root      291: 
        !           292: 
1.1       root      293: _save_context:
                    294: 
                    295:        move.l  a0,-(sp)        ; save a0
                    296: 
                    297:        move.l  8(sp),a0        ; get address of context save area
                    298: 
                    299: 
                    300: 
1.1.1.2 ! root      301:        tst.w   _no_mem_prot
        !           302: 
        !           303:        bne.s   noprot2
        !           304: 
        !           305:        pmove   crp,C_CRP(a0)   ; save the CRP from the MMU
        !           306: 
        !           307:        pmove   tc,C_TC(a0)     ; save the TC from the MMU
        !           308: 
        !           309: noprot2:
        !           310: 
        !           311: 
        !           312: 
1.1       root      313: ; if running with a true coprocessor we need to save the FPU state
                    314: 
                    315:        tst.w   _fpu            ; is there a true FPU in the system
                    316: 
                    317:        beq.s   nofpu2
                    318: 
                    319:        fsave   C_FSTATE(a0)            ; save internal state frame
                    320: 
                    321:        tst.b   C_FSTATE(a0)            ; if NULL frame then the FPU is not in use
                    322: 
                    323:        beq.s   nofpu2          ; skip programmer's model save
                    324: 
                    325:        fmovem.x        fp0-fp7,C_FREGS(a0)             ; save data registers
                    326: 
                    327:        fmovem.l        fpcr/fpsr/fpiar,C_FCTRL(a0)     ; and control registers
                    328: 
                    329: nofpu2:
                    330: 
                    331: ; note: I am somewhat unsure of this assumption, viz that save_context
                    332: 
                    333: ; can never be called in a situation where a co-processor
                    334: 
                    335: ; mid-instruction stack frame would be required. I suspect this is a
                    336: 
                    337: ; valid assumption, in which case the above FPU code is redundant, the
                    338: 
                    339: ; next line is not however!
                    340: 
                    341: 
                    342: 
                    343:        clr.w   C_SFMT(a0)              ; mark as a 4 word stack frame
                    344: 
                    345:        clr.b   C_PTRACE(a0)            ; no pending traces, thanks!
                    346: 
                    347: 
                    348: 
                    349:        movem.l d0-d7/a0-a6,(a0)        ; save D0-D7/A0-A6
                    350: 
                    351:        lea     8(sp),a1
                    352: 
                    353:        move.l  a1,C_SSP(a0)    ; save supervisor stack pointer
                    354: 
                    355:                                ; note that it should be pointing above the PC
                    356: 
                    357:        move.l  -4(a1),C_PC(a0) ; save PC
                    358: 
                    359:        move.l  usp,a1
                    360: 
                    361:        move.l  a1,C_USP(a0)    ; save user stack pointer
                    362: 
                    363:        move.w  sr,d0
                    364: 
                    365:        move.w  d0,C_SR(a0)     ; save status register
                    366: 
                    367:        move.l  ($408).w,C_TERM(a0)     ; save GEMDOS terminate vector
                    368: 
                    369:        move.l  (sp)+,C_A0(a0)  ; save old a0
                    370: 
                    371:        moveq.l #0,d0           ; return 0
                    372: 
                    373:        rts
                    374: 
                    375: 
                    376: 
                    377: _restore_context:
                    378: 
                    379:        ori.w   #$0700,sr       ; mask interrupts
                    380: 
                    381:        move.l  4(sp),a0        ; address of context save area
                    382: 
1.1.1.2 ! root      383: 
        !           384: 
        !           385: ; Switch stacks now - starting now ssp is in the memory space of
        !           386: 
        !           387: ; the process we're switching to. Thus, we can change memory context
        !           388: 
        !           389: ; to there.
        !           390: 
        !           391: 
        !           392: 
1.1       root      393:        move.l  C_SSP(a0),sp    ; supervisor stack pointer
                    394: 
                    395:        move.l  C_USP(a0),a1
                    396: 
                    397:        move.l  a1,usp          ; set user stack pointer
                    398: 
                    399:        move.l  C_TERM(a0),($408).w     ; restore GEMDOS terminate vector
                    400: 
                    401: 
                    402: 
1.1.1.2 ! root      403: ; Set memory context now: actually, this isn't necessary, since
        !           404: 
        !           405: ; we're coming back to a context in the same process as is running
        !           406: 
        !           407: ; now.
        !           408: 
        !           409: ;      tst.w   _no_mem_prot
        !           410: 
        !           411: ;      bne.s   noprot3
        !           412: 
        !           413: ;      pmove   C_CRP(a0),crp   ; restore MMU root pointer
        !           414: 
        !           415: ;      pmove   C_TC(a0),tc     ; restore MMU control register
        !           416: 
        !           417: noprot3:
        !           418: 
        !           419: 
        !           420: 
        !           421: %ifndef ONLY030
        !           422: 
1.1       root      423:        tst.w   ($59e).w        ; test longframe (AKP)
                    424: 
                    425:        beq.s   short3
                    426: 
1.1.1.2 ! root      427: %endif
        !           428: 
        !           429: ; was moveq.l #0,d0, but I don't think that's what was desired */
        !           430: 
        !           431:        moveq.l #0,d1
1.1       root      432: 
                    433:        lea     C_SFMT(a0),a1
                    434: 
                    435:        move.w  (a1)+,d0        ; fetch frame format word
                    436: 
                    437:        move.w  d0,d1           ; copy it for later
                    438: 
                    439:        lsr.w   #8,d1           ; isolate the frame format identifier
                    440: 
                    441:        lsr.w   #4,d1
                    442: 
                    443:        lea     _framesizes,a2
                    444: 
                    445:        move.b  0(a2,d1.w),d1
                    446: 
                    447:        sub.w   d1,sp
                    448: 
                    449:        sub.w   d1,sp
                    450: 
                    451:        move.l  sp,a2
                    452: 
                    453:        bra.s   rcover
                    454: 
                    455: rcint: move.w  (a1)+,(a2)+
                    456: 
                    457: rcover:        dbf     d1,rcint
                    458: 
                    459:        move.w  d0,-(sp)        ; frame format identifier
                    460: 
                    461: ; if running with a true coprocessor we need to restore the FPU state
                    462: 
                    463: 
                    464: 
                    465:        tst.w   _fpu            ; is there a true FPU in the system
                    466: 
                    467:        beq.s   short3
                    468: 
                    469:        tst.b   C_FSTATE(a0)            ; if NULL frame then the FPU is not in use
                    470: 
1.1.1.2 ! root      471:        beq.s   short4          ; skip programmer's model restore
1.1       root      472: 
                    473:        fmovem.l        C_FCTRL(a0),fpcr/fpsr/fpiar     ; restore control registers
                    474: 
                    475:        fmovem.x        C_FREGS(a0),fp0-fp7             ; and data registers
                    476: 
1.1.1.2 ! root      477: short4:        frestore        C_FSTATE(a0)                    ; finally the internal state
1.1       root      478: 
                    479: short3:
                    480: 
                    481:        move.l  C_PC(a0),-(sp)  ; push the PC
                    482: 
                    483:        move.w  C_SR(a0),d0     ; fetch status register
                    484: 
                    485:        move.w  d0,-(sp)        ; push the status register
                    486: 
                    487:        tst.b   C_PTRACE(a0)            ; check for a pending trace
                    488: 
                    489:        movem.l (a0),d0-d7/a0-a6        ; restore registers d0-d7/a0-a6
                    490: 
                    491:        beq.s   notrace
                    492: 
                    493:        jmp     _new_trace
                    494: 
                    495: notrace:
                    496: 
                    497:        rte                     ; jump back to old context
                    498: 
                    499: 
                    500: 
1.1.1.2 ! root      501: 
        !           502: 
        !           503: _change_context:
        !           504: 
        !           505:        ori.w   #$0700,sr       ; mask interrupts
        !           506: 
        !           507:        move.l  4(sp),a0        ; address of context save area
        !           508: 
        !           509: 
        !           510: 
        !           511: ; Switch stacks now - starting now ssp is in the memory space of
        !           512: 
        !           513: ; the process we're switching to. Thus, we can change memory context
        !           514: 
        !           515: ; to there.
        !           516: 
        !           517: 
        !           518: 
        !           519:        move.l  C_SSP(a0),sp    ; supervisor stack pointer
        !           520: 
        !           521:        move.l  C_USP(a0),a1
        !           522: 
        !           523:        move.l  a1,usp          ; set user stack pointer
        !           524: 
        !           525:        move.l  C_TERM(a0),($408).w     ; restore GEMDOS terminate vector
        !           526: 
        !           527: 
        !           528: 
        !           529: ; Set memory context now
        !           530: 
        !           531:        tst.w   _no_mem_prot
        !           532: 
        !           533:        bne.s   noprot4
        !           534: 
        !           535:        pmove   C_CRP(a0),crp   ; restore MMU root pointer
        !           536: 
        !           537:        pmove   C_TC(a0),tc     ; restore MMU control register
        !           538: 
        !           539: noprot4:
        !           540: 
        !           541: %ifndef ONLY030
        !           542: 
        !           543:        tst.w   ($59e).w        ; test longframe (AKP)
        !           544: 
        !           545:        beq.s   short6
        !           546: 
        !           547: %endif
        !           548: 
        !           549: ; was moveq.l #0,d0, but I don't think that's what was desired */
        !           550: 
        !           551:        moveq.l #0,d1
        !           552: 
        !           553:        lea     C_SFMT(a0),a1
        !           554: 
        !           555:        move.w  (a1)+,d0        ; fetch frame format word
        !           556: 
        !           557:        move.w  d0,d1           ; copy it for later
        !           558: 
        !           559:        lsr.w   #8,d1           ; isolate the frame format identifier
        !           560: 
        !           561:        lsr.w   #4,d1
        !           562: 
        !           563:        lea     _framesizes,a2
        !           564: 
        !           565:        move.b  0(a2,d1.w),d1
        !           566: 
        !           567:        sub.w   d1,sp
        !           568: 
        !           569:        sub.w   d1,sp
        !           570: 
        !           571:        move.l  sp,a2
        !           572: 
        !           573:        bra.s   rcover2
        !           574: 
        !           575: rcint2:        move.w  (a1)+,(a2)+
        !           576: 
        !           577: rcover2: dbf   d1,rcint2
        !           578: 
        !           579:        move.w  d0,-(sp)        ; frame format identifier
        !           580: 
        !           581: ; if running with a true coprocessor we need to restore the FPU state
        !           582: 
        !           583: 
        !           584: 
        !           585:        tst.w   _fpu            ; is there a true FPU in the system
        !           586: 
        !           587:        beq.s   short3
        !           588: 
        !           589:        tst.b   C_FSTATE(a0)            ; if NULL frame then the FPU is not in use
        !           590: 
        !           591:        beq.s   short5          ; skip programmer's model restore
        !           592: 
        !           593:        fmovem.l        C_FCTRL(a0),fpcr/fpsr/fpiar     ; restore control registers
        !           594: 
        !           595:        fmovem.x        C_FREGS(a0),fp0-fp7             ; and data registers
        !           596: 
        !           597: short5:        frestore        C_FSTATE(a0)                    ; finally the internal state
        !           598: 
        !           599: short6:
        !           600: 
        !           601:        move.l  C_PC(a0),-(sp)  ; push the PC
        !           602: 
        !           603:        move.w  C_SR(a0),d0     ; fetch status register
        !           604: 
        !           605:        move.w  d0,-(sp)        ; push the status register
        !           606: 
        !           607:        tst.b   C_PTRACE(a0)            ; check for a pending trace
        !           608: 
        !           609:        movem.l (a0),d0-d7/a0-a6        ; restore registers d0-d7/a0-a6
        !           610: 
        !           611:        beq.s   notrace2
        !           612: 
        !           613:        jmp     _new_trace
        !           614: 
        !           615: notrace2:
        !           616: 
        !           617:        rte                     ; jump back to old context
        !           618: 
        !           619: 
        !           620: 
1.1       root      621:        END
                    622: 

unix.superglobalmegacorp.com

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