Unix.Machine.Mod 25 KB

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