system.a 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. (* Copyright (C) 1987 Jensen & Partners International *)
  2. (* This assembler module is mainly concerned with implementing
  3. the multi-processing features of Modula-2 such as
  4. NEWPROCESS, TRANSFER and IOTRANSFER.
  5. There are some hardware dependencies, such as the interrupt
  6. controller port address. A dynamic check is performed to identify
  7. AT compatibles, otherwise a standard PC compatible is assumed.
  8. If you are programming non-standard peripherals on a new IBM
  9. machine such as the PS/2 model 50,60,80 some changes may be necessary.
  10. *)
  11. (*
  12. The "ROM" string denotes those sections requiring modification when
  13. creating ROMmable code.
  14. *)
  15. (*ROM
  16. A number of these routines make use of the Int 8 timer tick - they are
  17. marked with an "(*INT8*)" string. If the target machine does not provide
  18. a user timer tick via Int 8, then 1) don't use any of the facilities that
  19. need it; or 2) implement an Int 8.
  20. *)
  21. (*ROM
  22. These two values are used when sending an end-of-interrupt to the interrupt
  23. controller.
  24. *)
  25. eoiport = 20H (* the port to write EOI value to *)
  26. eoiportB = 0A0H (* the port to write EOI valkue to for AT and high int *)
  27. eoivalue = 20H (* the EOI value which will be written *)
  28. (*ROM
  29. These two values are used for accessing the interrupt controller.
  30. *)
  31. icport1 = 21H (* port for lower 8 bits of priority mask *)
  32. icport2 = 0A1H (* port for upper 8 bits of priority mask on AT *)
  33. (* Process descriptor offsets *)
  34. NextProcess = 0 (* Next in chain (-1 = end) *)
  35. (* of waiting processes *)
  36. LongCall = 2 (* Long call used to point interrupts *)
  37. LongCallIP = 4 (* at interrupt handler *)
  38. LongCallCS = 6
  39. ProcessSP = 8
  40. ProcessSS = 10
  41. ProcessPriority = 12
  42. ProcessFloat = 14
  43. ProcessRecordSize = 94 + ProcessFloat
  44. ProcessRecSize = 1 (* paragraphs *)
  45. ProcessRecSizeFloat = 7 (* paragraphs *)
  46. module SYSTEM
  47. segment INITCODE(CODE,28H);
  48. segment C_CODE(CODE,28H);
  49. group G_CODE(INITCODE,C_CODE)
  50. segment MP_DATA(M_DATA,68H)
  51. select C_CODE
  52. extrn @D_DATA
  53. extrn @MachineId
  54. extrn @CurrentProcess
  55. extrn @PrtAddrAbort
  56. extrn @Save8087
  57. @GetPri: (* read interrupt controller mask *)
  58. (* on entry, ds = [@D_DATA] *)
  59. xor ah,ah
  60. cmp byte [@MachineId],0FCH (*an AT ? *)
  61. jne @GetPri2
  62. in al,icport2
  63. mov ah,al
  64. @GetPri2:
  65. in al,icport1
  66. ret 0
  67. @SetPri: (* write interrupt controller mask *)
  68. (* on entry, ds = [@D_DATA] *)
  69. out icport1,al
  70. cmp byte [@MachineId],0FCH (*an AT ? *)
  71. jne @SetPri2
  72. xchg al,ah
  73. out icport2,al
  74. @SetPri2:
  75. ret 0
  76. public @NewPrio : (* compiler generated call *)
  77. pop bx
  78. push cs
  79. push bx
  80. public $NewPrio : (* compiler generated call *)
  81. push ax
  82. push dx
  83. push ds
  84. mov ds, cs:[@D_DATA]
  85. call @GetPri
  86. mov bx,ax
  87. mov ax,cx
  88. call @SetPri
  89. mov cx,bx
  90. pop ds
  91. pop dx
  92. pop ax
  93. ret far 0
  94. public @NewPri2 : (* compiler generated call *)
  95. pop bx
  96. push cs
  97. push bx
  98. public $NewPri2 : (* compiler generated call *)
  99. push ax
  100. push dx
  101. push ds
  102. mov ds, cs:[@D_DATA]
  103. call @GetPri
  104. mov bx, ax
  105. or ax, cx
  106. call @SetPri
  107. mov cx, bx
  108. pop ds
  109. pop dx
  110. pop ax
  111. ret far 0
  112. public SYSTEM$Listen : Mask = 6
  113. push bp; mov bp,sp; push ds
  114. mov ds, cs:[@D_DATA]
  115. call @GetPri
  116. mov bx,ax
  117. mov cx,[bp][Mask]
  118. not cx
  119. and ax,cx
  120. call @SetPri
  121. mov ax,bx
  122. call @SetPri
  123. pop ds; pop bp; ret far 2
  124. extrn FIERQQ
  125. extrn FIDRQQ
  126. SwapStack :
  127. (* Procedure used to change stack *)
  128. (* Inputs: ds = segment of new process record *)
  129. (* Out: cx = New priority *)
  130. (* NB Interrupts must be off *)
  131. (* The following registers are corrupted AX,CX,SI,DI,ES *)
  132. (* Out: es = Old (swapped) process *)
  133. mov es, cs:[@D_DATA]
  134. cmp byte es:[@Save8087], 0
  135. mov es, es:[@CurrentProcess]
  136. jne $dosave
  137. call @Swap
  138. $exitswap:
  139. call far $NewPrio
  140. ret 0
  141. $dosave: (* swap 8087 registers *)
  142. fsave es:[ProcessFloat]
  143. call @Swap
  144. frstor ds:[ProcessFloat]
  145. jmp $exitswap
  146. @Swap:
  147. (* local procedure to do the stack swap *)
  148. (* NB The first time a process gets swapped to, this routine returns to StartProcess *)
  149. cmp word ds:[LongCall],9A90H (* check word *)
  150. jne $CorruptProcess
  151. mov bx, ds
  152. mov ds, cs:[@D_DATA]
  153. mov [@CurrentProcess],bx
  154. mov di,ProcessSP
  155. mov ax,sp
  156. stosw
  157. mov ax,ss
  158. stosw
  159. call @GetPri
  160. mov ds, bx
  161. stosw
  162. mov si,ProcessSP
  163. lodsw
  164. mov sp,ax
  165. lodsw
  166. mov ss,ax
  167. lodsw
  168. mov cx,ax
  169. ret 0
  170. SwapStack2: (* Same as SwapStack but doesnt call $NewPrio *)
  171. mov es, cs:[@D_DATA]
  172. cmp byte es:[@Save8087], 0
  173. mov es, es:[@CurrentProcess]
  174. jne $dosave
  175. call @Swap
  176. jmp $exitswap2
  177. $dosave2:
  178. fsave es:[ProcessFloat]
  179. call @Swap
  180. frstor ds:[ProcessFloat]
  181. $exitswap2:
  182. xchg ax,cx
  183. push ds
  184. mov ds, cs:[@D_DATA]
  185. call @SetPri
  186. pop ds
  187. xchg ax,cx
  188. ret 0
  189. $CorruptProcess:
  190. sti
  191. mov dx,ipdmsg
  192. call @PrtAddrAbort
  193. ipdmsg : db "] Invalid process descriptor$"
  194. public SYSTEM$TRANSFER : p1seg=12; p1off=10; p2seg=8; p2off=6
  195. push bp; mov bp,sp
  196. push ds; push es; push si; push di
  197. pushf
  198. cli
  199. mov ds, cs:[@D_DATA]
  200. mov ax,[@CurrentProcess]
  201. (* Take copy of p2 *)
  202. lds bx, [bp][p2off]
  203. mov ds, [bx][2]
  204. (* Return result *)
  205. les bx, [bp][p1off]
  206. mov word es:[bx], 0
  207. mov word es:[bx][2],ax
  208. push bp
  209. call SwapStack
  210. pop bp
  211. popf
  212. pop di; pop si; pop es; pop ds
  213. pop bp; ret far 8
  214. public SYSTEM$IOTRANSFER : p1seg=14; p1off=12; p2seg=10; p2off=8; IntNo=6
  215. push bp; mov bp,sp
  216. push ds; push es; push si; push di
  217. pushf
  218. cli
  219. (* Return first result *)
  220. mov ds, cs:[@D_DATA]
  221. mov ax, [@CurrentProcess]
  222. (* Take copy of p2 *)
  223. lds bx, [bp][p2off]
  224. mov di, [bx][2]
  225. lds bx, [bp][p1off]
  226. mov word [bx],0
  227. mov [bx][2],ax
  228. (* Save old interrupt vector and set up new one *)
  229. sub bx, bx
  230. mov ds, bx
  231. mov bx, [bp][IntNo]
  232. shl bx, 1
  233. shl bx, 1
  234. push [bx]
  235. push [bx][2]
  236. mov [bx][2], ax (* current process *)
  237. mov word [bx],LongCall
  238. push ds
  239. push bx
  240. mov ds,di
  241. push bp
  242. call SwapStack
  243. pop bp
  244. pop bx
  245. pop ds
  246. (* Restore old interrupt vector *)
  247. pop [bx][2]
  248. pop [bx]
  249. (* issue EOI to interrupt controller *)
  250. cmp bx,20H
  251. jb skipa0
  252. cmp bx,40H
  253. mov al,eoivalue
  254. jae skip20
  255. out eoiport,al
  256. jmp skipa0
  257. skip20:
  258. cmp bx,1C0H
  259. jb skipa0
  260. cmp bx,1E0H
  261. jae skipa0
  262. out eoiportB,al (* assuming it's an AT *)
  263. out eoiport,al (* fix by Greg O'Nielsen *)
  264. skipa0:
  265. (* return second result *)
  266. lds bx, [bp][p2off]
  267. mov word [bx], 0
  268. mov [bx][2], es
  269. popf
  270. pop di; pop si; pop es; pop ds
  271. pop bp; ret far 10
  272. SYSTEM$IntHandler:
  273. (* On entry the stack has *)
  274. (* flags *)
  275. (* cs *)
  276. (* ip *)
  277. (* segment of task record of interrupting task ( used to save ax ) *)
  278. (* offset of ditto ( used to save bx ) *)
  279. (* Then registers saved in Registers record order *)
  280. (* flags = 16 *)
  281. (* CS = 14 *)
  282. (* IP = 12 *)
  283. (* 10 (flags copy) *)
  284. (* 8 (es) *)
  285. push ds (* 6 *)
  286. push di (* 4 *)
  287. push si (* 2 *)
  288. push bp (* 0 *)
  289. mov bp, sp
  290. push dx
  291. push cx
  292. push bx
  293. push ax
  294. pushf
  295. cld
  296. mov ds,ss:[bp][10] (* load ds with new process rec *)
  297. pop ss:[bp][10]
  298. mov [bp][8],es
  299. $preempt:
  300. call SwapStack2
  301. $exit:
  302. pop ax
  303. pop bx
  304. pop cx
  305. pop dx
  306. pop bp
  307. pop si
  308. pop di
  309. pop ds
  310. pop es
  311. add sp,2 (* flags are be restored by iret *)
  312. iret
  313. public SYSTEM$NEWPROCESS : pseg=18; poff=16; aseg=14; aoff=12; wspsize=10; p1seg=8; p1off=6
  314. push bp; mov bp,sp
  315. push ds; push es; push si; push di
  316. les di,[bp][aoff] (* address of process workspace *)
  317. mov bx,[bp][wspsize]
  318. mov ax,di
  319. and di,0FH (* amount lost due to normalizing *)
  320. jz $NoLoss
  321. sub di,16
  322. add bx,di
  323. $NoLoss:
  324. lds si,[bp][p1off] (* result *)
  325. add ax,15
  326. shr ax,1
  327. shr ax,1
  328. shr ax,1
  329. shr ax,1
  330. mov di,es
  331. add ax,di
  332. mov word ds:[si],0
  333. mov ds:[si][2],ax
  334. mov ds,ax
  335. push es
  336. mov es, cs:[@D_DATA]
  337. cmp byte es:[@Save8087],0
  338. pop es
  339. je $NoSave8087
  340. add ax,6 (* 94/16 *)
  341. sub bx,96
  342. and bx,0FFFEH (* put stack on even boundrary *)
  343. $NoSave8087:
  344. inc ax (* size of process record *)
  345. sub bx,16+12 (* 1 para + return addresses etc *)
  346. (* initialize record *)
  347. mov word ds:[NextProcess],-1
  348. mov word ds:[LongCall],09A90H
  349. mov word ds:[LongCallIP],SYSTEM$IntHandler
  350. mov ds:[LongCallCS],cs
  351. mov ds:[ProcessSS],ax
  352. mov ds:[ProcessSP],bx
  353. mov es,ax
  354. push ds
  355. mov ds, cs:[@D_DATA]
  356. call @GetPri
  357. pop ds
  358. mov ds:[ProcessPriority],ax
  359. (* initialize return stack frame *)
  360. mov di,bx
  361. mov ax,StartProcess
  362. stosw
  363. mov ax,[bp][poff]
  364. stosw
  365. mov ax,[bp][pseg]
  366. stosw
  367. mov ax,StopProcess
  368. stosw
  369. mov ax,cs
  370. stosw
  371. pop di; pop si; pop es; pop ds
  372. pop bp; ret far 14
  373. extrn @Abort
  374. FatalError :
  375. sti
  376. pop dx
  377. push cs
  378. pop ds
  379. mov ah, 9
  380. int 21H
  381. jmp @Abort
  382. StopProcess:
  383. call FatalError
  384. db "Fatal error: Return from process",7,13,10, "$"
  385. StartProcess:
  386. (* This is arrived at by first SwapStack *)
  387. (* IN cx = priority (from SwapStack) *)
  388. (* Initialize rounding control *)
  389. push ds
  390. mov ds, cs:[@D_DATA]
  391. cmp byte [@Save8087], 0
  392. pop ds
  393. je $No8087
  394. fstcw ds:[ProcessFloat]
  395. fwait
  396. or word ds:[ProcessFloat],0C00H
  397. fldcw ds:[ProcessFloat]
  398. $No8087:
  399. (*Initialise bp to zero, enable interrupts and set priority *)
  400. sub bp,bp
  401. cld
  402. call far $NewPrio
  403. sti
  404. ret far 0
  405. (* Utility procedures *)
  406. public SYSTEM$NewPriority :
  407. pop bx
  408. pop dx
  409. pop cx
  410. push dx
  411. push bx
  412. jmp far $NewPrio
  413. public SYSTEM$CurrentPriority :
  414. push ds
  415. mov ds, cs:[@D_DATA]
  416. call @GetPri
  417. pop ds; ret far 0
  418. public SYSTEM$InterruptRegisters : pseg=8; pofs=6
  419. push bp; mov bp,sp
  420. push ds
  421. (* called to find the registers of an interrupted process *)
  422. (* after an IOtransfer *)
  423. mov ds,[bp][pseg]
  424. mov dx,ds:[ProcessSS]
  425. mov ax,ds:[ProcessSP]
  426. add ax,4
  427. pop ds
  428. pop bp; ret far 4
  429. select MP_DATA
  430. MainProcess : org ProcessRecordSize
  431. extrn @D_DATA
  432. select INITCODE
  433. mov ax, MP_DATA
  434. mov ds, ax
  435. mov word [MainProcess], -1
  436. mov word [MainProcess][2], 9A90H
  437. mov word [MainProcess][4], SYSTEM$IntHandler
  438. mov word [MainProcess][6], C_CODE
  439. mov ds, cs:[@D_DATA]
  440. mov word [@CurrentProcess], MP_DATA
  441. section;
  442. segment C_CODE(CODE,28H); group G_CODE(C_CODE)
  443. select C_CODE
  444. extrn @D_DATA
  445. extrn @CurrentProcess
  446. public SYSTEM$CurrentProcess :
  447. (* returns the current process in DX:AX *)
  448. push ds
  449. mov ds, cs:[@D_DATA]
  450. mov dx, [@CurrentProcess]
  451. pop ds
  452. sub ax,ax
  453. ret far 0
  454. section;
  455. segment INITCODE(CODE,28H);
  456. group G_CODE(INITCODE)
  457. segment D_DATA(M_DATA,28H);
  458. segment HEAP(HEAP,68H);
  459. select D_DATA
  460. public @MachineId : org 1
  461. public @CurrentProcess : org 2
  462. public SYSTEM@HeapBase : org 2
  463. public @Save8087 : org 2 (* must be non zero *)
  464. (* if floating point context save required *)
  465. select INITCODE
  466. extrn @D_DATA
  467. public SYSTEM@:
  468. mov ds, cs:[@D_DATA]
  469. mov word ds:[SYSTEM@HeapBase],HEAP
  470. mov word [@Save8087], 0
  471. mov word [@CurrentProcess], 0
  472. (*ROM
  473. Get the machine ID byte. A 0FCH identifies an AT - this value is used
  474. to determine whether the interrupt controller mask is 8-bit (PC) or 16-bit
  475. (AT).
  476. *)
  477. mov ax,0F000H
  478. mov es,ax
  479. mov al,es:[0FFFEH]
  480. mov [@MachineId],al
  481. end
  482.