XFree86,DGA,XQuake and Pentium 4MB pages, patch

Ingo Molnar (mingo@pc5829.hil.siemens.at)
Fri, 3 Jan 1997 14:43:57 +0100 (MET)


the following patch is a (broken) way of using Pentium 4MB pages in
user-space, for accessing memory-mapped framebuffers with one TLB entry.
It should definitely crash when doing an mmunmap() on /dev/mem, but there
is a (slight) chance that it works after XFree86+DGA+mmap("/dev/mem")+
xquake starts up.

BIG FAT WARNING:

missing the apropriate videocard i couldnt give this any testing, other
than compiling it ... this pre-pre-pre-pre-patch against 2.1.20 is only
intended for 4MB framebuffer cards. It might work for smaller cards too,
if you remove the size checking.

this should cut down on TLB misses greatly btw. Dont know if it makes any
difference.

flames ('it's already done','makes no sense'), comments ('it makes no
difference','crashes') welcome,

Ingo

-------- patch starts in the next line -------->
--- linux/drivers/char/mem.c.original Fri Jan 3 13:25:53 1997
+++ linux/drivers/char/mem.c Fri Jan 3 14:29:26 1997
@@ -112,6 +112,53 @@
*/
if (x86 > 3 && offset >= __pa(high_memory))
pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+ /*
+ * look for possible 4MB pages optimization. FIXME: this is a hack.
+ *
+ * the MMU part of it is very i386 specific
+ *
+ * it should crash hard in do_munmap(). [because do_munmap() assumes there
+ * is a page directory for this entry, and we cannot fix this even with
+ * the usage of mpnt->vm_ops->unmap()].
+ */
+ if (x86_capability & 8) {
+ unsigned long address, size = vma->vm_end-vma->vm_start;
+ pgd_t * dir;
+
+ /*
+ * currently just for cards with exactly 4MB frame buffer.
+ * FIXME: N*4M support, and possible support for other sizes too.
+ */
+ if (size != 4*1024*1024) {
+ printk("FIXME: probably a non 4M frame buffer.\n");
+ return -ENXIO;
+ }
+
+ /*
+ * get the appropriate root page directory entry
+ */
+ dir = pgd_offset(current->mm, vma->vm_start);
+
+ /*
+ * write the physical offset into it
+ */
+ address = (offset >> (PAGE_SHIFT-2)) & 4*(PTRS_PER_PTE - 1);
+
+ __asm__("movl %%cr4,%%eax\n\t"
+ "orl $16,%%eax\n\t"
+ "movl %%eax,%%cr4"
+ : : :"ax");
+
+ pgd_val(*dir) = _PAGE_TABLE + _PAGE_4M + __pa(address);
+
+ /*
+ * lazyness rulez. overdoing TLB flush, and doing no error checking
+ */
+ flush_tlb_all();
+ vma->vm_inode = inode;
+ inode->i_count++;
+ return 0;
+ }
#endif
if (remap_page_range(vma->vm_start, offset, vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;