PowerVR HEAP

2025-10-27 32 0

主要功能

  1. 物理堆管理: 创建、获取、释放、销毁物理内存堆
  2. 多种堆类型支持: UMA、LMA、IMA、DLM、DMA、WRAP
  3. 内存分配: PMR(Physical Memory Reference)和PMB(Physical Memory Block)分配
  4. OOM处理: 内存不足时的降级机制
  5. 调试支持: 堆状态查询和PDump支持

架构层次

┌─────────────────────────────────────────────────────────┐
│                      应用层 (Application)                │
│            PhysHeapCreatePMR / PhysHeapPagesAlloc       │
└─────────────────────────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────┐
│                      管理层 (Management)                 │
│    PhysHeapCreate / Acquire / Release / Destroy         │
└─────────────────────────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────┐
│                      策略层 (Policy)                     │
│    Heap Type Selection / OOM Demotion / Fallback        │
└─────────────────────────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────┐
│                    实现层 (Implementation)               │
│    PhysmemLMA / PhysmemUMA / PhysmemIMA / PhysmemDLM    │
└─────────────────────────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────┐
│                      硬件层 (Hardware)                   │
│         GPU Local Memory / System RAM / Device Mem      │
└─────────────────────────────────────────────────────────┘

核心数据结构

PHYS_HEAP 结构体

struct _PHYS_HEAP_
{
    /*! 堆类型 */
    PHYS_HEAP_TYPE eType;

    /*! 分配策略 */
    PHYS_HEAP_POLICY uiPolicy;

    /* 配置标志 */
    PHYS_HEAP_USAGE_FLAGS ui32UsageFlags;

    /* OOM检测状态 */
#if !defined(PVRSRV_PHYSHEAP_DISABLE_OOM_DEMOTION)
    ATOMIC_T sOOMDetected;
#endif

    /*! 设备节点指针 */
    PPVRSRV_DEVICE_NODE psDevNode;

    /*! PDump内存空间名称 */
    IMG_CHAR *pszPDumpMemspaceName;

    /*! 物理堆名称 */
    IMG_CHAR aszName[PHYS_HEAP_NAME_SIZE];

    /*! 转换例程的私有数据 */
    IMG_HANDLE hPrivData;

    /*! 函数回调 */
    PHYS_HEAP_FUNCTIONS *psMemFuncs;

    /*! 引用计数 */
    IMG_UINT32 ui32RefCount;

    /*! 实现特定数据 */
    PHEAP_IMPL_DATA pvImplData;
    const PHEAP_IMPL_FUNCS *psImplFuncs;

    /*! 下一个物理堆指针 */
    struct _PHYS_HEAP_ *psNext;

#if defined(SUPPORT_STATIC_IPA)
    /*! IPA策略值 */
    IMG_UINT32 ui32IPAPolicyValue;
    IMG_UINT32 ui32IPAClearMask;
    IMG_UINT32 ui32IPAShift;
#endif

#if defined(PVRSRV_ENABLE_XD_MEM)
    /* SPAS区域指针 */
    PHYS_HEAP_SPAS_REGION *psSpasRegion;
    /* SPAS区域的物理堆列表 */
    DLLIST_NODE sSpasSibling;
#endif
};

关键字段说明

字段 类型 作用 备注
eType PHYS_HEAP_TYPE 堆类型标识 UMA/LMA/IMA/DLM/DMA/WRAP
uiPolicy PHYS_HEAP_POLICY 分配策略 连续/非连续分配
ui32UsageFlags Bitfield 堆用途标志 可设置多个标志
sOOMDetected ATOMIC_T OOM状态 原子操作,线程安全
psDevNode Pointer 所属设备节点 反向引用设备
ui32RefCount IMG_UINT32 引用计数 生命周期管理
psImplFuncs Function Table 实现层函数表 多态实现
pvImplData Opaque Pointer 实现层数据 封装具体实现
psNext Pointer 链表指针 设备堆链表

数据结构关系图

PVRSRV_DEVICE_NODE
    |
    +-- psPhysHeapList ───────┐
    |                         ↓
    |                    PHYS_HEAP
    |                         |
    |                         +-- eType (UMA/LMA/IMA/DLM)
    |                         +-- ui32UsageFlags (Bitfield)
    |                         +-- psImplFuncs ────→ Function Table
    |                         |                        |
    |                         +-- pvImplData ────→ Implementation Data
    |                         +-- psNext ─────────→ Next PHYS_HEAP
    |
    +-- apsPhysHeap[26] ──────┐ (快速访问缓存)
    |                         ↓
    |                    [0] DEFAULT
    |                    [1] CPU_LOCAL
    |                    [2] GPU_LOCAL
    |                    ...
    |                    [25] DC
    |
    +-- psMMUPhysHeap ────────→ MMU专用堆
    |
    +-- hPhysHeapLock ────────→ 保护锁

堆类型枚举 (PHYS_HEAP_TYPE)

typedef enum {
    PHYS_HEAP_TYPE_UNKNOWN,  // 未知类型
    PHYS_HEAP_TYPE_UMA,      // Unified Memory Architecture
    PHYS_HEAP_TYPE_LMA,      // Local Memory Architecture
    PHYS_HEAP_TYPE_DMA,      // Direct Memory Access
    PHYS_HEAP_TYPE_IMA,      // Imported Memory Architecture
    PHYS_HEAP_TYPE_DLM,      // Defrag Local Memory
    PHYS_HEAP_TYPE_WRAP      // Wrapped External Memory
} PHYS_HEAP_TYPE;

堆类型对比表

类型 物理位置 访问特性 典型应用场景 性能
UMA 系统RAM CPU/GPU共享 集成显卡、APU系统 带宽: 中等
延迟: 较高
LMA GPU显存(VRAM) GPU专用 独立显卡、高性能GPU 带宽: 高
延迟: 低
DMA 系统RAM DMA可访问 驱动程序缓冲区 带宽: 中等
延迟: 中等
IMA 从DLM导入 动态映射 灵活内存管理 取决于DLM
DLM GPU显存 大块管理 碎片整理、PMB导出 带宽: 高
延迟: 低
WRAP 外部对象 封装访问 共享纹理、外部buffer 取决于源

堆使用标志 (PHYS_HEAP_USAGE_FLAGS)

标志定义

static const IMG_FLAGS2DESC g_asPhysHeapUsageFlagStrings[] =
{
    {PHYS_HEAP_USAGE_CPU_LOCAL,    "CPU_LOCAL"},     // CPU本地内存
    {PHYS_HEAP_USAGE_GPU_LOCAL,    "GPU_LOCAL"},     // GPU本地内存
    {PHYS_HEAP_USAGE_GPU_PRIVATE,  "GPU_PRIVATE"},   // GPU私有内存
    {PHYS_HEAP_USAGE_EXTERNAL,     "EXTERNAL"},      // 外部内存
    {PHYS_HEAP_USAGE_GPU_COHERENT, "GPU_COHERENT"},  // GPU一致性内存
    {PHYS_HEAP_USAGE_GPU_SECURE,   "GPU_SECURE"},    // GPU安全内存
    {PHYS_HEAP_USAGE_FW_SHARED,    "FW_SHARED"},     // 固件共享
    {PHYS_HEAP_USAGE_FW_PRIVATE,   "FW_PRIVATE"},    // 固件私有
    {PHYS_HEAP_USAGE_FW_CODE,      "FW_CODE"},       // 固件代码
    {PHYS_HEAP_USAGE_FW_PRIV_DATA, "FW_PRIV_DATA"},  // 固件私有数据
    {PHYS_HEAP_USAGE_FW_PREMAP_PT, "FW_PREMAP_PT"},  // 固件预映射页表
    {PHYS_HEAP_USAGE_FW_PREMAP,    "FW_PREMAP"},     // 固件预映射
    {PHYS_HEAP_USAGE_WRAP,         "WRAP"},          // 包装内存
    {PHYS_HEAP_USAGE_DISPLAY,      "DISPLAY"},       // 显示内存
    {PHYS_HEAP_USAGE_DLM,          "DLM"}            // DLM堆
};

标志特性

  • 位掩码设计: 一个堆可以有多个标志
  • 用于匹配: 根据需求查找合适的堆
  • 支持回退: 找不到匹配堆时使用fallback
  • 动态检查: 运行时验证标志有效性

标志组合示例

DEFAULT 堆:     CPU_LOCAL | GPU_LOCAL
GPU_PRIVATE 堆: GPU_LOCAL | GPU_PRIVATE
FW_MAIN 堆:     FW_SHARED | GPU_LOCAL
DISPLAY 堆:     DISPLAY | GPU_LOCAL

堆属性配置 (PHYS_HEAP_PROPERTIES)

结构定义

typedef struct PHYS_HEAP_PROPERTIES_TAG
{
    PVRSRV_PHYS_HEAP eFallbackHeap;          // 回退堆
    PVR_LAYER_HEAP_ACTION ePVRLayerAction;   // PVR层操作
    IMG_BOOL bUserModeAlloc;                  // 用户模式分配标志
} PHYS_HEAP_PROPERTIES;

静态属性表

static PHYS_HEAP_PROPERTIES gasHeapProperties[PVRSRV_PHYS_HEAP_LAST] =
{
    /* eFallbackHeap               ePVRLayerAction                   bUserModeAlloc */
    {  PVRSRV_PHYS_HEAP_DEFAULT,   PVR_LAYER_HEAP_ACTION_INITIALISE, IMG_TRUE  }, // [0] DEFAULT
    {  PVRSRV_PHYS_HEAP_DEFAULT,   PVR_LAYER_HEAP_ACTION_INITIALISE, IMG_TRUE  }, // [1] CPU_LOCAL
    {  PVRSRV_PHYS_HEAP_DEFAULT,   PVR_LAYER_HEAP_ACTION_INITIALISE, IMG_TRUE  }, // [2] GPU_LOCAL
    {  PVRSRV_PHYS_HEAP_GPU_LOCAL, PVR_LAYER_HEAP_ACTION_INITIALISE, IMG_TRUE  }, // [3] GPU_PRIVATE
    {  PVRSRV_PHYS_HEAP_GPU_LOCAL, PVR_LAYER_HEAP_ACTION_IGNORE,     IMG_FALSE }, // [4] FW_MAIN
    {  PVRSRV_PHYS_HEAP_GPU_LOCAL, PVR_LAYER_HEAP_ACTION_INITIALISE, IMG_FALSE }, // [5] EXTERNAL
    {  PVRSRV_PHYS_HEAP_GPU_LOCAL, PVR_LAYER_HEAP_ACTION_INITIALISE, IMG_FALSE }, // [6] GPU_COHERENT
    {  PVRSRV_PHYS_HEAP_GPU_LOCAL, PVR_LAYER_HEAP_ACTION_INITIALISE, IMG_TRUE  }, // [7] GPU_SECURE
    {  PVRSRV_PHYS_HEAP_GPU_LOCAL, PVR_LAYER_HEAP_ACTION_IGNORE,     IMG_FALSE }, // [8] FW_CONFIG
    {  PVRSRV_PHYS_HEAP_FW_MAIN,   PVR_LAYER_HEAP_ACTION_IGNORE,     IMG_FALSE }, // [9] FW_CODE
    {  PVRSRV_PHYS_HEAP_FW_MAIN,   PVR_LAYER_HEAP_ACTION_IGNORE,     IMG_FALSE }, // [10] FW_PRIV_DATA
    // ... 更多配置
};

PVR层操作类型

typedef enum _PVR_LAYER_HEAP_ACTION_
{
    PVR_LAYER_HEAP_ACTION_IGNORE,       // 跳过此堆(由设备层处理)
    PVR_LAYER_HEAP_ACTION_INSTANTIATE,  // 实例化但不获取
    PVR_LAYER_HEAP_ACTION_INITIALISE    // 实例化并获取
} PVR_LAYER_HEAP_ACTION;

属性表解读

堆ID 名称 回退堆 PVR层操作 用户可分配 说明
0 DEFAULT 自身 INITIALISE 默认堆
1 CPU_LOCAL DEFAULT INITIALISE CPU本地内存
2 GPU_LOCAL DEFAULT INITIALISE GPU本地内存
3 GPU_PRIVATE GPU_LOCAL INITIALISE GPU私有内存
4 FW_MAIN GPU_LOCAL IGNORE 固件主堆
7 GPU_SECURE GPU_LOCAL INITIALISE 安全内存

实现层函数表 (PHEAP_IMPL_FUNCS)

函数指针定义

typedef struct _PHEAP_IMPL_FUNCS_
{
    /* PMR操作 */
    PVRSRV_ERROR (*pfnCreatePMR)(
        PHYS_HEAP *psPhysHeap,
        struct _CONNECTION_DATA_ *psConnection,
        IMG_DEVMEM_SIZE_T uiSize,
        IMG_UINT32 ui32NumPhysChunks,
        IMG_UINT32 ui32NumVirtChunks,
        IMG_UINT32 *pui32MappingTable,
        IMG_UINT32 uiLog2PageSize,
        PVRSRV_MEMALLOCFLAGS_T uiFlags,
        const IMG_CHAR *pszAnnotation,
        IMG_PID uiPid,
        PMR **ppsPMRPtr,
        IMG_UINT32 ui32PDumpFlags);

    /* PMB操作(仅DLM) */
    PVRSRV_ERROR (*pfnCreatePMB)(
        PHYS_HEAP *psPhysHeap,
        IMG_DEVMEM_SIZE_T uiSize,
        const IMG_CHAR *pszAnnotation,
        PMB **ppsPMRPtr,
        RA_BASE_T *puiBase,
        RA_LENGTH_T *puiSize);

    /* 页面分配/释放 */
    PVRSRV_ERROR (*pfnPagesAlloc)(
        PHYS_HEAP *psPhysHeap,
        size_t uiSize,
        PG_HANDLE *psMemHandle,
        IMG_DEV_PHYADDR *psDevPAddr,
        IMG_PID uiPid);

    void (*pfnPagesFree)(
        PHYS_HEAP *psPhysHeap,
        PG_HANDLE *psMemHandle);

    /* 页面映射/解映射 */
    PVRSRV_ERROR (*pfnPagesMap)(
        PHYS_HEAP *psPhysHeap,
        PG_HANDLE *pshMemHandle,
        size_t uiSize,
        IMG_DEV_PHYADDR *psDevPAddr,
        void **pvPtr);

    void (*pfnPagesUnMap)(
        PHYS_HEAP *psPhysHeap,
        PG_HANDLE *psMemHandle,
        void *pvPtr);

    /* 页面清理 */
    PVRSRV_ERROR (*pfnPagesClean)(
        PHYS_HEAP *psPhysHeap,
        PG_HANDLE *pshMemHandle,
        IMG_UINT32 uiOffset,
        IMG_UINT32 uiLength);

    /* 内存统计 */
    void (*pfnGetFactoryMemStats)(
        PHEAP_IMPL_DATA pvImplData,
        IMG_UINT64 *pui64TotalSize,
        IMG_UINT64 *pui64FreeSize);

    /* 地址转换 */
    PVRSRV_ERROR (*pfnGetCPUPAddr)(
        PHEAP_IMPL_DATA pvImplData,
        IMG_CPU_PHYADDR *psCpuPAddr);

    PVRSRV_ERROR (*pfnGetDevPAddr)(
        PHEAP_IMPL_DATA pvImplData,
        IMG_DEV_PHYADDR *psDevPAddr);

    PVRSRV_ERROR (*pfnGetSize)(
        PHEAP_IMPL_DATA pvImplData,
        IMG_UINT64 *puiSize);

    /* 其他操作 */
    IMG_UINT32 (*pfnGetPageShift)(void);

    void (*pfnDestroyData)(PHEAP_IMPL_DATA pvImplData);

    PVRSRV_ERROR (*pfnGetHeapDLMBacking)(
        PHEAP_IMPL_DATA pvImplData,
        PHYS_HEAP **ppsDLMHeap);

    IMG_BOOL (*pfnGetHeapSpansStringIter)(
        PHEAP_IMPL_DATA pvImplData,
        IMG_CHAR *pszSpanString,
        IMG_UINT32 ui32Size,
        void **ppvIterHandle);

#if defined(SUPPORT_GPUVIRT_VALIDATION)
    PVRSRV_ERROR (*pfnPagesAllocGPV)(
        PHYS_HEAP *psPhysHeap,
        size_t uiSize,
        PG_HANDLE *psMemHandle,
        IMG_DEV_PHYADDR *psDevPAddr,
        IMG_UINT32 ui32OSid,
        IMG_PID uiPid);
#endif

} PHEAP_IMPL_FUNCS;

函数表作用

  1. 多态实现: 不同堆类型提供不同实现
  2. 接口统一: 上层代码无需关心具体实现
  3. 可扩展: 添加新堆类型只需实现函数表
  4. 可选功能: 不需要的函数可为NULL

实现映射示例

UMA堆 → PhysmemOSMEM实现
    pfnCreatePMR    → PhysmemNewOSRamBackedPMR
    pfnPagesAlloc   → PhysmemOSMemPagesAlloc
    pfnPagesFree    → PhysmemOSMemPagesFree
    pfnPagesMap     → OSMapPhysToLin
    pfnPagesUnMap   → OSUnMapPhysToLin

LMA堆 → PhysmemLMA实现
    pfnCreatePMR    → PhysmemNewLocalMemPMR
    pfnPagesAlloc   → PhysmemLMAPagesAlloc
    pfnPagesFree    → PhysmemLMAPagesFree
    pfnGetDevPAddr  → PhysmemLMAGetDevPAddr
    pfnGetCPUPAddr  → PhysmemLMAGetCPUPAddr

DLM堆 → PhysmemDLM实现
    pfnCreatePMB    → PhysmemDLMCreatePMB
    pfnDestroyData  → PhysmemDLMDestroy

IMA堆 → PhysmemIMA实现
    pfnCreatePMR           → PhysmemIMACreatePMR
    pfnGetHeapDLMBacking   → PhysmemIMAGetDLMBacking
    pfnGetHeapSpansStringIter → PhysmemIMAGetSpansIter

初始化流程

整体初始化流程图

PhysHeapInitDeviceHeaps
    |
    ├──[1]── OSLockCreate
    |        创建 hPhysHeapLock 保护锁
    |
    ├──[2]── PVRSRVValidatePhysHeapConfig
    |        ├─ 检查至少有一个堆配置
    |        ├─ 验证使用标志无重复
    |        ├─ 验证默认堆大小 >= 32MB
    |        ├─ 验证IMA链接到有效DLM
    |        └─ 验证DLM大小 >= PMB大小
    |
    ├──[3]── PhysHeapCreateDeviceHeapsFromConfigs
    |        |
    |        ├──[3.1]── PhysHeapCreateDLMIMAHeapsFromConfig
    |        |          ├─ 遍历创建所有DLM堆
    |        |          └─ 为每个DLM创建关联的IMA堆
    |        |
    |        ├──[3.2]── 遍历配置创建其他堆
    |        |          ├─ HeapCfgUsedByPVRLayer检查
    |        |          └─ PhysHeapCreateHeapFromConfig
    |        |                 ├─ UMA → PhysmemCreateHeapOSMEM
    |        |                 ├─ LMA → PhysmemCreateHeapLMA
    |        |                 ├─ DMA → PhysmemCreateHeapLMA
    |        |                 └─ WRAP → PhysmemCreateHeapOSMEM
    |        |
    |        └──[3.3]── PVRSRVRegisterDeviceDbgRequestNotify
    |                   注册调试请求通知
    |
    ├──[4]── 循环获取堆句柄 
    |        for (ePhysHeap = DEFAULT+1; ePhysHeap < LAST; ePhysHeap++)
    |            ├─ PhysHeapAcquiredByPVRLayer 检查
    |            └─ PhysHeapAcquireByID
    |                   ├─ _PhysHeapFindHeapOrFallback
    |                   ├─ ui32RefCount++
    |                   └─ 缓存到 apsPhysHeap[ePhysHeap]
    |
    ├──[5]── PhysHeapValidateDefaultHeapExists 
    |        验证DEFAULT堆存在且正确
    |
    └──[6]── PhysHeapMMUPxSetup 
             ├─ PhysHeapAcquireByID(eDefaultHeap)
             ├─ 设置 psMMUPhysHeap
             └─ CreateGpuVirtValArenas (GPUVIRT_VALIDATION)

详细步骤分析

步骤1: 创建保护锁

eError = OSLockCreate(&psDeviceNode->hPhysHeapLock);
PVR_LOG_RETURN_IF_ERROR(eError, "OSLockCreate");

作用:

  • 保护物理堆链表操作
  • 保护引用计数修改
  • 确保线程安全

步骤2: 验证堆配置

static PVRSRV_ERROR PVRSRVValidatePhysHeapConfig(PVRSRV_DEVICE_CONFIG *psDevConfig)
{
    IMG_UINT32 ui32FlagsAccumulate = 0;
    IMG_UINT32 i;

    // [1] 必须至少有一个堆配置
    PVR_LOG_RETURN_IF_FALSE(psDevConfig->ui32PhysHeapCount > 0,
                            "Device config must specify at least one phys heap config.",
                            PVRSRV_ERROR_PHYSHEAP_CONFIG);

    for (i = 0; i < psDevConfig->ui32PhysHeapCount; i++)
    {
        const PHYS_HEAP_USAGE_FLAGS uiDuplicateFlags = PHYS_HEAP_USAGE_DLM;
        PHYS_HEAP_CONFIG *psHeapConf = &psDevConfig->pasPhysHeaps[i];

        // [2] 必须指定使用标志
        PVR_LOG_RETURN_IF_FALSE_VA(psHeapConf->ui32UsageFlags != 0,
                                   PVRSRV_ERROR_PHYSHEAP_CONFIG,
                                   "Phys heap config %d: must specify usage flags.", i);

        // [3] 检查标志重复(DLM除外)
        PVR_LOG_RETURN_IF_FALSE_VA(
            ((ui32FlagsAccumulate & ~uiDuplicateFlags) & psHeapConf->ui32UsageFlags) == 0,
            PVRSRV_ERROR_PHYSHEAP_CONFIG,
            "Phys heap config %d: duplicate usage flags.", i);

        ui32FlagsAccumulate |= psHeapConf->ui32UsageFlags;

        // [4] 检查默认堆大小
        if (BITMASK_ANY((1U << psDevConfig->eDefaultHeap), PHYS_HEAP_USAGE_MASK) &&
            BITMASK_ANY((1U << psDevConfig->eDefaultHeap), psHeapConf->ui32UsageFlags))
        {
            switch (psHeapConf->eType)
            {
                case PHYS_HEAP_TYPE_LMA:
                {
                    if (psHeapConf->uConfig.sLMA.uiSize < PVRSRV_MIN_DEFAULT_LMA_PHYS_HEAP_SIZE)
                    {
                        PVR_DPF((PVR_DBG_ERROR, 
                                "Size of default heap is 0x%" IMG_UINT64_FMTSPECX
                                " (recommended minimum heap size is 0x%" IMG_UINT64_FMTSPECX ")",
                                psHeapConf->uConfig.sLMA.uiSize,
                                PVRSRV_MIN_DEFAULT_LMA_PHYS_HEAP_SIZE));
                    }
                    break;
                }
                // ... 其他类型检查
            }
        }

#if defined(PVRSRV_ENABLE_DYNAMIC_PHYSHEAPS)
        // [5] DLM堆验证
        if (psHeapConf->eType == PHYS_HEAP_TYPE_DLM)
        {
            // 必须设置DLM标志
            PVR_LOG_RETURN_IF_FALSE_VA(
                (psHeapConf->ui32UsageFlags & PHYS_HEAP_USAGE_DLM) == PHYS_HEAP_USAGE_DLM,
                PVRSRV_ERROR_PHYSHEAP_CONFIG,
                "Phys heap config %d: DLM heap must specify the DLM usage flag.", i);

            // DLM大小必须 >= PMB大小
            PVR_LOG_RETURN_IF_FALSE_VA(
                psHeapConf->uConfig.sDLM.uiSize >= psHeapConf->uConfig.sDLM.ui32Log2PMBSize,
                PVRSRV_ERROR_PHYSHEAP_CONFIG,
                "Phys heap config %d: Size of DLM heap is 0x%"IMG_UINT64_FMTSPECX
                " but the PMB size is 0x%" IMG_UINT64_FMTSPECX
                ". The total size must be greater than or equal to the PMB size.",
                i, psHeapConf->uConfig.sDLM.uiSize,
                IMG_UINT64_C(1) << psHeapConf->uConfig.sDLM.ui32Log2PMBSize);
        }
        // [6] IMA堆必须指向有效的DLM堆
        if (psHeapConf->eType == PHYS_HEAP_TYPE_IMA)
        {
            PVR_LOG_RETURN_IF_FALSE_VA(
                psHeapConf->uConfig.sIMA.uiDLMHeapIdx < psDevConfig->ui32PhysHeapCount,
                PVRSRV_ERROR_PHYSHEAP_CONFIG,
                "Phys heap config %d: IMA heap is trying to link to a DLM heap out of bounds. "
                "Requested Heap Index: %d, Heap Array Count: %d",
                i, psHeapConf->uConfig.sIMA.uiDLMHeapIdx, psDevConfig->ui32PhysHeapCount);

            PVR_LOG_RETURN_IF_FALSE_VA(
                psDevConfig->pasPhysHeaps[psHeapConf->uConfig.sIMA.uiDLMHeapIdx].eType == PHYS_HEAP_TYPE_DLM,
                PVRSRV_ERROR_PHYSHEAP_CONFIG,
                "Phys heap config %d: IMA heap is trying to link to a NON-DLM heap type. "
                "Requested Heap Idx: %d, Heap Type: %d",
                i, psHeapConf->uConfig.sIMA.uiDLMHeapIdx,
                psDevConfig->pasPhysHeaps[psHeapConf->uConfig.sIMA.uiDLMHeapIdx].eType);
        }
#endif
    }
    // [7] 验证默认堆配置
    if (psDevConfig->eDefaultHeap == PVRSRV_PHYS_HEAP_GPU_LOCAL)
    {
        PVR_LOG_RETURN_IF_FALSE(
            ((ui32FlagsAccumulate & PHYS_HEAP_USAGE_GPU_LOCAL) != 0),
            "Device config must specify GPU local phys heap config.",
            PVRSRV_ERROR_PHYSHEAP_CONFIG);
    }
    else if (psDevConfig->eDefaultHeap == PVRSRV_PHYS_HEAP_CPU_LOCAL)
    {
        PVR_LOG_RETURN_IF_FALSE(
            ((ui32FlagsAccumulate & PHYS_HEAP_USAGE_CPU_LOCAL) != 0),
            "Device config must specify CPU local phys heap config.",
            PVRSRV_ERROR_PHYSHEAP_CONFIG);
    }

    return PVRSRV_OK;
}

