(* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)

MODULE MemInfo; (** AUTHOR "pjm"; PURPOSE "Memory mapping information"; *)

IMPORT SYSTEM, KernelLog, Machine;

CONST
	SoftInt = Machine.SoftInt;

		(* standard multipliers *)
	K = 1024;  M = 100000H;	(* 1K, 1M *)

	PS = 4096;
	RS = 4*M;	(* region covered by a page table in bytes *)
	PTEs = RS DIV PS;	(* number of page table/directory entries *)

VAR
	kernelPD: SYSTEM.ADDRESS;
	msrlow, msrhigh: SET;

PROCEDURE GetCR3(VAR state: Machine.State);
CODE {SYSTEM.AMD64, SYSTEM.Privileged}
	MOV RAX, CR3
	MOV RBX, kernelPD
	MOV [RBX], RAX
END GetCR3;

PROCEDURE -DoSoftInt(eax: LONGINT);
CODE {SYSTEM.AMD64}
	POP EAX
	INT SoftInt
END DoSoftInt;

(* Display mapped ranges. *)

PROCEDURE DisplayMap*;
VAR i, j: LONGINT; pt: LONGINT; virt, phys, virt0, phys0, size: LONGINT;

	PROCEDURE Page;
	BEGIN
		IF (phys = phys0+size) & (virt = virt0+size) THEN
			INC(size, PS)
		ELSE
			IF size # 0 THEN
				KernelLog.Hex(virt0, 9); KernelLog.Hex(phys0, 9);
				KernelLog.IntSuffix(size, 8, "B"); KernelLog.Ln
			END;
			virt0 := virt;  phys0 := phys;  size := PS
		END
	END Page;

BEGIN
	Machine.InstallHandler(GetCR3, SoftInt);	(* ignore race *)
	DoSoftInt(0);
	Machine.RemoveHandler(GetCR3, SoftInt);
	KernelLog.Enter; KernelLog.Char(0EX); KernelLog.Ln;
	KernelLog.String(" Virtual  Physical Size");  KernelLog.Ln;
	virt := 0;  virt0 := 0;  phys0 := 0;  size := 0;
	FOR i := 0 TO PTEs-1 DO
		SYSTEM.GET(kernelPD + SYSTEM.SIZEOF(SYSTEM.ADDRESS)*i, pt);
		IF ODD(pt) THEN	(* present *)
			pt := pt - pt MOD PS;
			FOR j := 0 TO PTEs-1 DO
				SYSTEM.GET(pt, phys);
				IF ODD(phys) THEN
					DEC(phys, phys MOD PS);
					Page
				END;
				INC(pt, 4);  INC(virt, 4*K)
			END
		ELSE
			INC(virt, 4*M)
		END
	END;
	virt := -1;  Page;
	KernelLog.Char(0FX); KernelLog.Exit;
END DisplayMap;

PROCEDURE Write64(s: ARRAY OF CHAR; low, high: SET);
BEGIN
	KernelLog.String(s);  KernelLog.Char("=");
	KernelLog.Hex(SYSTEM.VAL(LONGINT, high), 8);
	KernelLog.Hex(SYSTEM.VAL(LONGINT, low), 9)
END Write64;

PROCEDURE Bits(s: ARRAY OF CHAR; x: SET; ofs, n: LONGINT);
BEGIN
	KernelLog.String(s); KernelLog.Char("="); KernelLog.Bits(x, ofs, n)
END Bits;

PROCEDURE -RealReadMSR(msr: HUGEINT; VAR low, high: SET);
CODE {SYSTEM.AMD64, SYSTEM.Privileged}
	POP RDI
	POP RSI
	POP RCX
	RDMSR
	MOV [RSI], EAX
	MOV [RDI], EDX
END RealReadMSR;

PROCEDURE IntReadMSR(VAR state: Machine.State);
BEGIN
	RealReadMSR(state.RAX, msrlow, msrhigh)
END IntReadMSR;

PROCEDURE ReadMSR(msr: LONGINT; VAR low, high: SET);
BEGIN
	Machine.InstallHandler(IntReadMSR, SoftInt);	(* ignore race *)
	DoSoftInt(msr);
	Machine.RemoveHandler(IntReadMSR, SoftInt);
	low := msrlow; high := msrhigh
END ReadMSR;

PROCEDURE DisplayMTTR*;
VAR version, i, j, k, vcnt: LONGINT; features, low, high, mask: SET; vendor: Machine.Vendor;
BEGIN
	KernelLog.Enter;
