tsr.mod 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. (*========================================================
  2. == JPI Modula-2 demo program: ==
  3. == ==
  4. == TSR Shell ==
  5. == ==
  6. == Installs a "safe" Pop Up program ==
  7. == ==
  8. ========================================================*)
  9. IMPLEMENTATION MODULE TSR ;
  10. (* ======== *)
  11. IMPORT IO,Window,Lib,Storage,Str;
  12. FROM SYSTEM IMPORT PROCESS,NEWPROCESS,TRANSFER,EI,DI,GetFlags,SetFlags,
  13. Registers,CarryFlag,HeapBase,Seg,Ofs,In,Out ;
  14. VAR
  15. ProgDTA : ADDRESS ;
  16. ProgPSP : CARDINAL ;
  17. DosNest : POINTER TO SHORTCARD ;
  18. ActivateScan : SHORTCARD ;
  19. ActivateFlags : KBFlagSet ;
  20. KBFlags[40H:17H] : KBFlagSet ;
  21. TSRproc : PROC ;
  22. (*$W+*) (* Keep volatile variables in memory *)
  23. CONST
  24. KBFuseful = KBFlagSet { RShift, LShift, Ctrl, Alt } ;
  25. TYPE
  26. TSRmodeType = (Sleeping,Wake,Active,Kill,Dead ) ;
  27. VAR
  28. TSRmode : TSRmodeType ;
  29. MainProcess : PROCESS;
  30. (*$W=*) (* Restore volatile setting *)
  31. TYPE
  32. IPROC = PROCEDURE ( (* flags : *) BITSET ) ; (* Interrupt Proc *)
  33. VAR
  34. Irpt[0:0], (* Interrupt table *)
  35. SaveIrpt : ARRAY [0..255] OF IPROC ;
  36. PROCEDURE SetIrpt ( N : CARDINAL ; P : IPROC ) ;
  37. VAR
  38. fl : CARDINAL ;
  39. BEGIN
  40. fl := GetFlags() ; DI ;
  41. SaveIrpt[N] := Irpt[N] ;
  42. Irpt[N] := P ;
  43. SetFlags(fl) ;
  44. END SetIrpt ;
  45. PROCEDURE ResetIrpt ( N : CARDINAL ) ;
  46. VAR
  47. fl : CARDINAL ;
  48. BEGIN
  49. fl := GetFlags() ; DI ;
  50. Irpt[N] := SaveIrpt[N] ;
  51. SetFlags(fl) ;
  52. END ResetIrpt ;
  53. PROCEDURE SwapToTSR ;
  54. VAR
  55. op,np : PROCESS ;
  56. BEGIN
  57. TSRmode := Active ;
  58. np := MainProcess ;
  59. TRANSFER(op,np) ; (* can't use IOTRANSFER due to chaining problems
  60. with other TSRs (SideKick 1, for example) *)
  61. TSRmode := Sleeping ;
  62. END SwapToTSR ;
  63. (* Interrupt Handlers *)
  64. (* ================== *)
  65. (*$C FF,J+*) (* Save all registers and generate IRETs *)
  66. PROCEDURE NullInt ( flags : BITSET ) ; (* Do nothing interrupt *)
  67. BEGIN
  68. END NullInt;
  69. PROCEDURE Int9 ( flags : BITSET ) ; (* Keyboard H/W interrupt *)
  70. VAR
  71. sc : SHORTCARD ;
  72. BEGIN
  73. sc := In(60H) ;
  74. IF ((sc=ActivateScan)OR(ActivateScan=0))AND
  75. ((KBFlags*KBFuseful)=ActivateFlags) THEN
  76. sc := In(61H) ;
  77. Out(61H,SHORTCARD(BITSET(sc)+{7}));
  78. Out(61H,sc);
  79. Out(20H,20H);
  80. IF TSRmode=Sleeping THEN
  81. TSRmode := Wake ;
  82. END ;
  83. ELSE
  84. SaveIrpt[09H](BITSET(GetFlags())) ; (* Chain Int 28 *)
  85. END ;
  86. END Int9 ;
  87. VAR
  88. Save28stack : ARRAY[0..3FFH] OF BYTE ;
  89. PROCEDURE Int28 ( flags : BITSET ) ; (* DOS "I'm not doing much" interrupt *)
  90. VAR
  91. base : CARDINAL ;
  92. BEGIN
  93. Lib.Move(ADR(base),ADR(Save28stack),SIZE(Save28stack));
  94. SaveIrpt[28H](BITSET(GetFlags())) ; (* Chain Int 28 *)
  95. IF (Ofs(flags)>100H) AND (TSRmode=Wake) THEN
  96. SwapToTSR ;
  97. END ;
  98. Lib.Move(ADR(Save28stack),ADR(base),SIZE(Save28stack));
  99. END Int28 ;
  100. PROCEDURE Int1C ( flags : BITSET ) ; (* Timer Interrupt *)
  101. BEGIN
  102. SaveIrpt[1CH](BITSET(GetFlags())) ; (* Chain Int 1C *)
  103. IF (Ofs(flags)>100H)AND(DosNest^ = 0)AND(TSRmode=Wake) THEN
  104. Out(20H,20H) ; (* Send EOI to timer *)
  105. SwapToTSR ;
  106. END ;
  107. END Int1C ;
  108. (*$C FE*) (* Save all registers (except AX : function result) *)
  109. PROCEDURE Int24 ( flags : BITSET ) : CARDINAL ; (* Critical Error Interrupt *)
  110. BEGIN
  111. RETURN 0 ;
  112. END Int24;
  113. (*$C F0,J-*)
  114. PROCEDURE Resident;
  115. (* ======== *)
  116. VAR I,F : CARDINAL;
  117. R : Registers;
  118. SaveDTA : ADDRESS ;
  119. SavePSP : CARDINAL ;
  120. SaveBrk : SHORTCARD ;
  121. BEGIN
  122. (* Set Critical Error Handler and break handlers *)
  123. SetIrpt(24H,IPROC(Int24)) ;
  124. SetIrpt(1BH,NullInt);
  125. SetIrpt(23H,NullInt);
  126. (* Change DTA *)
  127. R.AH := 2FH ;
  128. Lib.Dos(R) ;
  129. SaveDTA := [R.ES:R.BX] ;
  130. R.AH := 1AH ;
  131. R.DS := Seg(ProgDTA^) ;
  132. R.DX := Ofs(ProgDTA^) ;
  133. Lib.Dos(R) ;
  134. (* Change PSP *)
  135. R.AX := 5100H ;
  136. Lib.Dos(R) ;
  137. SavePSP := R.BX ;
  138. R.BX := ProgPSP ;
  139. R.AX := 5000H ;
  140. Lib.Dos(R) ;
  141. (* Turn off break flag *)
  142. R.AX := 3300H ;
  143. Lib.Dos(R) ;
  144. SaveBrk := R.DL ;
  145. R.DL := 0 ;
  146. R.AX := 3301H ;
  147. Lib.Dos(R) ;
  148. R.AH := 3;
  149. R.BH := 0;
  150. Lib.Intr(R,010H);
  151. Window.Use(Window.FullScreen);
  152. Window.CursorOff;
  153. Window.SnapShot;
  154. TSRproc() ;
  155. R.AH := 0DH ;
  156. Lib.Dos(R) ;
  157. Window.Use(Window.FullScreen);
  158. Window.CursorOn;
  159. R.AH := 2;
  160. R.BH := 0;
  161. Lib.Intr(R,010H);
  162. (* Restore break flag *)
  163. R.DL := SaveBrk ;
  164. R.AX := 3301H ;
  165. Lib.Dos(R) ;
  166. (* Restore PSP *)
  167. R.BX := SavePSP ;
  168. R.AX := 5000H ;
  169. Lib.Dos(R) ;
  170. (* Restore DTA *)
  171. R.AH := 1AH ;
  172. R.DS := Seg(SaveDTA^) ;
  173. R.DX := Ofs(SaveDTA^) ;
  174. Lib.Dos(R) ;
  175. (* Restore Critical irpt and break handlers *)
  176. ResetIrpt(24H);
  177. ResetIrpt(1BH);
  178. ResetIrpt(23H);
  179. END Resident;
  180. VAR
  181. HeapSize : CARDINAL ;
  182. PROCEDURE TermProc ;
  183. VAR
  184. R : Registers ;
  185. BEGIN
  186. R.AX := 03100H; (*Terminate and stay resident*)
  187. R.DX := HeapBase+HeapSize-Lib.PSP ;
  188. Lib.Intr(R,21H); (* Use Intr, so as not to trigger the
  189. Dos re-entry run-time check *)
  190. (* No Return *)
  191. END TermProc ;
  192. VAR
  193. EnvPtr[0:4H*4] : POINTER TO RECORD
  194. op : SHORTCARD;
  195. ad : ADDRESS;
  196. str : ARRAY[0..5] OF CHAR;
  197. END ;
  198. PROCEDURE InEnv () : BOOLEAN ;
  199. BEGIN
  200. RETURN (EnvPtr<>NIL)AND (Str.Compare(EnvPtr^.str,'ENVREH')=0) ;
  201. END InEnv ;
  202. PROCEDURE SKinstalled () : BOOLEAN ;
  203. TYPE
  204. AP = POINTER TO ADDRESS ;
  205. VAR
  206. id1 : POINTER TO LONGCARD ;
  207. id2 : POINTER TO CARDINAL ;
  208. BEGIN
  209. id1 := Lib.SubAddr([0:8*4 AP]^,4) ;
  210. id2 := Lib.SubAddr([0:25H*4 AP]^,2) ;
  211. RETURN (id1^=049424B53H)OR(id2^=04B53H) ;
  212. END SKinstalled ;
  213. PROCEDURE Install ( P : PROC ; (* Procedure to be invoked *)
  214. KBF : KBFlagSet; (* Shift state to invoke *)
  215. Scan : SHORTCARD ; (* Invoking scancode (0=All) *)
  216. heapsize : CARDINAL (* Minimum heap required *)
  217. ) ;
  218. VAR
  219. hp,nhp : Storage.HeapRecPtr ;
  220. R : Registers ;
  221. stack : ARRAY[0..1023] OF BYTE ;
  222. termp : PROCESS ;
  223. BEGIN
  224. IF InEnv() THEN
  225. Lib.FatalError('Failed to install TSR: should be installed outside the JPI Environment');
  226. END ;
  227. IF SKinstalled() THEN
  228. Lib.FatalError('Failed to install TSR: should be installed BEFORE SideKick ');
  229. END ;
  230. ActivateScan := Scan ;
  231. ActivateFlags := KBF ;
  232. TSRproc := P ;
  233. hp := Storage.MainHeap ;
  234. (* Truncate Main Heap *)
  235. LOOP
  236. nhp := hp^.next ;
  237. IF nhp^.size = 0FFFFH THEN
  238. nhp := [HeapBase+heapsize-1:0] ;
  239. IF (Seg(hp^)+hp^.size<>Seg(nhp))
  240. AND (Seg(nhp^)>Seg(hp^)) THEN
  241. hp^.next := nhp ;
  242. hp^.size := Seg(nhp^)-Seg(hp^) ;
  243. nhp^.next := [HeapBase:0] ;
  244. nhp^.size := 0FFFFH ;
  245. ELSE
  246. Lib.FatalError('Not enough storage');
  247. END ;
  248. EXIT ;
  249. END ;
  250. hp := nhp ;
  251. END ;
  252. (* Release Environment *)
  253. R.ES := CARDINAL([Lib.PSP:2CH]^) ;
  254. R.AX := 04900H ;
  255. Lib.Dos(R);
  256. R.AH := 52 ;
  257. Lib.Dos(R) ;
  258. DosNest := [R.ES:R.BX] ; (* Dos nesting count *)
  259. R.AH := 2FH ;
  260. Lib.Dos(R) ;
  261. ProgDTA := [R.ES:R.BX] ; (* Current DTA *)
  262. R.AX := 5100H ;
  263. Lib.Dos(R) ;
  264. ProgPSP := R.BX ; (* Current PSP *)
  265. (* Install Interrupt handlers *)
  266. SetIrpt(09H,Int9);
  267. SetIrpt(1CH,Int1C);
  268. SetIrpt(28H,Int28);
  269. NEWPROCESS( TermProc, ADR(stack), SIZE(stack) , termp );
  270. HeapSize := heapsize ;
  271. TSRmode := Sleeping ;
  272. REPEAT
  273. TRANSFER(MainProcess,termp) ;
  274. Resident ;
  275. UNTIL TSRmode = Dead ;
  276. END Install ;
  277. PROCEDURE DeInstall ;
  278. TYPE
  279. BP = POINTER TO SHORTCARD ;
  280. CP = POINTER TO CARDINAL ;
  281. VAR
  282. s : CARDINAL ;
  283. R : Registers ;
  284. BEGIN
  285. IF TSRmode<>Dead THEN
  286. TSRmode := Dead ;
  287. ResetIrpt(09H);
  288. ResetIrpt(1CH);
  289. ResetIrpt(28H);
  290. R.AH := 52H ;
  291. Lib.Dos(R);
  292. s := [R.ES:R.BX-2 CP]^;
  293. WHILE [s:0 BP]^ = 4DH DO
  294. IF [s:1 CP]^ = ProgPSP THEN
  295. R.AH := 49H ;
  296. R.ES := s+1 ;
  297. Lib.Dos(R) ;
  298. END ;
  299. INC(s,[s:3 CP]^+1);
  300. END ;
  301. END ;
  302. END DeInstall ;
  303. VAR
  304. Continue : PROC ;
  305. PROCEDURE Closedown ;
  306. BEGIN
  307. DeInstall ;
  308. Continue() ;
  309. END Closedown ;
  310. BEGIN
  311. TSRmode := Dead ;
  312. Lib.Terminate(Closedown,Continue) ;
  313. END TSR.
  314. (*======================================================*)
  315.