#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);
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);
+ }
}
/*
void
flushpg(ulong va)
{
- if(X86FAMILY(m->cpuidax) >= 4)
+ if(m->cpuidfamily >= 4)
invlpg(va);
else
putcr3(getcr3());
if(*table & PTESIZE)
panic("mmuwalk2: va %luX entry %luX", va, *table);
if(!(*table & PTEVALID)){
- /*
- * Have to call low-level allocator from
- * memory.c if we haven't set up the xalloc
- * tables yet.
- */
- if(conf.mem[0].npage != 0)
- map = xspanalloc(BY2PG, BY2PG, 0);
- else
- map = rampage();
- if(map == nil)
- panic("mmuwalk xspanalloc failed");
+ map = rampage();
+ memset(map, 0, BY2PG);
*table = PADDR(map)|PTEWRITE|PTEVALID;
}
table = KADDR(PPN(*table));
static int findhole(ulong *a, int n, int count);
static ulong vmapalloc(ulong size);
+static int pdbmap(ulong *, ulong, ulong, int);
static void pdbunmap(ulong*, ulong, int);
/*
void
vunmap(void *v, int size)
{
- int i;
ulong va, o;
- Mach *nm;
- Proc *p;
/*
* might not be aligned
* boot. In that case it suffices to flush the MACH(0) TLB
* and return.
*/
- if(!active.thunderbirdsarego){
+ if(up == nil){
putcr3(PADDR(MACHP(0)->pdb));
return;
}
- for(i=0; i<conf.nproc; i++){
- p = proctab(i);
- if(p->state == Dead)
- continue;
- if(p != up)
- p->newtlb = 1;
- }
- for(i=0; i<conf.nmach; i++){
- nm = MACHP(i);
- if(nm != m)
- nm->flushmmu = 1;
- }
+ procflushothers();
flushmmu();
- for(i=0; i<conf.nmach; i++){
- nm = MACHP(i);
- if(nm != m)
- while(active.machs[nm->machno] && nm->flushmmu)
- ;
- }
}
/*
* Add kernel mappings for pa -> va for a section of size bytes.
*/
-int
+static int
pdbmap(ulong *pdb, ulong pa, ulong va, int size)
{
int pse;
}
}
+void
+pmap(ulong pa, ulong va, int size)
+{
+ pdbmap(MACHP(0)->pdb, pa, va, size);
+}
+
+void
+punmap(ulong va, int size)
+{
+ pdbunmap(MACHP(0)->pdb, va, size);
+ mmuflushtlb(PADDR(m->pdb));
+}
+
/*
* Handle a fault by bringing vmap up to date.
* Only copy pdb entries and they never go away,
/*
* More debugging.
*/
-void
-countpagerefs(ulong *ref, int print)
-{
- int i, n;
- Mach *mm;
- Page *pg;
- Proc *p;
-
- n = 0;
- for(i=0; i<conf.nproc; i++){
- p = proctab(i);
- if(p->mmupdb){
- if(print){
- if(ref[pagenumber(p->mmupdb)])
- iprint("page %#.8lux is proc %d (pid %lud) pdb\n",
- p->mmupdb->pa, i, p->pid);
- continue;
- }
- if(ref[pagenumber(p->mmupdb)]++ == 0)
- n++;
- else
- iprint("page %#.8lux is proc %d (pid %lud) pdb but has other refs!\n",
- p->mmupdb->pa, i, p->pid);
- }
- if(p->kmaptable){
- if(print){
- if(ref[pagenumber(p->kmaptable)])
- iprint("page %#.8lux is proc %d (pid %lud) kmaptable\n",
- p->kmaptable->pa, i, p->pid);
- continue;
- }
- if(ref[pagenumber(p->kmaptable)]++ == 0)
- n++;
- else
- iprint("page %#.8lux is proc %d (pid %lud) kmaptable but has other refs!\n",
- p->kmaptable->pa, i, p->pid);
- }
- for(pg=p->mmuused; pg; pg=pg->next){
- if(print){
- if(ref[pagenumber(pg)])
- iprint("page %#.8lux is on proc %d (pid %lud) mmuused\n",
- pg->pa, i, p->pid);
- continue;
- }
- if(ref[pagenumber(pg)]++ == 0)
- n++;
- else
- iprint("page %#.8lux is on proc %d (pid %lud) mmuused but has other refs!\n",
- pg->pa, i, p->pid);
- }
- for(pg=p->mmufree; pg; pg=pg->next){
- if(print){
- if(ref[pagenumber(pg)])
- iprint("page %#.8lux is on proc %d (pid %lud) mmufree\n",
- pg->pa, i, p->pid);
- continue;
- }
- if(ref[pagenumber(pg)]++ == 0)
- n++;
- else
- iprint("page %#.8lux is on proc %d (pid %lud) mmufree but has other refs!\n",
- pg->pa, i, p->pid);
- }
- }
- if(!print)
- iprint("%d pages in proc mmu\n", n);
- n = 0;
- for(i=0; i<conf.nmach; i++){
- mm = MACHP(i);
- for(pg=mm->pdbpool; pg; pg=pg->next){
- if(print){
- if(ref[pagenumber(pg)])
- iprint("page %#.8lux is in cpu%d pdbpool\n",
- pg->pa, i);
- continue;
- }
- if(ref[pagenumber(pg)]++ == 0)
- n++;
- else
- iprint("page %#.8lux is in cpu%d pdbpool but has other refs!\n",
- pg->pa, i);
- }
- }
- if(!print){
- iprint("%d pages in mach pdbpools\n", n);
- for(i=0; i<conf.nmach; i++)
- iprint("cpu%d: %d pdballoc, %d pdbfree\n",
- i, MACHP(i)->pdballoc, MACHP(i)->pdbfree);
- }
-}
-
void
checkfault(ulong, ulong)
{
return -KZERO - pa;
}
+/*
+ * mark pages as write combining (used for framebuffer)
+ */
+void
+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(MACHP(0)->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(MACHP(0)->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);
+ }
+}