BIOS.Environment.Mod 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. (* Runtime environment for BIOS *)
  2. (* Copyright (C) Florian Negele *)
  3. MODULE Environment;
  4. IMPORT SYSTEM, CPU, ACPI, Activities, HeapManager, Interrupts, Processors, Timer, Trace;
  5. CONST IsNative* = TRUE;
  6. CONST Running* = 0; ShuttingDown* = 1; Rebooting* = 2;
  7. CONST HeapAdr = 100000H;
  8. CONST MaxMemTop = 80000000H;
  9. CONST TraceV24 = 2; TraceScreen = 0;
  10. CONST TraceWidth = 80; TraceHeight = 25;
  11. CONST TraceLen = TraceWidth * SIZEOF (INTEGER);
  12. CONST TraceSize = TraceLen * TraceHeight;
  13. VAR memory: SIZE;
  14. VAR traceMode: SET;
  15. VAR bootFlag: ADDRESS;
  16. VAR clock: LONGINT;
  17. VAR status-: WORD;
  18. VAR memTop: ADDRESS;
  19. VAR traceBase: ADDRESS;
  20. VAR heap: HeapManager.Heap;
  21. VAR config: ARRAY 2048 OF CHAR;
  22. VAR initRegs: ARRAY 2OF ADDRESS;
  23. VAR tracePort, tracePos, traceColor: SIZE;
  24. VAR previousTimerHandler: CPU.InterruptHandler;
  25. PROCEDURE {NORETURN} Abort-;
  26. BEGIN {UNCOOPERATIVE, UNCHECKED}
  27. IF SYSTEM.GetActivity () # NIL THEN Activities.TerminateCurrentActivity END;
  28. Exit (ShuttingDown);
  29. END Abort;
  30. PROCEDURE Shutdown*;
  31. BEGIN {UNCOOPERATIVE, UNCHECKED}
  32. IF CAS (status, Running, ShuttingDown) # Running THEN RETURN END;
  33. Trace.StringLn ("system: shutting down...");
  34. END Shutdown;
  35. PROCEDURE Reboot*;
  36. BEGIN {UNCOOPERATIVE, UNCHECKED}
  37. Shutdown;
  38. ASSERT (CAS (status, ShuttingDown, Rebooting) = ShuttingDown);
  39. END Reboot;
  40. PROCEDURE {NORETURN} Exit- (status: WORD);
  41. VAR index: SIZE;
  42. BEGIN {UNCOOPERATIVE, UNCHECKED}
  43. Trace.String ("system: ");
  44. IF status = Rebooting THEN Trace.StringLn ("rebooting..."); CPU.Reset END;
  45. Trace.StringLn ("ready for power off or restart"); CPU.Halt;
  46. END Exit;
  47. PROCEDURE Clock- (): LONGINT;
  48. BEGIN {UNCOOPERATIVE, UNCHECKED}
  49. RETURN clock;
  50. END Clock;
  51. PROCEDURE Sleep- (milliseconds: LONGINT);
  52. VAR interrupt: Interrupts.Interrupt;
  53. BEGIN {UNCOOPERATIVE, UNCHECKED}
  54. Interrupts.Install (interrupt, CPU.IRQ0); INC (milliseconds, clock);
  55. WHILE (status = Running) & (clock - milliseconds < 0) DO Interrupts.Await (interrupt) END;
  56. END Sleep;
  57. PROCEDURE HandleTimerInterrupt (index: SIZE);
  58. BEGIN {UNCOOPERATIVE, UNCHECKED}
  59. INC (clock);
  60. END HandleTimerInterrupt;
  61. PROCEDURE Allocate- (size: SIZE): ADDRESS;
  62. VAR result, address: ADDRESS;
  63. BEGIN {UNCOOPERATIVE, UNCHECKED}
  64. result := HeapManager.Allocate (size, heap);
  65. IF result = NIL THEN RETURN NIL END;
  66. FOR address := result TO result + size - 1 DO SYSTEM.PUT8 (address, 0) END;
  67. RETURN result;
  68. END Allocate;
  69. PROCEDURE Deallocate- (address: ADDRESS);
  70. BEGIN {UNCOOPERATIVE, UNCHECKED}
  71. HeapManager.Deallocate (address, heap);
  72. END Deallocate;
  73. PROCEDURE StrToInt (VAR i: LONGINT; CONST s: ARRAY OF CHAR): LONGINT;
  74. VAR vd, vh, sgn, d: LONGINT; hex: BOOLEAN;
  75. BEGIN {UNCOOPERATIVE, UNCHECKED}
  76. vd := 0; vh := 0; hex := FALSE;
  77. IF s[i] = "-" THEN sgn := -1; INC (i) ELSE sgn := 1 END;
  78. LOOP
  79. IF (s[i] >= "0") & (s[i] <= "9") THEN d := ORD (s[i])-ORD ("0")
  80. ELSIF (CAP (s[i]) >= "A") & (CAP (s[i]) <= "F") THEN d := ORD (CAP (s[i]))-ORD ("A") + 10; hex := TRUE
  81. ELSE EXIT
  82. END;
  83. vd := 10*vd + d; vh := 16*vh + d;
  84. INC (i)
  85. END;
  86. IF CAP (s[i]) = "H" THEN hex := TRUE; INC (i) END; (* optional H *)
  87. IF hex THEN vd := vh END;
  88. RETURN sgn * vd
  89. END StrToInt;
  90. PROCEDURE GetString- (CONST name: ARRAY OF CHAR; VAR result: ARRAY OF CHAR);
  91. VAR i, src: LONGINT; ch: CHAR;
  92. BEGIN {UNCOOPERATIVE, UNCHECKED}
  93. ASSERT (name[0] # "="); (* no longer supported, use GetInit instead *)
  94. src := 0;
  95. LOOP
  96. ch := config[src];
  97. IF ch = 0X THEN EXIT END;
  98. i := 0;
  99. LOOP
  100. ch := config[src];
  101. IF (ch # name[i]) OR (name[i] = 0X) THEN EXIT END;
  102. INC (i); INC (src)
  103. END;
  104. IF (ch = 0X) & (name[i] = 0X) THEN (* found: (src^ = 0X) & (name[i] = 0X) *)
  105. i := 0;
  106. REPEAT
  107. INC (src); ch := config[src]; result[i] := ch; INC (i);
  108. IF i = LEN(result) THEN result[i - 1] := 0X; RETURN END (* val too short *)
  109. UNTIL ch = 0X;
  110. result[i] := 0X; RETURN
  111. ELSE
  112. WHILE ch # 0X DO (* skip to end of name *)
  113. INC (src); ch := config[src]
  114. END;
  115. INC (src);
  116. REPEAT (* skip to end of value *)
  117. ch := config[src]; INC (src)
  118. UNTIL ch = 0X
  119. END
  120. END;
  121. result[0] := 0X
  122. END GetString;
  123. PROCEDURE ReadBootTable (bt: ADDRESS);
  124. VAR i, p: ADDRESS; j, d, type, addr, size, heapSize: LONGINT; ch: CHAR;
  125. BEGIN {UNCOOPERATIVE, UNCHECKED}
  126. heapSize := 0;
  127. p := bt; d := 0;
  128. LOOP
  129. SYSTEM.GET (p, type);
  130. IF type = -1 THEN
  131. EXIT (* end *)
  132. ELSIF type = 3 THEN (* boot memory/top of low memory *)
  133. SYSTEM.GET (p + 8, addr); SYSTEM.GET (p + 12, size);
  134. ELSIF type = 4 THEN (* free memory/extended memory size *)
  135. SYSTEM.GET (p + 8, addr); SYSTEM.GET (p + 12, size);
  136. IF addr = HeapAdr THEN heapSize := size END
  137. ELSIF type = 5 THEN (* HD config *)
  138. ELSIF type = 8 THEN (* config strings *)
  139. i := p + 8; j := 0; (* copy the config strings over *)
  140. LOOP
  141. SYSTEM.GET (i, ch); config[j] := ch; INC (i); INC (j);
  142. IF ch = 0X THEN EXIT END;
  143. REPEAT SYSTEM.GET (i, ch); config[j] := ch; INC (i); INC (j) UNTIL ch = 0X; (* end of name *)
  144. REPEAT SYSTEM.GET (i, ch); config[j] := ch; INC (i); INC (j) UNTIL ch = 0X (* end of value *)
  145. END
  146. END;
  147. SYSTEM.GET (p + 4, size); INC (p, size)
  148. END;
  149. memTop := HeapAdr + heapSize
  150. END ReadBootTable;
  151. PROCEDURE TraceChar (c: CHAR);
  152. VAR status: SIZE;
  153. (* Scroll the screen by one line. *)
  154. PROCEDURE Scroll;
  155. VAR adr: ADDRESS; off: SIZE;
  156. BEGIN {UNCOOPERATIVE, UNCHECKED}
  157. adr := traceBase + TraceLen;
  158. SYSTEM.MOVE (adr, adr - TraceLen, TraceSize - TraceLen);
  159. adr := traceBase + TraceSize - TraceLen;
  160. FOR off := 0 TO TraceLen - SIZEOF(INTEGER) BY SIZEOF(INTEGER) DO SYSTEM.PUT16 (adr + off, 100H * 7H + 32) END
  161. END Scroll;
  162. BEGIN {UNCOOPERATIVE, UNCHECKED}
  163. IF TraceV24 IN traceMode THEN
  164. REPEAT (* wait until port is ready to accept a character *)
  165. status := CPU.InByte (tracePort + 5)
  166. UNTIL ODD (status DIV 20H); (* THR empty *)
  167. CPU.OutChar (tracePort, c);
  168. END;
  169. IF TraceScreen IN traceMode THEN
  170. IF c = 9X THEN c := 20X END;
  171. IF c = 0DX THEN (* CR *)
  172. DEC (tracePos, tracePos MOD TraceLen)
  173. ELSIF c = 0AX THEN (* LF *)
  174. IF tracePos < TraceSize THEN
  175. INC (tracePos, TraceLen) (* down to next line *)
  176. ELSE
  177. Scroll
  178. END
  179. ELSE
  180. IF tracePos >= TraceSize THEN
  181. Scroll;
  182. DEC (tracePos, TraceLen)
  183. END;
  184. SYSTEM.PUT16 (traceBase + tracePos, 100H * traceColor + ORD (c));
  185. INC (tracePos, SIZEOF(INTEGER))
  186. END
  187. END
  188. END TraceChar;
  189. PROCEDURE TraceColor (c: SHORTINT);
  190. BEGIN {UNCOOPERATIVE, UNCHECKED} traceColor := c;
  191. END TraceColor;
  192. PROCEDURE InitTrace;
  193. CONST MaxPorts = 8;
  194. VAR i, p, bps: LONGINT; off: SIZE; s, name: ARRAY 32 OF CHAR;
  195. baselist: ARRAY MaxPorts OF LONGINT;
  196. BEGIN {UNCOOPERATIVE, UNCHECKED}
  197. GetString ("TraceMode", s);
  198. p := 0; traceMode := SYSTEM.VAL (SET, StrToInt (p, s));
  199. IF TraceScreen IN traceMode THEN
  200. GetString ("TraceMem", s);
  201. p := 0; traceBase := SYSTEM.VAL (ADDRESS, StrToInt (p, s));
  202. IF traceBase = 0 THEN traceBase := 0B8000H END; (* default screen buffer *)
  203. FOR off := 0 TO TraceSize - SIZEOF(INTEGER) BY SIZEOF(INTEGER) DO SYSTEM.PUT16 (traceBase + off, 100H * 7H + 32) END;
  204. tracePos := 0;
  205. CPU.OutByte(3D4H, 0EH);
  206. CPU.OutByte(3D5H, (TraceWidth*TraceHeight) DIV 100H);
  207. CPU.OutByte(3D4H, 0FH);
  208. CPU.OutByte(3D5H, (TraceWidth*TraceHeight) MOD 100H)
  209. END;
  210. IF TraceV24 IN traceMode THEN
  211. FOR i := 0 TO MaxPorts - 1 DO
  212. COPY ("COMx", name); name[3] := CHR (ORD ("1") + i);
  213. GetString (name, s); p := 0; baselist[i] := StrToInt (p, s);
  214. END;
  215. IF baselist[0] = 0 THEN baselist[0] := 3F8H END; (* COM1 port default values *)
  216. IF baselist[1] = 0 THEN baselist[1] := 2F8H END; (* COM2 port default values *)
  217. GetString("TracePort", s); p := 0; p := StrToInt(p, s); DEC(p);
  218. IF (p >= 0) & (p < MaxPorts) THEN tracePort := baselist[p] ELSE tracePort := baselist[0] END;
  219. ASSERT(tracePort > 0);
  220. GetString("TraceBPS", s); p := 0; bps := StrToInt(p, s);
  221. IF bps <= 0 THEN bps := 38400 END;
  222. CPU.OutByte (tracePort + 3, 80H); (* Set the Divisor Latch Bit - DLAB = 1 *)
  223. bps := 115200 DIV bps; (* compiler DIV/PORTOUT bug workaround *)
  224. CPU.OutByte (tracePort + 1, bps DIV 100H); (* Set the Divisor Latch MSB *)
  225. CPU.OutByte (tracePort, bps MOD 100H); (* Set the Divisor Latch LSB *)
  226. CPU.OutByte (tracePort + 3, 3H); (* 8N1 *)
  227. CPU.OutByte (tracePort + 4, 3H); (* Set DTR, RTS on in the MCR *)
  228. CPU.OutByte (tracePort + 1, 0H); (* Disable receive interrupts *)
  229. END;
  230. Trace.Init;
  231. traceColor := 7; Trace.Char := TraceChar; Trace.Color := TraceColor;
  232. END InitTrace;
  233. (* Check if the specified address is RAM. *)
  234. PROCEDURE IsRAM(adr: ADDRESS): BOOLEAN;
  235. CONST Pattern1 = 0BEEFC0DEH; Pattern2 = 0AA55FF00H;
  236. VAR save, x: ADDRESS; ok: BOOLEAN;
  237. BEGIN {UNCOOPERATIVE, UNCHECKED}
  238. ok := FALSE;
  239. SYSTEM.GET (adr, save);
  240. SYSTEM.PUT (adr, Pattern1); (* attempt 1st write *)
  241. x := Pattern2; (* write something else *)
  242. SYSTEM.GET (adr, x); (* attempt 1st read *)
  243. IF x = Pattern1 THEN (* first test passed *)
  244. SYSTEM.PUT (adr, Pattern2); (* attempt 2nd write *)
  245. x := Pattern1; (* write something else *)
  246. SYSTEM.GET (adr, x); (* attempt 2nd read *)
  247. ok := (x = Pattern2)
  248. END;
  249. SYSTEM.PUT (adr, save);
  250. RETURN ok
  251. END IsRAM;
  252. (* Check amount of memory available and update memTop. *)
  253. PROCEDURE CheckMemory;
  254. CONST M = 100000H; ExtMemAdr = M; Step = M;
  255. VAR s: ARRAY 16 OF CHAR; adr: ADDRESS; i: LONGINT;
  256. BEGIN {UNCOOPERATIVE, UNCHECKED}
  257. GetString("ExtMemSize", s); (* in MB *)
  258. IF s[0] # 0X THEN (* override detection *)
  259. i := 0; memTop := ExtMemAdr + StrToInt(i, s) * M;
  260. ELSE
  261. IF memTop >= 15*M THEN (* search for more memory (ignore aliasing) *)
  262. adr := memTop-4;
  263. WHILE (LSH(memTop, -12) < LSH(MaxMemTop, -12)) & IsRAM(adr) DO
  264. memTop := adr + 4;
  265. INC (adr, Step)
  266. END;
  267. IF (memTop <= 0) THEN memTop := 2047 * M ; END;
  268. END
  269. END;
  270. END CheckMemory;
  271. PROCEDURE SetupTimer (channel, mode: SHORTINT; frequency: LONGINT);
  272. CONST CommandPort = 043H; AccessLoHiByte = 030H; Binary = 000H; Channel0Port = 040H;
  273. CONST OscillatorFrequency = 1193180;
  274. VAR divisor: SIZE;
  275. BEGIN {UNCOOPERATIVE, UNCHECKED}
  276. ASSERT (frequency > 1);
  277. ASSERT (frequency < OscillatorFrequency);
  278. divisor := OscillatorFrequency DIV frequency;
  279. CPU.OutByte (CommandPort, AccessLoHiByte + Binary + mode + channel * 64);
  280. CPU.OutChar (Channel0Port + channel, CHR (divisor MOD 100H));
  281. CPU.OutChar (Channel0Port + channel, CHR (divisor DIV 100H));
  282. END SetupTimer;
  283. PROCEDURE GetInit- (n: SIZE; VAR val: LONGINT);
  284. BEGIN val := initRegs[n]
  285. END GetInit;
  286. PROCEDURE Initialize-;
  287. CONST Channel0 = 0; RateGenerator = 4;
  288. BEGIN {UNCOOPERATIVE, UNCHECKED}
  289. SYSTEM.SetActivity (NIL);
  290. CPU.Initialize;
  291. ACPI.Initialize;
  292. Timer.Initialize;
  293. ReadBootTable (bootFlag);
  294. InitTrace;
  295. CheckMemory;
  296. memory := memTop - ADDRESS OF KernelEnd;
  297. HeapManager.Initialize (heap, ADDRESS OF KernelEnd, memTop);
  298. previousTimerHandler := CPU.InstallInterrupt (HandleTimerInterrupt, CPU.IRQ0);
  299. SetupTimer (Channel0, RateGenerator, 1000);
  300. END Initialize;
  301. PROCEDURE Terminate-;
  302. BEGIN {UNCOOPERATIVE, UNCHECKED}
  303. END Terminate;
  304. PROCEDURE {NOPAF, INITIAL, FIXED(100000H)} KernelBegin;
  305. CODE
  306. MOV bootFlag, EAX
  307. LEA EAX, initRegs
  308. MOV [EAX + 0], ESI
  309. MOV [EAX + 4], EDI
  310. END KernelBegin;
  311. PROCEDURE {NOPAF, FINAL, ALIGNED(32)} KernelEnd;
  312. CODE {SYSTEM.i386}
  313. END KernelEnd;
  314. BEGIN
  315. Trace.String ("Build "); Trace.String (SYSTEM.Date); Trace.String (" (");
  316. Trace.Int (memory DIV (1024 * 1024), 0); Trace.String (" MB RAM, ");
  317. Trace.String ("GC, ");
  318. Trace.Int (Processors.count, 0); Trace.String (" CPU");
  319. IF Processors.count > 1 THEN Trace.Char ('s') END; Trace.String (", ");
  320. Trace.Int (SIZE OF ADDRESS * 8, 0); Trace.String ("-bit)"); Trace.Ln;
  321. END Environment.