modify the GPU's MMU mechanism to avoid accessing the freed pagetables

This commit is contained in:
chenli
2012-01-16 14:46:23 +08:00
parent b55a7eeb64
commit eb91b3bb9d
4 changed files with 132 additions and 4 deletions

View File

@@ -710,9 +710,17 @@ gckHARDWARE_InitializeHardware(
)
{
/* Reset MMU. */
#if gcdENABLE_MMU_PROTECTING
//chenli:logical address added pageTableEntries to store the the physical addresses
gcmkONERROR(
gckHARDWARE_SetMMU(Hardware,
Hardware->kernel->mmu->pageTableLogical));
Hardware->kernel->mmu->pageTableLogical + Hardware->kernel->mmu->pageTableEntries));
#else
gcmkONERROR(
gckHARDWARE_SetMMU(Hardware,
Hardware->kernel->mmu->pageTableLogical));
#endif
}
/* Success. */

View File

@@ -360,5 +360,15 @@
#define USE_DMA_COHERENT 1
/*
chenli: gcdENABLE_MMU_PROTECTING
avoid GPU accessing the freed PageTables
gcdENABLE_MMU_PROTECTING:
0 - no use,original code
1 - use
*/
#define gcdENABLE_MMU_PROTECTING 1
#endif /* __gc_hal_options_h_ */

View File

@@ -366,6 +366,11 @@ struct _gckMMU
gctUINT32_PTR pageTableLogical;
gctUINT32 pageTableEntries;
#if gcdENABLE_MMU_PROTECTING
gctPHYS_ADDR FreePagePhysical;
gctUINT32_PTR FreePageLogical;
#endif
/* Free entries. */
gctUINT32 heapList;
gctBOOL freeNodes;

View File

