CPU.Mod 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. (* Runtime support for CPU internals *)
  2. (* Copyright (C) Florian Negele *)
  3. MODULE CPU;
  4. IMPORT SYSTEM;
  5. CONST StackSize* = 8 * 1024 * SIZEOF(ADDRESS);
  6. CONST Quantum* = 1000000;
  7. CONST CacheLineSize* = 64;
  8. CONST StackDisplacement* = 0;
  9. PROCEDURE Backoff-;
  10. CODE
  11. #IF I386 THEN
  12. MOV EAX, 80000H
  13. loop: DEC EAX
  14. JNZ loop
  15. #ELSIF AMD64 THEN
  16. MOV EAX, 80000H
  17. loop: DEC EAX
  18. JNZ loop
  19. #ELSE
  20. unimplemented
  21. #END
  22. END Backoff;
  23. (* cpu control *)
  24. PROCEDURE {NORETURN} Reset-;
  25. CODE
  26. #IF I386 THEN
  27. CLI
  28. PUSH 0
  29. PUSH 0
  30. LIDT [ESP]
  31. INT3
  32. #ELSIF AMD64 THEN
  33. CLI
  34. PUSH 0
  35. PUSH 0
  36. LIDT [RSP]
  37. INT3
  38. #ELSE
  39. unimplemented
  40. #END
  41. END Reset;
  42. PROCEDURE {NORETURN} Halt-;
  43. CODE
  44. #IF I386 THEN
  45. CLI
  46. end: HLT
  47. JMP end
  48. #ELSIF AMD64 THEN
  49. CLI
  50. end: HLT
  51. JMP end
  52. #ELSE
  53. unimplemented
  54. #END
  55. END Halt;
  56. (* input / output ports *)
  57. PROCEDURE OutChar- (port: SIZE; value: CHAR);
  58. CODE
  59. #IF I386 THEN
  60. MOV AL, [EBP + value]
  61. MOV DX, [EBP + port]
  62. OUT DX, AL
  63. #ELSIF AMD64 THEN
  64. MOV AL, [RBP + value]
  65. MOV DX, [RBP + port]
  66. OUT DX, AL
  67. #ELSE
  68. unimplemented
  69. #END
  70. END OutChar;
  71. PROCEDURE OutByte- (port: SIZE; value: SIZE);
  72. CODE
  73. #IF I386 THEN
  74. MOV AL, [EBP + value]
  75. MOV DX, [EBP + port]
  76. OUT DX, AL
  77. #ELSIF AMD64 THEN
  78. MOV AL, [RBP + value]
  79. MOV DX, [RBP + port]
  80. OUT DX, AL
  81. #ELSE
  82. unimplemented
  83. #END
  84. END OutByte;
  85. PROCEDURE OutSet- (port: SIZE; value: SET);
  86. CODE
  87. #IF I386 THEN
  88. MOV AL, [EBP + value]
  89. MOV DX, [EBP + port]
  90. OUT DX, AL
  91. #ELSIF AMD64 THEN
  92. MOV AL, [RBP + value]
  93. MOV DX, [RBP + port]
  94. OUT DX, AL
  95. #ELSE
  96. unimplemented
  97. #END
  98. END OutSet;
  99. PROCEDURE InChar- (port: SIZE): CHAR;
  100. CODE
  101. #IF I386 THEN
  102. MOV DX, [EBP + port]
  103. IN AL, DX
  104. #ELSIF AMD64 THEN
  105. MOV DX, [RBP + port]
  106. IN AL, DX
  107. #ELSE
  108. unimplemented
  109. #END
  110. END InChar;
  111. PROCEDURE InByte- (port: SIZE): SIZE;
  112. CODE
  113. #IF I386 THEN
  114. MOV DX, [EBP + port]
  115. IN AL, DX
  116. MOVZX EAX, AL
  117. #ELSIF AMD64 THEN
  118. MOV DX, [RBP + port]
  119. IN AL, DX
  120. MOVZX EAX, AL
  121. #ELSE
  122. unimplemented
  123. #END
  124. END InByte;
  125. PROCEDURE InSet- (port: SIZE): SET;
  126. CODE
  127. #IF I386 THEN
  128. MOV DX, [EBP + port]
  129. IN AL, DX
  130. MOVZX EAX, AL
  131. #ELSIF AMD64 THEN
  132. MOV DX, [RBP + port]
  133. IN AL, DX
  134. MOVZX EAX, AL
  135. #ELSE
  136. unimplemented
  137. #END
  138. END InSet;
  139. PROCEDURE -SaveResult-;
  140. CODE
  141. #IF I386 THEN
  142. PUSH EAX
  143. PUSH EDX
  144. #ELSIF AMD64 THEN
  145. PUSH RAX
  146. #ELSE
  147. unimplemented
  148. #END
  149. END SaveResult;
  150. PROCEDURE -RestoreResultAndReturn-;
  151. CODE
  152. #IF I386 THEN
  153. POP EDX
  154. POP EAX
  155. LEA ESP, [EBP + 4]
  156. POP EBP
  157. RET
  158. #ELSIF AMD64 THEN
  159. POP RAX
  160. LEA RSP, [RBP + 8]
  161. POP RBP
  162. RET
  163. #ELSE
  164. unimplemented
  165. #END
  166. END RestoreResultAndReturn;
  167. PROCEDURE Mask- (port: SIZE; value: SET);
  168. BEGIN {UNCOOPERATIVE, UNCHECKED}
  169. OutSet (port, InSet (port) + value);
  170. END Mask;
  171. PROCEDURE Unmask- (port: SIZE; value: SET);
  172. BEGIN {UNCOOPERATIVE, UNCHECKED}
  173. OutSet (port, InSet (port) - value);
  174. END Unmask;
  175. (* interrupt handling *)
  176. CONST Interrupts* = 48;
  177. CONST IRQ0* = 32; IRQ1* = 33; IRQ2* = 34; IRQ3* = 35; IRQ4* = 36; IRQ5* = 37; IRQ6* = 38; IRQ7* = 39;
  178. CONST IRQ8* = 40; IRQ9* = 41; IRQ10* = 42; IRQ11* = 43; IRQ12* = 44; IRQ13* = 45; IRQ14* = 46; IRQ15* = 47;
  179. CONST PIC1CommandPort = 020H; PIC1DataPort = 021H; PIC2CommandPort = 0A0H; PIC2DataPort = 0A1H;
  180. CONST ICW1_ICW4 = 001H; ICW1_INIT = 010H; ICW4_8086 = 001H; PIC_EOI = 020H; PIC_READ_ISR = 00AH;
  181. TYPE InterruptHandler* = PROCEDURE (index: SIZE);
  182. VAR handlers: ARRAY Interrupts OF InterruptHandler;
  183. PROCEDURE InstallInterrupt- (handler: InterruptHandler; index: SIZE): InterruptHandler;
  184. VAR previous: InterruptHandler;
  185. BEGIN {UNCOOPERATIVE, UNCHECKED}
  186. ASSERT (handler # NIL); ASSERT (index < Interrupts);
  187. REPEAT previous := CAS (handlers[index], NIL, NIL) UNTIL CAS (handlers[index], previous, handler) = previous;
  188. IF previous = NIL THEN EnableIRQ (index) END;
  189. RETURN previous;
  190. END InstallInterrupt;
  191. PROCEDURE HandleInterrupt (index: SIZE);
  192. BEGIN {UNCOOPERATIVE, UNCHECKED}
  193. CODE
  194. #IF I386 THEN
  195. PUSHAD
  196. #ELSIF AMD64 THEN
  197. PUSH RAX
  198. PUSH RCX
  199. PUSH RDX
  200. PUSH RBX
  201. PUSH RSI
  202. PUSH RDI
  203. PUSH R8
  204. PUSH R9
  205. PUSH R10
  206. PUSH R11
  207. PUSH R12
  208. PUSH R13
  209. PUSH R14
  210. PUSH R15
  211. #ELSE
  212. unimplemented
  213. #END
  214. END;
  215. SYSTEM.SetActivity (NIL);
  216. IF handlers[index] # NIL THEN handlers[index] (index) ELSE HALT (1234) END;
  217. IF index >= IRQ8 THEN
  218. OutByte (PIC2CommandPort, PIC_EOI); OutByte (PIC1CommandPort, PIC_EOI);
  219. ELSIF index >= IRQ0 THEN
  220. OutByte (PIC1CommandPort, PIC_EOI);
  221. END;
  222. CODE
  223. #IF I386 THEN
  224. POPAD
  225. #ELSIF AMD64 THEN
  226. POP R15
  227. POP R14
  228. POP R13
  229. POP R12
  230. POP R11
  231. POP R10
  232. POP R9
  233. POP R8
  234. POP RDI
  235. POP RSI
  236. POP RBX
  237. POP RDX
  238. POP RCX
  239. POP RAX
  240. #ELSE
  241. unimplemented
  242. #END
  243. END;
  244. END HandleInterrupt;
  245. PROCEDURE DisableInterrupt- (index: SIZE);
  246. VAR previous: InterruptHandler;
  247. BEGIN {UNCOOPERATIVE, UNCHECKED}
  248. ASSERT (index < Interrupts);
  249. DisableIRQ (index);
  250. REPEAT previous := CAS (handlers[index], NIL, NIL) UNTIL CAS (handlers[index], previous, NIL) = previous;
  251. END DisableInterrupt;
  252. PROCEDURE EnableIRQ- (index: SIZE);
  253. BEGIN {UNCOOPERATIVE, UNCHECKED}
  254. ASSERT (index < Interrupts);
  255. IF (index >= IRQ0) & (index <= IRQ7) THEN Unmask (PIC1DataPort, {index - IRQ0}) END;
  256. IF (index >= IRQ8) & (index <= IRQ15) THEN Unmask (PIC2DataPort, {index - IRQ8}) END;
  257. END EnableIRQ;
  258. PROCEDURE DisableIRQ- (index: SIZE);
  259. BEGIN {UNCOOPERATIVE, UNCHECKED}
  260. ASSERT (index < Interrupts);
  261. IF (index >= IRQ0) & (index <= IRQ7) THEN Mask (PIC1DataPort, {index - IRQ0}) END;
  262. IF (index >= IRQ8) & (index <= IRQ15) THEN Mask (PIC2DataPort, {index - IRQ8}) END;
  263. END DisableIRQ;
  264. #IF I386 THEN
  265. VAR idt-: ARRAY Interrupts OF ARRAY 4 OF INTEGER;
  266. VAR wrapper: ARRAY Interrupts OF ARRAY 16 OF CHAR;
  267. PROCEDURE Initialize-;
  268. CONST IRETD = 0CFX; PUSH = 06AX; CALL = 0E8X; ADD = 083X; ESP = 0C4X;
  269. VAR i, c: SIZE; address: ADDRESS;
  270. BEGIN {UNCOOPERATIVE, UNCHECKED}
  271. (* ICW1: initialization *)
  272. OutByte (PIC1CommandPort, ICW1_INIT + ICW1_ICW4);
  273. OutByte (PIC2CommandPort, ICW1_INIT + ICW1_ICW4);
  274. (* ICW2: vector offsets *)
  275. OutByte (PIC1DataPort, IRQ0);
  276. OutByte (PIC2DataPort, IRQ8);
  277. (* ICW3: cascading *)
  278. OutByte (PIC1DataPort, 4);
  279. OutByte (PIC2DataPort, 2);
  280. (* ICW4: mode *)
  281. OutByte (PIC1DataPort, ICW4_8086);
  282. OutByte (PIC2DataPort, ICW4_8086);
  283. (* mask all maskable interrupts *)
  284. OutChar (PIC1DataPort, 0FBX);
  285. OutChar (PIC2DataPort, 0FFX);
  286. FOR i := 0 TO Interrupts - 1 DO
  287. IF (i # 9) & (i # 15) & ((i < 20) OR (i > 29)) & (i # 31) THEN
  288. idt[i][0] := INTEGER (ADDRESS OF wrapper[i] MOD 10000H);
  289. idt[i][1] := INTEGER(8H);
  290. idt[i][2] := INTEGER(8E00H);
  291. idt[i][3] := INTEGER(ADDRESS OF wrapper[i] DIV 10000H);
  292. c := 0;
  293. IF i # 2 THEN
  294. IF (i = 8) OR (i >= 10) & (i <= 14) OR (i = 17) THEN
  295. wrapper[i][c] := ADD; INC (c);
  296. wrapper[i][c] := ESP; INC (c);
  297. wrapper[i][c] := CHR (4); INC (c);
  298. END;
  299. wrapper[i][c] := PUSH; INC (c);
  300. wrapper[i][c] := CHR (i); INC (c);
  301. wrapper[i][c] := CALL; INC (c);
  302. address := ADDRESS OF HandleInterrupt - ADDRESS OF wrapper[i][c + 4];
  303. wrapper[i][c] := CHR (address DIV 1H); INC (c);
  304. wrapper[i][c] := CHR (address DIV 100H); INC (c);
  305. wrapper[i][c] := CHR (address DIV 10000H); INC (c);
  306. wrapper[i][c] := CHR (address DIV 1000000H); INC (c);
  307. wrapper[i][c] := ADD; INC (c);
  308. wrapper[i][c] := ESP; INC (c);
  309. wrapper[i][c] := CHR (4); INC (c);
  310. END;
  311. wrapper[i][c] := IRETD;
  312. ELSE
  313. idt[i][0] := 0;
  314. idt[i][1] := 0;
  315. idt[i][2] := 0;
  316. idt[i][3] := 0;
  317. END;
  318. END;
  319. CODE
  320. LEA EAX, idt
  321. PUSH EAX
  322. MOV AX, Interrupts * 8
  323. PUSH AX
  324. LIDT [ESP]
  325. STI
  326. END;
  327. END Initialize;
  328. #ELSIF AMD64 THEN
  329. VAR idt-: ARRAY Interrupts OF ARRAY 8 OF INTEGER;
  330. VAR wrapper: ARRAY Interrupts OF ARRAY 20 OF CHAR;
  331. PROCEDURE Initialize-;
  332. CONST IRETQ = 0CFX; PUSH = 06AX; CALL = 0E8X; REX = 048X; ADD = 083X; RSP = 0C4X;
  333. VAR i, c: SIZE; address: ADDRESS;
  334. BEGIN {UNCOOPERATIVE, UNCHECKED}
  335. (* ICW1: initialization *)
  336. OutByte (PIC1CommandPort, ICW1_INIT + ICW1_ICW4);
  337. OutByte (PIC2CommandPort, ICW1_INIT + ICW1_ICW4);
  338. (* ICW2: vector offsets *)
  339. OutByte (PIC1DataPort, IRQ0);
  340. OutByte (PIC2DataPort, IRQ8);
  341. (* ICW3: cascading *)
  342. OutByte (PIC1DataPort, 4);
  343. OutByte (PIC2DataPort, 2);
  344. (* ICW4: mode *)
  345. OutByte (PIC1DataPort, ICW4_8086);
  346. OutByte (PIC2DataPort, ICW4_8086);
  347. (* mask all maskable interrupts *)
  348. OutChar (PIC1DataPort, 0FBX);
  349. OutChar (PIC2DataPort, 0FFX);
  350. FOR i := 0 TO Interrupts - 1 DO
  351. IF (i # 9) & (i # 15) & ((i < 20) OR (i > 29)) & (i # 31) THEN
  352. idt[i][0] := INTEGER (ADDRESS OF wrapper[i] MOD 10000H);
  353. idt[i][1] := INTEGER(8H);
  354. idt[i][2] := INTEGER(8E00H);
  355. idt[i][3] := INTEGER(ADDRESS OF wrapper[i] DIV 10000H);
  356. c := 0;
  357. IF i # 2 THEN
  358. IF (i = 8) OR (i >= 10) & (i <= 14) OR (i = 17) THEN
  359. wrapper[i][c] := REX; INC (c);
  360. wrapper[i][c] := ADD; INC (c);
  361. wrapper[i][c] := RSP; INC (c);
  362. wrapper[i][c] := CHR (8); INC (c);
  363. END;
  364. wrapper[i][c] := PUSH; INC (c);
  365. wrapper[i][c] := CHR (i); INC (c);
  366. wrapper[i][c] := CALL; INC (c);
  367. address := ADDRESS OF HandleInterrupt - ADDRESS OF wrapper[i][c + 4];
  368. wrapper[i][c] := CHR (address DIV 1H); INC (c);
  369. wrapper[i][c] := CHR (address DIV 100H); INC (c);
  370. wrapper[i][c] := CHR (address DIV 10000H); INC (c);
  371. wrapper[i][c] := CHR (address DIV 1000000H); INC (c);
  372. wrapper[i][c] := REX; INC (c);
  373. wrapper[i][c] := ADD; INC (c);
  374. wrapper[i][c] := RSP; INC (c);
  375. wrapper[i][c] := CHR (8); INC (c);
  376. END;
  377. wrapper[i][c] := IRETQ;
  378. ELSE
  379. idt[i][0] := 0;
  380. idt[i][1] := 0;
  381. idt[i][2] := 0;
  382. idt[i][3] := 0;
  383. END;
  384. idt[i][4] := 0;
  385. idt[i][5] := 0;
  386. idt[i][6] := 0;
  387. idt[i][7] := 0;
  388. END;
  389. CODE
  390. LEA RAX, idt
  391. PUSH RAX
  392. MOV AX, Interrupts * 8
  393. PUSH AX
  394. LIDT [RSP]
  395. STI
  396. END;
  397. END Initialize;
  398. #ELSE
  399. unimplemented
  400. #END
  401. END CPU.