(*	Machine.CPUID(vendor, version, features);
	KernelLog.String("CPU: ");  KernelLog.Int(ASH(version, -8) MOD 16, 1);
	KernelLog.Char(".");  KernelLog.Int(ASH(version, -4) MOD 16, 1);
	KernelLog.Char(".");  KernelLog.Int(version MOD 16, 1);
	Bits(", features", features, 0, 32);
	KernelLog.String(", vendor ");  KernelLog.String(vendor);
	KernelLog.Ln; *)
	features := Machine.features;
	IF 5 IN features THEN	(* MSR supported *)
		IF 12 IN features THEN	(* MTTR supported *)
			ReadMSR(0FEH, low, high);
			vcnt := SYSTEM.VAL(LONGINT, low) MOD 256;
			KernelLog.String("VCNT="); KernelLog.Int(vcnt, 1);
			Bits(", FIX", low, 8, 1); Bits(", WC", low, 10, 1);
			KernelLog.Ln;
			IF 8 IN low THEN
				ReadMSR(2FFH, low, high);  Write64("DefType", low, high);  KernelLog.Ln;
				ReadMSR(250H, low, high);  Write64("Fix64k", low, high);  KernelLog.Ln;
				ReadMSR(258H, low, high);  Write64("Fix16k", low, high);  KernelLog.Ln;
				ReadMSR(259H, low, high);  Write64("Fix16k", low, high);  KernelLog.Ln;
				ReadMSR(268H, low, high);  Write64("Fix4k", low, high);  KernelLog.Ln;
				ReadMSR(269H, low, high);  Write64("Fix4k", low, high);  KernelLog.Ln;
				ReadMSR(26AH, low, high);  Write64("Fix4k", low, high);  KernelLog.Ln;
				ReadMSR(26BH, low, high);  Write64("Fix4k", low, high);  KernelLog.Ln;
				ReadMSR(26CH, low, high);  Write64("Fix4k", low, high);  KernelLog.Ln;
				ReadMSR(26DH, low, high);  Write64("Fix4k", low, high);  KernelLog.Ln;
				ReadMSR(26EH, low, high);  Write64("Fix4k", low, high);  KernelLog.Ln;
				ReadMSR(26FH, low, high);  Write64("Fix4k", low, high);  KernelLog.Ln;
				FOR i := 0 TO vcnt-1 DO
					KernelLog.Int(i, 1);
					ReadMSR(200H+2*i, low, high);  Write64(" base", low, high);
					ReadMSR(200H+2*i+1, low, high);  Write64(", mask", low, high);
					IF 11 IN low THEN	(* valid *)
						mask := SYSTEM.LSH(low, -12);
						FOR j := 0 TO 3 DO
							IF j IN high THEN INCL(mask, 20+j) END
						END;
						j := 0;  WHILE (j # 32) & ~(j IN mask) DO INC(j) END;
						k := 31;  WHILE (k # -1) & ~(k IN mask) DO DEC(k) END;
						IF (k = 23) & (k >= j) & (mask = {j..k}) THEN
							KernelLog.String(", ");  KernelLog.IntSuffix(SYSTEM.VAL(LONGINT, {j})*4*1024, 1, "B")
						ELSE
							KernelLog.String(" discon=");  KernelLog.Hex(SYSTEM.VAL(LONGINT, mask), 8)
						END
					END;
					KernelLog.Ln
				END
			ELSE
				KernelLog.String("Fixed range registers not supported");  KernelLog.Ln
			END
		ELSE
			KernelLog.String("MTTR not supported");  KernelLog.Ln
		END
	ELSE
		KernelLog.String("MSR not supported");  KernelLog.Ln
	END;
	KernelLog.Exit;
END DisplayMTTR;

(*
PROCEDURE IntSetCache(VAR state: Machine.State);
VAR res: LONGINT;
BEGIN
	Machine.SetLocalCacheProperties(0FA800000H, 800000H, Machine.WC, res);
	KernelLog.Enter; KernelLog.String("SetCache "); KernelLog.Int(res, 1); KernelLog.Exit
END IntSetCache;

PROCEDURE Test*;
BEGIN
	Machine.InstallHandler(IntSetCache, SoftInt);	(* ignore race *)
	DoSoftInt(0);
	Machine.RemoveHandler(IntSetCache, SoftInt)
END Test;

PROCEDURE -SetMTTRphysBase(n: LONGINT; high, low: LONGINT);
CODE {SYSTEM.Pentium, SYSTEM.Privileged}
	POP EAX
	POP EDX
	POP ECX
	SHL ECX, 1
	ADD ECX, 200H	; MTTRphysBase0
	WRMSR
END SetMTTRphysBase;

PROCEDURE -SetMTTRphysMask(n: LONGINT; high, low: LONGINT);
CODE {SYSTEM.Pentium, SYSTEM.Privileged}
	POP EAX
	POP EDX
	POP ECX
	SHL ECX, 1
	ADD ECX, 201H	; MTTRphysMask0
	WRMSR
END SetMTTRphysMask;

(*
1 000000000H 4GB WB
0 0F0000000H 128MB UC
4 0F8000000H 64MB UC
- 0FC000000H 32MB WB (implicit)
3 0FE000000H 32MB UC
2 100000000H 256MB WB

WB 0MB-2048MB 2048MB
WB 2048MB-3072MB 1024MB
WB 3072MB-3584MB 512MB
WB 3584MB-3840MB 256MB
WC 4032MB-4064MB 32MB
WB 4096MB-4352MB 256MB
*)

PROCEDURE IntSetCache2(VAR state: Machine.State);
BEGIN
	SetMTTRphysBase(3, 0, 0FE000000H);
	SetMTTRphysMask(3, 0FH, 0FE000800H);
	SetMTTRphysBase(4, 0, 0F8000000H);
	SetMTTRphysMask(4, 0FH, 0FC000800H);
	SetMTTRphysBase(0, 0, 0F0000000H);
	SetMTTRphysMask(0, 0FH, 0F8000800H)
END IntSetCache2;

PROCEDURE Test2*;
BEGIN
	Machine.InstallHandler(IntSetCache2, SoftInt);	(* ignore race *)
	DoSoftInt(0);
	Machine.RemoveHandler(IntSetCache2, SoftInt)
END Test2;

PROCEDURE Test3*;
VAR res: LONGINT;
BEGIN
	Processors.GlobalSetCacheProperties(0FA800000H, 800000H, Machine.WC, res);
	KernelLog.Enter; KernelLog.String("SetCache "); KernelLog.Int(res, 1); KernelLog.Exit
END Test3;
*)

END MemInfo.

System.Free MemInfo ~

MemInfo.DisplayMap
MemInfo.DisplayMTTR

MemInfo.Test
MemInfo.Test2
MemInfo.Test3

DisplayTests.Mod

PCITools.Scan