Unix.Machine.Mod 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  1. MODULE Machine; (** AUTHOR "pjm, G.F."; PURPOSE "Bootstrapping, configuration and machine interface"; *)
  2. IMPORT S := SYSTEM, Trace, Unix, Glue;
  3. CONST
  4. DefaultConfig = "Color 0 StackSize 128";
  5. #IF I386 THEN
  6. Version = "A2 Gen. 32-bit, ";
  7. DefaultObjectFileExtension* = ".GofU";
  8. #ELSIF AMD64 THEN
  9. Version = "A2 Gen. 64-bit, ";
  10. DefaultObjectFileExtension* = ".GofUu";
  11. #END
  12. Second* = 1000; (* frequency of ticks increments in Hz *)
  13. (** bits in features variable *)
  14. MTTR* = 12; MMX* = 23;
  15. AddressSize = SIZEOF(ADDRESS);
  16. StaticBlockSize = 8 * AddressSize; (* static heap block size *)
  17. MemBlockSize* = 64*1024*1024;
  18. TraceOutput* = 0; (* Trace output *)
  19. Memory* = 1; (*! Virtual memory management, stack and page allocation, not used in UnixAos *)
  20. Heaps* = 2; (* Storage allocation and Garbage collection *)
  21. Interrupts* = 3; (*! Interrupt handling, not used in UnixAos *)
  22. Modules* = 4; (* Module list *)
  23. Objects* = 5; (*! Ready queue, not used in UnixAos *)
  24. Processors* = 6; (*! Interprocessor interrupts, not used in UnixAos *)
  25. KernelLog* = 7; (* Atomic output *)
  26. X11* = 8; (* XWindows I/O *)
  27. MaxLocks* = 9; (* { <= 32 } *)
  28. MaxCPU* = 4;
  29. StrongChecks = FALSE;
  30. TYPE
  31. Vendor* = ARRAY 13 OF CHAR;
  32. MemoryBlock* = POINTER {UNSAFE, UNTRACED} TO MemoryBlockDesc;
  33. MemoryBlockDesc* = RECORD
  34. next- : MemoryBlock;
  35. startAdr-: ADDRESS; (* sort key in linked list of memory blocks *)
  36. size-: SIZE;
  37. beginBlockAdr-, endBlockAdr-: ADDRESS
  38. END;
  39. (** processor state *)
  40. State* = RECORD
  41. PC*, BP*, SP*: ADDRESS
  42. END;
  43. VAR
  44. mtx : ARRAY MaxLocks OF Unix.Mutex_t;
  45. taken: ARRAY MaxLocks OF ADDRESS; (* for lock order check *)
  46. version-: ARRAY 64 OF CHAR; (** Aos version *)
  47. features-, features2 : SET;
  48. MMXSupport- : BOOLEAN;
  49. SSESupport- : BOOLEAN;
  50. SSE2Support- : BOOLEAN;
  51. SSE3Support- : BOOLEAN;
  52. SSSE3Support- : BOOLEAN;
  53. SSE41Support- : BOOLEAN;
  54. SSE42Support- : BOOLEAN;
  55. SSE5Support- : BOOLEAN;
  56. AVXSupport- : BOOLEAN;
  57. ticks-: LONGINT; (** timer ticks. Use Kernel.GetTicks() to read, don't write *)
  58. prioLow-, prioHigh-: LONGINT; (* permitted thread priorities *)
  59. fcr-: SET; (** default floating-point control register value (default rounding mode is towards -infinity, for ENTIER) *)
  60. mhz-: HUGEINT; (** clock rate of GetTimer in MHz, or 0 if not known *)
  61. gcThreshold-: SIZE;
  62. memBlockHead-{UNTRACED}, memBlockTail-{UNTRACED}: MemoryBlock; (* head and tail of sorted list of memory blocks *)
  63. config: ARRAY 2048 OF CHAR; (* config strings *)
  64. logname: ARRAY 32 OF CHAR;
  65. logfile: LONGINT;
  66. traceHeap: BOOLEAN;
  67. timer0 : HUGEINT;
  68. (** Return current processor ID (0 to MaxNum-1). *)
  69. PROCEDURE ID* (): LONGINT;
  70. BEGIN
  71. RETURN 0
  72. END ID;
  73. (**
  74. * Flush Data Cache for the specified virtual address range. If len is negative, flushes the whole cache.
  75. * This is used on some architecture to interact with DMA hardware (e.g. Ethernet and USB. It can be
  76. * left empty on Intel architecture.
  77. *)
  78. PROCEDURE FlushDCacheRange * (adr: ADDRESS; len: LONGINT);
  79. END FlushDCacheRange;
  80. (**
  81. * Invalidate Data Cache for the specified virtual address range. If len is negative, flushes the whole cache.
  82. * This is used on some architecture to interact with DMA hardware (e.g. Ethernet and USB. It can be
  83. * left empty on Intel architecture.
  84. *)
  85. PROCEDURE InvalidateDCacheRange * (adr: ADDRESS; len: LONGINT);
  86. END InvalidateDCacheRange;
  87. (**
  88. * Invalidate Instruction Cache for the specified virtual address range. If len is negative, flushes the whole cache.
  89. * This is used on some architecture to interact with DMA hardware (e.g. Ethernet and USB. It can be
  90. * left empty on Intel architecture.
  91. *)
  92. PROCEDURE InvalidateICacheRange * (adr: ADDRESS; len: LONGINT);
  93. END InvalidateICacheRange;
  94. (* insert given memory block in sorted list of memory blocks, sort key is startAdr field - called during GC *)
  95. PROCEDURE InsertMemoryBlock(memBlock: MemoryBlock);
  96. VAR cur {UNTRACED}, prev {UNTRACED}: MemoryBlock;
  97. BEGIN
  98. cur := memBlockHead;
  99. prev := NIL;
  100. WHILE (cur # NIL) & (ADDRESS OF cur^ < ADDRESS OF memBlock^) DO
  101. prev := cur;
  102. cur := cur.next
  103. END;
  104. IF prev = NIL THEN (* insert at head of list *)
  105. memBlock.next := memBlockHead;
  106. memBlockHead := memBlock
  107. ELSE (* insert in middle or at end of list *)
  108. prev.next := memBlock;
  109. memBlock.next := cur;
  110. END;
  111. IF cur = NIL THEN
  112. memBlockTail := memBlock
  113. END
  114. END InsertMemoryBlock;
  115. (* Free unused memory block - called during GC *)
  116. PROCEDURE FreeMemBlock*(memBlock: MemoryBlock);
  117. VAR cur {UNTRACED}, prev {UNTRACED}: MemoryBlock;
  118. BEGIN
  119. cur := memBlockHead;
  120. prev := NIL;
  121. WHILE (cur # NIL) & (cur # memBlock) DO
  122. prev := cur;
  123. cur := cur.next
  124. END;
  125. IF cur = memBlock THEN
  126. IF traceHeap THEN
  127. Trace.String( "Release memory block " ); Trace.Hex( memBlock.startAdr, -8 ); Trace.Ln
  128. END;
  129. IF prev = NIL THEN
  130. memBlockHead := cur.next
  131. ELSE
  132. prev.next := cur.next;
  133. IF cur.next = NIL THEN
  134. memBlockTail := prev
  135. END
  136. END;
  137. Unix.free( memBlock.startAdr )
  138. ELSE
  139. HALT(535) (* error in memory block management *)
  140. END;
  141. END FreeMemBlock;
  142. (* expand heap by allocating a new memory block *)
  143. PROCEDURE ExpandHeap*( dummy: LONGINT; size: SIZE; VAR memoryBlock: MemoryBlock; VAR beginBlockAdr, endBlockAdr: ADDRESS );
  144. VAR mBlock: MemoryBlock; alloc: SIZE; adr: ADDRESS;
  145. BEGIN
  146. ASSERT(SIZEOF(MemoryBlockDesc) <= StaticBlockSize); (* make sure MemoryBlock contents fits into one StaticBlock *)
  147. alloc := size + StaticBlockSize;
  148. IF alloc < MemBlockSize THEN alloc := MemBlockSize END;
  149. ASSERT((Unix.PageSize > StaticBlockSize) & (Unix.PageSize MOD StaticBlockSize = 0)); (* alignment to Unix.PageSize implies alignment to StaticBlockSize *)
  150. INC( alloc, (-alloc) MOD Unix.PageSize );
  151. IF Unix.posix_memalign( adr, Unix.PageSize, alloc ) # 0 THEN
  152. Unix.Perror( "Machine.ExpandHeap: posix_memalign" );
  153. beginBlockAdr := 0;
  154. endBlockAdr := 0;
  155. memoryBlock := NIL;
  156. ELSE
  157. IF Unix.mprotect( adr, alloc, 7 (* READ WRITE EXEC *) ) # 0 THEN
  158. Unix.Perror( "Machine.ExpandHeap: mprotect" )
  159. END;
  160. mBlock := adr;
  161. mBlock.next := NIL;
  162. mBlock.startAdr := adr;
  163. mBlock.size := alloc;
  164. beginBlockAdr := adr + StaticBlockSize;
  165. endBlockAdr := beginBlockAdr + alloc - StaticBlockSize;
  166. mBlock.beginBlockAdr := beginBlockAdr;
  167. mBlock.endBlockAdr := beginBlockAdr; (* block is still empty -- Heaps module will set the upper bound *)
  168. InsertMemoryBlock( mBlock );
  169. IF traceHeap THEN TraceHeap( mBlock ) END;
  170. memoryBlock := mBlock;
  171. END
  172. END ExpandHeap;
  173. (* Set memory block end address *)
  174. PROCEDURE SetMemoryBlockEndAddress*(memBlock: MemoryBlock; endBlockAdr: ADDRESS);
  175. BEGIN
  176. ASSERT(endBlockAdr >= memBlock.beginBlockAdr);
  177. memBlock.endBlockAdr := endBlockAdr
  178. END SetMemoryBlockEndAddress;
  179. PROCEDURE TraceHeap( new: MemoryBlock );
  180. VAR cur{UNTRACED}: MemoryBlock;
  181. BEGIN
  182. Trace.Ln;
  183. Trace.String( "Heap expanded" ); Trace.Ln;
  184. Trace.String("Static Heap: "); Trace.Hex(Glue.baseAdr, -8); Trace.String(" - "); Trace.Hex(Glue.endAdr, -8);
  185. Trace.Ln;
  186. cur := memBlockHead;
  187. WHILE cur # NIL DO
  188. Trace.Hex( cur.startAdr, -8 ); Trace.String( " " ); Trace.Hex( cur.startAdr + cur.size, -8 );
  189. IF cur = new THEN Trace.String( " (new)" ) END;
  190. Trace.Ln;
  191. cur := cur.next
  192. END
  193. END TraceHeap;
  194. (** Get first memory block and first free address, the first free address is identical to memBlockHead.endBlockAdr *)
  195. PROCEDURE GetStaticHeap*(VAR beginBlockAdr, endBlockAdr, freeBlockAdr: ADDRESS);
  196. BEGIN
  197. beginBlockAdr := NIL; endBlockAdr := NIL; freeBlockAdr := NIL;
  198. END GetStaticHeap;
  199. (* returns if an address is a currently allocated heap address *)
  200. PROCEDURE ValidHeapAddress*( p: ADDRESS ): BOOLEAN;
  201. VAR mb: MemoryBlock;
  202. BEGIN
  203. IF (p>=Glue.baseAdr) & (p<=Glue.endAdr) THEN RETURN TRUE END;
  204. mb := memBlockHead;
  205. WHILE mb # NIL DO
  206. IF (p >= mb.beginBlockAdr) & (p <= mb.endBlockAdr) THEN RETURN TRUE END;
  207. mb := mb.next;
  208. END;
  209. RETURN FALSE;
  210. END ValidHeapAddress;
  211. (** Return information on free memory in Kbytes. *)
  212. PROCEDURE GetFreeK*(VAR total, lowFree, highFree: SIZE);
  213. BEGIN
  214. (*! meaningless in Unix port, for interface compatibility only *)
  215. total := 0;
  216. lowFree := 0;
  217. highFree := 0
  218. END GetFreeK;
  219. (** Fill "size" bytes at "destAdr" with "filler". "size" must be multiple of 4. *)
  220. PROCEDURE Fill32* (destAdr: ADDRESS; size: SIZE; filler: LONGINT);
  221. CODE
  222. #IF I386 THEN
  223. MOV EDI, [EBP+destAdr]
  224. MOV ECX, [EBP+size]
  225. MOV EAX, [EBP+filler]
  226. TEST ECX, 3
  227. JZ ok
  228. PUSH 8 ; ASSERT failure
  229. INT 3
  230. ok:
  231. SHR ECX, 2
  232. CLD
  233. REP STOSD
  234. #ELSIF AMD64 THEN
  235. MOV RDI, [RBP + destAdr]
  236. MOV RCX, [RBP + size]
  237. MOV EAX, [RBP + filler]
  238. TEST RCX, 3
  239. JZ ok
  240. PUSH 8 ; ASSERT failure
  241. INT 3
  242. ok:
  243. SHR RCX, 2
  244. CLD
  245. REP STOSD
  246. #ELSE
  247. unimpemented
  248. #END
  249. END Fill32;
  250. PROCEDURE Portin8*(port: LONGINT; VAR val: CHAR);
  251. END Portin8;
  252. PROCEDURE Portin16*(port: LONGINT; VAR val: INTEGER);
  253. END Portin16;
  254. PROCEDURE Portin32*(port: LONGINT; VAR val: LONGINT);
  255. END Portin32;
  256. PROCEDURE Portout8*(port: LONGINT; val: CHAR);
  257. END Portout8;
  258. PROCEDURE Portout16*(port: LONGINT; val: INTEGER);
  259. END Portout16;
  260. PROCEDURE Portout32*(port: LONGINT; val: LONGINT);
  261. END Portout32;
  262. (** -- Atomic operations -- *)
  263. (** Atomic INC(x). *)
  264. PROCEDURE -AtomicInc*(VAR x: LONGINT);
  265. CODE
  266. #IF I386 THEN
  267. POP EAX
  268. LOCK
  269. INC DWORD [EAX]
  270. #ELSIF AMD64 THEN
  271. POP RAX
  272. LOCK
  273. INC DWORD [RAX]
  274. #ELSE
  275. unimplemented
  276. #END
  277. END AtomicInc;
  278. (** Atomic DEC(x). *)
  279. PROCEDURE -AtomicDec*(VAR x: LONGINT);
  280. CODE
  281. #IF I386 THEN
  282. POP EAX
  283. LOCK
  284. DEC DWORD [EAX]
  285. #ELSIF AMD64 THEN
  286. POP RAX
  287. LOCK
  288. DEC DWORD [RAX]
  289. #ELSE
  290. unimplemented
  291. #END
  292. END AtomicDec;
  293. (** Atomic INC(x, y). *)
  294. PROCEDURE -AtomicAdd*(VAR x: LONGINT; y: LONGINT);
  295. CODE
  296. #IF I386 THEN
  297. POP EBX
  298. POP EAX
  299. LOCK
  300. ADD DWORD [EAX], EBX
  301. #ELSIF AMD64 THEN
  302. POP EBX
  303. POP RAX
  304. LOCK
  305. ADD DWORD [RAX], EBX
  306. #ELSE
  307. unimplemented
  308. #END
  309. END AtomicAdd;
  310. (** Atomic EXCL. *)
  311. PROCEDURE AtomicExcl* (VAR s: SET; bit: LONGINT);
  312. CODE
  313. #IF I386 THEN
  314. MOV EAX, [EBP+bit]
  315. MOV EBX, [EBP+s]
  316. LOCK
  317. BTR [EBX], EAX
  318. #ELSIF AMD64 THEN
  319. MOV EAX, [RBP + bit]
  320. MOV RBX, [RBP + s]
  321. LOCK
  322. BTR [RBX], EAX
  323. #ELSE
  324. unimplemented
  325. #END
  326. END AtomicExcl;
  327. (** Atomic test-and-set. Set x = TRUE and return old value of x. *)
  328. PROCEDURE -AtomicTestSet*(VAR x: BOOLEAN): BOOLEAN;
  329. CODE
  330. #IF I386 THEN
  331. POP EBX
  332. MOV AL, 1
  333. XCHG [EBX], AL
  334. #ELSIF AMD64 THEN
  335. POP RBX
  336. MOV AL, 1
  337. XCHG [RBX], AL
  338. #ELSE
  339. unimplemented
  340. #END
  341. END AtomicTestSet;
  342. (* Atomic compare-and-swap. Set x = new if x = old and return old value of x *)
  343. PROCEDURE -AtomicCAS* (VAR x: LONGINT; old, new: LONGINT): LONGINT;
  344. CODE
  345. #IF I386 THEN
  346. POP EBX ; new
  347. POP EAX ; old
  348. POP ECX ; address of x
  349. LOCK CMPXCHG [ECX], EBX; atomicly compare x with old and set it to new if equal
  350. #ELSIF AMD64 THEN
  351. POP EBX ; new
  352. POP EAX ; old
  353. POP RCX ; address of x
  354. LOCK CMPXCHG [RCX], EBX ; atomicly compare x with old and set it to new if equal
  355. #ELSE
  356. unimplemented
  357. #END
  358. END AtomicCAS;
  359. (** This procedure should be called in all spin loops as a hint to the processor (e.g. Pentium 4). *)
  360. PROCEDURE -SpinHint*;
  361. CODE
  362. #IF I386 THEN
  363. PAUSE
  364. #ELSIF AMD64 THEN
  365. PAUSE
  366. #ELSE
  367. unimplemented
  368. #END
  369. END SpinHint;
  370. (* Return current instruction pointer *)
  371. PROCEDURE CurrentPC* (): ADDRESS;
  372. CODE
  373. #IF I386 THEN
  374. MOV EAX, [EBP+4]
  375. #ELSIF AMD64 THEN
  376. MOV RAX, [RBP + 8]
  377. #ELSE
  378. unimplemented
  379. #END
  380. END CurrentPC;
  381. PROCEDURE -GetTimer* (): HUGEINT;
  382. CODE
  383. #IF I386 THEN
  384. RDTSC ; set EDX:EAX
  385. #ELSIF AMD64 THEN
  386. XOR RAX, RAX
  387. RDTSC ; set EDX:EAX
  388. SHL RDX, 32
  389. OR RAX, RDX
  390. #ELSE
  391. unimplemented
  392. #END
  393. END GetTimer;
  394. (** -- Configuration and bootstrapping -- *)
  395. (** Return the value of the configuration string specified by parameter name in parameter val. Returns val = "" if the string was not found, or has an empty value. *)
  396. PROCEDURE GetConfig* (CONST name: ARRAY OF CHAR; VAR val: ARRAY OF CHAR);
  397. VAR i, src: LONGINT; ch: CHAR;
  398. BEGIN
  399. ASSERT (name[0] # "="); (* no longer supported, use GetInit instead *)
  400. src := -1; val := "";
  401. LOOP
  402. REPEAT
  403. INC( src ); ch := config[src];
  404. IF ch = 0X THEN EXIT END;
  405. UNTIL ch > ' ';
  406. i := 0;
  407. LOOP
  408. ch := config[src];
  409. IF (ch # name[i]) OR (name[i] = 0X) THEN EXIT END;
  410. INC (i); INC (src)
  411. END;
  412. IF (ch <= ' ') & (name[i] = 0X) THEN (* found *)
  413. i := 0;
  414. REPEAT
  415. INC (src); ch := config[src]; val[i] := ch; INC (i);
  416. IF i = LEN(val) THEN val[i - 1] := 0X; RETURN END (* val too short *)
  417. UNTIL ch <= ' ';
  418. IF ch = ' ' THEN val[i -1] := 0X END;
  419. RETURN
  420. ELSE
  421. WHILE ch > ' ' DO (* skip to end of name *)
  422. INC (src); ch := config[src]
  423. END;
  424. INC (src);
  425. REPEAT (* skip to end of value *)
  426. ch := config[src]; INC (src)
  427. UNTIL ch <= ' '
  428. END
  429. END;
  430. IF (name = "ObjectFileExtension") & (val = "") THEN
  431. val := DefaultObjectFileExtension
  432. END;
  433. END GetConfig;
  434. (** Convert a string to an integer. Parameter i specifies where in the string scanning should begin (usually 0 in the first call). Scanning stops at the first non-valid character, and i returns the updated position. Parameter s is the string to be scanned. The value is returned as result, or 0 if not valid. Syntax: number = ["-"] digit {digit} ["H" | "h"] . digit = "0" | ... "9" | "A" .. "F" | "a" .. "f" . If the number contains any hexdecimal letter, or if it ends in "H" or "h", it is interpreted as hexadecimal. *)
  435. PROCEDURE StrToInt* (VAR i: LONGINT; CONST s: ARRAY OF CHAR): LONGINT;
  436. VAR vd, vh, sgn, d: LONGINT; hex: BOOLEAN;
  437. BEGIN
  438. vd := 0; vh := 0; hex := FALSE;
  439. IF s[i] = "-" THEN sgn := -1; INC (i) ELSE sgn := 1 END;
  440. LOOP
  441. IF (s[i] >= "0") & (s[i] <= "9") THEN d := ORD (s[i])-ORD ("0")
  442. ELSIF (CAP (s[i]) >= "A") & (CAP (s[i]) <= "F") THEN d := ORD (CAP (s[i]))-ORD ("A") + 10; hex := TRUE
  443. ELSE EXIT
  444. END;
  445. vd := 10*vd + d; vh := 16*vh + d;
  446. INC (i)
  447. END;
  448. IF CAP (s[i]) = "H" THEN hex := TRUE; INC (i) END; (* optional H *)
  449. IF hex THEN vd := vh END;
  450. RETURN sgn * vd
  451. END StrToInt;
  452. (* function returning the number of processors that are available to Aos *)
  453. PROCEDURE NumberOfProcessors*( ): LONGINT;
  454. VAR res: LONGINT;
  455. BEGIN
  456. res := Unix.getnprocs();
  457. RETURN res;
  458. END NumberOfProcessors;
  459. (*! non portable code, for native Aos only *)
  460. PROCEDURE SetNumberOfProcessors*( num: LONGINT );
  461. BEGIN
  462. (* numberOfProcessors := num; *)
  463. END SetNumberOfProcessors;
  464. (* function for changing byte order *)
  465. PROCEDURE ChangeByteOrder* (n: LONGINT): LONGINT;
  466. CODE
  467. #IF I386 THEN
  468. MOV EAX, [EBP+n] ; load n in eax
  469. BSWAP EAX ; swap byte order
  470. #ELSIF AMD64 THEN
  471. MOV EAX, [RBP+n] ; load n in eax
  472. BSWAP EAX ; swap byte order
  473. #ELSE
  474. unimplemented
  475. #END
  476. END ChangeByteOrder;
  477. (* Send and print character *)
  478. PROCEDURE TraceChar *(c: CHAR);
  479. BEGIN
  480. Trace.Char( c )
  481. END TraceChar;
  482. (** CPU identification *)
  483. PROCEDURE CPUID*( VAR vendor: Vendor; VAR version: LONGINT; VAR features1,features2: SET );
  484. CODE
  485. #IF I386 THEN
  486. PUSH ECX
  487. MOV EAX, 0
  488. CPUID
  489. CMP EAX, 0
  490. JNE ok
  491. MOV ESI, [EBP+vendor]
  492. MOV [ESI], AL ; AL = 0
  493. MOV ESI, [EBP+version]
  494. MOV [ESI], EAX ; EAX = 0
  495. MOV ESI, [EBP+features1]
  496. MOV [ESI], EAX
  497. MOV ESI, [EBP+features2]
  498. MOV [ESI], EAX
  499. JMP end
  500. ok:
  501. MOV ESI, [EBP+vendor]
  502. MOV [ESI], EBX
  503. MOV [ESI+4], EDX
  504. MOV [ESI+8], ECX
  505. MOV BYTE [ESI+12], 0
  506. MOV EAX, 1
  507. CPUID
  508. MOV ESI, [EBP+version]
  509. MOV [ESI], EAX
  510. MOV ESI, [EBP+features1]
  511. MOV [ESI], EDX
  512. MOV ESI, [EBP+features2]
  513. MOV [ESI], ECX
  514. end:
  515. POP ECX
  516. #ELSIF AMD64 THEN
  517. PUSH RCX
  518. MOV EAX, 0
  519. CPUID
  520. CMP EAX, 0
  521. JNE ok
  522. MOV RSI, [RBP+vendor]
  523. MOV [RSI], AL ; AL = 0
  524. MOV RSI, [RBP+version]
  525. MOV [RSI], EAX ; EAX = 0
  526. MOV RSI, [RBP+features1]
  527. MOV [RSI], EAX
  528. MOV RSI, [RBP+features2]
  529. MOV [RSI], EAX
  530. JMP end
  531. ok:
  532. MOV RSI, [RBP+vendor]
  533. MOV [RSI], EBX
  534. MOV [RSI+4], EDX
  535. MOV [RSI+8], ECX
  536. MOV BYTE [RSI+12], 0
  537. MOV EAX, 1
  538. CPUID
  539. MOV RSI, [RBP+version]
  540. MOV [RSI], EAX
  541. MOV RSI, [RBP+features1]
  542. MOV [RSI], EDX
  543. MOV RSI, [RBP+features2]
  544. MOV [RSI], RCX
  545. end:
  546. POP RCX
  547. #ELSE
  548. unimplemented
  549. #END
  550. END CPUID;
  551. (* If the CPUID instruction is supported, the ID flag (bit 21) of the EFLAGS register is r/w *)
  552. PROCEDURE CpuIdSupported( ) : BOOLEAN;
  553. CODE
  554. #IF I386 THEN
  555. PUSHFD ; save EFLAGS
  556. POP EAX ; store EFLAGS in EAX
  557. MOV EBX, EAX ; save EBX for later testing
  558. XOR EAX, 00200000H ; toggle bit 21
  559. PUSH EAX ; push to stack
  560. POPFD ; save changed EAX to EFLAGS
  561. PUSHFD ; push EFLAGS to TOS
  562. POP EAX ; store EFLAGS in EAX
  563. CMP EAX, EBX ; see if bit 21 has changed
  564. SETNE AL; ; return TRUE if bit 21 has changed, FALSE otherwise
  565. #ELSIF AMD64 THEN
  566. PUSHFQ ; save RFLAGS
  567. POP RAX ; store RFLAGS in EAX
  568. MOV RBX, RAX ; save RBX for later testing
  569. XOR RAX, 00200000H ; toggle bit 21
  570. PUSH RAX ; push to stack
  571. POPFQ ; save changed EAX to EFLAGS
  572. PUSHFQ ; push EFLAGS to TOS
  573. POP RAX ; store EFLAGS in EAX
  574. CMP RAX, RBX ; see if bit 21 has changed
  575. SETNE AL; ; return TRUE if bit 21 has changed, FALSE otherwise
  576. #ELSE
  577. unimplemented
  578. #END
  579. END CpuIdSupported;
  580. (* setup MMX, SSE and SSE2..SSE5 and AVX extension *)
  581. PROCEDURE SetupSSE2Ext;
  582. CONST
  583. MMXFlag=23;(*IN features from EBX*)
  584. FXSRFlag = 24;
  585. SSEFlag = 25;
  586. SSE2Flag = 26;
  587. SSE3Flag = 0; (*IN features2 from ECX*) (*PH 04/11*)
  588. SSSE3Flag =9;
  589. SSE41Flag =19;
  590. SSE42Flag =20;
  591. SSE5Flag = 11;
  592. AVXFlag = 28;
  593. BEGIN
  594. MMXSupport := MMXFlag IN features;
  595. SSESupport := SSEFlag IN features;
  596. SSE2Support := SSESupport & (SSE2Flag IN features);
  597. SSE3Support := SSE2Support & (SSE3Flag IN features2);
  598. SSSE3Support := SSE3Support & (SSSE3Flag IN features2); (* PH 04/11*)
  599. SSE41Support := SSE3Support & (SSE41Flag IN features2);
  600. SSE42Support := SSE3Support & (SSE42Flag IN features2);
  601. SSE5Support := SSE3Support & (SSE5Flag IN features2);
  602. AVXSupport := SSE3Support & (AVXFlag IN features2);
  603. IF SSESupport & (FXSRFlag IN features) THEN
  604. (* InitSSE(); *) (*! not privileged mode in Windows and Unix, not allowed *)
  605. END;
  606. END SetupSSE2Ext;
  607. (** -- Processor initialization -- *)
  608. PROCEDURE -SetFCR( s: SET );
  609. CODE
  610. #IF I386 THEN
  611. FLDCW [ESP] ; parameter s
  612. POP EAX
  613. #ELSIF AMD64 THEN
  614. FLDCW WORD [RSP] ; parameter s
  615. POP RAX
  616. #ELSE
  617. unimplemented
  618. #END
  619. END SetFCR;
  620. PROCEDURE -FCR( ): SET;
  621. CODE
  622. #IF I386 THEN
  623. PUSH 0
  624. FNSTCW [ESP]
  625. FWAIT
  626. POP EAX
  627. #ELSIF AMD64 THEN
  628. PUSH 0
  629. FNSTCW WORD [RSP]
  630. FWAIT
  631. POP RAX
  632. #ELSE
  633. unimplemented
  634. #END
  635. END FCR;
  636. PROCEDURE -InitFPU;
  637. CODE
  638. #IF I386 THEN
  639. FNINIT
  640. #ELSIF AMD64 THEN
  641. FNINIT
  642. #ELSE
  643. unimplemented
  644. #END
  645. END InitFPU;
  646. (** Setup FPU control word of current processor. *)
  647. PROCEDURE SetupFPU*;
  648. BEGIN
  649. InitFPU; SetFCR( fcr )
  650. END SetupFPU;
  651. (* Initialize locks. *)
  652. PROCEDURE InitLocks;
  653. VAR i: LONGINT;
  654. BEGIN
  655. i := 0;
  656. WHILE i < MaxLocks DO mtx[i] := Unix.NewMtx( ); taken[i] := NIL; INC( i ) END;
  657. END InitLocks;
  658. PROCEDURE CleanupLocks*;
  659. VAR i: LONGINT;
  660. BEGIN
  661. i := 0;
  662. WHILE i < MaxLocks DO Unix.MtxDestroy( mtx[i] ); INC( i ) END;
  663. END CleanupLocks;
  664. (** Acquire a spin-lock. *)
  665. PROCEDURE Acquire*( level: LONGINT ); (* non reentrant lock *)
  666. VAR i: WORD;
  667. BEGIN
  668. Unix.MtxLock( mtx[level] );
  669. IF StrongChecks THEN
  670. ASSERT(taken[level] = NIL);
  671. taken[level] := Unix.ThrThis( );
  672. FOR i := 0 TO level-1 DO
  673. ASSERT(taken[i] # Unix.ThrThis( )); (*! lock order *)
  674. END;
  675. END;
  676. END Acquire;
  677. (** Release a spin-lock. *)
  678. PROCEDURE Release*( level: LONGINT );
  679. VAR i: WORD;
  680. BEGIN
  681. IF StrongChecks THEN
  682. ASSERT(taken[level] = Unix.ThrThis( ));
  683. taken[level] := NIL;
  684. FOR i := 0 TO level-1 DO
  685. ASSERT(taken[i] # Unix.ThrThis( )); (*! lock order *)
  686. END;
  687. END;
  688. Unix.MtxUnlock( mtx[level] );
  689. END Release;
  690. PROCEDURE Shutdown*( reboot: BOOLEAN );
  691. VAR r: LONGINT; logstat: Unix.Status;
  692. BEGIN
  693. IF logfile > 0 THEN
  694. r := Unix.fstat( logfile, logstat );
  695. r := Unix.close( logfile );
  696. IF logstat.size = 0 THEN r := Unix.unlink( ADDRESSOF( logname) ) END;
  697. END;
  698. IF reboot THEN Unix.exit( 0 ) ELSE Unix.exit( 1 ) END;
  699. END Shutdown;
  700. (* Set machine-dependent parameter gcThreshold *)
  701. PROCEDURE SetGCParams*;
  702. BEGIN
  703. gcThreshold := 10*1024*1024; (* 10 MB *)
  704. END SetGCParams;
  705. PROCEDURE InitConfig;
  706. VAR a: ADDRESS; i: LONGINT; c: CHAR;
  707. BEGIN
  708. a := Unix.getenv( ADDRESSOF( "AOSCONFIG" ) );
  709. IF a = 0 THEN config := DefaultConfig
  710. ELSE
  711. REPEAT
  712. S.GET( a, c ); INC( a ); config[i] := c; INC( i )
  713. UNTIL c = 0X
  714. END
  715. END InitConfig;
  716. PROCEDURE UpdateTicks*;
  717. BEGIN
  718. ticks := SHORT( (GetTimer() - timer0) DIV (mhz * 1000) );
  719. END UpdateTicks;
  720. PROCEDURE InitThreads;
  721. VAR res: BOOLEAN;
  722. BEGIN
  723. res := Unix.ThrInitialize( prioLow, prioHigh );
  724. IF ~res THEN
  725. Trace.StringLn( "Machine.InitThreads: no threads support in boot environment. teminating" );
  726. Unix.exit( 1 )
  727. END;
  728. IF Glue.debug # {} THEN
  729. Trace.String( "Threads initialized, priorities low, high: " );
  730. Trace.Int( prioLow, 0 ); Trace.String( ", " ); Trace.Int( prioHigh, 0 );
  731. Trace.Ln
  732. END
  733. END InitThreads;
  734. PROCEDURE CPUSpeed;
  735. VAR t0, t1: HUGEINT;
  736. BEGIN
  737. t0 := GetTimer(); Unix.ThrSleep( 100 ); t1 := GetTimer();
  738. mhz := (t1 - t0) DIV 100000;
  739. IF Glue.debug # {} THEN
  740. Trace.String( "CPU speed: ~" ); Trace.Int( SHORT( mhz ), 0); Trace.String( " MHz" ); Trace.Ln
  741. END
  742. END CPUSpeed;
  743. PROCEDURE Log( c: CHAR );
  744. VAR ignore: SIZE;
  745. BEGIN
  746. ignore := Unix.write( 1, ADDRESSOF( c ), 1 );
  747. ignore := Unix.write( logfile, ADDRESSOF( c ), 1 );
  748. END Log;
  749. PROCEDURE LogFileOnly( c: CHAR );
  750. VAR ignore: SIZE;
  751. BEGIN
  752. ignore := Unix.write( logfile, ADDRESSOF( c ), 1 );
  753. END LogFileOnly;
  754. PROCEDURE InitLog;
  755. VAR pid, i: LONGINT;
  756. BEGIN
  757. IF logfile > 0 THEN RETURN END;
  758. logname := "AOS.xxxxx.Log";
  759. pid := Unix.getpid(); i := 8;
  760. REPEAT
  761. logname[i] := CHR( pid MOD 10 + ORD( '0' ) ); DEC( i );
  762. pid := pid DIV 10;
  763. UNTIL i = 3;
  764. logfile := Unix.open( ADDRESSOF( logname ), Unix.rdwr + Unix.creat + Unix.trunc, Unix.rwrwr );
  765. END InitLog;
  766. PROCEDURE SilentLog*;
  767. BEGIN
  768. InitLog;
  769. Trace.Char := LogFileOnly
  770. END SilentLog;
  771. PROCEDURE VerboseLog*;
  772. BEGIN
  773. InitLog;
  774. Trace.Char := Log
  775. END VerboseLog;
  776. PROCEDURE Append( VAR a: ARRAY OF CHAR; CONST this: ARRAY OF CHAR );
  777. VAR i, j: LONGINT;
  778. BEGIN
  779. i := 0; j := 0;
  780. WHILE a[i] # 0X DO INC( i ) END;
  781. WHILE (i < LEN( a ) - 1) & (this[j] # 0X) DO a[i] := this[j]; INC( i ); INC( j ) END;
  782. a[i] := 0X
  783. END Append;
  784. PROCEDURE Init;
  785. VAR vendor: Vendor; ver: LONGINT;
  786. BEGIN
  787. COPY( Unix.Version, version ); Append( version, Version ); Append(version, S.Date);
  788. timer0 := GetTimer( ); ticks := 0;
  789. InitThreads;
  790. InitLocks;
  791. traceHeap := 1 IN Glue.debug;
  792. InitConfig;
  793. CPUSpeed;
  794. IF CpuIdSupported() THEN
  795. CPUID( vendor, ver, features, features2 ); SetupSSE2Ext
  796. END;
  797. fcr := (FCR() - {0,2,3,10,11}) + {0..5,8,9}; (* default FCR RC=00B *)
  798. END Init;
  799. PROCEDURE {INITIAL} Init0*;
  800. BEGIN
  801. Init;
  802. END Init0;
  803. END Machine.
  804. (*
  805. 03.03.1998 pjm First version
  806. 30.06.1999 pjm ProcessorID moved to AosProcessor
  807. *)
  808. (**
  809. Notes
  810. This module defines an interface to the boot environment of the system. The facilities provided here are only intended for the lowest levels of the system, and should never be directly imported by user modules (exceptions are noted below). They are highly specific to the system hardware and firmware architecture.
  811. Typically a machine has some type of firmware that performs initial testing and setup of the system. The firmware initiates the operating system bootstrap loader, which loads the boot file. This module is the first module in the statically linked boot file that gets control.
  812. There are two more-or-less general procedures in this module: GetConfig and StrToInt. GetConfig is used to query low-level system settings, e.g., the location of the boot file system. StrToInt is a utility procedure that parses numeric strings.
  813. Config strings:
  814. ExtMemSize Specifies size of extended memory (above 1MB) in MB. This value is not checked for validity. Setting it false may cause the system to fail, possible after running for some time. The memory size is usually detected automatically, but if the detection does not work for some reason, or if you want to limit the amount of memory detected, this string can be set. For example, if the machine has 64MB of memory, this value can be set as ExtMemSize="63".
  815. *)