Unix.Machine.Mod 24 KB

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