Unix.AMD64.Machine.Mod 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  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 = "Aos (rev.6242)";
  6. DefaultObjectFileExtension* = ".Obj";
  7. Second* = 1000; (* frequency of ticks increments in Hz *)
  8. (** bits in features variable *)
  9. MTTR* = 12; MMX* = 23;
  10. AddrSize = SIZEOF( ADDRESS );
  11. SizeSize = SIZEOF( SIZE );
  12. BlockSize = 32;
  13. MemBlockSize* = 64*1024*1024;
  14. TraceOutput* = 0; (* Trace output *)
  15. Memory* = 1; (*! Virtual memory management, stack and page allocation, not used in UnixAos *)
  16. Heaps* = 2; (* Storage allocation and Garbage collection *)
  17. Interrupts* = 3; (*! Interrupt handling, not used in UnixAos *)
  18. Modules* = 4; (* Module list *)
  19. Objects* = 5; (*! Ready queue, not used in UnixAos *)
  20. Processors* = 6; (*! Interprocessor interrupts, not used in UnixAos *)
  21. KernelLog* = 7; (* Atomic output *)
  22. X11* = 8; (* XWindows I/O *)
  23. Trap* = 9;
  24. GC* = 10;
  25. MaxLocks* = 11; (* { <= 32 } *)
  26. MaxCPU* = 4;
  27. TYPE
  28. Vendor* = ARRAY 13 OF CHAR;
  29. MemoryBlock* = POINTER TO MemoryBlockDesc;
  30. MemoryBlockDesc* = RECORD
  31. next- {UNTRACED}: MemoryBlock;
  32. startAdr-: ADDRESS; (* sort key in linked list of memory blocks *)
  33. size-: SIZE;
  34. beginBlockAdr-, endBlockAdr-: ADDRESS
  35. END;
  36. (** processor state, ordering of record fields is predefined! *)
  37. (*!(not used in UnixAos, for interface compatibility only)*)
  38. State* = RECORD (* offsets used in FieldInterrupt, FieldIRQ and Objects.RestoreState *)
  39. R15*, R14*, R13*, R12*, R11*, R10*, R9*, R8*: HUGEINT;
  40. RDI*, RSI*, ERR*, RSP0*, RBX*, RDX*, RCX*, RAX*: HUGEINT; (** RSP0 = ADR(s.INT) *)
  41. INT*, BP*, PC*, CS*: HUGEINT; (* RBP and ERR are exchanged by glue code, for procedure link *)
  42. FLAGS*: SET;
  43. SP*, SS*: HUGEINT;
  44. END;
  45. VAR
  46. lock- : ARRAY MaxLocks OF CHAR; (* not implemented as SET because of shared access *)
  47. mtx : ARRAY MaxLocks OF Unix.Mutex_t;
  48. version-: ARRAY 64 OF CHAR; (** Aos version *)
  49. features-, features2 : SET;
  50. MMXSupport- : BOOLEAN;
  51. SSESupport- : BOOLEAN;
  52. SSE2Support- : BOOLEAN;
  53. SSE3Support- : BOOLEAN;
  54. SSSE3Support- : BOOLEAN;
  55. SSE41Support- : BOOLEAN;
  56. SSE42Support- : BOOLEAN;
  57. SSE5Support- : BOOLEAN;
  58. AVXSupport- : BOOLEAN;
  59. ticks*: LONGINT; (** timer ticks. Use Kernel.GetTicks() to read, don't write *)
  60. prioLow-, prioHigh-: LONGINT; (* permitted thread priorities *)
  61. fcr-: SET; (** default floating-point control register value (default rounding mode is towards -infinity, for ENTIER) *)
  62. mhz-: HUGEINT; (** clock rate of GetTimer in MHz, or 0 if not known *)
  63. standaloneAppl-: BOOLEAN;
  64. firstMemBlock: MemoryBlockDesc; (* pseudo heap *)
  65. memBlockHead-{UNTRACED}, memBlockTail-{UNTRACED}: MemoryBlock; (* head and tail of sorted list of memory blocks *)
  66. config: ARRAY 2048 OF CHAR; (* config strings *)
  67. thrInitialize : PROCEDURE {REALTIME, C} ( VAR low, high: LONGINT ): BOOLEAN;
  68. mtxInit : PROCEDURE {REALTIME, C} ( dummy: LONGINT ): Unix.Mutex_t;
  69. mtxDestroy : PROCEDURE {REALTIME, C} ( mtx: Unix.Mutex_t );
  70. mtxLock : PROCEDURE {REALTIME, C} ( mtx: Unix.Mutex_t );
  71. mtxUnlock : PROCEDURE {REALTIME, C} ( mtx: Unix.Mutex_t );
  72. conInit : PROCEDURE {REALTIME, C} ( dummy: LONGINT ): Unix.Condition_t;
  73. conDestroy : PROCEDURE {REALTIME, C} ( cond: Unix.Condition_t );
  74. conWait : PROCEDURE {REALTIME, C} ( cond: Unix.Condition_t; mtx: Unix.Mutex_t );
  75. conSignal : PROCEDURE {REALTIME, C} ( cond: Unix.Condition_t );
  76. thrSleep : PROCEDURE {REALTIME, C} ( ms: LONGINT );
  77. thrThis : PROCEDURE {REALTIME, C} ( dummy: LONGINT ): Unix.Thread_t;
  78. saveSP* : PROCEDURE; (* save SP for usage by GC *)
  79. logfile: LONGINT;
  80. traceHeap: BOOLEAN;
  81. timer0 : HUGEINT;
  82. (** -- Processor identification -- *)
  83. (** Return current processor ID (0 to MaxNum-1). *)
  84. PROCEDURE {REALTIME} ID* (): LONGINT;
  85. BEGIN
  86. RETURN 0
  87. END ID;
  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) & (cur.startAdr < memBlock.startAdr) 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. IF cur = NIL THEN
  105. memBlockTail := memBlock
  106. END
  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 beginBlockAdr, endBlockAdr: ADDRESS );
  138. VAR mBlock: MemoryBlock; alloc, s: SIZE; a, adr: ADDRESS;
  139. BEGIN
  140. IF size < (MemBlockSize - (2*BlockSize)) THEN alloc := MemBlockSize
  141. ELSE alloc := size + (2*BlockSize);
  142. END;
  143. INC( alloc, (-alloc) MOD Unix.PageSize );
  144. IF Unix.posix_memalign( adr, Unix.PageSize, alloc ) # 0 THEN
  145. Unix.Perror( "Machine.ExpandHeap: posix_memalign" );
  146. beginBlockAdr := 0;
  147. endBlockAdr := 0
  148. ELSE
  149. IF Unix.mprotect( adr, alloc, 7 (* READ WRITE EXEC *) ) # 0 THEN
  150. Unix.Perror( "Machine.ExpandHeap: mprotect" )
  151. END;
  152. mBlock := S.VAL( MemoryBlock, adr );
  153. mBlock.next := NIL;
  154. mBlock.startAdr := adr;
  155. mBlock.size := alloc;
  156. mBlock.beginBlockAdr := adr + BlockSize - AddrSize;
  157. ASSERT( (mBlock.beginBlockAdr + AddrSize) MOD BlockSize = 0 );
  158. s := adr + alloc - mBlock.beginBlockAdr - BlockSize;
  159. DEC( s, s MOD BlockSize );
  160. ASSERT( s >= size );
  161. mBlock.endBlockAdr := mBlock.beginBlockAdr + s;
  162. InsertMemoryBlock( mBlock );
  163. IF traceHeap THEN TraceHeap( mBlock ) END;
  164. a := mBlock.beginBlockAdr;
  165. S.PUT( a, a + AddrSize ); (* tag *)
  166. S.PUT( a + AddrSize, s - AddrSize ); (* size *)
  167. S.PUT( a + AddrSize + SizeSize, S.VAL( ADDRESS, 0 ) ); (* next *)
  168. beginBlockAdr := mBlock.beginBlockAdr;
  169. endBlockAdr := mBlock.endBlockAdr;
  170. END
  171. END ExpandHeap;
  172. PROCEDURE TraceHeap( new: MemoryBlock );
  173. VAR cur{UNTRACED}: MemoryBlock;
  174. BEGIN
  175. Trace.Ln;
  176. Trace.String( "Heap expanded" ); Trace.Ln;
  177. cur := memBlockHead;
  178. WHILE cur # NIL DO
  179. Trace.Hex( cur.startAdr, -8 ); Trace.String( " " ); Trace.Int( cur.size, 15 );
  180. IF cur = new THEN Trace.String( " (new)" ) END;
  181. Trace.Ln;
  182. cur := cur.next
  183. END
  184. END TraceHeap;
  185. (* returns if an address is a currently allocated heap address *)
  186. PROCEDURE ValidHeapAddress*( p: ADDRESS ): BOOLEAN;
  187. VAR mb: MemoryBlock;
  188. BEGIN
  189. mb := memBlockHead;
  190. WHILE mb # NIL DO
  191. IF (p >= mb.beginBlockAdr) & (p <= mb.endBlockAdr) THEN RETURN TRUE END;
  192. mb := mb.next;
  193. END;
  194. RETURN FALSE
  195. END ValidHeapAddress;
  196. (** Return information on free memory in Kbytes. *)
  197. PROCEDURE GetFreeK*(VAR total, lowFree, highFree: SIZE);
  198. BEGIN
  199. (* meaningless in Unix port, for interface compatibility only *)
  200. total := 0;
  201. lowFree := 0;
  202. highFree := 0
  203. END GetFreeK;
  204. (** Fill "size" bytes at "destAdr" with "filler". "size" must be multiple of 4. *)
  205. PROCEDURE Fill32* (destAdr: ADDRESS; size: SIZE; filler: LONGINT);
  206. CODE {SYSTEM.AMD64}
  207. MOV RDI, [RBP + destAdr]
  208. MOV RCX, [RBP + size]
  209. MOV EAX, [RBP + filler]
  210. TEST RCX, 3
  211. JZ ok
  212. PUSH 8 ; ASSERT failure
  213. INT 3
  214. ok:
  215. SHR RCX, 2
  216. CLD
  217. REP STOSD
  218. END Fill32;
  219. (** Return timer value of the current processor, or 0 if not available. *)
  220. (* e.g. ARM does not have a fine-grained timer *)
  221. PROCEDURE -GetTimer* (): HUGEINT;
  222. CODE {SYSTEM.AMD64}
  223. XOR RAX, RAX
  224. RDTSC ; set EDX:EAX
  225. SHL RDX, 32
  226. OR RAX, RDX
  227. END GetTimer;
  228. (** -- HUGEINT operations -- *)
  229. (** Return h*g. *)
  230. PROCEDURE MulH* (h, g: HUGEINT): HUGEINT;
  231. BEGIN RETURN h * g;
  232. END MulH;
  233. (** Return h DIV g. Rounding and division by zero behaviour is currently undefined. *)
  234. PROCEDURE DivH* (x, y: HUGEINT): HUGEINT;
  235. BEGIN RETURN x DIV y
  236. END DivH;
  237. (** Return ASH(h, n). *)
  238. PROCEDURE ASHH* (h: HUGEINT; n: LONGINT): HUGEINT;
  239. BEGIN RETURN ASH (h, n);
  240. END ASHH;
  241. (** Return a HUGEINT composed of high and low. *)
  242. PROCEDURE -LInt2ToHInt* (high, low: LONGINT): HUGEINT;
  243. CODE {SYSTEM.AMD64}
  244. POP RAX
  245. END LInt2ToHInt;
  246. (** Return h as a LONGREAL, with possible loss of precision. *)
  247. PROCEDURE -HIntToLReal* (h: HUGEINT): LONGREAL;
  248. CODE {SYSTEM.AMD64, SYSTEM.FPU}
  249. FILD QWORD [ESP]
  250. PAUSE
  251. ADD RSP, 8
  252. END HIntToLReal;
  253. PROCEDURE Portin8*(port: LONGINT; VAR val: CHAR);
  254. END Portin8;
  255. PROCEDURE Portin16*(port: LONGINT; VAR val: INTEGER);
  256. END Portin16;
  257. PROCEDURE Portin32*(port: LONGINT; VAR val: LONGINT);
  258. END Portin32;
  259. PROCEDURE Portout8*(port: LONGINT; val: CHAR);
  260. END Portout8;
  261. PROCEDURE Portout16*(port: LONGINT; val: INTEGER);
  262. END Portout16;
  263. PROCEDURE Portout32*(port: LONGINT; val: LONGINT);
  264. END Portout32;
  265. PROCEDURE Is32BitAddress*( adr: ADDRESS ): BOOLEAN;
  266. BEGIN RETURN S.VAL( LONGINT, adr ) = adr;
  267. END Is32BitAddress;
  268. (** -- Atomic operations -- *)
  269. (** Atomic INC(x). *)
  270. PROCEDURE -AtomicInc*(VAR x: LONGINT);
  271. CODE {SYSTEM.AMD64}
  272. POP RAX
  273. LOCK
  274. INC DWORD [RAX]
  275. END AtomicInc;
  276. (** Atomic DEC(x). *)
  277. PROCEDURE -AtomicDec*(VAR x: LONGINT);
  278. CODE {SYSTEM.AMD64}
  279. POP RAX
  280. LOCK
  281. DEC DWORD [RAX]
  282. END AtomicDec;
  283. (** Atomic EXCL. *)
  284. PROCEDURE AtomicExcl* (VAR s: SET; bit: LONGINT);
  285. CODE {SYSTEM.AMD64}
  286. MOV EAX, [RBP + bit]
  287. MOV RBX, [RBP + s]
  288. LOCK
  289. BTR [RBX], EAX
  290. END AtomicExcl;
  291. (** Atomic INC(x, y). *)
  292. PROCEDURE -AtomicAdd*(VAR x: LONGINT; y: LONGINT);
  293. CODE {SYSTEM.AMD64}
  294. POP EBX
  295. POP RAX
  296. LOCK
  297. ADD DWORD [RAX], EBX
  298. END AtomicAdd;
  299. (** Atomic test-and-set. Set x = TRUE and return old value of x. *)
  300. PROCEDURE -AtomicTestSet*(VAR x: BOOLEAN): BOOLEAN;
  301. CODE {SYSTEM.AMD64}
  302. POP RBX
  303. MOV AL, 1
  304. XCHG [RBX], AL
  305. END AtomicTestSet;
  306. (* Atomic compare-and-swap. Set x = new if x = old and return old value of x *)
  307. PROCEDURE -AtomicCAS* (VAR x: LONGINT; old, new: LONGINT): LONGINT;
  308. CODE {SYSTEM.AMD64}
  309. POP EBX ; new
  310. POP EAX ; old
  311. POP RCX ; address of x
  312. LOCK CMPXCHG [RCX], EBX ; atomicly compare x with old and set it to new if equal
  313. END AtomicCAS;
  314. (* Return current instruction pointer *)
  315. PROCEDURE CurrentPC* (): ADDRESS;
  316. CODE {SYSTEM.AMD64}
  317. MOV RAX, [RBP + 8]
  318. END CurrentPC;
  319. (* Return current frame pointer *)
  320. PROCEDURE -CurrentBP* (): ADDRESS;
  321. CODE {SYSTEM.AMD64}
  322. MOV RAX, RBP
  323. END CurrentBP;
  324. (* Set current frame pointer *)
  325. PROCEDURE -SetBP* (bp: ADDRESS);
  326. CODE {SYSTEM.AMD64}
  327. POP RBP
  328. END SetBP;
  329. (* Return current stack pointer *)
  330. PROCEDURE -CurrentSP* (): ADDRESS;
  331. CODE {SYSTEM.AMD64}
  332. MOV RAX, RSP
  333. END CurrentSP;
  334. (* Set current stack pointer *)
  335. PROCEDURE -SetSP* (sp: ADDRESS);
  336. CODE {SYSTEM.AMD64}
  337. POP RSP
  338. END SetSP;
  339. PROCEDURE -GetRAX*(): HUGEINT;
  340. CODE{SYSTEM.AMD64}
  341. END GetRAX;
  342. PROCEDURE -GetRCX*(): HUGEINT;
  343. CODE{SYSTEM.AMD64}
  344. MOV RAX,RCX
  345. END GetRCX;
  346. PROCEDURE -GetRSI*(): HUGEINT;
  347. CODE{SYSTEM.AMD64}
  348. MOV RAX,RSI
  349. END GetRSI;
  350. PROCEDURE -GetRDI*(): HUGEINT;
  351. CODE{SYSTEM.AMD64}
  352. MOV RAX,RDI
  353. END GetRDI;
  354. PROCEDURE -SetRAX*(n: HUGEINT);
  355. CODE{SYSTEM.AMD64}
  356. NOP
  357. POP RAX
  358. END SetRAX;
  359. PROCEDURE -SetRBX*(n: HUGEINT);
  360. CODE{SYSTEM.AMD64}
  361. NOP
  362. POP RBX
  363. END SetRBX;
  364. PROCEDURE -SetRCX*(n: HUGEINT);
  365. CODE{SYSTEM.AMD64}
  366. POP RCX
  367. END SetRCX;
  368. PROCEDURE -SetRDX*(n: HUGEINT);
  369. CODE{SYSTEM.AMD64}
  370. POP RDX
  371. END SetRDX;
  372. PROCEDURE -SetRSI*(n: HUGEINT);
  373. CODE{SYSTEM.AMD64}
  374. POP RSI
  375. END SetRSI;
  376. PROCEDURE -SetRDI*(n: HUGEINT);
  377. CODE{SYSTEM.AMD64}
  378. POP RDI
  379. END SetRDI;
  380. (** -- Configuration and bootstrapping -- *)
  381. (** 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. *)
  382. PROCEDURE GetConfig* (CONST name: ARRAY OF CHAR; VAR val: ARRAY OF CHAR);
  383. VAR i, src: LONGINT; ch: CHAR;
  384. BEGIN
  385. ASSERT (name[0] # "="); (* no longer supported, use GetInit instead *)
  386. src := -1;
  387. LOOP
  388. REPEAT
  389. INC( src ); ch := config[src];
  390. IF ch = 0X THEN EXIT END;
  391. UNTIL ch > ' ';
  392. i := 0;
  393. LOOP
  394. ch := config[src];
  395. IF (ch # name[i]) OR (name[i] = 0X) THEN EXIT END;
  396. INC (i); INC (src)
  397. END;
  398. IF (ch <= ' ') & (name[i] = 0X) THEN (* found *)
  399. i := 0;
  400. REPEAT
  401. INC (src); ch := config[src]; val[i] := ch; INC (i);
  402. IF i = LEN(val) THEN val[i - 1] := 0X; RETURN END (* val too short *)
  403. UNTIL ch <= ' ';
  404. IF ch = ' ' THEN val[i -1] := 0X END;
  405. RETURN
  406. ELSE
  407. WHILE ch > ' ' DO (* skip to end of name *)
  408. INC (src); ch := config[src]
  409. END;
  410. INC (src);
  411. REPEAT (* skip to end of value *)
  412. ch := config[src]; INC (src)
  413. UNTIL ch <= ' '
  414. END
  415. END;
  416. val[0] := 0X
  417. END GetConfig;
  418. (** 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. *)
  419. PROCEDURE StrToInt* (VAR i: LONGINT; CONST s: ARRAY OF CHAR): LONGINT;
  420. VAR vd, vh, sgn, d: LONGINT; hex: BOOLEAN;
  421. BEGIN
  422. vd := 0; vh := 0; hex := FALSE;
  423. IF s[i] = "-" THEN sgn := -1; INC (i) ELSE sgn := 1 END;
  424. LOOP
  425. IF (s[i] >= "0") & (s[i] <= "9") THEN d := ORD (s[i])-ORD ("0")
  426. ELSIF (CAP (s[i]) >= "A") & (CAP (s[i]) <= "F") THEN d := ORD (CAP (s[i]))-ORD ("A") + 10; hex := TRUE
  427. ELSE EXIT
  428. END;
  429. vd := 10*vd + d; vh := 16*vh + d;
  430. INC (i)
  431. END;
  432. IF CAP (s[i]) = "H" THEN hex := TRUE; INC (i) END; (* optional H *)
  433. IF hex THEN vd := vh END;
  434. RETURN sgn * vd
  435. END StrToInt;
  436. (* function returning the number of processors that are available to Aos *)
  437. PROCEDURE NumberOfProcessors*( ): LONGINT;
  438. BEGIN
  439. RETURN 1
  440. END NumberOfProcessors;
  441. (*! non portable code, for native Aos only *)
  442. PROCEDURE SetNumberOfProcessors*( num: LONGINT );
  443. BEGIN
  444. (* numberOfProcessors := num; *)
  445. END SetNumberOfProcessors;
  446. (* function for changing byte order *)
  447. PROCEDURE ChangeByteOrder* (n: LONGINT): LONGINT;
  448. CODE {SYSTEM.AMD64}
  449. MOV EAX, [RBP + n] ; load n in eax
  450. BSWAP EAX ; swap byte order
  451. END ChangeByteOrder;
  452. (* Send and print character *)
  453. PROCEDURE TraceChar *(c: CHAR);
  454. BEGIN
  455. Trace.Char( c )
  456. END TraceChar;
  457. (** CPU identification *)
  458. PROCEDURE CPUID*(function : LONGINT; VAR eax, ebx, ecx, edx : SET);
  459. CODE {SYSTEM.AMD64}
  460. MOV EAX, [RBP+function] ; CPUID function parameter
  461. MOV RSI, [RBP+ecx] ; copy ecx into ECX (sometimes used as input parameter)
  462. MOV ECX, [RSI]
  463. CPUID ; execute CPUID
  464. MOV RSI, [RBP+eax] ; copy EAX into eax;
  465. MOV [RSI], EAX
  466. MOV RSI, [RBP+ebx] ; copy EBX into ebx
  467. MOV [RSI], EBX
  468. MOV RSI, [RBP+ecx] ; copy ECX into ecx
  469. MOV [RSI], ECX
  470. MOV RSI, [RBP+edx] ; copy EDX into edx
  471. MOV [RSI], EDX
  472. END CPUID;
  473. (* If the CPUID instruction is supported, the ID flag (bit 21) of the EFLAGS register is r/w *)
  474. PROCEDURE CpuIdSupported*() : BOOLEAN;
  475. CODE {SYSTEM.AMD64}
  476. PUSHFQ ; save RFLAGS
  477. POP RAX ; store RFLAGS in RAX
  478. MOV EBX, EAX ; save EBX for later testing
  479. XOR EAX, 00200000H ; toggle bit 21
  480. PUSH RAX ; push to stack
  481. POPFQ ; save changed RAX to RFLAGS
  482. PUSHFQ ; push RFLAGS to TOS
  483. POP RAX ; store RFLAGS in RAX
  484. CMP EAX, EBX ; see if bit 21 has changed
  485. SETNE AL; ; return TRUE if bit 21 has changed, FALSE otherwise
  486. END CpuIdSupported;
  487. (* setup MMX, SSE and SSE2..SSE5 and AVX extension *)
  488. PROCEDURE SetupSSE2Ext;
  489. CONST
  490. MMXFlag=23;(*IN features from EBX*)
  491. FXSRFlag = 24;
  492. SSEFlag = 25;
  493. SSE2Flag = 26;
  494. SSE3Flag = 0; (*IN features2 from ECX*) (*PH 04/11*)
  495. SSSE3Flag =9;
  496. SSE41Flag =19;
  497. SSE42Flag =20;
  498. SSE5Flag = 11;
  499. AVXFlag = 28;
  500. BEGIN
  501. MMXSupport := MMXFlag IN features;
  502. SSESupport := SSEFlag IN features;
  503. SSE2Support := SSESupport & (SSE2Flag IN features);
  504. SSE3Support := SSE2Support & (SSE3Flag IN features2);
  505. SSSE3Support := SSE3Support & (SSSE3Flag IN features2); (* PH 04/11*)
  506. SSE41Support := SSE3Support & (SSE41Flag IN features2);
  507. SSE42Support := SSE3Support & (SSE42Flag IN features2);
  508. SSE5Support := SSE3Support & (SSE5Flag IN features2);
  509. AVXSupport := SSE3Support & (AVXFlag IN features2);
  510. IF SSESupport & (FXSRFlag IN features) THEN
  511. (* InitSSE(); *) (*! not privileged mode in Windows and Unix not allowed *)
  512. END;
  513. END SetupSSE2Ext;
  514. (** -- Processor initialization -- *)
  515. PROCEDURE -SetFCR (s: SET);
  516. CODE {SYSTEM.AMD64, SYSTEM.FPU}
  517. FLDCW WORD [RSP] ; parameter s
  518. POP RAX
  519. END SetFCR;
  520. PROCEDURE -FCR (): SET;
  521. CODE {SYSTEM.AMD64, SYSTEM.FPU}
  522. PUSH 0
  523. FNSTCW WORD [RSP]
  524. FWAIT
  525. POP RAX
  526. END FCR;
  527. PROCEDURE -InitFPU;
  528. CODE {SYSTEM.AMD64, SYSTEM.FPU}
  529. FNINIT
  530. END InitFPU;
  531. (** Setup FPU control word of current processor. *)
  532. PROCEDURE SetupFPU*;
  533. BEGIN
  534. InitFPU; SetFCR(fcr)
  535. END SetupFPU;
  536. (* Initialize locks. *)
  537. PROCEDURE InitLocks;
  538. VAR i: LONGINT;
  539. BEGIN
  540. i := 0;
  541. WHILE i < MaxLocks DO
  542. mtx[i] := mtxInit(0); lock[i] := "N"; INC( i )
  543. END;
  544. END InitLocks;
  545. PROCEDURE CleanupLocks*;
  546. VAR i: LONGINT;
  547. BEGIN
  548. i := 0;
  549. WHILE i < MaxLocks DO mtxDestroy( mtx[i] ); INC( i ) END;
  550. END CleanupLocks;
  551. (** Acquire a spin-lock. *)
  552. PROCEDURE Acquire*( level: LONGINT ); (* non reentrant lock *)
  553. BEGIN
  554. lock[level] := "Y";
  555. mtxLock( mtx[level] );
  556. IF level = Heaps THEN saveSP END
  557. END Acquire;
  558. (** Release a spin-lock. *)
  559. PROCEDURE Release*( level: LONGINT );
  560. BEGIN
  561. mtxUnlock( mtx[level] );
  562. lock[level] := "N";
  563. END Release;
  564. PROCEDURE Shutdown*( reboot: BOOLEAN );
  565. VAR ignore: LONGINT;
  566. BEGIN
  567. ignore := Unix.close( logfile );
  568. IF reboot THEN Unix.exit( 0 ) ELSE Unix.exit( 1 ) END;
  569. END Shutdown;
  570. PROCEDURE InitHeap;
  571. VAR heapAdr, firstBlock: ADDRESS; size: SIZE;
  572. BEGIN
  573. Unix.Dlsym( 0, "heapAdr", ADDRESSOF( heapAdr ) );
  574. Unix.Dlsym( 0, "heapSize", ADDRESSOF( size ) );
  575. firstBlock := heapAdr + ((-heapAdr - AddrSize) MOD BlockSize);
  576. size := heapAdr + size - BlockSize - firstBlock; DEC( size, size MOD BlockSize + BlockSize );
  577. firstMemBlock.next := NIL;
  578. firstMemBlock.startAdr := heapAdr;
  579. firstMemBlock.beginBlockAdr := firstBlock;
  580. firstMemBlock.endBlockAdr := firstBlock + size;
  581. firstMemBlock.size := size;
  582. memBlockHead := S.VAL( MemoryBlock, ADDRESSOF( firstMemBlock ) );
  583. memBlockTail := memBlockHead;
  584. END InitHeap;
  585. PROCEDURE InitConfig;
  586. VAR a: ADDRESS; i: LONGINT; c: CHAR;
  587. BEGIN
  588. a := Unix.getenv( ADDRESSOF( "AOSCONFIG" ) );
  589. IF a = 0 THEN config := DefaultConfig
  590. ELSE
  591. REPEAT
  592. S.GET( a, c ); INC( a ); config[i] := c; INC( i )
  593. UNTIL c = 0X
  594. END
  595. END InitConfig;
  596. PROCEDURE UpdateTicks*;
  597. BEGIN
  598. ticks := SHORT( (GetTimer() - timer0) DIV (mhz * 1000) );
  599. END UpdateTicks;
  600. PROCEDURE InitThreads;
  601. VAR res: BOOLEAN;
  602. BEGIN
  603. res := thrInitialize( prioLow, prioHigh );
  604. IF ~res THEN
  605. Trace.StringLn( "Machine.InitThreads: no threads support in boot environment. teminating" );
  606. Unix.exit( 1 )
  607. END;
  608. IF Glue.debug # {} THEN
  609. Trace.String( "Threads initialized, priorities low, high: " );
  610. Trace.Int( prioLow, 0 ); Trace.String( ", " ); Trace.Int( prioHigh, 0 );
  611. Trace.Ln
  612. END
  613. END InitThreads;
  614. PROCEDURE CPUSpeed;
  615. VAR t0, t1: HUGEINT;
  616. BEGIN
  617. t0 := GetTimer(); thrSleep( 100 ); t1 := GetTimer();
  618. mhz := (t1 - t0) DIV 100000;
  619. IF Glue.debug # {} THEN
  620. Trace.String( "CPU speed: ~" ); Trace.Int( SHORT( mhz ), 0); Trace.String( " MHz" ); Trace.Ln
  621. END
  622. END CPUSpeed;
  623. PROCEDURE Log1( c: CHAR );
  624. VAR ignore: LONGINT;
  625. BEGIN
  626. ignore := Unix.write( 1, ADDRESSOF( c ), 1 );
  627. ignore := Unix.write( logfile, ADDRESSOF( c ), 1 );
  628. END Log1;
  629. PROCEDURE Log2( c: CHAR );
  630. VAR ignore: LONGINT;
  631. BEGIN
  632. ignore := Unix.write( logfile, ADDRESSOF( c ), 1 );
  633. END Log2;
  634. PROCEDURE InitLog;
  635. VAR name: ARRAY 32 OF CHAR; pid, i, d: LONGINT;
  636. BEGIN
  637. name := "AOS.xxxxx.Log";
  638. pid := Unix.getpid(); i := 8;
  639. REPEAT
  640. name[i] := CHR( pid MOD 10 + ORD( '0' ) ); DEC( i );
  641. pid := pid DIV 10;
  642. UNTIL i = 3;
  643. logfile := Unix.open( ADDRESSOF( name ), Unix.rdwr + Unix.creat + Unix.trunc, Unix.rwrwr );
  644. IF Unix.argc < 3 THEN VerboseLog
  645. ELSE standaloneAppl := TRUE; SilentLog
  646. END
  647. END InitLog;
  648. PROCEDURE SilentLog*;
  649. BEGIN
  650. Trace.Char := Log2
  651. END SilentLog;
  652. PROCEDURE VerboseLog*;
  653. BEGIN
  654. Trace.Char := Log1
  655. END VerboseLog;
  656. PROCEDURE Append( VAR a: ARRAY OF CHAR; CONST this: ARRAY OF CHAR );
  657. VAR i, j: LONGINT;
  658. BEGIN
  659. i := 0; j := 0;
  660. WHILE a[i] # 0X DO INC( i ) END;
  661. WHILE (i < LEN( a ) - 1) & (this[j] # 0X) DO a[i] := this[j]; INC( i ); INC( j ) END;
  662. a[i] := 0X
  663. END Append;
  664. PROCEDURE {REALTIME} Empty;
  665. END Empty;
  666. PROCEDURE Init;
  667. VAR eax, ebx, ecx, edx: SET;
  668. BEGIN
  669. Unix.Dlsym( 0, "thrInitialize", ADDRESSOF( thrInitialize ) );
  670. Unix.Dlsym( 0, "mtxInit", ADDRESSOF( mtxInit ) );
  671. Unix.Dlsym( 0, "mtxDestroy", ADDRESSOF( mtxDestroy ) );
  672. Unix.Dlsym( 0, "mtxLock", ADDRESSOF( mtxLock ) );
  673. Unix.Dlsym( 0, "mtxUnlock", ADDRESSOF( mtxUnlock ) );
  674. Unix.Dlsym( 0, "conInit", ADDRESSOF( conInit ) );
  675. Unix.Dlsym( 0, "conDestroy", ADDRESSOF( conDestroy ) );
  676. Unix.Dlsym( 0, "conWait", ADDRESSOF( conWait ) );
  677. Unix.Dlsym( 0, "conSignal", ADDRESSOF( conSignal ) );
  678. Unix.Dlsym( 0, "thrSleep", ADDRESSOF( thrSleep ) );
  679. Unix.Dlsym( 0, "thrThis", ADDRESSOF( thrThis ) );
  680. standaloneAppl := FALSE;
  681. saveSP := Empty; (* to be replaced in module Objects *)
  682. COPY( Unix.Version, version ); Append( version, Version );
  683. timer0 := GetTimer( ); ticks := 0;
  684. InitThreads;
  685. InitLocks;
  686. traceHeap := 1 IN Glue.debug;
  687. InitHeap;
  688. InitConfig;
  689. InitLog;
  690. CPUSpeed;
  691. (* CPUID standard function 1 returns: CPU features in ecx & edx *)
  692. CPUID( 1, eax, ebx, ecx, edx );
  693. features := S.VAL( SET, edx );
  694. features2 := S.VAL( SET, ecx );
  695. SetupSSE2Ext;
  696. fcr := (FCR() - {0,2,3,10,11}) + {0..5,8,9}; (* default FCR RC=00B *)
  697. END Init;
  698. BEGIN
  699. Init
  700. END Machine.
  701. (*
  702. 03.03.1998 pjm First version
  703. 30.06.1999 pjm ProcessorID moved to AosProcessor
  704. *)
  705. (**
  706. Notes
  707. 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.
  708. 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.
  709. 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.
  710. Config strings:
  711. 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".
  712. *)