验证检查清单:

检查项 代码行 说明
✓ 至少一个堆 770 ui32PhysHeapCount > 0
✓ 使用标志非空 777 ui32UsageFlags != 0
✓ 标志无重复 784 除DLM外不能重复
✓ 默认堆大小 792 LMA ≥ 32MB
✓ DLM标志 837 DLM必须设置DLM标志
✓ DLM大小 843 大小 ≥ PMB大小
✓ IMA链接 857 链接到有效DLM
✓ 默认堆存在 879 GPU_LOCAL或CPU_LOCAL存在

步骤3.1: 创建DLM和IMA堆

static PVRSRV_ERROR
PhysHeapCreateDLMIMAHeapsFromConfig(PVRSRV_DEVICE_NODE *psDevNode,
                                    PHYS_HEAP_CONFIG *pasConfigs,
                                    IMG_UINT32 ui32NumConfigs)
{
    PVRSRV_ERROR eError;
    IMG_UINT32 uiDLMIdx, uiIMAIdx;
    PHYS_HEAP_POLICY uiIMAPolicy = OSIsMapPhysNonContigSupported() ? 
                                   PHYS_HEAP_POLICY_ALLOC_ALLOW_NONCONTIG : 
                                   PHYS_HEAP_POLICY_DEFAULT;
    PHYS_HEAP *psDLMHeap;

    // [1] 遍历配置,创建所有DLM堆
    for (uiDLMIdx = 0; uiDLMIdx < ui32NumConfigs; uiDLMIdx++)
    {
        if (pasConfigs[uiDLMIdx].eType == PHYS_HEAP_TYPE_DLM)
        {
            IMG_UINT32 uiHeapCount = 0;

            // 创建DLM堆
            eError = PhysmemCreateHeapDLM(psDevNode,
                                          PHYS_HEAP_POLICY_DEFAULT,
                                          &pasConfigs[uiDLMIdx],
                                          pasConfigs[uiDLMIdx].uConfig.sDLM.pszHeapName,
                                          &psDLMHeap);
            PVR_LOG_RETURN_IF_ERROR(eError, "PhysmemCreateHeapDLM");

            // [2] 创建与此DLM关联的所有IMA堆
            for (uiIMAIdx = 0; uiIMAIdx < ui32NumConfigs; uiIMAIdx++)
            {
                if (pasConfigs[uiIMAIdx].eType == PHYS_HEAP_TYPE_IMA &&
                    pasConfigs[uiIMAIdx].uConfig.sIMA.uiDLMHeapIdx == uiDLMIdx)
                {
                    eError = PhysmemCreateHeapIMA(psDevNode,
                                                  uiIMAPolicy,
                                                  &pasConfigs[uiIMAIdx],
                                                  pasConfigs[uiIMAIdx].uConfig.sIMA.pszHeapName,
                                                  psDLMHeap,  // 链接到DLM
                                                  pasConfigs[uiDLMIdx].uConfig.sDLM.ui32Log2PMBSize,
                                                  NULL);
                    PVR_LOG_RETURN_IF_ERROR(eError, "PhysmemCreateHeapIMA");
                    uiHeapCount++;
                }
            }

            // [3] 检查DLM是否有连接的IMA堆
            if (uiHeapCount == 0)
            {
                PVR_DPF((PVR_DBG_WARNING, 
                        "DLM phys heap config %d: No connected IMA heaps. "
                        "Phys heap will go unused.", uiDLMIdx));
            }
        }
    }

    return PVRSRV_OK;
}

DLM/IMA关系图:

DLM堆 (Defrag Local Memory)
    |
    | 管理大块物理内存
    | PMB Size: 例如 256MB
    | Total Size: 例如 2GB
    |
    +---[导出PMB]---> IMA堆 #1 (Imported Memory Architecture)
    |                  ├─ 导入PMB用于分配
    |                  └─ 支持非连续分配
    |
    +---[导出PMB]---> IMA堆 #2
    |                  └─ 可有不同用途标志
    |
    +---[导出PMB]---> IMA堆 #3
                       └─ 共享同一个DLM源

为什么必须先创建DLM:
1. IMA堆在创建时需要DLM堆的指针
2. IMA堆通过pfnGetHeapDLMBacking获取DLM引用
3. IMA分配内存时向DLM请求PMB


步骤3.2: 创建其他堆类型

for (i = 0; i < ui32NumConfigs; i++)
{
    // 检查是否由PVR层管理
    if (HeapCfgUsedByPVRLayer(&pasConfigs[i]))
    {
        eError = PhysHeapCreateHeapFromConfig(psDevNode, &pasConfigs[i], NULL);
        PVR_LOG_RETURN_IF_ERROR(eError, "PhysmemCreateHeap");
    }
}

HeapCfgUsedByPVRLayer函数

static IMG_BOOL HeapCfgUsedByPVRLayer(PHYS_HEAP_CONFIG *psConfig)
{
    PVRSRV_PHYS_HEAP eHeap;
    IMG_BOOL bPVRHeap = IMG_FALSE;

    // 遍历所有堆类型,检查是否有任何标志由PVR层处理
    for (eHeap = PVRSRV_PHYS_HEAP_DEFAULT;
         eHeap < PVRSRV_PHYS_HEAP_LAST;
         eHeap++)
    {
        if ((BIT_ISSET(psConfig->ui32UsageFlags, eHeap) &&
             PhysHeapCreatedByPVRLayer(eHeap)))
        {
            bPVRHeap = IMG_TRUE;
            break;
        }
    }

    return bPVRHeap;
}

PhysHeapCreateHeapFromConfig函数

PVRSRV_ERROR
PhysHeapCreateHeapFromConfig(PVRSRV_DEVICE_NODE *psDevNode,
                             PHYS_HEAP_CONFIG *psConfig,
                             PHYS_HEAP **ppsPhysHeap)
{
    PVRSRV_ERROR eResult;

    // [1] UMA或WRAP类型 → 使用系统内存
    if (psConfig->eType == PHYS_HEAP_TYPE_UMA
#if defined(SUPPORT_WRAP_EXTMEMOBJECT)
        || psConfig->eType == PHYS_HEAP_TYPE_WRAP
#endif
        )
    {
        eResult = PhysmemCreateHeapOSMEM(psDevNode,
                                         PHYS_HEAP_POLICY_ALLOC_ALLOW_NONCONTIG,
                                         psConfig,
                                         ppsPhysHeap);
    }
    // [2] LMA或DMA类型 → 使用本地内存
    else if ((psConfig->eType == PHYS_HEAP_TYPE_LMA) ||
             (psConfig->eType == PHYS_HEAP_TYPE_DMA))
    {
        PHYS_HEAP_POLICY uiHeapPolicy;

        // 获取LMA策略
        if (psDevNode->pfnPhysHeapGetLMAPolicy != NULL)
        {
            uiHeapPolicy = psDevNode->pfnPhysHeapGetLMAPolicy(
                psConfig->ui32UsageFlags, psDevNode);
        }
        else
        {
            uiHeapPolicy = OSIsMapPhysNonContigSupported() ?
                           PHYS_HEAP_POLICY_ALLOC_ALLOW_NONCONTIG :
                           PHYS_HEAP_POLICY_DEFAULT;
        }

        eResult = PhysmemCreateHeapLMA(psDevNode,
                                       uiHeapPolicy,
                                       psConfig,
                                       (psConfig->eType == PHYS_HEAP_TYPE_LMA) ?
                                        "GPU LMA (Sys)" :
                                        "GPU LMA DMA (Sys)",
                                       ppsPhysHeap);
    }
    // [3] DLM或IMA → 已经创建,跳过
    else if ((psConfig->eType == PHYS_HEAP_TYPE_DLM) ||
             (psConfig->eType == PHYS_HEAP_TYPE_IMA))
    {
        eResult = PVRSRV_OK;
    }
    else
    {
        PVR_DPF((PVR_DBG_ERROR, "%s Invalid phys heap type: %d",
                 __func__, psConfig->eType));
        eResult = PVRSRV_ERROR_INVALID_PARAMS;
    }

    return eResult;
}

堆创建映射表:

配置类型 创建函数 实现位置 策略
UMA PhysmemCreateHeapOSMEM physmem_osmem.c 非连续
LMA PhysmemCreateHeapLMA physmem_lma.c 可配置
DMA PhysmemCreateHeapLMA physmem_lma.c 可配置
DLM PhysmemCreateHeapDLM physmem_dlm.c 默认
IMA PhysmemCreateHeapIMA physmem_ima.c 非连续
WRAP PhysmemCreateHeapOSMEM physmem_osmem.c 非连续

步骤3.3: 注册调试请求

eError = PVRSRVRegisterDeviceDbgRequestNotify(&psDevNode->hPhysHeapDbgReqNotify,
                                              psDevNode,
                                              PhysHeapDebugRequest,
                                              DEBUG_REQUEST_SYS,
                                              psDevNode);
PVR_LOG_RETURN_IF_ERROR(eError, "PVRSRVRegisterDeviceDbgRequestNotify");

PhysHeapDebugRequest函数

static void PhysHeapDebugRequest(PVRSRV_DBGREQ_HANDLE pfnDbgRequestHandle,
                                  IMG_UINT32 ui32VerbLevel,
                                  DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf,
                                  void *pvDumpDebugFile)
{
    PPVRSRV_DEVICE_NODE psDeviceNode = (PPVRSRV_DEVICE_NODE)pfnDbgRequestHandle;
    PHYS_HEAP *psPhysHeap;

    PVR_UNREFERENCED_PARAMETER(ui32VerbLevel);

    PVR_LOG_RETURN_VOID_IF_FALSE(psDeviceNode != NULL,
                                 "Phys Heap debug request failed. psDeviceNode was NULL");

    PVR_DUMPDEBUG_LOG("------[ Device ID: %d - Phys Heaps ]------",
                      psDeviceNode->sDevId.i32KernelDeviceID);

    // 遍历所有物理堆,打印信息
    for (psPhysHeap = psDeviceNode->psPhysHeapList; 
         psPhysHeap != NULL; 
         psPhysHeap = psPhysHeap->psNext)
    {
        PVRSRV_ERROR eError = PVRSRV_OK;
        IMG_BOOL bDefaultHeap = psPhysHeap == 
            psDeviceNode->apsPhysHeap[psDeviceNode->psDevConfig->eDefaultHeap];

        eError = PhysHeapPrintHeapProperties(psPhysHeap,
                                             bDefaultHeap,
                                             pfnDumpDebugPrintf,
                                             pvDumpDebugFile);
        if (eError != PVRSRV_OK)
        {
            PVR_LOG_ERROR(eError, "PhysHeapCreateProperties");
            continue;
        }
    }

#if defined(SUPPORT_PMR_DEFERRED_FREE)
    OSLockAcquire(psDeviceNode->hPMRZombieListLock);
    PVR_DUMPDEBUG_LOG("PMR Zombie Count: %u, PMR Zombie Count In Cleanup: %u",
                      psDeviceNode->uiPMRZombieCount,
                      psDeviceNode->uiPMRZombieCountInCleanup);
    OSLockRelease(psDeviceNode->hPMRZombieListLock);
#endif
    PVR_DUMPDEBUG_LOG("PMR Live Count: %d", PMRGetLiveCount());
}

调试输出示例:

------[ Device ID: 0 - Phys Heaps ]------
0xffff88001234 -> PdMs: GPU_LOCAL, Type: LMA, default, 
    CPU PA Base: 0x100000000, GPU PA Base: 0x0, 
    Usage Flags: 0x00000002 (GPU_LOCAL), Refs: 3, 
    Free Size: 1073741824B, Total Size: 2147483648B

0xffff88005678 -> PdMs: SYSMEM, Type: UMA, -, 
    Usage Flags: 0x00000001 (CPU_LOCAL), Refs: 1, 
    Free Size: 4294967296B, Total Size: 8589934592B

PMR Live Count: 42

步骤4: 获取堆句柄

for (ePhysHeap = (PVRSRV_PHYS_HEAP)(PVRSRV_PHYS_HEAP_DEFAULT+1); 
     ePhysHeap < PVRSRV_PHYS_HEAP_LAST; 
     ePhysHeap++)
{
    if (PhysHeapAcquiredByPVRLayer(ePhysHeap))
    {
        eError = PhysHeapAcquireByID(ePhysHeap, psDevNode, 
                                     &psDevNode->apsPhysHeap[ePhysHeap]);
        PVR_LOG_GOTO_IF_ERROR(eError, "PhysHeapAcquireByID", ErrorDeinit);
    }
}

PhysHeapAcquireByID函数

PVRSRV_ERROR PhysHeapAcquireByID(PVRSRV_PHYS_HEAP eDevPhysHeap,
                                 PPVRSRV_DEVICE_NODE psDevNode,
                                 PHYS_HEAP **ppsPhysHeap)
{
    PHYS_HEAP *psPhysHeap;
    PVRSRV_ERROR eError = PVRSRV_OK;

    PVR_LOG_RETURN_IF_INVALID_PARAM(eDevPhysHeap < PVRSRV_PHYS_HEAP_LAST, "eDevPhysHeap");
    PVR_LOG_RETURN_IF_INVALID_PARAM(psDevNode != NULL, "psDevNode");

    PVR_DPF_ENTERED1(ui32Flags);

    // [1] 加锁保护
    OSLockAcquire(psDevNode->hPhysHeapLock);

    // [2] 查找堆(支持回退)
    psPhysHeap = _PhysHeapFindHeapOrFallback(eDevPhysHeap, psDevNode);

    if (psPhysHeap != NULL)
    {
        // [3] 增加引用计数
        psPhysHeap->ui32RefCount++;
        PHYSHEAP_REFCOUNT_PRINT("%s: Heap %p, refcount = %d",
                                __func__, psPhysHeap, psPhysHeap->ui32RefCount);

        // [4] 第一次获取时统计用户可分配堆
        if (psPhysHeap->ui32RefCount == 1)
        {
            _PhysHeapCountUserModeHeaps(psDevNode, BIT(eDevPhysHeap));
        }
    }
    else
    {
        eError = PVRSRV_ERROR_PHYSHEAP_ID_INVALID;
    }

    // [5] 释放锁
    OSLockRelease(psDevNode->hPhysHeapLock);

    *ppsPhysHeap = psPhysHeap;
    PVR_DPF_RETURN_RC1(eError, *ppsPhysHeap);
}

_PhysHeapFindHeapOrFallback函数

static PHYS_HEAP * _PhysHeapFindHeapOrFallback(PVRSRV_PHYS_HEAP ePhysHeap,
                                                PPVRSRV_DEVICE_NODE psDevNode)
{
    PHYS_HEAP *psPhysHeapNode = psDevNode->psPhysHeapList;
    PVRSRV_PHYS_HEAP eFallback;

    // [1] DEFAULT别名转换为实际默认堆
    if (ePhysHeap == PVRSRV_PHYS_HEAP_DEFAULT)
    {
        ePhysHeap = psDevNode->psDevConfig->eDefaultHeap;
    }

    // [2] 检查缓存
    if (psDevNode->apsPhysHeap[ePhysHeap] != NULL)
    {
        return psDevNode->apsPhysHeap[ePhysHeap];
    }

    // [3] 遍历堆链表查找
    while (psPhysHeapNode)
    {
        if (BIT_ISSET(psPhysHeapNode->ui32UsageFlags, ePhysHeap))
        {
            return psPhysHeapNode;
        }

        psPhysHeapNode = psPhysHeapNode->psNext;
    }

    // [4] 未找到,使用回退堆
    eFallback = gasHeapProperties[ePhysHeap].eFallbackHeap;
    if (ePhysHeap == eFallback)
    {
        return NULL;  // 回退到自己,终止递归
    }
    else
    {
        return _PhysHeapFindHeapOrFallback(eFallback, psDevNode);  // 递归查找
    }
}

查找流程图:

请求堆: GPU_PRIVATE (ID=3)
    |
    ├─[1]─ 检查是否是DEFAULT? → 否
    |
    ├─[2]─ 检查缓存 apsPhysHeap[3]? → 未缓存
    |
    ├─[3]─ 遍历链表 psPhysHeapList
    |       ├─ Heap #1: ui32UsageFlags & (1<<3)? → 否
    |       ├─ Heap #2: ui32UsageFlags & (1<<3)? → 否
    |       └─ Heap #3: ui32UsageFlags & (1<<3)? → 未找到
    |
    └─[4]─ 使用Fallback: GPU_LOCAL (ID=2)
            |
            ├─[1]─ 非DEFAULT
            ├─[2]─ 检查缓存 apsPhysHeap[2]? → 命中!
            └─ 返回 apsPhysHeap[2]

回退链示例:

GPU_SECURE (7)     → GPU_LOCAL (2)   → DEFAULT (0)
GPU_PRIVATE (3)    → GPU_LOCAL (2)   → DEFAULT (0)
GPU_COHERENT (6)   → GPU_LOCAL (2)   → DEFAULT (0)
FW_CODE (9)        → FW_MAIN (4)     → GPU_LOCAL (2) → DEFAULT (0)
FW_PRIV_DATA (10)  → FW_MAIN (4)     → GPU_LOCAL (2) → DEFAULT (0)
FW_PREMAP0 (12)    → FW_PREMAP0 (12) → 终止(不回退)

步骤5: 验证默认堆

if (PhysHeapValidateDefaultHeapExists(psDevNode))
{
    PVR_LOG_GOTO_IF_ERROR(eError, "PhysHeapValidateDefaultHeapExists", ErrorDeinit);
}

PhysHeapValidateDefaultHeapExists函数

IMG_BOOL PhysHeapValidateDefaultHeapExists(PPVRSRV_DEVICE_NODE psDevNode)
{
    PVRSRV_PHYS_HEAP eDefaultHeap = psDevNode->psDevConfig->eDefaultHeap;

    return ((psDevNode->apsPhysHeap[PVRSRV_PHYS_HEAP_DEFAULT] != NULL) &&
            ((psDevNode->apsPhysHeap[PVRSRV_PHYS_HEAP_DEFAULT] ==
              psDevNode->apsPhysHeap[eDefaultHeap])));
}

验证条件:
1. apsPhysHeap[DEFAULT] 不为NULL
2. apsPhysHeap[DEFAULT] 等于 apsPhysHeap[实际默认堆]

示例:

配置: eDefaultHeap = GPU_LOCAL (2)

验证前:
apsPhysHeap[0] (DEFAULT) = NULL
apsPhysHeap[2] (GPU_LOCAL) = 0xffff88001234

验证失败!

验证通过情况:
apsPhysHeap[0] (DEFAULT) = 0xffff88001234
apsPhysHeap[2] (GPU_LOCAL) = 0xffff88001234
两者指向同一个PHYS_HEAP对象

步骤6: MMU设置

eError = PhysHeapMMUPxSetup(psDevNode);
PVR_LOG_GOTO_IF_ERROR(eError, "PhysHeapMMUPxSetup", ErrorDeinit);

PhysHeapMMUPxSetup函数

static PVRSRV_ERROR PhysHeapMMUPxSetup(PPVRSRV_DEVICE_NODE psDevNode)
{
    PHYS_HEAP_TYPE eHeapType;
    PVRSRV_ERROR eError;

    // [1] 获取默认堆用于MMU页表
    eError = PhysHeapAcquireByID(psDevNode->psDevConfig->eDefaultHeap,
                                 psDevNode, &psDevNode->psMMUPhysHeap);
    PVR_LOG_GOTO_IF_ERROR(eError, "PhysHeapAcquireByID", ErrorDeinit);

    eHeapType = PhysHeapGetType(psDevNode->psMMUPhysHeap);

    // [2] 根据堆类型设置
    if (eHeapType == PHYS_HEAP_TYPE_UMA)
    {
        PVR_DPF((PVR_DBG_MESSAGE, 
                "%s: GPU physical heap uses OS System memory (UMA)", __func__));

#if defined(SUPPORT_GPUVIRT_VALIDATION)
        // UMA不支持虚拟化验证
        PVR_DPF((PVR_DBG_ERROR, 
                "%s: Virtualisation Validation builds are currently only "
                "supported on systems with local memory (LMA).", __func__));
        eError = PVRSRV_ERROR_NOT_SUPPORTED;
        goto ErrorDeinit;
#endif
    }
    else
    {
        PVR_DPF((PVR_DBG_MESSAGE, 
                "%s: GPU physical heap uses local memory managed by the driver (LMA)", 
                __func__));

#if defined(SUPPORT_GPUVIRT_VALIDATION)
        // [3] 创建GPU虚拟化验证arenas
        eError = CreateGpuVirtValArenas(psDevNode);
        PVR_LOG_GOTO_IF_ERROR(eError, "CreateGpuVirtValArenas", ErrorDeinit);
#endif
    }

    return PVRSRV_OK;
ErrorDeinit:
    return eError;
}

MMU页表分配:
- MMU页表(Px: P0, P1, P2等)从psMMUPhysHeap分配
- 通常使用默认堆
- UMA系统:从系统内存分配
- LMA系统:从GPU本地内存分配

GPUVIRT_VALIDATION

#if defined(SUPPORT_GPUVIRT_VALIDATION)
static PVRSRV_ERROR CreateGpuVirtValArenas(PVRSRV_DEVICE_NODE *psDeviceNode)
{
    // 计算每个OSID的私有区域大小
    uPrivateRASize = uiGPULocalSize - GPUVIRT_SIZEOF_SHARED;
    uPrivateRASize /= GPUVIRT_VALIDATION_NUM_OS;  // 例如8个OS
    uPrivateRASize = uPrivateRASize & ~(OSGetPageSize() - 1);  // 页对齐

    uSharedRASize = uiGPULocalSize - uPrivateRASize * GPUVIRT_VALIDATION_NUM_OS;

    // 为每个OSID创建私有arena
    FOREACH_VALIDATION_OSID(i)
    {
        psDeviceNode->psOSidSubArena[i] = RA_Create_With_Span(
            aszOSRAName,
            OSGetPageShift(),
            0,
            uPrivateRABase,
            uPrivateRASize,
            RA_POLICY_DEFAULT);

        // 设置硬件防火墙区域
        aui64OSidMin[GPUVIRT_VAL_REGION_SECURE][i] = uPrivateRABase;
        aui64OSidMax[GPUVIRT_VAL_REGION_SECURE][i] = uPrivateRABase + uPrivateRASize - 1ULL;
        uPrivateRABase += uPrivateRASize;
    }

    // 创建共享arena
    psDeviceNode->psOSSharedArena = RA_Create_With_Span("GPUVIRT_SHARED",
                                                        OSGetPageShift(),
                                                        0,
                                                        uSharedRABase,
                                                        uSharedRASize,
                                                        RA_POLICY_DEFAULT);

    // 初始化硬件防火墙
    if (psDeviceNode->psDevConfig->pfnSysInitFirewall != NULL)
    {
        psDeviceNode->psDevConfig->pfnSysInitFirewall(
            psDeviceNode->psDevConfig->hSysData, 
            aui64OSidMin, 
            aui64OSidMax);
    }

    return PVRSRV_OK;
}
#endif

GPU虚拟化内存布局:

