This is the source for the MMUHACK 2.4 kernel module is included with the GP2X backend. This is the code used to build the mmuhack.o module that ships with the GP2X binaries.

-- line, and those below, will be ignored--

A    gp2x/mmuhack
AM   gp2x/mmuhack/flush_uppermem_cache.s
AM   gp2x/mmuhack/flush_uppermem_cache.h
AM   gp2x/mmuhack/mmuhack.c
AM   gp2x/mmuhack/readme.txt
AM   gp2x/mmuhack/Makefile

svn-id: r40449
This commit is contained in:
John Willis 2009-05-11 10:15:38 +00:00
parent 2cb051a394
commit 911556a824
5 changed files with 267 additions and 0 deletions

View File

@ -0,0 +1,11 @@
TARGET = mmuhack
INCLUDE = -I/opt/gcc-3.4.4-glibc-2.3.6/arm-open2x-linux/sys-include
CFLAGS = -O2 -DMODULE -D__KERNEL__ ${INCLUDE}
CC = arm-open2x-linux-gcc
all: ${TARGET}.o
${TARGET}.o: ${TARGET}.c
clean:
rm -rf ${TARGET}.o

View File

@ -0,0 +1,11 @@
#ifdef __cplusplus
extern "C"
{
#endif
void flush_uppermem_cache(void *start_address, void *end_address, int flags);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,6 @@
.global flush_uppermem_cache @ void *start_address, void *end_address, int flags
flush_uppermem_cache:
swi #0x9f0002
bx lr

View File

@ -0,0 +1,129 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/gp2x/gp2x-mem.cpp $
* $Id: gp2x-mem.cpp 39708 2009-03-27 14:12:42Z dhewg $
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <asm/memory.h>
#define MMUHACK_MINOR 225
#define DEVICE_NAME "mmuhack"
#if __GNUC__ == 3
#include <linux/version.h>
static const char __module_kernel_version_gcc3[] __attribute__((__used__)) __attribute__((section(".modinfo"))) =
"kernel_version=" UTS_RELEASE;
#endif
static ssize_t mmuhack_open(struct inode *inode, struct file *filp)
{
unsigned int *pgtable;
unsigned int *cpt;
int i, j;
int ttb;
int ret = -EFAULT;
// get the pointer to the translation table base...
asm volatile(
"stmdb sp!, {r0}\n\t"
"mrc p15, 0, r0, c2, c0, 0\n\t"
"mov %0, r0\n\t"
"ldmia sp!, {r0}\n\t": "=r"(ttb)
);
pgtable = __va(ttb);
for (i = 0; i < 4096; i ++) if ( (pgtable[i] & 3) == 1 ) {
cpt = __va(pgtable[i] & 0xfffffc00);
for (j = 0; j < 256; j ++) {/*
if ( (cpt[j] & 0xfe00000f) == 0x02000002 ) {
// set C and B bits in upper 32MB memory area...
printk("Set C&B bits %08x\n",cpt[j]);
cpt[j] |= 0xFFC;
ret = 0;
}
*/
if (((cpt[j] & 0xff000000) == 0x02000000) && ((cpt[j] & 12)==0) )
{
//printk("Set C&B bits %08x\n",cpt[j]);
cpt[j] |= 0xFFC;
}
//if ((a>=0x31 && a<=0x36) && ((cpt[i] & 12)==0))
if (((cpt[j] & 0xff000000) == 0x03000000) && ((cpt[j] & 12)==0))
{
//printk("Set C&B bits %08x\n",cpt[j]);
//printf("SDL c and b bits not set, overwriting\n");
cpt[j] |= 0xFFC;
}
}
}
// drain the write buffer and flush the tlb caches...
asm volatile(
"stmdb sp!, {r0}\n\t"
"mov r0, #0\n\t"
"mcr 15, 0, r0, cr7, cr10, 4\n\t"
"mcr 15, 0, r0, cr8, cr7, 0\n\t"
"ldmia sp!, {r0}\n\t"
);
if (ret == 0)
printk("MMU hack applied.\n");
return 0;
}
static struct file_operations mmuhack_fops = {
owner: THIS_MODULE,
open: mmuhack_open,
};
static struct miscdevice mmuhack = {
MMUHACK_MINOR, DEVICE_NAME, &mmuhack_fops
};
static int __init mmuhack_init(void)
{
misc_register(&mmuhack);
/*
printk("MMSP2 MMU Hack module.\n");
*/
return 0;
}
static void __exit mmuhack_exit(void)
{
misc_deregister(&mmuhack);
/*
printk(KERN_ALERT "MMU Hack module removed.\n");
*/
}
module_init(mmuhack_init);
module_exit(mmuhack_exit);

View File

@ -0,0 +1,110 @@
About
-----
This is a module for GP2X 2.4 based Linux kernel, created for developers to use in their
programs.
Normally the upper 32MB is uncached. This means that reads/writes on the memory
are always done via the physical memory modules rather than the much faster
memory built into the processor (called 'cache'). Access to the upper 32MB can
be sped up by Squidge's MMU hack. The easiest way to use the MMU hack is to add
and load the MMU hack kernel module into your program.
Note: Building this module requries a GP2X 'kernel' toolchain (i.e. GCC 2.95.*
for the GP2X stock, 3.* for Open2X).
You can't build this module with the GCC 4 based application toolchains.
Operation
---------
When loaded into kernel, this module creates /dev/mmuhack device. Whenever
a program opens that device using open() call, the module traverses all
memory, which was allocated in 0x02000000-0x03ffffff range by the program via
using mmap() system call. While doing that, it marks all encountered memory
as bufferable and cacheable.
The most common use of this is to remove the framebuffer access bottleneck.
Note that, however, by making the framebuffer cacheable you can cause display
artifacts. This can happen because parts of your framebuffer may stay in CPU
cache and not to be written back to the physical memory. The display
controller only fetches data from the physical memory, so you get incomplete
image (the memory will most likely contain data from previous frame, so these
artifacts are better visible during fade effects). The easy way to fix this
is by using a special ARM Linux system call, which flushes the cache (forces
the CPU to write data in cache to the physical memory (see section "Flushing
the cache")).
Using this module affects the whole upper memory area. But in some situations
this may be not desirable, for example when using ARM940 core in your program
(ether using 940 libraries like ogg940 and gpu940, or using your custom code,
which needs uncacheable memory for communication and such). If you need part
of your upper memory to be cached, and other part not, you should mmap() that
memory (which you want to be uncached) _after_ doing open("/dev/mmuhack").
Another way is to modify mmuhack.c to suit your needs and rebuild the module.
Usage
-----
The very first thing to do is to load the kernel module (mmuhack.o) into the
running kernel. But before that you should try to unload mmuhack module,
because other program might have left a different version loaded with
different memory configuration, which may not suit your program.
system("/sbin/rmmod mmuhack");
system("/sbin/insmod mmuhack.o");
Now you can assume the module is loaded into kernel and open /dev/mmuhack
device. You don't need to worry about previous calls failing, because in that
case open() will simply fail and nothing bad will happen.
IMPORTANT: you _must_ do the open() call _after_ you initialize your graphics
library or allocate your memory, because it can only work with memory which is
already allocated, it won't affect memory you or your lib allocates after the
open() call.
int mmufd = open("/dev/mmuhack", O_RDWR);
if(mmufd < 0)
{
printf("MMU hack failed");
}
else
{
printf("MMU hack loaded");
close(mmufd);
}
If the above call succeeded, you are all done.
I recommend to unload the module when your program exits, because the other
program may want to load a different mmuhack.o and may fail, because you left
your mmuhack.o loaded (it does not get unloaded automatically on exit).
system("/sbin/rmmod mmuhack");
Flushing the cache
------------------
If using mmuhack.o causes your program to display artifacts (see "Operation"
section for explanation), you will need to flush the CPU cache. This should
be done after finishing every frame and just before flipping your display
buffer/surface. You will need to add flush_uppermem_cache.s file to your
Makefile/project and add a call to flush_uppermem_cache() just before final
framebuffer flip or blit.
flush_uppermem_cache() has 3 parameters. First param is the start address,
second param is the end address, third one should always be 0. The addresses
should be virtual ones (most often pointers to the start/end of your
framebuffer). Example:
flush_uppermem_cache(screen_surface->pixels, screen_surface->pixels + 320*240, 0);
Credits
-------
Original idea/implementation: Squidge (this whole thing is also known as squidgehack)
Kernel module: NK
Documentation: notaz