2
0

Oberon.Kernel.Mod 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
  2. MODULE Kernel IN Oberon;
  3. (** AUTHOR "pjm"; PURPOSE "Oberon for Aos kernel"; *)
  4. IMPORT Machine IN A2, KernelLog IN A2, Objects IN A2, Kernel IN A2, Clock IN A2;
  5. CONST
  6. LittleEndian* = TRUE; (** byte order of basic types *)
  7. LsbIs0* = TRUE; (** bit order of SET type *)
  8. (*
  9. CONST
  10. (* timer *)
  11. TimeUnit* = Kernel.Second; (* timer ticks per second, returned by GetTimer *) (* not a constant! *)
  12. *)
  13. TYPE
  14. (*Name* = Modules.Name; (* module name *)
  15. Proc* = Modules.TerminationHandler;
  16. Cmd* = Modules.Command;
  17. Module* = Modules.Module; (* module descriptor *)
  18. ModuleDesc* = Modules.ModuleDesc;*)
  19. (*TrapHandler* = PROCEDURE (err, fp, pc, pf: LONGINT);*)
  20. Finalizer* = PROCEDURE (obj: ANY);
  21. (*MilliTimer* = Kernel.MilliTimer;*)
  22. OberonFinalizer = OBJECT
  23. VAR fin: Finalizer; next: OberonFinalizer; obj: ANY;
  24. PROCEDURE Finalize(obj: ANY);
  25. BEGIN (* assume only one finalization thread, so don't need to protect globals here *)
  26. DEC(NfinalizeAlive); INC(NfinalizeDead);
  27. SELF.obj := obj; (* anchor object *)
  28. next := finalizeRoot; finalizeRoot := SELF (* add to list, to be called by Oberon *)
  29. END Finalize;
  30. END OberonFinalizer;
  31. VAR
  32. (* exported variables *)
  33. version*: ARRAY 64 OF CHAR;
  34. (*break* : BOOLEAN;*) (** has ctrl-break been pressed? *) (* for Input *)
  35. (*inGC*: BOOLEAN;*) (* executing inside GC? *) (* for Input *)
  36. (*copro*: BOOLEAN;*) (* is a coprocessor present? *) (* for Reals *)
  37. (*modules* : Modules.Module;*) (** fake list of modules *) (* for Compiler *)
  38. (*shutdown*: LONGINT;*)
  39. (*
  40. (*StackOrg* : LONGINT;*) (** highest address on stack (single-process system) *)
  41. (*bt*: LONGINT;*) (** boot table *)
  42. (*tspeed*: LONGINT;*) (** =0: no tracing, >0: tspeed = speed of com output, <0: -tspeed = screen segment *)
  43. (*tbase*: INTEGER;*) (** trace base port, 3F8H=com1, 2F8H=com2, etc. *)
  44. (*EnableGC*, DisableGC*: Proc;*) (** Enable or Disable the GC *)
  45. (*timer*: Proc;*) (** for internal use *)
  46. (*runtime*: ARRAY 5 OF LONGINT;*) (** for internal use *)
  47. *)
  48. lockedBy: ANY;
  49. level: LONGINT;
  50. oberon: ANY;
  51. finalizeRoot: OberonFinalizer; (* finalizers that have to be executed by Oberon *)
  52. NfinalizeAlive, NfinalizeDead: LONGINT;
  53. finalizers: Kernel.FinalizedCollection; (* collection for all Oberon finalizers *)
  54. (** -- Low-level tracing support -- *)
  55. (** WriteChar - Write a character to the trace output *)
  56. PROCEDURE WriteChar*(c: CHAR);
  57. BEGIN
  58. KernelLog.Char(c)
  59. END WriteChar;
  60. (** WriteString - Write a string *)
  61. PROCEDURE WriteString*(s: ARRAY OF CHAR);
  62. BEGIN
  63. KernelLog.String(s)
  64. END WriteString;
  65. (** WriteLn - Skip to the next line on trace output *)
  66. PROCEDURE WriteLn*;
  67. BEGIN
  68. KernelLog.Ln
  69. END WriteLn;
  70. (** WriteInt - Write "x" as a decimal number. "w" is the field width. *)
  71. PROCEDURE WriteInt*(x, w: LONGINT);
  72. BEGIN
  73. KernelLog.Int(x, w)
  74. END WriteInt;
  75. (** WriteHex - Write "x" as a hexadecimal number. The absolute value of "w" is the field width. If "w" is negative, two hex digits are printed (x MOD 100H), otherwise 8 digits are printed. *)
  76. PROCEDURE WriteHex*(x, w: LONGINT);
  77. BEGIN
  78. KernelLog.Hex(x, w)
  79. END WriteHex;
  80. (** WriteMemory - Display a block of memory. *)
  81. PROCEDURE WriteMemory*(adr, size: LONGINT);
  82. BEGIN
  83. KernelLog.Memory(adr, size)
  84. END WriteMemory;
  85. (* -- Trap handling -- *)
  86. (*(** GetMod - Return the loaded module that contains code address pc. *)
  87. PROCEDURE GetMod*(pc : LONGINT): Module;
  88. BEGIN
  89. RETURN Modules.ModuleByAdr(pc)
  90. END GetMod;*)
  91. (*(** InstallTrap - Install the trap handler *)
  92. PROCEDURE InstallTrap*(p: TrapHandler);
  93. BEGIN
  94. handler := p
  95. END InstallTrap;*)
  96. (*(** InstallLoop - Install procedure to which control is transferred after a trap *)
  97. PROCEDURE InstallLoop*(p: Proc);
  98. BEGIN
  99. loop := p
  100. END InstallLoop;*)
  101. (*(** -- Interrupt handling -- *)*)
  102. (*(** InstallIP - Install interrupt handler & enable IRQ if necessary.
  103. "p" must be defined as a normal "PROCEDURE p;". On entry to p interrupts
  104. are disabled and may be enabled with SYSTEM.STI(). At exit from p the
  105. state of interrupts are restored. The acknowledgement of a hardware interrupt
  106. is done by the Kernel. No end-of-interrupt has to be signalled explicitly in
  107. procedure p. IRQs are mapped starting at interrupt Kernel.IRQ.
  108. At entry to procedure p the stack is as follows:
  109. 56 EFLAGS''
  110. 52 CS''
  111. 48 EIP'' (IRETD from glue code)
  112. 44 errorcode
  113. 40 intnum <-- ESP'
  114. 36 EAX
  115. 32 ECX
  116. 28 EDX
  117. 24 EBX
  118. 20 ESP'
  119. 16 EBP
  120. 12 ESI
  121. 08 EDI
  122. 04 EIP' (RET from p)
  123. 00 EBP' <-- EBP
  124. xx locals <-- ESP
  125. Interrupt priorities (highest to lowest):
  126. IRQ Common use
  127. 00 Timer
  128. 01 Keyboard
  129. 08 RT clock
  130. 09 EGA/VGA retrace
  131. 10 Ethernet or other card
  132. 11 card
  133. 12 PS/2 mouse or card
  134. 13 DMA/copro
  135. 14 Hard disk
  136. 15 card or IRQ error
  137. 03 COM2/4
  138. 04 COM1/3
  139. 05 card
  140. 06 Diskette
  141. 07 LPT1 or IRQ error
  142. *)
  143. PROCEDURE InstallIP*(p: Proc; i: INTEGER);
  144. BEGIN
  145. END InstallIP;*)
  146. (*(** RemoveIP - Uninstall interrupt handler & disable IRQ if necessary *)
  147. PROCEDURE RemoveIP*(p: Proc; i: INTEGER);
  148. BEGIN
  149. END RemoveIP;*)
  150. (** -- Memory/Object management -- *)
  151. (*
  152. (** Available - Return the size in bytes of the remaining free heap space *)
  153. PROCEDURE Available*(): LONGINT;
  154. BEGIN
  155. RETURN 0
  156. END Available;
  157. (** LargestAvailable - Return the size in bytes of the largest free available memory block.
  158. Allocating objects with a size greater than this size will cause the memory allocation to fail. *)
  159. PROCEDURE LargestAvailable*(): LONGINT;
  160. BEGIN
  161. RETURN 0
  162. END LargestAvailable;
  163. *)
  164. (** Used - Return the size in bytes of the amount of memory currently in use in the heap (not implemented on Aos). *)
  165. PROCEDURE Used*(): LONGINT;
  166. BEGIN
  167. RETURN 0
  168. END Used;
  169. (** GC - Immediately activate the garbage collector (on Aos, call the Oberon-based finalizers). *)
  170. PROCEDURE GC*;
  171. VAR of: OberonFinalizer;
  172. BEGIN
  173. CheckOberonLock; (* must hold Oberon lock *)
  174. WHILE finalizeRoot # NIL DO
  175. of := finalizeRoot; finalizeRoot := of.next; DEC(NfinalizeDead);
  176. of.fin(of.obj) (* call Oberon finalizer *)
  177. END
  178. END GC;
  179. (*(** NewDMA - Allocate memory correctly aligned for byte or word DMA in device drivers.
  180. "adr" returns the virtual and "phys" the physical address of the memory. To deallocate,
  181. call with size = -(size of block) and adr = virtual address of block. Max size=64k. *)
  182. PROCEDURE NewDMA*(size: LONGINT; VAR adr, phys: LONGINT);
  183. BEGIN
  184. END NewDMA;*)
  185. (*
  186. (** MapPhysical - Map a physical memory area into the virtual address space. {physAdr, size MOD PS = 0} *)
  187. PROCEDURE MapPhysical*(physAdr, size: LONGINT; VAR virtAdr: LONGINT);
  188. BEGIN
  189. Machine.MapPhysical(physAdr, size, virtAdr)
  190. END MapPhysical;
  191. *)
  192. (*
  193. (** DisableTracing - Disable the GC tracing of a record field of the specified type. For internal use only. *)
  194. PROCEDURE DisableTracing*(recadr, fldadr: LONGINT);
  195. BEGIN
  196. (*KernelLog.String("DisableTracing"); KernelLog.Hex(recadr, 9); KernelLog.Hex(fldadr, 9);
  197. KernelLog.Ln*)
  198. END DisableTracing;
  199. *)
  200. (** RegisterObject - Register a record for finalization. basic = FALSE *)
  201. PROCEDURE RegisterObject*(obj: ANY; fin: Finalizer; basic: BOOLEAN);
  202. VAR of: OberonFinalizer;
  203. BEGIN
  204. NEW(of); of.fin := fin; INC(NfinalizeAlive);
  205. finalizers.Add(obj, of.Finalize);
  206. (* when obj unreachable, Aos GC calls of.Finalizer, which will enqueue obj for calling by GC in this module, which is called by Oberon.Collect and periodically by the Oberon loop *)
  207. END RegisterObject;
  208. (*
  209. (** InstallTermHandler - Install a procedure to execute when a module is freed. Normally used to uninstall
  210. interrupt handlers or tasks and perform other cleanup duties. *)
  211. PROCEDURE InstallTermHandler* (h: Modules.TerminationHandler);
  212. BEGIN
  213. Modules.InstallTermHandler(h)
  214. END InstallTermHandler;
  215. *)
  216. (** -- Clock/Timer -- *)
  217. (** GetClock - Return current time and date *)
  218. PROCEDURE GetClock*(VAR time, date: LONGINT);
  219. BEGIN
  220. Clock.Get(time, date)
  221. END GetClock;
  222. (** SetClock - Set current time and date *)
  223. PROCEDURE SetClock*(time, date: LONGINT);
  224. BEGIN
  225. Clock.Set(time, date)
  226. END SetClock;
  227. (*
  228. (** GetTimer - Return "ticks" since initialisation (Kernel.TimeUnit ticks per second) *)
  229. PROCEDURE GetTimer*(): LONGINT;
  230. BEGIN
  231. RETURN Kernel.GetTicks()
  232. END GetTimer;
  233. (** SetTimer - Set timer to expire in approximately "ms" milliseconds. *)
  234. PROCEDURE SetTimer*(VAR t: MilliTimer; ms: LONGINT);
  235. BEGIN
  236. Kernel.SetTimer(t, ms)
  237. END SetTimer;
  238. (** Expired - Test if a timer has expired. Interrupts must be on. *)
  239. PROCEDURE Expired*(VAR t: MilliTimer): BOOLEAN;
  240. BEGIN
  241. RETURN Kernel.Expired(t)
  242. END Expired;
  243. *)
  244. (** -- Miscellaneous -- *)
  245. (** GetConfig - Return value of configuration string. Returns empty val if name not found. *)
  246. PROCEDURE GetConfig*(name: ARRAY OF CHAR; VAR val: ARRAY OF CHAR);
  247. BEGIN
  248. Machine.GetConfig(name, val)
  249. END GetConfig;
  250. (*
  251. (* ------------------------------------------------------------------------------------------------*)
  252. (* Shutdown - Terminate Oberon after executing all module terminators. If code = 1, perform an APM power-down, if code = 2, perform a soft reboot, or else just switch off interrupts and loop endlessly. *)
  253. PROCEDURE Shutdown*(code: LONGINT);
  254. BEGIN
  255. shutdown := code;
  256. Modules.Shutdown(code)
  257. END Shutdown;
  258. *)
  259. (*
  260. (** Idle - Called when system is idle. *)
  261. PROCEDURE Idle*(code: LONGINT); (* code currently unused *)
  262. BEGIN
  263. Objects.Yield
  264. END Idle;
  265. *)
  266. (*
  267. PROCEDURE TerminateInLock;
  268. BEGIN
  269. BEGIN {EXCLUSIVE}
  270. IF lockedBy = Objects.ActiveObject() THEN (* if we held it, release the lock *)
  271. lockedBy := NIL; level := 0 (* allow Oberon.Loop to re-acquire lock *)
  272. END
  273. END;
  274. Objects.Terminate (* fixme: should really call CurrentProcess().restartEIP *)
  275. END TerminateInLock;
  276. *)
  277. (* Handle exception that occurred while holding Oberon lock. *)
  278. (*
  279. PROCEDURE ExceptionInLock(p: Objects.Process; VAR int: Machine.State; VAR exc: Machine.ExceptionState; VAR return: BOOLEAN);
  280. VAR proc: PROCEDURE;
  281. BEGIN
  282. IF p.obj # oberon THEN (* similar to Traps.Exception *)
  283. Traps.Show(p, int, exc, TRUE);
  284. INCL(int.FLAGS, Machine.IFBit); (* enable interrupts on return *)
  285. int.EBP := 0; int.ESP := p.restartSP; (* reset stack *)
  286. proc := TerminateInLock; int.PC := SYSTEM.VAL(ADDRESS, proc); (* terminate *)
  287. return := TRUE (* return to TerminateInLock procedure at user level *)
  288. ELSE
  289. lockedBy := NIL; level := 0 (* Oberon.Loop will re-acquire lock *)
  290. END
  291. END ExceptionInLock;
  292. *)
  293. (** Acquire the Oberon lock (and replace exception handler). *)
  294. PROCEDURE LockOberon*;
  295. VAR me: ANY;
  296. BEGIN {EXCLUSIVE}
  297. me := Objects.ActiveObject();
  298. IF lockedBy = me THEN
  299. ASSERT(level # -1); (* overflow *)
  300. INC(level)
  301. ELSE
  302. AWAIT(lockedBy = NIL);
  303. lockedBy := me; level := 1;
  304. (* Objects.SetExceptionHandler(ExceptionInLock) (* assume no other exception handler is present *) *)
  305. END
  306. END LockOberon;
  307. (** Release the Oberon lock (and remove exception handler). *)
  308. PROCEDURE UnlockOberon*;
  309. BEGIN {EXCLUSIVE}
  310. ASSERT(lockedBy = Objects.ActiveObject()); (* must hold lock *)
  311. DEC(level);
  312. IF level = 0 THEN
  313. (* Objects.SetExceptionHandler(NIL); *)
  314. lockedBy := NIL
  315. END
  316. END UnlockOberon;
  317. (** Check if the oberon lock is held by the current process. *)
  318. PROCEDURE CheckOberonLock*;
  319. VAR me: ANY; ok: BOOLEAN;
  320. BEGIN
  321. BEGIN {EXCLUSIVE}
  322. me := Objects.ActiveObject();
  323. ok := (me = oberon) OR (lockedBy = me);
  324. END;
  325. IF ~ok THEN (* HALT(MAX(INTEGER)+1) *)
  326. KernelLog.String("Oberon has been called before from an outside process. Don't do that!"); KernelLog.Ln;
  327. END (* to do: halt here *)
  328. END CheckOberonLock;
  329. BEGIN
  330. oberon := Objects.ActiveObject();
  331. lockedBy := NIL; level := 0; finalizeRoot := NIL; NEW(finalizers);
  332. COPY(Machine.version, version);
  333. (*shutdown := 0;*)
  334. KernelLog.Enter; WriteString("ETH Oberon / "); WriteString(version); KernelLog.Exit;
  335. (*AosScope.Init;*)
  336. (*modules := NIL;*)
  337. (*break := FALSE; inGC := TRUE;*) (* set inGC = TRUE to disable hard break *)
  338. (*copro := TRUE;*)
  339. END Kernel.
  340. (*
  341. 28.04.98 pjm First version
  342. *)