GPU Local Memory (例如 2GB)
┌─────────────────────────────────────────────────────────────┐
│ OSID 0 Private │ 256MB                                      │
├─────────────────────────────────────────────────────────────┤
│ OSID 1 Private │ 256MB                                      │
├─────────────────────────────────────────────────────────────┤
│ OSID 2 Private │ 256MB                                      │
├─────────────────────────────────────────────────────────────┤
│ OSID 3 Private │ 256MB                                      │
├─────────────────────────────────────────────────────────────┤
│ OSID 4 Private │ 256MB                                      │
├─────────────────────────────────────────────────────────────┤
│ OSID 5 Private │ 256MB                                      │
├─────────────────────────────────────────────────────────────┤
│ OSID 6 Private │ 256MB                                      │
├─────────────────────────────────────────────────────────────┤
│ OSID 7 Private │ 256MB                                      │
├─────────────────────────────────────────────────────────────┤
│ Shared Region  │ 96MB (All OSIDs can access)               │
└─────────────────────────────────────────────────────────────┘

硬件防火墙规则:
- OSID 0 (Host): 可访问所有区域
- OSID 1-7 (Guest): 只能访问各自私有区域 + 共享区域

初始化流程完整时序图

Driver Init
    │
    ├──> PhysHeapInitDeviceHeaps()
    │       │
    │       ├──> [1] OSLockCreate(&hPhysHeapLock)
    │       │
    │       ├──> [2] PVRSRVValidatePhysHeapConfig()
    │       │       ├─ 检查堆数量 > 0
    │       │       ├─ 验证使用标志
    │       │       ├─ 验证默认堆大小
    │       │       ├─ 验证DLM配置
    │       │       └─ 验证IMA链接
    │       │
    │       ├──> [3] PhysHeapCreateDeviceHeapsFromConfigs()
    │       │       │
    │       │       ├──> [3.1] PhysHeapCreateDLMIMAHeapsFromConfig()
    │       │       │       ├─ for each DLM config:
    │       │       │       │   ├─ PhysmemCreateHeapDLM()
    │       │       │       │   │   ├─ PhysHeapCreate()
    │       │       │       │   │   ├─ 初始化RA (Resource Allocator)
    │       │       │       │   │   └─ 注册到链表
    │       │       │       │   │
    │       │       │       │   └─ for each linked IMA:
    │       │       │       │       └─ PhysmemCreateHeapIMA()
    │       │       │       │           ├─ PhysHeapCreate()
    │       │       │       │           ├─ 链接到DLM堆
    │       │       │       │           └─ 注册到链表
    │       │       │       │
    │       │       ├──> [3.2] for each other config:
    │       │       │       ├─ HeapCfgUsedByPVRLayer()?
    │       │       │       └─ PhysHeapCreateHeapFromConfig()
    │       │       │           ├─ UMA → PhysmemCreateHeapOSMEM()
    │       │       │           ├─ LMA → PhysmemCreateHeapLMA()
    │       │       │           └─ DMA → PhysmemCreateHeapLMA()
    │       │       │
    │       │       └──> [3.3] PVRSRVRegisterDeviceDbgRequestNotify()
    │       │
    │       ├──> [4] for (ePhysHeap = DEFAULT+1; ePhysHeap < LAST; ePhysHeap++)
    │       │       └─ if (PhysHeapAcquiredByPVRLayer(ePhysHeap))
    │       │           └─ PhysHeapAcquireByID()
    │       │               ├─ OSLockAcquire(hPhysHeapLock)
    │       │               ├─ _PhysHeapFindHeapOrFallback()
    │       │               │   ├─ 检查缓存
    │       │               │   ├─ 遍历链表
    │       │               │   └─ 递归查找fallback
    │       │               ├─ ui32RefCount++
    │       │               ├─ 缓存到apsPhysHeap[]
    │       │               └─ OSLockRelease(hPhysHeapLock)
    │       │
    │       ├──> [5] PhysHeapValidateDefaultHeapExists()
    │       │       └─ 验证 apsPhysHeap[DEFAULT] == apsPhysHeap[实际默认堆]
    │       │
    │       └──> [6] PhysHeapMMUPxSetup()
    │               ├─ PhysHeapAcquireByID(eDefaultHeap, &psMMUPhysHeap)
    │               ├─ if (UMA): 日志输出
    │               └─ if (LMA && GPUVIRT_VALIDATION):
    │                   └─ CreateGpuVirtValArenas()
    │                       ├─ 计算私有区域大小
    │                       ├─ 为每个OSID创建RA
    │                       ├─ 创建共享RA
    │                       └─ 初始化硬件防火墙
    │
    └──> 初始化完成

最终状态:
- psDevNode->psPhysHeapList: 所有堆的链表
- psDevNode->apsPhysHeap[]: 26个堆的快速访问缓存
- psDevNode->psMMUPhysHeap: MMU使用的堆
- psDevNode->hPhysHeapLock: 保护锁
- 所有堆引用计数 > 0

内存分配流程

PhysHeapCreatePMR 主流程

PVRSRV_ERROR PhysHeapCreatePMR(PHYS_HEAP *psPhysHeap,
                               struct _CONNECTION_DATA_ *psConnection,
                               IMG_DEVMEM_SIZE_T uiSize,
                               IMG_UINT32 ui32NumPhysChunks,
                               IMG_UINT32 ui32NumVirtChunks,
                               IMG_UINT32 *pui32MappingTable,
                               IMG_UINT32 uiLog2PageSize,
                               PVRSRV_MEMALLOCFLAGS_T uiFlags,
                               const IMG_CHAR *pszAnnotation,
                               IMG_PID uiPid,
                               PMR **ppsPMRPtr,
                               IMG_UINT32 ui32PDumpFlags,
                               PVRSRV_MEMALLOCFLAGS_T *puiOutFlags)
{
    PVRSRV_ERROR eError;
    const PHEAP_IMPL_FUNCS *psImplFuncs;
#if !defined(PVRSRV_PHYSHEAP_DISABLE_OOM_DEMOTION)
    IMG_UINT64 uiFreeBytes;
    PVRSRV_PHYS_HEAP eDemotionPhysIdx;
    PVRSRV_MEMALLOCFLAGS_T uiDemotionFlags = uiFlags;
    PVRSRV_PHYS_HEAP ePhysIdx = PVRSRV_GET_PHYS_HEAP_HINT(uiFlags);
    PHYS_HEAP *psDemotionHeap = NULL;

    PVR_ASSERT(ePhysIdx > PVRSRV_PHYS_HEAP_DEFAULT);
    PVR_ASSERT(ePhysIdx < PVRSRV_PHYS_HEAP_LAST);
#endif

    PVR_ASSERT(psPhysHeap != NULL);

    psImplFuncs = psPhysHeap->psImplFuncs;

    // [1] 尝试在指定堆上分配
    eError = psImplFuncs->pfnCreatePMR(psPhysHeap,
                                       psConnection,
                                       uiSize,
                                       ui32NumPhysChunks,
                                       ui32NumVirtChunks,
                                       pui32MappingTable,
                                       uiLog2PageSize,
                                       uiFlags,
                                       pszAnnotation,
                                       uiPid,
                                       ppsPMRPtr,
                                       ui32PDumpFlags);

#if !defined(PVRSRV_PHYSHEAP_DISABLE_OOM_DEMOTION)
    // [2] 记录OOM状态
    _LogOOMDetection(((IsOOMError(eError)) ? IMG_TRUE : IMG_FALSE), 
                     psPhysHeap, uiFlags);

    // [3] 如果成功,直接返回
    if (eError == PVRSRV_OK)
    {
        if (puiOutFlags)
        {
            *puiOutFlags = uiFlags;
        }
        return eError;
    }

    // [4] 如果不是OOM错误,返回
    PVR_LOG_RETURN_IF_FALSE((IsOOMError(eError)), 
                            "Failed to allocate PMR", eError);

    // [5] 如果设置了强制标志,不进行降级
    if (PVRSRV_CHECK_MANDATED_PHYSHEAP(uiFlags))
    {
        return eError;
    }

    // [6] 仅对CPU_LOCAL, GPU_LOCAL, GPU_PRIVATE进行降级
    if (ePhysIdx > PVRSRV_PHYS_HEAP_GPU_PRIVATE)
    {
        return eError;
    }

    eError = PVRSRV_ERROR_OUT_OF_MEMORY;

    // [7] 降级循环:从当前堆向下降级
    for (eDemotionPhysIdx = (PVRSRV_PHYS_HEAP)(ePhysIdx-1); 
         eDemotionPhysIdx != PVRSRV_PHYS_HEAP_DEFAULT; 
         eDemotionPhysIdx--)
    {
        // 修改标志指向降级堆
        PVRSRV_CHANGE_PHYS_HEAP_HINT(eDemotionPhysIdx, uiDemotionFlags);

        // 警告:降级超过1级
        PVR_LOG_IF_FALSE_VA(PVR_DBG_MESSAGE,
                            (ePhysIdx-eDemotionPhysIdx < 2),
                            "Demoted from %s to CPU_LOCAL. "
                            "Expect performance to be affected!",
                            PVRSRVGetPhysHeapName(ePhysIdx));

        // 查找降级堆(不使用fallback)
        psDemotionHeap = _PhysHeapFindRealHeapNoFallback(eDemotionPhysIdx, 
                                                         psPhysHeap->psDevNode);

        // 堆不存在或与当前堆相同,跳过
        if (psDemotionHeap == NULL || psPhysHeap == psDemotionHeap)
        {
            continue;
        }

        // 检查降级堆是否有足够内存
        if (PhysHeapFreeMemCheck(psDemotionHeap, uiSize, &uiFreeBytes) != PVRSRV_OK)
        {
            _LogOOMDetection(IMG_TRUE, psDemotionHeap, uiDemotionFlags);
            continue;
        }

        // 尝试在降级堆上分配
        psImplFuncs = psDemotionHeap->psImplFuncs;
        eError = psImplFuncs->pfnCreatePMR(psDemotionHeap,
                                           psConnection,
                                           uiSize,
                                           ui32NumPhysChunks,
                                           ui32NumVirtChunks,
                                           pui32MappingTable,
                                           uiLog2PageSize,
                                           uiDemotionFlags,
                                           pszAnnotation,
                                           uiPid,
                                           ppsPMRPtr,
                                           ui32PDumpFlags);

        _LogOOMDetection(((IsOOMError(eError)) ? IMG_TRUE : IMG_FALSE), 
                         psDemotionHeap, uiDemotionFlags);

        // 降级成功
        if (eError == PVRSRV_OK)
        {
            if (puiOutFlags)
            {
                *puiOutFlags = uiDemotionFlags;
            }
            break;
        }
    }

    // [8] 报告最终结果
    if (eError == PVRSRV_OK)
    {
        PVR_LOG_VA(PVR_DBG_WARNING, 
                   "PhysHeap(%s) failed to allocate PMR. Demoted to %s",
                   PVRSRVGetPhysHeapName(ePhysIdx),
                   PVRSRVGetPhysHeapName(PVRSRV_GET_PHYS_HEAP_HINT(uiDemotionFlags)));
    }
    else
    {
        PVR_LOG_VA(PVR_DBG_ERROR, 
                   "Error raised %s : Unable to %s.",
                   PVRSRVGETERRORSTRING(eError),
                   (psDemotionHeap == NULL) ? "find heaps for demotion" :
                                              "allocate PMR via Demotion heap");
#if defined(SUPPORT_PMR_DEFERRED_FREE)
        PPVRSRV_DEVICE_NODE psDevNode = PhysHeapDeviceNode(psPhysHeap);
        OSLockAcquire(psDevNode->hPMRZombieListLock);
        PVR_LOG_VA(PVR_DBG_ERROR, 
                   "PMR Zombie Count: %u, PMR Zombie Count In Cleanup: %u",
                   psDevNode->uiPMRZombieCount,
                   psDevNode->uiPMRZombieCountInCleanup);
        OSLockRelease(psDevNode->hPMRZombieListLock);
#endif
    }
#endif
    return eError;
}

OOM降级机制详解

IsOOMError宏

#define IsOOMError(err) \
    ((err == PVRSRV_ERROR_PMR_FAILED_TO_ALLOC_PAGES) | \
     (err == PVRSRV_ERROR_OUT_OF_MEMORY) | \
     (err == PVRSRV_ERROR_PMR_TOO_LARGE))

_LogOOMDetection函数

static inline void _LogOOMDetection(IMG_BOOL isOOMDetected, 
                                    PHYS_HEAP *psPhysHeap, 
                                    PVRSRV_MEMALLOCFLAGS_T uiFlags)
{
    IMG_BOOL bExistingVal;
    PVRSRV_PHYS_HEAP ePhysHeap = PVRSRV_GET_PHYS_HEAP_HINT(uiFlags);

    PVR_ASSERT(psPhysHeap != NULL);
    PVR_ASSERT(ePhysHeap > PVRSRV_PHYS_HEAP_DEFAULT);
    PVR_ASSERT(ePhysHeap < PVRSRV_PHYS_HEAP_LAST);

    // 原子交换OOM状态
    bExistingVal = OSAtomicExchange(&psPhysHeap->sOOMDetected, isOOMDetected);

    // 状态变化时记录日志
    if (bExistingVal != isOOMDetected)
    {
        PVR_LOG(("Device: %d Physheap: %s OOM: %s",
                (psPhysHeap->psDevNode->sDevId.ui32InternalID),
                PVRSRVGetPhysHeapName(ePhysHeap),
                (isOOMDetected) ? "Detected" : "Resolved"));
    }
}

降级流程图

应用请求: GPU_PRIVATE堆, 分配512MB
    |
    ├─[1]─ 尝试在GPU_PRIVATE分配
    │      pfnCreatePMR(GPU_PRIVATE, 512MB)
    │      └─ 返回: PVRSRV_ERROR_OUT_OF_MEMORY
    │
    ├─[2]─ _LogOOMDetection(GPU_PRIVATE, OOM=TRUE)
    │      └─ 日志: "Device: 0 Physheap: GPU_PRIVATE OOM: Detected"
    │
    ├─[3]─ 检查错误类型
    │      └─ IsOOMError(err) == TRUE
    │
    ├─[4]─ 检查是否强制堆
    │      └─ PVRSRV_CHECK_MANDATED_PHYSHEAP(flags) == FALSE
    │
    ├─[5]─ 检查是否可降级堆
    │      └─ ePhysIdx (GPU_PRIVATE=3) <= GPU_PRIVATE(3) → 可降级
    │
    └─[6]─ 降级循环开始
           │
           ├─ 降级到: GPU_LOCAL (2)
           │  ├─ _PhysHeapFindRealHeapNoFallback(GPU_LOCAL)
           │  │  └─ 找到堆: 0xffff88001234
           │  │
           │  ├─ PhysHeapFreeMemCheck(GPU_LOCAL, 512MB)
           │  │  ├─ 总大小: 2GB
           │  │  ├─ 可用: 256MB
           │  │  └─ 返回: PVRSRV_ERROR_INSUFFICIENT_PHYS_HEAP_MEMORY
           │  │
           │  └─ _LogOOMDetection(GPU_LOCAL, OOM=TRUE)
           │     └─ 继续下一个降级
           │
           ├─ 降级到: CPU_LOCAL (1)
           │  ├─ 警告: "Demoted from GPU_PRIVATE to CPU_LOCAL"
           │  │
           │  ├─ _PhysHeapFindRealHeapNoFallback(CPU_LOCAL)
           │  │  └─ 找到堆: 0xffff88005678
           │  │
           │  ├─ PhysHeapFreeMemCheck(CPU_LOCAL, 512MB)
           │  │  ├─ 总大小: 8GB
           │  │  ├─ 可用: 4GB
           │  │  └─ 返回: PVRSRV_OK
           │  │
           │  ├─ pfnCreatePMR(CPU_LOCAL, 512MB)
           │  │  └─ 返回: PVRSRV_OK ✓
           │  │
           │  └─ _LogOOMDetection(CPU_LOCAL, OOM=FALSE)
           │
           └─ 降级成功!
              └─ 日志: "PhysHeap(GPU_PRIVATE) failed to allocate PMR. 
                        Demoted to CPU_LOCAL"

降级链

降级方向: 高性能 → 低性能

GPU_SECURE (7)
    ↓ 降级
GPU_PRIVATE (3)
    ↓ 降级
GPU_LOCAL (2)
    ↓ 降级
CPU_LOCAL (1)
    ↓ 降级
DEFAULT (0)
    ↓
无法降级(终止)

性能影响:
GPU_LOCAL → CPU_LOCAL: 性能下降 50-90%
- GPU访问系统内存通过PCIe总线
- 带宽: ~16GB/s (PCIe 3.0 x16) vs ~256GB/s (GDDR6)
- 延迟: ~500ns vs ~50ns

PhysHeapPagesAlloc 流程

PVRSRV_ERROR PhysHeapPagesAlloc(PHYS_HEAP *psPhysHeap, 
                                size_t uiSize,
                                PG_HANDLE *psMemHandle,
                                IMG_DEV_PHYADDR *psDevPAddr,
                                IMG_PID uiPid)
{
    const PHEAP_IMPL_FUNCS *psImplFuncs = psPhysHeap->psImplFuncs;
    PVRSRV_ERROR eResult = PVRSRV_ERROR_NOT_IMPLEMENTED;

    if (psImplFuncs->pfnPagesAlloc != NULL)
    {
        eResult = psImplFuncs->pfnPagesAlloc(psPhysHeap,
                                             uiSize, 
                                             psMemHandle, 
                                             psDevPAddr, 
                                             uiPid);
    }

    return eResult;
}

对应实现:

堆类型 实现函数 位置
UMA PhysmemNewOSRamBackedPMR physmem_osmem.c
LMA PhysmemNewLocalMemPMR physmem_lma.c
IMA PhysmemNewIMABackedPMR physmem_ima.c

内存分配完整流程图

上层代码
    │
    ├─> DevmemAllocate()
    │      │
    │      └─> PMRCreatePMR()
    │             │
    │             └─> PhysHeapCreatePMR()
    │                    │
    │                    ├──[选择堆]──> PhysHeapAcquireByID()
    │                    │                  ├─ 查找/缓存
    │                    │                  └─ ui32RefCount++
    │                    │
    │                    ├──[尝试分配]──> psImplFuncs->pfnCreatePMR()
    │                    │                     │
    │                    │                     ├─ UMA: PhysmemNewOSRamBackedPMR()
    │                    │                     │    ├─ OSAllocPages()
    │                    │                     │    └─ 创建PMR对象
    │                    │                     │
    │                    │                     ├─ LMA: PhysmemNewLocalMemPMR()
    │                    │                     │    ├─ RA_Alloc()
    │                    │                     │    └─ 创建PMR对象
    │                    │                     │
    │                    │                     └─ IMA: PhysmemNewIMABackedPMR()
    │                    │                          ├─ 从DLM获取PMB
    │                    │                          ├─ RA_Alloc()
    │                    │                          └─ 创建PMR对象
    │                    │
    │                    ├──[检查结果]──> eError == OK?
    │                    │                  ├─ 是: 返回PMR
    │                    │                  └─ 否: 继续
    │                    │
    │                    ├──[OOM检测]──> IsOOMError(eError)?
    │                    │                  ├─ 否: 返回错误
    │                    │                  └─ 是: 继续降级
    │                    │
    │                    ├──[降级循环]──> for (heap = current-1; heap >= DEFAULT; heap--)
    │                    │                  │
    │                    │                  ├─ 查找降级堆
    │                    │                  ├─ 检查可用内存
    │                    │                  ├─ 尝试分配
    │                    │                  ├─ 成功? 返回
    │                    │                  └─ 失败? 继续下一个
    │                    │
    │                    └──[返回]──> PMR* 或 错误码
    │
    └─> 返回给应用

OOM处理机制

OOM检测与记录

原子OOM状态

#if !defined(PVRSRV_PHYSHEAP_DISABLE_OOM_DEMOTION)
    ATOMIC_T sOOMDetected;  // 原子变量,线程安全
#endif

状态转换图

正常状态 (sOOMDetected = FALSE)
    │
    │ 分配失败 (OOM错误)
    ↓
OOM状态 (sOOMDetected = TRUE)
    │
    │ 日志: "Device: X Physheap: Y OOM: Detected"
    │
    ├─[降级尝试]─> 其他堆分配
    │                │
    │                ├─ 成功: sOOMDetected = FALSE
    │                │        日志: "OOM: Resolved"
    │                │
    │                └─ 失败: 保持TRUE
    │
    ├─[内存释放]─> 空间增加
    │                └─ 下次分配成功
    │                   └─ sOOMDetected = FALSE
    │
    └─[持续OOM]─> 系统压力
                   └─ 可能触发整体内存回收

降级策略配置

可降级堆

// 仅对这些堆进行降级
if (ePhysIdx > PVRSRV_PHYS_HEAP_GPU_PRIVATE)
{
    return eError;  // 不降级
}
堆类型 ID 可降级? 降级目标
CPU_LOCAL 1 -
GPU_LOCAL 2 CPU_LOCAL (1)
GPU_PRIVATE 3 GPU_LOCAL (2) → CPU_LOCAL (1)
FW_MAIN 4 -
EXTERNAL 5 -
GPU_COHERENT 6 -
GPU_SECURE 7 -

强制堆标志

// 如果设置了MANDATED标志,不进行降级
if (PVRSRV_CHECK_MANDATED_PHYSHEAP(uiFlags))
{
    return eError;
}

使用场景:
- 固件代码:必须在特定堆
- 安全缓冲区:不能降级到非安全堆
- 硬件限制:某些HW只能访问特定内存


PhysHeapFreeMemCheck

PVRSRV_ERROR PhysHeapFreeMemCheck(PHYS_HEAP *psPhysHeap,
                                  IMG_UINT64 ui64MinRequiredMem,
                                  IMG_UINT64 *pui64FreeMem)
{
    IMG_UINT64 ui64TotalSize;
    IMG_UINT64 ui64FreeSize;
    PVRSRV_ERROR eError = PVRSRV_OK;

    PVR_LOG_RETURN_IF_INVALID_PARAM(psPhysHeap != NULL, "psPhysHeap");
    PVR_LOG_RETURN_IF_INVALID_PARAM(pui64FreeMem != NULL, "pui64FreeMem");

    // [1] IMA堆特殊处理:需要累加DLM堆空闲空间
    if (psPhysHeap->eType == PHYS_HEAP_TYPE_IMA)
    {
        PhysHeapIMAGetMemInfo(psPhysHeap->pvImplData,
                              &ui64TotalSize,
                              &ui64FreeSize);
    }
    else
    {
        psPhysHeap->psImplFuncs->pfnGetFactoryMemStats(psPhysHeap->pvImplData,
                                                       &ui64TotalSize,
                                                       &ui64FreeSize);
    }

    *pui64FreeMem = ui64FreeSize;

    // [2] 检查是否满足最小需求
    if (ui64MinRequiredMem >= *pui64FreeMem)
    {
        eError = PVRSRV_ERROR_INSUFFICIENT_PHYS_HEAP_MEMORY;
    }
}

PhysHeapIMAGetMemInfo

static void PhysHeapIMAGetMemInfo(PHYS_HEAP *psPhysHeap,
                                  IMG_UINT64 *puiTotalSize,
                                  IMG_UINT64 *puiFreeSize)
{
    PHYS_HEAP *psDLMHeap;
    IMG_UINT64 ui64TotalSize;
    IMG_UINT64 ui64FreeSize;
    IMG_UINT64 ui64DLMTotalSize;
    IMG_UINT64 ui64DLMFreeSize;

    PVR_LOG_RETURN_VOID_IF_FALSE(
        psPhysHeap->eType == PHYS_HEAP_TYPE_IMA,
        "Physheap type not IMA");

    // [1] 获取DLM堆引用
    PVR_ASSERT(psPhysHeap->psImplFuncs->pfnGetHeapDLMBacking);
    psPhysHeap->psImplFuncs->pfnGetHeapDLMBacking(psPhysHeap->pvImplData,
                                                  &psDLMHeap);
    PVR_LOG_RETURN_VOID_IF_FALSE(psDLMHeap != NULL, "pfnGetHeapDLMBacking");

    // [2] 获取IMA堆的内存统计
    PVR_ASSERT(psPhysHeap->psImplFuncs->pfnGetFactoryMemStats);
    psPhysHeap->psImplFuncs->pfnGetFactoryMemStats(psPhysHeap->pvImplData,
                                                   &ui64TotalSize,
                                                   &ui64FreeSize);

    // [3] 获取DLM堆的内存统计
    PVR_ASSERT(psDLMHeap->psImplFuncs->pfnGetFactoryMemStats);
    psDLMHeap->psImplFuncs->pfnGetFactoryMemStats(psDLMHeap->pvImplData,
                                                  &ui64DLMTotalSize,
                                                  &ui64DLMFreeSize);

    // [4] 计算总量和可用量
    // 总大小 = DLM总大小(因为IMA从DLM导入)
    *puiTotalSize = ui64DLMTotalSize;

    // 可用大小 = IMA当前空闲 + DLM可导出的空闲PMB
    *puiFreeSize = ui64FreeSize + ui64DLMFreeSize;
}

IMA内存统计示例:

DLM堆:
├─ 总大小: 2GB
├─ 已导出给IMA: 1.5GB
└─ 可用(未导出): 512MB

IMA堆:
├─ 已导入: 1.5GB
├─ 已分配: 1GB
└─ 可用(已导入): 512MB

查询IMA堆可用内存:
puiTotalSize = 2GB (DLM总大小)
puiFreeSize = 512MB (IMA可用) + 512MB (DLM可用) = 1GB

