| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- (*========================================================
- == JPI Modula-2 demo program: ==
- == ==
- == TSR Shell ==
- == ==
- == Installs a "safe" Pop Up program ==
- == ==
- ========================================================*)
- IMPLEMENTATION MODULE TSR ;
- (* ======== *)
- IMPORT IO,Window,Lib,Storage,Str;
- FROM SYSTEM IMPORT PROCESS,NEWPROCESS,TRANSFER,EI,DI,GetFlags,SetFlags,
- Registers,CarryFlag,HeapBase,Seg,Ofs,In,Out ;
- VAR
- ProgDTA : ADDRESS ;
- ProgPSP : CARDINAL ;
- DosNest : POINTER TO SHORTCARD ;
- ActivateScan : SHORTCARD ;
- ActivateFlags : KBFlagSet ;
- KBFlags[40H:17H] : KBFlagSet ;
- TSRproc : PROC ;
- (*$W+*) (* Keep volatile variables in memory *)
- CONST
- KBFuseful = KBFlagSet { RShift, LShift, Ctrl, Alt } ;
- TYPE
- TSRmodeType = (Sleeping,Wake,Active,Kill,Dead ) ;
- VAR
- TSRmode : TSRmodeType ;
- MainProcess : PROCESS;
- (*$W=*) (* Restore volatile setting *)
- TYPE
- IPROC = PROCEDURE ( (* flags : *) BITSET ) ; (* Interrupt Proc *)
- VAR
- Irpt[0:0], (* Interrupt table *)
- SaveIrpt : ARRAY [0..255] OF IPROC ;
- PROCEDURE SetIrpt ( N : CARDINAL ; P : IPROC ) ;
- VAR
- fl : CARDINAL ;
- BEGIN
- fl := GetFlags() ; DI ;
- SaveIrpt[N] := Irpt[N] ;
- Irpt[N] := P ;
- SetFlags(fl) ;
- END SetIrpt ;
- PROCEDURE ResetIrpt ( N : CARDINAL ) ;
- VAR
- fl : CARDINAL ;
- BEGIN
- fl := GetFlags() ; DI ;
- Irpt[N] := SaveIrpt[N] ;
- SetFlags(fl) ;
- END ResetIrpt ;
- PROCEDURE SwapToTSR ;
- VAR
- op,np : PROCESS ;
- BEGIN
- TSRmode := Active ;
- np := MainProcess ;
- TRANSFER(op,np) ; (* can't use IOTRANSFER due to chaining problems
- with other TSRs (SideKick 1, for example) *)
- TSRmode := Sleeping ;
- END SwapToTSR ;
- (* Interrupt Handlers *)
- (* ================== *)
- (*$C FF,J+*) (* Save all registers and generate IRETs *)
- PROCEDURE NullInt ( flags : BITSET ) ; (* Do nothing interrupt *)
- BEGIN
- END NullInt;
- PROCEDURE Int9 ( flags : BITSET ) ; (* Keyboard H/W interrupt *)
- VAR
- sc : SHORTCARD ;
- BEGIN
- sc := In(60H) ;
- IF ((sc=ActivateScan)OR(ActivateScan=0))AND
- ((KBFlags*KBFuseful)=ActivateFlags) THEN
- sc := In(61H) ;
- Out(61H,SHORTCARD(BITSET(sc)+{7}));
- Out(61H,sc);
- Out(20H,20H);
- IF TSRmode=Sleeping THEN
- TSRmode := Wake ;
- END ;
- ELSE
- SaveIrpt[09H](BITSET(GetFlags())) ; (* Chain Int 28 *)
- END ;
- END Int9 ;
- VAR
- Save28stack : ARRAY[0..3FFH] OF BYTE ;
- PROCEDURE Int28 ( flags : BITSET ) ; (* DOS "I'm not doing much" interrupt *)
- VAR
- base : CARDINAL ;
- BEGIN
- Lib.Move(ADR(base),ADR(Save28stack),SIZE(Save28stack));
- SaveIrpt[28H](BITSET(GetFlags())) ; (* Chain Int 28 *)
- IF (Ofs(flags)>100H) AND (TSRmode=Wake) THEN
- SwapToTSR ;
- END ;
- Lib.Move(ADR(Save28stack),ADR(base),SIZE(Save28stack));
- END Int28 ;
- PROCEDURE Int1C ( flags : BITSET ) ; (* Timer Interrupt *)
- BEGIN
- SaveIrpt[1CH](BITSET(GetFlags())) ; (* Chain Int 1C *)
- IF (Ofs(flags)>100H)AND(DosNest^ = 0)AND(TSRmode=Wake) THEN
- Out(20H,20H) ; (* Send EOI to timer *)
- SwapToTSR ;
- END ;
- END Int1C ;
- (*$C FE*) (* Save all registers (except AX : function result) *)
- PROCEDURE Int24 ( flags : BITSET ) : CARDINAL ; (* Critical Error Interrupt *)
- BEGIN
- RETURN 0 ;
- END Int24;
- (*$C F0,J-*)
- PROCEDURE Resident;
- (* ======== *)
- VAR I,F : CARDINAL;
- R : Registers;
- SaveDTA : ADDRESS ;
- SavePSP : CARDINAL ;
- SaveBrk : SHORTCARD ;
- BEGIN
- (* Set Critical Error Handler and break handlers *)
- SetIrpt(24H,IPROC(Int24)) ;
- SetIrpt(1BH,NullInt);
- SetIrpt(23H,NullInt);
- (* Change DTA *)
- R.AH := 2FH ;
- Lib.Dos(R) ;
- SaveDTA := [R.ES:R.BX] ;
- R.AH := 1AH ;
- R.DS := Seg(ProgDTA^) ;
- R.DX := Ofs(ProgDTA^) ;
- Lib.Dos(R) ;
- (* Change PSP *)
- R.AX := 5100H ;
- Lib.Dos(R) ;
- SavePSP := R.BX ;
- R.BX := ProgPSP ;
- R.AX := 5000H ;
- Lib.Dos(R) ;
- (* Turn off break flag *)
- R.AX := 3300H ;
- Lib.Dos(R) ;
- SaveBrk := R.DL ;
- R.DL := 0 ;
- R.AX := 3301H ;
- Lib.Dos(R) ;
- R.AH := 3;
- R.BH := 0;
- Lib.Intr(R,010H);
- Window.Use(Window.FullScreen);
- Window.CursorOff;
- Window.SnapShot;
- TSRproc() ;
- R.AH := 0DH ;
- Lib.Dos(R) ;
- Window.Use(Window.FullScreen);
- Window.CursorOn;
- R.AH := 2;
- R.BH := 0;
- Lib.Intr(R,010H);
- (* Restore break flag *)
- R.DL := SaveBrk ;
- R.AX := 3301H ;
- Lib.Dos(R) ;
- (* Restore PSP *)
- R.BX := SavePSP ;
- R.AX := 5000H ;
- Lib.Dos(R) ;
- (* Restore DTA *)
- R.AH := 1AH ;
- R.DS := Seg(SaveDTA^) ;
- R.DX := Ofs(SaveDTA^) ;
- Lib.Dos(R) ;
- (* Restore Critical irpt and break handlers *)
- ResetIrpt(24H);
- ResetIrpt(1BH);
- ResetIrpt(23H);
- END Resident;
- VAR
- HeapSize : CARDINAL ;
- PROCEDURE TermProc ;
- VAR
- R : Registers ;
- BEGIN
- R.AX := 03100H; (*Terminate and stay resident*)
- R.DX := HeapBase+HeapSize-Lib.PSP ;
- Lib.Intr(R,21H); (* Use Intr, so as not to trigger the
- Dos re-entry run-time check *)
- (* No Return *)
- END TermProc ;
- VAR
- EnvPtr[0:4H*4] : POINTER TO RECORD
- op : SHORTCARD;
- ad : ADDRESS;
- str : ARRAY[0..5] OF CHAR;
- END ;
- PROCEDURE InEnv () : BOOLEAN ;
- BEGIN
- RETURN (EnvPtr<>NIL)AND (Str.Compare(EnvPtr^.str,'ENVREH')=0) ;
- END InEnv ;
- PROCEDURE SKinstalled () : BOOLEAN ;
- TYPE
- AP = POINTER TO ADDRESS ;
- VAR
- id1 : POINTER TO LONGCARD ;
- id2 : POINTER TO CARDINAL ;
- BEGIN
- id1 := Lib.SubAddr([0:8*4 AP]^,4) ;
- id2 := Lib.SubAddr([0:25H*4 AP]^,2) ;
- RETURN (id1^=049424B53H)OR(id2^=04B53H) ;
- END SKinstalled ;
- PROCEDURE Install ( P : PROC ; (* Procedure to be invoked *)
- KBF : KBFlagSet; (* Shift state to invoke *)
- Scan : SHORTCARD ; (* Invoking scancode (0=All) *)
- heapsize : CARDINAL (* Minimum heap required *)
- ) ;
- VAR
- hp,nhp : Storage.HeapRecPtr ;
- R : Registers ;
- stack : ARRAY[0..1023] OF BYTE ;
- termp : PROCESS ;
- BEGIN
- IF InEnv() THEN
- Lib.FatalError('Failed to install TSR: should be installed outside the JPI Environment');
- END ;
- IF SKinstalled() THEN
- Lib.FatalError('Failed to install TSR: should be installed BEFORE SideKick ');
- END ;
- ActivateScan := Scan ;
- ActivateFlags := KBF ;
- TSRproc := P ;
- hp := Storage.MainHeap ;
- (* Truncate Main Heap *)
- LOOP
- nhp := hp^.next ;
- IF nhp^.size = 0FFFFH THEN
- nhp := [HeapBase+heapsize-1:0] ;
- IF (Seg(hp^)+hp^.size<>Seg(nhp))
- AND (Seg(nhp^)>Seg(hp^)) THEN
- hp^.next := nhp ;
- hp^.size := Seg(nhp^)-Seg(hp^) ;
- nhp^.next := [HeapBase:0] ;
- nhp^.size := 0FFFFH ;
- ELSE
- Lib.FatalError('Not enough storage');
- END ;
- EXIT ;
- END ;
- hp := nhp ;
- END ;
- (* Release Environment *)
- R.ES := CARDINAL([Lib.PSP:2CH]^) ;
- R.AX := 04900H ;
- Lib.Dos(R);
- R.AH := 52 ;
- Lib.Dos(R) ;
- DosNest := [R.ES:R.BX] ; (* Dos nesting count *)
- R.AH := 2FH ;
- Lib.Dos(R) ;
- ProgDTA := [R.ES:R.BX] ; (* Current DTA *)
- R.AX := 5100H ;
- Lib.Dos(R) ;
- ProgPSP := R.BX ; (* Current PSP *)
- (* Install Interrupt handlers *)
- SetIrpt(09H,Int9);
- SetIrpt(1CH,Int1C);
- SetIrpt(28H,Int28);
- NEWPROCESS( TermProc, ADR(stack), SIZE(stack) , termp );
- HeapSize := heapsize ;
- TSRmode := Sleeping ;
- REPEAT
- TRANSFER(MainProcess,termp) ;
- Resident ;
- UNTIL TSRmode = Dead ;
- END Install ;
- PROCEDURE DeInstall ;
- TYPE
- BP = POINTER TO SHORTCARD ;
- CP = POINTER TO CARDINAL ;
- VAR
- s : CARDINAL ;
- R : Registers ;
- BEGIN
- IF TSRmode<>Dead THEN
- TSRmode := Dead ;
- ResetIrpt(09H);
- ResetIrpt(1CH);
- ResetIrpt(28H);
- R.AH := 52H ;
- Lib.Dos(R);
- s := [R.ES:R.BX-2 CP]^;
- WHILE [s:0 BP]^ = 4DH DO
- IF [s:1 CP]^ = ProgPSP THEN
- R.AH := 49H ;
- R.ES := s+1 ;
- Lib.Dos(R) ;
- END ;
- INC(s,[s:3 CP]^+1);
- END ;
- END ;
- END DeInstall ;
- VAR
- Continue : PROC ;
- PROCEDURE Closedown ;
- BEGIN
- DeInstall ;
- Continue() ;
- END Closedown ;
- BEGIN
- TSRmode := Dead ;
- Lib.Terminate(Closedown,Continue) ;
- END TSR.
- (*======================================================*)
|