rlyeh
Certified Guru
Hello,
I'm trying to reallocate my framebuffers.
Putting them on any location in the upper 32mbs is fairly easy, but doing it in the lower 32 mbps is a madness.
I've got the following code almost working, but the LCD shows some rubbish when flipping video pages.
Initially jix suggested me I had to drain the writeback buffer, so I did it. But after that my problems still being there.
I think my memory is fragmented someway, and that is very possible under Linux.
About possible fixes, I'm thinking about doing a Linux module and trying to load it at boot or something else (before the memory gets fragmented). I would kmalloc() some contiguous areas, or even better, vmap() about 10 consecutive kernel pages (128 kb max each).
If there is another solution I'd like to hear it, because I don't like my solution at all.
That's all.
Regards.
I'm trying to reallocate my framebuffers.
Putting them on any location in the upper 32mbs is fairly easy, but doing it in the lower 32 mbps is a madness.
I've got the following code almost working, but the LCD shows some rubbish when flipping video pages.
Initially jix suggested me I had to drain the writeback buffer, so I did it. But after that my problems still being there.
I think my memory is fragmented someway, and that is very possible under Linux.
About possible fixes, I'm thinking about doing a Linux module and trying to load it at boot or something else (before the memory gets fragmented). I would kmalloc() some contiguous areas, or even better, vmap() about 10 consecutive kernel pages (128 kb max each).
If there is another solution I'd like to hear it, because I don't like my solution at all.
That's all.
Regards.
Code:
/*
,--------------------.
| |X
| GP2X - LIBRARY |X
| |X
`--------------------'X
XXXXXXXXXXXXXXXXXXXXXX
*/
static void gp2x_mem_allocupper(unsigned long *phys, void **virt, int length)
{
static int top = 0x2000000;
*phys = 0, *virt = (void **)0;
if(top - length >= 0)
{
top -= length;
*phys = 0x2000000 + top;
*virt = (void **)&gp2x_dualcore_ram[top>>2];
memset(*virt, 0, length);
}
}
#define BUFFER (0x10000)
#define BLOCKS (0x2000000/BUFFER)
int gp2x_mem_virt2phys(void *addr)
{
unsigned long *test=(unsigned long *)addr,backup[3],*buffer,bufferpos=0,i,j;
if(!addr) return 0;
buffer = (unsigned long *)malloc(BUFFER);
backup[0] = test[0]; test[0] = 0xDEADBEEF;
backup[1] = test[1]; test[1] = 0x00C0FFEE;
backup[2] = test[2]; test[2] = 0x1337BEEF;
for(j=0;j<BLOCKS;j++)
{
const char *progress_str[]={". ",".. ","..."};
printf("Searching for [%08x]: %03d%% %s\r",test,((j+1)*100)/BLOCKS,progress_str[ (j >> 7) & 3]);
memset((void *)buffer, 0, BUFFER);
lseek (gp2x_dev[2], bufferpos, SEEK_SET);
if(read (gp2x_dev[2], (void *)buffer, BUFFER) != BUFFER)
printf("bad read, block #j=%04x\n",j);
for(i=0;i<BUFFER>>2;i++)
if(buffer[i+0]==0xDEADBEEF)
if(buffer[i+1]==0x00C0FFEE)
if(buffer[i+2]==0x1337BEEF)
{
printf("Retrieved %08x physical address from pointer [%08x].\r\n",bufferpos+i,test);
lseek (gp2x_dev[2], 0, SEEK_SET);
test[0] = backup[0], test[1] = backup[1], test[2] = backup[2];
free((void *)buffer);
return bufferpos+i;
}
bufferpos+=BUFFER;
}
printf("Nothing found \r\n");
lseek (gp2x_dev[2], 0, SEEK_SET);
free((void *)buffer);
return 0;
}
unsigned long *myfb, myfb_addr=0;
void gp2x_mem_installhackdrain(void)
{
unsigned int i,a,tlbc[4] = { 0xe3a00000, // mov r0, #0
0xee070f9a, // mcr 15, 0, r0, cr7, cr10, 4
0xee080f17, // mcr 15, 0, r0, cr8, cr7, 0
0xe1a0f00e }; // mov pc, lr
do
{
for(a=i=0;i<4;i++)
{
lseek (gp2x_dev[2], 0x6ec00+i*4, SEEK_SET); // fixme: We should ask the kernel for this address rather than assuming it...
a+=write (gp2x_dev[2], &tlbc[i], 4);
}
} while(a!=4*4);
printf("Installed hackdrain\n");
lseek (gp2x_dev[2], 0, SEEK_SET);
}
static void gp2x_mem_patchfb(void)
{
myfb_addr=0;
if(!(myfb = (unsigned long *)malloc(640*480*2*2+0x1000))) return;
if(!(myfb_addr=gp2x_mem_virt2phys(myfb))) { free(myfb); return; }
myfb_addr += 0x1000 - (myfb_addr % 0x1000); //padding
printf("%s!\n",!mprotect(myfb,640*480*2*2,PROT_READ|PROT_WRITE|PROT_EXEC) ? "ok":"oh no");
printf("%d %s\n", errno, strerror(errno));
printf("Changed vram workspace to %08x [phys:%08x]\n",myfb,myfb_addr);
}
void gp2x_misc_draincache(void)
{ // jump to previously hooked trap at &uname() (0x6ec00)
asm volatile (".word 0xef90007a"); // swi syscall_uname
}
/*
Some notes:
gp2x_video_RGB[0].p[x] is a useable pointer which points to page x.
gp2x_video_RGB[0].i[x] is a non-useable int which points to page x (physically). It is used to flip vram pages.
gp2x_RGB_video_flip(0); will call gp2x_misc_draincache(); before doing the flip.
gp2x_init() has the following code:
int i;
//install 920T drain writeback buffer
gp2x_mem_installhackdrain();
//patch framebuffers
gp2x_mem_patchfb();
for(i=0;i<3;i++)
if(myfb_addr)
gp2x_video_RGB[0].p[i]=(void *)&myfb[(0x26000*i)>>2], gp2x_video_RGB[0].i[i]=myfb_addr+0x26000*i;
else
gp2x_mem_allocupper(&gp2x_video_RGB[0].i[i], &gp2x_video_RGB[0].p[i], 0x26000);
*/