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