Windows.AMD64.Machine.Mod 24 KB

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