Win64.Machine.Mod 32 KB

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