pc64: implement simple write combining for framebuffers with the PAT

on some modern machines like the x250, the bios arranges the mtrr's
and the framebuffer membar in a way that doesnt allow us to mark
the framebuffer pages as write combining, leading to slow graphics.

since the pentium III, the processor interprets the page table bit
combinations of the WT, CD and bit7 bits as an index into the
page attribute table (PAT).

to not change the semantics of the WT and CD bits, we preserve
the bit patterns 0-3 and use the last entry 7 for write combining.
(done in mmuinit() for each core).

the new patwc() function takes virtual address range and changes
the page table marking the range as write combining. no attempt
is made on invalidating tlb's. doesnt matter in our case as the
following mtrr() call in screen.c does it for us.
This commit is contained in:
cinap_lenrek 2016-12-15 23:27:01 +01:00
parent f3b5bcffce
commit d48a089486
5 changed files with 44 additions and 1 deletions

View file

@ -123,6 +123,7 @@ void outss(int, void*, int);
void outl(int, ulong);
void outsl(int, void*, int);
ulong paddr(void*);
void patwc(void*, int);
ulong pcibarsize(Pcidev*, int);
void pcibussize(Pcidev*, ulong*, ulong*);
int pcicfgr8(Pcidev*, int);

View file

@ -1065,3 +1065,7 @@ cankaddr(ulong pa)
return -KZERO - pa;
}
void
patwc(void *, int)
{
}

View file

@ -492,6 +492,9 @@ vgalinearaddr0(VGAscr *scr, ulong paddr, int size)
scr->vaddr = vmap(npaddr, nsize);
if(scr->vaddr == 0)
return "cannot allocate vga frame buffer";
patwc(scr->vaddr, nsize);
scr->vaddr = (char*)scr->vaddr+x;
scr->paddr = paddr;
scr->apsize = nsize;

View file

@ -117,6 +117,7 @@ void outss(int, void*, int);
void outl(int, ulong);
void outsl(int, void*, int);
uintptr paddr(void*);
void patwc(void*, int);
ulong pcibarsize(Pcidev*, int);
void pcibussize(Pcidev*, ulong*, ulong*);
int pcicfgr8(Pcidev*, int);

View file

@ -31,13 +31,16 @@ static struct {
ulong nfree;
} mmupool;
/* level */
enum {
/* level */
PML4E = 2,
PDPE = 1,
PDE = 0,
MAPBITS = 8*sizeof(m->mmumap[0]),
/* PAT entry used for write combining */
PATWC = 7,
};
static void
@ -130,6 +133,12 @@ mmuinit(void)
/* SYSCALL flags mask */
wrmsr(0xc0000084, 0x200);
/* IA32_PAT write combining */
rdmsr(0x277, &v);
v &= ~(255LL<<(PATWC*8));
v |= 1LL<<(PATWC*8); /* WC */
wrmsr(0x277, v);
}
/*
@ -535,3 +544,28 @@ vunmap(void *v, int)
{
paddr(v); /* will panic on error */
}
/*
* mark pages as write combining (used for framebuffer)
*/
void
patwc(void *v, int n)
{
uintptr *pte, mask, attr, va;
int z, l;
/* set the bits for all pages in range */
for(va = (uintptr)v; n > 0; n -= z, va += z){
l = 0;
pte = mmuwalk(m->pml4, va, l, 0);
if(pte == 0)
pte = mmuwalk(m->pml4, va, ++l, 0);
if(pte == 0 || (*pte & PTEVALID) == 0)
panic("patwc: va=%#p", va);
z = PGLSZ(l);
z -= va & (z-1);
mask = l == 0 ? 3<<3 | 1<<7 : 3<<3 | 1<<12;
attr = (((PATWC&3)<<3) | ((PATWC&4)<<5) | ((PATWC&4)<<10));
*pte = (*pte & ~mask) | (attr & mask);
}
}