ref: ea30cf94a5f247dd00c32c01325b8a47ad5f105a
parent: d48a0894865e810f46e1ef2f07476c4f3101698a
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Dec 17 11:35:26 EST 2016
pat write combinding support for 386 kernel, honor cpuid bits
--- a/sys/src/9/pc/dat.h
+++ b/sys/src/9/pc/dat.h
@@ -316,6 +316,7 @@
Mtrr = 1<<12, /* memory-type range regs. */
Pge = 1<<13, /* page global extension */
Mca = 1<<14, /* machine-check architecture */
+ Pat = 1<<16, /* page attribute table */
Pse2 = 1<<17, /* more page size extensions */
Clflush = 1<<19,
Acpif = 1<<22, /* therm control msr */
--- a/sys/src/9/pc/mmu.c
+++ b/sys/src/9/pc/mmu.c
@@ -66,11 +66,17 @@
#define VPTX(va) (((ulong)(va))>>12)
#define vpd (vpt+VPTX(VPT))
+enum {
+ /* PAT entry used for write combining */
+ PATWC = 7,
+};
+
void
mmuinit(void)
{
ulong x, *p;
ushort ptr[3];
+ vlong v;
if(0) print("vpt=%#.8ux vpd=%#p kmap=%#.8ux\n",
VPT, vpd, KMAP);
@@ -119,6 +125,14 @@
taskswitch(PADDR(m->pdb), (ulong)m + BY2PG);
ltr(TSSSEL);
+
+ /* IA32_PAT write combining */
+ if((MACHP(0)->cpuiddx & Pat) != 0
+ && rdmsr(0x277, &v) != -1){
+ v &= ~(255LL<<(PATWC*8));
+ v |= 1LL<<(PATWC*8); /* WC */
+ wrmsr(0x277, v);
+ }
}
/*
@@ -1065,7 +1079,36 @@
return -KZERO - pa;
}
+/*
+ * mark pages as write combining (used for framebuffer)
+ */
void
-patwc(void *, int)
+patwc(void *a, int n)
{
+ ulong *pte, mask, attr, va;
+ vlong v;
+ int z;
+
+ /* check if pat is usable */
+ if((MACHP(0)->cpuiddx & Pat) == 0
+ || rdmsr(0x277, &v) == -1
+ || ((v >> PATWC*8) & 7) != 1)
+ return;
+
+ /* set the bits for all pages in range */
+ for(va = (ulong)a; n > 0; n -= z, va += z){
+ pte = mmuwalk(m->pdb, va, 1, 0);
+ if(pte && (*pte & (PTEVALID|PTESIZE)) == (PTEVALID|PTESIZE)){
+ z = 4*MB - (va & (4*MB-1));
+ mask = 3<<3 | 1<<12;
+ } else {
+ pte = mmuwalk(m->pdb, va, 2, 0);
+ if(pte == 0 || (*pte & PTEVALID) == 0)
+ panic("patwc: va=%#p", va);
+ z = BY2PG - (va & (BY2PG-1));
+ mask = 3<<3 | 1<<7;
+ }
+ attr = (((PATWC&3)<<3) | ((PATWC&4)<<5) | ((PATWC&4)<<10));
+ *pte = (*pte & ~mask) | (attr & mask);
+ }
}
--- a/sys/src/9/pc64/dat.h
+++ b/sys/src/9/pc64/dat.h
@@ -279,6 +279,7 @@
Mtrr = 1<<12, /* memory-type range regs. */
Pge = 1<<13, /* page global extension */
Mca = 1<<14, /* machine-check architecture */
+ Pat = 1<<16, /* page attribute table */
Pse2 = 1<<17, /* more page size extensions */
Clflush = 1<<19,
Acpif = 1<<22, /* therm control msr */
--- a/sys/src/9/pc64/mmu.c
+++ b/sys/src/9/pc64/mmu.c
@@ -135,10 +135,12 @@
wrmsr(0xc0000084, 0x200);
/* IA32_PAT write combining */
- rdmsr(0x277, &v);
- v &= ~(255LL<<(PATWC*8));
- v |= 1LL<<(PATWC*8); /* WC */
- wrmsr(0x277, v);
+ if((MACHP(0)->cpuiddx & Pat) != 0
+ && rdmsr(0x277, &v) != -1){
+ v &= ~(255LL<<(PATWC*8));
+ v |= 1LL<<(PATWC*8); /* WC */
+ wrmsr(0x277, v);
+ }
}
/*
@@ -549,13 +551,20 @@
* mark pages as write combining (used for framebuffer)
*/
void
-patwc(void *v, int n)
+patwc(void *a, int n)
{
uintptr *pte, mask, attr, va;
int z, l;
+ vlong v;
+ /* check if pat is usable */
+ if((MACHP(0)->cpuiddx & Pat) == 0
+ || rdmsr(0x277, &v) == -1
+ || ((v >> PATWC*8) & 7) != 1)
+ return;
+
/* set the bits for all pages in range */
- for(va = (uintptr)v; n > 0; n -= z, va += z){
+ for(va = (uintptr)a; n > 0; n -= z, va += z){
l = 0;
pte = mmuwalk(m->pml4, va, l, 0);
if(pte == 0)