(* Aos, Copyright 2001, Pieter Muller, ETH Zurich *) MODULE MemCache; (** AUTHOR "pjm"; PURPOSE "Memory cache control"; *) IMPORT SYSTEM, Machine; CONST (** cache properties *) UC* = 0; WC* = 1; WT* = 4; WP* = 5; WB* = 6; PS = 4096; (* page size in bytes *) M = 100000H; (* 1K, 1M, 1G *) Ok = 0; TYPE SetCacheMessage = POINTER TO RECORD (Machine.Message) physAdr: ADDRESS; size, type: LONGINT; res: ARRAY Machine.MaxCPU OF LONGINT END; (* Return the value of the MTTRcap register. *) PROCEDURE -GetMTTRcapLow(): SET; CODE {SYSTEM.Pentium, SYSTEM.Privileged} MOV ECX, 0FEH ; MTTRcap RDMSR END GetMTTRcapLow; (* (* Return the value of the MTTRdefType register. *) PROCEDURE -GetMTTRdefTypeLow(): SET; CODE {SYSTEM.Pentium, SYSTEM.Privileged} MOV ECX, 2FFH ; MTTRdefType RDMSR END GetMTTRdefTypeLow; *) (* Return the value of the specified MTTRphysBase register. *) PROCEDURE -GetMTTRphysBaseLow(n: ADDRESS): SET; CODE {SYSTEM.Pentium, SYSTEM.Privileged} POP ECX SHL ECX, 1 ADD ECX, 200H ; MTTRphysBase0 RDMSR END GetMTTRphysBaseLow; (* Return the value of the specified MTTRphysMask register. *) PROCEDURE -GetMTTRphysMaskLow(n: ADDRESS): SET; CODE {SYSTEM.Pentium, SYSTEM.Privileged} POP ECX SHL ECX, 1 ADD ECX, 201H ; MTTRphysMask0 RDMSR END GetMTTRphysMaskLow; (* Set the specified MTTRphysBase register. *) PROCEDURE -SetMTTRphysBase(n: ADDRESS; high, low: SET); CODE {SYSTEM.Pentium, SYSTEM.Privileged} POP EAX POP EDX POP ECX SHL ECX, 1 ADD ECX, 200H ; MTTRphysBase0 WRMSR END SetMTTRphysBase; (* Set the specified MTTRphysMask register. *) PROCEDURE -SetMTTRphysMask(n: ADDRESS; high, low: SET); CODE {SYSTEM.Pentium, SYSTEM.Privileged} POP EAX POP EDX POP ECX SHL ECX, 1 ADD ECX, 201H ; MTTRphysMask0 WRMSR END SetMTTRphysMask; (** Set the cache properties of the specified physical memory area on the current processor. {physAdr, size MOD PS = 0} Must be called from supervisor mode. *) PROCEDURE LocalSetCacheProperties*(physAdr: ADDRESS; size, type: LONGINT; VAR res: WORD); VAR i, n, f: LONGINT; mask, base: SET; j, k: ADDRESS; BEGIN ASSERT((physAdr MOD PS = 0) & (size MOD PS = 0) & (size # 0)); IF (physAdr >= M) OR (physAdr < 0) THEN k := size; WHILE k > 0 DO k := ASH(k, 1) END; (* shift highest set bit into bit 31 *) IF k = 80000000H THEN (* only one bit was set => size is power of 2 *) IF physAdr MOD size = 0 THEN Machine.Acquire(Machine.Memory); (* hack *) IF Machine.MTTR IN Machine.features THEN (* MTTRs supported *) mask := GetMTTRcapLow(); IF (type # WC) OR (10 IN mask) THEN n := SYSTEM.VAL(LONGINT, mask * {0..7}); i := 0; f := -1; res := Ok; WHILE (i # n) & (res = Ok) DO mask := GetMTTRphysMaskLow(i); IF 11 IN mask THEN (* entry is valid *) mask := mask * {12..MAX(SET)}; base := GetMTTRphysBaseLow(i) * mask; j := physAdr; k := physAdr+size; WHILE (j # k) & (SYSTEM.VAL(SET, j) * mask # base) DO INC(j, PS) END; (* performance! *) IF j # k THEN res := 1508 END (* cache type of region already set *) ELSE IF f = -1 THEN f := i END (* first free entry *) END; INC(i) END; IF res = Ok THEN IF f # -1 THEN SetMTTRphysBase(f, {}, SYSTEM.VAL(SET, physAdr) * {12..31} + SYSTEM.VAL(SET, type) * {0..7}); SetMTTRphysMask(f, {0..3}, (-SYSTEM.VAL(SET, size-1)) * {12..31} + {11}) ELSE res := 1506 (* out of cache control entries *) END ELSE (* skip *) END ELSE res := 1511 (* region type not supported *) END ELSE res := 1505 (* MTTRs not supported *) END; Machine.Release(Machine.Memory) ELSE res := 1510 (* region base must be aligned on size *) END ELSE res := 1509 (* region size must be power of 2 *) END ELSE res := 1507 (* implementation restriction - fixed entries not supported *) END END LocalSetCacheProperties; PROCEDURE HandleSetCacheProperties(id: LONGINT; CONST state: Machine.State; msg: Machine.Message); BEGIN WITH msg: SetCacheMessage DO (* to do: page 11-25 *) LocalSetCacheProperties(msg.physAdr, msg.size, msg.type, msg.res[id]) END END HandleSetCacheProperties; (** Broadcast a LocalSetCacheProperties operation to all processors. *) PROCEDURE GlobalSetCacheProperties*(physAdr: ADDRESS; size, type: LONGINT; VAR res: WORD); VAR i: LONGINT; msg: SetCacheMessage; BEGIN NEW(msg); msg.physAdr := physAdr; msg.size := size; msg.type := type; FOR i := 0 TO Machine.MaxCPU-1 DO msg.res[i] := 2304 END; (* default result *) Machine.Broadcast(HandleSetCacheProperties, msg, {Machine.Self, Machine.FrontBarrier, Machine.BackBarrier}); res := 0; FOR i := 0 TO Machine.MaxCPU-1 DO IF (res = 0) & (msg.res[i] # 0) THEN res := msg.res[i] END (* return first non-ok result found *) END END GlobalSetCacheProperties; (** Disable all caching on the current processor. *) PROCEDURE LocalDisableCaching*; CODE {SYSTEM.Pentium, SYSTEM.Privileged} PUSHFD CLI MOV EAX, CR0 OR EAX, 40000000H AND EAX, 0DFFFFFFFH MOV CR0, EAX WBINVD MOV EAX, CR4 AND EAX, 0FFFFFF7FH MOV CR4, EAX MOV EAX, CR3 MOV CR3, EAX MOV ECX, 2FFH ; MTTRdefType MOV EAX, 0 MOV EDX, 0 WRMSR WBINVD MOV EAX, CR3 MOV CR3, EAX MOV EAX, CR0 OR EAX, 60000000H MOV CR0, EAX POPFD END LocalDisableCaching; PROCEDURE HandleDisableCaching(id: LONGINT; CONST state: Machine.State; msg: Machine.Message); BEGIN LocalDisableCaching END HandleDisableCaching; (** Broadcast a LocalDisableCaching operation to all processors. *) PROCEDURE GlobalDisableCaching*; BEGIN Machine.Broadcast(HandleDisableCaching, NIL, {Machine.Self, Machine.FrontBarrier, Machine.BackBarrier}) END GlobalDisableCaching; END MemCache. (* to do: o change error codes *)