Unix.I386.Machine.Mod 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  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.6547)";
  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. (** Return current processor ID (0 to MaxNum-1). *)
  81. PROCEDURE {REALTIME} ID* (): LONGINT;
  82. BEGIN
  83. RETURN 0
  84. END ID;
  85. (* insert given memory block in sorted list of memory blocks, sort key is startAdr field - called during GC *)
  86. PROCEDURE InsertMemoryBlock(memBlock: MemoryBlock);
  87. VAR cur {UNTRACED}, prev {UNTRACED}: MemoryBlock;
  88. BEGIN
  89. cur := memBlockHead;
  90. prev := NIL;
  91. WHILE (cur # NIL) & (cur.startAdr < memBlock.startAdr) DO
  92. prev := cur;
  93. cur := cur.next
  94. END;
  95. IF prev = NIL THEN (* insert at head of list *)
  96. memBlock.next := memBlockHead;
  97. memBlockHead := memBlock
  98. ELSE (* insert in middle or at end of list *)
  99. prev.next := memBlock;
  100. memBlock.next := cur;
  101. IF cur = NIL THEN
  102. memBlockTail := memBlock
  103. END
  104. END
  105. END InsertMemoryBlock;
  106. (* Free unused memory block - called during GC *)
  107. PROCEDURE FreeMemBlock*(memBlock: MemoryBlock);
  108. VAR cur {UNTRACED}, prev {UNTRACED}: MemoryBlock;
  109. BEGIN
  110. cur := memBlockHead;
  111. prev := NIL;
  112. WHILE (cur # NIL) & (cur # memBlock) DO
  113. prev := cur;
  114. cur := cur.next
  115. END;
  116. IF cur = memBlock THEN
  117. IF traceHeap THEN
  118. Trace.String( "Release memory block " ); Trace.Hex( memBlock.startAdr, -8 ); Trace.Ln
  119. END;
  120. IF prev = NIL THEN
  121. memBlockHead := cur.next
  122. ELSE
  123. prev.next := cur.next;
  124. IF cur.next = NIL THEN
  125. memBlockTail := prev
  126. END
  127. END;
  128. Unix.free( memBlock.startAdr )
  129. ELSE
  130. HALT(535) (* error in memory block management *)
  131. END;
  132. END FreeMemBlock;
  133. (* expand heap by allocating a new memory block *)
  134. PROCEDURE ExpandHeap*( dummy: LONGINT; size: SIZE; VAR beginBlockAdr, endBlockAdr: ADDRESS );
  135. VAR mBlock: MemoryBlock; alloc, s: SIZE; a, adr: ADDRESS;
  136. BEGIN
  137. IF size < (MemBlockSize - (2*BlockSize)) THEN alloc := MemBlockSize
  138. ELSE alloc := size + (2*BlockSize);
  139. END;
  140. INC( alloc, (-alloc) MOD Unix.PageSize );
  141. IF Unix.posix_memalign( adr, Unix.PageSize, alloc ) # 0 THEN
  142. Unix.Perror( "Machine.ExpandHeap: posix_memalign" );
  143. beginBlockAdr := 0;
  144. endBlockAdr := 0
  145. ELSE
  146. IF Unix.mprotect( adr, alloc, 7 (* READ WRITE EXEC *) ) # 0 THEN
  147. Unix.Perror( "Machine.ExpandHeap: mprotect" )
  148. END;
  149. mBlock := S.VAL( MemoryBlock, adr );
  150. mBlock.next := NIL;
  151. mBlock.startAdr := adr;
  152. mBlock.size := alloc;
  153. mBlock.beginBlockAdr := adr + BlockSize - AddrSize;
  154. ASSERT( (mBlock.beginBlockAdr + AddrSize) MOD BlockSize = 0 );
  155. s := adr + alloc - mBlock.beginBlockAdr - BlockSize;
  156. DEC( s, s MOD BlockSize );
  157. ASSERT( s >= size );
  158. mBlock.endBlockAdr := mBlock.beginBlockAdr + s;
  159. InsertMemoryBlock( mBlock );
  160. IF traceHeap THEN TraceHeap( mBlock ) END;
  161. a := mBlock.beginBlockAdr;
  162. S.PUT( a, a + AddrSize ); (* tag *)
  163. S.PUT( a + AddrSize, s - AddrSize ); (* size *)
  164. S.PUT( a + AddrSize + SizeSize, S.VAL( ADDRESS, 0 ) ); (* next *)
  165. beginBlockAdr := mBlock.beginBlockAdr;
  166. endBlockAdr := mBlock.endBlockAdr;
  167. END
  168. END ExpandHeap;
  169. PROCEDURE TraceHeap( new: MemoryBlock );
  170. VAR cur{UNTRACED}: MemoryBlock;
  171. BEGIN
  172. Trace.Ln;
  173. Trace.String( "Heap expanded" ); Trace.Ln;
  174. cur := memBlockHead;
  175. WHILE cur # NIL DO
  176. Trace.Hex( cur.startAdr, -8 ); Trace.String( " " ); Trace.Int( cur.size, 15 );
  177. IF cur = new THEN Trace.String( " (new)" ) END;
  178. Trace.Ln;
  179. cur := cur.next
  180. END
  181. END TraceHeap;
  182. (* returns if an address is a currently allocated heap address *)
  183. PROCEDURE ValidHeapAddress*( p: ADDRESS ): BOOLEAN;
  184. VAR mb: MemoryBlock;
  185. BEGIN
  186. mb := memBlockHead;
  187. WHILE mb # NIL DO
  188. IF (p >= mb.beginBlockAdr) & (p <= mb.endBlockAdr) THEN RETURN TRUE END;
  189. mb := mb.next;
  190. END;
  191. RETURN FALSE
  192. END ValidHeapAddress;
  193. (** Return information on free memory in Kbytes. *)
  194. PROCEDURE GetFreeK*(VAR total, lowFree, highFree: SIZE);
  195. BEGIN
  196. (*! meaningless in Unix port, for interface compatibility only *)
  197. total := 0;
  198. lowFree := 0;
  199. highFree := 0
  200. END GetFreeK;
  201. (** Fill "size" bytes at "destAdr" with "filler". "size" must be multiple of 4. *)
  202. PROCEDURE {REALTIME} Fill32* (destAdr: ADDRESS; size: SIZE; filler: LONGINT);
  203. CODE {SYSTEM.i386}
  204. MOV EDI, [EBP+destAdr]
  205. MOV ECX, [EBP+size]
  206. MOV EAX, [EBP+filler]
  207. TEST ECX, 3
  208. JZ ok
  209. PUSH 8 ; ASSERT failure
  210. INT 3
  211. ok:
  212. SHR ECX, 2
  213. CLD
  214. REP STOSD
  215. END Fill32;
  216. PROCEDURE Portin8*(port: LONGINT; VAR val: CHAR);
  217. END Portin8;
  218. PROCEDURE Portin16*(port: LONGINT; VAR val: INTEGER);
  219. END Portin16;
  220. PROCEDURE Portin32*(port: LONGINT; VAR val: LONGINT);
  221. END Portin32;
  222. PROCEDURE Portout8*(port: LONGINT; val: CHAR);
  223. END Portout8;
  224. PROCEDURE Portout16*(port: LONGINT; val: INTEGER);
  225. END Portout16;
  226. PROCEDURE Portout32*(port: LONGINT; val: LONGINT);
  227. END Portout32;
  228. (** -- Atomic operations -- *)
  229. (** Atomic INC(x). *)
  230. PROCEDURE -AtomicInc*(VAR x: LONGINT);
  231. CODE {SYSTEM.i386}
  232. POP EAX
  233. LOCK
  234. INC DWORD [EAX]
  235. END AtomicInc;
  236. (** Atomic DEC(x). *)
  237. PROCEDURE -AtomicDec*(VAR x: LONGINT);
  238. CODE {SYSTEM.i386}
  239. POP EAX
  240. LOCK
  241. DEC DWORD [EAX]
  242. END AtomicDec;
  243. (** Atomic INC(x, y). *)
  244. PROCEDURE -AtomicAdd*(VAR x: LONGINT; y: LONGINT);
  245. CODE {SYSTEM.i386}
  246. POP EBX
  247. POP EAX
  248. LOCK
  249. ADD DWORD [EAX], EBX
  250. END AtomicAdd;
  251. (** Atomic EXCL. *)
  252. PROCEDURE AtomicExcl* (VAR s: SET; bit: LONGINT);
  253. CODE {SYSTEM.i386}
  254. MOV EAX, [EBP+bit]
  255. MOV EBX, [EBP+s]
  256. LOCK
  257. BTR [EBX], EAX
  258. END AtomicExcl;
  259. (** Atomic test-and-set. Set x = TRUE and return old value of x. *)
  260. PROCEDURE -AtomicTestSet*(VAR x: BOOLEAN): BOOLEAN;
  261. CODE {SYSTEM.i386}
  262. POP EBX
  263. MOV AL, 1
  264. XCHG [EBX], AL
  265. END AtomicTestSet;
  266. (* Atomic compare-and-swap. Set x = new if x = old and return old value of x *)
  267. PROCEDURE {REALTIME} -AtomicCAS* (VAR x: LONGINT; old, new: LONGINT): LONGINT;
  268. CODE {SYSTEM.i386}
  269. POP EBX ; new
  270. POP EAX ; old
  271. POP ECX ; address of x
  272. DB 0F0X, 00FX, 0B1X, 019X ; LOCK CMPXCHG [ECX], EBX; atomicly compare x with old and set it to new if equal
  273. END AtomicCAS;
  274. (* Return current instruction pointer *)
  275. PROCEDURE {REALTIME} CurrentPC* (): ADDRESS;
  276. CODE {SYSTEM.i386}
  277. MOV EAX, [EBP+4]
  278. END CurrentPC;
  279. (* Return current frame pointer *)
  280. PROCEDURE {REALTIME} -CurrentBP* (): ADDRESS;
  281. CODE {SYSTEM.i386}
  282. MOV EAX, EBP
  283. END CurrentBP;
  284. (* Set current frame pointer *)
  285. PROCEDURE {REALTIME} -SetBP* (bp: ADDRESS);
  286. CODE {SYSTEM.i386}
  287. POP EBP
  288. END SetBP;
  289. (* Return current stack pointer *)
  290. PROCEDURE {REALTIME} -CurrentSP* (): ADDRESS;
  291. CODE {SYSTEM.i386}
  292. MOV EAX, ESP
  293. END CurrentSP;
  294. (* Set current stack pointer *)
  295. PROCEDURE {REALTIME} -SetSP* (sp: ADDRESS);
  296. CODE {SYSTEM.i386}
  297. POP ESP
  298. END SetSP;
  299. PROCEDURE {REALTIME} -GetEAX*(): LONGINT;
  300. CODE{SYSTEM.i386}
  301. END GetEAX;
  302. PROCEDURE {REALTIME} -GetECX*(): LONGINT;
  303. CODE{SYSTEM.i386}
  304. MOV EAX,ECX
  305. END GetECX;
  306. PROCEDURE {REALTIME} -GetESI*(): LONGINT;
  307. CODE{SYSTEM.i386}
  308. MOV EAX,ESI
  309. END GetESI;
  310. PROCEDURE {REALTIME} -GetEDI*(): LONGINT;
  311. CODE{SYSTEM.i386}
  312. MOV EAX,EDI
  313. END GetEDI;
  314. PROCEDURE {REALTIME} -SetEAX*(n: LONGINT);
  315. CODE{SYSTEM.i386}
  316. POP EAX
  317. END SetEAX;
  318. PROCEDURE {REALTIME} -SetEBX*(n: LONGINT);
  319. CODE{SYSTEM.i386}
  320. POP EBX
  321. END SetEBX;
  322. PROCEDURE {REALTIME} -SetECX*(n: LONGINT);
  323. CODE{SYSTEM.i386}
  324. POP ECX
  325. END SetECX;
  326. PROCEDURE {REALTIME} -SetEDX*(n: LONGINT);
  327. CODE{SYSTEM.i386}
  328. POP EDX
  329. END SetEDX;
  330. PROCEDURE {REALTIME} -SetESI*(n: LONGINT);
  331. CODE{SYSTEM.i386}
  332. POP ESI
  333. END SetESI;
  334. PROCEDURE {REALTIME} -SetEDI*(n: LONGINT);
  335. CODE{SYSTEM.i386}
  336. POP EDI
  337. END SetEDI;
  338. PROCEDURE -GetTimer* (): HUGEINT;
  339. CODE {SYSTEM.Pentium}
  340. RDTSC ; set EDX:EAX
  341. END GetTimer;
  342. (** -- Configuration and bootstrapping -- *)
  343. (** 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. *)
  344. PROCEDURE GetConfig* (CONST name: ARRAY OF CHAR; VAR val: ARRAY OF CHAR);
  345. VAR i, src: LONGINT; ch: CHAR;
  346. BEGIN
  347. ASSERT (name[0] # "="); (* no longer supported, use GetInit instead *)
  348. src := -1;
  349. LOOP
  350. REPEAT
  351. INC( src ); ch := config[src];
  352. IF ch = 0X THEN EXIT END;
  353. UNTIL ch > ' ';
  354. i := 0;
  355. LOOP
  356. ch := config[src];
  357. IF (ch # name[i]) OR (name[i] = 0X) THEN EXIT END;
  358. INC (i); INC (src)
  359. END;
  360. IF (ch <= ' ') & (name[i] = 0X) THEN (* found *)
  361. i := 0;
  362. REPEAT
  363. INC (src); ch := config[src]; val[i] := ch; INC (i);
  364. IF i = LEN(val) THEN val[i - 1] := 0X; RETURN END (* val too short *)
  365. UNTIL ch <= ' ';
  366. IF ch = ' ' THEN val[i -1] := 0X END;
  367. RETURN
  368. ELSE
  369. WHILE ch > ' ' DO (* skip to end of name *)
  370. INC (src); ch := config[src]
  371. END;
  372. INC (src);
  373. REPEAT (* skip to end of value *)
  374. ch := config[src]; INC (src)
  375. UNTIL ch <= ' '
  376. END
  377. END;
  378. val[0] := 0X
  379. END GetConfig;
  380. (** 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. *)
  381. PROCEDURE StrToInt* (VAR i: LONGINT; CONST s: ARRAY OF CHAR): LONGINT;
  382. VAR vd, vh, sgn, d: LONGINT; hex: BOOLEAN;
  383. BEGIN
  384. vd := 0; vh := 0; hex := FALSE;
  385. IF s[i] = "-" THEN sgn := -1; INC (i) ELSE sgn := 1 END;
  386. LOOP
  387. IF (s[i] >= "0") & (s[i] <= "9") THEN d := ORD (s[i])-ORD ("0")
  388. ELSIF (CAP (s[i]) >= "A") & (CAP (s[i]) <= "F") THEN d := ORD (CAP (s[i]))-ORD ("A") + 10; hex := TRUE
  389. ELSE EXIT
  390. END;
  391. vd := 10*vd + d; vh := 16*vh + d;
  392. INC (i)
  393. END;
  394. IF CAP (s[i]) = "H" THEN hex := TRUE; INC (i) END; (* optional H *)
  395. IF hex THEN vd := vh END;
  396. RETURN sgn * vd
  397. END StrToInt;
  398. (* function returning the number of processors that are available to Aos *)
  399. PROCEDURE NumberOfProcessors*( ): LONGINT;
  400. BEGIN
  401. RETURN 1
  402. END NumberOfProcessors;
  403. (*! non portable code, for native Aos only *)
  404. PROCEDURE SetNumberOfProcessors*( num: LONGINT );
  405. BEGIN
  406. (* numberOfProcessors := num; *)
  407. END SetNumberOfProcessors;
  408. (* function for changing byte order *)
  409. PROCEDURE ChangeByteOrder* (n: LONGINT): LONGINT;
  410. CODE { SYSTEM.i486 }
  411. MOV EAX, [EBP+n] ; load n in eax
  412. BSWAP EAX ; swap byte order
  413. END ChangeByteOrder;
  414. (* Send and print character *)
  415. PROCEDURE TraceChar *(c: CHAR);
  416. BEGIN
  417. Trace.Char( c )
  418. END TraceChar;
  419. (** CPU identification *)
  420. PROCEDURE CPUID*( VAR vendor: Vendor; VAR version: LONGINT; VAR features1,features2: SET );
  421. CODE {SYSTEM.i386, SYSTEM.Pentium}
  422. MOV EAX, 0
  423. CPUID
  424. CMP EAX, 0
  425. JNE ok
  426. MOV ESI, [EBP+vendor]
  427. MOV [ESI], AL ; AL = 0
  428. MOV ESI, [EBP+version]
  429. MOV [ESI], EAX ; EAX = 0
  430. MOV ESI, [EBP+features1]
  431. MOV [ESI], EAX
  432. MOV ESI, [EBP+features2]
  433. MOV [ESI], EAX
  434. JMP end
  435. ok:
  436. MOV ESI, [EBP+vendor]
  437. MOV [ESI], EBX
  438. MOV [ESI+4], EDX
  439. MOV [ESI+8], ECX
  440. MOV BYTE [ESI+12], 0
  441. MOV EAX, 1
  442. CPUID
  443. MOV ESI, [EBP+version]
  444. MOV [ESI], EAX
  445. MOV ESI, [EBP+features1]
  446. MOV [ESI], EDX
  447. MOV ESI, [EBP+features2]
  448. MOV [ESI], ECX
  449. end:
  450. END CPUID;
  451. (* If the CPUID instruction is supported, the ID flag (bit 21) of the EFLAGS register is r/w *)
  452. PROCEDURE CpuIdSupported( ) : BOOLEAN;
  453. CODE {SYSTEM.i386}
  454. PUSHFD ; save EFLAGS
  455. POP EAX ; store EFLAGS in EAX
  456. MOV EBX, EAX ; save EBX for later testing
  457. XOR EAX, 00200000H ; toggle bit 21
  458. PUSH EAX ; push to stack
  459. POPFD ; save changed EAX to EFLAGS
  460. PUSHFD ; push EFLAGS to TOS
  461. POP EAX ; store EFLAGS in EAX
  462. CMP EAX, EBX ; see if bit 21 has changed
  463. SETNE AL; ; return TRUE if bit 21 has changed, FALSE otherwise
  464. END CpuIdSupported;
  465. (* setup MMX, SSE and SSE2..SSE5 and AVX extension *)
  466. PROCEDURE SetupSSE2Ext;
  467. CONST
  468. MMXFlag=23;(*IN features from EBX*)
  469. FXSRFlag = 24;
  470. SSEFlag = 25;
  471. SSE2Flag = 26;
  472. SSE3Flag = 0; (*IN features2 from ECX*) (*PH 04/11*)
  473. SSSE3Flag =9;
  474. SSE41Flag =19;
  475. SSE42Flag =20;
  476. SSE5Flag = 11;
  477. AVXFlag = 28;
  478. BEGIN
  479. MMXSupport := MMXFlag IN features;
  480. SSESupport := SSEFlag IN features;
  481. SSE2Support := SSESupport & (SSE2Flag IN features);
  482. SSE3Support := SSE2Support & (SSE3Flag IN features2);
  483. SSSE3Support := SSE3Support & (SSSE3Flag IN features2); (* PH 04/11*)
  484. SSE41Support := SSE3Support & (SSE41Flag IN features2);
  485. SSE42Support := SSE3Support & (SSE42Flag IN features2);
  486. SSE5Support := SSE3Support & (SSE5Flag IN features2);
  487. AVXSupport := SSE3Support & (AVXFlag IN features2);
  488. IF SSESupport & (FXSRFlag IN features) THEN
  489. (* InitSSE(); *) (*! not privileged mode in Windows and Unix, not allowed *)
  490. END;
  491. END SetupSSE2Ext;
  492. (** -- Processor initialization -- *)
  493. PROCEDURE -SetFCR( s: SET );
  494. CODE {SYSTEM.i386, SYSTEM.FPU}
  495. FLDCW [ESP] ; parameter s
  496. POP EAX
  497. END SetFCR;
  498. PROCEDURE -FCR( ): SET;
  499. CODE {SYSTEM.i386, SYSTEM.FPU}
  500. PUSH 0
  501. FNSTCW [ESP]
  502. FWAIT
  503. POP EAX
  504. END FCR;
  505. PROCEDURE -InitFPU;
  506. CODE {SYSTEM.i386, SYSTEM.FPU}
  507. FNINIT
  508. END InitFPU;
  509. (** Setup FPU control word of current processor. *)
  510. PROCEDURE SetupFPU*;
  511. BEGIN
  512. InitFPU; SetFCR( fcr )
  513. END SetupFPU;
  514. (* Initialize locks. *)
  515. PROCEDURE InitLocks;
  516. VAR i: LONGINT;
  517. BEGIN
  518. i := 0;
  519. WHILE i < MaxLocks DO mtx[i] := mtxInit(0); INC( i ) END;
  520. END InitLocks;
  521. PROCEDURE CleanupLocks*;
  522. VAR i: LONGINT;
  523. BEGIN
  524. i := 0;
  525. WHILE i < MaxLocks DO mtxDestroy( mtx[i] ); INC( i ) END;
  526. END CleanupLocks;
  527. (** Acquire a spin-lock. *)
  528. PROCEDURE Acquire*( level: LONGINT ); (* non reentrant lock *)
  529. BEGIN
  530. mtxLock( mtx[level] );
  531. END Acquire;
  532. (** Release a spin-lock. *)
  533. PROCEDURE Release*( level: LONGINT );
  534. BEGIN
  535. mtxUnlock( mtx[level] );
  536. END Release;
  537. PROCEDURE Shutdown*( reboot: BOOLEAN );
  538. VAR ignore: LONGINT;
  539. BEGIN
  540. ignore := Unix.close( logfile );
  541. IF reboot THEN Unix.exit( 0 ) ELSE Unix.exit( 1 ) END;
  542. END Shutdown;
  543. PROCEDURE InitHeap;
  544. VAR heapAdr, firstBlock: ADDRESS; size: SIZE;
  545. BEGIN
  546. Unix.Dlsym( 0, "heapAdr", ADDRESSOF( heapAdr ) );
  547. Unix.Dlsym( 0, "heapSize", ADDRESSOF( size ) );
  548. firstBlock := heapAdr + ((-heapAdr - AddrSize) MOD BlockSize);
  549. size := heapAdr + size - BlockSize - firstBlock; DEC( size, size MOD BlockSize + BlockSize );
  550. firstMemBlock.next := NIL;
  551. firstMemBlock.startAdr := heapAdr;
  552. firstMemBlock.beginBlockAdr := firstBlock;
  553. firstMemBlock.endBlockAdr := firstBlock + size;
  554. firstMemBlock.size := size;
  555. memBlockHead := S.VAL( MemoryBlock, ADDRESSOF( firstMemBlock ) );
  556. memBlockTail := memBlockHead;
  557. END InitHeap;
  558. PROCEDURE InitConfig;
  559. VAR a: ADDRESS; i: LONGINT; c: CHAR;
  560. BEGIN
  561. a := Unix.getenv( ADDRESSOF( "AOSCONFIG" ) );
  562. IF a = 0 THEN config := DefaultConfig
  563. ELSE
  564. REPEAT
  565. S.GET( a, c ); INC( a ); config[i] := c; INC( i )
  566. UNTIL c = 0X
  567. END
  568. END InitConfig;
  569. PROCEDURE UpdateTicks*;
  570. BEGIN
  571. ticks := SHORT( (GetTimer() - timer0) DIV (mhz * 1000) );
  572. END UpdateTicks;
  573. PROCEDURE InitThreads;
  574. VAR res: BOOLEAN;
  575. BEGIN
  576. res := thrInitialize( prioLow, prioHigh );
  577. IF ~res THEN
  578. Trace.StringLn( "Machine.InitThreads: no threads support in boot environment. teminating" );
  579. Unix.exit( 1 )
  580. END;
  581. IF Glue.debug # {} THEN
  582. Trace.String( "Threads initialized, priorities low, high: " );
  583. Trace.Int( prioLow, 0 ); Trace.String( ", " ); Trace.Int( prioHigh, 0 );
  584. Trace.Ln
  585. END
  586. END InitThreads;
  587. PROCEDURE CPUSpeed;
  588. VAR t0, t1: HUGEINT;
  589. BEGIN
  590. t0 := GetTimer(); thrSleep( 100 ); t1 := GetTimer();
  591. mhz := (t1 - t0) DIV 100000;
  592. IF Glue.debug # {} THEN
  593. Trace.String( "CPU speed: ~" ); Trace.Int( SHORT( mhz ), 0); Trace.String( " MHz" ); Trace.Ln
  594. END
  595. END CPUSpeed;
  596. PROCEDURE Log( c: CHAR );
  597. VAR ignore: LONGINT;
  598. BEGIN
  599. ignore := Unix.write( 1, ADDRESSOF( c ), 1 );
  600. ignore := Unix.write( logfile, ADDRESSOF( c ), 1 );
  601. END Log;
  602. PROCEDURE LogFileOnly( c: CHAR );
  603. VAR ignore: LONGINT;
  604. BEGIN
  605. ignore := Unix.write( logfile, ADDRESSOF( c ), 1 );
  606. END LogFileOnly;
  607. PROCEDURE InitLog;
  608. VAR name, cmd: ARRAY 32 OF CHAR; pid, i: LONGINT;
  609. BEGIN
  610. name := "AOS.xxxxx.Log";
  611. pid := Unix.getpid(); i := 8;
  612. REPEAT
  613. name[i] := CHR( pid MOD 10 + ORD( '0' ) ); DEC( i );
  614. pid := pid DIV 10;
  615. UNTIL i = 3;
  616. logfile := Unix.open( ADDRESSOF( name ), Unix.rdwr + Unix.creat + Unix.trunc, Unix.rwrwr );
  617. IF Unix.argc > 2 THEN
  618. Unix.GetArgval( "-x", cmd );
  619. IF cmd # "" THEN SilentLog; standaloneAppl := TRUE
  620. ELSE VerboseLog
  621. END
  622. ELSE
  623. VerboseLog
  624. END
  625. END InitLog;
  626. PROCEDURE SilentLog*;
  627. BEGIN
  628. Trace.Char := LogFileOnly
  629. END SilentLog;
  630. PROCEDURE VerboseLog*;
  631. BEGIN
  632. Trace.Char := Log
  633. END VerboseLog;
  634. PROCEDURE Append( VAR a: ARRAY OF CHAR; CONST this: ARRAY OF CHAR );
  635. VAR i, j: LONGINT;
  636. BEGIN
  637. i := 0; j := 0;
  638. WHILE a[i] # 0X DO INC( i ) END;
  639. WHILE (i < LEN( a ) - 1) & (this[j] # 0X) DO a[i] := this[j]; INC( i ); INC( j ) END;
  640. a[i] := 0X
  641. END Append;
  642. PROCEDURE Init;
  643. VAR vendor: Vendor; ver: LONGINT;
  644. BEGIN
  645. Unix.Dlsym( 0, "thrInitialize", ADDRESSOF( thrInitialize ) );
  646. Unix.Dlsym( 0, "mtxInit", ADDRESSOF( mtxInit ) );
  647. Unix.Dlsym( 0, "mtxDestroy", ADDRESSOF( mtxDestroy ) );
  648. Unix.Dlsym( 0, "mtxLock", ADDRESSOF( mtxLock ) );
  649. Unix.Dlsym( 0, "mtxUnlock", ADDRESSOF( mtxUnlock ) );
  650. Unix.Dlsym( 0, "conInit", ADDRESSOF( conInit ) );
  651. Unix.Dlsym( 0, "conDestroy", ADDRESSOF( conDestroy ) );
  652. Unix.Dlsym( 0, "conWait", ADDRESSOF( conWait ) );
  653. Unix.Dlsym( 0, "conSignal", ADDRESSOF( conSignal ) );
  654. Unix.Dlsym( 0, "thrSleep", ADDRESSOF( thrSleep ) );
  655. Unix.Dlsym( 0, "thrThis", ADDRESSOF( thrThis ) );
  656. standaloneAppl := FALSE;
  657. COPY( Unix.Version, version ); Append( version, Version );
  658. timer0 := GetTimer( ); ticks := 0;
  659. InitThreads;
  660. InitLocks;
  661. traceHeap := 1 IN Glue.debug;
  662. InitHeap;
  663. InitConfig;
  664. InitLog;
  665. CPUSpeed;
  666. IF CpuIdSupported() THEN
  667. CPUID( vendor, ver, features, features2 ); SetupSSE2Ext
  668. END;
  669. fcr := (FCR() - {0,2,3,10,11}) + {0..5,8,9}; (* default FCR RC=00B *)
  670. END Init;
  671. BEGIN
  672. Init
  673. END Machine.
  674. (*
  675. 03.03.1998 pjm First version
  676. 30.06.1999 pjm ProcessorID moved to AosProcessor
  677. *)
  678. (**
  679. Notes
  680. 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.
  681. 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.
  682. 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.
  683. Config strings:
  684. 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".
  685. *)