Unix.AMD64.Machine.Mod 22 KB

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