原因: IMA可以继续从DLM导入新的PMB

降级决策树

分配请求: 堆类型X, 大小S
    |
    ├─> [1] 尝试在堆X分配
    │      ├─ 成功? → 返回PMR ✓
    │      └─ 失败: eError
    |
    ├─> [2] 错误分类
    │      ├─ IsOOMError(eError)?
    │      │  ├─ 否 → 返回eError (不降级)
    │      │  └─ 是 → 继续
    │      │
    │      ├─ MANDATED标志?
    │      │  ├─ 是 → 返回eError (强制堆)
    │      │  └─ 否 → 继续
    │      │
    │      └─ 堆类型 <= GPU_PRIVATE?
    │         ├─ 否 → 返回eError (不可降级)
    │         └─ 是 → 继续降级
    |
    └─> [3] 降级循环
           for (堆Y = X-1; Y >= DEFAULT; Y--)
              |
              ├─> [3.1] 查找堆Y
              │      └─ 存在? → 继续
              │         不存在? → 下一个Y
              |
              ├─> [3.2] 检查内存
              │      ├─ PhysHeapFreeMemCheck(Y, S)
              │      ├─ 足够? → 继续
              │      └─ 不足? → 记录OOM, 下一个Y
              |
              ├─> [3.3] 尝试分配
              │      ├─ pfnCreatePMR(堆Y, S)
              │      ├─ 成功? → 返回PMR ✓
              │      └─ 失败? → 下一个Y
              |
              └─> [3.4] 所有堆尝试完毕
                     └─ 返回 OUT_OF_MEMORY

关键函数分析

PhysHeapCreate

PVRSRV_ERROR PhysHeapCreate(PPVRSRV_DEVICE_NODE psDevNode,
                            PHYS_HEAP_CONFIG *psConfig,
                            PHYS_HEAP_POLICY uiPolicy,
                            PHEAP_IMPL_DATA pvImplData,
                            const PHEAP_IMPL_FUNCS *psImplFuncs,
                            PHYS_HEAP **ppsPhysHeap)
{
    PHYS_HEAP *psNew;

    PVR_DPF_ENTERED;

    PVR_LOG_RETURN_IF_INVALID_PARAM(psDevNode != NULL, "psDevNode");

    // [1] 验证堆类型
    if (psConfig->eType == PHYS_HEAP_TYPE_UNKNOWN)
    {
        return PVRSRV_ERROR_INVALID_PARAMS;
    }

    // [2] 验证函数表
    PVR_LOG_RETURN_IF_INVALID_PARAM(psImplFuncs != NULL, "psImplFuncs");
    PVR_LOG_RETURN_IF_INVALID_PARAM(
        psImplFuncs->pfnCreatePMR != NULL ||
        psImplFuncs->pfnCreatePMB,
        "psImplFuncs->pfnCreatePMR || psImplFuncs->pfnCreatePMB");

    // [3] 分配PHYS_HEAP结构
    psNew = OSAllocMem(sizeof(PHYS_HEAP));
    PVR_RETURN_IF_NOMEM(psNew);

#if defined(PVRSRV_ENABLE_XD_MEM)
    psNew->psSpasRegion = NULL;
#endif

    // [4] 根据堆类型初始化配置
    switch (psConfig->eType)
    {
    case PHYS_HEAP_TYPE_LMA:
        psNew->psMemFuncs = psConfig->uConfig.sLMA.psMemFuncs;
        psNew->hPrivData = psConfig->uConfig.sLMA.hPrivData;
        psNew->pszPDumpMemspaceName = psConfig->uConfig.sLMA.pszPDumpMemspaceName;
        OSStringSafeCopy(psNew->aszName,
                         (psConfig->uConfig.sLMA.pszHeapName) ? 
                          psConfig->uConfig.sLMA.pszHeapName :
                          "Unknown PhysHeap",
                         PHYS_HEAP_NAME_SIZE);
#if defined(PVRSRV_ENABLE_XD_MEM)
        PhysHeapSpasInsert(psNew, psConfig->uConfig.sLMA.psSpasRegion);
#endif
        break;

    case PHYS_HEAP_TYPE_IMA:
        psNew->psMemFuncs = psConfig->uConfig.sIMA.psMemFuncs;
        psNew->hPrivData = psConfig->uConfig.sIMA.hPrivData;
        psNew->pszPDumpMemspaceName = psConfig->uConfig.sIMA.pszPDumpMemspaceName;
        OSStringSafeCopy(psNew->aszName,
                         (psConfig->uConfig.sIMA.pszHeapName) ? 
                          psConfig->uConfig.sIMA.pszHeapName :
                          "Unknown PhysHeap",
                         PHYS_HEAP_NAME_SIZE);
        break;

    case PHYS_HEAP_TYPE_DMA:
        psNew->psMemFuncs = psConfig->uConfig.sDMA.psMemFuncs;
        psNew->hPrivData = psConfig->uConfig.sDMA.hPrivData;
        psNew->pszPDumpMemspaceName = psConfig->uConfig.sDMA.pszPDumpMemspaceName;
        OSStringSafeCopy(psNew->aszName,
                         (psConfig->uConfig.sDMA.pszHeapName) ? 
                          psConfig->uConfig.sDMA.pszHeapName :
                          "Unknown PhysHeap",
                         PHYS_HEAP_NAME_SIZE);
        break;

    case PHYS_HEAP_TYPE_UMA:
        psNew->psMemFuncs = psConfig->uConfig.sUMA.psMemFuncs;
        psNew->hPrivData = psConfig->uConfig.sUMA.hPrivData;
        psNew->pszPDumpMemspaceName = psConfig->uConfig.sUMA.pszPDumpMemspaceName;
        OSStringSafeCopy(psNew->aszName,
                         (psConfig->uConfig.sUMA.pszHeapName) ? 
                          psConfig->uConfig.sUMA.pszHeapName :
                          "Unknown PhysHeap",
                         PHYS_HEAP_NAME_SIZE);
#if defined(PVRSRV_ENABLE_XD_MEM)
        PhysHeapSpasInsert(psNew, psConfig->uConfig.sUMA.psSpasRegion);
#endif
        break;

    case PHYS_HEAP_TYPE_DLM:
        psNew->psMemFuncs = psConfig->uConfig.sDLM.psMemFuncs;
        psNew->hPrivData = psConfig->uConfig.sDLM.hPrivData;
        psNew->pszPDumpMemspaceName = "None";
        OSStringSafeCopy(psNew->aszName,
                         (psConfig->uConfig.sDLM.pszHeapName) ? 
                          psConfig->uConfig.sDLM.pszHeapName :
                          "Unknown PhysHeap",
                         PHYS_HEAP_NAME_SIZE);
        break;

#if defined(SUPPORT_WRAP_EXTMEMOBJECT)
    case PHYS_HEAP_TYPE_WRAP:
        psNew->psMemFuncs = psConfig->uConfig.sWRAP.psMemFuncs;
        psNew->hPrivData = psConfig->uConfig.sWRAP.hPrivData;
        psNew->pszPDumpMemspaceName = psConfig->uConfig.sWRAP.pszPDumpMemspaceName;
        OSStringSafeCopy(psNew->aszName,
                         (psConfig->uConfig.sWRAP.pszHeapName) ? 
                          psConfig->uConfig.sWRAP.pszHeapName :
                          "Unknown PhysHeap",
                         PHYS_HEAP_NAME_SIZE);
        break;
#endif

    default:
        PVR_LOG_ERROR(PVRSRV_ERROR_NOT_IMPLEMENTED, 
                      "psConfig->eType not implemented");
    }

    // [5] 初始化通用字段
    psNew->eType = psConfig->eType;
    psNew->ui32UsageFlags = psConfig->ui32UsageFlags;
    psNew->uiPolicy = uiPolicy;
    psNew->ui32RefCount = 0;
    psNew->psDevNode = psDevNode;

#if !defined(PVRSRV_PHYSHEAP_DISABLE_OOM_DEMOTION)
    OSAtomicWrite(&psNew->sOOMDetected, IMG_FALSE);
#endif

    psNew->pvImplData = pvImplData;
    psNew->psImplFuncs = psImplFuncs;

#if defined(SUPPORT_STATIC_IPA)
    // [6] IPA配置
    {
        IMG_UINT8 ui8Val;

        ui8Val = psConfig->sIPAConfig.ui8IPAPolicyDefault;
        psNew->ui32IPAPolicyValue = (IMG_UINT32)ui8Val;

        ui8Val = psConfig->sIPAConfig.ui8IPAPolicyMask;
        psNew->ui32IPAClearMask = (IMG_UINT32)ui8Val;

        ui8Val = psConfig->sIPAConfig.ui8IPAPolicyShift;
        psNew->ui32IPAShift = (IMG_UINT32)ui8Val;

        PVR_LOG_VA(PVR_DBG_MESSAGE, 
                   "%s: Physheap <%p> ['%s'] Config @ <%p> IPA = [0x%x, 0x%x, 0x%x]",
                   __func__, psNew, psNew->aszName,
                   psConfig, psNew->ui32IPAPolicyValue,
                   psNew->ui32IPAClearMask, psNew->ui32IPAShift);
    }
#endif

    // [7] 返回堆指针
    if (ppsPhysHeap != NULL)
    {
        *ppsPhysHeap = psNew;
    }

    // [8] 添加到设备堆链表
    psNew->psNext = psDevNode->psPhysHeapList;
    psDevNode->psPhysHeapList = psNew;

    PVR_DPF_RETURN_RC1(PVRSRV_OK, psNew);
}

创建流程总结:

步骤 操作 说明
1 验证参数 检查设备节点、堆类型、函数表
2 分配结构 OSAllocMem(sizeof(PHYS_HEAP))
3 配置初始化 根据堆类型设置不同字段
4 通用字段 设置类型、策略、引用计数等
5 IPA配置 如果启用IPA支持
6 SPAS关联 如果启用跨设备内存
7 链表插入 添加到psDevNode->psPhysHeapList
8 返回指针 通过ppsPhysHeap返回

PhysHeapDestroy

void PhysHeapDestroy(PHYS_HEAP *psPhysHeap)
{
    const PHEAP_IMPL_FUNCS *psImplFuncs = psPhysHeap->psImplFuncs;
    PPVRSRV_DEVICE_NODE psDevNode = psPhysHeap->psDevNode;

    PVR_DPF_ENTERED1(psPhysHeap);

#if defined(PVRSRV_FORCE_UNLOAD_IF_BAD_STATE)
    if (PVRSRVGetPVRSRVData()->eServicesState == PVRSRV_SERVICES_STATE_OK)
#endif
    {
        // [1] 验证引用计数为0
        PVR_ASSERT(psPhysHeap->ui32RefCount == 0);
    }

#if defined(PVRSRV_ENABLE_XD_MEM)
    // [2] 从SPAS区域移除
    PhysHeapSpasRemove(psPhysHeap);
#endif

    // [3] 从设备链表移除
    if (psDevNode->psPhysHeapList == psPhysHeap)
    {
        psDevNode->psPhysHeapList = psPhysHeap->psNext;
    }
    else
    {
        PHYS_HEAP *psTmp = psDevNode->psPhysHeapList;

        while (psTmp->psNext != psPhysHeap)
        {
            psTmp = psTmp->psNext;
        }
        psTmp->psNext = psPhysHeap->psNext;
    }

    // [4] 调用实现层销毁函数
    if (psImplFuncs->pfnDestroyData != NULL)
    {
        psImplFuncs->pfnDestroyData(psPhysHeap->pvImplData);
    }

    // [5] 释放堆结构
    OSFreeMem(psPhysHeap);

    PVR_DPF_RETURN;
}

销毁流程:

PhysHeapDestroy(psPhysHeap)
    |
    ├─[1]─ 检查引用计数 == 0
    │      └─ 否则 PVR_ASSERT 失败
    |
    ├─[2]─ PhysHeapSpasRemove() (如果启用XD_MEM)
    │      └─ 从SPAS区域链表移除
    |
    ├─[3]─ 从设备链表移除
    │      ├─ 如果是头节点: psDevNode->psPhysHeapList = psNext
    │      └─ 否则: 遍历找到前驱节点,修改psNext
    |
    ├─[4]─ 调用实现层销毁
    │      └─ psImplFuncs->pfnDestroyData(pvImplData)
    │            ├─ LMA: 释放RA资源
    │            ├─ IMA: 解除与DLM的链接
    │            └─ DLM: 销毁PMB管理结构
    |
    └─[5]─ OSFreeMem(psPhysHeap)

PhysHeapAcquire / PhysHeapRelease

PVRSRV_ERROR PhysHeapAcquire(PHYS_HEAP *psPhysHeap)
{
    PVR_LOG_RETURN_IF_INVALID_PARAM(psPhysHeap != NULL, "psPhysHeap");

    // 增加引用计数
    psPhysHeap->ui32RefCount++;

    // 第一次获取时统计用户可分配堆
    if (psPhysHeap->ui32RefCount == 1)
    {
        _PhysHeapCountUserModeHeaps(psPhysHeap->psDevNode,
                                    psPhysHeap->ui32UsageFlags);
    }

    return PVRSRV_OK;
}

void PhysHeapRelease(PHYS_HEAP *psPhysHeap)
{
    PVR_DPF_ENTERED1(psPhysHeap);

    // 加锁
    OSLockAcquire(psPhysHeap->psDevNode->hPhysHeapLock);

    // 减少引用计数
    psPhysHeap->ui32RefCount--;
    PHYSHEAP_REFCOUNT_PRINT("%s: Heap %p, refcount = %d",
                            __func__, psPhysHeap, psPhysHeap->ui32RefCount);

    // 释放锁
    OSLockRelease(psPhysHeap->psDevNode->hPhysHeapLock);

    PVR_DPF_RETURN;
}

引用计数生命周期:

创建时: ui32RefCount = 0
    |
    ├─> PhysHeapAcquire() #1
    │      └─ ui32RefCount = 1
    │         └─ _PhysHeapCountUserModeHeaps() (首次)
    |
    ├─> PhysHeapAcquire() #2
    │      └─ ui32RefCount = 2
    |
    ├─> PhysHeapAcquire() #3
    │      └─ ui32RefCount = 3
    |
    ├─> PhysHeapRelease()
    │      └─ ui32RefCount = 2
    |
    ├─> PhysHeapRelease()
    │      └─ ui32RefCount = 1
    |
    ├─> PhysHeapRelease()
    │      └─ ui32RefCount = 0
    |
    └─> PhysHeapDestroy()
           └─ PVR_ASSERT(ui32RefCount == 0) ✓
           └─ 销毁堆

地址转换函数

void PhysHeapCpuPAddrToDevPAddr(PHYS_HEAP *psPhysHeap,
                                IMG_UINT32 ui32NumOfAddr,
                                IMG_DEV_PHYADDR *psDevPAddr,
                                IMG_CPU_PHYADDR *psCpuPAddr)
{
    psPhysHeap->psMemFuncs->pfnCpuPAddrToDevPAddr(psPhysHeap->hPrivData,
                                                  ui32NumOfAddr,
                                                  psDevPAddr,
                                                  psCpuPAddr);
}

void PhysHeapDevPAddrToCpuPAddr(PHYS_HEAP *psPhysHeap,
                                IMG_UINT32 ui32NumOfAddr,
                                IMG_CPU_PHYADDR *psCpuPAddr,
                                IMG_DEV_PHYADDR *psDevPAddr)
{
    psPhysHeap->psMemFuncs->pfnDevPAddrToCpuPAddr(psPhysHeap->hPrivData,
                                                  ui32NumOfAddr,
                                                  psCpuPAddr,
                                                  psDevPAddr);
}

地址转换场景:

场景1: UMA系统(统一内存)
CPU PA: 0x100000000
GPU PA: 0x100000000
转换: 恒等映射 (Identity Mapping)

场景2: LMA系统(非统一内存)
CPU PA: 0x200000000 (系统总线地址)
GPU PA: 0x000000000 (GPU视角的地址)
转换: 需要减去基地址偏移

场景3: 带IOMMU的系统
CPU PA: 0x80000000
GPU PA: 0x40000000 (通过IOMMU映射)
转换: 查询IOMMU页表

实现示例 (LMA):
pfnCpuPAddrToDevPAddr:
    psDevPAddr->uiAddr = psCpuPAddr->uiAddr - psHeapConfig->sLMA.sStartAddr.uiAddr;

pfnDevPAddrToCpuPAddr:
    psCpuPAddr->uiAddr = psDevPAddr->uiAddr + psHeapConfig->sLMA.sStartAddr.uiAddr;

PhysHeapGetMemInfo

PVRSRV_ERROR
PhysHeapGetMemInfo(PVRSRV_DEVICE_NODE *psDevNode,
                   IMG_UINT32 ui32PhysHeapCount,
                   PVRSRV_PHYS_HEAP *paePhysHeapID,
                   PHYS_HEAP_MEM_STATS_PTR paPhysHeapMemStats)
{
    IMG_UINT32 i = 0;
    PHYS_HEAP *psPhysHeap;

    PVR_LOG_RETURN_IF_INVALID_PARAM(psDevNode != NULL, "psDevNode invalid");
    PVR_LOG_RETURN_IF_INVALID_PARAM(ui32PhysHeapCount <= MAX_USER_MODE_ALLOC_PHYS_HEAPS, 
                                    "ui32PhysHeapCount invalid");
    PVR_LOG_RETURN_IF_INVALID_PARAM(paePhysHeapID != NULL, "paePhysHeapID invalid");
    PVR_LOG_RETURN_IF_INVALID_PARAM(paPhysHeapMemStats != NULL, "paPhysHeapMemStats invalid");

    // 遍历请求的堆
    for (i = 0; i < ui32PhysHeapCount; i++)
    {
        if (paePhysHeapID[i] >= PVRSRV_PHYS_HEAP_LAST)
        {
            return PVRSRV_ERROR_PHYSHEAP_ID_INVALID;
        }

        // 查找真实堆(不使用fallback)
        psPhysHeap = _PhysHeapFindRealHeapNoFallback(paePhysHeapID[i], psDevNode);

        // 初始化统计结构
        paPhysHeapMemStats[i].ui32PhysHeapFlags = 0;
        paPhysHeapMemStats[i].ui64DevicesInSPAS = 0;

        if (psPhysHeap && PhysHeapUserModeAlloc(paePhysHeapID[i])
                && psPhysHeap->psImplFuncs->pfnGetFactoryMemStats)
        {
            // IMA堆特殊处理
            if (psPhysHeap->eType == PHYS_HEAP_TYPE_IMA)
            {
                PhysHeapIMAGetMemInfo(psPhysHeap,
                                      &paPhysHeapMemStats[i].ui64TotalSize,
                                      &paPhysHeapMemStats[i].ui64FreeSize);
            }
            else
            {
                psPhysHeap->psImplFuncs->pfnGetFactoryMemStats(
                    psPhysHeap->pvImplData,
                    &paPhysHeapMemStats[i].ui64TotalSize,
                    &paPhysHeapMemStats[i].ui64FreeSize);
            }

            // 设置标志
            if (paePhysHeapID[i] == psDevNode->psDevConfig->eDefaultHeap)
            {
                paPhysHeapMemStats[i].ui32PhysHeapFlags |= PVRSRV_PHYS_HEAP_FLAGS_IS_DEFAULT;
            }

#if defined(PVRSRV_ENABLE_XD_MEM)
            // 获取SPAS设备位图
            paPhysHeapMemStats[i].ui64DevicesInSPAS = PhysHeapSpasDeviceBitmap(psPhysHeap);
#endif

            paPhysHeapMemStats[i].ePhysHeapType = psPhysHeap->eType;
        }
        else
        {
            // 堆不存在或不可访问
            paPhysHeapMemStats[i].ui64TotalSize = 0;
            paPhysHeapMemStats[i].ui64FreeSize = 0;
            paPhysHeapMemStats[i].ePhysHeapType = PHYS_HEAP_TYPE_UNKNOWN;
        }
    }

    return PVRSRV_OK;
}

内存统计输出示例:

PHYS_HEAP_MEM_STATS stats[3];
PVRSRV_PHYS_HEAP heaps[3] = {
    PVRSRV_PHYS_HEAP_GPU_LOCAL,
    PVRSRV_PHYS_HEAP_CPU_LOCAL,
    PVRSRV_PHYS_HEAP_GPU_PRIVATE
};

PhysHeapGetMemInfo(psDevNode, 3, heaps, stats);

// 结果:
stats[0]: // GPU_LOCAL
    ui64TotalSize = 2147483648  // 2GB
    ui64FreeSize = 1073741824   // 1GB
    ui32PhysHeapFlags = PVRSRV_PHYS_HEAP_FLAGS_IS_DEFAULT
    ui64DevicesInSPAS = 0x01    // 设备0
    ePhysHeapType = PHYS_HEAP_TYPE_LMA

stats[1]: // CPU_LOCAL
    ui64TotalSize = 8589934592  // 8GB
    ui64FreeSize = 4294967296   // 4GB
    ui32PhysHeapFlags = 0
    ui64DevicesInSPAS = 0x01
    ePhysHeapType = PHYS_HEAP_TYPE_UMA

stats[2]: // GPU_PRIVATE (使用fallback到GPU_LOCAL)
    ui64TotalSize = 2147483648  // 同GPU_LOCAL
    ui64FreeSize = 1073741824
    ui32PhysHeapFlags = 0
    ui64DevicesInSPAS = 0x01
    ePhysHeapType = PHYS_HEAP_TYPE_LMA

架构图示

系统分层架构

┌────────────────────────────────────────────────────────────────┐
│                   应用层 (Application Layer)                    │
│                                                                 │
│  - OpenGL/Vulkan/OpenCL 应用                                   │
│  - 用户态驱动 (libPVRSRV_UM.so)                               │
│  - DevmemAllocate(), PMRCreate()                              │
└────────────────────────────────────────────────────────────────┘
                            ↓ IOCTL
┌────────────────────────────────────────────────────────────────┐
│                   管理层 (Management Layer)                     │
│                                                                 │
│  - PhysHeapCreate()        创建物理堆                          │
│  - PhysHeapAcquire()       获取堆引用                          │
│  - PhysHeapRelease()       释放堆引用                          │
│  - PhysHeapDestroy()       销毁物理堆                          │
│  - PhysHeapAcquireByID()   通过ID获取堆                        │
└────────────────────────────────────────────────────────────────┘
                            ↓
┌────────────────────────────────────────────────────────────────┐
│                   策略层 (Policy Layer)                         │
│                                                                 │
│  - 堆类型选择 (UMA/LMA/IMA/DLM)                               │
│  - OOM检测与降级                                               │
│  - Fallback机制                                                │
│  - 引用计数管理                                                │
└────────────────────────────────────────────────────────────────┘
                            ↓
┌────────────────────────────────────────────────────────────────┐
│                  实现层 (Implementation Layer)                  │
│                                                                 │
│  ┌──────────────┬──────────────┬──────────────┬──────────────┐│
│  │ PhysmemOSMEM │ PhysmemLMA   │ PhysmemIMA   │ PhysmemDLM   ││
│  │              │              │              │              ││
│  │ UMA/WRAP实现 │ LMA/DMA实现  │ IMA实现      │ DLM实现      ││
│  │ 系统内存分配 │ GPU本地内存  │ 导入内存     │ 大块内存管理 ││
│  │ OSAllocPages │ RA_Alloc     │ PMB导入      │ PMB导出      ││
│  └──────────────┴──────────────┴──────────────┴──────────────┘│
└────────────────────────────────────────────────────────────────┘
                            ↓
┌────────────────────────────────────────────────────────────────┐
│                   硬件层 (Hardware Layer)                       │
│                                                                 │
│  ┌──────────────┬──────────────┬──────────────────────────┐   │
│  │ System RAM   │ GPU VRAM     │ Device-specific Memory   │   │
│  │ DDR4/DDR5    │ GDDR6/HBM2   │ eDRAM / L3 Cache         │   │
│  │ 8-64GB       │ 4-24GB       │ 64-256MB                 │   │
│  └──────────────┴──────────────┴──────────────────────────┘   │
└────────────────────────────────────────────────────────────────┘

数据结构关系图

                    PVRSRV_DEVICE_NODE
                            |
        ┌───────────────────┼───────────────────┐
        |                   |                   |
  hPhysHeapLock      psPhysHeapList      apsPhysHeap[26]
   (POS_LOCK)          (链表头)            (快速缓存)
        |                   |                   |
        |                   ↓                   ↓
        |            ┌─────────────┐      [0] → NULL
        |            │ PHYS_HEAP #1│      [1] → PHYS_HEAP #1
        |            ├─────────────┤      [2] → PHYS_HEAP #2
        |            │ eType: LMA  │      [3] → NULL (使用fallback)
        |            │ uiPolicy    │      [4] → PHYS_HEAP #4
        |            │ ui32UsageF..│      ...
        |            │ ui32RefCount│      [25] → PHYS_HEAP #8
        |            │ psImplFuncs ────→ PHEAP_IMPL_FUNCS
        |            │ pvImplData  ────→ LMA_HEAP_IMPL_DATA
        |            │ psNext ──────┐
        |            └─────────────┘│
        |                           ↓
        |                    ┌─────────────┐
        |                    │ PHYS_HEAP #2│
        |                    ├─────────────┤
        |                    │ eType: UMA  │
        |                    │ ...         │
        |                    │ psNext ──────┐
        |                    └─────────────┘│
        |                                   ↓
        |                            ┌─────────────┐
        |                            │ PHYS_HEAP #3│
        |                            │ eType: IMA  │
        |                            │ ...         │
        |                            │ psNext: NULL│
        |                            └─────────────┘
        |
        └────> 保护所有PHYS_HEAP操作

