Windows.I386.Machine.Mod 25 KB

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