12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115 |
- MODULE Machine;
- (** AUTHOR "pjm,fof"; PURPOSE "Bootstrapping, configuration and machine interface, adaption to windows fof"; *)
- (* red marked parts are WinAos specific *)
- IMPORT SYSTEM, Trace, Kernel32;
- CONST
- Version = "WinAos (32bit) ";
- DefaultConfigFile = "aos.ini";
- DefaultGenericConfigFile = "aosg.ini";
- UserConfigFile = "myaos.ini";
- MaxCPU* = 8; (* dummy definition to make GC for both Win32 and I386 work *)
- DefaultObjectFileExtension* = ".Obw";
- (** bits in features variable *)
- MTTR* = 12; MMX* = 23;
- debug* = FALSE; (** display more debug output during booting *)
- CONST
- AddressSize = SIZEOF(ADDRESS);
- StaticBlockSize = 32; (* static heap block size *)
- BlockHeaderSize = 2 * AddressSize;
- (* change this when Heaps.HeapBlock is modified *)
- RecordDescSize = 4 * AddressSize; (* needs to be adapted in case Heaps.RecordBlockDesc is changed *)
- (** standard lock levels (in order) *) (* also refer to Traps.Show *)
- TraceOutput* = 0; (* Trace output *)
- Memory* = 1; (* Virtual memory management, stack and page allocation *)
- Heaps* = 2; (* Storage allocation and Garbage collection *)
- Interrupts* = 3; (* Interrupt handling. *)
- Modules* = 4; (* Module list *)
- Objects* = 5; (* Ready queue *)
- Processors* = 6; (* Interprocessor interrupts *)
- KernelLog* = 7; (* Atomic output *)
- GC* = 8;
- MaxLocks = 9; (* { <= 32 } *)
- StrongChecks = FALSE;
- HeaderSize = 40H; (* cf. Linker0 *)
- EndBlockOfs = 38H; (* cf. Linker0 *)
- MemoryBlockOfs = BlockHeaderSize + RecordDescSize + BlockHeaderSize; (* memory block (including header) starts at offset HeaderSize *)
- MemBlockSize = 32*1024*1024; (* must be multiple of StaticBlockSize *)
- MinMemBlockSize = 4*1024*1024;
- NilVal = 0;
- Second* = 1000; (* frequency of ticks increments in Hz *)
- CONST
- (* error codes *)
- Ok* = 0;
- NilAdr* = -1; (* nil value for addresses (not same as pointer NIL value) *)
- IsCooperative* = FALSE;
- TYPE
- Vendor* = ARRAY 13 OF CHAR;
- IDMap* = ARRAY 16 OF SHORTINT;
- Range* = RECORD
- adr*, size*: LONGINT
- END;
- MemoryBlock* = POINTER TO MemoryBlockDesc;
- MemoryBlockDesc* = RECORD
- next- {UNTRACED}: MemoryBlock;
- startAdr-: ADDRESS; (* sort key in linked list of memory blocks *)
- size-: SIZE;
- beginBlockAdr-, endBlockAdr-: ADDRESS
- END;
- (* dummy definition to make GC work for both I386 and Win32 - copied from I386.Machine.Mod, but not really used *)
- Stack* = RECORD (** values are read-only *)
- low: ADDRESS; (* lowest virtual address that may be allocated for stack *)
- adr*: ADDRESS; (* lowest address on allocated stack *) (* exported for Objects only *)
- high*: ADDRESS; (* next virtual address after stack *) (* exported for Objects only *)
- END;
- VAR
- LastAddress: RECORD END;
- MMXSupport*: BOOLEAN;
- SSESupport*: BOOLEAN;
- SSE2Support*: BOOLEAN;
- SSE3Support-: BOOLEAN; (* PH 04/11*)
- SSSE3Support-: BOOLEAN;
- SSE41Support-: BOOLEAN;
- SSE42Support-: BOOLEAN;
- SSE5Support-: BOOLEAN;
- AVXSupport-: BOOLEAN;
- version*: ARRAY 64 OF CHAR; (** Aos version *)
- features*,features2*: SET; (** processor features *)
- fcr*: SET; (** default floating-point control register value (default rounding mode is towards -infinity, for ENTIER) *)
- mhz*: HUGEINT; (** clock rate of GetTimer() in MHz, or 0 if not known *)
- boottime-: HUGEINT; (** in timer units *)
- commandLine-: ARRAY 256 OF CHAR;
- hin, hout: Kernel32.HANDLE;
- VAR
- lock-: ARRAY MaxLocks OF CHAR; (* not implemented as SET because of shared access *)
- cs: ARRAY MaxLocks OF Kernel32.CriticalSection;
- trace: ARRAY 2 OF CHAR;
- defaultConfigFile, userConfigFile, traceName: ARRAY Kernel32.MaxPath OF CHAR;
- gcThreshold-: SIZE;
- bootHeapAdr: ADDRESS; (* initialized by linker, variable name must not be changed, see Win32.Aos.Link *)
- bootHeapSize: SIZE; (* initialized by linker, variable name must not be changed, see Win32.Aos.Link *)
- memBlockHead-{UNTRACED}, memBlockTail-{UNTRACED}: MemoryBlock; (* head and tail of sorted list of memory blocks *)
- (** 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. *)
- PROCEDURE StrToInt*( VAR i: LONGINT; CONST s: ARRAY OF CHAR ): LONGINT;
- VAR vd, vh, sgn, d: LONGINT; hex: BOOLEAN;
- BEGIN
- vd := 0; vh := 0; hex := FALSE;
- IF s[i] = "-" THEN sgn := -1; INC( i ) ELSE sgn := 1 END;
- LOOP
- IF (s[i] >= "0") & (s[i] <= "9") THEN d := ORD( s[i] ) - ORD( "0" )
- ELSIF (CAP( s[i] ) >= "A") & (CAP( s[i] ) <= "F") THEN d := ORD( CAP( s[i] ) ) - ORD( "A" ) + 10; hex := TRUE
- ELSE EXIT
- END;
- vd := 10 * vd + d; vh := 16 * vh + d; INC( i )
- END;
- IF CAP( s[i] ) = "H" THEN hex := TRUE; INC( i ) END; (* optional H *)
- IF hex THEN vd := vh END;
- RETURN sgn * vd
- END StrToInt;
- (** -- Atomic operations -- *)
- (** Atomic INC(x). *)
- PROCEDURE -AtomicInc*(VAR x: LONGINT);
- CODE {SYSTEM.AMD64}
- POP RAX
- LOCK
- INC DWORD [RAX]
- END AtomicInc;
- (** Atomic DEC(x). *)
- PROCEDURE -AtomicDec*(VAR x: LONGINT);
- CODE {SYSTEM.AMD64}
- POP RAX
- LOCK
- DEC DWORD [RAX]
- END AtomicDec;
- (** Atomic EXCL. *)
- PROCEDURE AtomicExcl* (VAR s: SET; bit: LONGINT);
- CODE {SYSTEM.AMD64}
- MOV EAX, [RBP + bit]
- MOV RBX, [RBP + s]
- LOCK
- BTR [RBX], EAX
- END AtomicExcl;
- (** Atomic INC(x, y). *)
- PROCEDURE -AtomicAdd*(VAR x: LONGINT; y: LONGINT);
- CODE {SYSTEM.AMD64}
- POP EBX
- POP RAX
- LOCK
- ADD DWORD [RAX], EBX
- END AtomicAdd;
- (** Atomic test-and-set. Set x = TRUE and return old value of x. *)
- PROCEDURE -AtomicTestSet*(VAR x: BOOLEAN): BOOLEAN;
- CODE {SYSTEM.AMD64}
- POP RBX
- MOV AL, 1
- XCHG [RBX], AL
- END AtomicTestSet;
- (* Atomic compare-and-swap. Set x = new if x = old and return old value of x *)
- PROCEDURE -AtomicCAS* (VAR x: LONGINT; old, new: LONGINT): LONGINT;
- CODE {SYSTEM.AMD64}
- POP EBX ; new
- POP EAX ; old
- POP RCX ; address of x
- LOCK CMPXCHG [RCX], EBX ; atomicly compare x with old and set it to new if equal
- END AtomicCAS;
- (** -- Miscellaneous -- *)
- (* Return current instruction pointer *)
- PROCEDURE CurrentPC* (): ADDRESS;
- CODE {SYSTEM.AMD64}
- MOV RAX, [RBP + 8]
- END CurrentPC;
- (* Return current frame pointer *)
- PROCEDURE -CurrentBP* (): ADDRESS;
- CODE {SYSTEM.AMD64}
- MOV RAX, RBP
- END CurrentBP;
- (* Set current frame pointer *)
- PROCEDURE -SetBP* (bp: ADDRESS);
- CODE {SYSTEM.AMD64}
- POP RBP
- END SetBP;
- (* Return current stack pointer *)
- PROCEDURE -CurrentSP* (): ADDRESS;
- CODE {SYSTEM.AMD64}
- MOV RAX, RSP
- END CurrentSP;
- (* Set current stack pointer *)
- PROCEDURE -SetSP* (sp: ADDRESS);
- CODE {SYSTEM.AMD64}
- POP RSP
- END SetSP;
- (** This procedure should be called in all spin loops as a hint to the processor (e.g. Pentium 4). *)
- PROCEDURE -SpinHint*;
- CODE {SYSTEM.AMD64}
- PAUSE
- END SpinHint;
- (** Fill "size" bytes at "destAdr" with "filler". "size" must be multiple of 4. *)
- PROCEDURE Fill32* (destAdr: ADDRESS; size: SIZE; filler: LONGINT);
- CODE {SYSTEM.AMD64}
- MOV RDI, [RBP + destAdr]
- MOV RCX, [RBP + size]
- MOV EAX, [RBP + filler]
- TEST RCX, 3
- JZ ok
- PUSH 8 ; ASSERT failure
- INT 3
- ok:
- SHR RCX, 2
- CLD
- REP STOSD
- END Fill32;
- (** -- Processor initialization -- *)
- PROCEDURE -SetFCR( s: SET );
- CODE {SYSTEM.i386, SYSTEM.FPU}
- FLDCW [ESP] ; parameter s
- POP EAX
- END SetFCR;
- PROCEDURE -FCR( ): SET;
- CODE {SYSTEM.i386, SYSTEM.FPU}
- PUSH 0
- FNSTCW [ESP]
- FWAIT
- POP EAX
- END FCR;
- PROCEDURE -InitFPU;
- CODE {SYSTEM.i386, SYSTEM.FPU}
- FNINIT
- END InitFPU;
- (** Setup FPU control word of current processor. *)
- PROCEDURE SetupFPU*;
- BEGIN
- InitFPU; SetFCR( fcr )
- END SetupFPU;
- (** CPU identification. *)
- PROCEDURE CPUID*( VAR vendor: Vendor; VAR version: LONGINT; VAR features1,features2: SET );
- CODE {SYSTEM.i386, SYSTEM.Pentium}
- MOV EAX, 0
- CPUID
- CMP EAX, 0
- JNE ok
- MOV ESI, [EBP+vendor]
- MOV [ESI], AL ; AL = 0
- MOV ESI, [EBP+version]
- MOV [ESI], EAX ; EAX = 0
- MOV ESI, [EBP+features1]
- MOV [ESI], EAX
- MOV ESI, [EBP+features2]
- MOV [ESI], EAX
- JMP end
- ok:
- MOV ESI, [EBP+vendor]
- MOV [ESI], EBX
- MOV [ESI+4], EDX
- MOV [ESI+8], ECX
- MOV BYTE [ESI+12], 0
- MOV EAX, 1
- CPUID
- MOV ESI, [EBP+version]
- MOV [ESI], EAX
- MOV ESI, [EBP+features1]
- MOV [ESI], EDX
- MOV ESI, [EBP+features2]
- MOV [ESI], ECX
- end:
- END CPUID;
- PROCEDURE GetConfig*( CONST name: ARRAY OF CHAR; VAR val: ARRAY OF CHAR );
- CONST ConfigKey = "Configuration";
- BEGIN
- COPY ("", val);
- IF Kernel32.GetPrivateProfileString (ConfigKey, name, "", val, LEN (val), userConfigFile) # 0 THEN
- ELSIF Kernel32.GetPrivateProfileString (ConfigKey, name, "", val, LEN (val), defaultConfigFile) # 0 THEN
- END;
-
- IF (name = "ObjectFileExtension") & (val = "") THEN
- IF Kernel32.Generic THEN
- val := ".GofW";
- ELSE
- val := ".Obw"
- END;
- END;
- END GetConfig;
- PROCEDURE Shutdown*( restart: BOOLEAN );
- BEGIN
- RemoveTraceFile;
- Kernel32.Shutdown( 0 ); (* calls the finalizer of Heaps *)
- END Shutdown;
- (* Dan: from new Machine *)
- PROCEDURE -GetTimer*(): HUGEINT;
- CODE {SYSTEM.Pentium}
- RDTSC ; set EDX:EAX
- END GetTimer;
- (* Dan: mono CPU PCs *)
- PROCEDURE ID*(): LONGINT;
- BEGIN
- RETURN 0
- END ID;
- (**
- * Flush Data Cache for the specified virtual address range. If len is negative, flushes the whole cache.
- * This is used on some architecture to interact with DMA hardware (e.g. Ethernet and USB. It can be
- * left empty on Intel architecture.
- *)
- PROCEDURE FlushDCacheRange * (adr: ADDRESS; len: LONGINT);
- END FlushDCacheRange;
- (**
- * Invalidate Data Cache for the specified virtual address range. If len is negative, flushes the whole cache.
- * This is used on some architecture to interact with DMA hardware (e.g. Ethernet and USB. It can be
- * left empty on Intel architecture.
- *)
- PROCEDURE InvalidateDCacheRange * (adr: ADDRESS; len: LONGINT);
- END InvalidateDCacheRange;
- (**
- * Invalidate Instruction Cache for the specified virtual address range. If len is negative, flushes the whole cache.
- * This is used on some architecture to interact with DMA hardware (e.g. Ethernet and USB. It can be
- * left empty on Intel architecture.
- *)
- PROCEDURE InvalidateICacheRange * (adr: ADDRESS; len: LONGINT);
- END InvalidateICacheRange;
- (* setup MMX, SSE and SSE2..SSE5 and AVX extension *)
- PROCEDURE SetupSSE2Ext;
- CONST
- MMXFlag=23;(*IN features from EBX*)
- FXSRFlag = 24;
- SSEFlag = 25;
- SSE2Flag = 26;
- SSE3Flag = 0; (*IN features2 from ECX*) (*PH 04/11*)
- SSSE3Flag =9;
- SSE41Flag =19;
- SSE42Flag =20;
- SSE5Flag = 11;
- AVXFlag = 28;
- BEGIN
- MMXSupport := MMXFlag IN features;
- SSESupport := SSEFlag IN features;
- SSE2Support := SSESupport & (SSE2Flag IN features);
- SSE3Support := SSE2Support & (SSE3Flag IN features2);
- SSSE3Support := SSE3Support & (SSSE3Flag IN features2); (* PH 04/11*)
- SSE41Support := SSE3Support & (SSE41Flag IN features2);
- SSE42Support := SSE3Support & (SSE42Flag IN features2);
- SSE5Support := SSE3Support & (SSE5Flag IN features2);
- AVXSupport := SSE3Support & (AVXFlag IN features2);
- IF SSESupport & (FXSRFlag IN features) THEN
- (* InitSSE(); *) (*! not privileged mode in Windows not allowed *)
- END;
- END SetupSSE2Ext;
- PROCEDURE ReadCommandLine(VAR commandLine: ARRAY OF CHAR);
- VAR adr: ADDRESS; i: LONGINT; ch: CHAR;
- BEGIN
- adr := Kernel32.GetCommandLine();
- SYSTEM.GET(adr,ch);
- i := 0;
- WHILE (i<LEN(commandLine)-1) & (ch # 0X) DO
- commandLine[i] := ch;
- INC(adr); INC(i);
- SYSTEM.GET(adr,ch);
- END;
- END ReadCommandLine;
- PROCEDURE ParseLine(VAR c: ARRAY OF CHAR; VAR iniFile: ARRAY OF CHAR);
- VAR i: LONGINT;
- PROCEDURE SkipSpaces;
- BEGIN
- WHILE (c[i] <= " ") & (c[i] # 0X) DO INC(i) END;
- END SkipSpaces;
- PROCEDURE SkipName;
- BEGIN
- WHILE (c[i] > " ") DO INC(i) END;
- END SkipName;
- PROCEDURE CheckName(CONST name: ARRAY OF CHAR): BOOLEAN;
- VAR j: LONGINT;
- BEGIN
- j := 0;
- WHILE (c[i] = name[j]) & (c[i] # 0X) & (name[j] # 0X) DO
- INC(i); INC(j);
- END;
- RETURN (name[j] = 0X);
- END CheckName;
- PROCEDURE ReadName(VAR name: ARRAY OF CHAR);
- VAR j: LONGINT;
- BEGIN
- SkipSpaces;
- j := 0;
- WHILE (c[i] > " ") & (j < LEN(name)-1) DO
- name[j] := c[i];
- INC(i); INC(j);
- END;
- name[j] := 0X;
- END ReadName;
- BEGIN
- c[LEN(c)-1] := 0X;
- i := 0;
- SkipSpaces;
- SkipName;
- SkipSpaces;
- IF c[i] = "-" THEN (* option *)
- INC(i);
- IF CheckName("ini") THEN SkipSpaces; ReadName(iniFile) END;
- END;
- END ParseLine;
- PROCEDURE TraceChar(c: CHAR);
- VAR len: LONGINT; b: Kernel32.BOOL;
- BEGIN
- len := 1;
- b := Kernel32.WriteFile(hout,c,len,len,NIL);
- END TraceChar;
- PROCEDURE SetTraceFile(VAR filename: ARRAY OF CHAR);
- BEGIN
- Trace.String("trace -> file "); Trace.String(filename); Trace.Ln;
- hout := Kernel32.CreateFile(filename, {Kernel32.GenericWrite}, {Kernel32.FileShareRead}, NIL, Kernel32.CreateAlways, {Kernel32.FileAttributeNormal}, Kernel32.NULL);
- Kernel32.GetFullPathName(filename, LEN(filename), filename, NIL);
- Trace.Char := TraceChar;
- END SetTraceFile;
- PROCEDURE SetTraceConsole;
- VAR res: LONGINT;
- BEGIN
- Trace.String("trace -> console"); Trace.Ln;
- res := Kernel32.AllocConsole ();
- hin := Kernel32.GetStdHandle (Kernel32.STDInput);
- hout := Kernel32.GetStdHandle (Kernel32.STDOutput);
- Trace.Char := TraceChar;
- END SetTraceConsole;
- PROCEDURE SetupTraceName(VAR traceName: ARRAY OF CHAR);
- VAR
- ext: ARRAY 256 OF CHAR;
- extPos,i,j: LONGINT;
- systemTime: Kernel32.SystemTime;
- ch: CHAR;
- PROCEDURE AppendDecimals(int: LONGINT; from, to: LONGINT);
- VAR ten: LONGINT;
- BEGIN
- WHILE to >= from DO
- traceName[i] := CHR(ORD("0")+ int DIV to MOD 10); INC(i);
- to := to DIV 10;
- END;
- END AppendDecimals;
- BEGIN
- Kernel32.GetLocalTime(systemTime);
- extPos := 0;
- REPEAT
- ch := traceName[i];
- IF ch = "." THEN j := 0; extPos := i END;
- ext[j] := ch;
- INC(j); INC(i);
- UNTIL ch = 0X;
- IF extPos > 0 THEN i := extPos END;
- ext[j] := 0X;
- AppendDecimals(systemTime.wYear,1,1000);
- AppendDecimals(systemTime.wMonth,1,10);
- AppendDecimals(systemTime.wDay,1,10);
- traceName[i] := "_"; INC(i);
- AppendDecimals(systemTime.wHour,1,10);
- AppendDecimals(systemTime.wMinute,1,10);
- AppendDecimals(systemTime.wSecond,1,10);
- traceName[i] := "_"; INC(i);
- AppendDecimals(systemTime.wMilliseconds,10,100);
- j := 0;
- REPEAT
- ch := ext[j];
- traceName[i] := ch;
- INC(i); INC(j);
- UNTIL ch = 0X;
- END SetupTraceName;
- PROCEDURE RemoveTraceFile;
- VAR res: LONGINT;
- BEGIN
- IF traceName[0] # 0X THEN
- Trace.String("removing "); Trace.String(traceName); Trace.Ln;
- (*Trace.Char := LogChar;*)
- res := Kernel32.CloseHandle(hout);
- TRACE(res);
- IF res = 0 THEN
- res := Kernel32.GetLastError();
- Trace.String("could not close "); Trace.String("; res = "); Trace.Int(res,1); Trace.Ln;
- END;
- res := Kernel32.DeleteFile(traceName);
- TRACE(res);
- IF res = 0 THEN
- res := Kernel32.GetLastError();
- Trace.String("could not delete "); Trace.String(traceName); Trace.String("; res = "); Trace.Int(res,1); Trace.Ln;
- END;
- TRACE(res);
- END;
- END RemoveTraceFile;
- PROCEDURE ToExecutablePath(CONST name: ARRAY OF CHAR; VAR fullName: ARRAY OF CHAR);
- VAR i,j: LONGINT;
- BEGIN
- Kernel32.GetModuleFileName(Kernel32.hInstance, fullName, LEN( fullName ) );
- j := -1; i := 0;
- WHILE fullName[i] # 0X DO
- IF fullName[i] = '\' THEN j := i END;
- INC( i )
- END;
- i := 0; INC(j);
- WHILE name[i] # 0X DO
- fullName[j] := name[i]; INC(i); INC(j);
- END;
- fullName[j] := 0X;
- END ToExecutablePath;
- PROCEDURE Append(VAR s: ARRAY OF CHAR; CONST t: ARRAY OF CHAR);
- VAR i,j: LONGINT;
- BEGIN
- i := 0;
- WHILE(s[i] # 0X) DO INC(i) END;
- j := 0;
- WHILE (t[j] # 0X) DO
- s[i] := t[j];
- INC(i); INC(j);
- END;
- s[i] := 0X;
- END Append;
- PROCEDURE Init*;
- VAR vendor: Vendor; ver: LONGINT; hfile: Kernel32.HANDLE;
- BEGIN
- Kernel32.Init;
- Trace.String("Machine 1"); Trace.Ln;
- (* trace[1] := 0X; Trace.Char := LogChar; Trace.Color := TraceColor; *)
- InitLocks();
- boottime:=GetTimer();
- COPY( Version, version );
- Append(version, SYSTEM.Date);
- CPUID(vendor, ver, features,features2); SetupSSE2Ext;
- fcr := (FCR() - {0,2,3,10,11}) + {0..5,8,9}; (* default FCR RC=00B *)
- ReadCommandLine(commandLine);
- IF Kernel32.Generic THEN
- ToExecutablePath(DefaultGenericConfigFile, defaultConfigFile);
- ELSE
- ToExecutablePath(DefaultConfigFile, defaultConfigFile);
- END;
- COPY(UserConfigFile, userConfigFile);
- hfile := Kernel32.CreateFile( userConfigFile, {Kernel32.GenericRead}, {Kernel32.FileShareRead}, NIL , Kernel32.OpenExisting, {Kernel32.FileAttributeNormal}, 0 );
- IF hfile = Kernel32.InvalidHandleValue THEN
- ToExecutablePath(UserConfigFile, userConfigFile);
- ELSE
- Kernel32.CloseHandle(hfile)
- END;
- (* ever used ? *)
- ParseLine(commandLine, userConfigFile);
- userConfigFile[Kernel32.GetFullPathName (userConfigFile, Kernel32.MaxPath, userConfigFile, 0)] := 0X;
- Trace.String("config file = "); Trace.String(defaultConfigFile); Trace.Ln;
- Trace.String("user config file = "); Trace.String(userConfigFile); Trace.Ln;
- traceName[0] := 0X;
- GetConfig("Trace",traceName);
- Trace.String("traceName "); Trace.String(traceName); Trace.Ln;
- IF traceName = "File" THEN
- traceName := "SystemTrace.txt";
- SetupTraceName(traceName);
- Trace.String("trace file to "); Trace.String(traceName); Trace.Ln;
- SetTraceFile(traceName);
- ELSIF traceName = "Console" THEN SetTraceConsole
- (* else trace is on kernel log *)
- END;
- Trace.String("Machine init done"); Trace.Ln;
- END Init;
- PROCEDURE {INITIAL, NOPAF} Start;
- BEGIN
- Init; (* cannot allocate variables in here *)
- END Start;
- (* Initialize locks. *)
- PROCEDURE InitLocks;
- VAR i: LONGINT;
- BEGIN
- i := 0;
- WHILE i < MaxLocks DO Kernel32.InitializeCriticalSection( cs[i] ); lock[i] := "N"; INC( i ) END;
- END InitLocks;
- PROCEDURE CleanupLocks*;
- VAR i: LONGINT;
- BEGIN
- i := 0;
- WHILE i < MaxLocks DO Kernel32.DeleteCriticalSection( cs[i] ); INC( i ) END;
- END CleanupLocks;
- (** Acquire a spin-lock. *)
- PROCEDURE Acquire*( level: LONGINT ); (* non reentrant lock (non reentrance "ensured" by ASSERT statement ), CriticalSections are reentrant *)
- BEGIN
- Kernel32.EnterCriticalSection( cs[level] );
- IF StrongChecks THEN
- ASSERT ( lock[level] = "N", 1001 );
- ELSIF lock[level] # "N" THEN
- Trace.String("warning: reentered non-reentrant lock"); Trace.Ln;
- END;
- lock[level] := "Y";
- END Acquire;
- (** Release a spin-lock. *)
- PROCEDURE Release*( level: LONGINT ); (* release lock *)
- BEGIN
- IF StrongChecks THEN
- ASSERT ( lock[level] ="Y", 1002 );
- ELSIF lock[level] # "Y" THEN
- Trace.String("warning: reentered non-reentrant lock"); Trace.Ln;
- END;
- lock[level] := "N";
- Kernel32.LeaveCriticalSection( cs[level] )
- END Release;
- (* added by Alexey *)
- PROCEDURE GetMemStatus(VAR stat: Kernel32.MemoryStatusEx): BOOLEAN;
- BEGIN
- stat.dwLength := 64;
- IF Kernel32.GlobalMemoryStatusEx(stat) = 1 THEN
- RETURN TRUE;
- ELSE
- RETURN FALSE;
- END;
- END GetMemStatus;
- (** dummy procedure to make GC work for both I386 and Win32 *)
- PROCEDURE GetKernelStacks*(VAR stack: ARRAY OF Stack);
- VAR i: LONGINT;
- BEGIN
- FOR i := 0 TO MaxCPU-1 DO
- stack[i].adr := NilVal;
- stack[i].high := NilVal
- END
- END GetKernelStacks;
- (* Set machine-dependent parameter gcThreshold *)
- PROCEDURE SetGCParams*;
- BEGIN
- gcThreshold := 10*1024*1024; (* 10 MB *)
- END SetGCParams;
- (* expand heap by allocating a new memory block - called during GC *)
- PROCEDURE InitHeap(VAR memoryBlock: MemoryBlock; VAR beginBlockAdr, endBlockAdr: ADDRESS);
- CONST MemBlockHeaderSize = BlockHeaderSize + RecordDescSize + BlockHeaderSize;
- TypeDescOffset = -AddressSize; (* see Heaps.Mod *)
- HeapBlockOffset = - 2 * AddressSize; (* see Heaps.Mod *)
- DataAdrOffset = AddressSize; (* offset of dataAdr field in Heaps.HeapBlockDesc *)
- VAR memDescSize, memBlkSize, alignOffset: SIZE; adr, memHeaderAdr, memBlockAdr, memBlockHeadAdr: ADDRESS;
- memBlock {UNTRACED}: MemoryBlock; i: LONGINT; ch: CHAR; h: HUGEINT; size: LONGINT;
- initVal: LONGINT;
- BEGIN
- (*
- HeapBlockPtr -- bootHeapAdr
- 4 Type
- 8 Mark
- 12 DataAdr
- 16 Size
- 20 HeapBlockPtr
- 24 Type
- 28 next -- MemoryBlock
- 32 startAdr
- 36 size
- 40 beginBlockAdr
- 44 endBlockAdr
- 48 --beginBlockAdr
- ....
- --endBlockAdr
- *)
- size := 1;
- memDescSize := MemBlockHeaderSize + SIZEOF(MemoryBlockDesc);
- INC(memDescSize, (-memDescSize) MOD StaticBlockSize); (* round up to multiple of StaticBlockSize *)
- INC(size, (-size) MOD StaticBlockSize); (* round up to multiple of StaticBlockSize *)
- memBlkSize := memDescSize + size + StaticBlockSize; (* add StaticBlockSize to account for alignments different from multiples of StaticBlockSize *)
- IF memBlkSize < MemBlockSize THEN memBlkSize := MemBlockSize END; (* MemBlockSize implicitly multiple of StaticBlockSize *)
- initVal := 8*1024*1024;
- adr := Kernel32.VirtualAlloc(initVal, memBlkSize, {Kernel32.MEMCommit, Kernel32.MEMReserve}, {Kernel32.PageExecuteReadWrite});
- IF adr = NilVal THEN (* allocation failed *)
- adr := Kernel32.VirtualAlloc(NilVal, memBlkSize, {Kernel32.MEMCommit}, {Kernel32.PageExecuteReadWrite});
- END;
- Trace.String("first heap block intVal "); Trace.Int(initVal,1); Trace.Ln;
- Trace.String("first heap block memBlkSize "); Trace.Int(memBlkSize,1); Trace.Ln;
- Trace.String("first heap block adr "); Trace.Int(adr,1); Trace.Ln;
- ASSERT(adr # 0);
- alignOffset := (-adr) MOD StaticBlockSize;
- memHeaderAdr := adr + alignOffset; (* force alignment of memory block start *)
- memBlockAdr := memHeaderAdr + MemBlockHeaderSize;
- memBlock := SYSTEM.VAL(MemoryBlock, memBlockAdr);
- beginBlockAdr := memHeaderAdr + memDescSize;
- memBlock.next := NIL;
- memBlock.startAdr := adr;
- memBlock.size := memBlkSize;
- beginBlockAdr := memHeaderAdr + memDescSize;
- endBlockAdr := adr + memBlkSize - alignOffset;
- memBlock.beginBlockAdr := beginBlockAdr;
- memBlock.endBlockAdr := endBlockAdr;
- (* correct fields *)
- SYSTEM.PUT(memBlockAdr + HeapBlockOffset, memHeaderAdr + BlockHeaderSize); (* set reference to header part of memory block correctly *)
- SYSTEM.PUT(memBlockAdr + TypeDescOffset, 0); (* set type descriptor field of memory block to default value, memory blocks are not traced by GC *)
- SYSTEM.PUT(memHeaderAdr + BlockHeaderSize + DataAdrOffset, memBlockAdr); (* set dataAdr of RecordBlockDesc to correct value *)
- SYSTEM.PUT(memHeaderAdr + BlockHeaderSize + 2*AddressSize , memBlkSize);
- (* fill first heap block *)
- SYSTEM.PUT(beginBlockAdr,0);
- SYSTEM.PUT(beginBlockAdr+AddressSize,0);
- SYSTEM.PUT(beginBlockAdr+2*AddressSize,0);
- (* change this when Heaps.HeapBlock is modified *)
- SYSTEM.PUT(beginBlockAdr+3*AddressSize,beginBlockAdr+7*AddressSize);
- SYSTEM.PUT(beginBlockAdr+4*AddressSize,endBlockAdr-beginBlockAdr);
- SYSTEM.PUT(beginBlockAdr+5*AddressSize,beginBlockAdr+2*AddressSize);
- SYSTEM.PUT(beginBlockAdr+6*AddressSize,0);
- memoryBlock := memBlock;
- END InitHeap;
- (** Get first memory block and first free address, the first free address is identical to memBlockHead.endBlockAdr *)
- PROCEDURE GetStaticHeap*(VAR beginBlockAdr, endBlockAdr, freeBlockAdr: ADDRESS);
- VAR memBlockAdr: ADDRESS;
- BEGIN
- InitHeap(memBlockHead,beginBlockAdr, endBlockAdr);
- memBlockTail := memBlockHead;
- (*
- SYSTEM.GET(bootHeapAdr + EndBlockOfs, freeBlockAdr);
- ASSERT(freeBlockAdr MOD StaticBlockSize = 0);
- memBlockAdr := bootHeapAdr + HeaderSize + MemoryBlockOfs;
- memBlockHead := SYSTEM.VAL(MemoryBlock, memBlockAdr); (* this block will never be freed since there is a global reference (initBlock in Heaps.Mod) to it *)
- memBlockHead.startAdr := bootHeapAdr;
- memBlockHead.size := bootHeapSize;
- ASSERT(memBlockHead.beginBlockAdr MOD StaticBlockSize = 0);
- ASSERT((memBlockHead.endBlockAdr - memBlockHead.beginBlockAdr) MOD StaticBlockSize = 0);
- memBlockTail := memBlockHead;
- *)
- beginBlockAdr := memBlockHead.beginBlockAdr;
- endBlockAdr := memBlockHead.endBlockAdr;
- freeBlockAdr := beginBlockAdr;
- END GetStaticHeap;
- (* returns if an address is a currently allocated heap address *)
- PROCEDURE ValidHeapAddress*(p: ADDRESS): BOOLEAN;
- BEGIN
- RETURN (p >= memBlockHead.beginBlockAdr) & (p <= memBlockTail.endBlockAdr)
- OR (p>=401000H) & (p<=ADDRESSOF(LastAddress))
- END ValidHeapAddress;
- PROCEDURE GetFreeK* (VAR total, lowFree, highFree: SIZE);
- VAR
- stat: Kernel32.MemoryStatusEx;
- BEGIN
- total := MAX(LONGINT); lowFree := 0; highFree := total;
- (*<< added by Alexey *)
- IF GetMemStatus(stat) THEN
- total := SHORT(stat.ullTotalVirtual DIV 1024);
- lowFree := 0;
- highFree := SHORT(stat.ullAvailVirtual DIV 1024);
- END;
- (* added by Alexey >>*)
- END GetFreeK;
- (* ug *)
- PROCEDURE TraceMemBlocks*;
- VAR memBlock {UNTRACED}: MemoryBlock; i : LONGINT;
- BEGIN
- memBlock := memBlockHead;
- i := 0;
- WHILE memBlock # NIL DO
- Trace.String("block "); Trace.Int(i, 0); Trace.String(": startAdr = "); Trace.Hex(memBlock.startAdr, 0);
- Trace.String(" size = "); Trace.Hex(memBlock.size, 0);
- Trace.String(" beginBlockAdr = "); Trace.Hex(memBlock.beginBlockAdr, 0);
- Trace.String(" endBlockAdr = "); Trace.Hex(memBlock.endBlockAdr, 0); Trace.Ln;
- memBlock := memBlock.next;
- INC(i)
- END
- END TraceMemBlocks;
- (* insert given memory block in sorted list of memory blocks, sort key is startAdr field - called during GC *)
- PROCEDURE InsertMemoryBlock(memBlock: MemoryBlock);
- VAR cur {UNTRACED}, prev {UNTRACED}: MemoryBlock;
- BEGIN
- cur := memBlockHead;
- prev := NIL;
- WHILE (cur # NIL) & (cur.startAdr < memBlock.startAdr) DO
- prev := cur;
- cur := cur.next
- END;
- IF prev = NIL THEN (* insert at head of list *)
- memBlock.next := memBlockHead;
- memBlockHead := memBlock
- ELSE (* insert in middle or at end of list *)
- memBlock.next := cur;
- prev.next := memBlock;
- IF cur = NIL THEN
- memBlockTail := memBlock
- END
- END
- END InsertMemoryBlock;
- (* expand heap by allocating a new memory block - called during GC *)
- PROCEDURE ExpandHeap*(dummy: LONGINT; size: SIZE; VAR memoryBlock: MemoryBlock; VAR beginBlockAdr, endBlockAdr: ADDRESS);
- CONST MemBlockHeaderSize = BlockHeaderSize + RecordDescSize + BlockHeaderSize;
- TypeDescOffset = -AddressSize; (* see Heaps.Mod *)
- HeapBlockOffset = - 2 * AddressSize; (* see Heaps.Mod *)
- DataAdrOffset = AddressSize; (* offset of dataAdr field in Heaps.HeapBlockDesc *)
- VAR memDescSize, memBlkSize, alignOffset: SIZE; adr, memHeaderAdr, memBlockAdr, memBlockHeadAdr: ADDRESS;
- memBlock {UNTRACED}: MemoryBlock; i: LONGINT; ch: CHAR; h: HUGEINT; initVal: SIZE;
- continue: BOOLEAN;
- BEGIN
- memDescSize := MemBlockHeaderSize + SIZEOF(MemoryBlockDesc);
- INC(memDescSize, (-memDescSize) MOD StaticBlockSize); (* round up to multiple of StaticBlockSize *)
- INC(size, (-size) MOD StaticBlockSize); (* round up to multiple of StaticBlockSize *)
- memBlkSize := memDescSize + size + StaticBlockSize; (* add StaticBlockSize to account for alignments different from multiples of StaticBlockSize *)
- INC(memBlkSize, (-memBlkSize) MOD MemBlockSize);
- initVal := memBlockTail.startAdr + memBlockTail.size;
- adr := Kernel32.VirtualAlloc(initVal, memBlkSize, {Kernel32.MEMCommit, Kernel32.MEMReserve}, {Kernel32.PageExecuteReadWrite});
- IF adr = NilVal THEN (* allocation failed *)
- adr := Kernel32.VirtualAlloc(NilVal, memBlkSize, {Kernel32.MEMCommit}, {Kernel32.PageExecuteReadWrite});
- END;
- continue := adr = initVal;
- Trace.String("expand heap block intVal "); Trace.Int(initVal,1); Trace.Ln;
- Trace.String("expand heap block memBlkSize "); Trace.Int(memBlkSize,1); Trace.Ln;
- Trace.String("expand heap block adr "); Trace.Int(adr,1); Trace.Ln;
- ASSERT(adr # 0);
- IF adr # 0 THEN
- alignOffset := (-adr) MOD StaticBlockSize;
- IF continue THEN
- memBlock := memBlockTail;
- memBlock.size := memBlock.size + memBlkSize;
- beginBlockAdr := memBlockTail.endBlockAdr;
- endBlockAdr := beginBlockAdr;
- INC(endBlockAdr, memBlkSize);
- ELSE
- memHeaderAdr := adr + alignOffset; (* force alignment of memory block start *)
- memBlockAdr := memHeaderAdr + MemBlockHeaderSize;
- memBlock := SYSTEM.VAL(MemoryBlock, memBlockAdr);
- memBlock.next := NIL;
- memBlock.startAdr := adr;
- memBlock.size := memBlkSize;
- beginBlockAdr := memHeaderAdr + memDescSize;
- endBlockAdr := adr + memBlkSize - alignOffset;
- memBlock.beginBlockAdr := beginBlockAdr;
- memBlock.endBlockAdr := beginBlockAdr;
- (* upon memory block insertion memBlock.beginBlockAdr = memBlock.endBlockAdr to denote that the memory block has no valid heap blocks yet
- - necessary for real-time GC. Memory block end address is set by caller by using SetMemBlockEndAddress after fitting free block in. *)
- (* copy header of memBlockHead to header of memBlock - byte by byte *)
- memBlockHeadAdr := SYSTEM.VAL(ADDRESS, memBlockHead);
- FOR i := 0 TO MemBlockHeaderSize - 1 DO
- SYSTEM.GET(memBlockHeadAdr - MemBlockHeaderSize + i, ch);
- SYSTEM.PUT(memBlockAdr - MemBlockHeaderSize + i, ch)
- END;
- (* correct fields *)
- SYSTEM.PUT(memBlockAdr + HeapBlockOffset, memHeaderAdr + BlockHeaderSize); (* set reference to header part of memory block correctly *)
- SYSTEM.PUT(memBlockAdr + TypeDescOffset, 0); (* set type descriptor field of memory block to default value, memory blocks are not traced by GC *)
- SYSTEM.PUT(memHeaderAdr + BlockHeaderSize + DataAdrOffset, memBlockAdr); (* set dataAdr of RecordBlockDesc to correct value *)
- InsertMemoryBlock(memBlock);
- END;
- memoryBlock := memBlock;
- ELSE
- beginBlockAdr := 0; endBlockAdr := 0;
- END;
- END ExpandHeap;
- (* Set memory block end address *)
- PROCEDURE SetMemoryBlockEndAddress*(memBlock: MemoryBlock; endBlockAdr: ADDRESS);
- BEGIN
- ASSERT(endBlockAdr >= memBlock.beginBlockAdr);
- memBlock.endBlockAdr := endBlockAdr
- END SetMemoryBlockEndAddress;
- (* Free unused memory block - called during GC *)
- PROCEDURE FreeMemBlock*(memBlock: MemoryBlock);
- VAR cur {UNTRACED}, prev {UNTRACED}: MemoryBlock;
- startAdr: ADDRESS;
- BEGIN
- cur := memBlockHead;
- prev := NIL;
- WHILE (cur # NIL) & (cur # memBlock) DO
- prev := cur;
- cur := cur.next
- END;
- IF cur = memBlock THEN
- IF prev = NIL THEN
- memBlockHead := cur.next;
- ELSE
- prev.next := cur.next;
- IF prev.next = NIL THEN
- memBlockTail := prev
- END
- END;
- memBlock.next := NIL;
- startAdr := memBlock.startAdr; (* this value must be cached for the second call of Kernel32.VirtualFree *)
- Kernel32.VirtualFree(SYSTEM.VAL(LONGINT, memBlock.startAdr), memBlock.size, {Kernel32.MEMDecommit});
- Kernel32.VirtualFree(SYSTEM.VAL(LONGINT, startAdr ), 0, {Kernel32.MEMRelease});
- ELSE
- HALT(535) (* error in memory block management *)
- END;
- END FreeMemBlock;
- PROCEDURE PhysicalAdr*(adr: ADDRESS; size: SIZE): ADDRESS;
- END PhysicalAdr;
- (* function returning the number of processors that are available to Aos *)
- PROCEDURE NumberOfProcessors*( ): LONGINT;
- VAR info: Kernel32.SystemInfo;
- BEGIN
- Kernel32.GetSystemInfo( info );
- RETURN info.dwNumberOfProcessors
- END NumberOfProcessors;
- (* function for changing byte order *)
- PROCEDURE ChangeByteOrder* (n: LONGINT): LONGINT;
- CODE { SYSTEM.Pentium }
- MOV EAX, [EBP+n] ; load n in eax
- BSWAP EAX ; swap byte order
- END ChangeByteOrder;
- PROCEDURE TraceColor (c: SHORTINT);
- END TraceColor;
- PROCEDURE LogChar (c: CHAR);
- VAR trace: ARRAY 2 OF CHAR;
- BEGIN trace[0] := c; trace[1] := 0X; Kernel32.OutputString (trace);
- END LogChar;
- PROCEDURE -GetRAX*(): HUGEINT;
- CODE{SYSTEM.AMD64}
- END GetRAX;
- PROCEDURE -GetRCX*(): HUGEINT;
- CODE{SYSTEM.AMD64}
- MOV RAX,RCX
- END GetRCX;
- PROCEDURE -GetRSI*(): HUGEINT;
- CODE{SYSTEM.AMD64}
- MOV RAX,RSI
- END GetRSI;
- PROCEDURE -GetRDI*(): HUGEINT;
- CODE{SYSTEM.AMD64}
- MOV RAX,RDI
- END GetRDI;
- PROCEDURE -SetRAX*(n: HUGEINT);
- CODE{SYSTEM.AMD64}
- NOP
- POP RAX
- END SetRAX;
- PROCEDURE -SetRBX*(n: HUGEINT);
- CODE{SYSTEM.AMD64}
- NOP
- POP RBX
- END SetRBX;
- PROCEDURE -SetRCX*(n: HUGEINT);
- CODE{SYSTEM.AMD64}
- POP RCX
- END SetRCX;
- PROCEDURE -SetRDX*(n: HUGEINT);
- CODE{SYSTEM.AMD64}
- POP RDX
- END SetRDX;
- PROCEDURE -SetRSI*(n: HUGEINT);
- CODE{SYSTEM.AMD64}
- POP RSI
- END SetRSI;
- PROCEDURE -SetRDI*(n: HUGEINT);
- CODE{SYSTEM.AMD64}
- POP RDI
- END SetRDI;
- PROCEDURE Portin8*(port: LONGINT; VAR val: CHAR);
- CODE{SYSTEM.i386}
- MOV EDX,[EBP+port]
- IN AL, DX
- MOV ECX, [EBP+val]
- MOV [ECX], AL
- END Portin8;
- PROCEDURE Portin16*(port: LONGINT; VAR val: INTEGER);
- CODE{SYSTEM.i386}
- MOV EDX,[EBP+port]
- IN AX, DX
- MOV ECX, [EBP+val]
- MOV [ECX], AX
- END Portin16;
- PROCEDURE Portin32*(port: LONGINT; VAR val: LONGINT);
- CODE{SYSTEM.i386}
- MOV EDX,[EBP+port]
- IN EAX, DX
- MOV ECX, [EBP+val]
- MOV [ECX], EAX
- END Portin32;
- PROCEDURE Portout8*(port: LONGINT; val: CHAR);
- CODE{SYSTEM.i386}
- MOV AL,[EBP+val]
- MOV EDX,[EBP+port]
- OUT DX,AL
- END Portout8;
- PROCEDURE Portout16*(port: LONGINT; val: INTEGER);
- CODE{SYSTEM.i386}
- MOV AX,[EBP+val]
- MOV EDX,[EBP+port]
- OUT DX,AX
- END Portout16;
- PROCEDURE Portout32*(port: LONGINT; val: LONGINT);
- CODE{SYSTEM.i386}
- MOV EAX,[EBP+val]
- MOV EDX,[EBP+port]
- OUT DX,EAX
- END Portout32;
- BEGIN
- IF ~Kernel32.Generic THEN
- Init
- END;
- Trace.String("Machine (64 bit)"); Trace.Ln;
- END Machine.
|