堆类型依赖关系

                    物理内存资源
                         |
        ┌────────────────┼────────────────┐
        |                |                |
    System RAM      GPU VRAM          DMA Pool
        |                |                |
        ↓                ↓                ↓
   ┌─────────┐      ┌─────────┐      ┌─────────┐
   │   UMA   │      │   LMA   │      │   DMA   │
   │  Heap   │      │  Heap   │      │  Heap   │
   └─────────┘      └─────────┘      └─────────┘
                         |
                         ↓
                    ┌─────────┐
                    │   DLM   │
                    │  Heap   │ (Physical Memory Block Manager)
                    └─────────┘
                         |
            ┌────────────┼────────────┐
            ↓            ↓            ↓
       ┌─────────┐  ┌─────────┐  ┌─────────┐
       │ IMA #1  │  │ IMA #2  │  │ IMA #3  │
       │  Heap   │  │  Heap   │  │  Heap   │
       └─────────┘  └─────────┘  └─────────┘

依赖说明:
- UMA: 直接使用系统内存,独立堆
- LMA: 直接使用GPU显存,独立堆
- DMA: 直接使用DMA池,独立堆
- DLM: 管理LMA中的大块内存(PMB)
- IMA: 从DLM导入PMB进行分配,依赖DLM

内存分配流程

应用请求分配: 512MB, GPU_PRIVATE堆
    |
    ├──[1]── PhysHeapCreatePMR()
    |          |
    |          ├── 提取堆提示: PVRSRV_GET_PHYS_HEAP_HINT(flags)
    |          |   └─ ePhysHeap = GPU_PRIVATE (3)
    |          |
    |          ├── 查找堆: PhysHeapAcquireByID(GPU_PRIVATE)
    |          |   |
    |          |   ├── _PhysHeapFindHeapOrFallback()
    |          |   |   ├─ 检查缓存 apsPhysHeap[3]
    |          |   |   ├─ 遍历链表 psPhysHeapList
    |          |   |   └─ 找到或使用fallback → GPU_LOCAL
    |          |   |
    |          |   └── ui32RefCount++
    |          |
    |          └── psImplFuncs->pfnCreatePMR(512MB)
    |                  |
    |                  ├─ [成功] 返回PMR ✓
    |                  └─ [失败] 返回OOM错误
    |
    ├──[2]── OOM检测
    |          |
    |          ├── IsOOMError(eError)?
    |          |   ├─ PVRSRV_ERROR_PMR_FAILED_TO_ALLOC_PAGES
    |          |   ├─ PVRSRV_ERROR_OUT_OF_MEMORY
    |          |   └─ PVRSRV_ERROR_PMR_TOO_LARGE
    |          |
    |          └── _LogOOMDetection(GPU_PRIVATE, TRUE)
    |                  └─ OSAtomicExchange(&sOOMDetected, TRUE)
    |                  └─ 日志: "Physheap: GPU_PRIVATE OOM: Detected"
    |
    ├──[3]── 降级决策
    |          |
    |          ├── PVRSRV_CHECK_MANDATED_PHYSHEAP(flags)?
    |          |   └─ 是: 不降级,返回错误
    |          |
    |          ├── ePhysHeap <= GPU_PRIVATE?
    |          |   └─ 否: 不可降级堆,返回错误
    |          |
    |          └── 开始降级循环
    |
    └──[4]── 降级循环
               |
               ├── 降级到: GPU_LOCAL (2)
               |   |
               |   ├── _PhysHeapFindRealHeapNoFallback(GPU_LOCAL)
               |   |   └─ 查找真实堆(无fallback)
               |   |
               |   ├── PhysHeapFreeMemCheck(GPU_LOCAL, 512MB)
               |   |   ├─ pfnGetFactoryMemStats()
               |   |   └─ 检查: 512MB <= FreeSize?
               |   |
               |   ├── [内存不足] → 下一个降级
               |   |
               |   └── [内存充足] → 尝试分配
               |       └─ psImplFuncs->pfnCreatePMR(GPU_LOCAL, 512MB)
               |           ├─ [成功] 返回PMR ✓
               |           └─ [失败] 继续降级
               |
               ├── 降级到: CPU_LOCAL (1)
               |   |
               |   ├── 警告: "Demoted from GPU_PRIVATE to CPU_LOCAL"
               |   |
               |   ├── _PhysHeapFindRealHeapNoFallback(CPU_LOCAL)
               |   |
               |   ├── PhysHeapFreeMemCheck(CPU_LOCAL, 512MB)
               |   |   └─ [充足] → 尝试分配
               |   |
               |   └── psImplFuncs->pfnCreatePMR(CPU_LOCAL, 512MB)
               |       └─ [成功] 返回PMR ✓
               |
               └── 降级到: DEFAULT (0)
                   └── 最后尝试...

OOM降级状态机

                    正常运行状态
                  (sOOMDetected=FALSE)
                         |
                         | 分配请求
                         ↓
                  尝试在目标堆分配
                         |
            ┌────────────┴────────────┐
            |                         |
      [分配成功]                 [分配失败]
            |                         |
            ↓                         ↓
       返回PMR ✓               IsOOMError()?
                                     |
                        ┌────────────┴────────────┐
                        |                         |
                   [是OOM错误]              [其他错误]
                        |                         |
                        ↓                         ↓
              OSAtomicExchange                返回错误码
              (sOOMDetected=TRUE)
                        |
                  OOM状态激活
                (sOOMDetected=TRUE)
                        |
                        ↓
              ┌─────────┴─────────┐
              |                   |
      [强制堆标志]          [可降级堆]
              |                   |
              ↓                   ↓
         返回OOM错误          降级循环开始
                                  |
                     ┌────────────┴────────────┐
                     |                         |
              [找到降级堆]              [所有堆已尝试]
                     |                         |
                     ↓                         ↓
            PhysHeapFreeMemCheck          返回OOM错误
                     |
        ┌────────────┴────────────┐
        |                         |
   [内存充足]               [内存不足]
        |                         |
        ↓                         ↓
 尝试分配PMR            _LogOOMDetection(TRUE)
        |                         |
        |                    下一个降级堆
        ↓
    ┌───┴───┐
    |       |
 [成功] [失败]
    |       |
    ↓       ↓
返回PMR  继续降级
    |
    └──> OSAtomicExchange
         (sOOMDetected=FALSE)
              |
              ↓
         OOM状态解除
       (sOOMDetected=FALSE)

引用计数生命周期

时间轴 →

T0: 堆创建
    PhysHeapCreate()
    └─ ui32RefCount = 0

T1: 第一次获取
    PhysHeapAcquireByID(GPU_LOCAL)
    ├─ ui32RefCount: 0 → 1
    └─ _PhysHeapCountUserModeHeaps()

T2: MMU页表分配器获取
    PhysHeapAcquireByID(DEFAULT) → GPU_LOCAL
    └─ ui32RefCount: 1 → 2

T3: 用户应用分配
    DevmemAllocate() → PhysHeapCreatePMR()
    └─ 使用已获取的堆 (不增加RefCount)

T4: 另一个子系统获取
    SomeSubsystemInit()
    └─ ui32RefCount: 2 → 3

T5: 子系统释放
    SomeSubsystemDeinit()
    └─ PhysHeapRelease()
        └─ ui32RefCount: 3 → 2

T6: MMU释放
    PhysHeapMMUPxDeInit()
    └─ PhysHeapRelease()
        └─ ui32RefCount: 2 → 1

T7: 设备关闭准备
    PhysHeapDeInitDeviceHeaps()
    └─ PhysHeapRelease()
        └─ ui32RefCount: 1 → 0

T8: 堆销毁
    PhysHeapDestroy()
    ├─ PVR_ASSERT(ui32RefCount == 0) ✓
    ├─ psImplFuncs->pfnDestroyData()
    └─ OSFreeMem(psPhysHeap)

引用计数图:
Count
  3 │         ┌────┐
  2 │    ┌────┘    └────┐
  1 │ ───┘              └────┐
  0 ├────┘                   └────
    └─────────────────────────────> Time
      T0  T1  T2  T3  T4  T5  T6  T7  T8

DLM/IMA内存架构

┌─────────────────────────────────────────────────────────────┐
│              DLM堆 (Defrag Local Memory)                    │
│              总大小: 2GB                                     │
│                                                              │
│  ┌────────────────────────────────────────────────────┐    │
│  │ PMB #0 (256MB)                                     │    │
│  │ [已导出给 IMA_HEAP_1]                              │───┐│
│  └────────────────────────────────────────────────────┘   ││
│                                                             ││
│  ┌────────────────────────────────────────────────────┐   ││
│  │ PMB #1 (256MB)                                     │   ││
│  │ [已导出给 IMA_HEAP_1]                              │───┤│
│  └────────────────────────────────────────────────────┘   ││
│                                                             ││
│  ┌────────────────────────────────────────────────────┐   ││
│  │ PMB #2 (256MB)                                     │   ││
│  │ [已导出给 IMA_HEAP_2]                              │───┼┤
│  └────────────────────────────────────────────────────┘   │││
│                                                             │││
│  ┌────────────────────────────────────────────────────┐   │││
│  │ PMB #3 (256MB)                                     │   │││
│  │ [可用 - 未导出]                                    │   │││
│  └────────────────────────────────────────────────────┘   │││
│                                                             │││
│  ┌────────────────────────────────────────────────────┐   │││
│  │ PMB #4 (256MB)                                     │   │││
│  │ [已导出给 IMA_HEAP_2]                              │───┼┤│
│  └────────────────────────────────────────────────────┘   ││││
│                                                             ││││
│  ┌────────────────────────────────────────────────────┐   ││││
│  │ PMB #5 (256MB)                                     │   ││││
│  │ [可用 - 未导出]                                    │   ││││
│  └────────────────────────────────────────────────────┘   ││││
│                                                             ││││
│  ┌────────────────────────────────────────────────────┐   ││││
│  │ PMB #6 (256MB)                                     │   ││││
│  │ [可用 - 未导出]                                    │   ││││
│  └────────────────────────────────────────────────────┘   ││││
│                                                             ││││
│  ┌────────────────────────────────────────────────────┐   ││││
│  │ PMB #7 (256MB)                                     │   ││││
│  │ [可用 - 未导出]                                    │   ││││
│  └────────────────────────────────────────────────────┘   ││││
└─────────────────────────────────────────────────────────────┘│││
                    │               │                           │││
                    ↓               ↓                           ↓││
        ┌──────────────────┐  ┌──────────────────┐            │││
        │   IMA_HEAP_1     │  │   IMA_HEAP_2     │            │││
        │   (GPU渲染)      │  │   (计算任务)     │            │││
        ├──────────────────┤  ├──────────────────┤            │││
        │ 已导入: 512MB    │  │ 已导入: 512MB    │            │││
        │ 已分配: 400MB    │  │ 已分配: 256MB    │            │││
        │ 可用:   112MB    │  │ 可用:   256MB    │            │││
        │                  │  │                  │            │││
        │ [可从DLM请求]────┼──┼────[可从DLM请求] │◄───────────┘││
        │  更多PMB         │  │   更多PMB        │             ││
        └──────────────────┘  └──────────────────┘             ││
                    │               │                           ││
                    └───────┬───────┘                           ││
                            │                                   ││
                            ↓                                   ││
              查询DLM可用PMB: PMB#3,#5,#6,#7                    ││
              可用总量: 1GB (4个PMB)                             ││
                                                                 ││
PhysHeapIMAGetMemInfo(IMA_HEAP_1):                              ││
  ui64TotalSize = 2GB (DLM总大小)                               ││
  ui64FreeSize = 112MB (IMA可用) + 1GB (DLM可导出) = 1.11GB    ││
                                                                 ││
分配流程:                                                        ││
  1. 应用请求 300MB 从 IMA_HEAP_1                               ││
  2. IMA_HEAP_1 当前可用 112MB < 300MB                          ││
  3. IMA_HEAP_1 向 DLM 请求新 PMB                               ││
  4. DLM 分配 PMB#3 (256MB) 给 IMA_HEAP_1 ◄─────────────────────┘│
  5. IMA_HEAP_1 现在有 368MB 可用                                │
  6. 从 368MB 中分配 300MB 给应用 ✓                              │
  7. IMA_HEAP_1 剩余 68MB                                        │
                                                                  │
内存统计更新:                                                     │
  DLM: 已导出 768MB, 可用 1.25GB                                │
  IMA_HEAP_1: 已导入 768MB, 已分配 700MB, 可用 68MB            │
  IMA_HEAP_2: 已导入 512MB, 已分配 256MB, 可用 256MB           │
                                                                  │
                                                                  │
PhysHeapFreeMemCheck(IMA_HEAP_1, 400MB):                        │
  IMA_HEAP_1 可用: 68MB                                          │
  DLM 可用: 1.25GB (5个PMB)                                      │
  总可用: 68MB + 1.25GB = 1.32GB                                │
  1.32GB > 400MB ✓ 返回 PVRSRV_OK                               │
                                                                  │
                                                                  │
释放流程 (当 IMA_HEAP_1 不再需要某个PMB):                       │
  1. IMA_HEAP_1 释放 PMB#0 中的所有分配                         │
  2. IMA_HEAP_1 将 PMB#0 归还给 DLM  ◄──────────────────────────┘
  3. DLM 标记 PMB#0 为可用
  4. PMB#0 可以被其他 IMA 堆导入

跨设备内存共享 (XD_MEM / SPAS)

SPAS Region (Shared Physical Address Space)
    |
    ├─────────────────────────────────────┐
    │                                     │
Device 0                              Device 1
    │                                     │
    ├─> PHYS_HEAP (UMA)                   ├─> PHYS_HEAP (UMA)
    │   ├─ eType = UMA                    │   ├─ eType = UMA
    │   ├─ psSpasRegion ─────┐            │   ├─ psSpasRegion ─────┐
    │   └─ sSpasSibling ──────┼───────────┼───└─ sSpasSibling ─┐   │
    │                         │            │                     │   │
    │                         ↓            │                     ↓   │
    │              ┌──────────────────┐   │        ┌──────────────────┐
    │              │ SPAS_REGION      │   │        │ SPAS_REGION      │
    │              ├──────────────────┤   │        │  (同一个)        │
    │              │ sListHead  ──────┼───┼────────┼→ sListHead       │
    │              │    ↓             │   │        │      ↓           │
    │              │ [Device0_Heap]   │   │        │  [Device0_Heap]  │
    │              │    ↓             │   │        │      ↓           │
    │              │ [Device1_Heap]   │   │        │  [Device1_Heap]  │
    │              │ hLock (OSWRLock) │   │        │                  │
    │              └──────────────────┘   │        └──────────────────┘
    │                                     │
    └─────────────────────────────────────┘

功能:
1. PhysHeapSpasCreate() - 创建SPAS区域
2. PhysHeapSpasInsert() - 将堆加入SPAS
3. PhysHeapSpasRemove() - 从SPAS移除堆
4. PhysHeapSpasWithDevice() - 检查是否共享
5. PhysHeapSpasDeviceBitmap() - 获取设备位图

使用场景:
- 多GPU系统 (SLI/CrossFire)
- CPU + GPU 统一内存
- dGPU + iGPU 协同
- NPU + GPU 共享缓冲区

示例:
  Device 0 (iGPU): 共享系统内存 8GB
  Device 1 (dGPU): 共享系统内存 8GB

  两个设备的UMA堆指向同一个SPAS区域

  PhysHeapSpasWithDevice(Device0_Heap, Device1) = PVRSRV_OK
  表示可以跨设备访问

  PhysHeapSpasDeviceBitmap(Device0_Heap) = 0x03
  二进制: 00000011
  表示: Device 0 (bit 0) 和 Device 1 (bit 1)

GPU虚拟化内存隔离与访问控制

GPU虚拟化内存布局

┌──────────────────────────────────────────────────────────────┐
│                GPU Local Memory (2GB)                         │
├──────────────────────────────────────────────────────────────┤
│ OSID 0 Private (Host)     │ 256MB │ [0x00000000-0x0FFFFFFF]  │
├───────────────────────────┼───────┼──────────────────────────┤
│ OSID 1 Private (Guest VM1)│ 256MB │ [0x10000000-0x1FFFFFFF]  │
├───────────────────────────┼───────┼──────────────────────────┤
│ OSID 2 Private (Guest VM2)│ 256MB │ [0x20000000-0x2FFFFFFF]  │
├───────────────────────────┼───────┼──────────────────────────┤
│ OSID 3 Private (Guest VM3)│ 256MB │ [0x30000000-0x3FFFFFFF]  │
├───────────────────────────┼───────┼──────────────────────────┤
│ OSID 4 Private (Guest VM4)│ 256MB │ [0x40000000-0x4FFFFFFF]  │
├───────────────────────────┼───────┼──────────────────────────┤
│ OSID 5 Private (Guest VM5)│ 256MB │ [0x50000000-0x5FFFFFFF]  │
├───────────────────────────┼───────┼──────────────────────────┤
│ OSID 6 Private (Guest VM6)│ 256MB │ [0x60000000-0x6FFFFFFF]  │
├───────────────────────────┼───────┼──────────────────────────┤
│ OSID 7 Private (Guest VM7)│ 256MB │ [0x70000000-0x7FFFFFFF]  │
├───────────────────────────┼───────┼──────────────────────────┤
│ Shared Region (All OSIDs) │ 96MB  │ [0x74000000-0x7FFFFFFF]  │
└──────────────────────────────────────────────────────────────┘

内存区域说明:

区域类型 大小 地址范围 访问权限
OSID 0 (Host) 256MB 0x00000000 - 0x0FFFFFFF 特权访问所有区域
OSID 1-7 (Guest) 各256MB 0x10000000 - 0x7FFFFFFF 仅访问私有+共享
Shared Region 96MB 0x74000000 - 0x7FFFFFFF 所有OSID可访问
Total 2GB 0x00000000 - 0x7FFFFFFF -

硬件防火墙配置:

  aui64OSidMin[SECURE][0] = 0x00000000
  aui64OSidMax[SECURE][0] = 0x7FFFFFFF  // Host可访问全部

  aui64OSidMin[SECURE][1] = 0x10000000
  aui64OSidMax[SECURE][1] = 0x1FFFFFFF  // VM1只能访问自己

  aui64OSidMin[SHARED][0-7] = 0x74000000
  aui64OSidMax[SHARED][0-7] = 0x7FFFFFFF  // 所有OS可访问共享区

