Windows.Machine.Mod 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  1. MODULE Machine;
  2. (** AUTHOR "pjm,fof"; PURPOSE "Bootstrapping, configuration and machine interface, adaption to windows fof"; *)
  3. (* red marked parts are WinAos specific *)
  4. IMPORT SYSTEM, Trace, Kernel32;
  5. CONST
  6. #IF AMD64 THEN
  7. Version = "WinA2 (64bit) ";
  8. #ELSIF I386 THEN
  9. Version = "WinAos (32bit) ";
  10. #ELSE
  11. -- UNDEFINED
  12. #END
  13. DefaultConfigFile = "aos.ini";
  14. DefaultGenericConfigFile = "aosg.ini";
  15. UserConfigFile = "myaos.ini";
  16. MaxCPU* = 8; (* dummy definition to make GC for both Win32 and I386 work *)
  17. #IF AMD64 THEN
  18. DefaultObjectFileExtension* = ".GofWw";
  19. #ELSIF I386 THEN
  20. DefaultObjectFileExtension* = ".Obw";
  21. #ELSE
  22. -- UNDEFINED
  23. #END
  24. (** bits in features variable *)
  25. MTTR* = 12; MMX* = 23;
  26. debug* = FALSE; (** display more debug output during booting *)
  27. CONST
  28. StaticBlockSize = 8*SIZEOF(ADDRESS); (* static heap block size *)
  29. (** standard lock levels (in order) *) (* also refer to Traps.Show *)
  30. TraceOutput* = 0; (* Trace output *)
  31. Memory* = 1; (* Virtual memory management, stack and page allocation *)
  32. Heaps* = 2; (* Storage allocation and Garbage collection *)
  33. Interrupts* = 3; (* Interrupt handling. *)
  34. Modules* = 4; (* Module list *)
  35. Objects* = 5; (* Ready queue *)
  36. Processors* = 6; (* Interprocessor interrupts *)
  37. KernelLog* = 7; (* Atomic output *)
  38. GC* = 8;
  39. MaxLocks = 9; (* { <= 32 } *)
  40. StrongChecks = FALSE;
  41. MemBlockSize = 32*1024*1024; (* must be multiple of StaticBlockSize *)
  42. NilVal = 0;
  43. Second* = 1000; (* frequency of ticks increments in Hz *)
  44. CONST
  45. (* error codes *)
  46. Ok* = 0;
  47. NilAdr* = -1; (* nil value for addresses (not same as pointer NIL value) *)
  48. IsCooperative* = FALSE;
  49. TYPE
  50. Vendor* = ARRAY 13 OF CHAR;
  51. IDMap* = ARRAY 16 OF SHORTINT;
  52. Range* = RECORD
  53. adr*, size*: LONGINT
  54. END;
  55. MemoryBlock* = POINTER {UNSAFE, UNTRACED} TO MemoryBlockDesc;
  56. MemoryBlockDesc* = RECORD
  57. next- : MemoryBlock;
  58. startAdr-: ADDRESS; (* sort key in linked list of memory blocks *)
  59. size-: SIZE;
  60. beginBlockAdr-, endBlockAdr-: ADDRESS
  61. END;
  62. (* dummy definition to make GC work for both I386 and Win32 - copied from BIOS.I386.Machine.Mod, but not really used *)
  63. Stack* = RECORD (** values are read-only *)
  64. low: ADDRESS; (* lowest virtual address that may be allocated for stack *)
  65. adr*: ADDRESS; (* lowest address on allocated stack *) (* exported for Objects only *)
  66. high*: ADDRESS; (* next virtual address after stack *) (* exported for Objects only *)
  67. END;
  68. VAR
  69. LastAddress: RECORD END;
  70. stackBottom-: ADDRESS;
  71. MMXSupport*: BOOLEAN;
  72. SSESupport*: BOOLEAN;
  73. SSE2Support*: BOOLEAN;
  74. SSE3Support-: BOOLEAN; (* PH 04/11*)
  75. SSSE3Support-: BOOLEAN;
  76. SSE41Support-: BOOLEAN;
  77. SSE42Support-: BOOLEAN;
  78. SSE5Support-: BOOLEAN;
  79. AVXSupport-: BOOLEAN;
  80. version*: ARRAY 64 OF CHAR; (** Aos version *)
  81. features*,features2*: SET; (** processor features *)
  82. fcr*: SET; (** default floating-point control register value (default rounding mode is towards -infinity, for ENTIER) *)
  83. mhz*: HUGEINT; (** clock rate of GetTimer() in MHz, or 0 if not known *)
  84. boottime-: HUGEINT; (** in timer units *)
  85. commandLine-: ARRAY 256 OF CHAR;
  86. hin, hout: Kernel32.HANDLE;
  87. VAR
  88. lock-: ARRAY MaxLocks OF CHAR; (* not implemented as SET because of shared access *)
  89. cs: ARRAY MaxLocks OF Kernel32.CriticalSection;
  90. defaultConfigFile, userConfigFile, traceName: ARRAY Kernel32.MaxPath OF CHAR;
  91. gcThreshold-: SIZE;
  92. memBlockHead-{UNTRACED}, memBlockTail-{UNTRACED}: MemoryBlock; (* head and tail of sorted list of memory blocks *)
  93. (** 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. *)
  94. PROCEDURE StrToInt*( VAR i: LONGINT; CONST s: ARRAY OF CHAR ): LONGINT;
  95. VAR vd, vh, sgn, d: LONGINT; hex: BOOLEAN;
  96. BEGIN
  97. vd := 0; vh := 0; hex := FALSE;
  98. IF s[i] = "-" THEN sgn := -1; INC( i ) ELSE sgn := 1 END;
  99. LOOP
  100. IF (s[i] >= "0") & (s[i] <= "9") THEN d := ORD( s[i] ) - ORD( "0" )
  101. ELSIF (CAP( s[i] ) >= "A") & (CAP( s[i] ) <= "F") THEN d := ORD( CAP( s[i] ) ) - ORD( "A" ) + 10; hex := TRUE
  102. ELSE EXIT
  103. END;
  104. vd := 10 * vd + d; vh := 16 * vh + d; INC( i )
  105. END;
  106. IF CAP( s[i] ) = "H" THEN hex := TRUE; INC( i ) END; (* optional H *)
  107. IF hex THEN vd := vh END;
  108. RETURN sgn * vd
  109. END StrToInt;
  110. (** -- Atomic operations -- *)
  111. (** Atomic INC(x). *)
  112. PROCEDURE -AtomicInc*(VAR x: LONGINT);
  113. CODE
  114. #IF AMD64 THEN
  115. POP RAX
  116. LOCK
  117. INC DWORD [RAX]
  118. #ELSIF I386 THEN
  119. POP EAX
  120. LOCK
  121. INC DWORD[EAX]
  122. #ELSE
  123. UNIMPLEMENTED
  124. #END
  125. END AtomicInc;
  126. (** Atomic DEC(x). *)
  127. PROCEDURE -AtomicDec*(VAR x: LONGINT);
  128. CODE
  129. #IF AMD64 THEN
  130. POP RAX
  131. LOCK
  132. DEC DWORD [RAX]
  133. #ELSIF I386 THEN
  134. POP EAX
  135. LOCK
  136. DEC DWORD[EAX]
  137. #ELSE
  138. UNIMPLEMENTED
  139. #END
  140. END AtomicDec;
  141. (** Atomic EXCL. *)
  142. PROCEDURE AtomicExcl* (VAR s: SET; bit: LONGINT);
  143. CODE
  144. #IF AMD64 THEN
  145. MOV EAX, [RBP + bit]
  146. MOV RBX, [RBP + s]
  147. LOCK
  148. BTR [RBX], EAX
  149. #ELSIF I386 THEN
  150. MOV EAX, [EBP + bit]
  151. MOV EBX, [EBP + s]
  152. LOCK
  153. BTR [EBX], EAX
  154. #ELSE
  155. UNIMPLEMENTED
  156. #END
  157. END AtomicExcl;
  158. (** Atomic INC(x, y). *)
  159. PROCEDURE -AtomicAdd*(VAR x: LONGINT; y: LONGINT);
  160. CODE
  161. #IF AMD64 THEN
  162. POP EBX
  163. POP RAX
  164. LOCK
  165. ADD DWORD [RAX], EBX
  166. #ELSIF I386 THEN
  167. POP EBX
  168. POP EAX
  169. LOCK
  170. ADD DWORD[EAX], EBX
  171. #ELSE
  172. UNIMPLEMENTED
  173. #END
  174. END AtomicAdd;
  175. (** Atomic test-and-set. Set x = TRUE and return old value of x. *)
  176. PROCEDURE -AtomicTestSet*(VAR x: BOOLEAN): BOOLEAN;
  177. CODE
  178. #IF AMD64 THEN
  179. POP RBX
  180. MOV AL, 1
  181. XCHG [RBX], AL
  182. #ELSIF I386 THEN
  183. POP EBX
  184. MOV AL, 1
  185. XCHG [EBX], AL
  186. #ELSE
  187. UNIMPLEMENTED
  188. #END
  189. END AtomicTestSet;
  190. (* Atomic compare-and-swap. Set x = new if x = old and return old value of x *)
  191. PROCEDURE -AtomicCAS* (VAR x: LONGINT; old, new: LONGINT): LONGINT;
  192. CODE
  193. #IF AMD64 THEN
  194. POP EBX ; new
  195. POP EAX ; old
  196. POP RCX ; address of x
  197. LOCK CMPXCHG [RCX], EBX ; atomicly compare x with old and set it to new if equal
  198. #ELSIF I386 THEN
  199. POP EBX ; new
  200. POP EAX ; old
  201. POP ECX ; address of x
  202. DB 0F0X, 00FX, 0B1X, 019X ; LOCK CMPXCHG [ECX], EBX; atomicly compare x with old and set it to new if equal
  203. #ELSE
  204. UNIMPLEMENTED
  205. #END
  206. END AtomicCAS;
  207. (** This procedure should be called in all spin loops as a hint to the processor (e.g. Pentium 4). *)
  208. PROCEDURE -SpinHint*;
  209. CODE
  210. PAUSE
  211. END SpinHint;
  212. (** -- Miscellaneous -- *)
  213. (* Return current instruction pointer *)
  214. PROCEDURE CurrentPC* (): ADDRESS;
  215. CODE
  216. #IF AMD64 THEN
  217. MOV RAX, [RBP + 8]
  218. #ELSIF I386 THEN
  219. MOV EAX, [EBP+4]
  220. #ELSE
  221. UNIMPLEMENTED
  222. #END
  223. END CurrentPC;
  224. (** Fill "size" bytes at "destAdr" with "filler". "size" must be multiple of 4. *)
  225. PROCEDURE Fill32* (destAdr: ADDRESS; size: SIZE; filler: LONGINT);
  226. CODE
  227. #IF AMD64 THEN
  228. MOV RDI, [RBP + destAdr]
  229. MOV RCX, [RBP + size]
  230. MOV EAX, [RBP + filler]
  231. TEST RCX, 3
  232. JZ ok
  233. PUSH 8 ; ASSERT failure
  234. INT 3
  235. ok:
  236. SHR RCX, 2
  237. CLD
  238. REP STOSD
  239. #ELSIF I386 THEN
  240. MOV EDI, [EBP+destAdr]
  241. MOV ECX, [EBP+size]
  242. MOV EAX, [EBP+filler]
  243. TEST ECX, 3
  244. JZ ok
  245. PUSH 8 ; ASSERT failure
  246. INT 3
  247. ok:
  248. SHR ECX, 2
  249. CLD
  250. REP STOSD
  251. #ELSE
  252. UNIMPLEMENTED
  253. #END
  254. END Fill32;
  255. (** -- Processor initialization -- *)
  256. PROCEDURE -SetFCR( s: SET );
  257. CODE
  258. #IF AMD64 THEN
  259. FLDCW [RSP] ; parameter s
  260. POP EAX
  261. #ELSIF I386 THEN
  262. FLDCW [ESP] ; parameter s
  263. POP EAX
  264. #ELSE
  265. UNIMPLEMENTED
  266. #END
  267. END SetFCR;
  268. PROCEDURE -FCR( ): SET;
  269. CODE
  270. #IF AMD64 THEN
  271. PUSH 0
  272. FNSTCW [RSP]
  273. FWAIT
  274. POP EAX
  275. #ELSIF I386 THEN
  276. PUSH 0
  277. FNSTCW [ESP]
  278. FWAIT
  279. POP EAX
  280. #ELSE
  281. UNIMPLEMENTED
  282. #END
  283. END FCR;
  284. PROCEDURE -InitFPU;
  285. CODE
  286. FNINIT
  287. END InitFPU;
  288. (** Setup FPU control word of current processor. *)
  289. PROCEDURE SetupFPU*;
  290. BEGIN
  291. InitFPU; SetFCR( fcr )
  292. END SetupFPU;
  293. (** CPU identification. *)
  294. PROCEDURE CPUID*( VAR vendor: Vendor; VAR version: LONGINT; VAR features1,features2: SET );
  295. CODE
  296. #IF AMD64 THEN
  297. MOV EAX, 0
  298. CPUID
  299. CMP EAX, 0
  300. JNE ok
  301. MOV RSI, [RBP+vendor]
  302. MOV [RSI], AL ; AL = 0
  303. MOV RSI, [RBP+version]
  304. MOV [RSI], EAX ; EAX = 0
  305. MOV RSI, [RBP+features1]
  306. MOV [RSI], EAX
  307. MOV RSI, [RBP+features2]
  308. MOV [RSI], EAX
  309. JMP end
  310. ok:
  311. MOV RSI, [RBP+vendor]
  312. MOV [RSI], EBX
  313. MOV [RSI+4], EDX
  314. MOV [RSI+8], ECX
  315. MOV BYTE [RSI+12], 0
  316. MOV EAX, 1
  317. CPUID
  318. MOV RSI, [RBP+version]
  319. MOV [RSI], EAX
  320. MOV RSI, [RBP+features1]
  321. MOV [RSI], EDX
  322. MOV RSI, [RBP+features2]
  323. MOV [RSI], ECX
  324. end:
  325. #ELSIF I386 THEN
  326. MOV EAX, 0
  327. CPUID
  328. CMP EAX, 0
  329. JNE ok
  330. MOV ESI, [EBP+vendor]
  331. MOV [ESI], AL ; AL = 0
  332. MOV ESI, [EBP+version]
  333. MOV [ESI], EAX ; EAX = 0
  334. MOV ESI, [EBP+features1]
  335. MOV [ESI], EAX
  336. MOV ESI, [EBP+features2]
  337. MOV [ESI], EAX
  338. JMP end
  339. ok:
  340. MOV ESI, [EBP+vendor]
  341. MOV [ESI], EBX
  342. MOV [ESI+4], EDX
  343. MOV [ESI+8], ECX
  344. MOV BYTE [ESI+12], 0
  345. MOV EAX, 1
  346. CPUID
  347. MOV ESI, [EBP+version]
  348. MOV [ESI], EAX
  349. MOV ESI, [EBP+features1]
  350. MOV [ESI], EDX
  351. MOV ESI, [EBP+features2]
  352. MOV [ESI], ECX
  353. end:
  354. #ELSE
  355. UNIMPLEMENTED
  356. #END
  357. END CPUID;
  358. PROCEDURE GetConfig*( CONST name: ARRAY OF CHAR; VAR val: ARRAY OF CHAR );
  359. CONST ConfigKey = "Configuration";
  360. BEGIN
  361. COPY ("", val);
  362. IF Kernel32.GetPrivateProfileString (ConfigKey, name, "", val, LEN (val), userConfigFile) # 0 THEN
  363. ELSIF Kernel32.GetPrivateProfileString (ConfigKey, name, "", val, LEN (val), defaultConfigFile) # 0 THEN
  364. END;
  365. IF (name = "ObjectFileExtension") & (val = "") THEN
  366. #IF AMD64 THEN
  367. IF Kernel32.Generic THEN
  368. val := ".GofWw";
  369. ELSE
  370. val := ".Obww"
  371. END;
  372. #ELSIF I386 THEN
  373. IF Kernel32.Generic THEN
  374. val := ".GofW";
  375. ELSE
  376. val := ".Obw"
  377. END;
  378. #ELSE
  379. UNIMPLEMENTED
  380. #END
  381. END;
  382. END GetConfig;
  383. PROCEDURE Shutdown*( restart: BOOLEAN );
  384. BEGIN
  385. RemoveTraceFile;
  386. Kernel32.Shutdown( 0 ); (* calls the finalizer of Heaps *)
  387. END Shutdown;
  388. (* Dan: from new Machine *)
  389. PROCEDURE -GetTimer*(): HUGEINT;
  390. CODE {SYSTEM.Pentium}
  391. RDTSC ; set EDX:EAX
  392. END GetTimer;
  393. (* Dan: mono CPU PCs *)
  394. PROCEDURE ID*(): LONGINT;
  395. BEGIN
  396. RETURN 0
  397. END ID;
  398. (**
  399. * Flush Data Cache for the specified virtual address range. If len is negative, flushes the whole cache.
  400. * This is used on some architecture to interact with DMA hardware (e.g. Ethernet and USB. It can be
  401. * left empty on Intel architecture.
  402. *)
  403. PROCEDURE FlushDCacheRange * (adr: ADDRESS; len: LONGINT);
  404. END FlushDCacheRange;
  405. (**
  406. * Invalidate Data Cache for the specified virtual address range. If len is negative, flushes the whole cache.
  407. * This is used on some architecture to interact with DMA hardware (e.g. Ethernet and USB. It can be
  408. * left empty on Intel architecture.
  409. *)
  410. PROCEDURE InvalidateDCacheRange * (adr: ADDRESS; len: LONGINT);
  411. END InvalidateDCacheRange;
  412. (**
  413. * Invalidate Instruction Cache for the specified virtual address range. If len is negative, flushes the whole cache.
  414. * This is used on some architecture to interact with DMA hardware (e.g. Ethernet and USB. It can be
  415. * left empty on Intel architecture.
  416. *)
  417. PROCEDURE InvalidateICacheRange * (adr: ADDRESS; len: LONGINT);
  418. END InvalidateICacheRange;
  419. (* setup MMX, SSE and SSE2..SSE5 and AVX extension *)
  420. PROCEDURE SetupSSE2Ext;
  421. CONST
  422. MMXFlag=23;(*IN features from EBX*)
  423. FXSRFlag = 24;
  424. SSEFlag = 25;
  425. SSE2Flag = 26;
  426. SSE3Flag = 0; (*IN features2 from ECX*) (*PH 04/11*)
  427. SSSE3Flag =9;
  428. SSE41Flag =19;
  429. SSE42Flag =20;
  430. SSE5Flag = 11;
  431. AVXFlag = 28;
  432. BEGIN
  433. MMXSupport := MMXFlag IN features;
  434. SSESupport := SSEFlag IN features;
  435. SSE2Support := SSESupport & (SSE2Flag IN features);
  436. SSE3Support := SSE2Support & (SSE3Flag IN features2);
  437. SSSE3Support := SSE3Support & (SSSE3Flag IN features2); (* PH 04/11*)
  438. SSE41Support := SSE3Support & (SSE41Flag IN features2);
  439. SSE42Support := SSE3Support & (SSE42Flag IN features2);
  440. SSE5Support := SSE3Support & (SSE5Flag IN features2);
  441. AVXSupport := SSE3Support & (AVXFlag IN features2);
  442. IF SSESupport & (FXSRFlag IN features) THEN
  443. (* InitSSE(); *) (*! not privileged mode in Windows not allowed *)
  444. END;
  445. END SetupSSE2Ext;
  446. PROCEDURE ReadCommandLine(VAR commandLine: ARRAY OF CHAR);
  447. VAR adr: ADDRESS; i: LONGINT; ch: CHAR;
  448. BEGIN
  449. adr := Kernel32.GetCommandLine();
  450. SYSTEM.GET(adr,ch);
  451. i := 0;
  452. WHILE (i<LEN(commandLine)-1) & (ch # 0X) DO
  453. commandLine[i] := ch;
  454. INC(adr); INC(i);
  455. SYSTEM.GET(adr,ch);
  456. END;
  457. END ReadCommandLine;
  458. PROCEDURE ParseLine(VAR c: ARRAY OF CHAR; VAR iniFile: ARRAY OF CHAR);
  459. VAR i: LONGINT;
  460. PROCEDURE SkipSpaces;
  461. BEGIN
  462. WHILE (c[i] <= " ") & (c[i] # 0X) DO INC(i) END;
  463. END SkipSpaces;
  464. PROCEDURE SkipName;
  465. BEGIN
  466. WHILE (c[i] > " ") DO INC(i) END;
  467. END SkipName;
  468. PROCEDURE CheckName(CONST name: ARRAY OF CHAR): BOOLEAN;
  469. VAR j: LONGINT;
  470. BEGIN
  471. j := 0;
  472. WHILE (c[i] = name[j]) & (c[i] # 0X) & (name[j] # 0X) DO
  473. INC(i); INC(j);
  474. END;
  475. RETURN (name[j] = 0X);
  476. END CheckName;
  477. PROCEDURE ReadName(VAR name: ARRAY OF CHAR);
  478. VAR j: LONGINT;
  479. BEGIN
  480. SkipSpaces;
  481. j := 0;
  482. WHILE (c[i] > " ") & (j < LEN(name)-1) DO
  483. name[j] := c[i];
  484. INC(i); INC(j);
  485. END;
  486. name[j] := 0X;
  487. END ReadName;
  488. BEGIN
  489. c[LEN(c)-1] := 0X;
  490. i := 0;
  491. SkipSpaces;
  492. SkipName;
  493. SkipSpaces;
  494. IF c[i] = "-" THEN (* option *)
  495. INC(i);
  496. IF CheckName("ini") THEN SkipSpaces; ReadName(iniFile) END;
  497. END;
  498. END ParseLine;
  499. PROCEDURE TraceChar(c: CHAR);
  500. VAR len: LONGINT; b: Kernel32.BOOL;
  501. BEGIN
  502. len := 1;
  503. b := Kernel32.WriteFile(hout,c,len,len,NIL);
  504. END TraceChar;
  505. PROCEDURE SetTraceFile*;
  506. BEGIN
  507. traceName := "SystemTrace.txt";
  508. SetupTraceName(traceName);
  509. Trace.String("trace -> file "); Trace.String(traceName); Trace.Ln;
  510. hout := Kernel32.CreateFile(traceName, {Kernel32.GenericWrite}, {Kernel32.FileShareRead}, NIL, Kernel32.CreateAlways, {Kernel32.FileAttributeNormal}, Kernel32.NULL);
  511. IGNORE Kernel32.GetFullPathName(traceName, LEN(traceName),traceName, NIL);
  512. Trace.Char := TraceChar;
  513. Trace.String(version); Trace.Ln;
  514. END SetTraceFile;
  515. PROCEDURE SetTraceConsole*;
  516. VAR res: WORD;
  517. BEGIN
  518. Trace.String("trace -> console"); Trace.Ln;
  519. res := Kernel32.AllocConsole ();
  520. hin := Kernel32.GetStdHandle (Kernel32.STDInput);
  521. hout := Kernel32.GetStdHandle (Kernel32.STDOutput);
  522. Trace.Char := TraceChar;
  523. Trace.String(version); Trace.Ln;
  524. END SetTraceConsole;
  525. PROCEDURE SetupTraceName(VAR traceName: ARRAY OF CHAR);
  526. VAR
  527. ext: ARRAY 256 OF CHAR;
  528. extPos,i,j: LONGINT;
  529. systemTime: Kernel32.SystemTime;
  530. ch: CHAR;
  531. PROCEDURE AppendDecimals(int: LONGINT; from, to: LONGINT);
  532. BEGIN
  533. WHILE to >= from DO
  534. traceName[i] := CHR(ORD("0")+ int DIV to MOD 10); INC(i);
  535. to := to DIV 10;
  536. END;
  537. END AppendDecimals;
  538. BEGIN
  539. Kernel32.GetLocalTime(systemTime);
  540. extPos := 0;
  541. REPEAT
  542. ch := traceName[i];
  543. IF ch = "." THEN j := 0; extPos := i END;
  544. ext[j] := ch;
  545. INC(j); INC(i);
  546. UNTIL ch = 0X;
  547. IF extPos > 0 THEN i := extPos END;
  548. ext[j] := 0X;
  549. AppendDecimals(systemTime.wYear,1,1000);
  550. AppendDecimals(systemTime.wMonth,1,10);
  551. AppendDecimals(systemTime.wDay,1,10);
  552. traceName[i] := "_"; INC(i);
  553. AppendDecimals(systemTime.wHour,1,10);
  554. AppendDecimals(systemTime.wMinute,1,10);
  555. AppendDecimals(systemTime.wSecond,1,10);
  556. traceName[i] := "_"; INC(i);
  557. AppendDecimals(systemTime.wMilliseconds,10,100);
  558. j := 0;
  559. REPEAT
  560. ch := ext[j];
  561. traceName[i] := ch;
  562. INC(i); INC(j);
  563. UNTIL ch = 0X;
  564. END SetupTraceName;
  565. PROCEDURE RemoveTraceFile;
  566. VAR res: WORD;
  567. BEGIN
  568. IF (traceName # "") & (traceName # "Console") THEN
  569. Trace.String("removing "); Trace.String(traceName); Trace.Ln;
  570. (*Trace.Char := LogChar;*)
  571. res := Kernel32.CloseHandle(hout);
  572. IF res = 0 THEN
  573. res := Kernel32.GetLastError();
  574. Trace.String("could not close "); Trace.String("; res = "); Trace.Int(res,1); Trace.Ln;
  575. END;
  576. res := Kernel32.DeleteFile(traceName);
  577. IF res = 0 THEN
  578. res := Kernel32.GetLastError();
  579. Trace.String("could not delete "); Trace.String(traceName); Trace.String("; res = "); Trace.Int(res,1); Trace.Ln;
  580. END;
  581. END;
  582. END RemoveTraceFile;
  583. PROCEDURE ToExecutablePath(CONST name: ARRAY OF CHAR; VAR fullName: ARRAY OF CHAR);
  584. VAR i,j: LONGINT;
  585. BEGIN
  586. IGNORE Kernel32.GetModuleFileName(Kernel32.hInstance, fullName, LEN( fullName ) );
  587. j := -1; i := 0;
  588. WHILE fullName[i] # 0X DO
  589. IF fullName[i] = '\' THEN j := i END;
  590. INC( i )
  591. END;
  592. i := 0; INC(j);
  593. WHILE name[i] # 0X DO
  594. fullName[j] := name[i]; INC(i); INC(j);
  595. END;
  596. fullName[j] := 0X;
  597. END ToExecutablePath;
  598. PROCEDURE Append(VAR s: ARRAY OF CHAR; CONST t: ARRAY OF CHAR);
  599. VAR i,j: LONGINT;
  600. BEGIN
  601. i := 0;
  602. WHILE(s[i] # 0X) DO INC(i) END;
  603. j := 0;
  604. WHILE (t[j] # 0X) DO
  605. s[i] := t[j];
  606. INC(i); INC(j);
  607. END;
  608. s[i] := 0X;
  609. END Append;
  610. PROCEDURE Init*;
  611. VAR vendor: Vendor; ver: LONGINT; hfile: Kernel32.HANDLE;
  612. BEGIN
  613. Kernel32.Init;
  614. (* trace[1] := 0X; Trace.Char := LogChar; Trace.Color := TraceColor; *)
  615. InitLocks();
  616. boottime:=GetTimer();
  617. COPY( Version, version );
  618. Append(version, SYSTEM.Date);
  619. CPUID(vendor, ver, features,features2); SetupSSE2Ext;
  620. fcr := (FCR() - {0,2,3,10,11}) + {0..5,8,9}; (* default FCR RC=00B *)
  621. ReadCommandLine(commandLine);
  622. IF Kernel32.Generic THEN
  623. ToExecutablePath(DefaultGenericConfigFile, defaultConfigFile);
  624. ELSE
  625. ToExecutablePath(DefaultConfigFile, defaultConfigFile);
  626. END;
  627. COPY(UserConfigFile, userConfigFile);
  628. hfile := Kernel32.CreateFile( userConfigFile, {Kernel32.GenericRead}, {Kernel32.FileShareRead}, NIL , Kernel32.OpenExisting, {Kernel32.FileAttributeNormal}, 0 );
  629. IF hfile = Kernel32.InvalidHandleValue THEN
  630. ToExecutablePath(UserConfigFile, userConfigFile);
  631. ELSE
  632. IGNORE Kernel32.CloseHandle(hfile)
  633. END;
  634. (*
  635. (* ever used ? *)
  636. ParseLine(commandLine, userConfigFile);
  637. userConfigFile[Kernel32.GetFullPathName (userConfigFile, Kernel32.MaxPath, userConfigFile, 0)] := 0X;
  638. traceName[0] := 0X;
  639. GetConfig("Trace",traceName);
  640. Trace.String("traceName "); Trace.String(traceName); Trace.Ln;
  641. IF traceName = "File" THEN SetTraceFile;
  642. ELSIF traceName = "Console" THEN SetTraceConsole
  643. (* else trace is on kernel log *)
  644. END;
  645. Trace.String("Machine init done"); Trace.Ln;
  646. *)
  647. END Init;
  648. PROCEDURE {INITIAL, NOPAF} Start*;
  649. BEGIN
  650. stackBottom := SYSTEM.GetStackPointer();
  651. Init; (* cannot allocate variables in here *)
  652. END Start;
  653. (* Initialize locks. *)
  654. PROCEDURE InitLocks;
  655. VAR i: LONGINT;
  656. BEGIN
  657. i := 0;
  658. WHILE i < MaxLocks DO Kernel32.InitializeCriticalSection( cs[i] ); lock[i] := "N"; INC( i ) END;
  659. END InitLocks;
  660. PROCEDURE CleanupLocks*;
  661. VAR i: LONGINT;
  662. BEGIN
  663. i := 0;
  664. WHILE i < MaxLocks DO Kernel32.DeleteCriticalSection( cs[i] ); INC( i ) END;
  665. END CleanupLocks;
  666. (** Acquire a spin-lock. *)
  667. PROCEDURE Acquire*( level: LONGINT ); (* non reentrant lock (non reentrance "ensured" by ASSERT statement ), CriticalSections are reentrant *)
  668. BEGIN
  669. Kernel32.EnterCriticalSection( cs[level] );
  670. IF StrongChecks THEN
  671. ASSERT ( lock[level] = "N", 1001 );
  672. ELSIF lock[level] # "N" THEN
  673. Trace.String("warning: reentered non-reentrant lock"); Trace.Ln;
  674. END;
  675. lock[level] := "Y";
  676. END Acquire;
  677. (** Release a spin-lock. *)
  678. PROCEDURE Release*( level: LONGINT ); (* release lock *)
  679. BEGIN
  680. IF StrongChecks THEN
  681. ASSERT ( lock[level] ="Y", 1002 );
  682. ELSIF lock[level] # "Y" THEN
  683. Trace.String("warning: reentered non-reentrant lock"); Trace.Ln;
  684. END;
  685. lock[level] := "N";
  686. Kernel32.LeaveCriticalSection( cs[level] )
  687. END Release;
  688. (* added by Alexey *)
  689. PROCEDURE GetMemStatus(VAR stat: Kernel32.MemoryStatusEx): BOOLEAN;
  690. BEGIN
  691. stat.dwLength := 64;
  692. IF Kernel32.GlobalMemoryStatusEx(stat) = 1 THEN
  693. RETURN TRUE;
  694. ELSE
  695. RETURN FALSE;
  696. END;
  697. END GetMemStatus;
  698. (** dummy procedure to make GC work for both I386 and Win32 *)
  699. PROCEDURE GetKernelStacks*(VAR stack: ARRAY OF Stack);
  700. VAR i: LONGINT;
  701. BEGIN
  702. FOR i := 0 TO MaxCPU-1 DO
  703. stack[i].adr := NilVal;
  704. stack[i].high := NilVal
  705. END
  706. END GetKernelStacks;
  707. (* Set machine-dependent parameter gcThreshold *)
  708. PROCEDURE SetGCParams*;
  709. BEGIN
  710. gcThreshold := 10*1024*1024; (* 10 MB *)
  711. END SetGCParams;
  712. (** Get first memory block and first free address, the first free address is identical to memBlockHead.endBlockAdr *)
  713. PROCEDURE GetStaticHeap*(VAR beginBlockAdr, endBlockAdr, freeBlockAdr: ADDRESS);
  714. BEGIN
  715. beginBlockAdr := NIL; endBlockAdr := NIL; freeBlockAdr := NIL;
  716. END GetStaticHeap;
  717. (* returns if an address is a currently allocated heap address *)
  718. PROCEDURE ValidHeapAddress*(p: ADDRESS): BOOLEAN;
  719. BEGIN
  720. RETURN (p >= memBlockHead.beginBlockAdr) & (p <= memBlockTail.endBlockAdr)
  721. OR (p>=ADDRESS OF Kernel32.EntryPoint) & (p<=ADDRESSOF(LastAddress))
  722. END ValidHeapAddress;
  723. PROCEDURE GetFreeK* (VAR total, lowFree, highFree: SIZE);
  724. VAR
  725. stat: Kernel32.MemoryStatusEx;
  726. BEGIN
  727. total := MAX(LONGINT); lowFree := 0; highFree := total;
  728. (*<< added by Alexey *)
  729. IF GetMemStatus(stat) THEN
  730. total := SHORT(stat.ullTotalVirtual DIV 1024);
  731. lowFree := 0;
  732. highFree := SHORT(stat.ullAvailVirtual DIV 1024);
  733. END;
  734. (* added by Alexey >>*)
  735. END GetFreeK;
  736. (* ug *)
  737. PROCEDURE TraceMemBlocks*;
  738. VAR memBlock {UNTRACED}: MemoryBlock; i : LONGINT;
  739. BEGIN
  740. memBlock := memBlockHead;
  741. i := 0;
  742. WHILE memBlock # NIL DO
  743. Trace.String("block "); Trace.Int(i, 0); Trace.String(": startAdr = "); Trace.Hex(memBlock.startAdr, 0);
  744. Trace.String(" size = "); Trace.Hex(memBlock.size, 0);
  745. Trace.String(" beginBlockAdr = "); Trace.Hex(memBlock.beginBlockAdr, 0);
  746. Trace.String(" endBlockAdr = "); Trace.Hex(memBlock.endBlockAdr, 0); Trace.Ln;
  747. memBlock := memBlock.next;
  748. INC(i)
  749. END
  750. END TraceMemBlocks;
  751. (* insert given memory block in sorted list of memory blocks, sort key is startAdr field - called during GC *)
  752. PROCEDURE InsertMemoryBlock(memBlock: MemoryBlock);
  753. VAR cur {UNTRACED}, prev {UNTRACED}: MemoryBlock;
  754. BEGIN
  755. cur := memBlockHead;
  756. prev := NIL;
  757. WHILE (cur # NIL) & (cur.startAdr < memBlock.startAdr) DO
  758. prev := cur;
  759. cur := cur.next
  760. END;
  761. IF prev = NIL THEN (* insert at head of list *)
  762. memBlock.next := memBlockHead;
  763. memBlockHead := memBlock
  764. ELSE (* insert in middle or at end of list *)
  765. memBlock.next := cur;
  766. prev.next := memBlock;
  767. END;
  768. IF cur = NIL THEN
  769. memBlockTail := memBlock
  770. END
  771. END InsertMemoryBlock;
  772. (* expand heap by allocating a new memory block *)
  773. PROCEDURE ExpandHeap*( dummy: LONGINT; size: SIZE; VAR memoryBlock: MemoryBlock; VAR beginBlockAdr, endBlockAdr: ADDRESS );
  774. VAR mBlock: MemoryBlock; alloc: SIZE; adr,initVal: ADDRESS; continue: BOOLEAN;
  775. BEGIN
  776. ASSERT(SIZEOF(MemoryBlockDesc) <= StaticBlockSize); (* make sure MemoryBlock contents fits into one StaticBlock *)
  777. alloc := size + StaticBlockSize;
  778. IF alloc < MemBlockSize THEN alloc := MemBlockSize END;
  779. INC( alloc, (-alloc) MOD StaticBlockSize );
  780. IF memBlockTail # NIL THEN
  781. initVal := memBlockTail.startAdr + memBlockTail.size;
  782. ELSE
  783. initVal := NIL
  784. END;
  785. adr := Kernel32.VirtualAlloc(initVal, alloc, {Kernel32.MEMCommit, Kernel32.MEMReserve}, {Kernel32.PageExecuteReadWrite});
  786. IF adr = NilVal THEN (* allocation failed *)
  787. adr := Kernel32.VirtualAlloc(NilVal, alloc, {Kernel32.MEMCommit}, {Kernel32.PageExecuteReadWrite});
  788. END;
  789. continue := adr = initVal;
  790. ASSERT(adr MOD StaticBlockSize = 0); (* is fulfilled because VirtualAlloc is on page granularity *)
  791. IF adr # 0 THEN
  792. IF continue THEN
  793. memoryBlock := memBlockTail;
  794. memoryBlock.size := memoryBlock.size + alloc;
  795. beginBlockAdr := memBlockTail.endBlockAdr;
  796. endBlockAdr := beginBlockAdr;
  797. INC(endBlockAdr, alloc);
  798. ELSE
  799. mBlock := adr;
  800. mBlock.next := NIL;
  801. mBlock.startAdr := adr;
  802. mBlock.size := alloc;
  803. beginBlockAdr := adr + StaticBlockSize;
  804. endBlockAdr := beginBlockAdr + alloc - StaticBlockSize;
  805. mBlock.beginBlockAdr := beginBlockAdr;
  806. mBlock.endBlockAdr := beginBlockAdr; (* block is still empty -- Heaps module will set the upper bound *)
  807. InsertMemoryBlock( mBlock );
  808. memoryBlock := mBlock;
  809. END;
  810. ELSE
  811. beginBlockAdr := 0; endBlockAdr := 0; memoryBlock := NIL;
  812. END;
  813. END ExpandHeap;
  814. (* Set memory block end address *)
  815. PROCEDURE SetMemoryBlockEndAddress*(memBlock: MemoryBlock; endBlockAdr: ADDRESS);
  816. BEGIN
  817. ASSERT(endBlockAdr >= memBlock.beginBlockAdr);
  818. memBlock.endBlockAdr := endBlockAdr
  819. END SetMemoryBlockEndAddress;
  820. (* Free unused memory block - called during GC *)
  821. PROCEDURE FreeMemBlock*(memBlock: MemoryBlock);
  822. VAR cur {UNTRACED}, prev {UNTRACED}: MemoryBlock;
  823. startAdr: ADDRESS;
  824. BEGIN
  825. cur := memBlockHead;
  826. prev := NIL;
  827. WHILE (cur # NIL) & (cur # memBlock) DO
  828. prev := cur;
  829. cur := cur.next
  830. END;
  831. IF cur = memBlock THEN
  832. IF prev = NIL THEN
  833. memBlockHead := cur.next;
  834. ELSE
  835. prev.next := cur.next;
  836. IF prev.next = NIL THEN
  837. memBlockTail := prev
  838. END
  839. END;
  840. memBlock.next := NIL;
  841. startAdr := memBlock.startAdr; (* this value must be cached for the second call of Kernel32.VirtualFree *)
  842. IGNORE Kernel32.VirtualFree(SYSTEM.VAL(LONGINT, memBlock.startAdr), memBlock.size, {Kernel32.MEMDecommit});
  843. IGNORE Kernel32.VirtualFree(SYSTEM.VAL(LONGINT, startAdr ), 0, {Kernel32.MEMRelease});
  844. ELSE
  845. HALT(535) (* error in memory block management *)
  846. END;
  847. END FreeMemBlock;
  848. PROCEDURE PhysicalAdr*(adr: ADDRESS; size: SIZE): ADDRESS;
  849. END PhysicalAdr;
  850. (* function returning the number of processors that are available to Aos *)
  851. PROCEDURE NumberOfProcessors*( ): LONGINT;
  852. VAR info: Kernel32.SystemInfo;
  853. BEGIN
  854. Kernel32.GetSystemInfo( info );
  855. RETURN info.dwNumberOfProcessors
  856. END NumberOfProcessors;
  857. (* function for changing byte order *)
  858. PROCEDURE ChangeByteOrder* (n: LONGINT): LONGINT;
  859. CODE
  860. #IF AMD64 THEN
  861. MOV EAX, [RBP+n] ; load n in eax
  862. BSWAP EAX ; swap byte order
  863. #ELSIF I386 THEN
  864. MOV EAX, [EBP+n] ; load n in eax
  865. BSWAP EAX
  866. #ELSE
  867. UNIMPLEMENTED
  868. #END
  869. END ChangeByteOrder;
  870. PROCEDURE Portin8*(port: LONGINT; VAR val: CHAR);
  871. END Portin8;
  872. PROCEDURE Portin16*(port: LONGINT; VAR val: INTEGER);
  873. END Portin16;
  874. PROCEDURE Portin32*(port: LONGINT; VAR val: LONGINT);
  875. END Portin32;
  876. PROCEDURE Portout8*(port: LONGINT; val: CHAR);
  877. END Portout8;
  878. PROCEDURE Portout16*(port: LONGINT; val: INTEGER);
  879. END Portout16;
  880. PROCEDURE Portout32*(port: LONGINT; val: LONGINT);
  881. END Portout32;
  882. BEGIN
  883. IF ~Kernel32.Generic THEN
  884. Init
  885. END;
  886. Trace.String(version); Trace.Ln;
  887. END Machine.