/*! * \name PDumpOSCPUVAddrToPhysPages */ IMG_VOID PDumpOSCPUVAddrToPhysPages(IMG_HANDLE hOSMemHandle, IMG_UINT32 ui32Offset, IMG_PUINT8 pui8LinAddr, IMG_UINT32 ui32DataPageMask, IMG_UINT32 *pui32PageOffset) { if(hOSMemHandle) { /* * If a Services memory handle is provided then use it. */ IMG_CPU_PHYADDR sCpuPAddr; PVR_UNREFERENCED_PARAMETER(pui8LinAddr); sCpuPAddr = OSMemHandleToCpuPAddr(hOSMemHandle, ui32Offset); *pui32PageOffset = sCpuPAddr.uiAddr & ui32DataPageMask; } else { PVR_UNREFERENCED_PARAMETER(hOSMemHandle); PVR_UNREFERENCED_PARAMETER(ui32Offset); *pui32PageOffset = ((IMG_UINT32)pui8LinAddr & ui32DataPageMask); } }
IMG_VOID PDumpOSCPUVAddrToDevPAddr(PVRSRV_DEVICE_TYPE eDeviceType, IMG_HANDLE hOSMemHandle, IMG_UINT32 ui32Offset, IMG_UINT8 *pui8LinAddr, IMG_UINT32 ui32PageSize, IMG_DEV_PHYADDR *psDevPAddr) { if(hOSMemHandle) { IMG_CPU_PHYADDR sCpuPAddr; PVR_UNREFERENCED_PARAMETER(pui8LinAddr); sCpuPAddr = OSMemHandleToCpuPAddr(hOSMemHandle, ui32Offset); PVR_ASSERT((sCpuPAddr.uiAddr & (ui32PageSize - 1)) == 0); *psDevPAddr = SysCpuPAddrToDevPAddr(eDeviceType, sCpuPAddr); } else { IMG_CPU_PHYADDR sCpuPAddr; PVR_UNREFERENCED_PARAMETER(ui32Offset); sCpuPAddr = OSMapLinToCPUPhys(pui8LinAddr); *psDevPAddr = SysCpuPAddrToDevPAddr(eDeviceType, sCpuPAddr); } }
void PDumpMallocPages(u32 ui32DevVAddr, void *hOSMemHandle, u32 ui32NumBytes, void *hUniqueTag) { struct IMG_CPU_PHYADDR sCpuPAddr; struct IMG_DEV_PHYADDR sDevPAddr; u32 ui32Offset; PVR_ASSERT(((u32) ui32DevVAddr & ~PAGE_MASK) == 0); PVR_ASSERT(hOSMemHandle); PVR_ASSERT(((u32) ui32NumBytes & ~PAGE_MASK) == 0); PDumpComment("MALLOC :SGXMEM:VA_%8.8X 0x%8.8X %u\r\n", ui32DevVAddr, ui32NumBytes, PAGE_SIZE); for (ui32Offset = 0; ui32Offset < ui32NumBytes; ui32Offset += PAGE_SIZE) { sCpuPAddr = OSMemHandleToCpuPAddr(hOSMemHandle, ui32Offset); sDevPAddr = SysCpuPAddrToDevPAddr(0, sCpuPAddr); pdump_print(PDUMP_FLAGS_CONTINUOUS, "MALLOC :SGXMEM:PA_%8.8X%8.8X %u %u 0x%8.8X\r\n", (u32)hUniqueTag, sDevPAddr.uiAddr, PAGE_SIZE, PAGE_SIZE, sDevPAddr.uiAddr); } }
enum PVRSRV_ERROR PDumpMemPolKM(struct PVRSRV_KERNEL_MEM_INFO *psMemInfo, u32 ui32Offset, u32 ui32Value, u32 ui32Mask, enum PDUMP_POLL_OPERATOR eOperator, IMG_BOOL bLastFrame, IMG_BOOL bOverwrite, void *hUniqueTag) { #define MEMPOLL_DELAY (1000) #define MEMPOLL_COUNT (2000000000 / MEMPOLL_DELAY) u32 ui32PageOffset; struct IMG_DEV_PHYADDR sDevPAddr; struct IMG_DEV_VIRTADDR sDevVPageAddr; struct IMG_CPU_PHYADDR CpuPAddr; u32 ui32Flags; __PDBG_PDUMP_STATE_GET_SCRIPT_AND_FILE_STRING(PVRSRV_ERROR_GENERIC); PVR_ASSERT((ui32Offset + sizeof(u32)) <= psMemInfo->ui32AllocSize); if (gsDBGPdumpState.ui32ParamFileNum == 0) snprintf(pszFile, SZ_FILENAME_SIZE_MAX, "%%0%%.prm"); else snprintf(pszFile, SZ_FILENAME_SIZE_MAX, "%%0%%%lu.prm", gsDBGPdumpState.ui32ParamFileNum); ui32Flags = 0; if (bLastFrame) ui32Flags |= PDUMP_FLAGS_LASTFRAME; if (bOverwrite) ui32Flags |= PDUMP_FLAGS_RESETLFBUFFER; CpuPAddr = OSMemHandleToCpuPAddr(psMemInfo->sMemBlk.hOSMemHandle, ui32Offset); ui32PageOffset = CpuPAddr.uiAddr & (PAGE_SIZE - 1); sDevVPageAddr.uiAddr = psMemInfo->sDevVAddr.uiAddr + ui32Offset - ui32PageOffset; BM_GetPhysPageAddr(psMemInfo, sDevVPageAddr, &sDevPAddr); sDevPAddr.uiAddr += ui32PageOffset; snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, "POL :SGXMEM:PA_%p%8.8lX:0x%8.8lX 0x%8.8lX 0x%8.8lX %d %d %d\r\n", hUniqueTag, sDevPAddr.uiAddr & ~(SGX_MMU_PAGE_SIZE - 1), sDevPAddr.uiAddr & (SGX_MMU_PAGE_SIZE - 1), ui32Value, ui32Mask, eOperator, MEMPOLL_COUNT, MEMPOLL_DELAY); PDumpWriteString2(pszScript, ui32Flags); return PVRSRV_OK; }
void PDumpCBP(struct PVRSRV_KERNEL_MEM_INFO *psROffMemInfo, u32 ui32ROffOffset, u32 ui32WPosVal, u32 ui32PacketSize, u32 ui32BufferSize, u32 ui32Flags, void *hUniqueTag) { u32 ui32PageOffset; struct IMG_DEV_VIRTADDR sDevVAddr; struct IMG_DEV_PHYADDR sDevPAddr; struct IMG_DEV_VIRTADDR sDevVPageAddr; struct IMG_CPU_PHYADDR CpuPAddr; __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(); PVR_ASSERT((ui32ROffOffset + sizeof(u32)) <= psROffMemInfo->ui32AllocSize); sDevVAddr = psROffMemInfo->sDevVAddr; sDevVAddr.uiAddr += ui32ROffOffset; CpuPAddr = OSMemHandleToCpuPAddr(psROffMemInfo->sMemBlk.hOSMemHandle, ui32ROffOffset); ui32PageOffset = CpuPAddr.uiAddr & (PAGE_SIZE - 1); sDevVPageAddr.uiAddr = sDevVAddr.uiAddr - ui32PageOffset; BM_GetPhysPageAddr(psROffMemInfo, sDevVPageAddr, &sDevPAddr); sDevPAddr.uiAddr += ui32PageOffset; snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, "CBP :SGXMEM:PA_%p%8.8lX:0x%8.8lX 0x%8.8lX 0x%8.8lX " "0x%8.8lX\r\n", hUniqueTag, sDevPAddr.uiAddr & ~(SGX_MMU_PAGE_SIZE - 1), sDevPAddr.uiAddr & (SGX_MMU_PAGE_SIZE - 1), ui32WPosVal, ui32PacketSize, ui32BufferSize); PDumpWriteString2(pszScript, ui32Flags); }
void PDumpMallocPages(enum PVRSRV_DEVICE_TYPE eDeviceType, u32 ui32DevVAddr, void *pvLinAddr, void *hOSMemHandle, u32 ui32NumBytes, void *hUniqueTag) { u32 ui32Offset; u32 ui32NumPages; struct IMG_CPU_PHYADDR sCpuPAddr; struct IMG_DEV_PHYADDR sDevPAddr; u32 ui32Page; __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(); PVR_UNREFERENCED_PARAMETER(pvLinAddr); PVR_ASSERT(((u32) ui32DevVAddr & (SGX_MMU_PAGE_SIZE - 1)) == 0); PVR_ASSERT(hOSMemHandle); PVR_ASSERT(((u32) ui32NumBytes & (SGX_MMU_PAGE_SIZE - 1)) == 0); snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, "-- MALLOC :SGXMEM:VA_%8.8lX 0x%8.8lX %lu\r\n", ui32DevVAddr, ui32NumBytes, SGX_MMU_PAGE_SIZE); PDumpWriteString2(pszScript, PDUMP_FLAGS_CONTINUOUS); ui32Offset = 0; ui32NumPages = ui32NumBytes >> SGX_MMU_PAGE_SHIFT; while (ui32NumPages--) { sCpuPAddr = OSMemHandleToCpuPAddr(hOSMemHandle, ui32Offset); PVR_ASSERT((sCpuPAddr.uiAddr & (SGX_MMU_PAGE_SIZE - 1)) == 0); ui32Offset += SGX_MMU_PAGE_SIZE; sDevPAddr = SysCpuPAddrToDevPAddr(eDeviceType, sCpuPAddr); ui32Page = sDevPAddr.uiAddr >> SGX_MMU_PAGE_SHIFT; snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, "MALLOC :SGXMEM:PA_%p%8.8lX %lu %lu 0x%8.8lX\r\n", hUniqueTag, ui32Page * SGX_MMU_PAGE_SIZE, SGX_MMU_PAGE_SIZE, SGX_MMU_PAGE_SIZE, ui32Page * SGX_MMU_PAGE_SIZE); PDumpWriteString2(pszScript, PDUMP_FLAGS_CONTINUOUS); } }
/*! * \name PDumpOSCPUVAddrToDevPAddr */ IMG_VOID PDumpOSCPUVAddrToDevPAddr(PVRSRV_DEVICE_TYPE eDeviceType, IMG_HANDLE hOSMemHandle, IMG_UINT32 ui32Offset, IMG_UINT8 *pui8LinAddr, IMG_UINT32 ui32PageSize, IMG_DEV_PHYADDR *psDevPAddr) { IMG_CPU_PHYADDR sCpuPAddr; PVR_UNREFERENCED_PARAMETER(pui8LinAddr); PVR_UNREFERENCED_PARAMETER(ui32PageSize); /* for when no assert */ /* Caller must now alway supply hOSMemHandle, even though we only (presently) use it here in the linux implementation */ PVR_ASSERT (hOSMemHandle != IMG_NULL); sCpuPAddr = OSMemHandleToCpuPAddr(hOSMemHandle, ui32Offset); PVR_ASSERT((sCpuPAddr.uiAddr & (ui32PageSize - 1)) == 0); /* convert CPU physical addr to device physical */ *psDevPAddr = SysCpuPAddrToDevPAddr(eDeviceType, sCpuPAddr); }
IMG_VOID PDumpOSCPUVAddrToPhysPages(IMG_HANDLE hOSMemHandle, IMG_UINT32 ui32Offset, IMG_PUINT8 pui8LinAddr, IMG_UINT32 *pui32PageOffset) { if(hOSMemHandle) { IMG_CPU_PHYADDR sCpuPAddr; PVR_UNREFERENCED_PARAMETER(pui8LinAddr); sCpuPAddr = OSMemHandleToCpuPAddr(hOSMemHandle, ui32Offset); *pui32PageOffset = sCpuPAddr.uiAddr & (HOST_PAGESIZE() -1); } else { PVR_UNREFERENCED_PARAMETER(hOSMemHandle); PVR_UNREFERENCED_PARAMETER(ui32Offset); *pui32PageOffset = (IMG_UINT32)pui8LinAddr & (HOST_PAGESIZE() - 1); } }
PVRSRV_ERROR PDumpMemKM(void *pvAltLinAddr, PVRSRV_KERNEL_MEM_INFO * psMemInfo, u32 ui32Offset, u32 ui32Bytes, u32 ui32Flags, void *hUniqueTag) { PVRSRV_ERROR eErr; u32 ui32NumPages; u32 ui32PageByteOffset; u32 ui32BlockBytes; u8 *pui8LinAddr; u8 *pui8DataLinAddr = NULL; IMG_DEV_VIRTADDR sDevVPageAddr; IMG_DEV_VIRTADDR sDevVAddr; IMG_DEV_PHYADDR sDevPAddr; u32 ui32ParamOutPos; PDUMP_GET_SCRIPT_AND_FILE_STRING(); PVR_ASSERT((ui32Offset + ui32Bytes) <= psMemInfo->ui32AllocSize); if (!PDumpOSJTInitialised()) { return PVRSRV_ERROR_GENERIC; } if (ui32Bytes == 0 || PDumpOSIsSuspended()) { return PVRSRV_OK; } if (pvAltLinAddr) { pui8DataLinAddr = pvAltLinAddr; } else if (psMemInfo->pvLinAddrKM) { pui8DataLinAddr = (u8 *) psMemInfo->pvLinAddrKM + ui32Offset; } pui8LinAddr = (u8 *) psMemInfo->pvLinAddrKM; sDevVAddr = psMemInfo->sDevVAddr; sDevVAddr.uiAddr += ui32Offset; pui8LinAddr += ui32Offset; PVR_ASSERT(pui8DataLinAddr); PDumpOSCheckForSplitting(PDumpOSGetStream(PDUMP_STREAM_PARAM2), ui32Bytes, ui32Flags); ui32ParamOutPos = PDumpOSGetStreamOffset(PDUMP_STREAM_PARAM2); if (!PDumpOSWriteString(PDumpOSGetStream(PDUMP_STREAM_PARAM2), pui8DataLinAddr, ui32Bytes, ui32Flags)) { return PVRSRV_ERROR_GENERIC; } if (PDumpOSGetParamFileNum() == 0) { eErr = PDumpOSSprintf(pszFileName, ui32MaxLenFileName, "%%0%%.prm"); } else { eErr = PDumpOSSprintf(pszFileName, ui32MaxLenFileName, "%%0%%%lu.prm", PDumpOSGetParamFileNum()); } if (eErr != PVRSRV_OK) { return eErr; } eErr = PDumpOSBufprintf(hScript, ui32MaxLenScript, "-- LDB :SGXMEM:VA_%8.8lX%8.8lX:0x%8.8lX 0x%8.8lX 0x%8.8lX %s\r\n", (u32) hUniqueTag, psMemInfo->sDevVAddr.uiAddr, ui32Offset, ui32Bytes, ui32ParamOutPos, pszFileName); if (eErr != PVRSRV_OK) { return eErr; } PDumpOSWriteString2(hScript, ui32Flags); PDumpOSCPUVAddrToPhysPages(psMemInfo->sMemBlk.hOSMemHandle, ui32Offset, pui8LinAddr, &ui32PageByteOffset); ui32NumPages = (ui32PageByteOffset + ui32Bytes + HOST_PAGESIZE() - 1) / HOST_PAGESIZE(); while (ui32NumPages) { #if 0 u32 ui32BlockBytes = MIN(ui32BytesRemaining, PAGE_SIZE); CpuPAddr = OSMemHandleToCpuPAddr(psMemInfo->sMemBlk.hOSMemHandle, ui32CurrentOffset); #endif ui32NumPages--; sDevVPageAddr.uiAddr = sDevVAddr.uiAddr - ui32PageByteOffset; PVR_ASSERT((sDevVPageAddr.uiAddr & 0xFFF) == 0); BM_GetPhysPageAddr(psMemInfo, sDevVPageAddr, &sDevPAddr); sDevPAddr.uiAddr += ui32PageByteOffset; #if 0 if (ui32PageByteOffset) { ui32BlockBytes = MIN(ui32BytesRemaining, PAGE_ALIGN(CpuPAddr.uiAddr) - CpuPAddr.uiAddr); ui32PageByteOffset = 0; } #endif if (ui32PageByteOffset + ui32Bytes > HOST_PAGESIZE()) { ui32BlockBytes = HOST_PAGESIZE() - ui32PageByteOffset; } else { ui32BlockBytes = ui32Bytes; } eErr = PDumpOSBufprintf(hScript, ui32MaxLenScript, "LDB :SGXMEM:PA_%8.8lX%8.8lX:0x%8.8lX 0x%8.8lX 0x%8.8lX %s\r\n", (u32) hUniqueTag, sDevPAddr.uiAddr & ~(SGX_MMU_PAGE_MASK), sDevPAddr.uiAddr & (SGX_MMU_PAGE_MASK), ui32BlockBytes, ui32ParamOutPos, pszFileName); if (eErr != PVRSRV_OK) { return eErr; } PDumpOSWriteString2(hScript, ui32Flags); ui32PageByteOffset = 0; ui32Bytes -= ui32BlockBytes; sDevVAddr.uiAddr += ui32BlockBytes; pui8LinAddr += ui32BlockBytes; ui32ParamOutPos += ui32BlockBytes; } return PVRSRV_OK; }
struct IMG_CPU_PHYADDR LinuxMemAreaToCpuPAddr( struct LinuxMemArea *psLinuxMemArea, u32 ui32ByteOffset) { struct IMG_CPU_PHYADDR CpuPAddr; CpuPAddr.uiAddr = 0; switch (psLinuxMemArea->eAreaType) { case LINUX_MEM_AREA_IOREMAP: { CpuPAddr = psLinuxMemArea->uData.sIORemap.CPUPhysAddr; CpuPAddr.uiAddr += ui32ByteOffset; break; } case LINUX_MEM_AREA_EXTERNAL_KV: { if (psLinuxMemArea->uData.sExternalKV.bPhysContig) { CpuPAddr = SysSysPAddrToCpuPAddr( psLinuxMemArea->uData. sExternalKV.uPhysAddr. SysPhysAddr); CpuPAddr.uiAddr += ui32ByteOffset; } else { u32 ui32PageIndex = PHYS_TO_PFN(ui32ByteOffset); struct IMG_SYS_PHYADDR SysPAddr = psLinuxMemArea->uData.sExternalKV.uPhysAddr. pSysPhysAddr[ui32PageIndex]; CpuPAddr = SysSysPAddrToCpuPAddr(SysPAddr); CpuPAddr.uiAddr += ADDR_TO_PAGE_OFFSET(ui32ByteOffset); } break; } case LINUX_MEM_AREA_IO: { CpuPAddr = psLinuxMemArea->uData.sIO.CPUPhysAddr; CpuPAddr.uiAddr += ui32ByteOffset; break; } case LINUX_MEM_AREA_VMALLOC: { char *pCpuVAddr; pCpuVAddr = (char *) psLinuxMemArea->uData.sVmalloc. pvVmallocAddress; pCpuVAddr += ui32ByteOffset; CpuPAddr.uiAddr = VMallocToPhys(pCpuVAddr); break; } case LINUX_MEM_AREA_ALLOC_PAGES: { struct page *page; u32 ui32PageIndex = PHYS_TO_PFN(ui32ByteOffset); page = psLinuxMemArea->uData.sPageList. pvPageList[ui32PageIndex]; CpuPAddr.uiAddr = page_to_phys(page); CpuPAddr.uiAddr += ADDR_TO_PAGE_OFFSET(ui32ByteOffset); break; } case LINUX_MEM_AREA_SUB_ALLOC: { CpuPAddr = OSMemHandleToCpuPAddr(psLinuxMemArea->uData. sSubAlloc. psParentLinuxMemArea, psLinuxMemArea->uData. sSubAlloc.ui32ByteOffset + ui32ByteOffset); break; } default: PVR_DPF(PVR_DBG_ERROR, "%s: Unknown struct LinuxMemArea type (%d)\n", __func__, psLinuxMemArea->eAreaType); } PVR_ASSERT(CpuPAddr.uiAddr); return CpuPAddr; }
enum PVRSRV_ERROR PDumpPDDevPAddrKM(struct PVRSRV_KERNEL_MEM_INFO *psMemInfo, u32 ui32Offset, struct IMG_DEV_PHYADDR sPDDevPAddr, void *hUniqueTag1, void *hUniqueTag2) { u32 ui32ParamOutPos; struct IMG_CPU_PHYADDR CpuPAddr; u32 ui32PageByteOffset; struct IMG_DEV_VIRTADDR sDevVAddr; struct IMG_DEV_VIRTADDR sDevVPageAddr; struct IMG_DEV_PHYADDR sDevPAddr; __PDBG_PDUMP_STATE_GET_SCRIPT_AND_FILE_STRING(PVRSRV_ERROR_GENERIC); ui32ParamOutPos = gpfnDbgDrv->pfnGetStreamOffset(gsDBGPdumpState. psStream[PDUMP_STREAM_PARAM2]); if (!PDumpWriteILock(gsDBGPdumpState.psStream[PDUMP_STREAM_PARAM2], (u8 *)&sPDDevPAddr, sizeof(struct IMG_DEV_PHYADDR), PDUMP_FLAGS_CONTINUOUS)) return PVRSRV_ERROR_GENERIC; if (gsDBGPdumpState.ui32ParamFileNum == 0) snprintf(pszFile, SZ_FILENAME_SIZE_MAX, "%%0%%.prm"); else snprintf(pszFile, SZ_FILENAME_SIZE_MAX, "%%0%%%lu.prm", gsDBGPdumpState.ui32ParamFileNum); CpuPAddr = OSMemHandleToCpuPAddr(psMemInfo->sMemBlk.hOSMemHandle, ui32Offset); ui32PageByteOffset = CpuPAddr.uiAddr & (PAGE_SIZE - 1); sDevVAddr = psMemInfo->sDevVAddr; sDevVAddr.uiAddr += ui32Offset; sDevVPageAddr.uiAddr = sDevVAddr.uiAddr - ui32PageByteOffset; BM_GetPhysPageAddr(psMemInfo, sDevVPageAddr, &sDevPAddr); sDevPAddr.uiAddr += ui32PageByteOffset; if ((sPDDevPAddr.uiAddr & SGX_MMU_PDE_ADDR_MASK) != 0) { snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, "WRW :SGXMEM:PA_%p%8.8lX:0x%8.8lX :" "SGXMEM:PA_%p%8.8lX:0x%8.8lX\r\n", hUniqueTag1, sDevPAddr.uiAddr & ~(SGX_MMU_PAGE_SIZE - 1), sDevPAddr.uiAddr & (SGX_MMU_PAGE_SIZE - 1), hUniqueTag2, sPDDevPAddr.uiAddr & SGX_MMU_PDE_ADDR_MASK, sPDDevPAddr.uiAddr & ~SGX_MMU_PDE_ADDR_MASK); } else { PVR_ASSERT(!(sDevPAddr.uiAddr & SGX_MMU_PTE_VALID)); snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, "WRW :SGXMEM:PA_%p%8.8lX:0x%8.8lX 0x%8.8lX\r\n", hUniqueTag1, sDevPAddr.uiAddr & ~(SGX_MMU_PAGE_SIZE - 1), sDevPAddr.uiAddr & (SGX_MMU_PAGE_SIZE - 1), sPDDevPAddr.uiAddr); } PDumpWriteString2(pszScript, PDUMP_FLAGS_CONTINUOUS); return PVRSRV_OK; }
enum PVRSRV_ERROR PDumpMemKM(void *pvAltLinAddr, struct PVRSRV_KERNEL_MEM_INFO *psMemInfo, u32 ui32Offset, u32 ui32Bytes, u32 ui32Flags, void *hUniqueTag) { u32 ui32PageByteOffset; u8 *pui8DataLinAddr; struct IMG_DEV_VIRTADDR sDevVPageAddr; struct IMG_DEV_VIRTADDR sDevVAddr; struct IMG_DEV_PHYADDR sDevPAddr; struct IMG_CPU_PHYADDR CpuPAddr; u32 ui32ParamOutPos; u32 ui32CurrentOffset; u32 ui32BytesRemaining; struct LinuxMemArea *psLinuxMemArea; enum LINUX_MEM_AREA_TYPE eRootAreaType; char *pui8TransientCpuVAddr; __PDBG_PDUMP_STATE_GET_SCRIPT_AND_FILE_STRING(PVRSRV_ERROR_GENERIC); PVR_ASSERT((ui32Offset + ui32Bytes) <= psMemInfo->ui32AllocSize); if (ui32Bytes == 0 || gui32PDumpSuspended) return PVRSRV_OK; if (pvAltLinAddr) { pui8DataLinAddr = pvAltLinAddr; } else if (psMemInfo->pvLinAddrKM) { pui8DataLinAddr = (u8 *) psMemInfo->pvLinAddrKM + ui32Offset; } else { pui8DataLinAddr = 0; psLinuxMemArea = (struct LinuxMemArea *)psMemInfo->sMemBlk.hOSMemHandle; eRootAreaType = LinuxMemAreaRootType(psLinuxMemArea); } ui32ParamOutPos = gpfnDbgDrv->pfnGetStreamOffset(gsDBGPdumpState. psStream[PDUMP_STREAM_PARAM2]); if (pui8DataLinAddr) { if (!PDumpWriteILock (gsDBGPdumpState.psStream[PDUMP_STREAM_PARAM2], pui8DataLinAddr, ui32Bytes, ui32Flags)) return PVRSRV_ERROR_GENERIC; } else if (eRootAreaType == LINUX_MEM_AREA_IO) { CpuPAddr = OSMemHandleToCpuPAddr(psMemInfo->sMemBlk.hOSMemHandle, ui32Offset); pui8TransientCpuVAddr = IORemapWrapper(CpuPAddr, ui32Bytes, PVRSRV_HAP_CACHED); if (!PDumpWriteILock (gsDBGPdumpState.psStream[PDUMP_STREAM_PARAM2], pui8TransientCpuVAddr, ui32Bytes, ui32Flags)) { IOUnmapWrapper(pui8TransientCpuVAddr); return PVRSRV_ERROR_GENERIC; } IOUnmapWrapper(pui8TransientCpuVAddr); } else { PVR_ASSERT(eRootAreaType == LINUX_MEM_AREA_ALLOC_PAGES); ui32BytesRemaining = ui32Bytes; ui32CurrentOffset = ui32Offset; while (ui32BytesRemaining > 0) { u32 ui32BlockBytes = MIN(ui32BytesRemaining, PAGE_SIZE); struct page *psCurrentPage = NULL; CpuPAddr = OSMemHandleToCpuPAddr(psMemInfo->sMemBlk. hOSMemHandle, ui32CurrentOffset); if (CpuPAddr.uiAddr & (PAGE_SIZE - 1)) ui32BlockBytes = MIN(ui32BytesRemaining, PAGE_ALIGN(CpuPAddr.uiAddr) - CpuPAddr.uiAddr); psCurrentPage = LinuxMemAreaOffsetToPage(psLinuxMemArea, ui32CurrentOffset); pui8TransientCpuVAddr = KMapWrapper(psCurrentPage); pui8TransientCpuVAddr += (CpuPAddr.uiAddr & ~PAGE_MASK); if (!pui8TransientCpuVAddr) return PVRSRV_ERROR_GENERIC; if (!PDumpWriteILock (gsDBGPdumpState.psStream[PDUMP_STREAM_PARAM2], pui8TransientCpuVAddr, ui32BlockBytes, ui32Flags)) { KUnMapWrapper(psCurrentPage); return PVRSRV_ERROR_GENERIC; } KUnMapWrapper(psCurrentPage); ui32BytesRemaining -= ui32BlockBytes; ui32CurrentOffset += ui32BlockBytes; } PVR_ASSERT(ui32BytesRemaining == 0); } if (gsDBGPdumpState.ui32ParamFileNum == 0) snprintf(pszFile, SZ_FILENAME_SIZE_MAX, "%%0%%.prm"); else snprintf(pszFile, SZ_FILENAME_SIZE_MAX, "%%0%%%lu.prm", gsDBGPdumpState.ui32ParamFileNum); snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, "-- LDB :SGXMEM:VA_%8.8lX:0x%8.8lX 0x%8.8lX 0x%8.8lX %s\r\n", psMemInfo->sDevVAddr.uiAddr, ui32Offset, ui32Bytes, ui32ParamOutPos, pszFile); PDumpWriteString2(pszScript, ui32Flags); CpuPAddr = OSMemHandleToCpuPAddr(psMemInfo->sMemBlk.hOSMemHandle, ui32Offset); ui32PageByteOffset = CpuPAddr.uiAddr & (PAGE_SIZE - 1); sDevVAddr = psMemInfo->sDevVAddr; sDevVAddr.uiAddr += ui32Offset; ui32BytesRemaining = ui32Bytes; ui32CurrentOffset = ui32Offset; while (ui32BytesRemaining > 0) { u32 ui32BlockBytes = MIN(ui32BytesRemaining, PAGE_SIZE); CpuPAddr = OSMemHandleToCpuPAddr(psMemInfo->sMemBlk.hOSMemHandle, ui32CurrentOffset); sDevVPageAddr.uiAddr = psMemInfo->sDevVAddr.uiAddr + ui32CurrentOffset - ui32PageByteOffset; BM_GetPhysPageAddr(psMemInfo, sDevVPageAddr, &sDevPAddr); sDevPAddr.uiAddr += ui32PageByteOffset; if (ui32PageByteOffset) { ui32BlockBytes = MIN(ui32BytesRemaining, PAGE_ALIGN(CpuPAddr.uiAddr) - CpuPAddr.uiAddr); ui32PageByteOffset = 0; } snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, "LDB :SGXMEM:PA_%p%8.8lX:0x%8.8lX 0x%8.8lX " "0x%8.8lX %s\r\n", hUniqueTag, sDevPAddr.uiAddr & ~(SGX_MMU_PAGE_SIZE - 1), sDevPAddr.uiAddr & (SGX_MMU_PAGE_SIZE - 1), ui32BlockBytes, ui32ParamOutPos, pszFile); PDumpWriteString2(pszScript, ui32Flags); ui32BytesRemaining -= ui32BlockBytes; ui32CurrentOffset += ui32BlockBytes; ui32ParamOutPos += ui32BlockBytes; } PVR_ASSERT(ui32BytesRemaining == 0); return PVRSRV_OK; }
static IMG_BOOL ZeroBuf(BM_BUF *pBuf, BM_MAPPING *pMapping, IMG_SIZE_T ui32Bytes, IMG_UINT32 ui32Flags) { IMG_VOID *pvCpuVAddr; if(pBuf->CpuVAddr) { OSMemSet(pBuf->CpuVAddr, 0, ui32Bytes); } else if(pMapping->eCpuMemoryOrigin == hm_contiguous || pMapping->eCpuMemoryOrigin == hm_wrapped) { pvCpuVAddr = OSMapPhysToLin(pBuf->CpuPAddr, ui32Bytes, PVRSRV_HAP_KERNEL_ONLY | (ui32Flags & PVRSRV_HAP_CACHETYPE_MASK), IMG_NULL); if(!pvCpuVAddr) { PVR_DPF((PVR_DBG_ERROR, "ZeroBuf: OSMapPhysToLin for contiguous buffer failed")); return IMG_FALSE; } OSMemSet(pvCpuVAddr, 0, ui32Bytes); OSUnMapPhysToLin(pvCpuVAddr, ui32Bytes, PVRSRV_HAP_KERNEL_ONLY | (ui32Flags & PVRSRV_HAP_CACHETYPE_MASK), IMG_NULL); } else { IMG_SIZE_T ui32BytesRemaining = ui32Bytes; IMG_SIZE_T ui32CurrentOffset = 0; IMG_CPU_PHYADDR CpuPAddr; PVR_ASSERT(pBuf->hOSMemHandle); while(ui32BytesRemaining > 0) { IMG_SIZE_T ui32BlockBytes = MIN(ui32BytesRemaining, HOST_PAGESIZE()); CpuPAddr = OSMemHandleToCpuPAddr(pBuf->hOSMemHandle, ui32CurrentOffset); if(CpuPAddr.uiAddr & (HOST_PAGESIZE() -1)) { ui32BlockBytes = MIN(ui32BytesRemaining, (IMG_UINT32)(HOST_PAGEALIGN(CpuPAddr.uiAddr) - CpuPAddr.uiAddr)); } pvCpuVAddr = OSMapPhysToLin(CpuPAddr, ui32BlockBytes, PVRSRV_HAP_KERNEL_ONLY | (ui32Flags & PVRSRV_HAP_CACHETYPE_MASK), IMG_NULL); if(!pvCpuVAddr) { PVR_DPF((PVR_DBG_ERROR, "ZeroBuf: OSMapPhysToLin while zeroing non-contiguous memory FAILED")); return IMG_FALSE; } OSMemSet(pvCpuVAddr, 0, ui32BlockBytes); OSUnMapPhysToLin(pvCpuVAddr, ui32BlockBytes, PVRSRV_HAP_KERNEL_ONLY | (ui32Flags & PVRSRV_HAP_CACHETYPE_MASK), IMG_NULL); ui32BytesRemaining -= ui32BlockBytes; ui32CurrentOffset += ui32BlockBytes; } } return IMG_TRUE; }
enum PVRSRV_ERROR MMU_Initialise(struct PVRSRV_DEVICE_NODE *psDeviceNode, struct MMU_CONTEXT **ppsMMUContext, struct IMG_DEV_PHYADDR *psPDDevPAddr) { u32 *pui32Tmp; u32 i; void *pvPDCpuVAddr; struct IMG_DEV_PHYADDR sPDDevPAddr; struct IMG_CPU_PHYADDR sCpuPAddr; struct IMG_SYS_PHYADDR sSysPAddr; struct MMU_CONTEXT *psMMUContext; void *hPDOSMemHandle; struct SYS_DATA *psSysData; struct PVRSRV_SGXDEV_INFO *psDevInfo; PVR_DPF(PVR_DBG_MESSAGE, "MMU_Initialise"); if (SysAcquireData(&psSysData) != PVRSRV_OK) { PVR_DPF(PVR_DBG_ERROR, "MMU_Initialise: ERROR call to SysAcquireData failed"); return PVRSRV_ERROR_GENERIC; } if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct MMU_CONTEXT), (void **) &psMMUContext, NULL) != PVRSRV_OK) { PVR_DPF(PVR_DBG_ERROR, "MMU_Initialise: ERROR call to OSAllocMem failed"); return PVRSRV_ERROR_GENERIC; } OSMemSet(psMMUContext, 0, sizeof(struct MMU_CONTEXT)); psDevInfo = (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; psMMUContext->psDevInfo = psDevInfo; psMMUContext->psDeviceNode = psDeviceNode; if (psDeviceNode->psLocalDevMemArena == NULL) { if (OSAllocPages (PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, SGX_MMU_PAGE_SIZE, SGX_MMU_PAGE_SIZE, &pvPDCpuVAddr, &hPDOSMemHandle) != PVRSRV_OK) { PVR_DPF(PVR_DBG_ERROR, "MMU_Initialise: " "ERROR call to OSAllocPages failed"); goto err1; } if (pvPDCpuVAddr) sCpuPAddr = OSMapLinToCPUPhys(pvPDCpuVAddr); else sCpuPAddr = OSMemHandleToCpuPAddr(hPDOSMemHandle, 0); sPDDevPAddr = SysCpuPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, sCpuPAddr); } else { if (RA_Alloc(psDeviceNode->psLocalDevMemArena, SGX_MMU_PAGE_SIZE, NULL, 0, SGX_MMU_PAGE_SIZE, &(sSysPAddr.uiAddr)) != IMG_TRUE) { PVR_DPF(PVR_DBG_ERROR, "MMU_Initialise: " "ERROR call to RA_Alloc failed"); goto err1; } sCpuPAddr = SysSysPAddrToCpuPAddr(sSysPAddr); sPDDevPAddr = SysSysPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, sSysPAddr); pvPDCpuVAddr = (void __force *) OSMapPhysToLin(sCpuPAddr, SGX_MMU_PAGE_SIZE, PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, &hPDOSMemHandle); if (!pvPDCpuVAddr) { PVR_DPF(PVR_DBG_ERROR, "MMU_Initialise: " "ERROR failed to map page tables"); goto err2; } } PDUMPCOMMENT("Alloc page directory"); PDUMPMALLOCPAGETABLE(pvPDCpuVAddr, PDUMP_PD_UNIQUETAG); if (pvPDCpuVAddr) { pui32Tmp = (u32 *) pvPDCpuVAddr; } else { PVR_DPF(PVR_DBG_ERROR, "MMU_Initialise: pvPDCpuVAddr invalid"); goto err3; } for (i = 0; i < SGX_MMU_PD_SIZE; i++) pui32Tmp[i] = 0; PDUMPCOMMENT("Page directory contents"); PDUMPPAGETABLE(pvPDCpuVAddr, SGX_MMU_PAGE_SIZE, IMG_TRUE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); psMMUContext->pvPDCpuVAddr = pvPDCpuVAddr; psMMUContext->sPDDevPAddr = sPDDevPAddr; psMMUContext->hPDOSMemHandle = hPDOSMemHandle; *ppsMMUContext = psMMUContext; *psPDDevPAddr = sPDDevPAddr; psMMUContext->psNext = (struct MMU_CONTEXT *) psDevInfo->pvMMUContextList; psDevInfo->pvMMUContextList = (void *) psMMUContext; return PVRSRV_OK; err3: if (psDeviceNode->psLocalDevMemArena) OSUnMapPhysToLin((void __iomem __force *)pvPDCpuVAddr, SGX_MMU_PAGE_SIZE, PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, hPDOSMemHandle); err2: if (!psDeviceNode->psLocalDevMemArena) OSFreePages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, SGX_MMU_PAGE_SIZE, pvPDCpuVAddr, hPDOSMemHandle); else RA_Free(psDeviceNode->psLocalDevMemArena, sSysPAddr.uiAddr, IMG_FALSE); err1: OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct MMU_CONTEXT), psMMUContext, NULL); return PVRSRV_ERROR_GENERIC; }
static IMG_BOOL _DeferredAllocPagetables(struct MMU_HEAP *pMMUHeap, struct IMG_DEV_VIRTADDR DevVAddr, u32 ui32Size) { u32 ui32PTPageCount; u32 ui32PDIndex; u32 i; u32 *pui32PDEntry; struct MMU_PT_INFO **ppsPTInfoList; struct SYS_DATA *psSysData; struct IMG_DEV_VIRTADDR sHighDevVAddr; PVR_ASSERT(DevVAddr.uiAddr < (1 << SGX_FEATURE_ADDRESS_SPACE_SIZE)); if (SysAcquireData(&psSysData) != PVRSRV_OK) return IMG_FALSE; ui32PDIndex = DevVAddr.uiAddr >> (SGX_MMU_PAGE_SHIFT + SGX_MMU_PT_SHIFT); if ((UINT32_MAX_VALUE - DevVAddr.uiAddr) < (ui32Size + (1 << (SGX_MMU_PAGE_SHIFT + SGX_MMU_PT_SHIFT)) - 1)) { sHighDevVAddr.uiAddr = UINT32_MAX_VALUE; } else { sHighDevVAddr.uiAddr = DevVAddr.uiAddr + ui32Size + (1 << (SGX_MMU_PAGE_SHIFT + SGX_MMU_PT_SHIFT)) - 1; } ui32PTPageCount = sHighDevVAddr.uiAddr >> (SGX_MMU_PAGE_SHIFT + SGX_MMU_PT_SHIFT); ui32PTPageCount -= ui32PDIndex; pui32PDEntry = (u32 *) pMMUHeap->psMMUContext->pvPDCpuVAddr; pui32PDEntry += ui32PDIndex; ppsPTInfoList = &pMMUHeap->psMMUContext->apsPTInfoList[ui32PDIndex]; PDUMPCOMMENT("Alloc page table (page count == %08X)", ui32PTPageCount); PDUMPCOMMENT("Page directory mods (page count == %08X)", ui32PTPageCount); for (i = 0; i < ui32PTPageCount; i++) { if (ppsPTInfoList[i] == NULL) { if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct MMU_PT_INFO), (void **) &ppsPTInfoList[i], NULL) != PVRSRV_OK) { PVR_DPF(PVR_DBG_ERROR, "_DeferredAllocPagetables: " "ERROR call to OSAllocMem failed"); return IMG_FALSE; } OSMemSet(ppsPTInfoList[i], 0, sizeof(struct MMU_PT_INFO)); } if (ppsPTInfoList[i]->hPTPageOSMemHandle == NULL && ppsPTInfoList[i]->PTPageCpuVAddr == NULL) { struct IMG_CPU_PHYADDR sCpuPAddr; struct IMG_DEV_PHYADDR sDevPAddr; PVR_ASSERT(pui32PDEntry[i] == 0); if (pMMUHeap->psDevArena->psDeviceMemoryHeapInfo-> psLocalDevMemArena == NULL) { if (OSAllocPages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, SGX_MMU_PAGE_SIZE, SGX_MMU_PAGE_SIZE, (void **)&ppsPTInfoList[i]-> PTPageCpuVAddr, &ppsPTInfoList[i]-> hPTPageOSMemHandle) != PVRSRV_OK) { PVR_DPF(PVR_DBG_ERROR, "_DeferredAllocPagetables: " "ERROR call to OSAllocPages failed"); return IMG_FALSE; } if (ppsPTInfoList[i]->PTPageCpuVAddr) { sCpuPAddr = OSMapLinToCPUPhys(ppsPTInfoList[i]-> PTPageCpuVAddr); } else { sCpuPAddr = OSMemHandleToCpuPAddr( ppsPTInfoList[i]-> hPTPageOSMemHandle, 0); } sDevPAddr = SysCpuPAddrToDevPAddr (PVRSRV_DEVICE_TYPE_SGX, sCpuPAddr); } else { struct IMG_SYS_PHYADDR sSysPAddr; if (RA_Alloc(pMMUHeap->psDevArena-> psDeviceMemoryHeapInfo->psLocalDevMemArena, SGX_MMU_PAGE_SIZE, NULL, 0, SGX_MMU_PAGE_SIZE, &(sSysPAddr.uiAddr)) != IMG_TRUE) { PVR_DPF(PVR_DBG_ERROR, "_DeferredAllocPagetables: " "ERROR call to RA_Alloc failed"); return IMG_FALSE; } sCpuPAddr = SysSysPAddrToCpuPAddr(sSysPAddr); ppsPTInfoList[i]->PTPageCpuVAddr = (void __force *) OSMapPhysToLin(sCpuPAddr, SGX_MMU_PAGE_SIZE, PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, &ppsPTInfoList[i]-> hPTPageOSMemHandle); if (!ppsPTInfoList[i]->PTPageCpuVAddr) { PVR_DPF(PVR_DBG_ERROR, "_DeferredAllocPagetables: " "ERROR failed to map page tables"); return IMG_FALSE; } sDevPAddr = SysCpuPAddrToDevPAddr (PVRSRV_DEVICE_TYPE_SGX, sCpuPAddr); } OSMemSet(ppsPTInfoList[i]->PTPageCpuVAddr, 0, SGX_MMU_PAGE_SIZE); PDUMPMALLOCPAGETABLE(ppsPTInfoList[i]->PTPageCpuVAddr, PDUMP_PT_UNIQUETAG); PDUMPPAGETABLE(ppsPTInfoList[i]->PTPageCpuVAddr, SGX_MMU_PAGE_SIZE, IMG_TRUE, PDUMP_PT_UNIQUETAG, PDUMP_PT_UNIQUETAG); switch (pMMUHeap->psDevArena->DevMemHeapType) { case DEVICE_MEMORY_HEAP_SHARED: case DEVICE_MEMORY_HEAP_SHARED_EXPORTED: { struct MMU_CONTEXT *psMMUContext = (struct MMU_CONTEXT *)pMMUHeap-> psMMUContext->psDevInfo-> pvMMUContextList; while (psMMUContext) { pui32PDEntry = (u32 *)psMMUContext-> pvPDCpuVAddr; pui32PDEntry += ui32PDIndex; pui32PDEntry[i] = sDevPAddr.uiAddr | SGX_MMU_PDE_VALID; PDUMPPAGETABLE ((void *)&pui32PDEntry[i], sizeof(u32), IMG_FALSE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); psMMUContext = psMMUContext->psNext; } break; } case DEVICE_MEMORY_HEAP_PERCONTEXT: case DEVICE_MEMORY_HEAP_KERNEL: { pui32PDEntry[i] = sDevPAddr.uiAddr | SGX_MMU_PDE_VALID; PDUMPPAGETABLE((void *)&pui32PDEntry[i], sizeof(u32), IMG_FALSE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); break; } default: { PVR_DPF(PVR_DBG_ERROR, "_DeferredAllocPagetables: " "ERROR invalid heap type"); return IMG_FALSE; } } MMU_InvalidateDirectoryCache(pMMUHeap->psMMUContext-> psDevInfo); } else { PVR_ASSERT(pui32PDEntry[i] != 0); } } return IMG_TRUE; }
static IMG_BOOL ZeroBuf(struct BM_BUF *pBuf, struct BM_MAPPING *pMapping, u32 ui32Bytes, u32 ui32Flags) { void *pvCpuVAddr; if (pBuf->CpuVAddr) { OSMemSet(pBuf->CpuVAddr, 0, ui32Bytes); } else if (pMapping->eCpuMemoryOrigin == hm_contiguous || pMapping->eCpuMemoryOrigin == hm_wrapped) { pvCpuVAddr = (void __force *)OSMapPhysToLin(pBuf->CpuPAddr, ui32Bytes, PVRSRV_HAP_KERNEL_ONLY | (ui32Flags & PVRSRV_HAP_CACHETYPE_MASK), NULL); if (!pvCpuVAddr) { PVR_DPF(PVR_DBG_ERROR, "ZeroBuf: " "OSMapPhysToLin for contiguous buffer failed"); return IMG_FALSE; } OSMemSet(pvCpuVAddr, 0, ui32Bytes); OSUnMapPhysToLin((void __force __iomem *)pvCpuVAddr, ui32Bytes, PVRSRV_HAP_KERNEL_ONLY | (ui32Flags & PVRSRV_HAP_CACHETYPE_MASK), NULL); } else { u32 ui32BytesRemaining = ui32Bytes; u32 ui32CurrentOffset = 0; struct IMG_CPU_PHYADDR CpuPAddr; PVR_ASSERT(pBuf->hOSMemHandle); while (ui32BytesRemaining > 0) { u32 ui32BlockBytes = MIN(ui32BytesRemaining, HOST_PAGESIZE()); CpuPAddr = OSMemHandleToCpuPAddr(pBuf->hOSMemHandle, ui32CurrentOffset); if (CpuPAddr.uiAddr & (HOST_PAGESIZE() - 1)) ui32BlockBytes = MIN(ui32BytesRemaining, HOST_PAGEALIGN(CpuPAddr.uiAddr) - CpuPAddr.uiAddr); pvCpuVAddr = (void __force *)OSMapPhysToLin(CpuPAddr, ui32BlockBytes, PVRSRV_HAP_KERNEL_ONLY | (ui32Flags & PVRSRV_HAP_CACHETYPE_MASK), NULL); if (!pvCpuVAddr) { PVR_DPF(PVR_DBG_ERROR, "ZeroBuf: " "OSMapPhysToLin while " "zeroing non-contiguous memory FAILED"); return IMG_FALSE; } OSMemSet(pvCpuVAddr, 0, ui32BlockBytes); OSUnMapPhysToLin((void __force __iomem *)pvCpuVAddr, ui32BlockBytes, PVRSRV_HAP_KERNEL_ONLY | (ui32Flags & PVRSRV_HAP_CACHETYPE_MASK), NULL); ui32BytesRemaining -= ui32BlockBytes; ui32CurrentOffset += ui32BlockBytes; } } return IMG_TRUE; }