Generic.Unix.I386.Machine.Mod 30 KB

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