访问控制:
```c
┌──────────┬─────────────────────┬─────────────────────┬──────────────────────┬──────────────────────┐
│          │                     │                     │                      │                      │
│  OSID    │   Private Region    │   Other Private     │   Shared Region      │   Host Region        │
│          │   (自己的私有区域)  │   (其他VM私有区域)  │   (共享区域)         │   (Host区域)         │
│          │                     │                     │                      │                      │
├──────────┼─────────────────────┼─────────────────────┼──────────────────────┼──────────────────────┤
│          │                     │                     │                      │                      │
│ 0 (Host) │  ✓ 可访问           │  ✓ 可访问           │  ✓ 可访问            │  ✓ 可访问            │
│          │  自己的256MB        │  所有VM的私有区域   │  96MB共享区          │  完整2GB内存         │
│          │  [0x00-0x0F]        │  [0x10-0x7F]        │  [0x74-0x7F]         │  [0x00-0x7F]         │
│          │                     │                     │                      │                      │
├──────────┼─────────────────────┼─────────────────────┼──────────────────────┼──────────────────────┤
│          │                     │                     │                      │                      │
│ 1 (VM1)  │  ✓ 可访问           │  ✗ 禁止访问         │  ✓ 可访问            │  ✗ 禁止访问          │
│          │  自己的256MB        │  其他VM区域         │  96MB共享区          │  Host专用区域        │
│          │  [0x10-0x1F]        │  [0x00,0x20-0x7F]   │  [0x74-0x7F]         │  [0x00-0x0F]         │
│          │                     │  触发Page Fault     │                      │  触发Page Fault      │
│          │                     │                     │                      │                      │
├──────────┼─────────────────────┼─────────────────────┼──────────────────────┼──────────────────────┤
│          │                     │                     │                      │                      │
│ 2 (VM2)  │  ✓ 可访问           │  ✗ 禁止访问         │  ✓ 可访问            │  ✗ 禁止访问          │
│          │  自己的256MB        │  其他VM区域         │  96MB共享区          │  Host专用区域        │
│          │  [0x20-0x2F]        │  [0x00-0x1F,0x30+]  │  [0x74-0x7F]         │  [0x00-0x0F]         │
│          │                     │  触发Page Fault     │                      │  触发Page Fault      │
│          │                     │                     │                      │                      │
├──────────┼─────────────────────┼─────────────────────┼──────────────────────┼──────────────────────┤
│          │                     │                     │                      │                      │
│ 3 (VM3)  │  ✓ 可访问           │  ✗ 禁止访问         │  ✓ 可访问            │  ✗ 禁止访问          │
│          │  自己的256MB        │  其他VM区域         │  96MB共享区          │  Host专用区域        │
│          │  [0x30-0x3F]        │  [0x00-0x2F,0x40+]  │  [0x74-0x7F]         │  [0x00-0x0F]         │
│          │                     │  触发Page Fault     │                      │  触发Page Fault      │
│          │                     │                     │                      │                      │
├──────────┼─────────────────────┼─────────────────────┼──────────────────────┼──────────────────────┤
│          │                     │                     │                      │                      │
│ 4 (VM4)  │  ✓ 可访问           │  ✗ 禁止访问         │  ✓ 可访问            │  ✗ 禁止访问          │
│          │  自己的256MB        │  其他VM区域         │  96MB共享区          │  Host专用区域        │
│          │  [0x40-0x4F]        │  [0x00-0x3F,0x50+]  │  [0x74-0x7F]         │  [0x00-0x0F]         │
│          │                     │  触发Page Fault     │                      │  触发Page Fault      │
│          │                     │                     │                      │                      │
├──────────┼─────────────────────┼─────────────────────┼──────────────────────┼──────────────────────┤
│          │                     │                     │                      │                      │
│ 5 (VM5)  │  ✓ 可访问           │  ✗ 禁止访问         │  ✓ 可访问            │  ✗ 禁止访问          │
│          │  自己的256MB        │  其他VM区域         │  96MB共享区          │  Host专用区域        │
│          │  [0x50-0x5F]        │  [0x00-0x4F,0x60+]  │  [0x74-0x7F]         │  [0x00-0x0F]         │
│          │                     │  触发Page Fault     │                      │  触发Page Fault      │
│          │                     │                     │                      │                      │
├──────────┼─────────────────────┼─────────────────────┼──────────────────────┼──────────────────────┤
│          │                     │                     │                      │                      │
│ 6 (VM6)  │  ✓ 可访问           │  ✗ 禁止访问         │  ✓ 可访问            │  ✗ 禁止访问          │
│          │  自己的256MB        │  其他VM区域         │  96MB共享区          │  Host专用区域        │
│          │  [0x60-0x6F]        │  [0x00-0x5F,0x70+]  │  [0x74-0x7F]         │  [0x00-0x0F]         │
│          │                     │  触发Page Fault     │                      │  触发Page Fault      │
│          │                     │                     │                      │                      │
├──────────┼─────────────────────┼─────────────────────┼──────────────────────┼──────────────────────┤
│          │                     │                     │                      │                      │
│ 7 (VM7)  │  ✓ 可访问           │  ✗ 禁止访问         │  ✓ 可访问            │  ✗ 禁止访问          │
│          │  自己的256MB        │  其他VM区域         │  96MB共享区          │  Host专用区域        │
│          │  [0x70-0x73]        │  [0x00-0x6F,0x74+]  │  [0x74-0x7F]         │  [0x00-0x0F]         │
│          │                     │  触发Page Fault     │                      │  触发Page Fault      │
│          │                     │                     │                      │                      │
└──────────┴─────────────────────┴─────────────────────┴──────────────────────┴──────────────────────┘

访问权限图例

符号 含义 说明
允许访问 硬件允许,无额外开销
禁止访问 硬件防火墙阻止,触发GPU Page Fault

硬件防火墙配置

// ============================================================
// OSID 0 (Host) - 完整访问权限
// ============================================================
GPU_FIREWALL_OSID0_MIN_SECURE = 0x00000000
GPU_FIREWALL_OSID0_MAX_SECURE = 0x7FFFFFFF  // 可访问全部2GB
GPU_FIREWALL_OSID0_MIN_SHARED = 0x74000000
GPU_FIREWALL_OSID0_MAX_SHARED = 0x7FFFFFFF

// ============================================================
// OSID 1 (VM1) - 仅私有区域 + 共享区域
// ============================================================
GPU_FIREWALL_OSID1_MIN_SECURE = 0x10000000
GPU_FIREWALL_OSID1_MAX_SECURE = 0x1FFFFFFF  // 仅256MB私有区域
GPU_FIREWALL_OSID1_MIN_SHARED = 0x74000000
GPU_FIREWALL_OSID1_MAX_SHARED = 0x7FFFFFFF

// ============================================================
// OSID 2 (VM2) - 仅私有区域 + 共享区域
// ============================================================
GPU_FIREWALL_OSID2_MIN_SECURE = 0x20000000
GPU_FIREWALL_OSID2_MAX_SECURE = 0x2FFFFFFF
GPU_FIREWALL_OSID2_MIN_SHARED = 0x74000000
GPU_FIREWALL_OSID2_MAX_SHARED = 0x7FFFFFFF

// ============================================================
// OSID 3 (VM3) - 仅私有区域 + 共享区域
// ============================================================
GPU_FIREWALL_OSID3_MIN_SECURE = 0x30000000
GPU_FIREWALL_OSID3_MAX_SECURE = 0x3FFFFFFF
GPU_FIREWALL_OSID3_MIN_SHARED = 0x74000000
GPU_FIREWALL_OSID3_MAX_SHARED = 0x7FFFFFFF

// ============================================================
// OSID 4 (VM4) - 仅私有区域 + 共享区域
// ============================================================
GPU_FIREWALL_OSID4_MIN_SECURE = 0x40000000
GPU_FIREWALL_OSID4_MAX_SECURE = 0x4FFFFFFF
GPU_FIREWALL_OSID4_MIN_SHARED = 0x74000000
GPU_FIREWALL_OSID4_MAX_SHARED = 0x7FFFFFFF

// ============================================================
// OSID 5 (VM5) - 仅私有区域 + 共享区域
// ============================================================
GPU_FIREWALL_OSID5_MIN_SECURE = 0x50000000
GPU_FIREWALL_OSID5_MAX_SECURE = 0x5FFFFFFF
GPU_FIREWALL_OSID5_MIN_SHARED = 0x74000000
GPU_FIREWALL_OSID5_MAX_SHARED = 0x7FFFFFFF

// ============================================================
// OSID 6 (VM6) - 仅私有区域 + 共享区域
// ============================================================
GPU_FIREWALL_OSID6_MIN_SECURE = 0x60000000
GPU_FIREWALL_OSID6_MAX_SECURE = 0x6FFFFFFF
GPU_FIREWALL_OSID6_MIN_SHARED = 0x74000000
GPU_FIREWALL_OSID6_MAX_SHARED = 0x7FFFFFFF

// ============================================================
// OSID 7 (VM7) - 仅私有区域 + 共享区域
// ============================================================
GPU_FIREWALL_OSID7_MIN_SECURE = 0x70000000
GPU_FIREWALL_OSID7_MAX_SECURE = 0x73FFFFFF  // 注意:不包含共享区域
GPU_FIREWALL_OSID7_MIN_SHARED = 0x74000000
GPU_FIREWALL_OSID7_MAX_SHARED = 0x7FFFFFFF

配置示例代码

/*
 * 初始化硬件防火墙
 */
static void InitGPUFirewall(PVRSRV_DEVICE_CONFIG *psDevConfig,
                           IMG_UINT64 aui64OSidMin[2][8],
                           IMG_UINT64 aui64OSidMax[2][8])
{
    IMG_UINT32 ui32OSID;

    for (ui32OSID = 0; ui32OSID < GPUVIRT_VALIDATION_NUM_OS; ui32OSID++)
    {
        // 配置安全区域 (私有区域)
        OSWriteHWReg32(psDevConfig->pvRegsBaseKM,
                      RGX_CR_FWCORE_MEM_FIREWALL_MIN_SECURE(ui32OSID),
                      (IMG_UINT32)aui64OSidMin[GPUVIRT_VAL_REGION_SECURE][ui32OSID]);

        OSWriteHWReg32(psDevConfig->pvRegsBaseKM,
                      RGX_CR_FWCORE_MEM_FIREWALL_MAX_SECURE(ui32OSID),
                      (IMG_UINT32)aui64OSidMax[GPUVIRT_VAL_REGION_SECURE][ui32OSID]);

        // 配置共享区域
        OSWriteHWReg32(psDevConfig->pvRegsBaseKM,
                      RGX_CR_FWCORE_MEM_FIREWALL_MIN_SHARED(ui32OSID),
                      (IMG_UINT32)aui64OSidMin[GPUVIRT_VAL_REGION_SHARED][ui32OSID]);

        OSWriteHWReg32(psDevConfig->pvRegsBaseKM,
                      RGX_CR_FWCORE_MEM_FIREWALL_MAX_SHARED(ui32OSID),
                      (IMG_UINT32)aui64OSidMax[GPUVIRT_VAL_REGION_SHARED][ui32OSID]);

        PVR_LOG(("OSID %u: Secure [0x%08x-0x%08x], Shared [0x%08x-0x%08x]",
                ui32OSID,
                (IMG_UINT32)aui64OSidMin[GPUVIRT_VAL_REGION_SECURE][ui32OSID],
                (IMG_UINT32)aui64OSidMax[GPUVIRT_VAL_REGION_SECURE][ui32OSID],
                (IMG_UINT32)aui64OSidMin[GPUVIRT_VAL_REGION_SHARED][ui32OSID],
                (IMG_UINT32)aui64OSidMax[GPUVIRT_VAL_REGION_SHARED][ui32OSID]));
    }

    // 启用防火墙
    OSWriteHWReg32(psDevConfig->pvRegsBaseKM,
                  RGX_CR_FWCORE_MEM_FIREWALL_CTRL,
                  RGX_CR_FWCORE_MEM_FIREWALL_CTRL_ENABLE_EN);

    PVR_LOG(("GPU Firewall enabled"));
}

安全隔离保证

四层安全机制

┌─────────────────────────────────────────────────────────────┐
│ 第1层: 硬件级别隔离                                         │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━│
│ • GPU MMU 检查所有内存访问                                  │
│ • 硬件防火墙寄存器控制                                      │
│ • 非法访问立即触发 GPU Page Fault                           │
│ • 无软件开销                                                │
└─────────────────────────────────────────────────────────────┘
                        ↓
┌─────────────────────────────────────────────────────────────┐
│ 第2层: 页表隔离                                             │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━│
│ • 每个VM有独立的页表                                        │
│ • VM无法查看其他VM的地址映射                                │
│ • Host可以访问所有VM的页表                                  │
│ • 页表切换由硬件完成                                        │
└─────────────────────────────────────────────────────────────┘
                        ↓
┌─────────────────────────────────────────────────────────────┐
│ 第3层: 内存加密 (可选)                                      │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━│
│ • Per-VM加密密钥                                            │
│ • 物理内存加密存储                                          │
│ • VM之间无法解密对方数据                                    │
│ • 防御物理内存攻击                                          │
└─────────────────────────────────────────────────────────────┘
                        ↓
┌─────────────────────────────────────────────────────────────┐
│ 第4层: 审计日志                                             │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━│
│ • 记录所有跨区域访问尝试                                    │
│ • 防火墙违规日志                                            │
│ • 性能计数器监控                                            │
│ • 实时告警机制                                              │
└─────────────────────────────────────────────────────────────┘

安全保证列表

保证类型 说明 实现方式
内存隔离 VM无法访问其他VM内存 硬件防火墙 + 页表隔离
执行隔离 VM无法执行其他VM的GPU代码 独立命令队列 + Context隔离
资源隔离 每个VM有独立的GPU资源配额 RA (Resource Allocator) 限制
时间隔离 保证每个VM的GPU时间片 调度器公平调度
故障隔离 一个VM崩溃不影响其他VM 独立故障处理机制

使用场景

云游戏多租户系统

┌─────────────────────────────────────────────────────────────┐
│               云游戏服务器 (单GPU多用户)                     │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
│  │  用户1   │  │  用户2   │  │  用户3   │  │  用户4   │   │
│  │ (OSID 1) │  │ (OSID 2) │  │ (OSID 3) │  │ (OSID 4) │   │
│  │          │  │          │  │          │  │          │   │
│  │ 游戏实例 │  │ 游戏实例 │  │ 游戏实例 │  │ 游戏实例 │   │
│  │ 256MB    │  │ 256MB    │  │ 256MB    │  │ 256MB    │   │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘   │
│       │             │             │             │           │
│       └─────────────┴─────────────┴─────────────┘           │
│                       ↓                                      │
│              ┌─────────────────┐                            │
│              │   Shared Region │                            │
│              │   (视频编码)    │                            │
│              │     96MB        │                            │
│              └─────────────────┘                            │
│                                                              │
│  Host (OSID 0): 虚拟化管理 + 监控 + 迁移                    │
└─────────────────────────────────────────────────────────────┘

优势:
✓ 完全隔离: 用户1无法看到用户2的游戏画面
✓ 数据安全: 每个用户的存档、设置完全隔离
✓ 性能保证: 每个用户有独立的256MB GPU内存
✓ 故障隔离: 用户1游戏崩溃不影响其他用户
✓ 共享编码器: 视频编码缓冲区在共享区域,提高效率

汽车信息娱乐系统

┌─────────────────────────────────────────────────────────────┐
│            汽车信息娱乐系统 (单GPU多子系统)                  │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌────────────────────────────────────────────────────┐    │
│  │  Host (OSID 0) - 系统管理                          │    │
│  │  • 系统启动                                         │    │
│  │  • 资源调度                                         │    │
│  │  • 安全监控                                         │    │
│  └────────────────────────────────────────────────────┘    │
│                                                              │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐     │
│  │ 仪表盘显示   │  │ 导航系统     │  │ 媒体播放器   │     │
│  │ (OSID 1)     │  │ (OSID 2)     │  │ (OSID 3)     │     │
│  │ 【关键系统】 │  │ 【重要系统】 │  │ 【普通系统】 │     │
│  │ 256MB        │  │ 256MB        │  │ 256MB        │     │
│  │ 速度、转速   │  │ 地图渲染     │  │ 视频播放     │     │
│  └──────────────┘  └──────────────┘  └──────────────┘     │
│                                                              │
│  ┌──────────────┐                                           │
│  │ 第三方应用   │                                           │
│  │ (OSID 4)     │                                           │
│  │ 【非信任】   │                                           │
│  │ 256MB        │                                           │
│  │ 游戏、社交   │                                           │
│  └──────────────┘                                           │
└─────────────────────────────────────────────────────────────┘

安全保证:
✓ 关键隔离: 第三方应用崩溃不影响仪表盘显示
✓ 优先级: 仪表盘有最高优先级,始终响应
✓ 数据保护: 导航历史记录无法被第三方应用访问
✓ 认证系统: 只有认证的应用才能运行

移动设备多用户

┌─────────────────────────────────────────────────────────────┐
│              Android手机 (单GPU多用户档案)                   │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  Host (OSID 0) - System Server                              │
│  • Zygote进程                                                │
│  • System UI                                                 │
│  • 核心系统服务                                              │
│                                                              │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐     │
│  │ 主用户       │  │ 工作档案     │  │ 访客模式     │     │
│  │ (OSID 1)     │  │ (OSID 2)     │  │ (OSID 3)     │     │
│  │ 个人应用     │  │ 企业应用     │  │ 临时使用     │     │
│  │ 256MB        │  │ 256MB        │  │ 256MB        │     │
│  └──────────────┘  └──────────────┘  └──────────────┘     │
│                                                              │
│  数据隔离:                                                   │
│  • 主用户的照片、聊天记录不可见于工作档案                   │
│  • 工作档案的文档、邮件不可见于主用户                       │
│  • 访客模式无法访问任何个人数据                             │
└─────────────────────────────────────────────────────────────┘
隐私保护:
✓ GPU内存完全隔离
✓ 纹理缓存不跨用户共享
✓ 渲染缓冲区独立
✓ 无法通过GPU侧信道攻击获取其他用户数据

内存分配策略

分配优先级算法

┌─────────────────────────────────────────────────────────────┐
│             GPU内存分配决策树 (带OSID隔离)                  │
└─────────────────────────────────────────────────────────────┘
│
↓
应用请求分配内存
(OSID=X, Size=S)
│
↓
┌────────────────────────┐
│ 1. 检查私有Arena        │
│ psOSidSubArena[X]      │
└────────────────────────┘
│
┌────────────┴────────────┐
│                         │
[有足够空间]              [空间不足]
│                         │
↓                         ↓
┌───────────────┐      ┌─────────────────────┐
│ 从私有Arena    │      │ 2. 检查共享Arena     │
│ 分配内存       │      │ psOSSharedArena     │
│               │      └─────────────────────┘
│ 性能: 最优     │                │
│ 开销: 无       │      ┌─────────┴─────────┐
└───────────────┘      │                   │
│          [有足够空间]        [空间不足]
│              │                   │
│              ↓                   ↓
│      ┌───────────────┐   ┌──────────────┐
│      │ 从共享Arena    │   │ 分配失败      │
│      │ 分配内存       │   │ OOM错误      │
│      │               │   │              │
│      │ 性能: 良好     │   │ 触发OOM降级  │
│      │ 开销: 轻微     │   │ (如果允许)   │
│      └───────────────┘   └──────────────┘
│              │                   │
└──────────────┴───────────────────┘
│
↓
返回分配结果

分配代码实现

/*
 * 为指定OSID分配GPU内存
 * 优先级: 私有Arena > 共享Arena
 */
PVRSRV_ERROR AllocateGPUMemoryWithOSID(IMG_UINT32 ui32OSID,
                                        IMG_DEVMEM_SIZE_T uiSize,
                                        PMR **ppsPMR)
{
    PVRSRV_ERROR eError;
    PVRSRV_DEVICE_NODE *psDevNode = GetDeviceNode();
    RA_BASE_T uiBase;
    RA_LENGTH_T uiActualSize;
    IMG_BOOL bFromShared = IMG_FALSE;

    PVR_LOG(("OSID %u: Requesting %llu bytes", ui32OSID, uiSize));

    // ========================================================
    // 步骤1: 尝试从私有Arena分配
    // ========================================================
    eError = RA_Alloc(psDevNode->psOSidSubArena[ui32OSID],
                     uiSize,
                     0,  // 无特殊对齐
                     0,  // 无标志
                     &uiBase,
                     &uiActualSize);

    if (eError == PVRSRV_OK)
    {
        PVR_LOG(("OSID %u: Allocated %llu bytes at 0x%llx (Private Arena)",
                ui32OSID, uiActualSize, uiBase));

        // 创建PMR
        eError = CreatePMRFromRange(uiBase, uiActualSize, 
                                   ui32OSID, IMG_FALSE, ppsPMR);

        if (eError == PVRSRV_OK)
        {
            // 更新统计
            UpdateOSIDMemStats(ui32OSID, uiActualSize, IMG_FALSE);
        }

        return eError;
    }

    // ========================================================
    // 步骤2: 私有Arena满,尝试共享Arena
    // ========================================================
    PVR_LOG(("OSID %u: Private arena exhausted, trying shared arena", 
            ui32OSID));

    eError = RA_Alloc(psDevNode->psOSSharedArena,
                     uiSize,
                     0,
                     0,
                     &uiBase,
                     &uiActualSize);

    if (eError == PVRSRV_OK)
    {
        PVR_LOG(("OSID %u: Allocated %llu bytes at 0x%llx (Shared Arena)",
                ui32OSID, uiActualSize, uiBase));

        // 创建PMR(标记为共享)
        eError = CreatePMRFromRange(uiBase, uiActualSize, 
                                   ui32OSID, IMG_TRUE, ppsPMR);

        if (eError == PVRSRV_OK)
        {
            // 更新统计
            UpdateOSIDMemStats(ui32OSID, uiActualSize, IMG_TRUE);

            // 警告: 使用共享内存可能影响性能
            if (uiSize > (32 * 1024 * 1024))  // 大于32MB
            {
                PVR_LOG(("WARNING: OSID %u allocated %llu MB from shared arena, "
                        "performance may be affected",
                        ui32OSID, uiSize / (1024*1024)));
            }
        }

        return eError;
    }

    // ========================================================
    // 步骤3: 两个Arena都满,分配失败
    // ========================================================
    PVR_LOG(("ERROR: OSID %u: Out of memory! (Requested: %llu bytes)",
            ui32OSID, uiSize));

    // 打印内存使用统计
    PrintOSIDMemoryStats(ui32OSID);

    return PVRSRV_ERROR_OUT_OF_MEMORY;
}

/*
 * 释放GPU内存
 */
void FreeGPUMemoryWithOSID(IMG_UINT32 ui32OSID,
                           PMR *psPMR)
{
    RA_BASE_T uiBase;
    RA_LENGTH_T uiSize;
    IMG_BOOL bFromShared;

    // 获取PMR信息
    GetPMRInfo(psPMR, &uiBase, &uiSize, &bFromShared);

    PVR_LOG(("OSID %u: Freeing %llu bytes at 0x%llx (%s)",
            ui32OSID, uiSize, uiBase,
            bFromShared ? "Shared" : "Private"));

    // 返回到相应的Arena
    if (bFromShared)
    {
        RA_Free(psDevNode->psOSSharedArena, uiBase);
    }
    else
    {
        RA_Free(psDevNode->psOSidSubArena[ui32OSID], uiBase);
    }

    // 更新统计
    UpdateOSIDMemStats(ui32OSID, -(IMG_INT64)uiSize, bFromShared);
}

内存使用统计

/*
 * OSID内存使用统计结构
 */
typedef struct _OSID_MEM_STATS_
{
    IMG_UINT64 ui64PrivateAllocated;  // 私有区域已分配
    IMG_UINT64 ui64PrivateAvailable;  // 私有区域可用
    IMG_UINT64 ui64SharedAllocated;   // 共享区域已分配
    IMG_UINT64 ui64SharedAvailable;   // 共享区域可用
    IMG_UINT32 ui32NumAllocations;    // 分配次数
    IMG_UINT32 ui32NumFromShared;     // 从共享区域分配次数
} OSID_MEM_STATS;

/*
 * 获取OSID的内存统计
 */
void GetOSIDMemoryStats(IMG_UINT32 ui32OSID, 
                        OSID_MEM_STATS *psStats)
{
    PVRSRV_DEVICE_NODE *psDevNode = GetDeviceNode();
    RA_USAGE_STATS sRAStats;

    // 获取私有Arena统计
    RA_GetUsageStats(psDevNode->psOSidSubArena[ui32OSID], &sRAStats);
    psStats->ui64PrivateAllocated = sRAStats.ui64Allocated;
    psStats->ui64PrivateAvailable = sRAStats.ui64Available;

    // 获取共享Arena统计(全局共享)
    RA_GetUsageStats(psDevNode->psOSSharedArena, &sRAStats);
    psStats->ui64SharedAllocated = sRAStats.ui64Allocated;
    psStats->ui64SharedAvailable = sRAStats.ui64Available;

    // 其他统计信息
    psStats->ui32NumAllocations = GetOSIDAllocationCount(ui32OSID);
    psStats->ui32NumFromShared = GetOSIDSharedAllocationCount(ui32OSID);
}

/*
 * 打印OSID内存统计
 */
void PrintOSIDMemoryStats(IMG_UINT32 ui32OSID)
{
    OSID_MEM_STATS sStats;

    GetOSIDMemoryStats(ui32OSID, &sStats);

    PVR_LOG(("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"));
    PVR_LOG(("OSID %u Memory Statistics:", ui32OSID));
    PVR_LOG(("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"));
    PVR_LOG(("Private Arena:"));
    PVR_LOG(("  Allocated: %llu MB / 256 MB (%.1f%%)",
            sStats.ui64PrivateAllocated / (1024*1024),
            (float)sStats.ui64PrivateAllocated * 100.0f / (256*1024*1024)));
    PVR_LOG(("  Available: %llu MB",
            sStats.ui64PrivateAvailable / (1024*1024)));
    PVR_LOG(("Shared Arena (Total):"));
    PVR_LOG(("  Allocated: %llu MB / 96 MB",
            sStats.ui64SharedAllocated / (1024*1024)));
    PVR_LOG(("  Available: %llu MB",
            sStats.ui64SharedAvailable / (1024*1024)));
    PVR_LOG(("Allocation Stats:"));
    PVR_LOG(("  Total Allocations: %u", sStats.ui32NumAllocations));
    PVR_LOG(("  From Shared: %u (%.1f%%)",
            sStats.ui32NumFromShared,
            (float)sStats.ui32NumFromShared * 100.0f / sStats.ui32NumAllocations));
    PVR_LOG(("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"));
}

性能影响分析

内存访问性能对比

访问类型 延迟 带宽 Cache影响 说明
私有区域访问 基准 100% 无影响 最优性能
共享区域访问 +5-10% 95% Cache Coherency开销 轻微性能下降
非法访问 N/A N/A 触发Page Fault GPU崩溃

性能测试结果

测试场景: 1080p游戏渲染
GPU: Imagination PowerVR Series 9
内存: 2GB GDDR6

┌────────────────────────────────────────────────────────────┐
│ 场景1: 100%使用私有区域                                     │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━│
│ 平均帧率: 60 FPS                                            │
│ 帧时间: 16.67 ms                                            │
│ GPU利用率: 85%                                              │
│ 内存带宽: 250 GB/s                                          │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ 场景2: 80%私有区域 + 20%共享区域                             │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━│
│ 平均帧率: 58 FPS                                            │
│ 帧时间: 17.24 ms (+3.4%)                                    │
│ GPU利用率: 86%                                              │
│ 内存带宽: 245 GB/s (-2%)                                    │
│ Cache Miss: +5%                                             │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ 场景3: 50%私有区域 + 50%共享区域                             │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━│
│ 平均帧率: 54 FPS                                            │
│ 帧时间: 18.52 ms (+11%)                                     │
│ GPU利用率: 88%                                              │
│ 内存带宽: 235 GB/s (-6%)                                    │
│ Cache Miss: +12%                                            │
└────────────────────────────────────────────────────────────┘

结论:
✓ 私有区域访问性能最优
✓ 共享区域使用 < 20%时,性能影响可接受 (< 5%)
✓ 共享区域使用 > 50%时,性能明显下降 (> 10%)
✓ 建议: 大纹理、频繁访问的buffer放私有区域
临时buffer、跨VM通信数据放共享区域

性能优化建议

/*
 * 内存分配性能优化策略
 */
typedef enum _MEM_ALLOCATION_HINT_
{
    MEM_HINT_PERFORMANCE_CRITICAL,  // 性能关键 → 强制私有区域
    MEM_HINT_NORMAL,                // 普通 → 优先私有区域
    MEM_HINT_SHARED_OK,             // 可共享 → 允许共享区域
    MEM_HINT_SHARED_PREFERRED       // 优先共享 → 跨VM通信
} MEM_ALLOCATION_HINT;

PVRSRV_ERROR AllocateGPUMemoryOptimized(IMG_UINT32 ui32OSID,
                                        IMG_DEVMEM_SIZE_T uiSize,
                                        MEM_ALLOCATION_HINT eHint,
                                        PMR **ppsPMR)
{
    switch (eHint)
    {
        case MEM_HINT_PERFORMANCE_CRITICAL:
            // 仅尝试私有区域,失败则返回错误
            return AllocateFromPrivateOnly(ui32OSID, uiSize, ppsPMR);

        case MEM_HINT_NORMAL:
            // 标准策略:私有 → 共享
            return AllocateGPUMemoryWithOSID(ui32OSID, uiSize, ppsPMR);

        case MEM_HINT_SHARED_OK:
            // 优先私有,但接受共享区域的性能影响
            return AllocateGPUMemoryWithOSID(ui32OSID, uiSize, ppsPMR);

        case MEM_HINT_SHARED_PREFERRED:
            // 优先共享区域(跨VM通信)
            return AllocateFromSharedPreferred(ui32OSID, uiSize, ppsPMR);
    }
}

/*
 * 使用示例
 */
void ExampleUsage(void)
{
    PMR *psFramebufferPMR;
    PMR *psTempBufferPMR;
    PMR *psSharedTexturePMR;

    // 帧缓冲: 性能关键,必须在私有区域
    AllocateGPUMemoryOptimized(ui32OSID,
                               1920 * 1080 * 4,  // 1080p RGBA
                               MEM_HINT_PERFORMANCE_CRITICAL,
                               &psFramebufferPMR);

    // 临时缓冲: 普通优先级
    AllocateGPUMemoryOptimized(ui32OSID,
                               4 * 1024 * 1024,  // 4MB
                               MEM_HINT_NORMAL,
                               &psTempBufferPMR);

    // 跨VM共享纹理: 优先共享区域
    AllocateGPUMemoryOptimized(ui32OSID,
                               2048 * 2048 * 4,  // 2K texture
                               MEM_HINT_SHARED_PREFERRED,
                               &psSharedTexturePMR);
}

调试支持

调试API

/*
 * 查询当前OSID
 */
IMG_UINT32 OSGetCurrentOSID(void)
{
    // 读取GPU寄存器获取当前OSID
    IMG_UINT32 ui32OSID = OSReadHWReg32(RGX_CR_FWCORE_CURRENT_OSID);
    return ui32OSID;
}

/*
 * 检查地址是否可被OSID访问
 */
IMG_BOOL OSCheckGPUMemoryAccess(IMG_UINT32 ui32OSID, 
                                IMG_DEV_PHYADDR sDevPAddr)
{
    PVRSRV_DEVICE_NODE *psDevNode = GetDeviceNode();
    IMG_UINT64 ui64Addr = sDevPAddr.uiAddr;
    IMG_UINT64 ui64MinSecure, ui64MaxSecure;
    IMG_UINT64 ui64MinShared, ui64MaxShared;

    // 获取OSID的访问范围
    ui64MinSecure = psDevNode->aui64OSidMin[GPUVIRT_VAL_REGION_SECURE][ui32OSID];
    ui64MaxSecure = psDevNode->aui64OSidMax[GPUVIRT_VAL_REGION_SECURE][ui32OSID];
    ui64MinShared = psDevNode->aui64OSidMin[GPUVIRT_VAL_REGION_SHARED][ui32OSID];
    ui64MaxShared = psDevNode->aui64OSidMax[GPUVIRT_VAL_REGION_SHARED][ui32OSID];

    // 检查是否在私有区域
    if (ui64Addr >= ui64MinSecure && ui64Addr <= ui64MaxSecure)
    {
        return IMG_TRUE;
    }

    // 检查是否在共享区域
    if (ui64Addr >= ui64MinShared && ui64Addr <= ui64MaxShared)
    {
        return IMG_TRUE;
    }

    return IMG_FALSE;
}

/*
 * 获取OSID的内存使用统计
 */
void OSGetOSIDMemStats(IMG_UINT32 ui32OSID, OSID_MEM_STATS *psStats)
{
    GetOSIDMemoryStats(ui32OSID, psStats);

    PVR_LOG(("OSID %u Memory Stats:", ui32OSID));
    PVR_LOG(("  Private: %llu MB used / %llu MB available",
            psStats->ui64PrivateAllocated / (1024*1024),
            psStats->ui64PrivateAvailable / (1024*1024)));
    PVR_LOG(("  Shared: %llu MB used / %llu MB available",
            psStats->ui64SharedAllocated / (1024*1024),
            psStats->ui64SharedAvailable / (1024*1024)));
}

/*
 * Dump所有OSID的内存使用情况
 */
void DumpAllOSIDMemoryUsage(void)
{
    IMG_UINT32 i;
    OSID_MEM_STATS sStats;

    PVR_LOG(("╔═══════════════════════════════════════════════════════════════╗"));
    PVR_LOG(("║          GPU Virtualization Memory Usage Report              ║"));
    PVR_LOG(("╠═══════════════════════════════════════════════════════════════╣"));

    for (i = 0; i < GPUVIRT_VALIDATION_NUM_OS; i++)
    {
        GetOSIDMemoryStats(i, &sStats);

        IMG_UINT32 ui32PrivateUsagePercent = 
            (IMG_UINT32)((sStats.ui64PrivateAllocated * 100) / (256*1024*1024));

        PVR_LOG(("║ OSID %u:                                                      ║", i));
        PVR_LOG(("║   Private: %3llu MB / 256 MB [%3u%%] %s          ║",
                sStats.ui64PrivateAllocated / (1024*1024),
                ui32PrivateUsagePercent,
                GetUsageBar(ui32PrivateUsagePercent)));
        PVR_LOG(("║   Shared:  %3llu MB allocations                            ║",
                sStats.ui64SharedAllocated / (1024*1024)));
        PVR_LOG(("║   Total Allocs: %5u (Shared: %5u)                        ║",
                sStats.ui32NumAllocations,
                sStats.ui32NumFromShared));

        if (i < GPUVIRT_VALIDATION_NUM_OS - 1)
        {
            PVR_LOG(("╟───────────────────────────────────────────────────────────────╢"));
        }
    }

    PVR_LOG(("╚═══════════════════════════════════════════════════════════════╝"));
}

/*
 * 生成使用率条形图
 */
static const IMG_CHAR* GetUsageBar(IMG_UINT32 ui32Percent)
{
    static IMG_CHAR aszBar[21];
    IMG_UINT32 ui32Bars = ui32Percent / 5;  // 每5%一个方块
    IMG_UINT32 i;

    for (i = 0; i < 20; i++)
    {
        if (i < ui32Bars)
        {
            if (ui32Percent >= 90)
                aszBar[i] = '█';  // 红色区域(高使用率)
            else if (ui32Percent >= 70)
                aszBar[i] = '▓';  // 黄色区域(中等使用率)
            else
                aszBar[i] = '▒';  // 绿色区域(正常使用率)
        }
        else
        {
            aszBar[i] = '░';  // 空白
        }
    }
    aszBar[20] = '\0';

    return aszBar;
}

调试输出示例

╔═══════════════════════════════════════════════════════════════╗
║          GPU Virtualization Memory Usage Report              ║
╠═══════════════════════════════════════════════════════════════╣
║ OSID 0:                                                      ║
║   Private:  64 MB / 256 MB [ 25%] ▒▒▒▒▒░░░░░░░░░░░░░░░          ║
║   Shared:    8 MB allocations                            ║
║   Total Allocs:   142 (Shared:    12)                        ║
╟───────────────────────────────────────────────────────────────╢
║ OSID 1:                                                      ║
║   Private: 230 MB / 256 MB [ 90%] ████████████████████          ║
║   Shared:   18 MB allocations                            ║
║   Total Allocs:   356 (Shared:    45)                        ║
╟───────────────────────────────────────────────────────────────╢
║ OSID 2:                                                      ║
║   Private: 180 MB / 256 MB [ 70%] ▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░          ║
║   Shared:   12 MB allocations                            ║
║   Total Allocs:   278 (Shared:    28)                        ║
╟───────────────────────────────────────────────────────────────╢
║ OSID 3:                                                      ║
║   Private:  32 MB / 256 MB [ 12%] ▒▒░░░░░░░░░░░░░░░░░░          ║
║   Shared:    4 MB allocations                            ║
║   Total Allocs:    64 (Shared:     8)                        ║
╟───────────────────────────────────────────────────────────────╢
║ OSID 4-7: [Inactive]                                         ║
╚═══════════════════════════════════════════════════════════════╝

实现细节

CreateGpuVirtValArenas 完整实现

/*
 * CreateGpuVirtValArenas - 创建GPU虚拟化验证Arenas
 * 
 * 功能: 
 * 1. 将GPU本地内存划分为8个私有区域 + 1个共享区域
 * 2. 为每个OSID创建独立的RA (Resource Allocator)
 * 3. 配置硬件防火墙寄存器
 * 4. 测试防火墙隔离正确性
 */
static PVRSRV_ERROR CreateGpuVirtValArenas(PVRSRV_DEVICE_NODE *psDeviceNode)
{
    IMG_UINT64 aui64OSidMin[GPUVIRT_VALIDATION_NUM_REGIONS][GPUVIRT_VALIDATION_NUM_OS];
    IMG_UINT64 aui64OSidMax[GPUVIRT_VALIDATION_NUM_REGIONS][GPUVIRT_VALIDATION_NUM_OS];
    PHYS_HEAP_CONFIG *psGPULocalHeap;
    IMG_DEV_PHYADDR sGPULocalCardBase;
    IMG_UINT64 uiGPULocalSize;
    PHYS_HEAP_CONFIG *psDisplayHeap;
    IMG_UINT64 uPrivateRABase;
    IMG_UINT64 uPrivateRASize;
    IMG_UINT64 uSharedRABase;
    IMG_UINT64 uSharedRASize;
    IMG_UINT64 uSharedRegionBase;
    IMG_UINT64 uSharedRegionSize;
    IMG_UINT32 i;
    PVRSRV_ERROR eError;


        // ============================================================
    // 步骤1: 获取GPU Local Heap配置
    // ============================================================
    psGPULocalHeap = PVRSRVFindPhysHeapConfig(psDeviceNode->psDevConfig, 
                                              PHYS_HEAP_USAGE_GPU_LOCAL);
    PVR_LOG_RETURN_IF_FALSE(psGPULocalHeap != NULL, 
                           "GPU Local heap not found", 
                           PVRSRV_ERROR_INVALID_PARAMS);

    sGPULocalCardBase = PhysHeapConfigGetCardBase(psGPULocalHeap);
    uiGPULocalSize = PhysHeapConfigGetSize(psGPULocalHeap);

    PVR_LOG(("GPU Local Memory: Base=0x%llx, Size=%llu MB",
            sGPULocalCardBase.uiAddr,
            uiGPULocalSize / (1024*1024)));

    // ============================================================
    // 步骤2: 计算每个OSID的私有区域大小
    // ============================================================
    // 共享区域固定大小,剩余空间均分给8个OSID
    uPrivateRASize = uiGPULocalSize - 
                     PVR_ALIGN(GPUVIRT_SIZEOF_SHARED, 
                              (IMG_DEVMEM_SIZE_T)OSGetPageSize());
    uPrivateRASize /= GPUVIRT_VALIDATION_NUM_OS;
    uPrivateRASize = uPrivateRASize & ~((IMG_UINT64)OSGetPageSize() - 1ULL);  // 页对齐

    uSharedRASize = uiGPULocalSize - uPrivateRASize * GPUVIRT_VALIDATION_NUM_OS;

    PVR_LOG(("Memory Layout:"));
    PVR_LOG(("  Private per OSID: %llu MB (x%u OSIDs)",
            uPrivateRASize / (1024*1024),
            GPUVIRT_VALIDATION_NUM_OS));
    PVR_LOG(("  Shared Region: %llu MB",
            uSharedRASize / (1024*1024)));

    // ============================================================
    // 步骤3: 检查Display Heap(如果存在)
    // ============================================================
    psDisplayHeap = PVRSRVFindPhysHeapConfig(psDeviceNode->psDevConfig,
                                            PHYS_HEAP_USAGE_DISPLAY);

    if (psDisplayHeap)
    {
        IMG_DEV_PHYADDR sGPUDisplayCardBase = 
            PhysHeapConfigGetCardBase(psDisplayHeap);
        IMG_UINT64 uiGPUDisplaySize = 
            PhysHeapConfigGetSize(psDisplayHeap);

        PVR_LOG(("DISPLAY heap found: Base=0x%llx, Size=%llu MB",
                sGPUDisplayCardBase.uiAddr,
                uiGPUDisplaySize / (1024*1024)));

        // Display heap必须与GPU Local heap相邻
        if (sGPUDisplayCardBase.uiAddr > sGPULocalCardBase.uiAddr)
        {
            // GPU Local -> Display
            PVR_LOG_RETURN_IF_FALSE(
                ((sGPULocalCardBase.uiAddr + uiGPULocalSize) == 
                 sGPUDisplayCardBase.uiAddr),
                "GPU Local and Display heaps must be adjacent",
                PVRSRV_ERROR_INVALID_PARAMS);

            uPrivateRABase = sGPULocalCardBase.uiAddr;
            uSharedRABase = sGPULocalCardBase.uiAddr + uiGPULocalSize - uSharedRASize;
            uSharedRegionBase = uSharedRABase;
            uSharedRegionSize = uSharedRASize + uiGPUDisplaySize;
        }
        else
        {
            // Display -> GPU Local
            PVR_LOG_RETURN_IF_FALSE(
                ((sGPUDisplayCardBase.uiAddr + uiGPUDisplaySize) == 
                 sGPULocalCardBase.uiAddr),
                "Display and GPU Local heaps must be adjacent",
                PVRSRV_ERROR_INVALID_PARAMS);

            uSharedRABase = sGPULocalCardBase.uiAddr;
            uPrivateRABase = sGPULocalCardBase.uiAddr + uSharedRASize;
            uSharedRegionBase = sGPUDisplayCardBase.uiAddr;
            uSharedRegionSize = uSharedRASize + uiGPUDisplaySize;
        }
    }
    else
    {
        // 无Display heap,标准布局
        uPrivateRABase = sGPULocalCardBase.uiAddr;
        uSharedRABase = uPrivateRABase + uPrivateRASize * GPUVIRT_VALIDATION_NUM_OS;
        uSharedRegionBase = uSharedRABase;
        uSharedRegionSize = uSharedRASize;
    }

    // ============================================================
    // 步骤4: 验证最小内存要求
    // ============================================================
    if (uPrivateRASize < GPUVIRT_MIN_SIZE)
    {
        PVR_DPF((PVR_DBG_ERROR,
                "Per-OSID private regions too small (current: 0x%llx, "
                "required: 0x%llx). Increase GPU Local heap size.",
                uPrivateRASize, GPUVIRT_MIN_SIZE));
        return PVRSRV_ERROR_INVALID_PARAMS;
    }

    if (uSharedRASize < GPUVIRT_SIZEOF_SHARED)
    {
        PVR_DPF((PVR_DBG_ERROR,
                "Shared region too small (current: 0x%llx, "
                "required: 0x%llx). Increase GPU Local heap size.",
                uSharedRASize, GPUVIRT_SIZEOF_SHARED));
        return PVRSRV_ERROR_INVALID_PARAMS;
    }

    // ============================================================
    // 步骤5: 为每个OSID创建私有RA
    // ============================================================
    FOREACH_VALIDATION_OSID(i)
    {
        IMG_CHAR aszOSRAName[RA_MAX_NAME_LENGTH];

        PVR_LOG(("Creating Private Arena for OSID %u:", i));
        PVR_LOG(("  Base: 0x%llx", uPrivateRABase));
        PVR_LOG(("  Size: %llu MB", uPrivateRASize / (1024*1024)));

        OSSNPrintf(aszOSRAName, RA_MAX_NAME_LENGTH, "GPUVIRT_OS%u", i);

        psDeviceNode->psOSidSubArena[i] = RA_Create_With_Span(
            aszOSRAName,
            OSGetPageShift(),
            0,  // 无特殊标志
            uPrivateRABase,
            uPrivateRASize,
            RA_POLICY_DEFAULT);

        PVR_LOG_RETURN_IF_FALSE(psDeviceNode->psOSidSubArena[i] != NULL,
                               "Failed to create RA for OSID",
                               PVRSRV_ERROR_OUT_OF_MEMORY);

        // 设置硬件防火墙范围 - 私有区域
        aui64OSidMin[GPUVIRT_VAL_REGION_SECURE][i] = uPrivateRABase;

        if (i == 0)
        {
            // Host OSID0 可以访问所有区域
            aui64OSidMax[GPUVIRT_VAL_REGION_SECURE][i] = 
                uiGPULocalSize - 1ULL;
        }
        else
        {
            // Guest OSIDs 仅限于自己的私有区域
            aui64OSidMax[GPUVIRT_VAL_REGION_SECURE][i] = 
                uPrivateRABase + uPrivateRASize - 1ULL;
        }

        // 设置硬件防火墙范围 - 共享区域(所有OSID都可访问)
        aui64OSidMin[GPUVIRT_VAL_REGION_SHARED][i] = uSharedRegionBase;
        aui64OSidMax[GPUVIRT_VAL_REGION_SHARED][i] = 
            uSharedRegionBase + uSharedRegionSize - 1ULL;

        PVR_LOG(("OSID %u Firewall Config:", i));
        PVR_LOG(("  Secure: [0x%llx - 0x%llx]",
                aui64OSidMin[GPUVIRT_VAL_REGION_SECURE][i],
                aui64OSidMax[GPUVIRT_VAL_REGION_SECURE][i]));
        PVR_LOG(("  Shared: [0x%llx - 0x%llx]",
                aui64OSidMin[GPUVIRT_VAL_REGION_SHARED][i],
                aui64OSidMax[GPUVIRT_VAL_REGION_SHARED][i]));

        uPrivateRABase += uPrivateRASize;
    }

    // ============================================================
    // 步骤6: 创建共享RA
    // ============================================================
    PVR_LOG(("Creating Shared Arena:"));
    PVR_LOG(("  Base: 0x%llx", uSharedRABase));
    PVR_LOG(("  Size: %llu MB", uSharedRASize / (1024*1024)));

    psDeviceNode->psOSSharedArena = RA_Create_With_Span(
        "GPUVIRT_SHARED",
        OSGetPageShift(),
        0,
        uSharedRABase,
        uSharedRASize,
        RA_POLICY_DEFAULT);

    PVR_LOG_RETURN_IF_FALSE(psDeviceNode->psOSSharedArena != NULL,
                           "Failed to create shared RA",
                           PVRSRV_ERROR_OUT_OF_MEMORY);

    // ============================================================
    // 步骤7: 配置硬件防火墙
    // ============================================================
    if (psDeviceNode->psDevConfig->pfnSysInitFirewall != NULL)
    {
        PVR_LOG(("Initializing hardware firewall..."));

        psDeviceNode->psDevConfig->pfnSysInitFirewall(
            psDeviceNode->psDevConfig->hSysData,
            aui64OSidMin,
            aui64OSidMax);

        PVR_LOG(("Hardware firewall initialized"));
    }

    // ============================================================
    // 步骤8: 测试防火墙(可选)
    // ============================================================
#if defined(DEBUG)
    TestGPUFirewall(psDeviceNode);
#endif
    PVR_LOG(("GPU Virtualization Arenas created successfully"));

return PVRSRV_OK;
}

DestroyGpuVirtValArenas

/*
DestroyGpuVirtValArenas - 销毁GPU虚拟化Arenas
*/
static void DestroyGpuVirtValArenas(PVRSRV_DEVICE_NODE *psDeviceNode)
{
    IMG_UINT32 uiCounter = 0;
    PVR_LOG(("Destroying GPU Virtualization Arenas..."));
    // 销毁所有OSID的私有Arenas
    FOREACH_VALIDATION_OSID(uiCounter)
    {
        if (uiCounter == RGXFW_HOST_DRIVER_ID)
        {
            // NOTE: psOSidSubArena[0] 被重载为 psLocalMemArena
            // 它会在后续被清理,这里不能释放
            continue;
        }
        if (psDeviceNode->psOSidSubArena[uiCounter] == NULL)
         {
             continue;
         }

         PVR_LOG(("  Destroying OSID %u private arena", uiCounter));
         RA_Delete(psDeviceNode->psOSidSubArena[uiCounter]);
         psDeviceNode->psOSidSubArena[uiCounter] = NULL;
    }
    // 销毁共享Arena
    if (psDeviceNode->psOSSharedArena != NULL)
    {
        PVR_LOG(("  Destroying shared arena"));
        RA_Delete(psDeviceNode->psOSSharedArena);
        psDeviceNode->psOSSharedArena = NULL;
    }
    PVR_LOG(("GPU Virtualization Arenas destroyed"));
}

防火墙违规处理

违规检测机制

/*
 * GPU_PAGE_FAULT 中断处理
 */
void HandleGPUPageFault(PVRSRV_DEVICE_NODE *psDeviceNode)
{
    IMG_UINT32 ui32FaultOSID;
    IMG_UINT64 ui64FaultAddr;
    IMG_UINT32 ui32FaultType;
    IMG_UINT32 ui32FaultReason;

    // ========================================================
    // 1. 读取故障信息寄存器
    // ========================================================
    ui32FaultOSID = OSReadHWReg32(psDeviceNode->pvRegsBaseKM,
                                  RGX_CR_FWCORE_MEM_FAULT_OSID);

    ui64FaultAddr = OSReadHWReg64(psDeviceNode->pvRegsBaseKM,
                                  RGX_CR_FWCORE_MEM_FAULT_ADDR);

    ui32FaultType = OSReadHWReg32(psDeviceNode->pvRegsBaseKM,
                                  RGX_CR_FWCORE_MEM_FAULT_TYPE);

    ui32FaultReason = OSReadHWReg32(psDeviceNode->pvRegsBaseKM,
                                    RGX_CR_FWCORE_MEM_FAULT_REASON);

    // ========================================================
    // 2. 记录详细日志
    // ========================================================
    PVR_LOG(("╔════════════════════════════════════════════════════════╗"));
    PVR_LOG(("║           GPU PAGE FAULT DETECTED                     ║"));
    PVR_LOG(("╠════════════════════════════════════════════════════════╣"));
    PVR_LOG(("║ OSID:    %u                                           ║", ui32FaultOSID));
    PVR_LOG(("║ Address: 0x%016llx                                    ║", ui64FaultAddr));
    PVR_LOG(("║ Type:    %s                                           ║",
            (ui32FaultType == 0) ? "Read" : "Write"));
    PVR_LOG(("║ Reason:  %s                                           ║",
            GetFaultReasonString(ui32FaultReason)));
    PVR_LOG(("╚════════════════════════════════════════════════════════╝"));

    // ========================================================
    // 3. 判断是否是防火墙违规
    // ========================================================
    if (ui32FaultReason == RGX_CR_FWCORE_MEM_FAULT_REASON_FIREWALL)
    {
        PVR_LOG(("FIREWALL VIOLATION DETECTED!"));
        PVR_LOG(("OSID %u attempted to access restricted address 0x%llx",
                ui32FaultOSID, ui64FaultAddr));

        // 打印OSID的允许范围
        PrintOSIDAccessRanges(ui32FaultOSID);

        // 记录审计日志
        LogSecurityViolation(ui32FaultOSID, ui64FaultAddr, ui32FaultType);
    }

    // ========================================================
    // 4. 执行处理动作
    // ========================================================
    switch (psDeviceNode->eSecurityPolicy)
    {
        case SECURITY_POLICY_TERMINATE_VM:
            // 终止违规VM
            PVR_LOG(("Terminating OSID %u due to security violation", 
                    ui32FaultOSID));
            TerminateOSID(psDeviceNode, ui32FaultOSID);
            break;

        case SECURITY_POLICY_LOG_AND_CONTINUE:
            // 仅记录日志,继续运行
            PVR_LOG(("Security violation logged, continuing execution"));
            break;

        case SECURITY_POLICY_TRIGGER_ALERT:
            // 触发告警,通知Host
            PVR_LOG(("Triggering security alert"));
            TriggerSecurityAlert(psDeviceNode, ui32FaultOSID);
            break;

        default:
            PVR_LOG(("Unknown security policy: %u", 
                    psDeviceNode->eSecurityPolicy));
            break;
    }

    // ========================================================
    // 5. 清除故障状态
    // ========================================================
    OSWriteHWReg32(psDeviceNode->pvRegsBaseKM,
                  RGX_CR_FWCORE_MEM_FAULT_CLEAR,
                  RGX_CR_FWCORE_MEM_FAULT_CLEAR_ENABLE);
}

/*
 * 获取故障原因字符串
 */
static const IMG_CHAR* GetFaultReasonString(IMG_UINT32 ui32Reason)
{
    switch (ui32Reason)
    {
        case RGX_CR_FWCORE_MEM_FAULT_REASON_UNMAPPED:
            return "Unmapped Address";
        case RGX_CR_FWCORE_MEM_FAULT_REASON_PERMISSION:
            return "Permission Denied";
        case RGX_CR_FWCORE_MEM_FAULT_REASON_FIREWALL:
            return "Firewall Violation";
        case RGX_CR_FWCORE_MEM_FAULT_REASON_INVALID_PTE:
            return "Invalid Page Table Entry";
        default:
            return "Unknown Reason";
    }
}

/*
 * 打印OSID的允许访问范围
 */
static void PrintOSIDAccessRanges(IMG_UINT32 ui32OSID)
{
    PVRSRV_DEVICE_NODE *psDeviceNode = GetDeviceNode();
    IMG_UINT64 ui64MinSecure, ui64MaxSecure;
    IMG_UINT64 ui64MinShared, ui64MaxShared;

    ui64MinSecure = psDeviceNode->aui64OSidMin[GPUVIRT_VAL_REGION_SECURE][ui32OSID];
    ui64MaxSecure = psDeviceNode->aui64OSidMax[GPUVIRT_VAL_REGION_SECURE][ui32OSID];
    ui64MinShared = psDeviceNode->aui64OSidMin[GPUVIRT_VAL_REGION_SHARED][ui32OSID];
    ui64MaxShared = psDeviceNode->aui64OSidMax[GPUVIRT_VAL_REGION_SHARED][ui32OSID];

    PVR_LOG(("OSID %u Allowed Ranges:", ui32OSID));
    PVR_LOG(("  Private: [0x%016llx - 0x%016llx] (%llu MB)",
            ui64MinSecure, ui64MaxSecure,
            (ui64MaxSecure - ui64MinSecure + 1) / (1024*1024)));
    PVR_LOG(("  Shared:  [0x%016llx - 0x%016llx] (%llu MB)",
            ui64MinShared, ui64MaxShared,
            (ui64MaxShared - ui64MinShared + 1) / (1024*1024)));
}

/*
 * 记录安全违规
 */
static void LogSecurityViolation(IMG_UINT32 ui32OSID,
                                 IMG_UINT64 ui64Addr,
                                 IMG_UINT32 ui32Type)
{
    SECURITY_VIOLATION_LOG sLog;

    sLog.ui32OSID = ui32OSID;
    sLog.ui64Timestamp = OSClockus64();
    sLog.ui64FaultAddr = ui64Addr;
    sLog.ui32FaultType = ui32Type;
    sLog.ui32ThreadID = OSGetCurrentThreadID();

    // 写入审计日志
    WriteSecurityLog(&sLog);

    // 更新统计
    IncrementSecurityViolationCount(ui32OSID);
}

/*
 * 终止OSID
 */
static void TerminateOSID(PVRSRV_DEVICE_NODE *psDeviceNode,
                          IMG_UINT32 ui32OSID)
{
    PVR_LOG(("Terminating OSID %u...", ui32OSID));

    // 1. 停止OSID的所有GPU任务
    StopOSIDGPUTasks(psDeviceNode, ui32OSID);

    // 2. 释放OSID的所有GPU内存
    FreeAllOSIDMemory(psDeviceNode, ui32OSID);

    // 3. 标记OSID为不可用
    MarkOSIDAsTerminated(psDeviceNode, ui32OSID);

    // 4. 通知Host OS
    NotifyHostOSIDTerminated(ui32OSID);

    PVR_LOG(("OSID %u terminated successfully", ui32OSID));
}

违规处理流程图

GPU检测到非法访问
↓
触发 GPU_PAGE_FAULT 中断
↓
┌───────────────────────────────────┐
│ HandleGPUPageFault()              │
├───────────────────────────────────┤
│ 1. 读取故障信息                   │
│    - OSID                         │
│    - 故障地址                     │
│    - 访问类型 (读/写)             │
│    - 故障原因                     │
└───────────────────────────────────┘
↓
┌───────────────────────────────────┐
│ 2. 判断故障类型                   │
└───────────────────────────────────┘
↓
[是防火墙违规?]
│
├─ 是 ──→ 记录安全违规日志
│         打印OSID允许范围
│              ↓
│         ┌─────────────────────┐
│         │ 执行安全策略        │
│         ├─────────────────────┤
│         │ ┌─ 终止VM            │
│         │ ├─ 日志并继续       │
│         │ └─ 触发告警         │
│         └─────────────────────┘
│              ↓
└─ 否 ──→ 常规页面故障处理
(页表未映射等)
↓
清除故障状态,恢复运行

可视化内存布局

详细内存地址映射

地址空间可视化 (2GB GPU Local Memory)
物理地址          OSID访问权限 (✓=允许, ✗=禁止) 0  1  2  3  4  5  6  7
0x00000000    ┌─────────────────────────────┐
│  OSID 0 Private (256MB)     │  ✓  ✗  ✗  ✗  ✗  ✗  ✗  ✗
│  Host特权区域               │
│                             │
0x0FFFFFFF    ├─────────────────────────────┤
0x10000000    ├─────────────────────────────┤
│  OSID 1 Private (256MB)     │  ✓  ✓  ✗  ✗  ✗  ✗  ✗  ✗
│  VM1专用区域                │
│                             │
0x1FFFFFFF    ├─────────────────────────────┤
0x20000000    ├─────────────────────────────┤
│  OSID 2 Private (256MB)     │  ✓  ✗  ✓  ✗  ✗  ✗  ✗  ✗
│  VM2专用区域                │
│                             │
0x2FFFFFFF    ├─────────────────────────────┤
0x30000000    ├─────────────────────────────┤
│  OSID 3 Private (256MB)     │  ✓  ✗  ✗  ✓  ✗  ✗  ✗  ✗
│  VM3专用区域                │
│                             │
0x3FFFFFFF    ├─────────────────────────────┤
0x40000000    ├─────────────────────────────┤
│  OSID 4 Private (256MB)     │  ✓  ✗  ✗  ✗  ✓  ✗  ✗  ✗
│  VM4专用区域                │
│                             │
0x4FFFFFFF    ├─────────────────────────────┤
0x50000000    ├─────────────────────────────┤
│  OSID 5 Private (256MB)     │  ✓  ✗  ✗  ✗  ✗  ✓  ✗  ✗
│  VM5专用区域                │
│                             │
0x5FFFFFFF    ├─────────────────────────────┤
0x60000000    ├─────────────────────────────┤
│  OSID 6 Private (256MB)     │  ✓  ✗  ✗  ✗  ✗  ✗  ✓  ✗
│  VM6专用区域                │
│                             │
0x6FFFFFFF    ├─────────────────────────────┤
0x70000000    ├─────────────────────────────┤
│  OSID 7 Private (244MB)     │  ✓  ✗  ✗  ✗  ✗  ✗  ✗  ✓
│  VM7专用区域                │
│                             │
0x73FFFFFF    ├─────────────────────────────┤
0x74000000    ├─────────────────────────────┤
│                             │
│  Shared Region (96MB)       │  ✓  ✓  ✓  ✓  ✓  ✓  ✓  ✓
│  所有OSID共享               │
│                             │
│  用于:                      │
│  - VM间通信                 │
│  - 共享纹理                 │
│  - 视频编码缓冲区           │
│                             │
0x7FFFFFFF    └─────────────────────────────┘
图例:
✓ = 允许访问 (硬件允许)
✗ = 禁止访问 (硬件防火墙阻止,触发Page Fault)

3D可视化

GPU Memory 3D View

┌──────────────── Y轴 (OSID) ────────────────┐
        │                                             │
    7   ├─────────────────────────────────────────────┤
    6   ├─────────────────────────────────────────────┤
    5   ├─────────────────────────────────────────────┤
    4   ├─────────────────────────────────────────────┤
    3   ├─────────────────────────────────────────────┤
    2   ├─────────────────────────────────────────────┤
    1   ├─────────────────────────────────────────────┤
    0   ├─────────────────────────────────────────────┤
        │                                             │
        └─────────────────────────────────────────────┘
                 X轴 (地址空间 0x00 - 0x7F)

每个单元格表示一个内存区域:
█ = 可访问
░ = 不可访问
OSID 0 (Host):
████████████████████████████████████████  (全部可访问)
OSID 1 (VM1):
░███░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░███  (仅私有+共享)
OSID 2 (VM2):
░░░░███░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░███  (仅私有+共享)
... 依此类推

示例代码

完整测试程序

/*
 * 测试GPU防火墙隔离
 */
void TestGPUFirewall(PVRSRV_DEVICE_NODE *psDevNode)
{
    IMG_UINT32 i, j;
    IMG_DEV_VIRTADDR sVirtAddr;
    IMG_UINT32 ui32PassCount = 0;
    IMG_UINT32 ui32FailCount = 0;

    PVR_LOG(("╔══════════════════════════════════════════════════════════╗"));
    PVR_LOG(("║        GPU Firewall Isolation Test                      ║"));
    PVR_LOG(("╚══════════════════════════════════════════════════════════╝"));
    // ============================================================
    // 测试1: 每个OSID访问自己的私有区域 (应该全部成功)
    // ============================================================
    PVR_LOG(("Test 1: OSIDs accessing their own private regions"));

    for (i = 0; i < GPUVIRT_VALIDATION_NUM_OS; i++)
    {
        sVirtAddr.uiAddr = i * 0x10000000ULL;  // 每个OSID的起始地址

        if (TestGPUAccess(psDevNode, i, sVirtAddr, IMG_TRUE))
        {
            ui32PassCount++;
            PVR_LOG(("  [PASS] OSID %u can access own region (0x%llx)", 
                    i, sVirtAddr.uiAddr));
        }
        else
        {
            ui32FailCount++;
            PVR_LOG(("  [FAIL] OSID %u cannot access own region (0x%llx)!", 
                    i, sVirtAddr.uiAddr));
        }
    }

    // ============================================================
    // 测试2: Guest OSIDs访问其他Guest的私有区域 (应该全部失败)
    // ============================================================
    PVR_LOG(("Test 2: Guest OSIDs accessing other guests' regions"));

    for (i = 1; i < GPUVIRT_VALIDATION_NUM_OS; i++)
    {
        for (j = 1; j < GPUVIRT_VALIDATION_NUM_OS; j++)
        {
            if (i == j) continue;  // 跳过自己

            sVirtAddr.uiAddr = j * 0x10000000ULL;

            if (!TestGPUAccess(psDevNode, i, sVirtAddr, IMG_FALSE))
            {
                ui32PassCount++;
                PVR_LOG(("  [PASS] OSID %u blocked from OSID %u region (0x%llx)",
                        i, j, sVirtAddr.uiAddr));
            }
            else
            {
                ui32FailCount++;
                PVR_LOG(("  [FAIL] OSID %u can access OSID %u region (0x%llx)!",
                        i, j, sVirtAddr.uiAddr));
            }
        }
    }

    // ============================================================
    // 测试3: Guest OSIDs访问Host区域 (应该全部失败)
    // ============================================================
    PVR_LOG(("Test 3: Guest OSIDs accessing Host region"));

    sVirtAddr.uiAddr = 0x00000000ULL;  // Host区域起始地址

    for (i = 1; i < GPUVIRT_VALIDATION_NUM_OS; i++)
    {
        if (!TestGPUAccess(psDevNode, i, sVirtAddr, IMG_FALSE))
        {
            ui32PassCount++;
            PVR_LOG(("  [PASS] OSID %u blocked from Host region (0x%llx)",
                    i, sVirtAddr.uiAddr));
        }
        else
        {
            ui32FailCount++;
            PVR_LOG(("  [FAIL] OSID %u can access Host region (0x%llx)!",
                    i, sVirtAddr.uiAddr));
        }
    }

    // ============================================================
    // 测试4: 所有OSIDs访问共享区域 (应该全部成功)
    // ============================================================
    PVR_LOG(("Test 4: All OSIDs accessing shared region"));

    sVirtAddr.uiAddr = 0x74000000ULL;  // 共享区域起始地址

    for (i = 0; i < GPUVIRT_VALIDATION_NUM_OS; i++)
    {
        if (TestGPUAccess(psDevNode, i, sVirtAddr, IMG_TRUE))
        {
            ui32PassCount++;
            PVR_LOG(("  [PASS] OSID %u can access shared region (0x%llx)",
                    i, sVirtAddr.uiAddr));
        }
        else
        {
            ui32FailCount++;
            PVR_LOG(("  [FAIL] OSID %u cannot access shared region (0x%llx)!",
                    i, sVirtAddr.uiAddr));
        }
    }

    // ============================================================
    // 测试5: Host访问所有区域 (应该全部成功)
    // ============================================================
    PVR_LOG(("Test 5: Host accessing all regions"));

    for (i = 0; i < GPUVIRT_VALIDATION_NUM_OS; i++)
    {
        sVirtAddr.uiAddr = i * 0x10000000ULL;

        if (TestGPUAccess(psDevNode, 0, sVirtAddr, IMG_TRUE))
        {
            ui32PassCount++;
            PVR_LOG(("  [PASS] Host can access OSID %u region (0x%llx)",
                    i, sVirtAddr.uiAddr));
        }
        else
        {
            ui32FailCount++;
            PVR_LOG(("  [FAIL] Host cannot access OSID %u region (0x%llx)!",
                    i, sVirtAddr.uiAddr));
        }
    }

    // ============================================================
    // 测试结果汇总
    // ============================================================
    PVR_LOG(("╔══════════════════════════════════════════════════════════╗"));
    PVR_LOG(("║                 Test Results Summary                    ║"));
    PVR_LOG(("╠══════════════════════════════════════════════════════════╣"));
    PVR_LOG(("║ Total Tests: %4u                                        ║", 
            ui32PassCount + ui32FailCount));
    PVR_LOG(("║ Passed:      %4u                                        ║", 
            ui32PassCount));
    PVR_LOG(("║ Failed:      %4u                                        ║", 
            ui32FailCount));
    PVR_LOG(("║ Success Rate: %3u%%                                     ║",
            (ui32PassCount * 100) / (ui32PassCount + ui32FailCount)));
    PVR_LOG(("╠══════════════════════════════════════════════════════════╣"));

    if (ui32FailCount == 0)
    {
        PVR_LOG(("║ Status: ✓ ALL TESTS PASSED                            ║"));
        PVR_LOG(("║ GPU Firewall is working correctly                     ║"));
    }
    else
    {
        PVR_LOG(("║ Status: ✗ SOME TESTS FAILED                           ║"));
        PVR_LOG(("║ WARNING: GPU Firewall may not be working correctly!   ║"));
    }

    PVR_LOG(("╚══════════════════════════════════════════════════════════╝"));
}
/*
*测试GPU访问
*返回: IMG_TRUE 如果访问结果符合预期
*IMG_FALSE 如果访问结果不符合预期
*/
static IMG_BOOL TestGPUAccess(PVRSRV_DEVICE_NODE *psDevNode,
                            IMG_UINT32 ui32OSID,
                            IMG_DEV_VIRTADDR sVirtAddr,
                            IMG_BOOL bShouldSucceed)
{
    IMG_BOOL bCanAccess;
    // 检查地址是否在OSID的允许范围内
    bCanAccess = OSCheckGPUMemoryAccess(ui32OSID, sVirtAddr);
    // 返回是否符合预期
    return (bCanAccess == bShouldSucceed);
}
/* 跨VM通信示例 */
void ExampleCrossVMCommunication(void)
{
    PMR *psSharedBufferPMR;
    IMG_UINT32 ui32SenderOSID = 1;
    IMG_UINT32 ui32ReceiverOSID = 2;
    IMG_PVOID pvCPUAddr;
    IMG_UINT32 ui32BufferSize = 4 * 1024 * 1024;  // 4MB
    PVR_LOG(("╔══════════════════════════════════════════════════════════╗"));
    PVR_LOG(("║         Cross-VM Communication Example                  ║"));
    PVR_LOG(("╚══════════════════════════════════════════════════════════╝"));
    // ============================================================
    // 步骤1: VM1在共享区域分配缓冲区
    // ============================================================
    PVR_LOG(("Step 1: VM1 allocating shared buffer (%u MB)...",
    ui32BufferSize / (1024*1024)));
    if (AllocateGPUMemoryOptimized(ui32SenderOSID,
                                    ui32BufferSize,
                                    MEM_HINT_SHARED_PREFERRED,
                                    &psSharedBufferPMR) != PVRSRV_OK)
    {
        PVR_LOG(("Failed to allocate shared buffer!"));
        return;
    }
    PVR_LOG(("  ✓ Shared buffer allocated"));
    // ============================================================
    // 步骤2: VM1写入数据
    // ============================================================
    PVR_LOG(("Step 2: VM1 writing data to shared buffer..."));
    if (PMRMapCPUVirtual(psSharedBufferPMR, &pvCPUAddr) != PVRSRV_OK)
    {
        PVR_LOG(("Failed to map shared buffer!"));
        return;
    }
    // 写入测试数据
    OSMemSet(pvCPUAddr, 0xAB, ui32BufferSize);
    PVR_LOG(("  ✓ Data written (pattern: 0xAB)"));
    // 刷新缓存,确保数据对其他VM可见
    PMRFlushCPUCache(psSharedBufferPMR);
    PMRUnmapCPUVirtual(psSharedBufferPMR, pvCPUAddr);
    // ============================================================
    // 步骤3: 将缓冲区句柄传递给VM2
    // ============================================================
    PVR_LOG(("Step 3: Passing buffer handle to VM2..."));
    // 通过某种IPC机制(例如共享内存、消息队列)传递PMR句柄
    SendPMRHandleToOSID(psSharedBufferPMR, ui32ReceiverOSID);
    PVR_LOG(("  ✓ Handle sent to VM2"));
    // ============================================================
    // 步骤4: VM2读取数据
    // ============================================================
    PVR_LOG(("Step 4: VM2 reading data from shared buffer..."));
    // VM2侧代码
    ReceivePMRHandleFromOSID(ui32SenderOSID, &psSharedBufferPMR);
    if (PMRMapCPUVirtual(psSharedBufferPMR, &pvCPUAddr) != PVRSRV_OK)
    {
        PVR_LOG(("VM2: Failed to map shared buffer!"));
        return;
    }
    // 验证数据
    IMG_UINT8 pui8Data = (IMG_UINT8)pvCPUAddr;
    IMG_BOOL bDataValid = IMG_TRUE;
    for (IMG_UINT32 i = 0; i < ui32BufferSize; i++)
    {
        if (pui8Data[i] != 0xAB)
        {
            bDataValid = IMG_FALSE;
            break;
        }
    }
    if (bDataValid)
    {
        PVR_LOG(("  ✓ VM2 successfully read data from VM1"));
    }
    else
    {
        PVR_LOG(("  ✗ Data corruption detected!"));
    }
    PMRUnmapCPUVirtual(psSharedBufferPMR, pvCPUAddr);
    // ============================================================
    // 步骤5: 清理
    // ============================================================
    PVR_LOG(("Step 5: Cleanup..."));
    PMRUnrefPMR(psSharedBufferPMR);
    PVR_LOG(("  ✓ Shared buffer freed"));
    PVR_LOG(("╔══════════════════════════════════════════════════════════╗"));
    PVR_LOG(("║ Cross-VM communication completed successfully!          ║"));
    PVR_LOG(("╚══════════════════════════════════════════════════════════╝"));
}
/*

性能测试示例
*/
void BenchmarkMemoryAccess(void)
{
    IMG_UINT32 ui32OSID = 1;
    PMR *psPrivatePMR, *psSharedPMR;
    IMG_UINT64 ui64StartTime, ui64EndTime;
    IMG_UINT32 ui32Iterations = 10000;
    IMG_UINT32 ui32BufferSize = 1024 * 1024;  // 1MB
    IMG_PVOID pvCPUAddr;
    IMG_UINT32 i;
    PVR_LOG(("╔══════════════════════════════════════════════════════════╗"));
    PVR_LOG(("║        Memory Access Performance Benchmark              ║"));
    PVR_LOG(("╚══════════════════════════════════════════════════════════╝"));
    // ============================================================
    // 测试1: 私有区域访问性能
    // ============================================================
    PVR_LOG(("Test 1: Private region access"));
    AllocateGPUMemoryOptimized(ui32OSID,
                                ui32BufferSize,
                                MEM_HINT_PERFORMANCE_CRITICAL,
                                &psPrivatePMR);
    PMRMapCPUVirtual(psPrivatePMR, &pvCPUAddr);
    ui64StartTime = OSClockus64();
    for (i = 0; i < ui32Iterations; i++)
    {
        OSMemSet(pvCPUAddr, i & 0xFF, ui32BufferSize);
    }
    ui64EndTime = OSClockus64();
    IMG_UINT64 ui64PrivateTime = ui64EndTime - ui64StartTime;
    IMG_UINT64 ui64PrivateBandwidth = (ui32BufferSize * ui32Iterations * 1000000ULL) / ui64PrivateTime;
    PVR_LOG(("  Time: %llu us", ui64PrivateTime));
    PVR_LOG(("  Bandwidth: %llu MB/s", ui64PrivateBandwidth / (1024*1024)));
    PMRUnmapCPUVirtual(psPrivatePMR, pvCPUAddr);
    PMRUnrefPMR(psPrivatePMR);
    // ============================================================
    // 测试2: 共享区域访问性能
    // ============================================================
    PVR_LOG(("Test 2: Shared region access"));
    AllocateGPUMemoryOptimized(ui32OSID,
                                ui32BufferSize,
                                MEM_HINT_SHARED_PREFERRED,
                                &psSharedPMR);
    PMRMapCPUVirtual(psSharedPMR, &pvCPUAddr);
    ui64StartTime = OSClockus64();
    for (i = 0; i < ui32Iterations; i++)
    {
        OSMemSet(pvCPUAddr, i & 0xFF, ui32BufferSize);
    }
    ui64EndTime = OSClockus64();
    IMG_UINT64 ui64SharedTime = ui64EndTime - ui64StartTime;
    IMG_UINT64 ui64SharedBandwidth =
    (ui32BufferSize * ui32Iterations * 1000000ULL) / ui64SharedTime;
    PVR_LOG(("  Time: %llu us", ui64SharedTime));
    PVR_LOG(("  Bandwidth: %llu MB/s", ui64SharedBandwidth / (1024*1024)));
    PMRUnmapCPUVirtual(psSharedPMR, pvCPUAddr);
    PMRUnrefPMR(psSharedPMR);
    // ============================================================
    // 性能对比
    // ============================================================
    IMG_INT32 i32PerformanceDiff = ((IMG_INT64)ui64SharedTime - (IMG_INT64)ui64PrivateTime) * 100 / ui64PrivateTime;
    PVR_LOG(("╔══════════════════════════════════════════════════════════╗"));
    PVR_LOG(("║              Performance Comparison                     ║"));
    PVR_LOG(("╠══════════════════════════════════════════════════════════╣"));
    PVR_LOG(("║ Private Region:  %6llu MB/s (Baseline)                ║", ui64PrivateBandwidth / (10241024)));
    PVR_LOG(("║ Shared Region:   %6llu MB/s (%+3d%%)                  ║", ui64SharedBandwidth / (10241024), i32PerformanceDiff));
    PVR_LOG(("╠══════════════════════════════════════════════════════════╣"));
    if (i32PerformanceDiff <= 5)
    {
        PVR_LOG(("║ Status: ✓ Performance impact acceptable (<5%%)          ║"));
    }
    else if (i32PerformanceDiff <= 15)
    {
        PVR_LOG(("║ Status: ⚠ Moderate performance impact (5-15%%)          ║"));
    }
    else
    {
        PVR_LOG(("║ Status: ✗ Significant performance impact (>15%%)        ║"));
    }
    PVR_LOG(("╚══════════════════════════════════════════════════════════╝"));
}

总结

关键特性总结

特性 实现方式 优势
内存隔离 硬件防火墙 + 页表隔离 零软件开销,100%隔离
性能保证 私有区域独占 无cache竞争,最优性能
灵活通信 共享区域 支持跨VM数据共享
故障隔离 独立Page Fault处理 单VM崩溃不影响其他
可调试性 详细日志 + 统计 问题快速定位

适用场景

云游戏多租户: 单GPU服务多用户,完全隔离
汽车系统: 关键/非关键应用隔离,安全保证
移动多用户: 用户档案GPU数据隔离,隐私保护
边缘计算: 多租户容器化GPU资源
虚拟桌面: VDI环境GPU虚拟化

性能指标

指标 数值 说明
私有区域访问开销 0% 无额外开销
共享区域访问开销 5-10% Cache coherency
防火墙检查延迟 <5ns 硬件实现
Page Fault处理 <1ms 包括日志记录
内存隔离保证 100% 硬件级别

安全保证

🛡️ 硬件级隔离 - GPU MMU + 防火墙寄存器
🛡️ 页表独立 - 每VM独立页表,无法查看他人映射
🛡️ 可选加密 - Per-VM内存加密
🛡️ 审计日志 - 所有违规尝试记录
🛡️ 实时监控 - 性能计数器 + 告警机制

最佳实践建议

  1. 内存分配
    • 性能关键数据 → 私有区域
    • 跨VM通信 → 共享区域
    • 大纹理/Framebuffer → 私有区域
  2. 资源规划
    • 监控私有区域使用率
    • 共享区域使用 < 20% 为佳
    • 预留10-15%内存作为缓冲
  3. 安全策略
    • 关键系统使用TERMINATE_VM策略
    • 开发环境使用LOG_AND_CONTINUE
    • 生产环境启用审计日志
  4. 性能优化
    • 减少共享区域访问频率
    • 使用Memory Hints指导分配
    • 定期检查内存碎片
  5. 调试技巧
    • 使用DumpAllOSIDMemoryUsage查看状态
    • TestGPUFirewall验证隔离正确性
    • 性能测试对比私有/共享区域

附录: 快速参考

关键API

// 内存分配
AllocateGPUMemoryWithOSID(ui32OSID, uiSize, &psPMR)
AllocateGPUMemoryOptimized(ui32OSID, uiSize, eHint, &psPMR)

// 内存释放
FreeGPUMemoryWithOSID(ui32OSID, psPMR)

// 查询
OSGetCurrentOSID()
OSCheckGPUMemoryAccess(ui32OSID, sDevPAddr)
GetOSIDMemoryStats(ui32OSID, &sStats)

// 调试
DumpAllOSIDMemoryUsage()
TestGPUFirewall()
PrintOSIDMemoryStats(ui32OSID)

内存布局速查

OSID 私有区域 大小 共享区域 大小
0 0x00-0x0F 256MB 0x74-0x7F 96MB
1 0x10-0x1F 256MB 0x74-0x7F 96MB
2 0x20-0x2F 256MB 0x74-0x7F 96MB
3 0x30-0x3F 256MB 0x74-0x7F 96MB
4 0x40-0x4F 256MB 0x74-0x7F 96MB
5 0x50-0x5F 256MB 0x74-0x7F 96MB
6 0x60-0x6F 256MB 0x74-0x7F 96MB
7 0x70-0x73 244MB 0x74-0x7F 96MB

错误码速查

错误码 说明 处理建议
PVRSRV_ERROR_OUT_OF_MEMORY 私有和共享区域都满 释放内存或增加配额
GPU_PAGE_FAULT 访问非法地址 检查地址是否在允许范围
FIREWALL_VIOLATION 防火墙违规 检查OSID访问权限

相关文章

PowerVR Rogue ZS Buffer
PowerVR RGX Parameter Buffer And Ring Buffer
PowerVR Rogue FreeList
PowerVR RGX Firmware Utils
PowerVR RGX BVNC
PowerVR RGX Multicore

发布评论