| /*************************************************************************/ /*! |
| @File |
| @Title Environment related functions |
| @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved |
| @License MIT |
| |
| The contents of this file are subject to the MIT license as set out below. |
| |
| Permission is hereby granted, free of charge, to any person obtaining a copy |
| of this software and associated documentation files (the "Software"), to deal |
| in the Software without restriction, including without limitation the rights |
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| copies of the Software, and to permit persons to whom the Software is |
| furnished to do so, subject to the following conditions: |
| |
| The above copyright notice and this permission notice shall be included in |
| all copies or substantial portions of the Software. |
| |
| This License is also included in this distribution in the file called |
| "MIT-COPYING". |
| |
| EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS |
| PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING |
| BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
| PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR |
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ /**************************************************************************/ |
| |
| #include <condition_variable> |
| #include <mutex> |
| #include <shared_mutex> |
| #include <thread> |
| #include <vector> |
| |
| #include <lib/zx/event.h> |
| #include <zircon/syscalls.h> |
| |
| #include "fuchsia/msd_img_connection.h" |
| #include "fuchsia/msd_img_device.h" |
| #include "magma_util/macros.h" |
| #include "platform_barriers.h" |
| #include "platform_bus_mapper.h" |
| #include "platform_thread.h" |
| |
| extern "C" { |
| #include "allocmem.h" |
| #include "cache_km.h" |
| #include "img_types.h" |
| #include "log2.h" |
| #include "osfunc.h" |
| #if defined(PVRSRV_ENABLE_PROCESS_STATS) |
| #include "process_stats.h" |
| #endif |
| #include "pvr_debug.h" |
| #include "pvrsrv_memallocflags.h" |
| } |
| #define NOT_IMPLEMENTED() fprintf(stderr, "msd-img-rgx-mtk: Not implemented in %s:%s:%d\n", __func__, __FILE__, __LINE__); |
| |
| namespace msd_img |
| { |
| struct EventObject |
| { |
| std::mutex mutex; |
| std::condition_variable condition_variable; |
| // wake_count is guarded by mutex, but clang's thread safety analysis |
| // doesn't understand that. |
| uint32_t wake_count = 0; |
| }; |
| |
| struct EventObjectHandle |
| { |
| static constexpr uint32_t kMagic = 'hEVT'; |
| |
| static EventObjectHandle *FromHandle(IMG_HANDLE img_event_object) |
| { |
| auto event_object = reinterpret_cast<EventObjectHandle *>(img_event_object); |
| assert(event_object->magic == kMagic); |
| return event_object; |
| } |
| |
| uint32_t magic = kMagic; |
| std::shared_ptr<EventObject> object; |
| }; |
| |
| // This struct is used by a single thread to wait for a signal to happen. |
| struct EventObjectOpenHandle |
| { |
| static constexpr uint32_t kMagic = 'hEVO'; |
| |
| static EventObjectOpenHandle *FromHandle(IMG_HANDLE img_event_object) |
| { |
| auto event_object = reinterpret_cast<EventObjectOpenHandle *>(img_event_object); |
| assert(event_object->magic == kMagic); |
| return event_object; |
| } |
| |
| uint32_t magic = kMagic; |
| std::shared_ptr<EventObject> object; |
| // last_seen_wake_count is set to 0 on the new object, so the first wait |
| // will succeed instantly if the object was ever signaled. |
| uint32_t last_seen_wake_count = 0; |
| }; |
| |
| struct Thread |
| { |
| static constexpr uint32_t kMagic = 'hThr'; |
| uint32_t magic = kMagic; |
| std::thread thread; |
| |
| static Thread *cast(IMG_HANDLE thr) |
| { |
| auto thread_ptr = static_cast<Thread *>(thr); |
| assert(thread_ptr->magic == kMagic); |
| |
| return thread_ptr; |
| } |
| }; |
| |
| struct PageWrapper |
| { |
| static constexpr uint32_t kMagic = 'hPGS'; |
| uint32_t magic = kMagic; |
| std::unique_ptr<magma::PlatformBuffer> buffer; |
| std::unique_ptr<magma::PlatformBusMapper::BusMapping> mapping; |
| |
| static PageWrapper *FromHandle(PG_HANDLE *psMemHandle) |
| { |
| auto object = reinterpret_cast<PageWrapper *>(psMemHandle->u.pvHandle); |
| DASSERT(object->magic == kMagic); |
| return object; |
| } |
| }; |
| |
| struct MisrHandle |
| { |
| std::thread thread; |
| // ZX_EVENT_SIGNALED is used to wake up, and ZX_USER_SIGNAL_0 is used to |
| // force the handler to quit. |
| zx::event event; |
| }; |
| |
| |
| } // namespace msd_img |
| |
| static PVRSRV_ERROR |
| ZxStatusToError(zx_status_t status) |
| { |
| switch (status) |
| { |
| case ZX_OK: return PVRSRV_OK; |
| case ZX_ERR_INTERNAL: return PVRSRV_ERROR_INTERNAL_ERROR; |
| case ZX_ERR_NOT_SUPPORTED: return PVRSRV_ERROR_NOT_SUPPORTED; |
| case ZX_ERR_NO_RESOURCES: return PVRSRV_ERROR_OUT_OF_MEMORY; |
| case ZX_ERR_NO_MEMORY: return PVRSRV_ERROR_OUT_OF_MEMORY; |
| case ZX_ERR_INVALID_ARGS: return PVRSRV_ERROR_INVALID_PARAMS; |
| case ZX_ERR_BAD_HANDLE: return PVRSRV_ERROR_INVALID_HANDLE_TYPE; |
| case ZX_ERR_OUT_OF_RANGE: return PVRSRV_ERROR_HANDLE_INDEX_OUT_OF_RANGE; |
| case ZX_ERR_BUFFER_TOO_SMALL: return PVRSRV_ERROR_INVALID_PARAMS; |
| case ZX_ERR_BAD_STATE: return PVRSRV_ERROR_INVALID_DEVICE; |
| case ZX_ERR_TIMED_OUT: return PVRSRV_ERROR_TIMEOUT; |
| case ZX_ERR_UNAVAILABLE: return PVRSRV_ERROR_INVALID_DEVICE; |
| case ZX_ERR_ACCESS_DENIED: return PVRSRV_ERROR_INIT_FAILURE; |
| default: return PVRSRV_ERROR_NOT_SUPPORTED; |
| } |
| } |
| |
| |
| void |
| OSThreadDumpInfo(IMG_HANDLE hDbgReqestHandle, DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, void *pvDumpDebugFile) |
| { |
| } |
| |
| PVRSRV_ERROR |
| OSPhyContigPagesAlloc(PVRSRV_DEVICE_NODE *psDevNode, size_t uiSize, PG_HANDLE *psMemHandle, IMG_DEV_PHYADDR *psDevPAddr) |
| { |
| MsdImgDevice *device = MsdImgDevice::cast(psDevNode->psDevConfig->pvOSDevice); |
| auto page_struct = std::make_unique<msd_img::PageWrapper>(); |
| page_struct->buffer = device->bus_mapper()->CreateContiguousBuffer(uiSize, magma::page_shift(), "IMG contig"); |
| if (!page_struct->buffer) |
| { |
| return DRET(PVRSRV_ERROR_OUT_OF_MEMORY); |
| } |
| page_struct->mapping = device->bus_mapper()->MapPageRangeBus(page_struct->buffer.get(), 0, |
| page_struct->buffer->size() / magma::page_size()); |
| if (!page_struct->mapping) |
| { |
| return DRET(PVRSRV_ERROR_OUT_OF_MEMORY); |
| } |
| psDevPAddr->uiAddr = page_struct->mapping->Get()[0]; |
| psMemHandle->u.pvHandle = page_struct.release(); |
| return PVRSRV_OK; |
| } |
| void |
| OSPhyContigPagesFree(PVRSRV_DEVICE_NODE *psDevNode, PG_HANDLE *psMemHandle) |
| { |
| auto page_struct = msd_img::PageWrapper::FromHandle(psMemHandle); |
| delete page_struct; |
| } |
| |
| PVRSRV_ERROR |
| OSPhyContigPagesMap(PVRSRV_DEVICE_NODE *psDevNode, |
| PG_HANDLE *psMemHandle, |
| size_t uiSize, |
| IMG_DEV_PHYADDR *psDevPAddr, |
| void **pvPtr) |
| { |
| auto page_struct = msd_img::PageWrapper::FromHandle(psMemHandle); |
| |
| if (!page_struct->buffer->MapCpu(pvPtr, 0)) |
| { |
| return DRET(PVRSRV_ERROR_OUT_OF_MEMORY); |
| } |
| return PVRSRV_OK; |
| } |
| |
| void |
| OSPhyContigPagesUnmap(PVRSRV_DEVICE_NODE *psDevNode, PG_HANDLE *psMemHandle, void *pvPtr) |
| { |
| auto page_struct = msd_img::PageWrapper::FromHandle(psMemHandle); |
| page_struct->buffer->UnmapCpu(); |
| } |
| |
| PVRSRV_ERROR |
| OSPhyContigPagesClean(PVRSRV_DEVICE_NODE *psDevNode, PG_HANDLE *psMemHandle, IMG_UINT32 uiOffset, IMG_UINT32 uiLength) |
| { |
| auto page_struct = msd_img::PageWrapper::FromHandle(psMemHandle); |
| if (!page_struct->buffer->CleanCache(uiOffset, uiLength, false)) |
| { |
| return DRET(PVRSRV_ERROR_INVALID_PARAMS); |
| } |
| return PVRSRV_OK; |
| } |
| |
| IMG_UINT32 |
| OSCPUCacheAttributeSize(IMG_DCACHE_ATTRIBUTE eCacheAttribute) |
| { |
| return zx_system_get_dcache_line_size(); |
| } |
| |
| IMG_UINT32 |
| OSVSScanf(IMG_CHAR *pStr, const IMG_CHAR *pszFormat, ...) |
| { |
| va_list args; |
| va_start(args, pszFormat); |
| uint32_t res = vsscanf(pStr, pszFormat, args); |
| va_end(args); |
| return res; |
| } |
| |
| IMG_INT |
| OSMemCmp(void *pvBufA, void *pvBufB, size_t uiLen) |
| { |
| return memcmp(pvBufA, pvBufB, uiLen); |
| } |
| |
| size_t |
| OSStringLCopy(IMG_CHAR *pszDest, const IMG_CHAR *pszSrc, size_t uSize) |
| { |
| return strlcpy(pszDest, pszSrc, uSize); |
| } |
| |
| IMG_CHAR * |
| OSStringNCopy(IMG_CHAR *pszDest, const IMG_CHAR *pszSrc, size_t uSize) |
| { |
| return strncpy(pszDest, pszSrc, uSize); |
| } |
| |
| IMG_INT32 |
| OSSNPrintf(IMG_CHAR *pStr, size_t ui32Size, const IMG_CHAR *pszFormat, ...) |
| { |
| va_list args; |
| va_start(args, pszFormat); |
| int res = vsnprintf(pStr, ui32Size, pszFormat, args); |
| va_end(args); |
| return res; |
| } |
| |
| size_t |
| OSStringLength(const IMG_CHAR *pStr) |
| { |
| return strlen(pStr); |
| } |
| |
| size_t |
| OSStringNLength(const IMG_CHAR *pStr, size_t uiCount) |
| { |
| return strnlen(pStr, uiCount); |
| } |
| |
| IMG_INT32 |
| OSStringCompare(const IMG_CHAR *pStr1, const IMG_CHAR *pStr2) |
| { |
| return strcmp(pStr1, pStr2); |
| } |
| |
| IMG_INT32 |
| OSStringNCompare(const IMG_CHAR *pStr1, const IMG_CHAR *pStr2, size_t uiSize) |
| { |
| return strncmp(pStr1, pStr2, uiSize); |
| } |
| |
| PVRSRV_ERROR |
| OSStringToUINT32(const IMG_CHAR *pStr, IMG_UINT32 ui32Base, IMG_UINT32 *ui32Result) |
| { |
| *ui32Result = strtoul(pStr, nullptr, ui32Base); |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| OSInitEnvData(void) |
| { |
| return PVRSRV_OK; |
| } |
| |
| |
| void |
| OSDeInitEnvData(void) |
| { |
| NOT_IMPLEMENTED(); |
| } |
| |
| #if defined(PVRSRV_USE_BRIDGE_LOCK) |
| PVRSRV_ERROR |
| OSGetGlobalBridgeBuffers(void **ppvBridgeInBuffer, void **ppvBridgeOutBuffer) |
| { |
| NOT_IMPLEMENTED(); |
| return PVRSRV_OK; |
| } |
| #endif |
| |
| void |
| OSReleaseThreadQuanta(void) |
| { |
| std::this_thread::yield(); |
| } |
| |
| IMG_UINT64 |
| OSClockns64(void) |
| { |
| return zx_clock_get_monotonic(); |
| } |
| |
| IMG_UINT64 |
| OSClockus64(void) |
| { |
| return zx_clock_get_monotonic() / 1000; |
| } |
| |
| IMG_UINT32 |
| OSClockus(void) |
| { |
| return zx_clock_get_monotonic() / 1000; |
| } |
| |
| IMG_UINT32 |
| OSClockms(void) |
| { |
| return zx_clock_get_monotonic() / 1000000; |
| } |
| |
| |
| PVRSRV_ERROR |
| OSClockMonotonicns64(IMG_UINT64 *pui64Time) |
| { |
| *pui64Time = zx_clock_get_monotonic(); |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| OSClockMonotonicus64(IMG_UINT64 *pui64Time) |
| { |
| *pui64Time = zx_clock_get_monotonic() / 1000; |
| return PVRSRV_OK; |
| } |
| |
| IMG_UINT64 |
| OSClockMonotonicRawns64(void) |
| { |
| return zx_clock_get_monotonic(); |
| } |
| |
| IMG_UINT64 |
| OSClockMonotonicRawus64(void) |
| { |
| return zx_clock_get_monotonic() / 1000; |
| } |
| |
| void |
| OSWaitus(IMG_UINT32 ui32Timeus) |
| { |
| uint64_t start = OSClockus64(); |
| while (OSClockus64() - start < ui32Timeus) |
| ; |
| } |
| |
| void |
| OSSleepms(IMG_UINT32 ui32Timems) |
| { |
| zx_nanosleep(zx_deadline_after(ZX_MSEC(ui32Timems))); |
| } |
| |
| |
| IMG_UINT64 |
| OSGetCurrentProcessVASpaceSize(void) |
| { |
| // Currently every process on Fuchsia has the same VA space size. |
| return magma::PlatformBuffer::MinimumMappableAddress() + magma::PlatformBuffer::MappableAddressRegionLength(); |
| } |
| |
| IMG_PID |
| OSGetCurrentProcessID(void) |
| { |
| return magma::PlatformProcessHelper::GetCurrentProcessId(); |
| } |
| |
| IMG_CHAR * |
| OSGetCurrentProcessName(void) |
| { |
| return OSGetCurrentClientProcessNameKM(); |
| } |
| |
| uintptr_t |
| OSGetCurrentThreadID(void) |
| { |
| NOT_IMPLEMENTED(); |
| return 0; |
| } |
| |
| IMG_PID |
| OSGetCurrentClientProcessIDKM(void) |
| { |
| MsdImgConnection *connection = MsdImgConnection::GetCurrentConnection(); |
| // Some statistics will check for the process id on startup when there |
| // is no current connection. |
| if (!connection) |
| return 0; |
| return connection->client_id(); |
| } |
| |
| IMG_CHAR * |
| OSGetCurrentClientProcessNameKM(void) |
| { |
| static char msd_name[] = "MSD"; |
| MsdImgConnection *connection = MsdImgConnection::GetCurrentConnection(); |
| // If there's no connection the current action is on the behalf of the |
| // MSD. |
| return connection ? connection->client_name() : msd_name; |
| } |
| |
| uintptr_t |
| OSGetCurrentClientThreadIDKM(void) |
| { |
| NOT_IMPLEMENTED(); |
| return 0; |
| } |
| |
| size_t |
| OSGetPageSize(void) |
| { |
| return magma::page_size(); |
| } |
| |
| size_t |
| OSGetPageShift(void) |
| { |
| return magma::page_shift(); |
| } |
| |
| size_t |
| OSGetPageMask(void) |
| { |
| // Lower bits set. |
| return magma::page_size() - 1; |
| } |
| |
| size_t |
| OSGetOrder(size_t uSize) |
| { |
| NOT_IMPLEMENTED(); |
| return 0; |
| } |
| |
| IMG_UINT64 |
| OSGetRAMSize(void) |
| { |
| NOT_IMPLEMENTED(); |
| return 0; |
| } |
| |
| |
| int |
| PVRSRVToNativeError(PVRSRV_ERROR e) |
| { |
| NOT_IMPLEMENTED(); |
| return 0; |
| } |
| |
| PVRSRV_ERROR |
| OSInstallMISR(IMG_HANDLE *hMISRData, PFN_MISR pfnMISR, void *hData) |
| { |
| auto misr_handle = std::make_unique<msd_img::MisrHandle>(); |
| zx_status_t status = zx::event::create(0, &misr_handle->event); |
| if (status != ZX_OK) |
| { |
| return ZxStatusToError(status); |
| } |
| misr_handle->thread = std::thread( |
| [](PFN_MISR pfnMISR, void *hData, msd_img::MisrHandle *misr_handle) { |
| while (true) |
| { |
| zx_signals_t observed; |
| zx_status_t status = misr_handle->event.wait_one(ZX_EVENT_SIGNALED | ZX_USER_SIGNAL_0, |
| zx::time::infinite(), &observed); |
| if (status != ZX_OK) |
| { |
| DLOG("Failed to wait on MISR handle"); |
| return; |
| } |
| // Clear before running the callback to ensure a signal during the |
| // callback won't be ignored. |
| status = misr_handle->event.signal(ZX_EVENT_SIGNALED, 0); |
| if (status != ZX_OK) |
| { |
| DLOG("Failed clear MISR handle"); |
| return; |
| } |
| if (observed & ZX_USER_SIGNAL_0) |
| break; |
| pfnMISR(hData); |
| } |
| }, |
| pfnMISR, hData, misr_handle.get()); |
| *hMISRData = misr_handle.release(); |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| OSUninstallMISR(IMG_HANDLE hMISRData) |
| { |
| auto misr_handle = reinterpret_cast<msd_img::MisrHandle *>(hMISRData); |
| if (misr_handle->event.signal(0, ZX_USER_SIGNAL_0) != ZX_OK) |
| { |
| DLOG("Failed to signal MISR on shutdown"); |
| misr_handle->thread.detach(); |
| } |
| else |
| { |
| misr_handle->thread.join(); |
| } |
| delete misr_handle; |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| OSScheduleMISR(IMG_HANDLE hMISRData) |
| { |
| auto misr_handle = reinterpret_cast<msd_img::MisrHandle *>(hMISRData); |
| return ZxStatusToError(misr_handle->event.signal(0, ZX_EVENT_SIGNALED)); |
| } |
| |
| PVRSRV_ERROR |
| OSThreadCreate(IMG_HANDLE *phThread, |
| IMG_CHAR *pszThreadName, |
| PFN_THREAD pfnThread, |
| IMG_HANDLE pfnDebugDumpCB, |
| IMG_BOOL bIsSupportingThread, |
| void *hData) |
| { |
| auto handle = std::make_unique<msd_img::Thread>(); |
| handle->thread = std::thread([](PFN_THREAD thread, void *data) { thread(data); }, pfnThread, hData); |
| *phThread = handle.release(); |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| OSThreadCreatePriority(IMG_HANDLE *phThread, |
| IMG_CHAR *pszThreadName, |
| PFN_THREAD pfnThread, |
| IMG_HANDLE pfnDebugDumpCB, |
| IMG_BOOL bIsSupportingThread, |
| void *hData, |
| OS_THREAD_LEVEL eThreadPriority) |
| { |
| // The thread is created, but priority is ignored. |
| // TODO(MA-579): Implement. |
| return OSThreadCreate(phThread, pszThreadName, pfnThread, pfnDebugDumpCB, bIsSupportingThread, hData); |
| } |
| |
| PVRSRV_ERROR |
| OSThreadDestroy(IMG_HANDLE hThread) |
| { |
| msd_img::Thread *handle = msd_img::Thread::cast(hThread); |
| handle->thread.join(); |
| delete handle; |
| return PVRSRV_OK; |
| } |
| |
| void |
| OSPanic(void) |
| { |
| NOT_IMPLEMENTED(); |
| } |
| |
| PVRSRV_ERROR |
| OSSetThreadPriority(IMG_HANDLE hThread, IMG_UINT32 nThreadPriority, IMG_UINT32 nThreadWeight) |
| { |
| // TODO(MA-579): Implement. |
| NOT_IMPLEMENTED(); |
| return PVRSRV_OK; |
| } |
| |
| void * |
| OSMapPhysToLin(IMG_CPU_PHYADDR BasePAddr, size_t ui32Bytes, IMG_UINT32 ui32MappingFlags) |
| { |
| if (BasePAddr.uiAddr == MsdImgDevice::GetRegistersPhysicalAddress()) |
| { |
| return MsdImgDevice::GetRegistersCpuAddress(); |
| } |
| |
| NOT_IMPLEMENTED(); |
| return nullptr; |
| } |
| |
| |
| IMG_BOOL |
| OSUnMapPhysToLin(void *pvLinAddr, size_t ui32Bytes, IMG_UINT32 ui32MappingFlags) |
| { |
| NOT_IMPLEMENTED(); |
| return IMG_FALSE; |
| } |
| |
| IMG_HANDLE |
| OSAddTimer(PFN_TIMER_FUNC pfnTimerFunc, void *pvData, IMG_UINT32 ui32MsTimeout) |
| { |
| NOT_IMPLEMENTED(); |
| return 0; |
| } |
| |
| |
| |
| PVRSRV_ERROR |
| OSRemoveTimer(IMG_HANDLE hTimer) |
| { |
| NOT_IMPLEMENTED(); |
| return PVRSRV_ERROR_NOT_SUPPORTED; |
| } |
| |
| PVRSRV_ERROR |
| OSEnableTimer(IMG_HANDLE hTimer) |
| { |
| NOT_IMPLEMENTED(); |
| return PVRSRV_ERROR_NOT_SUPPORTED; |
| } |
| |
| |
| PVRSRV_ERROR |
| OSDisableTimer(IMG_HANDLE hTimer) |
| { |
| NOT_IMPLEMENTED(); |
| return PVRSRV_ERROR_NOT_SUPPORTED; |
| } |
| |
| PVRSRV_ERROR |
| OSEventObjectCreate(const IMG_CHAR *pszName, IMG_HANDLE *hEventObject) |
| { |
| auto handle = std::make_unique<msd_img::EventObjectHandle>(); |
| handle->object = std::make_shared<msd_img::EventObject>(); |
| *hEventObject = handle.release(); |
| return PVRSRV_OK; |
| } |
| |
| |
| PVRSRV_ERROR |
| OSEventObjectDestroy(IMG_HANDLE hEventObject) |
| { |
| delete msd_img::EventObjectHandle::FromHandle(hEventObject); |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| OSEventObjectWait(IMG_HANDLE hOSEventKM) |
| { |
| auto handle = msd_img::EventObjectOpenHandle::FromHandle(hOSEventKM); |
| std::unique_lock<std::mutex> lock(handle->object->mutex); |
| handle->object->condition_variable.wait( |
| lock, [&handle]() { return handle->object->wake_count != handle->last_seen_wake_count; }); |
| handle->last_seen_wake_count = handle->object->wake_count; |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| OSEventObjectWaitTimeoutAndHoldBridgeLock(IMG_HANDLE hOSEventKM, IMG_UINT64 uiTimeoutus) |
| { |
| #if defined(PVRSRV_USE_BRIDGE_LOCK) |
| #error Bridge lock not supported |
| #endif |
| return OSEventObjectWaitTimeout(hOSEventKM, uiTimeoutus); |
| } |
| |
| PVRSRV_ERROR |
| OSEventObjectWaitAndHoldBridgeLock(IMG_HANDLE hOSEventKM) |
| { |
| #if defined(PVRSRV_USE_BRIDGE_LOCK) |
| #error Bridge lock not supported |
| #endif |
| return OSEventObjectWait(hOSEventKM); |
| } |
| |
| PVRSRV_ERROR |
| OSEventObjectWaitKernel(IMG_HANDLE hOSEventKM, IMG_UINT64 uiTimeoutus) |
| { |
| auto handle = msd_img::EventObjectOpenHandle::FromHandle(hOSEventKM); |
| std::unique_lock<std::mutex> lock(handle->object->mutex); |
| auto timeout_time = std::chrono::steady_clock::now() + std::chrono::microseconds(uiTimeoutus); |
| if (!handle->object->condition_variable.wait_until( |
| lock, timeout_time, [&handle]() { return handle->object->wake_count != handle->last_seen_wake_count; })) |
| { |
| DASSERT(handle->last_seen_wake_count == handle->object->wake_count); |
| return PVRSRV_ERROR_TIMEOUT; |
| } |
| handle->last_seen_wake_count = handle->object->wake_count; |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| OSEventObjectOpen(IMG_HANDLE hEventObject, IMG_HANDLE *phOSEvent) |
| { |
| auto event_object = msd_img::EventObjectHandle::FromHandle(hEventObject); |
| auto event_object_open = std::make_unique<msd_img::EventObjectOpenHandle>(); |
| event_object_open->object = event_object->object; |
| *phOSEvent = event_object_open.release(); |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| OSEventObjectClose(IMG_HANDLE hOSEventKM) |
| { |
| delete msd_img::EventObjectOpenHandle::FromHandle(hOSEventKM); |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| OSEventObjectSignal(IMG_HANDLE hEventObject) |
| { |
| auto handle = msd_img::EventObjectHandle::FromHandle(hEventObject); |
| std::lock_guard<std::mutex> lock(handle->object->mutex); |
| handle->object->wake_count++; |
| handle->object->condition_variable.notify_all(); |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| OSCopyToUser(void *pvProcess, void __user *pvDest, const void *pvSrc, size_t ui32Bytes) |
| { |
| NOT_IMPLEMENTED(); |
| return PVRSRV_ERROR_NOT_SUPPORTED; |
| } |
| |
| PVRSRV_ERROR |
| OSCopyFromUser(void *pvProcess, void *pvDest, const void __user *pvSrc, size_t ui32Bytes) |
| { |
| PVR_UNREFERENCED_PARAMETER(pvProcess); |
| |
| NOT_IMPLEMENTED(); |
| return PVRSRV_ERROR_NOT_SUPPORTED; |
| } |
| |
| IMG_UINT64 |
| OSDivide64r64(IMG_UINT64 ui64Divident, IMG_UINT32 ui32Divisor, IMG_UINT32 *pui32Remainder) |
| { |
| *pui32Remainder = ui64Divident % ui32Divisor; |
| return ui64Divident / ui32Divisor; |
| } |
| |
| IMG_UINT32 |
| OSDivide64(IMG_UINT64 ui64Divident, IMG_UINT32 ui32Divisor, IMG_UINT32 *pui32Remainder) |
| { |
| *pui32Remainder = ui64Divident % ui32Divisor; |
| return ui64Divident / ui32Divisor; |
| } |
| |
| /* One time osfunc initialisation */ |
| PVRSRV_ERROR |
| PVROSFuncInit(void) |
| { |
| NOT_IMPLEMENTED(); |
| return PVRSRV_ERROR_NOT_SUPPORTED; |
| } |
| |
| /* |
| * Osfunc deinitialisation. |
| * Note that PVROSFuncInit may not have been called |
| */ |
| void |
| PVROSFuncDeInit(void) |
| { |
| NOT_IMPLEMENTED(); |
| } |
| |
| void |
| OSDumpStack(void) |
| { |
| NOT_IMPLEMENTED(); |
| } |
| |
| #if defined(PVRSRV_USE_BRIDGE_LOCK) |
| |
| |
| void |
| OSAcquireBridgeLock(void) |
| { |
| NOT_IMPLEMENTED(); |
| } |
| |
| void |
| OSReleaseBridgeLock(void) |
| { |
| NOT_IMPLEMENTED(); |
| } |
| |
| |
| IMG_BOOL |
| BridgeLockIsLocked(void) |
| { |
| NOT_IMPLEMENTED(); |
| return 0; |
| } |
| |
| #endif |
| |
| struct StatisticEntry |
| { |
| uint32_t unused; |
| }; |
| |
| void * |
| OSCreateStatisticEntry(IMG_CHAR *pszName, |
| void *pvFolder, |
| OS_STATS_PRINT_FUNC *pfnStatsPrint, |
| OS_INC_STATS_MEM_REFCOUNT_FUNC *pfnIncMemRefCt, |
| OS_DEC_STATS_MEM_REFCOUNT_FUNC *pfnDecMemRefCt, |
| void *pvData) |
| { |
| // TODO(MA-578): Implement. |
| NOT_IMPLEMENTED(); |
| return new StatisticEntry; |
| } |
| |
| void |
| OSRemoveStatisticEntry(void *pvEntry) |
| { |
| delete reinterpret_cast<StatisticEntry *>(pvEntry); |
| } |
| |
| #if defined(PVRSRV_ENABLE_MEMTRACK_STATS_FILE) |
| void * |
| OSCreateRawStatisticEntry(const IMG_CHAR *pszFileName, void *pvParentDir, OS_STATS_PRINT_FUNC *pfStatsPrint) |
| { |
| NOT_IMPLEMENTED(); |
| return 0; |
| } |
| |
| void |
| OSRemoveRawStatisticEntry(void *pvEntry) |
| { |
| NOT_IMPLEMENTED(); |
| } |
| #endif |
| |
| /*************************************************************************/ /*! |
| @Function OSCreateStatisticFolder |
| @Description Create a statistic folder to hold statistic entries. |
| @Input pszName String containing the name for the folder. |
| @Input pvFolder Reference from OSCreateStatisticFolder() of the folder |
| to create the folder in, or NULL for the root. |
| @Return Pointer void reference to the folder created, which can be |
| passed to OSRemoveStatisticFolder() to remove the folder. |
| */ /**************************************************************************/ |
| void * |
| OSCreateStatisticFolder(IMG_CHAR *pszName, void *pvFolder) |
| { |
| NOT_IMPLEMENTED(); |
| return 0; |
| } /* OSCreateStatisticFolder */ |
| |
| |
| /*************************************************************************/ /*! |
| @Function OSRemoveStatisticFolder |
| @Description Removes a statistic folder. |
| @Input ppvFolder Reference from OSCreateStatisticFolder() of the |
| folder that should be removed. |
| This needs to be double pointer because it has to |
| be NULLed right after memory is freed to avoid |
| possible races and use-after-free situations. |
| */ /**************************************************************************/ |
| void |
| OSRemoveStatisticFolder(void **ppvFolder) |
| { |
| NOT_IMPLEMENTED(); |
| } /* OSRemoveStatisticFolder */ |
| |
| |
| PVRSRV_ERROR |
| OSChangeSparseMemCPUAddrMap(void **psPageArray, |
| IMG_UINT64 sCpuVAddrBase, |
| IMG_CPU_PHYADDR sCpuPAHeapBase, |
| IMG_UINT32 ui32AllocPageCount, |
| IMG_UINT32 *pai32AllocIndices, |
| IMG_UINT32 ui32FreePageCount, |
| IMG_UINT32 *pai32FreeIndices, |
| IMG_BOOL bIsLMA) |
| { |
| NOT_IMPLEMENTED(); |
| return PVRSRV_ERROR_NOT_SUPPORTED; |
| } |
| |
| /*************************************************************************/ /*! |
| @Function OSDebugSignalPID |
| @Description Sends a SIGTRAP signal to a specific PID in user mode for |
| debugging purposes. The user mode process can register a handler |
| against this signal. |
| This is necessary to support the Rogue debugger. If the Rogue |
| debugger is not used then this function may be implemented as |
| a stub. |
| @Input ui32PID The PID for the signal. |
| @Return PVRSRV_OK on success, a failure code otherwise. |
| */ /**************************************************************************/ |
| PVRSRV_ERROR |
| OSDebugSignalPID(IMG_UINT32 ui32PID) |
| { |
| NOT_IMPLEMENTED(); |
| return PVRSRV_ERROR_NOT_SUPPORTED; |
| } |
| |
| void |
| OSDumpVersionInfo(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, void *pvDumpDebugFile) |
| { |
| NOT_IMPLEMENTED(); |
| } |
| |
| void |
| OSWriteMemoryBarrier(void) |
| { |
| magma::barriers::WriteBarrier(); |
| } |
| |
| void |
| OSMemoryBarrier(void) |
| { |
| magma::barriers::Barrier(); |
| } |
| |
| struct _OSWR_LOCK_ { |
| std::shared_mutex mutex; |
| }; |
| PVRSRV_ERROR OSWRLockCreate(POSWR_LOCK *ppsLock) { |
| *ppsLock = new _OSWR_LOCK_; |
| return PVRSRV_OK; |
| } |
| void OSWRLockDestroy(POSWR_LOCK psLock) { |
| delete psLock; |
| } |
| void OSWRLockAcquireRead(POSWR_LOCK psLock) { |
| psLock->mutex.lock_shared(); |
| } |
| void OSWRLockReleaseRead(POSWR_LOCK psLock) { |
| psLock->mutex.unlock_shared(); |
| } |
| void OSWRLockAcquireWrite(POSWR_LOCK psLock) { |
| psLock->mutex.lock(); |
| } |
| void OSWRLockReleaseWrite(POSWR_LOCK psLock) { |
| psLock->mutex.unlock(); |
| } |
| |
| |
| // The memory barriers in the following functions don't seem to necessarily be |
| // required by the definitions of the methods, but we have them to match linux |
| // in case they happen to matter. |
| IMG_UINT8 |
| OSReadHWReg8(volatile void *pvLinRegBaseAddr, IMG_UINT32 ui32Offset) |
| { |
| uint8_t value = *(reinterpret_cast<volatile uint8_t *>(pvLinRegBaseAddr) + ui32Offset); |
| magma::barriers::ReadBarrier(); |
| return value; |
| } |
| |
| IMG_UINT16 |
| OSReadHWReg16(volatile void *pvLinRegBaseAddr, IMG_UINT32 ui32Offset) |
| { |
| uint16_t value = |
| *reinterpret_cast<volatile uint16_t *>(reinterpret_cast<volatile uint8_t *>(pvLinRegBaseAddr) + ui32Offset); |
| magma::barriers::ReadBarrier(); |
| return value; |
| } |
| |
| IMG_UINT32 |
| OSReadHWReg32(volatile void *pvLinRegBaseAddr, IMG_UINT32 ui32Offset) |
| { |
| uint32_t value = |
| *reinterpret_cast<volatile uint32_t *>(reinterpret_cast<volatile uint8_t *>(pvLinRegBaseAddr) + ui32Offset); |
| magma::barriers::ReadBarrier(); |
| return value; |
| } |
| |
| IMG_UINT64 |
| OSReadHWReg64(volatile void *pvLinRegBaseAddr, IMG_UINT32 ui32Offset) |
| { |
| auto first_reg = reinterpret_cast<volatile uint32_t *>(reinterpret_cast<uintptr_t>(pvLinRegBaseAddr) + ui32Offset); |
| uint64_t value = first_reg[0] | (static_cast<uint64_t>(first_reg[1]) << 32); |
| magma::barriers::ReadBarrier(); |
| return value; |
| } |
| |
| |
| void |
| OSWriteHWReg8(volatile void *pvLinRegBaseAddr, IMG_UINT32 ui32Offset, IMG_UINT8 ui8Value) |
| { |
| magma::barriers::WriteBarrier(); |
| *(reinterpret_cast<volatile uint8_t *>(pvLinRegBaseAddr) + ui32Offset) = ui8Value; |
| } |
| |
| void |
| OSWriteHWReg16(volatile void *pvLinRegBaseAddr, IMG_UINT32 ui32Offset, IMG_UINT16 ui16Value) |
| { |
| magma::barriers::WriteBarrier(); |
| *reinterpret_cast<volatile uint16_t *>(reinterpret_cast<volatile uint8_t *>(pvLinRegBaseAddr) + ui32Offset) = |
| ui16Value; |
| } |
| |
| void |
| OSWriteHWReg32(volatile void *pvLinRegBaseAddr, IMG_UINT32 ui32Offset, IMG_UINT32 ui32Value) |
| { |
| magma::barriers::WriteBarrier(); |
| *reinterpret_cast<volatile uint32_t *>(reinterpret_cast<volatile uint8_t *>(pvLinRegBaseAddr) + ui32Offset) = |
| ui32Value; |
| } |
| |
| void |
| OSWriteHWReg64(volatile void *pvLinRegBaseAddr, IMG_UINT32 ui32Offset, IMG_UINT64 ui64Value) |
| { |
| magma::barriers::WriteBarrier(); |
| auto first_reg = reinterpret_cast<volatile uint32_t *>(reinterpret_cast<uintptr_t>(pvLinRegBaseAddr) + ui32Offset); |
| first_reg[0] = ui64Value & 0xffffffff; |
| first_reg[1] = (ui64Value >> 32) & 0xffffffff; |
| } |