Skip to content

Commit

Permalink
Add functionality to set Write Allocate register.
Browse files Browse the repository at this point in the history
Takes into account 15-16M hole too.

Provides "setWriteAllocateManual", a function to set manual range
+ Hole flag for later when we allow custom parameters.

Also provides "setWriteAllocateForSystemRAM", which finds
the total system memory size and sets write allocate for it.
It interprets the result of the Int15h call to find out if the 15-
16M hole needs to be respected.

The underlying assembly function called
"k6_setWriteAllocate" takes care of the
actual WHCR MSR.
  • Loading branch information
Eric Voirin committed Aug 26, 2021
1 parent 7812bd5 commit 213c2d5
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 7 deletions.
10 changes: 9 additions & 1 deletion K6.H
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ typedef struct {

extern unsigned short k6_getMemorySize(unsigned long _far *memorySizeBelow16M, unsigned long _far *memorySizeAbove16M);

extern void k6_setWriteAllocate(unsigned long value);

extern void k6_getCPUIdentifier(char _far *cpuidString);
extern cpuidProcessorType k6_getCPUProcessorType(void);

Expand All @@ -47,8 +49,14 @@ int checkSupportedCPU(void);

int enableWriteCombiningForLFBs(void);

// Memory stuff
// Memory / Write Allocate stuff

void showMemoryInfo(void);

void setWriteAllocateManual(unsigned long writeAllocateMemorySize,
int enableForMemoryHole);

void setWriteAllocateForSystemRAM(void);


#endif
44 changes: 42 additions & 2 deletions K6CPU.ASM
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

k6_getMemorySize PROTO C memSizeBelow16M:FAR PTR DWORD, memSizeAbove16M:FAR PTR DWORD

k6_setWriteAllocate PROTO C whcrValue:DWORD

k6_getCPUIdentifier PROTO C cpuidString:FAR PTR CHAR
k6_getCPUProcessorType PROTO C

Expand All @@ -20,8 +22,8 @@ k6_getVBEModeInfo PROTO C videoMode:WORD, vbeModeInfoPtr:FAR PTR BYTE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; getMemorySize
;
; Parameters: pointer to DWORD to put the size below 16M in bytes in
; pointer to DWORD to put the size above 16M in bytes in
; Parameters: pointer to DWORD to put the size below 16M in bytes in
; pointer to DWORD to put the size above 16M in bytes in
; Returns: 1 in ax on success, 0 if not.

k6_getMemorySize PROC C uses ebx ecx edx es di,memSizeBelow16M:FAR PTR DWORD, memSizeAbove16M:FAR PTR DWORD
Expand Down Expand Up @@ -75,6 +77,44 @@ done:
k6_getMemorySize ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; setWriteAllocate
;
; Parameters: DWORD containing the register value.

k6_setWriteAllocate PROC C USES eax ebx ecx edx, whcrValue:DWORD

k6_MSR_WHCR EQU 0C0000082h

; MSR register ID needs to go in ecx

mov ecx, k6_MSR_WHCR ; Write Handling Control Register (WHCR)

; 31-00 = eax
; 63-32 = edx

; we only write eax since that's what we need.

mov eax, whcrValue
xor edx, edx

; since we're messing with caching stuff, we need to
; write back and invalidate the cache first

pushf
cli
wbinvd

; write the WHCR value

wrmsr
popf

ret


k6_setWriteAllocate ENDP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; getCPUIdentifier
;
Expand Down
51 changes: 51 additions & 0 deletions K6INIT.C
Original file line number Diff line number Diff line change
Expand Up @@ -402,4 +402,55 @@ void showMemoryInfo(void)

printf("\n");

}

void setWriteAllocateManual(unsigned long writeAllocateMemorySize,
int enableForMemoryHole)
{
// Sets write allocation for the given parameters
// The size is in bytes.

// 4 MiB mask: 0xFFC00000
// Memory hole bit: 0x00010000

// We need to increment this value by 1 or rather 0x0040000,
// else the last 4MB won't be inside the range!


unsigned long writeAllocateReg = (writeAllocateMemorySize + 1)
& 0xFFC00000UL;

if (enableForMemoryHole) {
writeAllocateReg = writeAllocateReg | 0x00010000UL;
}

printf("Enabling Write Allocate for 1 - %lu MiB\n",
writeAllocateReg >> 20UL);
printf("Setting Write Allocate WHCR Register: %08lx\n", writeAllocateReg);

k6_setWriteAllocate(writeAllocateReg);

}

void setWriteAllocateForSystemRAM(void)
{
unsigned long writeAllocateMemorySize;
int systemHasMemoryHole;

writeAllocateMemorySize = getMemorySize();
systemHasMemoryHole = hasMemoryHole();

// Leave if we have an error in detection

if ((writeAllocateMemorySize == 0) || (systemHasMemoryHole < 0)) {
printf("ERROR getting memory info! Not setting Write allocate.\n");
return;
}

// Make sure to negate the memory hole var, since it needs to be 1 if
// we DON'T have a memory hole to enable write allocate for the 15-16M
// region!!

setWriteAllocateManual(writeAllocateMemorySize, !systemHasMemoryHole);

}
2 changes: 2 additions & 0 deletions MAIN.C
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ int main (int argc, char **argv)
goto cleanup;
}

setWriteAllocateForSystemRAM();

/* Parse the command line. */

signal(SIGINT, SIG_IGN);
Expand Down
12 changes: 8 additions & 4 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,14 @@ NO! I'm still learning.
* yes
* Set MTRR to enable Write combining for LFB
* yes
* Detect total available system memory and set WA mode
* No
* Detect 15-16M Memory hole for WA
* No
* Set Write Combine Mode
* no, need to do more research
* Detect total available system memory
* yes
* Detect 15-16M Memory hole
* yes
* Set write allocate for system memory
* yes (not verified yet, it's late)
* Set K6-3 Multiplier
* I don't actually own this CPU. ETA: When the cows come home

Expand Down

0 comments on commit 213c2d5

Please sign in to comment.