1 /****************************************************************************
3 * Copyright (C) 2005 - 2013 by Vivante Corp.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the license, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *****************************************************************************/
22 #include "gc_hal_kernel_precomp.h"
26 #define _GC_OBJ_ZONE gcvZONE_MMU
28 /*******************************************************************************
32 ** Construct a new gckVGMMU object.
37 ** Pointer to an gckVGKERNEL object.
40 ** Number of bytes for the page table.
45 ** Pointer to a variable that receives the gckVGMMU object pointer.
47 gceSTATUS gckVGMMU_Construct(
48 IN gckVGKERNEL Kernel,
54 gckVGHARDWARE hardware;
57 gctUINT32 * pageTable;
60 gcmkHEADER_ARG("Kernel=0x%x MmuSize=0x%x Mmu=0x%x", Kernel, MmuSize, Mmu);
62 /* Verify the arguments. */
63 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
64 gcmkVERIFY_ARGUMENT(MmuSize > 0);
65 gcmkVERIFY_ARGUMENT(Mmu != gcvNULL);
67 /* Extract the gckOS object pointer. */
69 gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
71 /* Extract the gckVGHARDWARE object pointer. */
72 hardware = Kernel->hardware;
73 gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
75 /* Allocate memory for the gckVGMMU object. */
76 status = gckOS_Allocate(os, sizeof(struct _gckVGMMU), (gctPOINTER *) &mmu);
82 "%s(%d): could not allocate gckVGMMU object.",
83 __FUNCTION__, __LINE__
90 /* Initialize the gckVGMMU object. */
91 mmu->object.type = gcvOBJ_MMU;
93 mmu->hardware = hardware;
95 /* Create the mutex. */
96 status = gckOS_CreateMutex(os, &mmu->mutex);
101 mmu->object.type = gcvOBJ_UNKNOWN;
102 gcmkVERIFY_OK(gckOS_Free(os, mmu));
109 /* Allocate the page table. */
110 mmu->pageTableSize = MmuSize;
111 status = gckOS_AllocateContiguous(os,
114 &mmu->pageTablePhysical,
115 &mmu->pageTableLogical);
120 gcmkVERIFY_OK(gckOS_DeleteMutex(os, mmu->mutex));
122 mmu->object.type = gcvOBJ_UNKNOWN;
123 gcmkVERIFY_OK(gckOS_Free(os, mmu));
127 "%s(%d): could not allocate page table.",
128 __FUNCTION__, __LINE__
135 /* Compute number of entries in page table. */
136 mmu->entryCount = mmu->pageTableSize / sizeof(gctUINT32);
139 /* Mark the entire page table as available. */
140 pageTable = (gctUINT32 *) mmu->pageTableLogical;
141 for (i = 0; i < mmu->entryCount; i++)
143 pageTable[i] = (gctUINT32)~0;
146 /* Set page table address. */
147 status = gckVGHARDWARE_SetMMU(hardware, mmu->pageTableLogical);
151 /* Free the page table. */
152 gcmkVERIFY_OK(gckOS_FreeContiguous(mmu->os,
153 mmu->pageTablePhysical,
154 mmu->pageTableLogical,
155 mmu->pageTableSize));
158 gcmkVERIFY_OK(gckOS_DeleteMutex(os, mmu->mutex));
160 mmu->object.type = gcvOBJ_UNKNOWN;
161 gcmkVERIFY_OK(gckOS_Free(os, mmu));
165 "%s(%d): could not program page table.",
166 __FUNCTION__, __LINE__
173 /* Return the gckVGMMU object pointer. */
177 gcvLEVEL_INFO, gcvZONE_MMU,
178 "%s(%d): %u entries at %p.(0x%08X)\n",
179 __FUNCTION__, __LINE__,
181 mmu->pageTableLogical,
182 mmu->pageTablePhysical
190 /*******************************************************************************
194 ** Destroy a nAQMMU object.
199 ** Pointer to an gckVGMMU object.
205 gceSTATUS gckVGMMU_Destroy(
209 gcmkHEADER_ARG("Mmu=0x%x", Mmu);
211 /* Verify the arguments. */
212 gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
214 /* Free the page table. */
215 gcmkVERIFY_OK(gckOS_FreeContiguous(Mmu->os,
216 Mmu->pageTablePhysical,
217 Mmu->pageTableLogical,
218 Mmu->pageTableSize));
221 gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->mutex));
223 /* Mark the gckVGMMU object as unknown. */
224 Mmu->object.type = gcvOBJ_UNKNOWN;
226 /* Free the gckVGMMU object. */
227 gcmkVERIFY_OK(gckOS_Free(Mmu->os, Mmu));
234 /*******************************************************************************
236 ** gckVGMMU_AllocatePages
238 ** Allocate pages inside the page table.
243 ** Pointer to an gckVGMMU object.
245 ** gctSIZE_T PageCount
246 ** Number of pages to allocate.
250 ** gctPOINTER * PageTable
251 ** Pointer to a variable that receives the base address of the page
254 ** gctUINT32 * Address
255 ** Pointer to a variable that receives the hardware specific address.
257 gceSTATUS gckVGMMU_AllocatePages(
259 IN gctSIZE_T PageCount,
260 OUT gctPOINTER * PageTable,
261 OUT gctUINT32 * Address
265 gctUINT32 tail, index, i;
267 gctBOOL allocated = gcvFALSE;
269 gcmkHEADER_ARG("Mmu=0x%x PageCount=0x%x PageTable=0x%x Address=0x%x",
270 Mmu, PageCount, PageTable, Address);
272 /* Verify the arguments. */
273 gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
274 gcmkVERIFY_ARGUMENT(PageCount > 0);
275 gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
276 gcmkVERIFY_ARGUMENT(Address != gcvNULL);
279 gcvLEVEL_INFO, gcvZONE_MMU,
280 "%s(%d): %u pages.\n",
281 __FUNCTION__, __LINE__,
285 if (PageCount > Mmu->entryCount)
288 gcvLEVEL_ERROR, gcvZONE_MMU,
289 "%s(%d): page table too small for %u pages.\n",
290 __FUNCTION__, __LINE__,
295 /* Not enough pages avaiable. */
296 return gcvSTATUS_OUT_OF_RESOURCES;
299 /* Grab the mutex. */
300 status = gckOS_AcquireMutex(Mmu->os, Mmu->mutex, gcvINFINITE);
305 gcvLEVEL_ERROR, gcvZONE_MMU,
306 "%s(%d): could not acquire mutex.\n"
307 ,__FUNCTION__, __LINE__
315 /* Compute the tail for this allocation. */
316 tail = Mmu->entryCount - PageCount;
318 /* Walk all entries until we find enough slots. */
319 for (index = Mmu->entry; index <= tail;)
321 /* Access page table. */
322 table = (gctUINT32 *) Mmu->pageTableLogical + index;
324 /* See if all slots are available. */
325 for (i = 0; i < PageCount; i++, table++)
329 /* Start from next slot. */
337 /* Bail out if we have enough page entries. */
347 /* Walk all entries until we find enough slots. */
348 for (index = 0; index <= tail;)
350 /* Access page table. */
351 table = (gctUINT32 *) Mmu->pageTableLogical + index;
353 /* See if all slots are available. */
354 for (i = 0; i < PageCount; i++, table++)
358 /* Start from next slot. */
366 /* Bail out if we have enough page entries. */
374 if (!allocated && (status >= 0))
377 gcvLEVEL_ERROR, gcvZONE_MMU,
378 "%s(%d): not enough free pages for %u pages.\n",
379 __FUNCTION__, __LINE__,
383 /* Not enough empty slots available. */
384 status = gcvSTATUS_OUT_OF_RESOURCES;
389 /* Build virtual address. */
390 status = gckVGHARDWARE_BuildVirtualAddress(Mmu->hardware,
397 /* Update current entry into page table. */
398 Mmu->entry = index + PageCount;
400 /* Return pointer to page table. */
401 *PageTable = (gctUINT32 *) Mmu->pageTableLogical + index;
404 gcvLEVEL_INFO, gcvZONE_MMU,
405 "%s(%d): allocated %u pages at index %u (0x%08X) @ %p.\n",
406 __FUNCTION__, __LINE__,
415 /* Release the mutex. */
416 gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->mutex));
423 /*******************************************************************************
425 ** gckVGMMU_FreePages
427 ** Free pages inside the page table.
432 ** Pointer to an gckVGMMU object.
434 ** gctPOINTER PageTable
435 ** Base address of the page table to free.
437 ** gctSIZE_T PageCount
438 ** Number of pages to free.
444 gceSTATUS gckVGMMU_FreePages(
446 IN gctPOINTER PageTable,
447 IN gctSIZE_T PageCount
452 gcmkHEADER_ARG("Mmu=0x%x PageTable=0x%x PageCount=0x%x",
453 Mmu, PageTable, PageCount);
455 /* Verify the arguments. */
456 gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
457 gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
458 gcmkVERIFY_ARGUMENT(PageCount > 0);
461 gcvLEVEL_INFO, gcvZONE_MMU,
462 "%s(%d): freeing %u pages at index %u @ %p.\n",
463 __FUNCTION__, __LINE__,
465 ((gctUINT32 *) PageTable - (gctUINT32 *) Mmu->pageTableLogical),
469 /* Convert pointer. */
470 table = (gctUINT32 *) PageTable;
472 /* Mark the page table entries as available. */
473 while (PageCount-- > 0)
475 *table++ = (gctUINT32)~0;
486 IN gctUINT32 PageAddress,
487 IN gctUINT32 *PageEntry
490 gcmkHEADER_ARG("Mmu=0x%x", Mmu);
492 /* Verify the arguments. */
493 gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
494 gcmkVERIFY_ARGUMENT(PageEntry != gcvNULL);
495 gcmkVERIFY_ARGUMENT(!(PageAddress & 0xFFF));
497 *PageEntry = PageAddress;
509 gckVGHARDWARE hardware;
511 gcmkHEADER_ARG("Mmu=0x%x", Mmu);
513 hardware = Mmu->hardware;
515 gckOS_AtomSet(hardware->os, hardware->pageTableDirty, 1));
522 #endif /* gcdENABLE_VG */