Windows.Machine.Mod 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065
  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. (* Return current frame pointer *)
  225. PROCEDURE -CurrentBP* (): ADDRESS;
  226. CODE
  227. #IF AMD64 THEN
  228. MOV RAX, RBP
  229. #ELSIF I386 THEN
  230. MOV EAX, EBP
  231. #ELSE
  232. UNIMPLEMENTED
  233. #END
  234. END CurrentBP;
  235. (* Set current frame pointer *)
  236. PROCEDURE -SetBP* (bp: ADDRESS);
  237. CODE
  238. #IF AMD64 THEN
  239. POP RBP
  240. #ELSIF I386 THEN
  241. POP EBP
  242. #ELSE
  243. UNIMPLEMENTED
  244. #END
  245. END SetBP;
  246. (* Return current stack pointer *)
  247. PROCEDURE -CurrentSP* (): ADDRESS;
  248. CODE
  249. #IF AMD64 THEN
  250. MOV RAX, RSP
  251. #ELSIF I386 THEN
  252. MOV EAX, ESP
  253. #ELSE
  254. UNIMPLEMENTED
  255. #END
  256. END CurrentSP;
  257. (* Set current stack pointer *)
  258. PROCEDURE -SetSP* (sp: ADDRESS);
  259. CODE {SYSTEM.AMD64}
  260. #IF AMD64 THEN
  261. POP RSP
  262. #ELSIF I386 THEN
  263. POP ESP
  264. #ELSE
  265. UNIMPLEMENTED
  266. #END
  267. END SetSP;
  268. (** Fill "size" bytes at "destAdr" with "filler". "size" must be multiple of 4. *)
  269. PROCEDURE Fill32* (destAdr: ADDRESS; size: SIZE; filler: LONGINT);
  270. CODE
  271. #IF AMD64 THEN
  272. MOV RDI, [RBP + destAdr]
  273. MOV RCX, [RBP + size]
  274. MOV EAX, [RBP + filler]
  275. TEST RCX, 3
  276. JZ ok
  277. PUSH 8 ; ASSERT failure
  278. INT 3
  279. ok:
  280. SHR RCX, 2
  281. CLD
  282. REP STOSD
  283. #ELSIF I386 THEN
  284. MOV EDI, [EBP+destAdr]
  285. MOV ECX, [EBP+size]
  286. MOV EAX, [EBP+filler]
  287. TEST ECX, 3
  288. JZ ok
  289. PUSH 8 ; ASSERT failure
  290. INT 3
  291. ok:
  292. SHR ECX, 2
  293. CLD
  294. REP STOSD
  295. #ELSE
  296. UNIMPLEMENTED
  297. #END
  298. END Fill32;
  299. (** -- Processor initialization -- *)
  300. PROCEDURE -SetFCR( s: SET );
  301. CODE
  302. #IF AMD64 THEN
  303. FLDCW [RSP] ; parameter s
  304. POP EAX
  305. #ELSIF I386 THEN
  306. FLDCW [ESP] ; parameter s
  307. POP EAX
  308. #ELSE
  309. UNIMPLEMENTED
  310. #END
  311. END SetFCR;
  312. PROCEDURE -FCR( ): SET;
  313. CODE
  314. #IF AMD64 THEN
  315. PUSH 0
  316. FNSTCW [RSP]
  317. FWAIT
  318. POP EAX
  319. #ELSIF I386 THEN
  320. PUSH 0
  321. FNSTCW [ESP]
  322. FWAIT
  323. POP EAX
  324. #ELSE
  325. UNIMPLEMENTED
  326. #END
  327. END FCR;
  328. PROCEDURE -InitFPU;
  329. CODE
  330. FNINIT
  331. END InitFPU;
  332. (** Setup FPU control word of current processor. *)
  333. PROCEDURE SetupFPU*;
  334. BEGIN
  335. InitFPU; SetFCR( fcr )
  336. END SetupFPU;
  337. (** CPU identification. *)
  338. PROCEDURE CPUID*( VAR vendor: Vendor; VAR version: LONGINT; VAR features1,features2: SET );
  339. CODE
  340. #IF AMD64 THEN
  341. MOV EAX, 0
  342. CPUID
  343. CMP EAX, 0
  344. JNE ok
  345. MOV RSI, [RBP+vendor]
  346. MOV [RSI], AL ; AL = 0
  347. MOV RSI, [RBP+version]
  348. MOV [RSI], EAX ; EAX = 0
  349. MOV RSI, [RBP+features1]
  350. MOV [RSI], EAX
  351. MOV RSI, [RBP+features2]
  352. MOV [RSI], EAX
  353. JMP end
  354. ok:
  355. MOV RSI, [RBP+vendor]
  356. MOV [RSI], EBX
  357. MOV [RSI+4], EDX
  358. MOV [RSI+8], ECX
  359. MOV BYTE [RSI+12], 0
  360. MOV EAX, 1
  361. CPUID
  362. MOV RSI, [RBP+version]
  363. MOV [RSI], EAX
  364. MOV RSI, [RBP+features1]
  365. MOV [RSI], EDX
  366. MOV RSI, [RBP+features2]
  367. MOV [RSI], ECX
  368. end:
  369. #ELSIF I386 THEN
  370. MOV EAX, 0
  371. CPUID
  372. CMP EAX, 0
  373. JNE ok
  374. MOV ESI, [EBP+vendor]
  375. MOV [ESI], AL ; AL = 0
  376. MOV ESI, [EBP+version]
  377. MOV [ESI], EAX ; EAX = 0
  378. MOV ESI, [EBP+features1]
  379. MOV [ESI], EAX
  380. MOV ESI, [EBP+features2]
  381. MOV [ESI], EAX
  382. JMP end
  383. ok:
  384. MOV ESI, [EBP+vendor]
  385. MOV [ESI], EBX
  386. MOV [ESI+4], EDX
  387. MOV [ESI+8], ECX
  388. MOV BYTE [ESI+12], 0
  389. MOV EAX, 1
  390. CPUID
  391. MOV ESI, [EBP+version]
  392. MOV [ESI], EAX
  393. MOV ESI, [EBP+features1]
  394. MOV [ESI], EDX
  395. MOV ESI, [EBP+features2]
  396. MOV [ESI], ECX
  397. end:
  398. #ELSE
  399. UNIMPLEMENTED
  400. #END
  401. END CPUID;
  402. PROCEDURE GetConfig*( CONST name: ARRAY OF CHAR; VAR val: ARRAY OF CHAR );
  403. CONST ConfigKey = "Configuration";
  404. BEGIN
  405. COPY ("", val);
  406. IF Kernel32.GetPrivateProfileString (ConfigKey, name, "", val, LEN (val), userConfigFile) # 0 THEN
  407. ELSIF Kernel32.GetPrivateProfileString (ConfigKey, name, "", val, LEN (val), defaultConfigFile) # 0 THEN
  408. END;
  409. IF (name = "ObjectFileExtension") & (val = "") THEN
  410. #IF AMD64 THEN
  411. IF Kernel32.Generic THEN
  412. val := ".GofWw";
  413. ELSE
  414. val := ".Obww"
  415. END;
  416. #ELSIF I386 THEN
  417. IF Kernel32.Generic THEN
  418. val := ".GofW";
  419. ELSE
  420. val := ".Obw"
  421. END;
  422. #ELSE
  423. UNIMPLEMENTED
  424. #END
  425. END;
  426. END GetConfig;
  427. PROCEDURE Shutdown*( restart: BOOLEAN );
  428. BEGIN
  429. RemoveTraceFile;
  430. Kernel32.Shutdown( 0 ); (* calls the finalizer of Heaps *)
  431. END Shutdown;
  432. (* Dan: from new Machine *)
  433. PROCEDURE -GetTimer*(): HUGEINT;
  434. CODE {SYSTEM.Pentium}
  435. RDTSC ; set EDX:EAX
  436. END GetTimer;
  437. (* Dan: mono CPU PCs *)
  438. PROCEDURE ID*(): LONGINT;
  439. BEGIN
  440. RETURN 0
  441. END ID;
  442. (**
  443. * Flush Data Cache for the specified virtual address range. If len is negative, flushes the whole cache.
  444. * This is used on some architecture to interact with DMA hardware (e.g. Ethernet and USB. It can be
  445. * left empty on Intel architecture.
  446. *)
  447. PROCEDURE FlushDCacheRange * (adr: ADDRESS; len: LONGINT);
  448. END FlushDCacheRange;
  449. (**
  450. * Invalidate Data Cache for the specified virtual address range. If len is negative, flushes the whole cache.
  451. * This is used on some architecture to interact with DMA hardware (e.g. Ethernet and USB. It can be
  452. * left empty on Intel architecture.
  453. *)
  454. PROCEDURE InvalidateDCacheRange * (adr: ADDRESS; len: LONGINT);
  455. END InvalidateDCacheRange;
  456. (**
  457. * Invalidate Instruction Cache for the specified virtual address range. If len is negative, flushes the whole cache.
  458. * This is used on some architecture to interact with DMA hardware (e.g. Ethernet and USB. It can be
  459. * left empty on Intel architecture.
  460. *)
  461. PROCEDURE InvalidateICacheRange * (adr: ADDRESS; len: LONGINT);
  462. END InvalidateICacheRange;
  463. (* setup MMX, SSE and SSE2..SSE5 and AVX extension *)
  464. PROCEDURE SetupSSE2Ext;
  465. CONST
  466. MMXFlag=23;(*IN features from EBX*)
  467. FXSRFlag = 24;
  468. SSEFlag = 25;
  469. SSE2Flag = 26;
  470. SSE3Flag = 0; (*IN features2 from ECX*) (*PH 04/11*)
  471. SSSE3Flag =9;
  472. SSE41Flag =19;
  473. SSE42Flag =20;
  474. SSE5Flag = 11;
  475. AVXFlag = 28;
  476. BEGIN
  477. MMXSupport := MMXFlag IN features;
  478. SSESupport := SSEFlag IN features;
  479. SSE2Support := SSESupport & (SSE2Flag IN features);
  480. SSE3Support := SSE2Support & (SSE3Flag IN features2);
  481. SSSE3Support := SSE3Support & (SSSE3Flag IN features2); (* PH 04/11*)
  482. SSE41Support := SSE3Support & (SSE41Flag IN features2);
  483. SSE42Support := SSE3Support & (SSE42Flag IN features2);
  484. SSE5Support := SSE3Support & (SSE5Flag IN features2);
  485. AVXSupport := SSE3Support & (AVXFlag IN features2);
  486. IF SSESupport & (FXSRFlag IN features) THEN
  487. (* InitSSE(); *) (*! not privileged mode in Windows not allowed *)
  488. END;
  489. END SetupSSE2Ext;
  490. PROCEDURE ReadCommandLine(VAR commandLine: ARRAY OF CHAR);
  491. VAR adr: ADDRESS; i: LONGINT; ch: CHAR;
  492. BEGIN
  493. adr := Kernel32.GetCommandLine();
  494. SYSTEM.GET(adr,ch);
  495. i := 0;
  496. WHILE (i<LEN(commandLine)-1) & (ch # 0X) DO
  497. commandLine[i] := ch;
  498. INC(adr); INC(i);
  499. SYSTEM.GET(adr,ch);
  500. END;
  501. END ReadCommandLine;
  502. PROCEDURE ParseLine(VAR c: ARRAY OF CHAR; VAR iniFile: ARRAY OF CHAR);
  503. VAR i: LONGINT;
  504. PROCEDURE SkipSpaces;
  505. BEGIN
  506. WHILE (c[i] <= " ") & (c[i] # 0X) DO INC(i) END;
  507. END SkipSpaces;
  508. PROCEDURE SkipName;
  509. BEGIN
  510. WHILE (c[i] > " ") DO INC(i) END;
  511. END SkipName;
  512. PROCEDURE CheckName(CONST name: ARRAY OF CHAR): BOOLEAN;
  513. VAR j: LONGINT;
  514. BEGIN
  515. j := 0;
  516. WHILE (c[i] = name[j]) & (c[i] # 0X) & (name[j] # 0X) DO
  517. INC(i); INC(j);
  518. END;
  519. RETURN (name[j] = 0X);
  520. END CheckName;
  521. PROCEDURE ReadName(VAR name: ARRAY OF CHAR);
  522. VAR j: LONGINT;
  523. BEGIN
  524. SkipSpaces;
  525. j := 0;
  526. WHILE (c[i] > " ") & (j < LEN(name)-1) DO
  527. name[j] := c[i];
  528. INC(i); INC(j);
  529. END;
  530. name[j] := 0X;
  531. END ReadName;
  532. BEGIN
  533. c[LEN(c)-1] := 0X;
  534. i := 0;
  535. SkipSpaces;
  536. SkipName;
  537. SkipSpaces;
  538. IF c[i] = "-" THEN (* option *)
  539. INC(i);
  540. IF CheckName("ini") THEN SkipSpaces; ReadName(iniFile) END;
  541. END;
  542. END ParseLine;
  543. PROCEDURE TraceChar(c: CHAR);
  544. VAR len: LONGINT; b: Kernel32.BOOL;
  545. BEGIN
  546. len := 1;
  547. b := Kernel32.WriteFile(hout,c,len,len,NIL);
  548. END TraceChar;
  549. PROCEDURE SetTraceFile*;
  550. BEGIN
  551. traceName := "SystemTrace.txt";
  552. SetupTraceName(traceName);
  553. Trace.String("trace -> file "); Trace.String(traceName); Trace.Ln;
  554. hout := Kernel32.CreateFile(traceName, {Kernel32.GenericWrite}, {Kernel32.FileShareRead}, NIL, Kernel32.CreateAlways, {Kernel32.FileAttributeNormal}, Kernel32.NULL);
  555. Kernel32.GetFullPathName(traceName, LEN(traceName),traceName, NIL);
  556. Trace.Char := TraceChar;
  557. Trace.String(version); Trace.Ln;
  558. END SetTraceFile;
  559. PROCEDURE SetTraceConsole*;
  560. VAR res: WORD;
  561. BEGIN
  562. Trace.String("trace -> console"); Trace.Ln;
  563. res := Kernel32.AllocConsole ();
  564. hin := Kernel32.GetStdHandle (Kernel32.STDInput);
  565. hout := Kernel32.GetStdHandle (Kernel32.STDOutput);
  566. Trace.Char := TraceChar;
  567. Trace.String(version); Trace.Ln;
  568. END SetTraceConsole;
  569. PROCEDURE SetupTraceName(VAR traceName: ARRAY OF CHAR);
  570. VAR
  571. ext: ARRAY 256 OF CHAR;
  572. extPos,i,j: LONGINT;
  573. systemTime: Kernel32.SystemTime;
  574. ch: CHAR;
  575. PROCEDURE AppendDecimals(int: LONGINT; from, to: LONGINT);
  576. BEGIN
  577. WHILE to >= from DO
  578. traceName[i] := CHR(ORD("0")+ int DIV to MOD 10); INC(i);
  579. to := to DIV 10;
  580. END;
  581. END AppendDecimals;
  582. BEGIN
  583. Kernel32.GetLocalTime(systemTime);
  584. extPos := 0;
  585. REPEAT
  586. ch := traceName[i];
  587. IF ch = "." THEN j := 0; extPos := i END;
  588. ext[j] := ch;
  589. INC(j); INC(i);
  590. UNTIL ch = 0X;
  591. IF extPos > 0 THEN i := extPos END;
  592. ext[j] := 0X;
  593. AppendDecimals(systemTime.wYear,1,1000);
  594. AppendDecimals(systemTime.wMonth,1,10);
  595. AppendDecimals(systemTime.wDay,1,10);
  596. traceName[i] := "_"; INC(i);
  597. AppendDecimals(systemTime.wHour,1,10);
  598. AppendDecimals(systemTime.wMinute,1,10);
  599. AppendDecimals(systemTime.wSecond,1,10);
  600. traceName[i] := "_"; INC(i);
  601. AppendDecimals(systemTime.wMilliseconds,10,100);
  602. j := 0;
  603. REPEAT
  604. ch := ext[j];
  605. traceName[i] := ch;
  606. INC(i); INC(j);
  607. UNTIL ch = 0X;
  608. END SetupTraceName;
  609. PROCEDURE RemoveTraceFile;
  610. VAR res: WORD;
  611. BEGIN
  612. IF (traceName # "") & (traceName # "Console") THEN
  613. Trace.String("removing "); Trace.String(traceName); Trace.Ln;
  614. (*Trace.Char := LogChar;*)
  615. res := Kernel32.CloseHandle(hout);
  616. IF res = 0 THEN
  617. res := Kernel32.GetLastError();
  618. Trace.String("could not close "); Trace.String("; res = "); Trace.Int(res,1); Trace.Ln;
  619. END;
  620. res := Kernel32.DeleteFile(traceName);
  621. IF res = 0 THEN
  622. res := Kernel32.GetLastError();
  623. Trace.String("could not delete "); Trace.String(traceName); Trace.String("; res = "); Trace.Int(res,1); Trace.Ln;
  624. END;
  625. END;
  626. END RemoveTraceFile;
  627. PROCEDURE ToExecutablePath(CONST name: ARRAY OF CHAR; VAR fullName: ARRAY OF CHAR);
  628. VAR i,j: LONGINT;
  629. BEGIN
  630. Kernel32.GetModuleFileName(Kernel32.hInstance, fullName, LEN( fullName ) );
  631. j := -1; i := 0;
  632. WHILE fullName[i] # 0X DO
  633. IF fullName[i] = '\' THEN j := i END;
  634. INC( i )
  635. END;
  636. i := 0; INC(j);
  637. WHILE name[i] # 0X DO
  638. fullName[j] := name[i]; INC(i); INC(j);
  639. END;
  640. fullName[j] := 0X;
  641. END ToExecutablePath;
  642. PROCEDURE Append(VAR s: ARRAY OF CHAR; CONST t: ARRAY OF CHAR);
  643. VAR i,j: LONGINT;
  644. BEGIN
  645. i := 0;
  646. WHILE(s[i] # 0X) DO INC(i) END;
  647. j := 0;
  648. WHILE (t[j] # 0X) DO
  649. s[i] := t[j];
  650. INC(i); INC(j);
  651. END;
  652. s[i] := 0X;
  653. END Append;
  654. PROCEDURE Init*;
  655. VAR vendor: Vendor; ver: LONGINT; hfile: Kernel32.HANDLE;
  656. BEGIN
  657. Kernel32.Init;
  658. (* trace[1] := 0X; Trace.Char := LogChar; Trace.Color := TraceColor; *)
  659. InitLocks();
  660. boottime:=GetTimer();
  661. COPY( Version, version );
  662. Append(version, SYSTEM.Date);
  663. CPUID(vendor, ver, features,features2); SetupSSE2Ext;
  664. fcr := (FCR() - {0,2,3,10,11}) + {0..5,8,9}; (* default FCR RC=00B *)
  665. ReadCommandLine(commandLine);
  666. IF Kernel32.Generic THEN
  667. ToExecutablePath(DefaultGenericConfigFile, defaultConfigFile);
  668. ELSE
  669. ToExecutablePath(DefaultConfigFile, defaultConfigFile);
  670. END;
  671. COPY(UserConfigFile, userConfigFile);
  672. hfile := Kernel32.CreateFile( userConfigFile, {Kernel32.GenericRead}, {Kernel32.FileShareRead}, NIL , Kernel32.OpenExisting, {Kernel32.FileAttributeNormal}, 0 );
  673. IF hfile = Kernel32.InvalidHandleValue THEN
  674. ToExecutablePath(UserConfigFile, userConfigFile);
  675. ELSE
  676. Kernel32.CloseHandle(hfile)
  677. END;
  678. (*
  679. (* ever used ? *)
  680. ParseLine(commandLine, userConfigFile);
  681. userConfigFile[Kernel32.GetFullPathName (userConfigFile, Kernel32.MaxPath, userConfigFile, 0)] := 0X;
  682. traceName[0] := 0X;
  683. GetConfig("Trace",traceName);
  684. Trace.String("traceName "); Trace.String(traceName); Trace.Ln;
  685. IF traceName = "File" THEN SetTraceFile;
  686. ELSIF traceName = "Console" THEN SetTraceConsole
  687. (* else trace is on kernel log *)
  688. END;
  689. Trace.String("Machine init done"); Trace.Ln;
  690. *)
  691. END Init;
  692. PROCEDURE {INITIAL, NOPAF} Start*;
  693. BEGIN
  694. stackBottom := CurrentSP();
  695. Init; (* cannot allocate variables in here *)
  696. END Start;
  697. (* Initialize locks. *)
  698. PROCEDURE InitLocks;
  699. VAR i: LONGINT;
  700. BEGIN
  701. i := 0;
  702. WHILE i < MaxLocks DO Kernel32.InitializeCriticalSection( cs[i] ); lock[i] := "N"; INC( i ) END;
  703. END InitLocks;
  704. PROCEDURE CleanupLocks*;
  705. VAR i: LONGINT;
  706. BEGIN
  707. i := 0;
  708. WHILE i < MaxLocks DO Kernel32.DeleteCriticalSection( cs[i] ); INC( i ) END;
  709. END CleanupLocks;
  710. (** Acquire a spin-lock. *)
  711. PROCEDURE Acquire*( level: LONGINT ); (* non reentrant lock (non reentrance "ensured" by ASSERT statement ), CriticalSections are reentrant *)
  712. BEGIN
  713. Kernel32.EnterCriticalSection( cs[level] );
  714. IF StrongChecks THEN
  715. ASSERT ( lock[level] = "N", 1001 );
  716. ELSIF lock[level] # "N" THEN
  717. Trace.String("warning: reentered non-reentrant lock"); Trace.Ln;
  718. END;
  719. lock[level] := "Y";
  720. END Acquire;
  721. (** Release a spin-lock. *)
  722. PROCEDURE Release*( level: LONGINT ); (* release lock *)
  723. BEGIN
  724. IF StrongChecks THEN
  725. ASSERT ( lock[level] ="Y", 1002 );
  726. ELSIF lock[level] # "Y" THEN
  727. Trace.String("warning: reentered non-reentrant lock"); Trace.Ln;
  728. END;
  729. lock[level] := "N";
  730. Kernel32.LeaveCriticalSection( cs[level] )
  731. END Release;
  732. (* added by Alexey *)
  733. PROCEDURE GetMemStatus(VAR stat: Kernel32.MemoryStatusEx): BOOLEAN;
  734. BEGIN
  735. stat.dwLength := 64;
  736. IF Kernel32.GlobalMemoryStatusEx(stat) = 1 THEN
  737. RETURN TRUE;
  738. ELSE
  739. RETURN FALSE;
  740. END;
  741. END GetMemStatus;
  742. (** dummy procedure to make GC work for both I386 and Win32 *)
  743. PROCEDURE GetKernelStacks*(VAR stack: ARRAY OF Stack);
  744. VAR i: LONGINT;
  745. BEGIN
  746. FOR i := 0 TO MaxCPU-1 DO
  747. stack[i].adr := NilVal;
  748. stack[i].high := NilVal
  749. END
  750. END GetKernelStacks;
  751. (* Set machine-dependent parameter gcThreshold *)
  752. PROCEDURE SetGCParams*;
  753. BEGIN
  754. gcThreshold := 10*1024*1024; (* 10 MB *)
  755. END SetGCParams;
  756. (** Get first memory block and first free address, the first free address is identical to memBlockHead.endBlockAdr *)
  757. PROCEDURE GetStaticHeap*(VAR beginBlockAdr, endBlockAdr, freeBlockAdr: ADDRESS);
  758. BEGIN
  759. beginBlockAdr := NIL; endBlockAdr := NIL; freeBlockAdr := NIL;
  760. END GetStaticHeap;
  761. (* returns if an address is a currently allocated heap address *)
  762. PROCEDURE ValidHeapAddress*(p: ADDRESS): BOOLEAN;
  763. BEGIN
  764. RETURN (p >= memBlockHead.beginBlockAdr) & (p <= memBlockTail.endBlockAdr)
  765. OR (p>=401000H) & (p<=ADDRESSOF(LastAddress))
  766. END ValidHeapAddress;
  767. PROCEDURE GetFreeK* (VAR total, lowFree, highFree: SIZE);
  768. VAR
  769. stat: Kernel32.MemoryStatusEx;
  770. BEGIN
  771. total := MAX(LONGINT); lowFree := 0; highFree := total;
  772. (*<< added by Alexey *)
  773. IF GetMemStatus(stat) THEN
  774. total := SHORT(stat.ullTotalVirtual DIV 1024);
  775. lowFree := 0;
  776. highFree := SHORT(stat.ullAvailVirtual DIV 1024);
  777. END;
  778. (* added by Alexey >>*)
  779. END GetFreeK;
  780. (* ug *)
  781. PROCEDURE TraceMemBlocks*;
  782. VAR memBlock {UNTRACED}: MemoryBlock; i : LONGINT;
  783. BEGIN
  784. memBlock := memBlockHead;
  785. i := 0;
  786. WHILE memBlock # NIL DO
  787. Trace.String("block "); Trace.Int(i, 0); Trace.String(": startAdr = "); Trace.Hex(memBlock.startAdr, 0);
  788. Trace.String(" size = "); Trace.Hex(memBlock.size, 0);
  789. Trace.String(" beginBlockAdr = "); Trace.Hex(memBlock.beginBlockAdr, 0);
  790. Trace.String(" endBlockAdr = "); Trace.Hex(memBlock.endBlockAdr, 0); Trace.Ln;
  791. memBlock := memBlock.next;
  792. INC(i)
  793. END
  794. END TraceMemBlocks;
  795. (* insert given memory block in sorted list of memory blocks, sort key is startAdr field - called during GC *)
  796. PROCEDURE InsertMemoryBlock(memBlock: MemoryBlock);
  797. VAR cur {UNTRACED}, prev {UNTRACED}: MemoryBlock;
  798. BEGIN
  799. cur := memBlockHead;
  800. prev := NIL;
  801. WHILE (cur # NIL) & (cur.startAdr < memBlock.startAdr) DO
  802. prev := cur;
  803. cur := cur.next
  804. END;
  805. IF prev = NIL THEN (* insert at head of list *)
  806. memBlock.next := memBlockHead;
  807. memBlockHead := memBlock
  808. ELSE (* insert in middle or at end of list *)
  809. memBlock.next := cur;
  810. prev.next := memBlock;
  811. END;
  812. IF cur = NIL THEN
  813. memBlockTail := memBlock
  814. END
  815. END InsertMemoryBlock;
  816. (* expand heap by allocating a new memory block *)
  817. PROCEDURE ExpandHeap*( dummy: LONGINT; size: SIZE; VAR memoryBlock: MemoryBlock; VAR beginBlockAdr, endBlockAdr: ADDRESS );
  818. VAR mBlock: MemoryBlock; alloc: SIZE; adr,initVal: ADDRESS; continue: BOOLEAN;
  819. BEGIN
  820. ASSERT(SIZEOF(MemoryBlockDesc) <= StaticBlockSize); (* make sure MemoryBlock contents fits into one StaticBlock *)
  821. alloc := size + StaticBlockSize;
  822. IF alloc < MemBlockSize THEN alloc := MemBlockSize END;
  823. INC( alloc, (-alloc) MOD StaticBlockSize );
  824. IF memBlockTail # NIL THEN
  825. initVal := memBlockTail.startAdr + memBlockTail.size;
  826. ELSE
  827. initVal := NIL
  828. END;
  829. adr := Kernel32.VirtualAlloc(initVal, alloc, {Kernel32.MEMCommit, Kernel32.MEMReserve}, {Kernel32.PageExecuteReadWrite});
  830. IF adr = NilVal THEN (* allocation failed *)
  831. adr := Kernel32.VirtualAlloc(NilVal, alloc, {Kernel32.MEMCommit}, {Kernel32.PageExecuteReadWrite});
  832. END;
  833. continue := adr = initVal;
  834. ASSERT(adr MOD StaticBlockSize = 0); (* is fulfilled because VirtualAlloc is on page granularity *)
  835. IF adr # 0 THEN
  836. IF continue THEN
  837. memoryBlock := memBlockTail;
  838. memoryBlock.size := memoryBlock.size + alloc;
  839. beginBlockAdr := memBlockTail.endBlockAdr;
  840. endBlockAdr := beginBlockAdr;
  841. INC(endBlockAdr, alloc);
  842. ELSE
  843. mBlock := adr;
  844. mBlock.next := NIL;
  845. mBlock.startAdr := adr;
  846. mBlock.size := alloc;
  847. beginBlockAdr := adr + StaticBlockSize;
  848. endBlockAdr := beginBlockAdr + alloc - StaticBlockSize;
  849. mBlock.beginBlockAdr := beginBlockAdr;
  850. mBlock.endBlockAdr := beginBlockAdr; (* block is still empty -- Heaps module will set the upper bound *)
  851. InsertMemoryBlock( mBlock );
  852. memoryBlock := mBlock;
  853. END;
  854. ELSE
  855. beginBlockAdr := 0; endBlockAdr := 0; memoryBlock := NIL;
  856. END;
  857. END ExpandHeap;
  858. (* Set memory block end address *)
  859. PROCEDURE SetMemoryBlockEndAddress*(memBlock: MemoryBlock; endBlockAdr: ADDRESS);
  860. BEGIN
  861. ASSERT(endBlockAdr >= memBlock.beginBlockAdr);
  862. memBlock.endBlockAdr := endBlockAdr
  863. END SetMemoryBlockEndAddress;
  864. (* Free unused memory block - called during GC *)
  865. PROCEDURE FreeMemBlock*(memBlock: MemoryBlock);
  866. VAR cur {UNTRACED}, prev {UNTRACED}: MemoryBlock;
  867. startAdr: ADDRESS;
  868. BEGIN
  869. cur := memBlockHead;
  870. prev := NIL;
  871. WHILE (cur # NIL) & (cur # memBlock) DO
  872. prev := cur;
  873. cur := cur.next
  874. END;
  875. IF cur = memBlock THEN
  876. IF prev = NIL THEN
  877. memBlockHead := cur.next;
  878. ELSE
  879. prev.next := cur.next;
  880. IF prev.next = NIL THEN
  881. memBlockTail := prev
  882. END
  883. END;
  884. memBlock.next := NIL;
  885. startAdr := memBlock.startAdr; (* this value must be cached for the second call of Kernel32.VirtualFree *)
  886. Kernel32.VirtualFree(SYSTEM.VAL(LONGINT, memBlock.startAdr), memBlock.size, {Kernel32.MEMDecommit});
  887. Kernel32.VirtualFree(SYSTEM.VAL(LONGINT, startAdr ), 0, {Kernel32.MEMRelease});
  888. ELSE
  889. HALT(535) (* error in memory block management *)
  890. END;
  891. END FreeMemBlock;
  892. PROCEDURE PhysicalAdr*(adr: ADDRESS; size: SIZE): ADDRESS;
  893. END PhysicalAdr;
  894. (* function returning the number of processors that are available to Aos *)
  895. PROCEDURE NumberOfProcessors*( ): LONGINT;
  896. VAR info: Kernel32.SystemInfo;
  897. BEGIN
  898. Kernel32.GetSystemInfo( info );
  899. RETURN info.dwNumberOfProcessors
  900. END NumberOfProcessors;
  901. (* function for changing byte order *)
  902. PROCEDURE ChangeByteOrder* (n: LONGINT): LONGINT;
  903. CODE
  904. #IF AMD64 THEN
  905. MOV EAX, [RBP+n] ; load n in eax
  906. BSWAP EAX ; swap byte order
  907. #ELSIF I386 THEN
  908. MOV EAX, [EBP+n] ; load n in eax
  909. BSWAP EAX
  910. #ELSE
  911. UNIMPLEMENTED
  912. #END
  913. END ChangeByteOrder;
  914. PROCEDURE Portin8*(port: LONGINT; VAR val: CHAR);
  915. END Portin8;
  916. PROCEDURE Portin16*(port: LONGINT; VAR val: INTEGER);
  917. END Portin16;
  918. PROCEDURE Portin32*(port: LONGINT; VAR val: LONGINT);
  919. END Portin32;
  920. PROCEDURE Portout8*(port: LONGINT; val: CHAR);
  921. END Portout8;
  922. PROCEDURE Portout16*(port: LONGINT; val: INTEGER);
  923. END Portout16;
  924. PROCEDURE Portout32*(port: LONGINT; val: LONGINT);
  925. END Portout32;
  926. BEGIN
  927. IF ~Kernel32.Generic THEN
  928. Init
  929. END;
  930. Trace.String(version); Trace.Ln;
  931. END Machine.