Unix.I386.Machine.Mod 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  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.6275)";
  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. EDI*, ESI*, ERR*, ESP0*, EBX*, EDX*, ECX*, EAX*: LONGINT; (** ESP0 = ADR(s.INT) *)
  40. INT*, BP*, PC*, CS*: LONGINT; (* BP and ERR are exchanged by glue code, for procedure link *)
  41. FLAGS*: SET;
  42. SP*, SS*: LONGINT; (** only valid if (VMBit IN s.EFLAGS) OR (CS MOD 4 < s.CS MOD 4) *)
  43. ES*, DS*, FS*, GS*: LONGINT; (** only valid if (VMBit IN s.FLAGS) *)
  44. END;
  45. VAR
  46. mtx : ARRAY MaxLocks OF Unix.Mutex_t;
  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. standaloneAppl-: BOOLEAN;
  63. firstMemBlock: MemoryBlockDesc; (* pseudo heap *)
  64. memBlockHead-{UNTRACED}, memBlockTail-{UNTRACED}: MemoryBlock; (* head and tail of sorted list of memory blocks *)
  65. config: ARRAY 2048 OF CHAR; (* config strings *)
  66. thrInitialize : PROCEDURE {REALTIME, C} ( VAR low, high: LONGINT ): BOOLEAN;
  67. mtxInit : PROCEDURE {REALTIME, C} ( dummy: LONGINT ): Unix.Mutex_t;
  68. mtxDestroy : PROCEDURE {REALTIME, C} ( mtx: Unix.Mutex_t );
  69. mtxLock : PROCEDURE {REALTIME, C} ( mtx: Unix.Mutex_t );
  70. mtxUnlock : PROCEDURE {REALTIME, C} ( mtx: Unix.Mutex_t );
  71. conInit : PROCEDURE {REALTIME, C} ( dummy: LONGINT ): Unix.Condition_t;
  72. conDestroy : PROCEDURE {REALTIME, C} ( cond: Unix.Condition_t );
  73. conWait : PROCEDURE {REALTIME, C} ( cond: Unix.Condition_t; mtx: Unix.Mutex_t );
  74. conSignal : PROCEDURE {REALTIME, C} ( cond: Unix.Condition_t );
  75. thrSleep : PROCEDURE {REALTIME, C} ( ms: LONGINT );
  76. thrThis : PROCEDURE {REALTIME, C} ( dummy: LONGINT ): Unix.Thread_t;
  77. logfile: LONGINT;
  78. traceHeap: BOOLEAN;
  79. timer0 : HUGEINT;
  80. (** -- Processor identification -- *)
  81. (** Return current processor ID (0 to MaxNum-1). *)
  82. PROCEDURE {REALTIME} ID* (): LONGINT;
  83. BEGIN
  84. RETURN 0
  85. END ID;
  86. (* insert given memory block in sorted list of memory blocks, sort key is startAdr field - called during GC *)
  87. PROCEDURE InsertMemoryBlock(memBlock: MemoryBlock);
  88. VAR cur {UNTRACED}, prev {UNTRACED}: MemoryBlock;
  89. BEGIN
  90. cur := memBlockHead;
  91. prev := NIL;
  92. WHILE (cur # NIL) & (cur.startAdr < memBlock.startAdr) DO
  93. prev := cur;
  94. cur := cur.next
  95. END;
  96. IF prev = NIL THEN (* insert at head of list *)
  97. memBlock.next := memBlockHead;
  98. memBlockHead := memBlock
  99. ELSE (* insert in middle or at end of list *)
  100. prev.next := memBlock;
  101. memBlock.next := cur;
  102. IF cur = NIL THEN
  103. memBlockTail := memBlock
  104. END
  105. END
  106. END InsertMemoryBlock;
  107. (* Free unused memory block - called during GC *)
  108. PROCEDURE FreeMemBlock*(memBlock: MemoryBlock);
  109. VAR cur {UNTRACED}, prev {UNTRACED}: MemoryBlock;
  110. BEGIN
  111. cur := memBlockHead;
  112. prev := NIL;
  113. WHILE (cur # NIL) & (cur # memBlock) DO
  114. prev := cur;
  115. cur := cur.next
  116. END;
  117. IF cur = memBlock THEN
  118. IF traceHeap THEN
  119. Trace.String( "Release memory block " ); Trace.Hex( memBlock.startAdr, -8 ); Trace.Ln
  120. END;
  121. IF prev = NIL THEN
  122. memBlockHead := cur.next
  123. ELSE
  124. prev.next := cur.next;
  125. IF cur.next = NIL THEN
  126. memBlockTail := prev
  127. END
  128. END;
  129. Unix.free( memBlock.startAdr )
  130. ELSE
  131. HALT(535) (* error in memory block management *)
  132. END;
  133. END FreeMemBlock;
  134. (* expand heap by allocating a new memory block *)
  135. PROCEDURE ExpandHeap*( dummy: LONGINT; size: SIZE; VAR beginBlockAdr, endBlockAdr: ADDRESS );
  136. VAR mBlock: MemoryBlock; alloc, s: SIZE; a, adr: ADDRESS;
  137. BEGIN
  138. IF size < (MemBlockSize - (2*BlockSize)) THEN alloc := MemBlockSize
  139. ELSE alloc := size + (2*BlockSize);
  140. END;
  141. INC( alloc, (-alloc) MOD Unix.PageSize );
  142. IF Unix.posix_memalign( adr, Unix.PageSize, alloc ) # 0 THEN
  143. Unix.Perror( "Machine.ExpandHeap: posix_memalign" );
  144. beginBlockAdr := 0;
  145. endBlockAdr := 0
  146. ELSE
  147. IF Unix.mprotect( adr, alloc, 7 (* READ WRITE EXEC *) ) # 0 THEN
  148. Unix.Perror( "Machine.ExpandHeap: mprotect" )
  149. END;
  150. mBlock := S.VAL( MemoryBlock, adr );
  151. mBlock.next := NIL;
  152. mBlock.startAdr := adr;
  153. mBlock.size := alloc;
  154. mBlock.beginBlockAdr := adr + BlockSize - AddrSize;
  155. ASSERT( (mBlock.beginBlockAdr + AddrSize) MOD BlockSize = 0 );
  156. s := adr + alloc - mBlock.beginBlockAdr - BlockSize;
  157. DEC( s, s MOD BlockSize );
  158. ASSERT( s >= size );
  159. mBlock.endBlockAdr := mBlock.beginBlockAdr + s;
  160. InsertMemoryBlock( mBlock );
  161. IF traceHeap THEN TraceHeap( mBlock ) END;
  162. a := mBlock.beginBlockAdr;
  163. S.PUT( a, a + AddrSize ); (* tag *)
  164. S.PUT( a + AddrSize, s - AddrSize ); (* size *)
  165. S.PUT( a + AddrSize + SizeSize, S.VAL( ADDRESS, 0 ) ); (* next *)
  166. beginBlockAdr := mBlock.beginBlockAdr;
  167. endBlockAdr := mBlock.endBlockAdr;
  168. END
  169. END ExpandHeap;
  170. PROCEDURE TraceHeap( new: MemoryBlock );
  171. VAR cur{UNTRACED}: MemoryBlock;
  172. BEGIN
  173. Trace.Ln;
  174. Trace.String( "Heap expanded" ); Trace.Ln;
  175. cur := memBlockHead;
  176. WHILE cur # NIL DO
  177. Trace.Hex( cur.startAdr, -8 ); Trace.String( " " ); Trace.Int( cur.size, 15 );
  178. IF cur = new THEN Trace.String( " (new)" ) END;
  179. Trace.Ln;
  180. cur := cur.next
  181. END
  182. END TraceHeap;
  183. (** Return information on free memory in Kbytes. *)
  184. PROCEDURE GetFreeK*(VAR total, lowFree, highFree: SIZE);
  185. BEGIN
  186. (* meaningless in Unix port, for interface compatibility only *)
  187. total := 0;
  188. lowFree := 0;
  189. highFree := 0
  190. END GetFreeK;
  191. (** Fill "size" bytes at "destAdr" with "filler". "size" must be multiple of 4. *)
  192. PROCEDURE {REALTIME} Fill32* (destAdr: ADDRESS; size: SIZE; filler: LONGINT);
  193. CODE {SYSTEM.i386}
  194. MOV EDI, [EBP+destAdr]
  195. MOV ECX, [EBP+size]
  196. MOV EAX, [EBP+filler]
  197. TEST ECX, 3
  198. JZ ok
  199. PUSH 8 ; ASSERT failure
  200. INT 3
  201. ok:
  202. SHR ECX, 2
  203. CLD
  204. REP STOSD
  205. END Fill32;
  206. (** Return h*g. based on code from "AMD Athlon Processor x86 code optimization guide" *)
  207. PROCEDURE {REALTIME} MulH* (h, g: HUGEINT): HUGEINT;
  208. CODE {SYSTEM.i386}
  209. MOV EDX, [EBP+12] ; y_hi
  210. MOV ECX, [EBP+20] ; x_hi
  211. OR EDX, ECX ; are x_hi and y_hi both zeros?
  212. MOV EDX, [EBP+16] ; x_lo
  213. MOV EAX, [EBP+8] ; y_lo
  214. JNZ fullMul ; yes, requires full multiplication
  215. MUL EDX ; EDX:EAX := y_lo * x_lo
  216. JMP exit ; done, return to caller
  217. fullMul: ; full multiplication is required
  218. MUL ECX ; EAX := LO(y_lo*x_hi)
  219. MOV EBX, EAX ; keep the result
  220. MOV EAX, [EBP+12] ; y_hi
  221. MUL DWORD [EBP+16] ; EAX := LO(y_hi*x_lo)
  222. ADD EBX, EAX ; EBX := LO(y_lo*x_hi) + LO(y_hi*x_lo)
  223. MOV EAX, [EBP+8] ; y_lo
  224. MUL DWORD [EBP+16] ; EDX := HI(y_lo*x_lo), EAX := LO(y_lo*x_lo)
  225. ADD EDX, EBX ; EDX := y_lo*x_hi + y_hi*x_lo + HI(y_lo*x_lo)
  226. exit:
  227. END MulH;
  228. (** Return h DIV g. Rounding and division by zero behaviour is currently undefined. *)
  229. PROCEDURE {REALTIME} DivH* (x, y: HUGEINT): HUGEINT;
  230. CODE {SYSTEM.i386}
  231. MOV ECX, [EBP+12] ; y-hi
  232. MOV EBX, [EBP+8] ; y-lo
  233. MOV EDX, [EBP+20] ; x-hi
  234. MOV EAX, [EBP+16] ; x-lo
  235. MOV ESI, ECX ; y-hi
  236. XOR ESI, EDX ; y-hi ^ x-hi
  237. SAR ESI, 31 ; (quotient < 0) ? -1 : 0
  238. MOV EDI, EDX ; x-hi
  239. SAR EDI, 31 ; (x < 0) ? -1 : 0
  240. XOR EAX, EDI ; if (x < 0)
  241. XOR EDX, EDI ; compute 1s complement of x
  242. SUB EAX, EDI ; if (x < 0)
  243. SBB EDX, EDI ; compute 2s complement of x
  244. MOV EDI, ECX ; y-hi
  245. SAR EDI, 31 ; (y < 0) ? -1 : 0
  246. XOR EBX, EDI ; if (y < 0)
  247. XOR ECX, EDI ; compute 1s complement of y
  248. SUB EBX, EDI ; if (y < 0)
  249. SBB ECX, EDI ; compute 2s complement of y
  250. JNZ bigDivisor ; y > 2^32-1
  251. CMP EDX, EBX ; only one division needed ? (ECX = 0)
  252. JAE twoDivs ; need two divisions
  253. DIV EBX ; EAX = quotient-lo
  254. MOV EDX, ECX ; EDX = quotient-hi = 0
  255. ; quotient in EDX:EAX
  256. XOR EAX, ESI ; if (quotient < 0)
  257. XOR EDX, ESI ; compute 1s complement of result
  258. SUB EAX, ESI ; if (quotient < 0)
  259. SBB EDX, ESI ; compute 2s complement of result
  260. JMP exit ; done, return to caller
  261. twoDivs:
  262. MOV ECX, EAX ; save x-lo in ECX
  263. MOV EAX, EDX ; get x-hi
  264. XOR EDX, EDX ; zero extend it into EDX:EAX
  265. DIV EBX ; quotient-hi in EAX
  266. XCHG EAX, ECX ; ECX = quotient-hi, EAX = x-lo
  267. DIV EBX ; EAX = quotient-lo
  268. MOV EDX, ECX ; EDX = quotient-hi
  269. ; quotient in EDX:EAX
  270. JMP makeSign ; make quotient signed
  271. bigDivisor:
  272. SUB ESP, 12 ; create three local variables
  273. MOV [ESP], EAX ; x-lo
  274. MOV [ESP+4], EBX ; y-lo
  275. MOV [ESP+8], EDX ; x-hi
  276. MOV EDI, ECX ; save y-hi
  277. SHR EDX, 1 ; shift both
  278. RCR EAX, 1 ; y and
  279. ROR EDI, 1 ; and x
  280. RCR EBX, 1 ; right by 1 bit
  281. BSR ECX, ECX ; ECX = number of remaining shifts
  282. SHRD EBX, EDI, CL ; scale down y and
  283. SHRD EAX, EDX, CL ; x such that y
  284. SHR EDX, CL ; less than 2^32 (i.e. fits in EBX)
  285. ROL EDI, 1 ; restore original y-hi
  286. DIV EBX ; compute quotient
  287. MOV EBX, [ESP] ; x-lo
  288. MOV ECX, EAX ; save quotient
  289. IMUL EDI, EAX ; quotient * y hi-word (low only)
  290. MUL DWORD [ESP+4] ; quotient * y lo-word
  291. ADD EDX, EDI ; EDX:EAX = quotient * y
  292. SUB EBX, EAX ; x-lo - (quot.*y)-lo
  293. MOV EAX, ECX ; get quotient
  294. MOV ECX, [ESP+8] ; x-hi
  295. SBB ECX, EDX ; subtract y * quot. from x
  296. SBB EAX, 0 ; adjust quotient if remainder negative
  297. XOR EDX, EDX ; clear hi-word of quotient
  298. ADD ESP, 12 ; remove local variables
  299. makeSign:
  300. XOR EAX, ESI ; if (quotient < 0)
  301. XOR EDX, ESI ; compute 1s complement of result
  302. SUB EAX, ESI ; if (quotient < 0)
  303. SBB EDX, ESI ; compute 2s complement of result
  304. exit:
  305. END DivH;
  306. (** Return ASH(h, n). *)
  307. PROCEDURE {REALTIME} -ASHH* (h: HUGEINT; n: LONGINT): HUGEINT;
  308. CODE {SYSTEM.i386}
  309. POP ECX
  310. POP EAX
  311. POP EDX
  312. CMP ECX, 0
  313. JL right
  314. AND ECX, 63 ; limit count, like ASH
  315. JZ exit
  316. ll:
  317. SHL EAX, 1
  318. RCL EDX, 1
  319. DEC ECX
  320. JNZ ll
  321. JMP exit
  322. right:
  323. NEG ECX
  324. AND ECX, 63 ; limit count, like ASH
  325. JZ exit
  326. lr:
  327. SAR EDX, 1
  328. RCR EAX, 1
  329. DEC ECX
  330. JNZ lr
  331. exit:
  332. END ASHH;
  333. (** Return a HUGEINT composed of high and low. *)
  334. PROCEDURE {REALTIME} -LInt2ToHInt* (high, low: LONGINT): HUGEINT;
  335. CODE {SYSTEM.i386}
  336. POP EAX
  337. POP EDX
  338. END LInt2ToHInt;
  339. (** Return h as a LONGREAL, with possible loss of precision. *)
  340. PROCEDURE {REALTIME} -HIntToLReal* (h: HUGEINT): LONGREAL;
  341. CODE {SYSTEM.i386, SYSTEM.FPU}
  342. FILD QWORD [ESP]
  343. FWAIT
  344. ADD ESP, 8
  345. END HIntToLReal;
  346. PROCEDURE Portin8*(port: LONGINT; VAR val: CHAR);
  347. END Portin8;
  348. PROCEDURE Portin16*(port: LONGINT; VAR val: INTEGER);
  349. END Portin16;
  350. PROCEDURE Portin32*(port: LONGINT; VAR val: LONGINT);
  351. END Portin32;
  352. PROCEDURE Portout8*(port: LONGINT; val: CHAR);
  353. END Portout8;
  354. PROCEDURE Portout16*(port: LONGINT; val: INTEGER);
  355. END Portout16;
  356. PROCEDURE Portout32*(port: LONGINT; val: LONGINT);
  357. END Portout32;
  358. (* returns if an address is a currently allocated heap address *)
  359. PROCEDURE ValidHeapAddress*( p: ADDRESS ): BOOLEAN;
  360. VAR mb: MemoryBlock;
  361. BEGIN
  362. mb := memBlockHead;
  363. WHILE mb # NIL DO
  364. IF (p >= mb.beginBlockAdr) & (p <= mb.endBlockAdr) THEN RETURN TRUE END;
  365. mb := mb.next;
  366. END;
  367. RETURN FALSE
  368. END ValidHeapAddress;
  369. PROCEDURE Ensure32BitAddress*( adr: ADDRESS ): LONGINT;
  370. BEGIN
  371. RETURN adr
  372. END Ensure32BitAddress;
  373. PROCEDURE Is32BitAddress*( adr: ADDRESS ): BOOLEAN;
  374. BEGIN RETURN S.VAL( LONGINT, adr ) = adr;
  375. END Is32BitAddress;
  376. (** -- Atomic operations -- *)
  377. (** Atomic INC(x). *)
  378. PROCEDURE -AtomicInc*(VAR x: LONGINT);
  379. CODE {SYSTEM.i386}
  380. POP EAX
  381. LOCK
  382. INC DWORD [EAX]
  383. END AtomicInc;
  384. (** Atomic DEC(x). *)
  385. PROCEDURE -AtomicDec*(VAR x: LONGINT);
  386. CODE {SYSTEM.i386}
  387. POP EAX
  388. LOCK
  389. DEC DWORD [EAX]
  390. END AtomicDec;
  391. (** Atomic INC(x, y). *)
  392. PROCEDURE -AtomicAdd*(VAR x: LONGINT; y: LONGINT);
  393. CODE {SYSTEM.i386}
  394. POP EBX
  395. POP EAX
  396. LOCK
  397. ADD DWORD [EAX], EBX
  398. END AtomicAdd;
  399. (** Atomic EXCL. *)
  400. PROCEDURE AtomicExcl* (VAR s: SET; bit: LONGINT);
  401. CODE {SYSTEM.i386}
  402. MOV EAX, [EBP+bit]
  403. MOV EBX, [EBP+s]
  404. LOCK
  405. BTR [EBX], EAX
  406. END AtomicExcl;
  407. (** Atomic test-and-set. Set x = TRUE and return old value of x. *)
  408. PROCEDURE -AtomicTestSet*(VAR x: BOOLEAN): BOOLEAN;
  409. CODE {SYSTEM.i386}
  410. POP EBX
  411. MOV AL, 1
  412. XCHG [EBX], AL
  413. END AtomicTestSet;
  414. (* Atomic compare-and-swap. Set x = new if x = old and return old value of x *)
  415. PROCEDURE {REALTIME} -AtomicCAS* (VAR x: LONGINT; old, new: LONGINT): LONGINT;
  416. CODE {SYSTEM.i386}
  417. POP EBX ; new
  418. POP EAX ; old
  419. POP ECX ; address of x
  420. DB 0F0X, 00FX, 0B1X, 019X ; LOCK CMPXCHG [ECX], EBX; atomicly compare x with old and set it to new if equal
  421. END AtomicCAS;
  422. (* Return current instruction pointer *)
  423. PROCEDURE {REALTIME} CurrentPC* (): ADDRESS;
  424. CODE {SYSTEM.i386}
  425. MOV EAX, [EBP+4]
  426. END CurrentPC;
  427. (* Return current frame pointer *)
  428. PROCEDURE {REALTIME} -CurrentBP* (): ADDRESS;
  429. CODE {SYSTEM.i386}
  430. MOV EAX, EBP
  431. END CurrentBP;
  432. (* Set current frame pointer *)
  433. PROCEDURE {REALTIME} -SetBP* (bp: ADDRESS);
  434. CODE {SYSTEM.i386}
  435. POP EBP
  436. END SetBP;
  437. (* Return current stack pointer *)
  438. PROCEDURE {REALTIME} -CurrentSP* (): ADDRESS;
  439. CODE {SYSTEM.i386}
  440. MOV EAX, ESP
  441. END CurrentSP;
  442. (* Set current stack pointer *)
  443. PROCEDURE {REALTIME} -SetSP* (sp: ADDRESS);
  444. CODE {SYSTEM.i386}
  445. POP ESP
  446. END SetSP;
  447. PROCEDURE {REALTIME} -GetEAX*(): LONGINT;
  448. CODE{SYSTEM.i386}
  449. END GetEAX;
  450. PROCEDURE {REALTIME} -GetECX*(): LONGINT;
  451. CODE{SYSTEM.i386}
  452. MOV EAX,ECX
  453. END GetECX;
  454. PROCEDURE {REALTIME} -GetESI*(): LONGINT;
  455. CODE{SYSTEM.i386}
  456. MOV EAX,ESI
  457. END GetESI;
  458. PROCEDURE {REALTIME} -GetEDI*(): LONGINT;
  459. CODE{SYSTEM.i386}
  460. MOV EAX,EDI
  461. END GetEDI;
  462. PROCEDURE {REALTIME} -SetEAX*(n: LONGINT);
  463. CODE{SYSTEM.i386}
  464. POP EAX
  465. END SetEAX;
  466. PROCEDURE {REALTIME} -SetEBX*(n: LONGINT);
  467. CODE{SYSTEM.i386}
  468. POP EBX
  469. END SetEBX;
  470. PROCEDURE {REALTIME} -SetECX*(n: LONGINT);
  471. CODE{SYSTEM.i386}
  472. POP ECX
  473. END SetECX;
  474. PROCEDURE {REALTIME} -SetEDX*(n: LONGINT);
  475. CODE{SYSTEM.i386}
  476. POP EDX
  477. END SetEDX;
  478. PROCEDURE {REALTIME} -SetESI*(n: LONGINT);
  479. CODE{SYSTEM.i386}
  480. POP ESI
  481. END SetESI;
  482. PROCEDURE {REALTIME} -SetEDI*(n: LONGINT);
  483. CODE{SYSTEM.i386}
  484. POP EDI
  485. END SetEDI;
  486. PROCEDURE -GetTimer* (): HUGEINT;
  487. CODE {SYSTEM.Pentium}
  488. RDTSC ; set EDX:EAX
  489. END GetTimer;
  490. (** -- Configuration and bootstrapping -- *)
  491. (** 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. *)
  492. PROCEDURE GetConfig* (CONST name: ARRAY OF CHAR; VAR val: ARRAY OF CHAR);
  493. VAR i, src: LONGINT; ch: CHAR;
  494. BEGIN
  495. ASSERT (name[0] # "="); (* no longer supported, use GetInit instead *)
  496. src := -1;
  497. LOOP
  498. REPEAT
  499. INC( src ); ch := config[src];
  500. IF ch = 0X THEN EXIT END;
  501. UNTIL ch > ' ';
  502. i := 0;
  503. LOOP
  504. ch := config[src];
  505. IF (ch # name[i]) OR (name[i] = 0X) THEN EXIT END;
  506. INC (i); INC (src)
  507. END;
  508. IF (ch <= ' ') & (name[i] = 0X) THEN (* found *)
  509. i := 0;
  510. REPEAT
  511. INC (src); ch := config[src]; val[i] := ch; INC (i);
  512. IF i = LEN(val) THEN val[i - 1] := 0X; RETURN END (* val too short *)
  513. UNTIL ch <= ' ';
  514. IF ch = ' ' THEN val[i -1] := 0X END;
  515. RETURN
  516. ELSE
  517. WHILE ch > ' ' DO (* skip to end of name *)
  518. INC (src); ch := config[src]
  519. END;
  520. INC (src);
  521. REPEAT (* skip to end of value *)
  522. ch := config[src]; INC (src)
  523. UNTIL ch <= ' '
  524. END
  525. END;
  526. val[0] := 0X
  527. END GetConfig;
  528. (** 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. *)
  529. PROCEDURE StrToInt* (VAR i: LONGINT; CONST s: ARRAY OF CHAR): LONGINT;
  530. VAR vd, vh, sgn, d: LONGINT; hex: BOOLEAN;
  531. BEGIN
  532. vd := 0; vh := 0; hex := FALSE;
  533. IF s[i] = "-" THEN sgn := -1; INC (i) ELSE sgn := 1 END;
  534. LOOP
  535. IF (s[i] >= "0") & (s[i] <= "9") THEN d := ORD (s[i])-ORD ("0")
  536. ELSIF (CAP (s[i]) >= "A") & (CAP (s[i]) <= "F") THEN d := ORD (CAP (s[i]))-ORD ("A") + 10; hex := TRUE
  537. ELSE EXIT
  538. END;
  539. vd := 10*vd + d; vh := 16*vh + d;
  540. INC (i)
  541. END;
  542. IF CAP (s[i]) = "H" THEN hex := TRUE; INC (i) END; (* optional H *)
  543. IF hex THEN vd := vh END;
  544. RETURN sgn * vd
  545. END StrToInt;
  546. (* function returning the number of processors that are available to Aos *)
  547. PROCEDURE NumberOfProcessors*( ): LONGINT;
  548. BEGIN
  549. RETURN 1
  550. END NumberOfProcessors;
  551. (*! non portable code, for native Aos only *)
  552. PROCEDURE SetNumberOfProcessors*( num: LONGINT );
  553. BEGIN
  554. (* numberOfProcessors := num; *)
  555. END SetNumberOfProcessors;
  556. (* function for changing byte order *)
  557. PROCEDURE ChangeByteOrder* (n: LONGINT): LONGINT;
  558. CODE { SYSTEM.i486 }
  559. MOV EAX, [EBP+n] ; load n in eax
  560. BSWAP EAX ; swap byte order
  561. END ChangeByteOrder;
  562. (* Send and print character *)
  563. PROCEDURE TraceChar *(c: CHAR);
  564. BEGIN
  565. Trace.Char( c )
  566. END TraceChar;
  567. (** CPU identification *)
  568. PROCEDURE CPUID*( VAR vendor: Vendor; VAR version: LONGINT; VAR features1,features2: SET );
  569. CODE {SYSTEM.i386, SYSTEM.Pentium}
  570. MOV EAX, 0
  571. CPUID
  572. CMP EAX, 0
  573. JNE ok
  574. MOV ESI, [EBP+vendor]
  575. MOV [ESI], AL ; AL = 0
  576. MOV ESI, [EBP+version]
  577. MOV [ESI], EAX ; EAX = 0
  578. MOV ESI, [EBP+features1]
  579. MOV [ESI], EAX
  580. MOV ESI, [EBP+features2]
  581. MOV [ESI], EAX
  582. JMP end
  583. ok:
  584. MOV ESI, [EBP+vendor]
  585. MOV [ESI], EBX
  586. MOV [ESI+4], EDX
  587. MOV [ESI+8], ECX
  588. MOV BYTE [ESI+12], 0
  589. MOV EAX, 1
  590. CPUID
  591. MOV ESI, [EBP+version]
  592. MOV [ESI], EAX
  593. MOV ESI, [EBP+features1]
  594. MOV [ESI], EDX
  595. MOV ESI, [EBP+features2]
  596. MOV [ESI], ECX
  597. end:
  598. END CPUID;
  599. (* If the CPUID instruction is supported, the ID flag (bit 21) of the EFLAGS register is r/w *)
  600. PROCEDURE CpuIdSupported( ) : BOOLEAN;
  601. CODE {SYSTEM.i386}
  602. PUSHFD ; save EFLAGS
  603. POP EAX ; store EFLAGS in EAX
  604. MOV EBX, EAX ; save EBX for later testing
  605. XOR EAX, 00200000H ; toggle bit 21
  606. PUSH EAX ; push to stack
  607. POPFD ; save changed EAX to EFLAGS
  608. PUSHFD ; push EFLAGS to TOS
  609. POP EAX ; store EFLAGS in EAX
  610. CMP EAX, EBX ; see if bit 21 has changed
  611. SETNE AL; ; return TRUE if bit 21 has changed, FALSE otherwise
  612. END CpuIdSupported;
  613. (* setup MMX, SSE and SSE2..SSE5 and AVX extension *)
  614. PROCEDURE SetupSSE2Ext;
  615. CONST
  616. MMXFlag=23;(*IN features from EBX*)
  617. FXSRFlag = 24;
  618. SSEFlag = 25;
  619. SSE2Flag = 26;
  620. SSE3Flag = 0; (*IN features2 from ECX*) (*PH 04/11*)
  621. SSSE3Flag =9;
  622. SSE41Flag =19;
  623. SSE42Flag =20;
  624. SSE5Flag = 11;
  625. AVXFlag = 28;
  626. BEGIN
  627. MMXSupport := MMXFlag IN features;
  628. SSESupport := SSEFlag IN features;
  629. SSE2Support := SSESupport & (SSE2Flag IN features);
  630. SSE3Support := SSE2Support & (SSE3Flag IN features2);
  631. SSSE3Support := SSE3Support & (SSSE3Flag IN features2); (* PH 04/11*)
  632. SSE41Support := SSE3Support & (SSE41Flag IN features2);
  633. SSE42Support := SSE3Support & (SSE42Flag IN features2);
  634. SSE5Support := SSE3Support & (SSE5Flag IN features2);
  635. AVXSupport := SSE3Support & (AVXFlag IN features2);
  636. IF SSESupport & (FXSRFlag IN features) THEN
  637. (* InitSSE(); *) (*! not privileged mode in Windows and Unix not allowed *)
  638. END;
  639. END SetupSSE2Ext;
  640. PROCEDURE -InitSSE;
  641. CODE {SYSTEM.Pentium, SYSTEM.Privileged}
  642. MOV EAX, CR4
  643. OR EAX, 00000200H ; set bit 9 (OSFXSR)
  644. AND EAX, 0FFFFFBFFH ; delete bit 10 (OSXMMEXCPT)
  645. MOV CR4, EAX
  646. END InitSSE;
  647. (** -- Processor initialization -- *)
  648. PROCEDURE -SetFCR( s: SET );
  649. CODE {SYSTEM.i386, SYSTEM.FPU}
  650. FLDCW [ESP] ; parameter s
  651. POP EAX
  652. END SetFCR;
  653. PROCEDURE -FCR( ): SET;
  654. CODE {SYSTEM.i386, SYSTEM.FPU}
  655. PUSH 0
  656. FNSTCW [ESP]
  657. FWAIT
  658. POP EAX
  659. END FCR;
  660. PROCEDURE -InitFPU;
  661. CODE {SYSTEM.i386, SYSTEM.FPU}
  662. FNINIT
  663. END InitFPU;
  664. (** Setup FPU control word of current processor. *)
  665. PROCEDURE SetupFPU*;
  666. BEGIN
  667. InitFPU; SetFCR( fcr )
  668. END SetupFPU;
  669. (* Initialize locks. *)
  670. PROCEDURE InitLocks;
  671. VAR i: LONGINT;
  672. BEGIN
  673. i := 0;
  674. WHILE i < MaxLocks DO mtx[i] := mtxInit(0); INC( i ) END;
  675. END InitLocks;
  676. PROCEDURE CleanupLocks*;
  677. VAR i: LONGINT;
  678. BEGIN
  679. i := 0;
  680. WHILE i < MaxLocks DO mtxDestroy( mtx[i] ); INC( i ) END;
  681. END CleanupLocks;
  682. (** Acquire a spin-lock. *)
  683. PROCEDURE Acquire*( level: LONGINT ); (* non reentrant lock *)
  684. BEGIN
  685. mtxLock( mtx[level] );
  686. END Acquire;
  687. (** Release a spin-lock. *)
  688. PROCEDURE Release*( level: LONGINT );
  689. BEGIN
  690. mtxUnlock( mtx[level] );
  691. END Release;
  692. PROCEDURE Shutdown*( reboot: BOOLEAN );
  693. VAR ignore: LONGINT;
  694. BEGIN
  695. ignore := Unix.close( logfile );
  696. IF reboot THEN Unix.exit( 0 ) ELSE Unix.exit( 1 ) END;
  697. END Shutdown;
  698. PROCEDURE InitHeap;
  699. VAR heapAdr, firstBlock: ADDRESS; size: SIZE;
  700. BEGIN
  701. Unix.Dlsym( 0, "heapAdr", ADDRESSOF( heapAdr ) );
  702. Unix.Dlsym( 0, "heapSize", ADDRESSOF( size ) );
  703. firstBlock := heapAdr + ((-heapAdr - AddrSize) MOD BlockSize);
  704. size := heapAdr + size - BlockSize - firstBlock; DEC( size, size MOD BlockSize + BlockSize );
  705. firstMemBlock.next := NIL;
  706. firstMemBlock.startAdr := heapAdr;
  707. firstMemBlock.beginBlockAdr := firstBlock;
  708. firstMemBlock.endBlockAdr := firstBlock + size;
  709. firstMemBlock.size := size;
  710. memBlockHead := S.VAL( MemoryBlock, ADDRESSOF( firstMemBlock ) );
  711. memBlockTail := memBlockHead;
  712. END InitHeap;
  713. PROCEDURE InitConfig;
  714. VAR a: ADDRESS; i: LONGINT; c: CHAR;
  715. BEGIN
  716. a := Unix.getenv( ADDRESSOF( "AOSCONFIG" ) );
  717. IF a = 0 THEN config := DefaultConfig
  718. ELSE
  719. REPEAT
  720. S.GET( a, c ); INC( a ); config[i] := c; INC( i )
  721. UNTIL c = 0X
  722. END
  723. END InitConfig;
  724. PROCEDURE UpdateTicks*;
  725. BEGIN
  726. ticks := SHORT( (GetTimer() - timer0) DIV (mhz * 1000) );
  727. END UpdateTicks;
  728. PROCEDURE InitThreads;
  729. VAR res: BOOLEAN;
  730. BEGIN
  731. res := thrInitialize( prioLow, prioHigh );
  732. IF ~res THEN
  733. Trace.StringLn( "Machine.InitThreads: no threads support in boot environment. teminating" );
  734. Unix.exit( 1 )
  735. END;
  736. IF Glue.debug # {} THEN
  737. Trace.String( "Threads initialized, priorities low, high: " );
  738. Trace.Int( prioLow, 0 ); Trace.String( ", " ); Trace.Int( prioHigh, 0 );
  739. Trace.Ln
  740. END
  741. END InitThreads;
  742. PROCEDURE CPUSpeed;
  743. VAR t0, t1: HUGEINT;
  744. BEGIN
  745. t0 := GetTimer(); thrSleep( 100 ); t1 := GetTimer();
  746. mhz := (t1 - t0) DIV 100000;
  747. IF Glue.debug # {} THEN
  748. Trace.String( "CPU speed: ~" ); Trace.Int( SHORT( mhz ), 0); Trace.String( " MHz" ); Trace.Ln
  749. END
  750. END CPUSpeed;
  751. PROCEDURE Log1( c: CHAR );
  752. VAR ignore: LONGINT;
  753. BEGIN
  754. ignore := Unix.write( 1, ADDRESSOF( c ), 1 );
  755. ignore := Unix.write( logfile, ADDRESSOF( c ), 1 );
  756. END Log1;
  757. PROCEDURE Log2( c: CHAR );
  758. VAR ignore: LONGINT;
  759. BEGIN
  760. ignore := Unix.write( logfile, ADDRESSOF( c ), 1 );
  761. END Log2;
  762. PROCEDURE InitLog;
  763. VAR name: ARRAY 32 OF CHAR; pid, i, d: LONGINT;
  764. BEGIN
  765. name := "AOS.xxxxx.Log";
  766. pid := Unix.getpid(); i := 8;
  767. REPEAT
  768. name[i] := CHR( pid MOD 10 + ORD( '0' ) ); DEC( i );
  769. pid := pid DIV 10;
  770. UNTIL i = 3;
  771. logfile := Unix.open( ADDRESSOF( name ), Unix.rdwr + Unix.creat + Unix.trunc, Unix.rwrwr );
  772. IF Unix.argc < 3 THEN VerboseLog
  773. ELSE standaloneAppl := TRUE; SilentLog
  774. END
  775. END InitLog;
  776. PROCEDURE SilentLog*;
  777. BEGIN
  778. Trace.Char := Log2
  779. END SilentLog;
  780. PROCEDURE VerboseLog*;
  781. BEGIN
  782. Trace.Char := Log1
  783. END VerboseLog;
  784. PROCEDURE Append( VAR a: ARRAY OF CHAR; CONST this: ARRAY OF CHAR );
  785. VAR i, j: LONGINT;
  786. BEGIN
  787. i := 0; j := 0;
  788. WHILE a[i] # 0X DO INC( i ) END;
  789. WHILE (i < LEN( a ) - 1) & (this[j] # 0X) DO a[i] := this[j]; INC( i ); INC( j ) END;
  790. a[i] := 0X
  791. END Append;
  792. PROCEDURE Init;
  793. VAR vendor: Vendor; ver: LONGINT;
  794. BEGIN
  795. Unix.Dlsym( 0, "thrInitialize", ADDRESSOF( thrInitialize ) );
  796. Unix.Dlsym( 0, "mtxInit", ADDRESSOF( mtxInit ) );
  797. Unix.Dlsym( 0, "mtxDestroy", ADDRESSOF( mtxDestroy ) );
  798. Unix.Dlsym( 0, "mtxLock", ADDRESSOF( mtxLock ) );
  799. Unix.Dlsym( 0, "mtxUnlock", ADDRESSOF( mtxUnlock ) );
  800. Unix.Dlsym( 0, "conInit", ADDRESSOF( conInit ) );
  801. Unix.Dlsym( 0, "conDestroy", ADDRESSOF( conDestroy ) );
  802. Unix.Dlsym( 0, "conWait", ADDRESSOF( conWait ) );
  803. Unix.Dlsym( 0, "conSignal", ADDRESSOF( conSignal ) );
  804. Unix.Dlsym( 0, "thrSleep", ADDRESSOF( thrSleep ) );
  805. Unix.Dlsym( 0, "thrThis", ADDRESSOF( thrThis ) );
  806. standaloneAppl := FALSE;
  807. COPY( Unix.Version, version ); Append( version, Version );
  808. timer0 := GetTimer( ); ticks := 0;
  809. InitThreads;
  810. InitLocks;
  811. traceHeap := 1 IN Glue.debug;
  812. InitHeap;
  813. InitConfig;
  814. InitLog;
  815. CPUSpeed;
  816. CPUID( vendor, ver, features, features2 ); SetupSSE2Ext;
  817. fcr := (FCR() - {0,2,3,10,11}) + {0..5,8,9}; (* default FCR RC=00B *)
  818. END Init;
  819. BEGIN
  820. Init
  821. END Machine.
  822. (*
  823. 03.03.1998 pjm First version
  824. 30.06.1999 pjm ProcessorID moved to AosProcessor
  825. *)
  826. (**
  827. Notes
  828. 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.
  829. 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.
  830. 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.
  831. Config strings:
  832. 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".
  833. *)