MODULE Machine;
IMPORT SYSTEM, Trace, Kernel32;
CONST
Version = "WinAos Revision 4634 (12.03.2012)";
DefaultConfigFile = "aos.ini";
UserConfigFile = "myaos.ini";
MaxCPU* = 8;
DefaultObjectFileExtension* = ".Obw";
MTTR* = 12; MMX* = 23;
debug* = FALSE;
CONST
AddressSize = SYSTEM.SIZEOF(SYSTEM.ADDRESS);
StaticBlockSize = 32;
BlockHeaderSize = 2 * AddressSize;
RecordDescSize = 4 * AddressSize;
TraceOutput* = 0;
Memory* = 1;
Heaps* = 2;
Interrupts* = 3;
Modules* = 4;
Objects* = 5;
Processors* = 6;
KernelLog* = 7;
GC* = 8;
MaxLocks = 9;
StrongChecks = FALSE;
HeaderSize = 40H;
EndBlockOfs = 38H;
MemoryBlockOfs = BlockHeaderSize + RecordDescSize + BlockHeaderSize;
MemBlockSize = 8*1024*1024;
MinMemBlockSize = 4*1024*1024;
NilVal = 0;
Second* = 1000;
CONST
Ok* = 0;
NilAdr* = -1;
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-: SYSTEM.ADDRESS;
size-: SYSTEM.SIZE;
beginBlockAdr-, endBlockAdr-: SYSTEM.ADDRESS
END;
Stack* = RECORD
low: SYSTEM.ADDRESS;
adr*: SYSTEM.ADDRESS;
high*: SYSTEM.ADDRESS;
END;
VAR
MMXSupport*: BOOLEAN;
SSESupport*: BOOLEAN;
SSE2Support*: BOOLEAN;
SSE3Support-: BOOLEAN;
SSSE3Support-: BOOLEAN;
SSE41Support-: BOOLEAN;
SSE42Support-: BOOLEAN;
SSE5Support-: BOOLEAN;
AVXSupport-: BOOLEAN;
hInstance-: Kernel32.HINSTANCE;
isEXE-: BOOLEAN; locks*: LONGINT;
version*: ARRAY 64 OF CHAR;
features*,features2*: SET;
fcr*: SET;
mhz*: HUGEINT;
boottime-: HUGEINT;
commandLine-: ARRAY 256 OF CHAR;
hin, hout: Kernel32.HANDLE;
VAR
lock-: ARRAY MaxLocks OF CHAR;
cs: ARRAY MaxLocks OF Kernel32.CriticalSection;
trace: ARRAY 2 OF CHAR;
defaultConfigFile, userConfigFile, traceName: ARRAY Kernel32.MaxPath OF CHAR;
gcThreshold-: SYSTEM.SIZE;
bootHeapAdr: SYSTEM.ADDRESS;
bootHeapSize: SYSTEM.SIZE;
memBlockHead-{UNTRACED}, memBlockTail-{UNTRACED}: MemoryBlock;
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;
IF hex THEN vd := vh END;
RETURN sgn * vd
END StrToInt;
PROCEDURE -Inc*( VAR x: LONGINT );
CODE {SYSTEM.i386}
POP EAX
LOCK
INC DWORD[EAX]
END Inc;
PROCEDURE Excl*( VAR s: SET; bit: LONGINT );
CODE {SYSTEM.i386}
MOV EAX, [EBP+bit]
MOV EBX, [EBP+s]
LOCK
BTR [EBX], EAX
END Excl;
PROCEDURE -SpinHint*;
CODE {SYSTEM.i386}
XOR ECX, ECX ; just in case some processor interprets REP this way
REP NOP ; PAUSE instruction
END SpinHint;
PROCEDURE CurrentPC* (): SYSTEM.ADDRESS;
CODE {SYSTEM.i386}
MOV EAX, [EBP+4]
END CurrentPC;
PROCEDURE -CurrentBP* (): SYSTEM.ADDRESS;
CODE {SYSTEM.i386}
MOV EAX, EBP
END CurrentBP;
PROCEDURE -SetBP* (bp: SYSTEM.ADDRESS);
CODE {SYSTEM.i386}
POP EBP
END SetBP;
PROCEDURE -CurrentSP* (): SYSTEM.ADDRESS;
CODE {SYSTEM.i386}
MOV EAX, ESP
END CurrentSP;
PROCEDURE -SetSP* (sp: SYSTEM.ADDRESS);
CODE {SYSTEM.i386}
POP ESP
END SetSP;
PROCEDURE -LessThan* (a, b: SYSTEM.ADDRESS): BOOLEAN;
CODE {SYSTEM.i386}
POP EBX
POP EAX
CMP EAX, EBX
SETB AL
END LessThan;
PROCEDURE -LessOrEqual* (a, b: SYSTEM.ADDRESS): BOOLEAN;
CODE {SYSTEM.i386}
POP EBX
POP EAX
CMP EAX, EBX
SETBE AL
END LessOrEqual;
PROCEDURE -GreaterThan* (a, b: SYSTEM.ADDRESS): BOOLEAN;
CODE {SYSTEM.i386}
POP EBX
POP EAX
CMP EAX, EBX
SETA AL
END GreaterThan;
PROCEDURE -GreaterOrEqual* (a, b: SYSTEM.ADDRESS): BOOLEAN;
CODE {SYSTEM.i386}
POP EBX
POP EAX
CMP EAX, EBX
SETAE AL
END GreaterOrEqual;
PROCEDURE Fill32*( destAdr, size, filler: LONGINT );
CODE {SYSTEM.i386}
MOV EDI, [EBP+destAdr]
MOV ECX, [EBP+size]
MOV EAX, [EBP+filler]
TEST ECX, 3
JZ ok
PUSH 8 ; ASSERT failure
INT 3
ok:
SHR ECX, 2
CLD
REP STOSD
END Fill32;
PROCEDURE MulH* (h, g: HUGEINT): HUGEINT;
CODE {SYSTEM.i386}
MOV EDX, [EBP+12] ; y_hi
MOV ECX, [EBP+20] ; x_hi
OR EDX, ECX ; are x_hi and y_hi both zeros?
MOV EDX, [EBP+16] ; x_lo
MOV EAX, [EBP+8] ; y_lo
JNZ fullMul ; yes, requires full multiplication
MUL EDX ; EDX:EAX := y_lo * x_lo
JMP exit ; done, return to caller
fullMul: ; full multiplication is required
MUL ECX ; EAX := LO(y_lo*x_hi)
MOV EBX, EAX ; keep the result
MOV EAX, [EBP+12] ; y_hi
MUL DWORD [EBP+16] ; EAX := LO(y_hi*x_lo)
ADD EBX, EAX ; EBX := LO(y_lo*x_hi) + LO(y_hi*x_lo)
MOV EAX, [EBP+8] ; y_lo
MUL DWORD [EBP+16] ; EDX := HI(y_lo*x_lo), EAX := LO(y_lo*x_lo)
ADD EDX, EBX ; EDX := y_lo*x_hi + y_hi*x_lo + HI(y_lo*x_lo)
exit:
END MulH;
PROCEDURE DivH* (x, y: HUGEINT): HUGEINT;
CODE {SYSTEM.i386}
MOV ECX, [EBP+12] ; y-hi
MOV EBX, [EBP+8] ; y-lo
MOV EDX, [EBP+20] ; x-hi
MOV EAX, [EBP+16] ; x-lo
MOV ESI, ECX ; y-hi
XOR ESI, EDX ; y-hi ^ x-hi
SAR ESI, 31 ; (quotient < 0) ? -1 : 0
MOV EDI, EDX ; x-hi
SAR EDI, 31 ; (x < 0) ? -1 : 0
XOR EAX, EDI ; if (x < 0)
XOR EDX, EDI ; compute 1s complement of x
SUB EAX, EDI ; if (x < 0)
SBB EDX, EDI ; compute 2s complement of x
MOV EDI, ECX ; y-hi
SAR EDI, 31 ; (y < 0) ? -1 : 0
XOR EBX, EDI ; if (y < 0)
XOR ECX, EDI ; compute 1s complement of y
SUB EBX, EDI ; if (y < 0)
SBB ECX, EDI ; compute 2s complement of y
JNZ bigDivisor ; y > 2^32-1
CMP EDX, EBX ; only one division needed ? (ECX = 0)
JAE twoDivs ; need two divisions
DIV EBX ; EAX = quotient-lo
MOV EDX, ECX ; EDX = quotient-hi = 0
; quotient in EDX:EAX
XOR EAX, ESI ; if (quotient < 0)
XOR EDX, ESI ; compute 1s complement of result
SUB EAX, ESI ; if (quotient < 0)
SBB EDX, ESI ; compute 2s complement of result
JMP exit ; done, return to caller
twoDivs:
MOV ECX, EAX ; save x-lo in ECX
MOV EAX, EDX ; get x-hi
XOR EDX, EDX ; zero extend it into EDX:EAX
DIV EBX ; quotient-hi in EAX
XCHG EAX, ECX ; ECX = quotient-hi, EAX = x-lo
DIV EBX ; EAX = quotient-lo
MOV EDX, ECX ; EDX = quotient-hi
; quotient in EDX:EAX
JMP makeSign ; make quotient signed
bigDivisor:
SUB ESP, 12 ; create three local variables
MOV [ESP], EAX ; x-lo
MOV [ESP+4], EBX ; y-lo
MOV [ESP+8], EDX ; x-hi
MOV EDI, ECX ; save y-hi
SHR EDX, 1 ; shift both
RCR EAX, 1 ; y and
ROR EDI, 1 ; and x
RCR EBX, 1 ; right by 1 bit
BSR ECX, ECX ; ECX = number of remaining shifts
SHRD EBX, EDI, CL ; scale down y and
SHRD EAX, EDX, CL ; x such that y
SHR EDX, CL ; less than 2^32 (i.e. fits in EBX)
ROL EDI, 1 ; restore original y-hi
DIV EBX ; compute quotient
MOV EBX, [ESP] ; x-lo
MOV ECX, EAX ; save quotient
IMUL EDI, EAX ; quotient * y hi-word (low only)
MUL DWORD [ESP+4] ; quotient * y lo-word
ADD EDX, EDI ; EDX:EAX = quotient * y
SUB EBX, EAX ; x-lo - (quot.*y)-lo
MOV EAX, ECX ; get quotient
MOV ECX, [ESP+8] ; x-hi
SBB ECX, EDX ; subtract y * quot. from x
SBB EAX, 0 ; adjust quotient if remainder negative
XOR EDX, EDX ; clear hi-word of quotient
ADD ESP, 12 ; remove local variables
makeSign:
XOR EAX, ESI ; if (quotient < 0)
XOR EDX, ESI ; compute 1s complement of result
SUB EAX, ESI ; if (quotient < 0)
SBB EDX, ESI ; compute 2s complement of result
exit:
END DivH;
PROCEDURE -ASHH*( h: HUGEINT; n: LONGINT ): HUGEINT;
CODE {SYSTEM.i386}
POP ECX
POP EAX
POP EDX
CMP ECX, 0
JL right
AND ECX, 63 ; limit count, like ASH
JZ exit
ll:
SHL EAX, 1
RCL EDX, 1
DEC ECX
JNZ ll
JMP exit
right:
NEG ECX
AND ECX, 63 ; limit count, like ASH
JZ exit
lr:
SAR EDX, 1
RCR EAX, 1
DEC ECX
JNZ lr
exit:
END ASHH;
PROCEDURE -LInt2ToHInt*( high, low: LONGINT ): HUGEINT;
CODE {SYSTEM.i386}
POP EAX
POP EDX
END LInt2ToHInt;
PROCEDURE -HIntToLReal*( h: HUGEINT ): LONGREAL;
CODE {SYSTEM.i386, SYSTEM.FPU}
FILD QWORD[ESP]
FWAIT
ADD ESP, 8
END HIntToLReal;
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;
PROCEDURE SetupFPU*;
BEGIN
InitFPU; SetFCR( fcr )
END SetupFPU;
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;
END GetConfig;
PROCEDURE Shutdown*( restart: BOOLEAN );
BEGIN
ASSERT ( locks <= 0 );
IF locks = MIN( LONGINT ) THEN RETURN END;
locks := MIN( LONGINT ); Trace.StringLn ( "Machine.Shutdown" );
RemoveTraceFile;
Kernel32.Shutdown( 0 );
END Shutdown;
PROCEDURE -GetTimer*(): HUGEINT;
CODE {SYSTEM.Pentium}
RDTSC ; set EDX:EAX
END GetTimer;
PROCEDURE ID*(): LONGINT;
BEGIN
RETURN 0
END ID;
PROCEDURE SetupSSE2Ext;
CONST
MMXFlag=23;
FXSRFlag = 24;
SSEFlag = 25;
SSE2Flag = 26;
SSE3Flag = 0;
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);
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
END;
END SetupSSE2Ext;
PROCEDURE ReadCommandLine(VAR commandLine: ARRAY OF CHAR);
VAR adr: SYSTEM.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
INC(i);
IF CheckName("ini") THEN SkipSpaces; ReadName(iniFile) END;
END;
END ParseLine;
PROCEDURE TraceChar(c: CHAR);
VAR len: LONGINT;
BEGIN
len := 1;
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);
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);
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;
END;
END RemoveTraceFile;
PROCEDURE Init;
VAR vendor: Vendor; ver: LONGINT;
BEGIN
boottime:=GetTimer();
locks := 0;
IF hInstance = Kernel32.NULL THEN
hInstance := Kernel32.GetModuleHandle( NIL ); isEXE := TRUE
ELSE isEXE := FALSE
END;
COPY( Version, version );
CPUID(vendor, ver, features,features2); SetupSSE2Ext;
fcr := (FCR() - {0,2,3,10,11}) + {0..5,8,9};
ReadCommandLine(commandLine);
defaultConfigFile[Kernel32.GetFullPathName (DefaultConfigFile, Kernel32.MaxPath, defaultConfigFile, 0)] := 0X;
userConfigFile := UserConfigFile;
ParseLine(commandLine, userConfigFile);
userConfigFile[Kernel32.GetFullPathName (userConfigFile, Kernel32.MaxPath, userConfigFile, 0)] := 0X;
Trace.String("config file = "); Trace.String(userConfigFile); Trace.Ln;
traceName[0] := 0X;
GetConfig("Trace",traceName);
IF traceName = "File" THEN
traceName := "SystemTrace.txt";
SetupTraceName(traceName);
SetTraceFile(traceName);
ELSIF traceName = "Console" THEN SetTraceConsole
END;
END Init;
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;
PROCEDURE Acquire*( level: LONGINT );
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;
PROCEDURE Release*( level: LONGINT );
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;
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;
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;
PROCEDURE SetGCParams*;
BEGIN
gcThreshold := 10*1024*1024;
END SetGCParams;
PROCEDURE InitHeap(VAR memoryBlock: MemoryBlock; VAR beginBlockAdr, endBlockAdr: SYSTEM.ADDRESS);
CONST MemBlockHeaderSize = BlockHeaderSize + RecordDescSize + BlockHeaderSize;
TypeDescOffset = -AddressSize;
HeapBlockOffset = - 2 * AddressSize;
DataAdrOffset = AddressSize;
VAR memDescSize, memBlkSize, alignOffset: SYSTEM.SIZE; adr, memHeaderAdr, memBlockAdr, memBlockHeadAdr: SYSTEM.ADDRESS;
memBlock {UNTRACED}: MemoryBlock; i: LONGINT; ch: CHAR; h: HUGEINT; size: LONGINT;
initVal: LONGINT;
BEGIN
size := 1;
memDescSize := MemBlockHeaderSize + SYSTEM.SIZEOF(MemoryBlockDesc);
INC(memDescSize, (-memDescSize) MOD StaticBlockSize);
INC(size, (-size) MOD StaticBlockSize);
memBlkSize := memDescSize + size + StaticBlockSize;
IF memBlkSize < MemBlockSize THEN memBlkSize := MemBlockSize END;
initVal := 8*1024*1024;
adr := Kernel32.VirtualAlloc(initVal, memBlkSize, {Kernel32.MEMCommit, Kernel32.MEMReserve}, {Kernel32.PageExecuteReadWrite});
IF adr = NilVal THEN
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);
IF adr > 0 THEN
alignOffset := (-adr) MOD StaticBlockSize;
ELSE
h := LONG(adr)+100000000H;
alignOffset := SHORT(-h MOD StaticBlockSize);
END;
memHeaderAdr := adr + alignOffset;
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;
SYSTEM.PUT(memBlockAdr + HeapBlockOffset, memHeaderAdr + BlockHeaderSize);
SYSTEM.PUT(memBlockAdr + TypeDescOffset, 0);
SYSTEM.PUT(memHeaderAdr + BlockHeaderSize + DataAdrOffset, memBlockAdr);
SYSTEM.PUT(memHeaderAdr + BlockHeaderSize + 2*AddressSize , memBlkSize);
SYSTEM.PUT(beginBlockAdr,0);
SYSTEM.PUT(beginBlockAdr+AddressSize,0);
SYSTEM.PUT(beginBlockAdr+2*AddressSize,0);
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;
PROCEDURE GetStaticHeap*(VAR beginBlockAdr, endBlockAdr, freeBlockAdr: SYSTEM.ADDRESS);
VAR memBlockAdr: SYSTEM.ADDRESS;
BEGIN
InitHeap(memBlockHead,beginBlockAdr, endBlockAdr);
memBlockTail := memBlockHead;
beginBlockAdr := memBlockHead.beginBlockAdr;
endBlockAdr := memBlockHead.endBlockAdr;
freeBlockAdr := beginBlockAdr;
END GetStaticHeap;
PROCEDURE ValidHeapAddress*(p: SYSTEM.ADDRESS): BOOLEAN;
BEGIN
RETURN GreaterOrEqual(p,memBlockHead.beginBlockAdr) & LessOrEqual(p,memBlockTail.endBlockAdr)
OR (p>=401000H) & (p<=500000H)
END ValidHeapAddress;
PROCEDURE GetFreeK* (VAR total, lowFree, highFree: SYSTEM.SIZE);
VAR
stat: Kernel32.MemoryStatusEx;
BEGIN
total := MAX(LONGINT); lowFree := 0; highFree := total;
IF GetMemStatus(stat) THEN
total := SHORT(stat.ullTotalVirtual DIV 1024);
lowFree := 0;
highFree := SHORT(stat.ullAvailVirtual DIV 1024);
END;
END GetFreeK;
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;
PROCEDURE InsertMemoryBlock(memBlock: MemoryBlock);
VAR cur {UNTRACED}, prev {UNTRACED}: MemoryBlock;
BEGIN
cur := memBlockHead;
prev := NIL;
WHILE (cur # NIL) & LessThan(cur.startAdr, memBlock.startAdr) DO
prev := cur;
cur := cur.next
END;
IF prev = NIL THEN
memBlock.next := memBlockHead;
memBlockHead := memBlock
ELSE
memBlock.next := cur;
prev.next := memBlock;
IF cur = NIL THEN
memBlockTail := memBlock
END
END
END InsertMemoryBlock;
PROCEDURE ExpandHeap*(dummy: LONGINT; size: SYSTEM.SIZE; VAR memoryBlock: MemoryBlock; VAR beginBlockAdr, endBlockAdr: SYSTEM.ADDRESS);
CONST MemBlockHeaderSize = BlockHeaderSize + RecordDescSize + BlockHeaderSize;
TypeDescOffset = -AddressSize;
HeapBlockOffset = - 2 * AddressSize;
DataAdrOffset = AddressSize;
VAR memDescSize, memBlkSize, alignOffset: SYSTEM.SIZE; adr, memHeaderAdr, memBlockAdr, memBlockHeadAdr: SYSTEM.ADDRESS;
memBlock {UNTRACED}: MemoryBlock; i: LONGINT; ch: CHAR; h: HUGEINT; initVal: LONGINT;
continue: BOOLEAN;
BEGIN
memDescSize := MemBlockHeaderSize + SYSTEM.SIZEOF(MemoryBlockDesc);
INC(memDescSize, (-memDescSize) MOD StaticBlockSize);
INC(size, (-size) MOD StaticBlockSize);
memBlkSize := memDescSize + size + StaticBlockSize;
IF memBlkSize < MinMemBlockSize THEN memBlkSize := MemBlockSize END;
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
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
IF adr > 0 THEN
alignOffset := (-adr) MOD StaticBlockSize;
ELSE
h := LONG(adr)+100000000H;
alignOffset := SHORT(-h MOD StaticBlockSize);
END;
IF continue THEN
memBlock := memBlockTail;
memBlock.size := memBlock.size + memBlkSize;
beginBlockAdr := memBlockTail.endBlockAdr;
endBlockAdr := beginBlockAdr;
INC(endBlockAdr, memBlkSize);
ELSE
memHeaderAdr := adr + alignOffset;
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;
memBlockHeadAdr := SYSTEM.VAL(SYSTEM.ADDRESS, memBlockHead);
FOR i := 0 TO MemBlockHeaderSize - 1 DO
SYSTEM.GET(memBlockHeadAdr - MemBlockHeaderSize + i, ch);
SYSTEM.PUT(memBlockAdr - MemBlockHeaderSize + i, ch)
END;
SYSTEM.PUT(memBlockAdr + HeapBlockOffset, memHeaderAdr + BlockHeaderSize);
SYSTEM.PUT(memBlockAdr + TypeDescOffset, 0);
SYSTEM.PUT(memHeaderAdr + BlockHeaderSize + DataAdrOffset, memBlockAdr);
InsertMemoryBlock(memBlock);
END;
memoryBlock := memBlock;
ELSE
beginBlockAdr := 0; endBlockAdr := 0;
END;
END ExpandHeap;
PROCEDURE SetMemoryBlockEndAddress*(memBlock: MemoryBlock; endBlockAdr: SYSTEM.ADDRESS);
BEGIN
ASSERT(GreaterOrEqual(endBlockAdr,memBlock.beginBlockAdr));
memBlock.endBlockAdr := endBlockAdr
END SetMemoryBlockEndAddress;
PROCEDURE FreeMemBlock*(memBlock: MemoryBlock);
VAR cur {UNTRACED}, prev {UNTRACED}: MemoryBlock;
startAdr: SYSTEM.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;
Kernel32.VirtualFree(SYSTEM.VAL(LONGINT, memBlock.startAdr), memBlock.size, {Kernel32.MEMDecommit});
Kernel32.VirtualFree(SYSTEM.VAL(LONGINT, startAdr ), 0, {Kernel32.MEMRelease});
ELSE
HALT(535)
END;
END FreeMemBlock;
PROCEDURE PhysicalAdr*(adr: SYSTEM.ADDRESS; size: SYSTEM.SIZE): SYSTEM.ADDRESS;
END PhysicalAdr;
PROCEDURE -AtomicInc*( VAR x: LONGINT );
CODE {SYSTEM.i386}
POP EAX
LOCK
INC DWORD[EAX]
END AtomicInc;
PROCEDURE -AtomicDec*( VAR x: LONGINT );
CODE {SYSTEM.i386}
POP EAX
LOCK
DEC DWORD[EAX]
END AtomicDec;
PROCEDURE -AtomicAdd*( VAR x: LONGINT; y: LONGINT );
CODE {SYSTEM.i386}
POP EBX
POP EAX
LOCK
ADD DWORD[EAX], EBX
END AtomicAdd;
PROCEDURE -AtomicTestSet*( VAR x: BOOLEAN ): BOOLEAN;
CODE {SYSTEM.i386}
POP EBX
MOV AL, 1
XCHG [EBX], AL
END AtomicTestSet;
PROCEDURE -AtomicCAS* (VAR x: LONGINT; old, new: LONGINT): LONGINT;
CODE {SYSTEM.i386}
POP EBX ; new
POP EAX ; old
POP ECX ; address of x
DB 0F0X, 00FX, 0B1X, 019X ; LOCK CMPXCHG [ECX], EBX; atomicly compare x with old and set it to new if equal
END AtomicCAS;
PROCEDURE NumberOfProcessors*( ): LONGINT;
VAR info: Kernel32.SystemInfo;
BEGIN
Kernel32.GetSystemInfo( info );
RETURN info.dwNumberOfProcessors
END NumberOfProcessors;
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);
BEGIN trace[0] := c; Kernel32.OutputString (trace);
END LogChar;
PROCEDURE -GetEAX*(): LONGINT;
CODE{SYSTEM.i386}
END GetEAX;
PROCEDURE -GetECX*(): LONGINT;
CODE{SYSTEM.i386}
MOV EAX,ECX
END GetECX;
PROCEDURE -SetEAX*(n: LONGINT);
CODE{SYSTEM.i386} POP EAX
END SetEAX;
PROCEDURE -SetEBX*(n: LONGINT);
CODE{SYSTEM.i386}
POP EBX
END SetEBX;
PROCEDURE -SetECX*(n: LONGINT);
CODE{SYSTEM.i386}
POP ECX
END SetECX;
PROCEDURE -SetEDX*(n: LONGINT);
CODE{SYSTEM.i386}
POP EDX
END SetEDX;
PROCEDURE -SetESI*(n: LONGINT);
CODE{SYSTEM.i386}
POP ESI
END SetESI;
PROCEDURE -SetEDI*(n: LONGINT);
CODE{SYSTEM.i386}
POP EDI
END SetEDI;
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
trace[1] := 0X; Trace.Char := LogChar; Trace.Color := TraceColor;
InitLocks();
Init;
END Machine.