@@ -25,6 +25,10 @@
#define _GC_OBJ_ZONE gcvZONE_MMU
#if gcdENABLE_MMU_PROTECTING
#include "../os/linux/kernel/gc_hal_kernel_os.h"
#endif
typedef enum _gceMMU_TYPE
{
gcvMMU_USED = 0,
@@ -214,6 +218,11 @@ gckMMU_Construct(
gckMMU mmu = gcvNULL;
gctUINT32_PTR pageTable;
#if gcdENABLE_MMU_PROTECTING
gctSIZE_T pageTableSize_x2;
gctSIZE_T OnePage = PAGE_SIZE;
#endif
gcmkHEADER_ARG("Kernel=0x%x MmuSize=%lu", Kernel, MmuSize);
/* Verify the arguments. */
@@ -254,12 +263,39 @@ gckMMU_Construct(
/* Allocate the page table (not more than 256 kB). */
mmu->pageTableSize = gcmMIN(MmuSize, 256 << 10);
#if gcdENABLE_MMU_PROTECTING
//one pageTableSize to store the labels ,another pageTableSize to store the physical addresses
pageTableSize_x2 = mmu->pageTableSize*2;
gcmkONERROR(
gckOS_AllocateContiguous(os,
gcvFALSE,
&pageTableSize_x2,
&mmu->pageTablePhysical,
(gctPOINTER *) &mmu->pageTableLogical));
if(pageTableSize_x2 != mmu->pageTableSize*2)
{
printk("pageTableSize_x2 != mmu->pageTableSize*2\n");
goto OnError;
}
//this page's physical address is set to the freed pageTable in gckMMU_FreePages
gcmkONERROR(
gckOS_AllocateContiguous(os,
gcvFALSE,
&OnePage,
&mmu->FreePagePhysical,
(gctPOINTER *)&mmu->FreePageLogical));
#else
gcmkONERROR(
gckOS_AllocateContiguous(os,
gcvFALSE,
&mmu->pageTableSize,
&mmu->pageTablePhysical,
(gctPOINTER *) &mmu->pageTableLogical));
#endif
/* Compute number of entries in page table. */
mmu->pageTableEntries = mmu->pageTableSize / sizeof(gctUINT32);
@@ -272,8 +308,14 @@ gckMMU_Construct(
mmu->freeNodes = gcvFALSE;
/* Set page table address. */
#if gcdENABLE_MMU_PROTECTING
//logical address added pageTableEntries to store the the physical addresses
gcmkONERROR(
gckHARDWARE_SetMMU(hardware, (gctPOINTER) (mmu->pageTableLogical + mmu->pageTableEntries)));
#else
gcmkONERROR(
gckHARDWARE_SetMMU(hardware, (gctPOINTER) mmu->pageTableLogical));
#endif
/* Return the gckMMU object pointer. */
*Mmu = mmu;
@@ -283,17 +325,33 @@ gckMMU_Construct(
return gcvSTATUS_OK;
OnError:
/* Roll back. */
if (mmu != gcvNULL)
{
if (mmu->pageTableLogical != gcvNULL)
{
/* Free the page table. */
#if gcdENABLE_MMU_PROTECTING
gcmkVERIFY_OK(
gckOS_FreeContiguous(os,
mmu->pageTablePhysical,
(gctPOINTER) mmu->pageTableLogical,
mmu->pageTableSize*2));
gcmkVERIFY_OK(
gckOS_FreeContiguous(os,
mmu->FreePagePhysical,
(gctPOINTER) mmu->FreePageLogical,
PAGE_SIZE));
#else
gcmkVERIFY_OK(
gckOS_FreeContiguous(os,
mmu->pageTablePhysical,
(gctPOINTER) mmu->pageTableLogical,
mmu->pageTableSize));
#endif
}
if (mmu->pageTableMutex != gcvNULL)
@@ -363,11 +421,24 @@ gckMMU_Destroy(
#endif
/* Free the page table. */
#if gcdENABLE_MMU_PROTECTING
gcmkVERIFY_OK(
gckOS_FreeContiguous(Mmu->os,
Mmu->pageTablePhysical,
(gctPOINTER) Mmu->pageTableLogical,
Mmu->pageTableSize*2));
gcmkVERIFY_OK(
gckOS_FreeContiguous(Mmu->os,
Mmu->FreePagePhysical,
(gctPOINTER) Mmu->FreePageLogical,
PAGE_SIZE));
#else
gcmkVERIFY_OK(
gckOS_FreeContiguous(Mmu->os,
Mmu->pageTablePhysical,
(gctPOINTER) Mmu->pageTableLogical,
Mmu->pageTableSize));
#endif
#ifdef __QNXNTO__
/* Delete the node list mutex. */
@@ -438,7 +509,7 @@ gckMMU_AllocatePages(
/* Not enough pages avaiable. */
gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
}
/* Grab the mutex. */
gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
mutex = gcvTRUE;
@@ -542,7 +613,15 @@ gckMMU_AllocatePages(
pageTable[index] = gcvMMU_USED;
/* Return pointer to page table. */
#if gcdENABLE_MMU_PROTECTING
//index add pageTableEntries to store real physical address
*PageTable = &pageTable[index +Mmu->pageTableEntries];
//must do memset because the elements may be set to ~0U in gckMMU_FreePages or _AddFree
memset(&pageTable[index], gcvMMU_USED, PageCount*4);
#else
*PageTable = &pageTable[index];
#endif
/* Build virtual address. */
gcmkONERROR(
@@ -562,6 +641,7 @@ gckMMU_AllocatePages(
return gcvSTATUS_OK;
OnError:
if (mutex)
{
/* Release the mutex. */
@@ -602,10 +682,15 @@ gckMMU_FreePages(
)
{
gctUINT32_PTR pageTable;
#if gcdENABLE_MMU_PROTECTING
int i;
#endif
gcmkHEADER_ARG("Mmu=0x%x PageTable=0x%x PageCount=%lu",
Mmu, PageTable, PageCount);
/* Verify the arguments. */
gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
@@ -614,18 +699,38 @@ gckMMU_FreePages(
/* Convert the pointer. */
pageTable = (gctUINT32_PTR) PageTable;
#if gcdENABLE_MMU_PROTECTING
//sub pageTableEntries to get the address that store lables
pageTable -= Mmu->pageTableEntries;
#endif
if (PageCount == 1)
{
/* Single page node. */
pageTable[0] = (~0U << 8) | gcvMMU_SINGLE;
#if gcdENABLE_MMU_PROTECTING
//set the special phsical address to avoid GPU accessing other addresses
pageTable[Mmu->pageTableEntries] = ((PLINUX_MDL)(Mmu->FreePagePhysical))->dmaHandle;
#endif
}
else
{
/* Mark the node as free. */
pageTable[0] = (PageCount << 8) | gcvMMU_FREE;
pageTable[1] = ~0U;
}
#if gcdENABLE_MMU_PROTECTING
//set the special phsical address to avoid GPU accessing other addresses
for(i=0; i<PageCount; i++)
{
pageTable[Mmu->pageTableEntries+i] = ((PLINUX_MDL)(Mmu->FreePagePhysical))->dmaHandle;
}
#endif
}
/* We have free nodes. */
Mmu->freeNodes = gcvTRUE;