MODULE Machine;
IMPORT SYSTEM, Trace;
CONST
Version = "A2 Revision 2958 (26.02.2010)";
MaxCPU* = 8;
DefaultObjectFileExtension* = ".Abx";
MTTR* = 12; MMX* = 23; HTT* = 28;
MaxDisks = 2;
HeapAdr = 100000H;
MaxMemTop = 4000000H * 4000000H;
DefaultDMASize = 20;
CONST
StrongChecks = FALSE;
Stats* = FALSE;
TimeCount = 0 ;
TraceOutput* = 0;
Memory* = 1;
Heaps* = 2;
Interrupts* = 3 ;
Modules* = 4;
Objects* = 5;
Processors* = 6;
KernelLog* = 7;
Preemption* = 31;
MaxLocks = 8;
LowestLock = 0; HighestLock = MaxLocks-1;
CONST
TraceVerbose = FALSE;
AddressSize = SYSTEM.SIZEOF(SYSTEM.ADDRESS);
SetSize = MAX (SET) + 1;
Ok* = 0;
K = 1024; M = 100000H;
PS = 4096;
PSlog2 = 12;
TPS = 4096;
PTEs = TPS DIV AddressSize;
RS = PTEs * PS;
ReservedPages = 8;
NilAdr* = -1;
NodeSP = 0;
NodeNext = AddressSize;
NodePrev = AddressSize*2;
MinSP = AddressSize*3; MaxSP = PS;
MapAreaAdr = SHORT(80000000H);
MapAreaSize = 64*M;
IntelAreaAdr = SHORT(0FEE00000H);
IntelAreaSize = 00001000H;
StackAreaAdr = MapAreaAdr+MapAreaSize;
StackAreaSize = IntelAreaAdr-StackAreaAdr;
KernelStackSize = 2*PS;
MaxUserStackSize = 128*K;
InitUserStackSize = PS;
UserStackGuardSize = PS;
MaxUserStacks = StackAreaSize DIV MaxUserStackSize;
LowAdr = PS;
LinkAdr = M;
StaticBlockSize = 32;
BlockHeaderSize = 2 * AddressSize;
RecordDescSize = 3 * AddressSize;
TSSOfs = 8;
StackOfs = TSSOfs + MaxCPU;
GDTSize = TSSOfs + MaxCPU * 2;
Kernel32CodeSel = 1*8;
Kernel64CodeSel = 2*8;
User32CodeSel = 3*8 + 3;
User64CodeSel = 4*8 + 3;
KernelStackSel = 5*8;
UserStackSel = 6*8 + 3;
DataSel = 7*8;
KernelTR = TSSOfs*8;
PageNotPresent = 0;
KernelPage = 3;
UserPage = 7;
HeapMin = 50;
HeapMax = 95;
ExpandRate = 1;
Threshold = 10;
InitialHeapIncrement = 4096;
HeaderSize = 40H;
EndBlockOfs = 38H;
MemoryBlockOfs = BlockHeaderSize + RecordDescSize + BlockHeaderSize;
CONST
DE* = 0; DB* = 1; NMI* = 2; BP* = 3; OVF* = 4; BR* = 5; UD* = 6; NM* = 7;
DF* = 8; TS* = 10; NP* = 11; SSF* = 12; GP* = 13; PF* = 14; MF*= 16; AC*= 17; MC* = 18;
IRQ0* = 32;
IRQ2 = IRQ0 + 2;
IRQ7 = IRQ0 + 7;
IRQ8 = IRQ0 + 8;
IRQ15 = 47;
MaxIRQ* = IRQ15;
MPKC* = 49;
SoftInt* = 58;
MPIPCLocal* = 59;
MPTMR* = 60;
MPIPC* = 61;
MPERR* = 62;
MPSPU* = 63;
IDTSize = 64;
MaxNumHandlers = 16;
TraceSpurious = FALSE;
HandleSpurious = TRUE OR TraceSpurious;
IntA0 = 020H; IntA1 = 021H;
IntB0 = 0A0H; IntB1 = 0A1H;
IFBit* = 9; VMBit* = 17;
KernelLevel* = 0; UserLevel* = 3;
Second* = 1000;
CONST
Self* = 0; FrontBarrier* = 1; BackBarrier* = 2;
TraceApic = FALSE;
TraceProcessor = FALSE;
ClockRateDelay = 50;
TimerClock = 1193180;
CONST
TraceV24 = 2; TraceScreen = 0;
TraceWidth = 80; TraceHeight = 25;
TraceLen = TraceWidth * SYSTEM.SIZEOF (INTEGER);
TraceSize = TraceLen * TraceHeight;
TYPE
Vendor* = ARRAY 13 OF CHAR;
IDMap* = ARRAY 16 OF SHORTINT;
TYPE
Stack* = RECORD
low: SYSTEM.ADDRESS;
adr*: SYSTEM.ADDRESS;
high*: SYSTEM.ADDRESS;
END;
TSSDesc = RECORD
Reserved1: LONGINT;
RSP0 {ALIGNED(4)}, RSP1{ALIGNED(4)}, RSP2{ALIGNED(4)}: HUGEINT;
Reserved2, Reserved3: LONGINT;
IST1 {ALIGNED(4)}, IST2 {ALIGNED(4)}, IST3 {ALIGNED(4)}, IST4{ALIGNED(4)}, IST5{ALIGNED(4)}, IST6{ALIGNED(4)}, IST7{ALIGNED(4)}: HUGEINT;
Reserved4, Reserved5: LONGINT;
Reserved6, IOMapBaseAddress: INTEGER;
END;
Startup* = PROCEDURE;
SegDesc = RECORD
low, high: LONGINT
END;
GDT = ARRAY GDTSize OF SegDesc;
Range* = RECORD
adr*: SYSTEM.ADDRESS; size*: SYSTEM.SIZE;
END;
TYPE
State* = RECORD
R15*, R14*, R13*, R12*, R11*, R10*, R9*, R8*: HUGEINT;
RDI*, RSI*, ERR*, RSP0*, RBX*, RDX*, RCX*, RAX*: HUGEINT;
INT*, BP*, PC*, CS*: HUGEINT;
FLAGS*: SET;
SP*, SS*: HUGEINT;
END;
ExceptionState* = RECORD
halt*: SYSTEM.ADDRESS;
pf*: SYSTEM.ADDRESS;
locks*: SET;
SP*: SYSTEM.ADDRESS;
CR*: ARRAY 16 OF HUGEINT;
DR*: ARRAY 16 OF HUGEINT;
FPU*: ARRAY 7 OF SET
END;
Handler* = PROCEDURE {DELEGATE} (VAR state: State);
HandlerRec = RECORD
valid: BOOLEAN;
handler {ALIGNED(4)}: Handler
END;
GateDescriptor = RECORD
offsetBits0to15: INTEGER;
selector: INTEGER;
gateType: INTEGER;
offsetBits16to31: INTEGER;
offsetBits32to63: LONGINT;
reserved: LONGINT;
END;
IDT = ARRAY IDTSize OF GateDescriptor;
SSEState* = ARRAY (512+16) OF CHAR;
TYPE
MemoryBlock* = POINTER TO MemoryBlockDesc;
MemoryBlockDesc* = RECORD
next- {UNTRACED}: MemoryBlock;
startAdr-: SYSTEM.ADDRESS;
size-: SYSTEM.SIZE;
beginBlockAdr-, endBlockAdr-: SYSTEM.ADDRESS
END;
TYPE
EventHandler = PROCEDURE (id: LONGINT; CONST state: State);
Message* = POINTER TO RECORD END;
BroadcastHandler = PROCEDURE (id: LONGINT; CONST state: State; msg: Message);
TimeArray = ARRAY MaxCPU OF HUGEINT;
Address32* = LONGINT;
VAR
lowTop*: SYSTEM.ADDRESS;
memTop*: SYSTEM.ADDRESS;
dmaSize*: SYSTEM.SIZE;
configMP: SYSTEM.ADDRESS;
revMP: CHAR;
featureMP: ARRAY 5 OF CHAR;
version-: ARRAY 64 OF CHAR;
SSESupport-: BOOLEAN;
SSE2Support-: BOOLEAN;
features-, features2-: SET;
fcr*: SET;
mhz*: HUGEINT;
chs: ARRAY MaxDisks OF RECORD cyls, hds, spt: LONGINT END;
initRegs0, initRegs1: HUGEINT;
fbadr*, fbInfoPtr*: SYSTEM.ADDRESS;
initRegs: ARRAY 2 OF HUGEINT;
config: ARRAY 2048 OF CHAR;
bootFlag: SYSTEM.ADDRESS;
idAdr: SYSTEM.ADDRESS;
map: IDMap;
bootID: LONGINT;
numberOfProcessors: LONGINT;
coresPerProcessor : LONGINT;
threadsPerCore : LONGINT;
CONST
CacheLineSize = 128;
TYPE
Lock = RECORD
locked : BOOLEAN;
filler : ARRAY CacheLineSize - 1 OF CHAR;
END;
VAR
lock: ARRAY MaxLocks OF Lock;
proc-, trapState-: ARRAY MaxCPU OF RECORD
locksHeld-: SET;
state-: SET;
preemptCount-: LONGINT;
padding : ARRAY CacheLineSize - 20 OF CHAR;
END;
padding : ARRAY 92 OF CHAR;
trapLocksBusy-: SET;
maxTime: HUGEINT;
VAR
gdt: GDT;
procm: ARRAY MaxCPU OF RECORD
tss: TSSDesc;
sp: SYSTEM.ADDRESS;
stack: Stack
END;
kernelPML4: SYSTEM.ADDRESS;
freeLowPage: SYSTEM.ADDRESS;
freeLowPages, freeHighPages, totalPages: HUGEINT;
mapTop: SYSTEM.ADDRESS;
heapEndAdr: SYSTEM.ADDRESS;
topPageNum: HUGEINT;
pageHeapAdr: SYSTEM.ADDRESS;
pageStackAdr: SYSTEM.ADDRESS;
freeStack: ARRAY (MaxUserStacks+SetSize-1) DIV SetSize OF SET;
freeStackIndex: HUGEINT;
Nbigskips-: LONGINT;
Nfilled-: LONGINT;
NnewStacks-, NnewStackLoops-, NnewStackInnerLoops-, NdisposeStacks-,
NlostPages-, NreservePagesUsed-, NmaxUserStacks-: HUGEINT;
VAR
idt: IDT;
glue: ARRAY IDTSize OF ARRAY 15 OF CHAR;
intHandler: ARRAY IDTSize, MaxNumHandlers OF HandlerRec;
stateTag: SYSTEM.ADDRESS;
default: HandlerRec;
i, j, ticks*: LONGINT;
VAR
ipcBusy, ipcFlags, ipcFrontBarrier, ipcBackBarrier: SET;
ipcHandler: BroadcastHandler;
ipcMessage: Message;
numProcessors-: LONGINT;
maxProcessors: LONGINT;
allProcessors-: SET;
localAPIC: SYSTEM.ADDRESS;
apicVer: ARRAY MaxCPU OF LONGINT;
started: ARRAY MaxCPU OF BOOLEAN;
busHz0, busHz1: ARRAY MaxCPU OF LONGINT;
timer: EventHandler;
timerRate: LONGINT;
stopped: BOOLEAN;
idMap: IDMap;
revIDmap: ARRAY MaxCPU OF SHORTINT;
time: TimeArray;
eventCount, eventMax: LONGINT;
event: Handler;
expandMin, heapMinKB, heapMaxKB : SYSTEM.SIZE;
gcThreshold-: SYSTEM.SIZE;
memBlockHead-{UNTRACED}, memBlockTail-{UNTRACED}: MemoryBlock;
initialMemBlock: MemoryBlockDesc;
traceProcessorProc*: EventHandler;
traceProcessor: BOOLEAN;
Timeslice*: Handler;
start*: PROCEDURE;
VAR
traceMode: SET;
traceBase: SYSTEM.ADDRESS;
tracePos: SYSTEM.SIZE;
tracePort: LONGINT;
traceColor: SHORTINT;
PROCEDURE ID* (): LONGINT;
CODE {SYSTEM.AMD64}
; todo: use MOV instead of LEA as soon as assembler returns address for global variables
LEA RAX, idAdr ; get address of idAdr
MOV RAX, [RAX] ; get value of idAdr
MOV EAX, [RAX] ; dereference idAdr
LEA RBX, map ; address of map
SHR EAX, 24
AND EAX, 15
MOV AL, [RBX + RAX]
END ID;
PROCEDURE -SpinHint*;
CODE {SYSTEM.AMD64}
PAUSE
END SpinHint;
PROCEDURE -LessThan* (a, b: SYSTEM.ADDRESS): BOOLEAN;
CODE {SYSTEM.AMD64}
POP RBX
POP RAX
CMP RAX, RBX
SETB AL
END LessThan;
PROCEDURE -LessOrEqual* (a, b: SYSTEM.ADDRESS): BOOLEAN;
CODE {SYSTEM.AMD64}
POP RBX
POP RAX
CMP RAX, RBX
SETBE AL
END LessOrEqual;
PROCEDURE -GreaterThan* (a, b: SYSTEM.ADDRESS): BOOLEAN;
CODE {SYSTEM.AMD64}
POP RBX
POP RAX
CMP RAX, RBX
SETA AL
END GreaterThan;
PROCEDURE -GreaterOrEqual* (a, b: SYSTEM.ADDRESS): BOOLEAN;
CODE {SYSTEM.AMD64}
POP RBX
POP RAX
CMP RAX, RBX
SETAE AL
END GreaterOrEqual;
PROCEDURE Fill32* (destAdr: SYSTEM.ADDRESS; size: SYSTEM.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;
PROCEDURE -GetTimer* (): HUGEINT;
CODE {SYSTEM.AMD64}
XOR RAX, RAX
RDTSC ; set EDX:EAX
SHL RDX, 32
OR RAX, RDX
END GetTimer;
PROCEDURE -DisableInterrupts* (): SET;
CODE {SYSTEM.AMD64}
PUSHFQ
CLI
POP RAX
END DisableInterrupts;
PROCEDURE -RestoreInterrupts* (s: SET);
CODE {SYSTEM.AMD64}
POPFQ
END RestoreInterrupts;
PROCEDURE -InterruptsEnabled* (): BOOLEAN;
CODE {SYSTEM.AMD64}
PUSHFQ
POP RAX
SHR RAX, 9
AND AL, 1
END InterruptsEnabled;
PROCEDURE MulH* (h, g: HUGEINT): HUGEINT;
BEGIN RETURN h * g;
END MulH;
PROCEDURE DivH* (x, y: HUGEINT): HUGEINT;
BEGIN RETURN x DIV y
END DivH;
PROCEDURE ASHH* (h: HUGEINT; n: LONGINT): HUGEINT;
BEGIN RETURN ASH (h, n);
END ASHH;
PROCEDURE -LInt2ToHInt* (high, low: LONGINT): HUGEINT;
CODE {SYSTEM.AMD64}
POP RAX
END LInt2ToHInt;
PROCEDURE -HIntToLReal* (h: HUGEINT): LONGREAL;
CODE {SYSTEM.AMD64, SYSTEM.FPU}
FILD QWORD [ESP]
PAUSE
ADD RSP, 8
END HIntToLReal;
PROCEDURE -SetFCR (s: SET);
CODE {SYSTEM.AMD64, SYSTEM.FPU}
FLDCW WORD [RSP] ; parameter s
POP RAX
END SetFCR;
PROCEDURE -FCR (): SET;
CODE {SYSTEM.AMD64, SYSTEM.FPU}
PUSH 0
FNSTCW WORD [RSP]
FWAIT
POP RAX
END FCR;
PROCEDURE -InitFPU;
CODE {SYSTEM.AMD64, SYSTEM.FPU}
FNINIT
END InitFPU;
PROCEDURE SetupFPU*;
BEGIN
InitFPU; SetFCR(fcr)
END SetupFPU;
PROCEDURE -SetupFlags;
CODE {SYSTEM.AMD64}
PUSHFD
AND DWORD [RSP], 0FFF8802AH
OR DWORD [RSP], 3000H
POPFD
END SetupFlags;
PROCEDURE -Setup486Flags;
CODE {SYSTEM.486, SYSTEM.Privileged}
MOV EAX, CR0
OR EAX, 00040020H
AND EAX, 0FFFEFFFFH
MOV CR0, EAX
END Setup486Flags;
PROCEDURE -Setup586Flags;
CODE {SYSTEM.586, SYSTEM.Privileged}
MOV EAX, CR4
BTR EAX, 2 ; clear TSD
MOV CR4, EAX
END Setup586Flags;
PROCEDURE -DisableMathTaskEx;
CODE {SYSTEM.386, SYSTEM.Privileged}
MOV EAX,CR0
AND AL, 0F5H
MOV CR0, EAX
END DisableMathTaskEx;
PROCEDURE -DisableEmulation;
CODE {SYSTEM.386, SYSTEM.Privileged}
MOV EAX, CR0
AND AL, 0FBH
MOV CR0, EAX
END DisableEmulation;
PROCEDURE CPUID*(function : LONGINT; VAR eax, ebx, ecx, edx : SET);
CODE {SYSTEM.AMD64}
MOV EAX, [RBP+function] ; CPUID function parameter
MOV RSI, [RBP+ecx] ; copy ecx into ECX (sometimes used as input parameter)
MOV ECX, [RSI]
CPUID ; execute CPUID
MOV RSI, [RBP+eax] ; copy EAX into eax;
MOV [RSI], EAX
MOV RSI, [RBP+ebx] ; copy EBX into ebx
MOV [RSI], EBX
MOV RSI, [RBP+ecx] ; copy ECX into ecx
MOV [RSI], ECX
MOV RSI, [RBP+edx] ; copy EDX into edx
MOV [RSI], EDX
END CPUID;
PROCEDURE CpuIdSupported*() : BOOLEAN;
CODE {SYSTEM.AMD64}
PUSHFQ ; save RFLAGS
POP RAX ; store RFLAGS in RAX
MOV EBX, EAX ; save EBX for later testing
XOR EAX, 00200000H ; toggle bit 21
PUSH RAX ; push to stack
POPFQ ; save changed RAX to RFLAGS
PUSHFQ ; push RFLAGS to TOS
POP RAX ; store RFLAGS in RAX
CMP EAX, EBX ; see if bit 21 has changed
SETNE AL; ; return TRUE if bit 21 has changed, FALSE otherwise
END CpuIdSupported;
PROCEDURE InitProcessor*;
BEGIN
SetupFlags;
Setup486Flags;
Setup586Flags;
DisableMathTaskEx;
DisableEmulation;
SetupFPU;
END InitProcessor;
PROCEDURE InitAPICIDAdr* (adr: SYSTEM.ADDRESS; CONST m: IDMap);
VAR s: SET;
BEGIN
s := DisableInterrupts ();
idAdr := adr; map := m;
RestoreInterrupts (s)
END InitAPICIDAdr;
PROCEDURE InitBoot;
VAR
largestFunction, i: LONGINT;
eax, ebx, ecx, edx : SET;
logicalProcessorCount : LONGINT;
u: ARRAY 8 OF CHAR; vendor : Vendor;
PROCEDURE GetString(VAR string : ARRAY OF CHAR; offset : LONGINT; register : SET);
BEGIN
string[offset] :=CHR(SYSTEM.VAL(LONGINT, register * {0..7}));
string[offset+1] := CHR(SYSTEM.VAL(LONGINT, SYSTEM.LSH(register * {8..15}, -8)));
string[offset+2] := CHR(SYSTEM.VAL(LONGINT, SYSTEM.LSH(register * {16..23}, -16)));
string[offset+3] := CHR(SYSTEM.VAL(LONGINT, SYSTEM.LSH(register * {24..31}, -24)));
END GetString;
BEGIN
vendor := "Unknown"; features := {}; features2 := {};
coresPerProcessor := 1; threadsPerCore := 1;
IF CpuIdSupported() THEN
CPUID(0, eax, ebx, ecx, edx);
largestFunction := SYSTEM.VAL(LONGINT, eax);
ASSERT(LEN(vendor) >= 13);
GetString(vendor, 0, ebx); GetString(vendor, 4, edx); GetString(vendor, 8, ecx); vendor[12] := 0X;
IF (largestFunction >= 1) THEN
CPUID(1, eax, ebx, ecx, edx);
features := SYSTEM.VAL(SET, edx);
features2 := SYSTEM.VAL(SET, ecx);
IF (HTT IN features) THEN
logicalProcessorCount := SYSTEM.VAL(LONGINT, SYSTEM.LSH(ebx * {16..23}, -16));
IF (vendor = "GenuineIntel") THEN
IF (largestFunction >= 4) THEN
ecx := SYSTEM.VAL(SET, 0);
CPUID(4, eax, ebx, ecx, edx);
coresPerProcessor := SYSTEM.VAL(LONGINT, SYSTEM.LSH(eax * {26..31}, -26)) + 1;
threadsPerCore := logicalProcessorCount DIV coresPerProcessor;
ELSE
threadsPerCore := logicalProcessorCount;
END;
ELSIF (vendor = "AuthenticAMD") THEN
CPUID(SHORT(80000000H), eax, ebx, ecx, edx);
largestFunction := SYSTEM.VAL(LONGINT, eax - {31});
IF (largestFunction >= 8) THEN
CPUID(SHORT(80000008H), eax, ebx, ecx, edx);
coresPerProcessor := SYSTEM.VAL(LONGINT, ecx * {0..7}) + 1;
threadsPerCore := logicalProcessorCount DIV coresPerProcessor;
ELSIF (largestFunction >= 1) THEN
CPUID(SHORT(80000001H), eax, ebx, ecx, edx);
IF 1 IN ecx THEN
coresPerProcessor := logicalProcessorCount;
threadsPerCore := 1;
END;
ELSE
END;
ELSE
Trace.String("Machine: "); Trace.Yellow; Trace.String("Warning: Cannot detect hyperthreading, unknown CPU vendor ");
Trace.String(vendor); Trace.Ln; Trace.Default;
END;
END;
END;
END;
Trace.String("Machine: "); Trace.Int(coresPerProcessor, 0); Trace.String(" cores per physical package, ");
Trace.Int(threadsPerCore, 0); Trace.String(" threads per core.");
Trace.Ln;
InitFPU;
fcr := (FCR () - {0, 2, 3, 10, 11}) + {0 .. 5, 8, 9};
bootID := 0; map[0] := 0;
idAdr := SYSTEM.ADR (bootID);
GetConfig ("MHz", u);
i := 0; mhz := StrToInt (i, u);
END InitBoot;
PROCEDURE GetConfig* (CONST name: ARRAY OF CHAR; VAR val: ARRAY OF CHAR);
VAR i, src: LONGINT; ch: CHAR;
BEGIN
ASSERT (name[0] # "=");
src := 0;
LOOP
ch := config[src];
IF ch = 0X THEN EXIT END;
i := 0;
LOOP
ch := config[src];
IF (ch # name[i]) OR (name[i] = 0X) THEN EXIT END;
INC (i); INC (src)
END;
IF (ch = 0X) & (name[i] = 0X) THEN
i := 0;
REPEAT
INC (src); ch := config[src]; val[i] := ch; INC (i);
IF i = LEN(val) THEN val[i - 1] := 0X; RETURN END
UNTIL ch = 0X;
val[i] := 0X; RETURN
ELSE
WHILE ch # 0X DO
INC (src); ch := config[src]
END;
INC (src);
REPEAT
ch := config[src]; INC (src)
UNTIL ch = 0X
END
END;
val[0] := 0X
END GetConfig;
PROCEDURE GetDiskCHS* (d: LONGINT; VAR cyls, hds, spt: LONGINT);
BEGIN
cyls := chs[d].cyls; hds := chs[d].hds; spt := chs[d].spt
END GetDiskCHS;
PROCEDURE GetInit* (n: LONGINT; VAR val: HUGEINT);
BEGIN
val := initRegs[n]
END GetInit;
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 -Wait*;
CODE {SYSTEM.AMD64}
JMP N1
N1: JMP N2
N2: JMP N3
N3:
END Wait;
PROCEDURE Reboot;
CODE {SYSTEM.AMD64, SYSTEM.Privileged}
PUSH DWORD 0
PUSH DWORD 0
LIDT [RSP]
INT 3
END Reboot;
PROCEDURE Shutdown* (reboot: BOOLEAN);
VAR i: LONGINT;
BEGIN
Cli;
IF reboot THEN
Portout8 (70H, 8FX);
Wait; Portout8 (71H, 0X);
Wait; Portout8 (70H, 0DX);
Wait; Portout8 (64H, 0FEX);
FOR i := 1 TO 10000 DO END;
Reboot
END;
LOOP END
END Shutdown;
PROCEDURE GetPar (p: SYSTEM.ADDRESS; ofs: LONGINT): LONGINT;
VAR ch: CHAR;
BEGIN
SYSTEM.GET (p + 12 + ofs, ch);
RETURN ORD (ch)
END GetPar;
PROCEDURE ReadBootTable (bt: SYSTEM.ADDRESS);
VAR i, p: SYSTEM.ADDRESS; j, d, type, addr, size, heapSize: LONGINT; ch: CHAR;
BEGIN
heapSize := 0; lowTop := 0;
p := bt; d := 0;
LOOP
SYSTEM.GET (p, type);
IF type = -1 THEN
EXIT
ELSIF type = 3 THEN
SYSTEM.GET (p + 8, addr); SYSTEM.GET (p + 12, size);
lowTop := addr + size
ELSIF type = 4 THEN
SYSTEM.GET (p + 8, addr); SYSTEM.GET (p + 12, size);
IF addr = HeapAdr THEN heapSize := size END
ELSIF type = 5 THEN
IF d < MaxDisks THEN
chs[d].cyls := GetPar (p, 0) + 100H * GetPar (p, 1);
chs[d].hds := GetPar (p, 2); chs[d].spt := GetPar (p, 14);
INC (d)
END
ELSIF type = 8 THEN
i := p + 8; j := 0;
LOOP
SYSTEM.GET (i, ch); config[j] := ch; INC (i); INC (j);
IF ch = 0X THEN EXIT END;
REPEAT SYSTEM.GET (i, ch); config[j] := ch; INC (i); INC (j) UNTIL ch = 0X;
REPEAT SYSTEM.GET (i, ch); config[j] := ch; INC (i); INC (j) UNTIL ch = 0X
END
END;
SYSTEM.GET (p + 4, size); INC (p, size)
END;
ASSERT((heapSize # 0) & (lowTop # 0));
memTop := HeapAdr + heapSize
END ReadBootTable;
PROCEDURE GetNVByte* (ofs: LONGINT): CHAR;
VAR c: CHAR;
BEGIN
Portout8 (70H, CHR(ofs)); Wait; Portin8(71H, c);
RETURN c
END GetNVByte;
PROCEDURE PutNVByte* (ofs: LONGINT; val: CHAR);
BEGIN
Portout8 (70H, CHR(ofs)); Wait; Portout8 (71H, val)
END PutNVByte;
PROCEDURE ChecksumMP* (adr: SYSTEM.ADDRESS; size: SYSTEM.SIZE): LONGINT;
VAR sum: LONGINT; x: SYSTEM.ADDRESS; ch: CHAR;
BEGIN
sum := 0;
FOR x := adr TO adr + size-1 DO
SYSTEM.GET (x, ch);
sum := (sum + ORD(ch)) MOD 256
END;
RETURN sum
END ChecksumMP;
PROCEDURE SearchMem (adr: SYSTEM.ADDRESS; size: SYSTEM.SIZE): SYSTEM.ADDRESS;
VAR x, len: LONGINT; ch: CHAR;
BEGIN
WHILE size > 0 DO
SYSTEM.GET (adr, x);
IF x = 05F504D5FH THEN
SYSTEM.GET (adr + 8, ch); len := ORD(ch)*16;
IF len > 0 THEN
SYSTEM.GET (adr + 9, ch);
IF (ch = 1X) OR (ch >= 4X) THEN
IF ChecksumMP(adr, len) = 0 THEN
RETURN adr
END
END
END
END;
INC (adr, 16); DEC (size, 16)
END;
RETURN NilAdr
END SearchMem;
PROCEDURE SearchMP;
VAR adr: SYSTEM.ADDRESS;
BEGIN
adr := 0;
SYSTEM.GET (040EH, SYSTEM.VAL (INTEGER, adr));
adr := adr*16;
IF adr < 100000H THEN adr := SearchMem(adr, 1024)
ELSE adr := NilAdr
END;
IF adr = NilAdr THEN
adr := SearchMem(lowTop + (-lowTop) MOD 10000H - 1024, 1024);
IF adr = NilAdr THEN
adr := SearchMem(memTop - 1024, 1024);
IF adr = NilAdr THEN
adr := SearchMem(0E0000H, 20000H)
END
END
END;
IF adr = NilAdr THEN
revMP := 0X; configMP := NilAdr
ELSE
SYSTEM.GET (adr + 9, revMP);
SYSTEM.MOVE(adr + 11, SYSTEM.ADR(featureMP[0]), 5);
configMP := SYSTEM.GET32 (adr + 4);
IF configMP = 0 THEN configMP := NilAdr END
END
END SearchMP;
PROCEDURE AllocateDMA;
VAR old: SYSTEM.ADDRESS;
BEGIN
old := lowTop;
dmaSize := DefaultDMASize*1024;
ASSERT((dmaSize >= 0) & (dmaSize <= 65536));
IF (lowTop-dmaSize) DIV 65536 # (lowTop-1) DIV 65536 THEN
DEC (lowTop, lowTop MOD 65536)
END;
DEC (lowTop, dmaSize);
dmaSize := old - lowTop
END AllocateDMA;
PROCEDURE IsRAM(adr: SYSTEM.ADDRESS): BOOLEAN;
CONST Pattern1 = SHORT(0BEEFC0DEH); Pattern2 = SHORT(0AA55FF00H);
VAR save, x: LONGINT; ok: BOOLEAN;
BEGIN
ok := FALSE;
SYSTEM.GET (adr, save);
SYSTEM.PUT (adr, Pattern1);
x := Pattern2;
SYSTEM.GET (adr, x);
IF x = Pattern1 THEN
SYSTEM.PUT (adr, Pattern2);
x := Pattern1;
SYSTEM.GET (adr, x);
ok := (x = Pattern2)
END;
SYSTEM.PUT (adr, save);
RETURN ok
END IsRAM;
PROCEDURE -InvalidateTLB (address: SYSTEM.ADDRESS);
CODE {SYSTEM.AMD64, SYSTEM.Privileged}
POP RAX
INVLPG [RAX]
END InvalidateTLB;
PROCEDURE -GetPML4Base (): SYSTEM.ADDRESS;
CODE {SYSTEM.AMD64}
MOV RAX, CR3
END GetPML4Base;
PROCEDURE -INVLPG (adr: SYSTEM.ADDRESS);
CODE {SYSTEM.AMD64, SYSTEM.Privileged}
POP RAX
INVLPG [RAX]
END INVLPG;
PROCEDURE CheckMemory;
CONST K = 1024; M = K * K; PS = 2 * M; ExtMemAdr = M;
TPS = 4 * K; UserPage = 7; PageNotPresent = 0;
VAR s: ARRAY 16 OF CHAR; i: LONGINT;
physicalAddress, pml4Base, pdpBase, pdBase: SYSTEM.ADDRESS;
pml4e, pdpe, pde, lastTable: SYSTEM.ADDRESS;
PROCEDURE AllocateTranslationTable (VAR baseAddress, firstEntry: SYSTEM.ADDRESS);
BEGIN
baseAddress := lastTable;
firstEntry := baseAddress;
INC (lastTable, TPS);
Fill32 (baseAddress, TPS, PageNotPresent)
END AllocateTranslationTable;
BEGIN
GetConfig("ExtMemSize", s);
IF s[0] # 0X THEN
i := 0;
memTop := ExtMemAdr + LONG (StrToInt(i, s)) * M
END;
pml4Base := GetPML4Base ();
DEC (pml4Base, pml4Base MOD TPS);
SYSTEM.GET (pml4Base, pdpBase);
DEC (pdpBase, pdpBase MOD TPS);
SYSTEM.GET (pdpBase, pdBase);
DEC (pdBase, pdBase MOD TPS);
physicalAddress := PS;
lastTable := pdBase + TPS;
pml4e := pml4Base;
pdpe := pdpBase;
pde := pdBase;
WHILE (pml4e < pml4Base + TPS) DO
WHILE (pdpe < pdpBase + TPS) DO
WHILE (pde < pdBase + TPS) DO
INC (pde, 8);
SYSTEM.PUT (pde, physicalAddress + UserPage + 80H);
INVLPG (physicalAddress);
INC (physicalAddress, PS);
IF physicalAddress >= memTop THEN RETURN END;
END;
INC (pdpe, 8);
AllocateTranslationTable (pdBase, pde);
SYSTEM.PUT (pdpe, pde + UserPage);
END;
INC (pml4e, 8);
AllocateTranslationTable (pdpBase, pdpe);
SYSTEM.PUT (pml4e, pdpe + UserPage);
END;
HALT (99);
END CheckMemory;
PROCEDURE InitLocks;
VAR i: LONGINT; s: ARRAY 12 OF CHAR;
BEGIN
IF TimeCount # 0 THEN
GetConfig("LockTimeout", s);
i := 0; maxTime := StrToInt(i, s);
IF maxTime > MAX(LONGINT) DIV 1000000 THEN
maxTime := MAX(LONGINT)
ELSE
maxTime := maxTime * 1000000
END
END;
FOR i := 0 TO MaxCPU-1 DO
proc[i].locksHeld := {}; proc[i].preemptCount := 0
END;
FOR i := 0 TO MaxLocks-1 DO
lock[i].locked := FALSE
END
END InitLocks;
PROCEDURE -GetFlags (): SET;
CODE {SYSTEM.AMD64}
PUSHFQ
POP RAX
END GetFlags;
PROCEDURE -SetFlags (s: SET);
CODE {SYSTEM.AMD64}
POPFQ
END SetFlags;
PROCEDURE -PushFlags*;
CODE {SYSTEM.AMD64}
PUSHFQ
END PushFlags;
PROCEDURE -PopFlags*;
CODE {SYSTEM.AMD64}
POPFQ
END PopFlags;
PROCEDURE AcquirePreemption* (): LONGINT;
VAR id: LONGINT;
BEGIN
PushFlags; Cli;
id := ID ();
INC (proc[id].preemptCount);
PopFlags;
RETURN id
END AcquirePreemption;
PROCEDURE ReleasePreemption*;
VAR id: LONGINT;
BEGIN
PushFlags; Cli;
id := ID ();
IF StrongChecks THEN
ASSERT(proc[id].preemptCount > 0)
END;
DEC (proc[id].preemptCount);
PopFlags
END ReleasePreemption;
PROCEDURE PreemptCount* (id: LONGINT): LONGINT;
BEGIN
IF StrongChecks THEN
ASSERT(id = ID ())
END;
RETURN proc[id].preemptCount
END PreemptCount;
PROCEDURE AcquireSpinTimeout(VAR locked: BOOLEAN; count: LONGINT; flags: SET): CHAR;
CODE {SYSTEM.AMD64}
MOV RSI, [RBP + flags] ; RSI := flags
MOV EDI, [RBP + count] ; RDI := count
MOV RBX, [RBP + locked] ; RBX := ADR(locked)
MOV AL, 1 ; AL := 1
CLI ; switch interrupts off before acquiring lock
test:
CMP [RBX], AL ; locked? { AL = 1 }
JE wait ; yes, go wait
XCHG [RBX], AL ; set and read the lock atomically. LOCK prefix implicit.
CMP AL, 1 ; was locked?
JNE exit ; no, we have it now, interrupts are off, and AL # 1
wait:
; ASSERT(AL = 1)
XOR RCX, RCX ; just in case some processor interprets REP this way
REP NOP ; PAUSE instruction
TEST RSI, 200H ; bit 9 - IF
JZ intoff
STI ; restore interrupt state quickly to allow pending interrupts (e.g. AosProcessors.StopAll/Broadcast)
NOP ; NOP required, otherwise STI; CLI not interruptable
CLI ; disable interrupts
intoff:
DEC EDI ; counter
JNZ test ; not timed out yet
OR EDI, [RBP + count] ; re-fetch original value & set flags
JZ test ; if count = 0, retry forever
; timed out (AL = 1)
exit:
END AcquireSpinTimeout;
PROCEDURE Acquire* (level: LONGINT);
VAR id, i: LONGINT; flags: SET; start: HUGEINT;
BEGIN
id := AcquirePreemption ();
flags := GetFlags ();
IF StrongChecks THEN
ASSERT(~(9 IN flags) OR (proc[id].locksHeld = {}));
ASSERT(~(level IN proc[id].locksHeld))
END;
IF (TimeCount = 0) OR (maxTime = 0) THEN
IF AcquireSpinTimeout(lock[level].locked, 0, flags) = 0X THEN END;
ELSE
start := GetTimer ();
WHILE AcquireSpinTimeout(lock[level].locked, TimeCount, flags) = 1X DO
IF GetTimer () - start > maxTime THEN
trapState := proc;
trapLocksBusy := {};
FOR i := 0 TO MaxLocks-1 DO
IF lock[i].locked THEN INCL(trapLocksBusy, i) END
END;
HALT(1301)
END
END
END;
IF proc[id].locksHeld = {} THEN
proc[id].state := flags
END;
INCL(proc[id].locksHeld, level);
IF StrongChecks THEN
ASSERT((level = 0) OR (proc[id].locksHeld * {0..level-1} = {}))
END
END Acquire;
PROCEDURE Release* (level: LONGINT);
VAR id: LONGINT; flags: SET;
BEGIN
id := ID ();
IF StrongChecks THEN
ASSERT(~(9 IN GetFlags ()));
ASSERT(lock[level].locked);
ASSERT(level IN proc[id].locksHeld)
END;
EXCL(proc[id].locksHeld, level);
IF proc[id].locksHeld = {} THEN
flags := proc[id].state ELSE flags := GetFlags ()
END;
lock[level].locked := FALSE;
SetFlags(flags);
ReleasePreemption
END Release;
PROCEDURE AcquireAll*;
VAR lock: LONGINT;
BEGIN
FOR lock := HighestLock TO LowestLock BY -1 DO Acquire(lock) END
END AcquireAll;
PROCEDURE ReleaseAll*;
VAR lock: LONGINT;
BEGIN
FOR lock := LowestLock TO HighestLock DO Release(lock) END
END ReleaseAll;
PROCEDURE BreakAll* (): SET;
VAR id, level: LONGINT; released: SET;
BEGIN
id := AcquirePreemption ();
PushFlags; Cli;
released := {};
FOR level := 0 TO MaxLocks-1 DO
IF level IN proc[id].locksHeld THEN
lock[level].locked := FALSE;
EXCL(proc[id].locksHeld, level);
INCL(released, level)
END
END;
IF proc[id].preemptCount > 1 THEN INCL(released, Preemption) END;
proc[id].preemptCount := 0;
PopFlags;
RETURN released
END BreakAll;
PROCEDURE AcquireObject* (VAR locked: BOOLEAN);
CODE {SYSTEM.AMD64}
PUSHFQ
MOV RBX, [RBP + locked] ; RBX := ADR(locked)
MOV AL, 1
test:
CMP [RBX], AL ; locked? { AL = 1 }
JNE try
STI
PAUSE ; PAUSE instruction
CLI
JMP test
try:
XCHG [RBX], AL ; set and read the lock atomically. LOCK prefix implicit.
CMP AL, 1 ; was locked?
JE test ; yes, try again
POPFQ
END AcquireObject;
PROCEDURE ReleaseObject* (VAR locked: BOOLEAN);
CODE {SYSTEM.AMD64}
MOV RBX, [RBP + locked] ; RBX := ADR(locked)
MOV BYTE [RBX], 0
END ReleaseObject;
PROCEDURE LoadGDT(base: SYSTEM.ADDRESS; size: SYSTEM.SIZE);
CODE {SYSTEM.AMD64, SYSTEM.Privileged}
; LGDT needs 10 bytes: 2 for the 16-bit limit and 8 for the 64-bit base address in this order
; Assumption: size argument in front of base -> promote size value to upper 48 bits of size
SHL QWORD [RBP + size], 64-16
LGDT [RBP + size + (64-16) / 8]
END LoadGDT;
PROCEDURE LoadSegRegs(data: INTEGER);
CODE {SYSTEM.AMD64}
MOV AX, [RBP + data]
MOV DS, AX
XOR AX, AX
MOV ES, AX
MOV FS, AX
MOV GS, AX
END LoadSegRegs;
PROCEDURE -CS* (): INTEGER;
CODE {SYSTEM.AMD64}
MOV AX, CS
END CS;
PROCEDURE NewLowPage(VAR adr: SYSTEM.ADDRESS);
BEGIN
adr := freeLowPage;
IF freeLowPage # NilAdr THEN
SYSTEM.GET (freeLowPage, freeLowPage);
DEC(freeLowPages)
END
END NewLowPage;
PROCEDURE NewDirectPage(VAR adr: SYSTEM.ADDRESS);
BEGIN
IF pageHeapAdr # heapEndAdr THEN
DEC(pageHeapAdr, PS); adr := pageHeapAdr;
DEC(freeHighPages)
ELSE
adr := NilAdr
END
END NewDirectPage;
PROCEDURE NewPage(VAR physAdr: SYSTEM.ADDRESS);
VAR sp, prev: SYSTEM.ADDRESS;
BEGIN
SYSTEM.GET(pageStackAdr + NodeSP, sp);
ASSERT((sp >= MinSP) & (sp <= MaxSP) & (sp MOD AddressSize = 0));
IF sp > MinSP THEN
DEC(sp, AddressSize);
SYSTEM.GET (pageStackAdr+sp, physAdr);
SYSTEM.PUT (pageStackAdr+NodeSP, sp);
SYSTEM.GET (pageStackAdr+NodePrev, prev);
IF (sp = MinSP) & (prev # NilAdr) THEN
pageStackAdr := prev
END;
DEC(freeHighPages)
ELSE
NewDirectPage(physAdr)
END
END NewPage;
PROCEDURE DisposePage(physAdr: SYSTEM.ADDRESS);
VAR sp, next, newAdr: SYSTEM.ADDRESS;
BEGIN
SYSTEM.GET (pageStackAdr + NodeSP, sp);
ASSERT((sp >= MinSP) & (sp <= MaxSP) & (sp MOD AddressSize = 0));
IF sp = MaxSP THEN
SYSTEM.GET (pageStackAdr + NodeNext, next);
IF next # NilAdr THEN
pageStackAdr := next;
SYSTEM.GET (pageStackAdr+NodeSP, sp);
ASSERT(sp = MinSP)
ELSE
NewDirectPage(newAdr);
IF newAdr = NilAdr THEN
NewLowPage(newAdr);
IF newAdr = NilAdr THEN
IF Stats THEN INC(NlostPages) END;
RETURN
ELSE
IF Stats THEN INC(NreservePagesUsed) END
END
END;
sp := MinSP;
SYSTEM.PUT (newAdr + NodeNext, next);
SYSTEM.PUT (newAdr + NodePrev, pageStackAdr);
pageStackAdr := newAdr
END
END;
SYSTEM.PUT (pageStackAdr + sp, physAdr);
SYSTEM.PUT (pageStackAdr + NodeSP, sp + AddressSize);
INC(freeHighPages)
END DisposePage;
PROCEDURE NewVirtual(VAR virtAdr: SYSTEM.ADDRESS; size: SYSTEM.SIZE);
BEGIN
ASSERT(size MOD PS = 0);
virtAdr := mapTop;
INC(mapTop, size)
END NewVirtual;
PROCEDURE DisposeVirtual(virtAdr: SYSTEM.ADDRESS; size: SYSTEM.SIZE);
END DisposeVirtual;
PROCEDURE MapTable (base, index: SYSTEM.ADDRESS): SYSTEM.ADDRESS;
VAR pt: SYSTEM.ADDRESS;
BEGIN
SYSTEM.GET (base + index * AddressSize, pt);
IF ODD (pt) THEN
DEC (pt, pt MOD TPS)
ELSE
NewPage(pt);
IF pt = NilAdr THEN RETURN NilAdr END;
SYSTEM.PUT (base + index * AddressSize, pt + UserPage);
Fill32 (pt, TPS, PageNotPresent)
END;
RETURN pt;
END MapTable;
PROCEDURE MapPage(virtAdr, phys: SYSTEM.ADDRESS): BOOLEAN;
VAR i, pt: SYSTEM.ADDRESS;
pml4e, pdpe, pde, pte: SYSTEM.ADDRESS;
BEGIN
virtAdr := virtAdr DIV PS;
pte := virtAdr MOD PTEs; virtAdr := virtAdr DIV PTEs;
pde := virtAdr MOD PTEs; virtAdr := virtAdr DIV PTEs;
pdpe := virtAdr MOD PTEs; virtAdr := virtAdr DIV PTEs;
pml4e := virtAdr MOD PTEs;
pt := MapTable (kernelPML4, pml4e);
IF pt = NilAdr THEN RETURN FALSE END;
pt := MapTable (pt, pdpe);
IF pt = NilAdr THEN RETURN FALSE END;
pt := MapTable (pt, pde);
IF pt = NilAdr THEN RETURN FALSE END;
SYSTEM.PUT(pt + pte * AddressSize, phys);
RETURN TRUE;
END MapPage;
PROCEDURE MappedPage(virtAdr: SYSTEM.ADDRESS): SYSTEM.ADDRESS;
VAR pt: SYSTEM.ADDRESS;
pml4e, pdpe, pde, pte: SYSTEM.ADDRESS;
BEGIN
virtAdr := virtAdr DIV PS;
pte := virtAdr MOD PTEs; virtAdr := virtAdr DIV PTEs;
pde := virtAdr MOD PTEs; virtAdr := virtAdr DIV PTEs;
pdpe := virtAdr MOD PTEs; virtAdr := virtAdr DIV PTEs;
pml4e := virtAdr MOD PTEs;
SYSTEM.GET(kernelPML4 + pml4e * AddressSize, pt);
IF ~ODD(pt) THEN RETURN 0 END;
DEC (pt, pt MOD 1000H);
SYSTEM.GET(pt + pdpe * AddressSize, pt);
IF ~ODD(pt) THEN RETURN 0 END;
DEC (pt, pt MOD 1000H);
SYSTEM.GET(pt + pde * AddressSize, pt);
IF ~ODD(pt) THEN RETURN 0 END;
DEC (pt, pt MOD 1000H);
SYSTEM.GET (pt + pte * AddressSize, pt);
RETURN pt;
END MappedPage;
PROCEDURE UnmapPage(virtAdr: SYSTEM.ADDRESS): SYSTEM.ADDRESS;
VAR t, pt: SYSTEM.ADDRESS;
pml4e, pdpe, pde, pte: SYSTEM.ADDRESS;
BEGIN
virtAdr := virtAdr DIV PS;
pte := virtAdr MOD PTEs; virtAdr := virtAdr DIV PTEs;
pde := virtAdr MOD PTEs; virtAdr := virtAdr DIV PTEs;
pdpe := virtAdr MOD PTEs; virtAdr := virtAdr DIV PTEs;
pml4e := virtAdr MOD PTEs;
SYSTEM.GET(kernelPML4 + pml4e * AddressSize, pt);
IF ~ODD(pt) THEN RETURN 0 END;
DEC (pt, pt MOD 1000H);
SYSTEM.GET(pt + pdpe * AddressSize, pt);
IF ~ODD(pt) THEN RETURN 0 END;
DEC (pt, pt MOD 1000H);
SYSTEM.GET(pt + pde * AddressSize, pt);
IF ~ODD(pt) THEN RETURN 0 END;
DEC (pt, pt MOD 1000H);
SYSTEM.GET(pt + pte * AddressSize, t);
SYSTEM.PUT(pt + pte * AddressSize, NIL);
INVLPG (t);
RETURN t;
END UnmapPage;
PROCEDURE MapDirect(virtAdr: SYSTEM.ADDRESS; size: SYSTEM.SIZE; phys: SYSTEM.ADDRESS): BOOLEAN;
BEGIN
ASSERT((virtAdr MOD PS = 0) & (size MOD PS = 0));
WHILE size # 0 DO
IF ~ODD(MappedPage(virtAdr)) THEN
IF ~MapPage(virtAdr, phys) THEN RETURN FALSE END
END;
INC(virtAdr, PS); INC(phys, PS); DEC(size, PS)
END;
RETURN TRUE
END MapDirect;
PROCEDURE ExpandNow(try: LONGINT): BOOLEAN;
VAR size: SYSTEM.SIZE;
BEGIN
size := SYSTEM.LSH(memBlockTail.endBlockAdr - memBlockHead.beginBlockAdr, -10);
RETURN (~ODD(try) OR (size < heapMinKB)) & (size < heapMaxKB)
END ExpandNow;
PROCEDURE ExpandHeap*(try: LONGINT; size: SYSTEM.SIZE; VAR memBlock: MemoryBlock; VAR beginBlockAdr, endBlockAdr: SYSTEM.ADDRESS);
BEGIN
IF ExpandNow(try) THEN
IF size < expandMin THEN size := expandMin END;
beginBlockAdr := memBlockHead.endBlockAdr;
endBlockAdr := beginBlockAdr;
INC(endBlockAdr, size);
SetHeapEndAdr(endBlockAdr);
memBlock := memBlockHead;
ELSE
beginBlockAdr := memBlockHead.endBlockAdr;
endBlockAdr := memBlockHead.endBlockAdr;
memBlock := NIL
END
END ExpandHeap;
PROCEDURE SetMemoryBlockEndAddress*(memBlock: MemoryBlock; endBlockAdr: SYSTEM.ADDRESS);
BEGIN
ASSERT(endBlockAdr >= memBlock.beginBlockAdr);
memBlock.endBlockAdr := endBlockAdr
END SetMemoryBlockEndAddress;
PROCEDURE FreeMemBlock*(memBlock: MemoryBlock);
BEGIN
HALT(515)
END FreeMemBlock;
PROCEDURE SetHeapEndAdr(VAR endAdr: SYSTEM.ADDRESS);
VAR n, m: SYSTEM.SIZE;
BEGIN
Acquire(Memory);
n := SYSTEM.LSH(endAdr+(PS-1), -PSlog2) - SYSTEM.LSH(heapEndAdr, -PSlog2);
m := SYSTEM.LSH(pageHeapAdr, -PSlog2) - SYSTEM.LSH(heapEndAdr, -PSlog2) - ReservedPages;
IF n > m THEN n := m END;
IF n > 0 THEN INC(heapEndAdr, n*PS); DEC(freeHighPages, n) END;
endAdr := heapEndAdr;
Release(Memory)
END SetHeapEndAdr;
PROCEDURE MapPhysical*(physAdr: SYSTEM.ADDRESS; size: SYSTEM.SIZE; VAR virtAdr: SYSTEM.ADDRESS);
VAR ofs: SYSTEM.ADDRESS;
BEGIN
IF (SYSTEM.LSH(physAdr, -PSlog2) <= topPageNum) &
(SYSTEM.LSH(physAdr+size-1, -PSlog2) <= topPageNum) &
(SYSTEM.LSH(physAdr, -PSlog2) >= SYSTEM.LSH(LowAdr, -PSlog2)) THEN
virtAdr := physAdr
ELSE
ofs := physAdr MOD PS;
DEC(physAdr, ofs); INC(size, ofs);
INC(size, (-size) MOD PS);
Acquire(Memory);
NewVirtual(virtAdr, size);
IF virtAdr # NilAdr THEN
IF ~MapDirect(virtAdr, size, physAdr + UserPage) THEN
DisposeVirtual(virtAdr, size);
virtAdr := NilAdr
END
END;
Release(Memory);
IF TraceVerbose THEN
Acquire (TraceOutput);
Trace.String("Mapping ");
Trace.IntSuffix(SHORT(size), 1, "B"); Trace.String(" at ");
Trace.Address (physAdr); Trace.String (" - "); Trace.Address (physAdr+size-1);
IF virtAdr = NilAdr THEN
Trace.String(" failed")
ELSE
Trace.String (" to "); Trace.Address (virtAdr);
IF ofs # 0 THEN Trace.String (", offset "); Trace.Int(SHORT(ofs), 0) END
END;
Trace.Ln;
Release (TraceOutput);
END;
IF virtAdr # NilAdr THEN INC(virtAdr, ofs) END
END
END MapPhysical;
PROCEDURE UnmapPhysical*(virtAdr: SYSTEM.ADDRESS; size: SYSTEM.SIZE);
END UnmapPhysical;
PROCEDURE PhysicalAdr*(adr: SYSTEM.ADDRESS; size: SYSTEM.SIZE): SYSTEM.ADDRESS;
VAR physAdr, mapped, expected: SYSTEM.ADDRESS;
BEGIN
IF (SYSTEM.LSH(adr, -PSlog2) <= topPageNum) & (SYSTEM.LSH(adr+size-1, -PSlog2) <= topPageNum) THEN
RETURN adr
ELSE
Acquire(Memory);
mapped := MappedPage(adr);
Release(Memory);
IF ODD(mapped) & (size > 0) THEN
physAdr := mapped - mapped MOD PS + adr MOD PS;
DEC(size, PS - adr MOD PS);
IF size > 0 THEN
expected := SYSTEM.LSH(mapped, -PSlog2)+1;
LOOP
INC(adr, PS);
Acquire(Memory);
mapped := MappedPage(adr);
Release(Memory);
IF ~ODD(mapped) OR (SYSTEM.LSH(mapped, -PSlog2) # expected) THEN
physAdr := NilAdr; EXIT
END;
DEC(size, PS);
IF size <= 0 THEN EXIT END;
INC(expected)
END
ELSE
END
ELSE
physAdr := NilAdr
END;
RETURN physAdr
END
END PhysicalAdr;
PROCEDURE TranslateVirtual*(virtAdr: SYSTEM.ADDRESS; size: SYSTEM.SIZE; VAR num: LONGINT; VAR physAdr: ARRAY OF Range);
VAR ofs, phys1: SYSTEM.ADDRESS; size1: SYSTEM.SIZE;
BEGIN
Acquire(Memory);
num := 0;
LOOP
IF size = 0 THEN EXIT END;
IF num = LEN(physAdr) THEN num := 0; EXIT END;
ofs := virtAdr MOD PS;
size1 := PS - ofs;
IF size1 > size THEN size1 := size END;
phys1 := MappedPage(virtAdr);
IF ~ODD(phys1) THEN num := 0; EXIT END;
physAdr[num].adr := phys1 - phys1 MOD PS + ofs;
physAdr[num].size := size1; INC(num);
INC(virtAdr, size1); DEC(size, size1)
END;
IF num = 0 THEN physAdr[0].adr := NilAdr; physAdr[0].size := 0 END;
Release(Memory)
END TranslateVirtual;
PROCEDURE GetFreeK*(VAR total, lowFree, highFree: SYSTEM.SIZE);
CONST KperPage = PS DIV 1024;
BEGIN
Acquire(Memory);
total := totalPages * KperPage;
lowFree := freeLowPages * KperPage;
highFree := freeHighPages * KperPage;
Release(Memory)
END GetFreeK;
PROCEDURE ExtendStack*(VAR s: Stack; virtAdr: SYSTEM.ADDRESS): BOOLEAN;
VAR phys: SYSTEM.ADDRESS; ok: BOOLEAN;
BEGIN
Acquire(Memory);
ok := FALSE;
IF (virtAdr < s.high) & (virtAdr >= s.low) THEN
DEC(virtAdr, virtAdr MOD PS);
IF Stats & (virtAdr < s.adr-PS) THEN INC(Nbigskips) END;
IF ODD(MappedPage(virtAdr)) THEN
ok := TRUE
ELSE
NewPage(phys);
IF phys # NilAdr THEN
IF MapPage(virtAdr, phys + UserPage) THEN
IF virtAdr < s.adr THEN
s.adr := virtAdr
ELSE
IF Stats THEN INC(Nfilled) END
END;
ok := TRUE
ELSE
DisposePage(phys)
END
END
END
END;
Release(Memory);
RETURN ok
END ExtendStack;
PROCEDURE NewStack*(VAR s: Stack; process: ANY; VAR initSP: SYSTEM.ADDRESS);
VAR adr, phys: SYSTEM.ADDRESS; old: HUGEINT; free: SET;
BEGIN
ASSERT(InitUserStackSize = PS);
Acquire(Memory);
IF Stats THEN INC(NnewStacks) END;
old := freeStackIndex;
LOOP
IF Stats THEN INC(NnewStackLoops) END;
free := freeStack[freeStackIndex];
IF free # {} THEN
adr := 0; WHILE ~(adr IN free) DO INC(adr) END;
IF Stats THEN INC(NnewStackInnerLoops, adr+1) END;
EXCL(freeStack[freeStackIndex], adr);
adr := 10000000H + (freeStackIndex*SetSize + adr)*MaxUserStackSize;
EXIT
END;
INC(freeStackIndex);
IF freeStackIndex = LEN(freeStack) THEN freeStackIndex := 0 END;
IF freeStackIndex = old THEN HALT(1503) END
END;
NewPage(phys); ASSERT(phys # NilAdr);
s.high := adr + MaxUserStackSize; s.low := adr + UserStackGuardSize;
s.adr := s.high - InitUserStackSize;
initSP := s.high-AddressSize;
IF ~MapPage(s.adr, phys + UserPage) THEN HALT(99) END;
SYSTEM.PUT (initSP, process);
Release(Memory)
END NewStack;
PROCEDURE -GetProcessPtr* (): ANY;
CODE {SYSTEM.AMD64}
MOV RAX, -MaxUserStackSize
AND RAX, RSP
MOV RAX, [RAX + MaxUserStackSize - 8]
POP RBX; pointer return passed via stack
MOV [RBX], RAX
END GetProcessPtr;
PROCEDURE WorkingOnKernelStack* (): BOOLEAN;
VAR id: LONGINT; sp: SYSTEM.ADDRESS;
BEGIN
ASSERT(KernelStackSize # MaxUserStackSize - UserStackGuardSize);
sp := CurrentSP ();
id := ID ();
RETURN (sp >= procm[id].stack.low) & (sp <= procm[id].stack.high)
END WorkingOnKernelStack;
PROCEDURE DisposeStack*(CONST s: Stack);
VAR adr, phys: SYSTEM.ADDRESS;
BEGIN
GlobalFlushTLB;
Acquire(Memory);
IF Stats THEN INC(NdisposeStacks) END;
adr := s.adr;
REPEAT
phys := UnmapPage(adr);
IF ODD(phys) THEN DisposePage(phys - phys MOD PS) END;
INC(adr, PS)
UNTIL adr = s.high;
adr := (adr - MaxUserStackSize - StackAreaAdr) DIV MaxUserStackSize;
INCL(freeStack[adr DIV 32], adr MOD 32);
Release(Memory)
END DisposeStack;
PROCEDURE ValidStack*(CONST s: Stack; sp: SYSTEM.ADDRESS): BOOLEAN;
VAR valid: BOOLEAN;
BEGIN
Acquire(Memory);
valid := (sp MOD 4 = 0) & (sp >= s.adr) & (sp <= s.high);
WHILE valid & (sp < s.high) DO
valid := ODD(MappedPage(sp));
INC(sp, PS)
END;
Release(Memory);
RETURN valid
END ValidStack;
PROCEDURE UpdateState*;
VAR id: LONGINT;
BEGIN
ASSERT(CS () MOD 4 = 0);
id := ID ();
ASSERT(procm[id].stack.high # 0);
procm[id].sp := CurrentBP ()
END UpdateState;
PROCEDURE GetKernelStacks*(VAR stack: ARRAY OF Stack);
VAR i: LONGINT;
BEGIN
FOR i := 0 TO MaxCPU-1 DO
stack[i].adr := procm[i].sp;
stack[i].high := procm[i].stack.high
END
END GetKernelStacks;
PROCEDURE InitPages;
VAR i, j: HUGEINT; phys, lTop, mTop: SYSTEM.ADDRESS;
BEGIN
mTop := memTop;
DEC(mTop, mTop MOD PS);
topPageNum := SYSTEM.LSH(mTop-1, -PSlog2);
lTop := lowTop;
DEC(lTop, lTop MOD PS);
SYSTEM.GET (LinkAdr + EndBlockOfs, heapEndAdr);
pageHeapAdr := mTop;
freeHighPages := SYSTEM.LSH(pageHeapAdr, -PSlog2) - SYSTEM.LSH(heapEndAdr, -PSlog2);
IF TraceVerbose THEN
Trace.String("Kernel: "); Trace.Address (LinkAdr); Trace.String(" .. ");
Trace.Address (heapEndAdr-1); Trace.Ln;
Trace.String ("High: "); Trace.Address (heapEndAdr); Trace.String(" .. ");
Trace.Address (pageHeapAdr-1); Trace.String(" = "); Trace.Int (SHORT(freeHighPages),0);
Trace.StringLn (" free pages")
END;
NewDirectPage(pageStackAdr); ASSERT(pageStackAdr # NilAdr);
SYSTEM.PUT (pageStackAdr+NodeSP, SYSTEM.VAL (SYSTEM.ADDRESS, MinSP));
SYSTEM.PUT (pageStackAdr+NodeNext, SYSTEM.VAL (SYSTEM.ADDRESS, NilAdr));
SYSTEM.PUT (pageStackAdr+NodePrev, SYSTEM.VAL (SYSTEM.ADDRESS, NilAdr));
freeLowPage := NilAdr; freeLowPages := 0;
i := lTop DIV PS; j := LowAdr DIV PS;
IF TraceVerbose THEN
Trace.String("Low: "); Trace.Address (j*PS); Trace.String (".."); Trace.Address (i*PS-1)
END;
REPEAT
DEC(i); phys := i*PS;
SYSTEM.PUT (phys, freeLowPage);
freeLowPage := phys; INC(freeLowPages)
UNTIL i = j;
IF TraceVerbose THEN
Trace.String(" = "); Trace.Int(SHORT(freeLowPages), 1); Trace.StringLn (" free pages")
END;
totalPages := SYSTEM.LSH(memTop - M + lowTop + dmaSize + PS, -PSlog2);
ASSERT((StackAreaAdr MOD MaxUserStackSize = 0) & (StackAreaSize MOD MaxUserStackSize = 0));
FOR i := 0 TO LEN(freeStack)-1 DO freeStack[i] := {0..SetSize-1} END;
FOR i := MaxUserStacks TO LEN(freeStack)*SetSize-1 DO EXCL(freeStack[i DIV SetSize], i MOD SetSize) END;
freeStackIndex := 0;
mapTop := MapAreaAdr;
NewPage(kernelPML4); ASSERT(kernelPML4 # NilAdr);
Fill32(kernelPML4, TPS, PageNotPresent);
IF ~MapDirect(LowAdr, memTop-LowAdr, LowAdr + UserPage) THEN HALT(99) END
END InitPages;
PROCEDURE GenCodeSegDesc (dpl, base, limit: LONGINT; conforming, longmode: BOOLEAN; VAR sd: SegDesc);
VAR s: SET;
BEGIN
sd.low := ASH(base MOD 10000H, 16) + limit MOD 10000H;
s := SYSTEM.VAL(SET, ASH(ASH(base, -24), 24) + ASH(ASH(limit, -16), 16) +
ASH(dpl, 13) + ASH(base, -16) MOD 100H);
s := s + {9, 11, 12, 15, 23};
IF conforming THEN INCL(s, 10) END;
IF longmode THEN INCL(s, 21) ELSE INCL (s, 22) END;
sd.high := SYSTEM.VAL(LONGINT, s)
END GenCodeSegDesc;
PROCEDURE GenDataSegDesc (dpl, base, limit: LONGINT; VAR sd: SegDesc);
VAR s: SET;
BEGIN
sd.low := ASH(base MOD 10000H, 16) + limit MOD 10000H;
s := SYSTEM.VAL(SET, ASH(ASH(base, -24), 24) + ASH(ASH(limit, -16), 16) +
ASH(dpl, 13) + ASH(base, -16) MOD 100H);
s := s + {9, 12, 15, 22, 23};
sd.high := SYSTEM.VAL(LONGINT, s)
END GenDataSegDesc;
PROCEDURE GenTSSDesc(base: SYSTEM.ADDRESS; limit, dpl: LONGINT; VAR sdl, sdh: SegDesc);
VAR s: SET;
BEGIN
sdl.low := SYSTEM.VAL(LONGINT, ASH(base MOD 10000H, 16) + limit MOD 10000H);
s := SYSTEM.VAL(SET, ASH(ASH(base, -24), 24) + ASH(ASH(limit, -16), 16) +
ASH(dpl, 13) + ASH(base, -16) MOD 100H);
s := s + {8, 11, 15};
sdl.high := SYSTEM.VAL(LONGINT, s);
sdh.low := SYSTEM.VAL(LONGINT, base DIV 10000000H);
sdh.high := 0;
END GenTSSDesc;
PROCEDURE InitSegments;
VAR i: LONGINT;
BEGIN
gdt[0].low := 0; gdt[0].high := 0;
GenCodeSegDesc(0, 0, M-1, FALSE, FALSE, gdt[1]);
GenCodeSegDesc(0, 0, M-1, FALSE, TRUE, gdt[2]);
GenCodeSegDesc(0, 0, M-1, TRUE, FALSE, gdt[3]);
GenCodeSegDesc(0, 0, M-1, TRUE, TRUE, gdt[4]);
GenDataSegDesc(0, 0, M-1, gdt[5]);
GenDataSegDesc(3, 0, M-1, gdt[6]);
GenDataSegDesc(3, 0, M-1, gdt[7]);
FOR i := 0 TO MaxCPU-1 DO
GenTSSDesc(SYSTEM.ADR(procm[i].tss), SYSTEM.SIZEOF(TSSDesc)-1, 0, gdt[TSSOfs+i*2], gdt[TSSOfs+i*2 + 1]);
procm[i].sp := 0; procm[i].stack.high := 0
END
END InitSegments;
PROCEDURE EnableSegments;
BEGIN
LoadGDT(SYSTEM.ADR(gdt[0]), SYSTEM.SIZEOF(GDT)-1);
LoadSegRegs(DataSel)
END EnableSegments;
PROCEDURE NewKernelStack(VAR stack: Stack);
VAR phys, virt: SYSTEM.ADDRESS; size: SYSTEM.SIZE;
BEGIN
size := KernelStackSize;
NewVirtual(virt, size + PS);
ASSERT(virt # NilAdr, 1502);
INC(virt, PS);
stack.low := virt;
stack.adr := virt;
REPEAT
NewPage(phys); ASSERT(phys # NilAdr);
IF ~MapPage(virt, phys + KernelPage) THEN HALT(99) END;
DEC(size, PS); INC(virt, PS)
UNTIL size = 0;
stack.high := virt
END NewKernelStack;
PROCEDURE -SetTR(tr: SYSTEM.ADDRESS);
CODE {SYSTEM.AMD64, SYSTEM.Privileged}
POP RAX
LTR AX
END SetTR;
PROCEDURE -EnableMM(pml4Base, rsp: SYSTEM.ADDRESS);
CODE {SYSTEM.AMD64, SYSTEM.Privileged}
POP RBX
POP RAX
MOV RCX, [RBP + 8] ; caller0 return
MOV RDX, [RBP] ; caller0 RBP
MOV RDX, [RDX + 8] ; caller 1 return
MOV CR3, RAX ; pml4 page translation base address
XOR RAX, RAX
MOV [RBX - 8], RAX ; not UserStackSel (cf. GetUserStack)
MOV [RBX - 16], RDX ; caller1 return on new stack
MOV [RBX - 24], RAX ; caller1 RBP on new stack
LEA RBP, [RBX - 24] ; new stack top
MOV RSP, RBP
JMP RCX
END EnableMM;
PROCEDURE InitMemory*;
VAR id: LONGINT;
BEGIN
EnableSegments;
id := ID ();
NewKernelStack(procm[id].stack);
procm[id].sp := 0;
Fill32(SYSTEM.ADR(procm[id].tss), SYSTEM.SIZEOF(TSSDesc), 0);
procm[id].tss.RSP0 := procm[id].stack.high;
procm[id].tss.IOMapBaseAddress := -1;
SetTR(KernelTR + id*16);
EnableMM(kernelPML4, procm[id].tss.RSP0)
END InitMemory;
PROCEDURE InitBootPage*(start: Startup; VAR physAdr: SYSTEM.ADDRESS);
CONST BootOfs = 800H;
VAR adr, a: SYSTEM.ADDRESS;
BEGIN
Acquire(Memory);
NewLowPage(physAdr);
Release(Memory);
ASSERT((physAdr # NilAdr) & (physAdr >= 0) & (physAdr < M) & (physAdr MOD PS = 0));
adr := physAdr + BootOfs;
a := adr;
SYSTEM.PUT32(a, 0002F10EBH); INC (a, 4);
SYSTEM.PUT32(a, 000000000H); INC (a, 4);
SYSTEM.PUT32(a, 000000000H); INC (a, 4);
SYSTEM.PUT32(a, 000000000H); INC (a, 4);
SYSTEM.PUT32(a, 031660000H); INC (a, 4);
SYSTEM.PUT32(a, 066C88CC0H); INC (a, 4);
SYSTEM.PUT32(a, 02E04E0C1H); INC (a, 4);
SYSTEM.PUT32(a, 04A060966H); INC (a, 4);
SYSTEM.PUT32(a, 0010F2E08H); INC (a, 4);
SYSTEM.PUT32(a, 02E08081EH); INC (a, 4);
SYSTEM.PUT32(a, 00216010FH); INC (a, 4);
SYSTEM.PUT32(a, 0C4896608H); INC (a, 4);
SYSTEM.PUT32(a, 000C48166H); INC (a, 4);
SYSTEM.PUT32(a, 00F000008H); INC (a, 4);
SYSTEM.PUT32(a, 00F66C020H); INC (a, 4);
SYSTEM.PUT32(a, 00F00E8BAH); INC (a, 4);
SYSTEM.PUT32(a, 0662EC022H); INC (a, 4);
SYSTEM.PUT32(a, 0080E1E8BH); INC (a, 4);
SYSTEM.PUT32(a, 00850EA66H); INC (a, 4);
SYSTEM.PUT32(a, 000080000H); INC (a, 4);
SYSTEM.PUT32(a, 00FE0200FH); INC (a, 4);
SYSTEM.PUT32(a, 00F05E8BAH); INC (a, 4);
SYSTEM.PUT32(a, 0220FE022H); INC (a, 4);
SYSTEM.PUT32(a, 00080B9DBH); INC (a, 4);
SYSTEM.PUT32(a, 0320FC000H); INC (a, 4);
SYSTEM.PUT32(a, 008E8BA0FH); INC (a, 4);
SYSTEM.PUT32(a, 0200F300FH); INC (a, 4);
SYSTEM.PUT32(a, 0E8BA0FC0H); INC (a, 4);
SYSTEM.PUT32(a, 0C0220F1FH); INC (a, 4);
SYSTEM.PUT32(a, 0000000EAH); INC (a, 4);
SYSTEM.PUT16(a, 01000H); INC (a, 2);
SYSTEM.PUT8(a, 000H); INC (a);
SYSTEM.PUT32 (adr+14, SYSTEM.VAL (LONGINT, kernelPML4));
SYSTEM.PUT32 (adr+117, SYSTEM.VAL (LONGINT, start));
SYSTEM.PUT32 (adr+4, SYSTEM.VAL (LONGINT, SYSTEM.ADR(gdt[0])));
SYSTEM.PUT8(physAdr, 0EAX);
SYSTEM.PUT32(physAdr + 1, ASH(physAdr, 16-4) + BootOfs)
END InitBootPage;
PROCEDURE InitAPICArea*(adr: SYSTEM.ADDRESS; size: SYSTEM.SIZE);
BEGIN
IF ~MapDirect(adr, size, adr + UserPage) THEN HALT(99) END
END InitAPICArea;
PROCEDURE SetGCParams*;
VAR size, t: SYSTEM.SIZE;
BEGIN
GetFreeK(size, t, t);
heapMinKB := size * HeapMin DIV 100;
heapMaxKB := size * HeapMax DIV 100;
expandMin := size * ExpandRate DIV 100 * 1024;
IF expandMin < 0 THEN expandMin := MAX(LONGINT) END;
gcThreshold := size * Threshold DIV 100 * 1024;
IF gcThreshold < 0 THEN gcThreshold := MAX(LONGINT) END
END SetGCParams;
PROCEDURE GetStaticHeap*(VAR beginBlockAdr, endBlockAdr, freeBlockAdr: SYSTEM.ADDRESS);
BEGIN
beginBlockAdr := initialMemBlock.beginBlockAdr;
endBlockAdr := initialMemBlock.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 JumpToUserLevel*(userRBP: SYSTEM.ADDRESS);
CODE {SYSTEM.AMD64, SYSTEM.Privileged}
PUSH UserStackSel ; SS3
PUSH QWORD [RBP + userRBP] ; RSP3
PUSHFQ ; RFLAGS3
PUSH User64CodeSel ; CS3
CALL DWORD L1 ; PUSH L1 (RIP3)
L1:
ADD QWORD [RSP], BYTE 7 ; adjust RIP3 to L2 (L2-L1 should be 7)
IRETQ ; switch to level 3 and continue at following instruction
L2:
POP RBP ; from level 3 stack (refer to AosActive.NewProcess)
RET 16 ; jump to body of first active object; cf. Objects.NewProcess
END JumpToUserLevel;
PROCEDURE Ensure32BitAddress*(adr: SYSTEM.ADDRESS): Address32;
BEGIN
ASSERT (Is32BitAddress (adr), 9876);
RETURN SYSTEM.VAL (Address32, adr)
END Ensure32BitAddress;
PROCEDURE Is32BitAddress*(adr: SYSTEM.ADDRESS): BOOLEAN;
BEGIN RETURN SYSTEM.VAL (Address32, adr) = adr;
END Is32BitAddress;
PROCEDURE Unexpected(VAR state: State);
VAR int: HUGEINT; isr, irr: CHAR;
BEGIN
int := state.INT;
IF HandleSpurious & ((int >= IRQ0) & (int <= MaxIRQ) OR (int = MPSPU)) THEN
IF (int >= IRQ8) & (int <= IRQ15) THEN
Portout8 (IntB0, 0BX); Portin8(IntB0, isr);
Portout8 (IntB0, 0AX); Portin8(IntB0, irr)
ELSIF (int >= IRQ0) & (int <= IRQ7) THEN
Portout8 (IntA0, 0BX); Portin8(IntA0, isr);
Portout8 (IntA0, 0AX); Portin8(IntA0, irr)
ELSE
isr := 0X; irr := 0X
END;
IF TraceSpurious THEN
Acquire (TraceOutput);
Trace.String("INT"); Trace.Int(SHORT(int), 1);
Trace.Hex(ORD(isr), -3); Trace.Hex(ORD(irr), -2); Trace.Ln;
Release (TraceOutput);
END
ELSE
Acquire (TraceOutput);
Trace.StringLn ("Unexpected interrupt");
Trace.Memory(SYSTEM.ADR(state), SYSTEM.SIZEOF(State)-4*8);
IF int = 3 THEN
LOOP END
ELSE
Release (TraceOutput);
SetRAX(int);
HALT(1801)
END
END
END Unexpected;
PROCEDURE -InEnableIRQ (int: HUGEINT);
CODE {SYSTEM.AMD64}
POP RBX
CMP RBX, IRQ7
JG cont2
IN AL, IntA1
SUB RBX, IRQ0
BTR RAX, RBX
OUT IntA1, AL
JMP end
cont2:
IN AL, IntB1
SUB RBX, IRQ8
BTR RAX, RBX
OUT IntB1, AL
end:
END InEnableIRQ;
PROCEDURE -InDisableIRQ (int: HUGEINT);
CODE {SYSTEM.AMD64}
POP RBX
CMP RBX, IRQ7
JG cont2
IN AL, IntA1
SUB RBX, IRQ0
BTS RAX, RBX
OUT IntA1, AL
JMP end
cont2:
IN AL, IntB1
SUB RBX, IRQ8
BTS RAX, RBX
OUT IntB1, AL
end:
END InDisableIRQ;
PROCEDURE EnableIRQ* (int: HUGEINT);
BEGIN
Acquire(Interrupts);
InEnableIRQ(int);
Release(Interrupts)
END EnableIRQ;
PROCEDURE DisableIRQ* (int: HUGEINT);
BEGIN
ASSERT((int >= IRQ0) & (int <= IRQ15) & (int # IRQ2));
Acquire(Interrupts);
InDisableIRQ(int);
Release(Interrupts)
END DisableIRQ;
PROCEDURE InstallHandler* (h: Handler; int: LONGINT);
VAR i: LONGINT; unexpected: Handler;
BEGIN
ASSERT(default.valid);
ASSERT(int # IRQ2);
Acquire(Interrupts);
i := 0;
unexpected := Unexpected;
IF intHandler[int, 0].handler # unexpected THEN
WHILE (i < MaxNumHandlers - 1) & intHandler[int, i].valid DO
INC(i)
END;
IF i < MaxNumHandlers - 1 THEN
intHandler[int, i].valid := TRUE;
intHandler[int, i].handler := h;
ELSE
Acquire(TraceOutput);
Trace.String("Machine.InstallHandler: handler could not be installed for interrupt "); Trace.Int(int, 0);
Trace.String(" - too many handlers per interrupt number"); Trace.Ln;
Release(TraceOutput)
END
ELSE
intHandler[int, 0].handler := h;
IF (int >= IRQ0) & (int <= IRQ15) THEN InEnableIRQ(int) END
END;
Release(Interrupts)
END InstallHandler;
PROCEDURE RemoveHandler* (h: Handler; int: LONGINT);
VAR i, j, foundIndex: LONGINT;
BEGIN
ASSERT(default.valid);
Acquire(Interrupts);
i := 0;
foundIndex := -1;
WHILE (i < MaxNumHandlers - 1) & intHandler[int, i].valid DO
IF intHandler[int, i].handler = h THEN foundIndex := i END;
INC(i)
END;
IF foundIndex # -1 THEN
FOR j := foundIndex TO i - 2 DO
intHandler[int, j] := intHandler[int, j + 1]
END
END;
IF ~intHandler[int, 0].valid THEN
intHandler[int, 0] := default;
IF (int >= IRQ0) & (int <= IRQ15) THEN DisableIRQ(int) END
END;
Release(Interrupts)
END RemoveHandler;
PROCEDURE GetCR0to4(VAR cr: ARRAY OF HUGEINT);
CODE {SYSTEM.AMD64, SYSTEM.Privileged}
MOV RDI, [RBP + cr]
MOV RAX, CR0
XOR RBX, RBX ; CR1 is not documented
MOV RCX, CR2
MOV RDX, CR3
MOV [RDI + 0], RAX
MOV [RDI + 8], RBX
MOV [RDI + 16], RCX
MOV [RDI + 24], RDX
MOV RAX, CR4 ; Pentium only
MOV [RDI + 32], RAX
END GetCR0to4;
PROCEDURE GetDR0to7(VAR dr: ARRAY OF HUGEINT);
CODE {SYSTEM.AMD64, SYSTEM.Privileged}
MOV RDI, [RBP + dr]
MOV RAX, DR0
MOV RBX, DR1
MOV RCX, DR2
MOV RDX, DR3
MOV [RDI + 0], RAX
MOV [RDI + 8], RBX
MOV [RDI + 16], RCX
MOV [RDI + 24], RDX
XOR RAX, RAX ; DR4 is not documented
XOR RBX, RBX ; DR5 is not documented
MOV RCX, DR6
MOV RDX, DR7
MOV [RDI + 32], RAX
MOV [RDI + 40], RBX
MOV [RDI + 48], RCX
MOV [RDI + 56], RDX
END GetDR0to7;
PROCEDURE -CLTS;
CODE {SYSTEM.AMD64, SYSTEM.Privileged}
CLTS
END CLTS;
PROCEDURE -GetFPU(adr: SYSTEM.ADDRESS);
CODE {SYSTEM.AMD64, SYSTEM.FPU}
POP RBX
FNSTENV [RBX] ; also masks all exceptions
FWAIT
END GetFPU;
PROCEDURE -CR2* (): SYSTEM.ADDRESS;
CODE {SYSTEM.AMD64, SYSTEM.Privileged}
MOV RAX, CR2
END CR2;
PROCEDURE GetExceptionState* (VAR int: State; VAR exc: ExceptionState);
VAR id: LONGINT; level0: BOOLEAN;
BEGIN
exc.halt := -int.INT; id := ID ();
IF int.INT = PF THEN exc.pf := CR2 () ELSE exc.pf := 0 END;
GetCR0to4(exc.CR);
GetDR0to7(exc.DR);
CLTS;
IF int.INT = MF THEN
GetFPU(SYSTEM.ADR(exc.FPU[0]));
int.PC := SYSTEM.VAL (SYSTEM.ADDRESS, exc.FPU[3]);
IF 2 IN exc.FPU[1] THEN exc.halt := -32
ELSIF 3 IN exc.FPU[1] THEN exc.halt := -33
ELSIF 0 IN exc.FPU[1] THEN exc.halt := -34
ELSIF 6 IN exc.FPU[1] THEN exc.halt := -35
ELSIF 1 IN exc.FPU[1] THEN exc.halt := -36
ELSIF 4 IN exc.FPU[1] THEN exc.halt := -37
ELSIF 5 IN exc.FPU[1] THEN exc.halt := -38
ELSE
END
ELSE
Fill32(SYSTEM.ADR(exc.FPU[0]), LEN(exc.FPU)*SYSTEM.SIZEOF(SET), 0)
END;
SetupFPU;
level0 := (int.CS MOD 4 = KernelLevel);
IF int.INT = BP THEN
IF level0 THEN
exc.halt := int.SP
ELSE
SYSTEM.GET (int.SP, exc.halt);
IF exc.halt >= MAX(INTEGER) THEN INC (int.SP, AddressSize) END
END;
IF exc.halt < MAX(INTEGER) THEN DEC (int.PC) END;
ELSIF int.INT = OVF THEN
DEC (int.PC)
ELSIF int.INT = PF THEN
IF int.PC = 0 THEN
IF level0 THEN int.PC := int.SP ELSE SYSTEM.GET (int.SP, int.PC) END
END
END;
IF level0 THEN
exc.SP := SYSTEM.ADR(int.SP)
ELSE
exc.SP := int.SP
END
END GetExceptionState;
PROCEDURE {NOPAF} FieldInterrupt;
CONST SizeOfHandlerRec = SYSTEM.SIZEOF(HandlerRec);
CODE {SYSTEM.AMD64, SYSTEM.Privileged}
entry:
; fake PUSHAD (not available in 64-bit mode)
PUSH RAX
PUSH RCX
PUSH RDX
PUSH RBX ; (error code)
LEA RAX, [RSP - 4 * 8] ; (RSP minus the four pushed 64-bit registers)
PUSH RAX ; original value of RSP
PUSH RBP
PUSH RSI
PUSH RDI
PUSH R8
PUSH R9
PUSH R10
PUSH R11
PUSH R12
PUSH R13
PUSH R14
PUSH R15
LEA RBP, [RSP + 136]
MOV RBX, [RSP + 128] ; RBX = int number
IMUL RBX, RBX, MaxNumHandlers
IMUL RBX, RBX, SizeOfHandlerRec
; todo: replace LEA by MOV when compiler supports this
LEA RAX, intHandler
ADD RAX, RBX ; address of intHandler[int, 0]
; todo: replace LEA by MOV when compiler supports this
LEA RDX, stateTag
loop: ; call all handlers for the interrupt
MOV RCX, RSP
PUSH RAX ; save ptr for table
PUSH RDX ; TAG(state)
PUSH RCX ; ADR(state)
MOV RBX, [RAX + 12] ; check for delegate
CMP RBX, 0
JE nodelegate
PUSH RBX ; object pointer for DELEGATE
nodelegate:
CALL QWORD [RAX+4] ; call handler
CLI ; handler may have re-enabled interrupts
POP RAX
ADD RAX, SizeOfHandlerRec
MOV RBX, [RAX]
CMP RBX, 0
JNE loop
; fake POPAD (not available in 64-bit mode)
POP R15
POP R14
POP R13
POP R12
POP R11
POP R10
POP R9
POP R8
POP RDI
POP RSI
POP RBP
ADD RSP, 8 ;POP RSP
POP RBX
POP RDX
POP RCX
POP RAX ; now EBP = error code
POP RBP ; now EBP = INT
POP RBP ; now EBP = caller RBP
IRETQ
END FieldInterrupt;
PROCEDURE {NOPAF} FieldIRQ;
CONST SizeOfHandlerRec = SYSTEM.SIZEOF(HandlerRec);
CODE {SYSTEM.AMD64}
entry:
; fake PUSHAD (not available in 64-bit mode)
PUSH RAX
PUSH RCX
PUSH RDX
PUSH RBX ; (error code)
LEA RAX, [RSP - 4 * 8] ; (RSP minus the four pushed 64-bit registers)
PUSH RAX ; original value of RSP
PUSH RBP
PUSH RSI
PUSH RDI
PUSH R8
PUSH R9
PUSH R10
PUSH R11
PUSH R12
PUSH R13
PUSH R14
PUSH R15
LEA RBP, [RSP + 136]
;; PUSH 32[ESP] ; int number
;; CALL traceInterruptIn
MOV RBX, [RSP + 128] ; RBX = int number
IMUL RBX, RBX, MaxNumHandlers
IMUL RBX, RBX, SizeOfHandlerRec
; todo: replace LEA by MOV when compiler supports this
LEA RAX, intHandler
ADD RAX, RBX ; address of intHandler[int, 0]
; todo: replace LEA by MOV when compiler supports this
LEA RDX, stateTag
loop: ; call all handlers for the interrupt
MOV RCX, RSP
PUSH RAX ; save ptr for linked list
PUSH RDX ; TAG(state)
PUSH RCX ; ADR(state)
MOV RBX, [RAX + 12] ; check for delegate
CMP RBX, 0
JE nodelegate
PUSH RBX ; object pointer for DELEGATE
nodelegate:
CALL QWORD [RAX + 4] ; call handler
CLI ; handler may have re-enabled interrupts
POP RAX
ADD RAX, SizeOfHandlerRec
MOV RBX, [RAX]
CMP RBX, 0
JNE loop
;; PUSH 32[ESP] ; int number
;; CALL traceInterruptOut
; ack interrupt
MOV AL, 20H ; undoc PC ed. 2 p. 1018
CMP BYTE [RSP + 128], IRQ8
JB irq0
OUT IntB0, AL ; 2nd controller
irq0:
OUT IntA0, AL ; 1st controller
; fake POPAD (not available in 64-bit mode)
POP R15
POP R14
POP R13
POP R12
POP R11
POP R10
POP R9
POP R8
POP RDI
POP RSI
POP RBP
ADD RSP, 8 ;POP RSP
POP RBX
POP RDX
POP RCX
POP RAX ; now RBP = error code
POP RBP ; now RBP = INT
POP RBP ; now RBP = caller RBP
IRETQ
END FieldIRQ;
PROCEDURE LoadIDT(base: SYSTEM.ADDRESS; size: SYSTEM.SIZE);
CODE {SYSTEM.AMD64, SYSTEM.Privileged}
; LIDT needs 10 bytes: 2 for the 16-bit limit and 8 for the 64-bit base address
; Assumption: size in front of base -> promote size value to upper 48 bits of size
SHL QWORD [RBP + size], 64-16
LIDT [RBP + size + (64-16) / 8]
END LoadIDT;
PROCEDURE InitInterrupts*;
VAR a: SYSTEM.ADDRESS; o, i: LONGINT; p: PROCEDURE; mask: SET;
BEGIN
stateTag := SYSTEM.TYPECODE(State);
Portout8 (IntA0, 11X); Portout8 (IntA1, CHR(IRQ0));
Portout8 (IntA1, 4X); Portout8 (IntA1, 1X); Portout8 (IntA1, 0FFX);
Portout8 (IntB0, 11X); Portout8 (IntB1, CHR(IRQ8));
Portout8 (IntB1, 2X); Portout8 (IntB1, 1X); Portout8 (IntB1, 0FFX);
Portin8(IntA1, SYSTEM.VAL (CHAR, mask));
EXCL(mask, IRQ2-IRQ0);
Portout8 (IntA1, SYSTEM.VAL (CHAR, mask));
default.valid := TRUE; default.handler := Unexpected;
FOR i := 0 TO IDTSize-1 DO
intHandler[i, 0] := default; o := 0;
glue[i][o] := 6AX; INC (o); glue[i][o] := 0X; INC (o);
glue[i][o] := 48X; INC(o); glue[i][o] := 87X; INC(o); glue[i][o] := 2CX; INC(o); glue[i][o] := 24X; INC(o);
glue[i][o] := 6AX; INC (o); glue[i][o] := CHR(i); INC (o);
IF (i >= IRQ0) & (i <= IRQ15) THEN p := FieldIRQ ELSE p := FieldInterrupt END;
a := SYSTEM.VAL(SYSTEM.ADDRESS, p) - (SYSTEM.ADR(glue[i][o])+5);
glue[i][o] := 0E9X; INC (o);
SYSTEM.PUT32 (SYSTEM.ADR(glue[i][o]), a);
IF (i > 31) OR ~(i IN {8, 10..14, 17}) THEN a := SYSTEM.ADR(glue[i][0])
ELSE a := SYSTEM.ADR(glue[i][2])
END;
idt[i].offsetBits0to15 := SHORT (SHORT(a MOD 10000H));
IF TRUE THEN
idt[i].selector := Kernel64CodeSel;
idt[i].gateType := SYSTEM.VAL(INTEGER, 0EE00H)
ELSE
idt[i].selector := User64CodeSel;
idt[i].gateType := SYSTEM.VAL(INTEGER, 08E00H)
END;
idt[i].offsetBits16to31 := SHORT (SHORT(a DIV 10000H));
idt[i].offsetBits32to63 := SHORT(a DIV 100000000H);
idt[i].reserved := 0;
END
END InitInterrupts;
PROCEDURE Start*;
BEGIN
ASSERT(default.valid);
LoadIDT(SYSTEM.ADR(idt[0]), SYSTEM.SIZEOF(IDT)-1);
Sti
END Start;
PROCEDURE CurrentPC* (): SYSTEM.ADDRESS;
CODE {SYSTEM.AMD64}
MOV RAX, [RBP + 8]
END CurrentPC;
PROCEDURE -CurrentBP* (): SYSTEM.ADDRESS;
CODE {SYSTEM.AMD64}
MOV RAX, RBP
END CurrentBP;
PROCEDURE -SetBP* (bp: SYSTEM.ADDRESS);
CODE {SYSTEM.AMD64}
POP RBP
END SetBP;
PROCEDURE -CurrentSP* (): SYSTEM.ADDRESS;
CODE {SYSTEM.AMD64}
MOV RAX, RSP
END CurrentSP;
PROCEDURE -SetSP* (sp: SYSTEM.ADDRESS);
CODE {SYSTEM.AMD64}
POP RSP
END SetSP;
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.AMD64}
MOV EDX,[RBP+port]
IN AL, DX
MOV RCX, [RBP+val]
MOV [RCX], AL
END Portin8;
PROCEDURE Portin16*(port: LONGINT; VAR val: INTEGER);
CODE{SYSTEM.AMD64}
MOV EDX,[RBP+port]
IN AX, DX
MOV RCX, [RBP+val]
MOV [RCX], AX
END Portin16;
PROCEDURE Portin32*(port: LONGINT; VAR val: LONGINT);
CODE{SYSTEM.AMD64}
MOV EDX,[RBP+port]
IN EAX, DX
MOV RCX, [RBP+val]
MOV [RCX], EAX
END Portin32;
PROCEDURE Portout8*(port: LONGINT; val: CHAR);
CODE{SYSTEM.AMD64}
MOV AL,[RBP+val]
MOV EDX,[RBP+port]
OUT DX,AL
END Portout8;
PROCEDURE Portout16*(port: LONGINT; val: INTEGER);
CODE{SYSTEM.AMD64}
MOV AX,[RBP+val]
MOV EDX,[RBP+port]
OUT DX,AX
END Portout16;
PROCEDURE Portout32*(port: LONGINT; val: LONGINT);
CODE{SYSTEM.AMD64}
MOV EAX,[RBP+val]
MOV EDX,[RBP+port]
OUT DX,EAX
END Portout32;
PROCEDURE -Cli*;
CODE{SYSTEM.AMD64}
CLI
END Cli;
PROCEDURE -Sti*;
CODE{SYSTEM.AMD64}
STI
END Sti;
PROCEDURE -FPUSaveMin* (VAR state: SSEState);
CODE {SYSTEM.AMD64, SYSTEM.FPU}
POP RAX
FNSTCW [RAX] ; control word is at state[0]
FWAIT
END FPUSaveMin;
PROCEDURE -FPURestoreMin* (VAR state: SSEState);
CODE {SYSTEM.AMD64, SYSTEM.FPU}
POP RAX
FLDCW [RAX] ; control word is at state[0]
END FPURestoreMin;
PROCEDURE -FPUSaveFull* (VAR state: SSEState);
CODE {SYSTEM.AMD64, SYSTEM.FPU}
POP RAX
FSAVE [RAX]
END FPUSaveFull;
PROCEDURE -FPURestoreFull* (VAR state: SSEState);
CODE {SYSTEM.AMD64, SYSTEM.FPU}
POP RAX
FRSTOR [RAX]
END FPURestoreFull;
PROCEDURE -SSESaveFull* (stateAdr: SYSTEM.ADDRESS);
CODE {SYSTEM.AMD64, SYSTEM.FPU}
POP RAX
FXSAVE [RAX]
FWAIT
FNINIT
END SSESaveFull;
PROCEDURE -SSERestoreFull* (stateAdr: SYSTEM.ADDRESS);
CODE {SYSTEM.AMD64, SYSTEM.FPU}
POP RAX
FXRSTOR [RAX]
END SSERestoreFull;
PROCEDURE -SSESaveMin* (stateAdr: SYSTEM.ADDRESS);
CODE {SYSTEM.AMD64, SYSTEM.FPU}
POP RAX
FNSTCW [RAX]
FWAIT
STMXCSR [RAX + 24]
END SSESaveMin;
PROCEDURE -SSERestoreMin* (stateAdr: SYSTEM.ADDRESS);
CODE {SYSTEM.AMD64, SYSTEM.FPU}
POP RAX
FLDCW [RAX]
LDMXCSR [RAX + 24]
END SSERestoreMin;
PROCEDURE -PushState* (CONST state: State);
CODE {SYSTEM.AMD64}
POP RAX ; ADR (state)
POP RBX ; TYPECODE (state), ignored
PUSH QWORD [RAX + 176] ; SS
PUSH QWORD [RAX + 168] ; SP
PUSH QWORD [RAX + 160] ; FLAGS
PUSH QWORD [RAX + 152] ; CS
PUSH QWORD [RAX + 144] ; PC
PUSH QWORD [RAX + 120] ; RAX
PUSH QWORD [RAX + 112] ; RCX
PUSH QWORD [RAX + 104] ; RDX
PUSH QWORD [RAX + 96] ; RBX
PUSH DWORD 0; ignored
PUSH QWORD [RAX + 136] ; RBP
PUSH QWORD [RAX + 72] ; RSI
PUSH QWORD [RAX + 64] ; RDI
PUSH QWORD [RAX + 56] ; R8
PUSH QWORD [RAX + 48] ; R9
PUSH QWORD [RAX + 40] ; R10
PUSH QWORD [RAX + 32] ; R11
PUSH QWORD [RAX + 24] ; R12
PUSH QWORD [RAX + 16] ; R13
PUSH QWORD [RAX + 8] ; R14
PUSH QWORD [RAX + 0] ; R15
END PushState;
PROCEDURE -JumpState*;
CODE {SYSTEM.AMD64}
POP R15
POP R14
POP R13
POP R12
POP R11
POP R10
POP R9
POP R8
POP RDI
POP RSI
POP RBP
POP RBX; ignored
POP RBX
POP RDX
POP RCX
POP RAX
IRETQ
END JumpState;
PROCEDURE -CallLocalIPC*;
CODE {SYSTEM.AMD64}
INT MPIPCLocal
END CallLocalIPC;
PROCEDURE -HLT*;
CODE {SYSTEM.AMD64, SYSTEM.Privileged}
STI ;
HLT
END HLT;
PROCEDURE KernelCallHLT*;
CODE {SYSTEM.AMD64}
MOV EAX, 2
INT MPKC
END KernelCallHLT;
PROCEDURE CPUID1*(): LONGINT;
CODE {SYSTEM.AMD64}
MOV EAX, 1
CPUID
MOV EAX, EBX
END CPUID1;
PROCEDURE -AtomicInc*(VAR x: LONGINT);
CODE {SYSTEM.AMD64}
POP RAX
LOCK
INC DWORD [RAX]
END AtomicInc;
PROCEDURE -AtomicDec*(VAR x: LONGINT);
CODE {SYSTEM.AMD64}
POP RAX
LOCK
DEC DWORD [RAX]
END AtomicDec;
PROCEDURE AtomicExcl* (VAR s: SET; bit: LONGINT);
CODE {SYSTEM.AMD64}
MOV EAX, [RBP + bit]
MOV RBX, [RBP + s]
LOCK
BTR [RBX], EAX
END AtomicExcl;
PROCEDURE -AtomicAdd*(VAR x: LONGINT; y: LONGINT);
CODE {SYSTEM.AMD64}
POP EBX
POP RAX
LOCK
ADD DWORD [RAX], EBX
END AtomicAdd;
PROCEDURE -AtomicTestSet*(VAR x: BOOLEAN): BOOLEAN;
CODE {SYSTEM.AMD64}
POP RBX
MOV AL, 1
XCHG [RBX], AL
END AtomicTestSet;
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;
PROCEDURE CopyState* (CONST from: State; VAR to: State);
BEGIN
to.R15 := from.R15;
to.R14 := from.R14;
to.R13 := from.R13;
to.R12 := from.R12;
to.R11 := from.R11;
to.R10 := from.R10;
to.R9 := from.R9;
to.R8 := from.R8;
to.RDI := from.RDI;
to.RSI := from.RSI;
to.RBX := from.RBX;
to.RDX := from.RDX;
to.RCX := from.RCX;
to.RAX := from.RAX;
to.BP := from.BP;
to.PC := from.PC;
to.CS := from.CS;
to.SP := from.SP;
to.SS := from.SS;
to.FLAGS := from.FLAGS;
END CopyState;
PROCEDURE NumberOfProcessors*( ): LONGINT;
BEGIN
RETURN numberOfProcessors
END NumberOfProcessors;
PROCEDURE SetNumberOfProcessors*(num: LONGINT);
BEGIN
numberOfProcessors := num;
END SetNumberOfProcessors;
PROCEDURE ChangeByteOrder* (n: LONGINT): LONGINT;
CODE {SYSTEM.AMD64}
MOV EAX, [RBP + n] ; load n in eax
BSWAP EAX ; swap byte order
END ChangeByteOrder;
PROCEDURE ApicPut(ofs: SYSTEM.SIZE; val: SET);
BEGIN
IF TraceApic THEN
Acquire(TraceOutput);
Trace.Hex(ofs, SYSTEM.SIZEOF(SYSTEM.SIZE)*2); Trace.String(" := "); Trace.Hex(SYSTEM.VAL (LONGINT, val), 9); Trace.Ln;
Release(TraceOutput);
END;
SYSTEM.PUT(localAPIC+ofs, SYSTEM.VAL (LONGINT, val))
END ApicPut;
PROCEDURE ApicGet(ofs: SYSTEM.SIZE): SET;
VAR val: SET;
BEGIN
SYSTEM.GET(localAPIC+ofs, SYSTEM.VAL (LONGINT, val));
IF TraceApic THEN
Acquire(TraceOutput);
Trace.String(" ("); Trace.Hex(ofs, SYSTEM.SIZEOF(SYSTEM.SIZE)*2); Trace.String(" = ");
Trace.Hex(SYSTEM.VAL(LONGINT, val), 9); Trace.StringLn (")");
Release(TraceOutput);
END;
RETURN val
END ApicGet;
PROCEDURE HandleIPC(VAR state: State);
VAR id: LONGINT;
BEGIN
id := ID();
IF ~TraceProcessor OR (id IN allProcessors) THEN
IF FrontBarrier IN ipcFlags THEN
AtomicExcl(ipcFrontBarrier, id);
WHILE ipcFrontBarrier # {} DO SpinHint END
END;
ipcHandler(id, state, ipcMessage);
IF BackBarrier IN ipcFlags THEN
AtomicExcl(ipcBackBarrier, id);
WHILE ipcBackBarrier # {} DO SpinHint END
END;
AtomicExcl(ipcBusy, id)
END;
IF state.INT = MPIPC THEN
ApicPut(0B0H, {})
END
END HandleIPC;
PROCEDURE HandleError(VAR state: State);
VAR esr: SET;
BEGIN
esr := ApicGet(280H);
ApicPut(0B0H, {});
HALT(2302)
END HandleError;
PROCEDURE LocalBroadcast(h: BroadcastHandler; msg: Message; flags: SET);
BEGIN
IF Self IN flags THEN ipcBusy := allProcessors
ELSE ipcBusy := allProcessors - {ID()}
END;
ipcFrontBarrier := ipcBusy; ipcBackBarrier := ipcBusy;
ipcHandler := h; ipcMessage := msg; ipcFlags := flags;
IF numProcessors > 1 THEN
ApicPut(300H, {18..19} + SYSTEM.VAL (SET, MPIPC));
END;
IF Self IN flags THEN CallLocalIPC END;
WHILE ipcBusy # {} DO SpinHint END;
ipcHandler := NIL; ipcMessage := NIL
END LocalBroadcast;
PROCEDURE Broadcast* (h: BroadcastHandler; msg: Message; flags: SET);
BEGIN
Acquire(Processors);
LocalBroadcast(h, msg, flags);
Release(Processors)
END Broadcast;
PROCEDURE StartAll*;
BEGIN
Acquire(Processors);
ASSERT(stopped & (ipcBusy = {}));
ipcBusy := allProcessors - {ID()};
stopped := FALSE;
WHILE ipcBusy # {} DO SpinHint END;
Release(Processors)
END StartAll;
PROCEDURE HandleFlushTLB(id: LONGINT; CONST state: State; msg: Message);
CODE {SYSTEM.AMD64, SYSTEM.Privileged}
MOV EAX, CR3
MOV CR3, EAX
END HandleFlushTLB;
PROCEDURE GlobalFlushTLB;
BEGIN
Acquire(Processors);
LocalBroadcast(HandleFlushTLB, NIL, {Self, FrontBarrier, BackBarrier});
Release(Processors)
END GlobalFlushTLB;
PROCEDURE HandleFlushCache(id: LONGINT; CONST state: State; msg: Message);
CODE {SYSTEM.AMD64, SYSTEM.Privileged}
WBINVD ; write back and invalidate internal cache and initiate write back and invalidation of external caches
END HandleFlushCache;
PROCEDURE GlobalFlushCache;
BEGIN
Acquire(Processors);
LocalBroadcast(HandleFlushCache, NIL, {Self, FrontBarrier, BackBarrier});
Release(Processors)
END GlobalFlushCache;
PROCEDURE HandleKernelCall(VAR state: State);
BEGIN
IF IFBit IN state.FLAGS THEN
Sti
END;
CASE state.RAX OF
|2:
IF IFBit IN state.FLAGS THEN
HLT
END
END
END HandleKernelCall;
PROCEDURE HandleGetTimestamp(id: LONGINT; CONST state: State; msg: Message);
BEGIN
time[id] := GetTimer()
END HandleGetTimestamp;
PROCEDURE GlobalGetTimestamp;
VAR t: TimeArray; i: LONGINT; mean, var, n: HUGEINT;
BEGIN
Acquire(Processors);
LocalBroadcast(HandleGetTimestamp, NIL, {Self, FrontBarrier});
LocalBroadcast(HandleGetTimestamp, NIL, {Self, FrontBarrier});
t := time;
Release(Processors);
Acquire (TraceOutput);
FOR i := 0 TO numProcessors-1 DO Trace.HIntHex(t[i], 17) END;
IF numProcessors > 1 THEN
mean := 0;
n := numProcessors;
FOR i := 0 TO numProcessors-1 DO
INC (mean, t[i])
END;
mean := DivH(mean, n);
var := 0;
FOR i := 0 TO numProcessors-1 DO
n := t[i] - mean;
INC (var, MulH(n, n))
END;
var := DivH(var, numProcessors - 1);
Trace.String(" mean="); Trace.HIntHex(mean, 16);
Trace.String(" var="); Trace.HIntHex(var, 16);
Trace.String(" var="); Trace.Int(SHORT (var), 1);
Trace.String(" diff:");
FOR i := 0 TO numProcessors-1 DO
Trace.Int(SHORT (t[i] - mean), 1); Trace.Char(" ")
END
END;
Release (TraceOutput);
END GlobalGetTimestamp;
PROCEDURE ParseProcessor(adr: SYSTEM.ADDRESS);
VAR id, idx, signature, family, feat, ver, log: LONGINT; flags: SET; string : ARRAY 8 OF CHAR;
BEGIN
SYSTEM.GET(adr, SYSTEM.VAL (LONGINT, flags));
id := ASH(SYSTEM.VAL (LONGINT, flags * {8..15}), -8);
ver := ASH(SYSTEM.VAL (LONGINT, flags * {16..23}), -16);
SYSTEM.GET (adr+4, signature);
family := ASH(signature, -8) MOD 10H;
SYSTEM.GET (adr+8, feat);
idx := -1;
IF (family # 0) & (signature MOD 1000H # 0FFFH) & (24 IN flags) & (id < LEN(idMap)) & (idMap[id] = -1) THEN
IF 25 IN flags THEN idx := 0
ELSIF numProcessors < maxProcessors THEN idx := numProcessors; INC(numProcessors)
ELSE
END
END;
IF idx # -1 THEN apicVer[idx] := ver; idMap[id] := SHORT(SHORT(idx)) END;
Trace.String(" Processor "); Trace.Int(id, 1);
Trace.String(", APIC"); Trace.Hex(ver, -3);
Trace.String(", ver "); Trace.Int(family, 1);
Trace.Char("."); Trace.Int(ASH(signature, -4) MOD 10H, 1);
Trace.Char("."); Trace.Int(signature MOD 10H, 1);
Trace.String(", features "); Trace.Hex(feat, 9);
Trace.String(", ID "); Trace.Int(idx, 1);
IF (threadsPerCore > 1) THEN Trace.String(" ("); Trace.Int(threadsPerCore, 0); Trace.String(" threads)"); END;
Trace.Ln;
IF (threadsPerCore > 1) THEN
GetConfig("DisableHyperthreading", string);
IF (string = "1") THEN
Trace.String("Machine: Hyperthreading disabled."); Trace.Ln;
RETURN;
END;
log := (SYSTEM.LSH(CPUID1(), -16) MOD 256);
WHILE log > 1 DO
INC(id); DEC(log);
IF numProcessors < maxProcessors THEN
idx := numProcessors; INC(numProcessors);
apicVer[idx] := ver; idMap[id] := SHORT(SHORT(idx))
END
END
END
END ParseProcessor;
PROCEDURE ParseMPConfig;
VAR adr, x: SYSTEM.ADDRESS; i: LONGINT; entries: INTEGER; ch: CHAR; s: SET; str: ARRAY 8 OF CHAR;
BEGIN
localAPIC := 0; numProcessors := 1; allProcessors := {0};
FOR i := 0 TO LEN(idMap)-1 DO idMap[i] := -1 END;
FOR i := 0 TO MaxCPU-1 DO started[i] := FALSE END;
adr := configMP;
GetConfig("MaxProcs", str);
i := 0; maxProcessors := StrToInt(i, str);
IF maxProcessors = 0 THEN maxProcessors := MaxCPU END;
IF (maxProcessors > 0) & (adr # NilAdr) THEN
Trace.String("Machine: Intel MP Spec "); Trace.Int(ORD(revMP) DIV 10H + 1, 1);
Trace.Char("."); Trace.Int(ORD(revMP) MOD 10H, 1); Trace.Ln;
IF TraceVerbose THEN
IF ODD(ASH(ORD(featureMP[1]), -7)) THEN
Trace.StringLn (" PIC mode");
ELSE
Trace.StringLn (" Virtual wire mode");
END
END;
IF featureMP[0] # 0X THEN
Trace.String(" Default config "); Trace.Int(ORD(featureMP[0]), 1); Trace.Ln;
localAPIC := SHORT(0FEE00000H);
apicVer[0] := 0; apicVer[1] := 0
ELSE
MapPhysical(adr, 68*1024, adr);
SYSTEM.GET (adr, i); ASSERT(i = 504D4350H);
SYSTEM.GET (adr+4, i);
ASSERT(ChecksumMP(adr, i MOD 10000H) = 0);
IF TraceVerbose THEN
Trace.String(" ID: ");
FOR x := adr+8 TO adr+27 DO
SYSTEM.GET (x, ch); Trace.Char(ch);
IF x = adr+15 THEN Trace.Char(" ") END
END;
Trace.Ln
END;
localAPIC := 0; SYSTEM.GET(adr+36, SYSTEM.VAL (LONGINT, localAPIC));
IF TraceVerbose THEN Trace.String(" Local APIC:"); Trace.Address (localAPIC); Trace.Ln END;
SYSTEM.GET (adr+34, entries);
INC(adr, 44);
WHILE entries > 0 DO
SYSTEM.GET (adr, ch);
CASE ORD(ch) OF
0:
ParseProcessor(adr);
INC(adr, 20)
|1:
IF TraceVerbose THEN
SYSTEM.GET (adr+1, ch);
Trace.String(" Bus "); Trace.Int(ORD(ch), 1); Trace.String(": ");
FOR x := adr+2 TO adr+7 DO SYSTEM.GET (x, ch); Trace.Char(ch) END;
Trace.Ln
END;
INC(adr, 8)
|2:
IF TraceVerbose THEN
SYSTEM.GET (adr+1, ch); Trace.String(" IO APIC ID:"); Trace.Hex(ORD(ch), -3);
SYSTEM.GET (adr+2, ch); Trace.String(", version "); Trace.Int(ORD(ch), 1);
SYSTEM.GET(adr, SYSTEM.VAL (LONGINT, s)); IF ~(24 IN s) THEN Trace.String(" (disabled)") END;
Trace.Ln
END;
INC(adr, 8)
|3:
INC(adr, 8)
|4:
INC(adr, 8)
END;
DEC(entries)
END
END
END;
IF localAPIC = 0 THEN
Trace.StringLn ("Machine: Single-processor");
apicVer[0] := 0
END;
started[0] := TRUE;
FOR i := 0 TO MaxCPU-1 DO revIDmap[i] := -1 END;
FOR i := 0 TO LEN(idMap)-1 DO
x := idMap[i];
IF x # -1 THEN
ASSERT(revIDmap[x] = -1);
revIDmap[x] := SHORT(SHORT(i))
END
END;
GetConfig("TimerRate", str);
i := 0; timerRate := StrToInt(i, str);
IF timerRate = 0 THEN timerRate := 1000 END;
IF TraceProcessor THEN
GetConfig("TraceProc", str);
i := 0; traceProcessor := StrToInt(i, str) # 0
END
END ParseMPConfig;
PROCEDURE GetBusClockRate(): LONGINT;
VAR timer: LONGINT; t: LONGINT;
BEGIN
t := ticks;
REPEAT UNTIL ticks # t;
timer := ticks + ClockRateDelay;
ApicPut(380H, SYSTEM.VAL (SET, MAX(LONGINT)));
REPEAT UNTIL timer - ticks <= 0;
t := MAX(LONGINT) - SYSTEM.VAL (LONGINT, ApicGet(390H));
IF t <= MAX(LONGINT) DIV 1000 THEN
RETURN 1000 * t DIV ClockRateDelay
ELSE
RETURN t DIV ClockRateDelay * 1000
END
END GetBusClockRate;
PROCEDURE InitMPTimer;
VAR rate: LONGINT;
BEGIN
IF timerRate > 0 THEN
ApicPut(3E0H, {0,1,3});
ApicPut(320H, {16} + SYSTEM.VAL (SET, MPTMR));
rate := GetBusClockRate();
busHz0[ID()] := rate;
rate := (rate+500000) DIV 1000000 * 1000000;
busHz1[ID()] := rate;
ApicPut(320H, {17} + SYSTEM.VAL (SET, MPTMR));
ApicPut(380H, SYSTEM.VAL (SET, rate DIV timerRate))
END
END InitMPTimer;
PROCEDURE HandleMPTimer(VAR state: State);
BEGIN
timer(ID(), state);
ApicPut(0B0H, {});
Sti;
Timeslice(state)
END HandleMPTimer;
PROCEDURE HandleUPTimer(VAR state: State);
BEGIN
timer(0, state);
Sti;
Timeslice(state)
END HandleUPTimer;
PROCEDURE DummyEvent(id: LONGINT; CONST state: State);
END DummyEvent;
PROCEDURE InstallEventHandler* (h: EventHandler);
BEGIN
IF h # NIL THEN timer := h ELSE timer := DummyEvent END
END InstallEventHandler;
PROCEDURE InitAPIC;
BEGIN
ASSERT(MPSPU MOD 16 = 15);
ApicPut(0F0H, {8} + SYSTEM.VAL (SET, MPSPU));
ApicPut(370H, SYSTEM.VAL (SET, MPERR));
InitMPTimer
END InitAPIC;
PROCEDURE StartMP;
VAR id: LONGINT; state: State;
BEGIN
InitAPIC;
id := ID();
Acquire (TraceOutput);
Trace.String (" P"); Trace.Int(id, 1); Trace.StringLn (" running");
Release (TraceOutput);
IF TraceProcessor & traceProcessor & (id = numProcessors-1) THEN
DEC(numProcessors)
ELSE
INCL(allProcessors, id)
END;
started[id] := TRUE;
IF TraceProcessor & ~(id IN allProcessors) THEN
Acquire (TraceOutput);
Trace.String (" P"); Trace.Int(id, 1); Trace.StringLn (" tracing");
Release (TraceOutput);
LOOP
IF traceProcessorProc # NIL THEN traceProcessorProc(id, state) END;
SpinHint
END
END;
WHILE stopped DO SpinHint END;
AtomicExcl(ipcBusy, id);
Acquire (TraceOutput);
Trace.String (" P"); Trace.Int(id, 1); Trace.StringLn(" scheduling");
Release (TraceOutput);
ASSERT(id = ID());
start;
END StartMP;
PROCEDURE EnterMP;
BEGIN
InitProcessor;
InitMemory;
Start;
StartMP
END EnterMP;
PROCEDURE StartProcessor(phys: SYSTEM.ADDRESS; apicid: LONGINT; startup: BOOLEAN);
VAR j, k: LONGINT; s: SET; timer: LONGINT;
BEGIN
ApicPut(280H, {}); s := ApicGet(280H);
ApicPut(310H, SYSTEM.VAL (SET, ASH(apicid, 24)));
ApicPut(300H, {8, 10, 14, 15});
timer := ticks + 5;
REPEAT UNTIL timer - ticks <= 0;
ApicPut(310H, SYSTEM.VAL (SET, ASH(apicid, 24)));
ApicPut(300H, {8, 10, 15});
IF startup THEN
j := 0; k := 2;
WHILE j # k DO
ApicPut(280H, {});
ApicPut(310H, SYSTEM.VAL (SET, ASH(apicid, 24)));
ApicPut(300H, {9, 10} + SYSTEM.VAL (SET, phys DIV 4096 MOD 256));
timer := ticks + 10;
REPEAT UNTIL timer - ticks <= 0;
IF ~(12 IN ApicGet(300H)) THEN
IF ApicGet(280H) * {0..3, 5..7} = {} THEN k := j
ELSE INC(j)
END
ELSE INC(j)
END
END
END
END StartProcessor;
PROCEDURE BootMP;
VAR phys, page0Adr: SYSTEM.ADDRESS; i: LONGINT; timer: LONGINT;
BEGIN
stopped := TRUE; ipcBusy := {};
InitBootPage(EnterMP, phys);
MapPhysical(0, 4096, page0Adr);
Acquire(TraceOutput); Trace.String("Machine: Booting processors... "); Trace.Ln; Release(TraceOutput);
FOR i := 1 TO numProcessors-1 DO
SYSTEM.PUT (page0Adr + 467H, ASH(phys, 16-4));
PutNVByte(15, 0AX);
Acquire(TraceOutput); Trace.String(" P0 starting P"); Trace.Int(i, 1); Trace.Ln; Release(TraceOutput);
StartProcessor(phys, revIDmap[i], apicVer[i] >= 10H);
timer := ticks + 5000;
REPEAT SpinHint UNTIL started[i] OR (timer - ticks <= 0);
Acquire(TraceOutput);
IF started[i] THEN
Trace.String(" P0 recognized P"); Trace.Int(i, 1);
ELSE
Trace.String(" P0 timeout on P"); Trace.Int(i, 1);
END;
Trace.Ln;
Release(TraceOutput);
END;
SYSTEM.PUT (page0Adr + 467H, SYSTEM.VAL (LONGINT, 0));
UnmapPhysical(page0Adr, 4096);
PutNVByte(15, 0X)
END BootMP;
PROCEDURE TimerInterruptHandler(VAR state: State);
BEGIN
INC(ticks);
DEC(eventCount);
IF eventCount = 0 THEN
eventCount := eventMax; event(state)
END
END TimerInterruptHandler;
PROCEDURE Dummy(VAR state: State);
END Dummy;
PROCEDURE InitTicks;
CONST Div = (2*TimerClock + Second) DIV (2*Second);
BEGIN
eventCount := 0; eventMax := 0; event := Dummy;
ASSERT(Div <= 65535);
Portout8(43H, 34X); Wait;
Portout8(40H, CHR(Div MOD 100H)); Wait;
Portout8(40H, CHR(ASH(Div, -8)));
InstallHandler(TimerInterruptHandler, IRQ0)
END InitTicks;
PROCEDURE InstallTickHandler(handler: Handler; divisor: LONGINT);
BEGIN
eventMax := divisor; event := handler;
eventCount := eventMax
END InstallTickHandler;
PROCEDURE InitProcessors*;
BEGIN
traceProcessor := FALSE; traceProcessorProc := NIL;
ASSERT(Second = 1000);
InitTicks;
timer := DummyEvent;
ParseMPConfig;
InstallHandler(HandleIPC, MPIPCLocal);
IF localAPIC # 0 THEN
InitAPICArea(localAPIC, 4096);
InitAPICIDAdr(localAPIC+20H, idMap);
ASSERT(MPSPU MOD 16 = 15);
InstallHandler(HandleError, MPERR);
InstallHandler(HandleMPTimer, MPTMR);
InstallHandler(HandleIPC, MPIPC);
InitAPIC;
IF numProcessors > 1 THEN BootMP END
ELSE
IF timerRate > 0 THEN
InstallTickHandler(HandleUPTimer, Second DIV timerRate)
END
END;
InstallHandler(HandleKernelCall, MPKC);
END InitProcessors;
PROCEDURE TraceChar (c: CHAR);
VAR status: SHORTINT;
PROCEDURE Scroll;
VAR adr: SYSTEM.ADDRESS; off: SYSTEM.SIZE;
BEGIN
adr := traceBase + TraceLen;
SYSTEM.MOVE (adr, adr - TraceLen, TraceSize - TraceLen);
adr := traceBase + TraceSize - TraceLen;
FOR off := 0 TO TraceLen - SYSTEM.SIZEOF(INTEGER) BY SYSTEM.SIZEOF(INTEGER) DO SYSTEM.PUT16 (adr + off, 100H * 7H + 32) END
END Scroll;
BEGIN
IF TraceV24 IN traceMode THEN
REPEAT
Portin8 (tracePort + 5, SYSTEM.VAL(CHAR,status))
UNTIL ODD (status DIV 20H);
Portout8 (tracePort, c);
END;
IF TraceScreen IN traceMode THEN
IF c = 9X THEN c := 20X END;
IF c = 0DX THEN
DEC (tracePos, tracePos MOD TraceLen)
ELSIF c = 0AX THEN
IF tracePos < TraceSize THEN
INC (tracePos, TraceLen)
ELSE
Scroll
END
ELSE
IF tracePos >= TraceSize THEN
Scroll;
DEC (tracePos, TraceLen)
END;
SYSTEM.PUT16 (traceBase + tracePos, 100H * traceColor + ORD (c));
INC (tracePos, SYSTEM.SIZEOF(INTEGER))
END
END
END TraceChar;
PROCEDURE TraceColor (c: SHORTINT);
BEGIN traceColor := c;
END TraceColor;
PROCEDURE InitTrace;
CONST MaxPorts = 8;
VAR i, p, bps: LONGINT; off: SYSTEM.SIZE; s, name: ARRAY 32 OF CHAR;
baselist: ARRAY MaxPorts OF LONGINT;
BEGIN
GetConfig ("TraceMode", s);
p := 0; traceMode := SYSTEM.VAL (SET, StrToInt (p, s));
IF TraceScreen IN traceMode THEN
GetConfig ("TraceMem", s);
p := 0; traceBase := SYSTEM.VAL (SYSTEM.ADDRESS, StrToInt (p, s));
IF traceBase = 0 THEN traceBase := 0B8000H END;
FOR off := 0 TO TraceSize - SYSTEM.SIZEOF(INTEGER) BY SYSTEM.SIZEOF(INTEGER) DO SYSTEM.PUT16 (traceBase + off, 100H * 7H + 32) END;
tracePos := 0;
Portout8(3D4H, 0EX);
Portout8(3D5H, CHR((TraceWidth*TraceHeight) DIV 100H));
Portout8(3D4H, 0FX);
Portout8(3D5H, CHR((TraceWidth*TraceHeight) MOD 100H))
END;
IF TraceV24 IN traceMode THEN
FOR i := 0 TO MaxPorts - 1 DO
COPY ("COMx", name); name[3] := CHR (ORD ("1") + i);
GetConfig (name, s); p := 0; baselist[i] := StrToInt (p, s);
END;
IF baselist[0] = 0 THEN baselist[0] := 3F8H END;
IF baselist[1] = 0 THEN baselist[1] := 2F8H END;
GetConfig("TracePort", s); p := 0; p := StrToInt(p, s); DEC(p);
IF (p >= 0) & (p < MaxPorts) THEN tracePort := baselist[p] ELSE tracePort := baselist[0] END;
ASSERT(tracePort > 0);
GetConfig("TraceBPS", s); p := 0; bps := StrToInt(p, s);
IF bps <= 0 THEN bps := 38400 END;
Portout8 (tracePort + 3, 80X);
bps := 115200 DIV bps;
Portout8 (tracePort + 1, CHR (bps DIV 100H));
Portout8 (tracePort, CHR (bps MOD 100H));
Portout8 (tracePort + 3, 3X);
Portout8 (tracePort + 4, 3X);
Portout8 (tracePort + 1, 0X);
END;
traceColor := 7; Trace.Char := TraceChar; Trace.Color := TraceColor;
END InitTrace;
PROCEDURE {NOPAF, FIXED(01000000H)} FirstAddress;
CODE{SYSTEM.AMD64}
; save arguments passed by bootloader
MOV bootFlag, RAX
MOV initRegs0,RSI
MOV initRegs1, RDI
MOV fbadr, RDI
MOV fbInfoPtr, RCX
END FirstAddress;
PROCEDURE {NOPAF} LastAddress;
CODE {SYSTEM.AMD64}
END LastAddress;
BEGIN
initRegs[0] := initRegs0;
initRegs[1] := initRegs1;
SYSTEM.PUT16(0472H, 01234H);
ReadBootTable(bootFlag);
InitTrace;
Trace.String("Machine: "); Trace.Blue;Trace.StringLn (Version); Trace.Default;
CheckMemory;
SearchMP;
AllocateDMA;
version := Version;
InitBoot;
InitProcessor;
InitLocks;
NmaxUserStacks := MaxUserStacks;
ASSERT(ASH(1, PSlog2) = PS);
Trace.String("Machine: Enabling MMU... ");
InitSegments;
InitPages;
InitMemory;
Trace.Green; Trace.StringLn("Ok"); Trace.Default;
memBlockHead := SYSTEM.VAL (MemoryBlock, SYSTEM.ADR (initialMemBlock));
memBlockTail := memBlockHead;
initialMemBlock.beginBlockAdr := SYSTEM.VAL (SYSTEM.ADDRESS, LastAddress);
initialMemBlock.endBlockAdr := initialMemBlock.beginBlockAdr + StaticBlockSize;
initialMemBlock.size := initialMemBlock.endBlockAdr - initialMemBlock.beginBlockAdr;
FOR i := 0 TO IDTSize - 1 DO
FOR j := 0 TO MaxNumHandlers - 1 DO
intHandler[i, j].valid := FALSE;
intHandler[i, j].handler := NIL
END
END;
default.valid := FALSE;
END Machine.
(*
03.03.1998 pjm First version
30.06.1999 pjm ProcessorID moved to AosProcessor
*)
(**
Notes
This module defines an interface to the boot environment of the system. The facilities provided here are only intended for the lowest levels of the system, and should never be directly imported by user modules (exceptions are noted below). They are highly specific to the system hardware and firmware architecture.
Typically a machine has some type of firmware that performs initial testing and setup of the system. The firmware initiates the operating system bootstrap loader, which loads the boot file. This module is the first module in the statically linked boot file that gets control.
There are two more-or-less general procedures in this module: GetConfig and StrToInt. GetConfig is used to query low-level system settings, e.g., the location of the boot file system. StrToInt is a utility procedure that parses numeric strings.
Config strings:
ExtMemSize Specifies size of extended memory (above 1MB) in MB. This value is not checked for validity. Setting it false may cause the system to fail, possible after running for some time. The memory size is usually detected automatically, but if the detection does not work for some reason, or if you want to limit the amount of memory detected, this string can be set. For example, if the machine has 64MB of memory, this value can be set as ExtMemSize="63".
*)