1 /****************************************************************************
3 * Copyright (C) 2005 - 2011 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 *****************************************************************************/
24 #include "gc_hal_kernel_precomp.h"
28 #define _GC_OBJ_ZONE gcvZONE_MMU
30 /*******************************************************************************
34 ** Construct a new gckVGMMU object.
39 ** Pointer to an gckVGKERNEL object.
42 ** Number of bytes for the page table.
47 ** Pointer to a variable that receives the gckVGMMU object pointer.
49 gceSTATUS
gckVGMMU_Construct(
50 IN gckVGKERNEL Kernel
,
56 gckVGHARDWARE hardware
;
59 gctUINT32
* pageTable
;
62 gcmkHEADER_ARG("Kernel=0x%x MmuSize=0x%x Mmu=0x%x", Kernel
, MmuSize
, Mmu
);
64 /* Verify the arguments. */
65 gcmkVERIFY_OBJECT(Kernel
, gcvOBJ_KERNEL
);
66 gcmkVERIFY_ARGUMENT(MmuSize
> 0);
67 gcmkVERIFY_ARGUMENT(Mmu
!= gcvNULL
);
69 /* Extract the gckOS object pointer. */
71 gcmkVERIFY_OBJECT(os
, gcvOBJ_OS
);
73 /* Extract the gckVGHARDWARE object pointer. */
74 hardware
= Kernel
->hardware
;
75 gcmkVERIFY_OBJECT(hardware
, gcvOBJ_HARDWARE
);
77 /* Allocate memory for the gckVGMMU object. */
78 status
= gckOS_Allocate(os
, sizeof(struct _gckVGMMU
), (gctPOINTER
*) &mmu
);
84 "%s(%d): could not allocate gckVGMMU object.",
85 __FUNCTION__
, __LINE__
91 /* Initialize the gckVGMMU object. */
92 mmu
->object
.type
= gcvOBJ_MMU
;
94 mmu
->hardware
= hardware
;
96 /* Create the mutex. */
97 status
= gckOS_CreateMutex(os
, &mmu
->mutex
);
102 mmu
->object
.type
= gcvOBJ_UNKNOWN
;
103 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__
134 /* Compute number of entries in page table. */
135 mmu
->entryCount
= mmu
->pageTableSize
/ sizeof(gctUINT32
);
138 /* Mark the entire page table as available. */
139 pageTable
= (gctUINT32
*) mmu
->pageTableLogical
;
140 for (i
= 0; i
< mmu
->entryCount
; i
++)
142 pageTable
[i
] = (gctUINT32
)~0;
145 /* Set page table address. */
146 status
= gckVGHARDWARE_SetMMU(hardware
, mmu
->pageTableLogical
);
150 /* Free the page table. */
151 gcmkVERIFY_OK(gckOS_FreeContiguous(mmu
->os
,
152 mmu
->pageTablePhysical
,
153 mmu
->pageTableLogical
,
154 mmu
->pageTableSize
));
157 gcmkVERIFY_OK(gckOS_DeleteMutex(os
, mmu
->mutex
));
159 mmu
->object
.type
= gcvOBJ_UNKNOWN
;
160 gcmkVERIFY_OK(gckOS_Free(os
, mmu
));
164 "%s(%d): could not program page table.",
165 __FUNCTION__
, __LINE__
171 /* Return the gckVGMMU object pointer. */
175 gcvLEVEL_INFO
, gcvZONE_MMU
,
176 "%s(%d): %u entries at %p.(0x%08X)\n",
177 __FUNCTION__
, __LINE__
,
179 mmu
->pageTableLogical
,
180 mmu
->pageTablePhysical
188 /*******************************************************************************
192 ** Destroy a nAQMMU object.
197 ** Pointer to an gckVGMMU object.
203 gceSTATUS
gckVGMMU_Destroy(
207 gcmkHEADER_ARG("Mmu=0x%x", Mmu
);
209 /* Verify the arguments. */
210 gcmkVERIFY_OBJECT(Mmu
, gcvOBJ_MMU
);
212 /* Free the page table. */
213 gcmkVERIFY_OK(gckOS_FreeContiguous(Mmu
->os
,
214 Mmu
->pageTablePhysical
,
215 Mmu
->pageTableLogical
,
216 Mmu
->pageTableSize
));
219 gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu
->os
, Mmu
->mutex
));
221 /* Mark the gckVGMMU object as unknown. */
222 Mmu
->object
.type
= gcvOBJ_UNKNOWN
;
224 /* Free the gckVGMMU object. */
225 gcmkVERIFY_OK(gckOS_Free(Mmu
->os
, Mmu
));
232 /*******************************************************************************
234 ** gckVGMMU_AllocatePages
236 ** Allocate pages inside the page table.
241 ** Pointer to an gckVGMMU object.
243 ** gctSIZE_T PageCount
244 ** Number of pages to allocate.
248 ** gctPOINTER * PageTable
249 ** Pointer to a variable that receives the base address of the page
252 ** gctUINT32 * Address
253 ** Pointer to a variable that receives the hardware specific address.
255 gceSTATUS
gckVGMMU_AllocatePages(
257 IN gctSIZE_T PageCount
,
258 OUT gctPOINTER
* PageTable
,
259 OUT gctUINT32
* Address
263 gctUINT32 tail
, index
, i
;
265 gctBOOL allocated
= gcvFALSE
;
267 gcmkHEADER_ARG("Mmu=0x%x PageCount=0x%x PageTable=0x%x Address=0x%x",
268 Mmu
, PageCount
, PageTable
, Address
);
270 /* Verify the arguments. */
271 gcmkVERIFY_OBJECT(Mmu
, gcvOBJ_MMU
);
272 gcmkVERIFY_ARGUMENT(PageCount
> 0);
273 gcmkVERIFY_ARGUMENT(PageTable
!= gcvNULL
);
274 gcmkVERIFY_ARGUMENT(Address
!= gcvNULL
);
277 gcvLEVEL_INFO
, gcvZONE_MMU
,
278 "%s(%d): %u pages.\n",
279 __FUNCTION__
, __LINE__
,
283 if (PageCount
> Mmu
->entryCount
)
286 gcvLEVEL_ERROR
, gcvZONE_MMU
,
287 "%s(%d): page table too small for %u pages.\n",
288 __FUNCTION__
, __LINE__
,
292 /* Not enough pages avaiable. */
293 return gcvSTATUS_OUT_OF_RESOURCES
;
296 /* Grab the mutex. */
297 status
= gckOS_AcquireMutex(Mmu
->os
, Mmu
->mutex
, gcvINFINITE
);
302 gcvLEVEL_ERROR
, gcvZONE_MMU
,
303 "%s(%d): could not acquire mutex.\n"
304 ,__FUNCTION__
, __LINE__
311 /* Compute the tail for this allocation. */
312 tail
= Mmu
->entryCount
- PageCount
;
314 /* Walk all entries until we find enough slots. */
315 for (index
= Mmu
->entry
; index
<= tail
;)
317 /* Access page table. */
318 table
= (gctUINT32
*) Mmu
->pageTableLogical
+ index
;
320 /* See if all slots are available. */
321 for (i
= 0; i
< PageCount
; i
++, table
++)
325 /* Start from next slot. */
333 /* Bail out if we have enough page entries. */
342 status
= gckVGHARDWARE_FlushMMU(Mmu
->hardware
);
346 /* Walk all entries until we find enough slots. */
347 for (index
= 0; index
<= tail
;)
349 /* Access page table. */
350 table
= (gctUINT32
*) Mmu
->pageTableLogical
+ index
;
352 /* See if all slots are available. */
353 for (i
= 0; i
< PageCount
; i
++, table
++)
357 /* Start from next slot. */
365 /* Bail out if we have enough page entries. */
373 if (!allocated
&& (status
>= 0))
376 gcvLEVEL_ERROR
, gcvZONE_MMU
,
377 "%s(%d): not enough free pages for %u pages.\n",
378 __FUNCTION__
, __LINE__
,
382 /* Not enough empty slots available. */
383 status
= gcvSTATUS_OUT_OF_RESOURCES
;
388 /* Build virtual address. */
389 status
= gckVGHARDWARE_BuildVirtualAddress(Mmu
->hardware
,
396 /* Update current entry into page table. */
397 Mmu
->entry
= index
+ PageCount
;
399 /* Return pointer to page table. */
400 *PageTable
= (gctUINT32
*) Mmu
->pageTableLogical
+ index
;
403 gcvLEVEL_INFO
, gcvZONE_MMU
,
404 "%s(%d): allocated %u pages at index %u (0x%08X) @ %p.\n",
405 __FUNCTION__
, __LINE__
,
414 /* Release the mutex. */
415 gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu
->os
, Mmu
->mutex
));
422 /*******************************************************************************
424 ** gckVGMMU_FreePages
426 ** Free pages inside the page table.
431 ** Pointer to an gckVGMMU object.
433 ** gctPOINTER PageTable
434 ** Base address of the page table to free.
436 ** gctSIZE_T PageCount
437 ** Number of pages to free.
443 gceSTATUS
gckVGMMU_FreePages(
445 IN gctPOINTER PageTable
,
446 IN gctSIZE_T PageCount
451 gcmkHEADER_ARG("Mmu=0x%x PageTable=0x%x PageCount=0x%x",
452 Mmu
, PageTable
, PageCount
);
454 /* Verify the arguments. */
455 gcmkVERIFY_OBJECT(Mmu
, gcvOBJ_MMU
);
456 gcmkVERIFY_ARGUMENT(PageTable
!= gcvNULL
);
457 gcmkVERIFY_ARGUMENT(PageCount
> 0);
460 gcvLEVEL_INFO
, gcvZONE_MMU
,
461 "%s(%d): freeing %u pages at index %u @ %p.\n",
462 __FUNCTION__
, __LINE__
,
464 ((gctUINT32
*) PageTable
- (gctUINT32
*) Mmu
->pageTableLogical
),
468 /* Convert pointer. */
469 table
= (gctUINT32
*) PageTable
;
471 /* Mark the page table entries as available. */
472 while (PageCount
-- > 0)
474 *table
++ = (gctUINT32
)~0;
485 IN gctUINT32 PageAddress
,
486 IN gctUINT32
*PageEntry
489 gcmkHEADER_ARG("Mmu=0x%x", Mmu
);
491 /* Verify the arguments. */
492 gcmkVERIFY_OBJECT(Mmu
, gcvOBJ_MMU
);
493 gcmkVERIFY_ARGUMENT(PageEntry
!= gcvNULL
);
494 gcmkVERIFY_ARGUMENT(!(PageAddress
& 0xFFF));
496 *PageEntry
= PageAddress
;
503 #endif /* gcdENABLE_VG */