From: Feifei Xu <[email protected]>

Add interface to query the optional MEM_RESERVED_INFO table:

  - introduce amdgpu_discovery_get_mem_reserved_info_table() which
    resolves the table from the discovery binary and caches the pointer
    in adev->discovery.mem_reserved_table so subsequent lookups are
    cheap;
  - invoke it once at init time. Missing/invalid table is non-fatal.

Signed-off-by: Feifei Xu <[email protected]>
Reviewed-by: Hawking Zhang <[email protected]>
Signed-off-by: Alex Deucher <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 55 ++++++++++++++++++-
 drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h |  4 ++
 2 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index af1404ae2b70c..4d55933f033cc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -684,6 +684,15 @@ static int amdgpu_discovery_table_check(struct 
amdgpu_device *adev,
                check_table = false;
                break;
        }
+       case MEM_RESERVED_INFO: {
+               struct mem_reserved_info_header *mrhdr =
+                       (struct mem_reserved_info_header *)(discovery_bin + 
offset);
+               act_val = le32_to_cpu(mrhdr->signature);
+               exp_val = MEM_RSV_TABLE_SIGNATURE;
+               table_size = le32_to_cpu(mrhdr->size);
+               table_name = "mem_reserved table";
+               break;
+       }
        default:
                dev_err(adev->dev, "invalid ip discovery table id %d 
specified\n", table_id);
                check_table = false;
@@ -772,12 +781,17 @@ static int amdgpu_discovery_init(struct amdgpu_device 
*adev)
                goto out;
        }
 
-       for (table_id = 0; table_id <= MALL_INFO; table_id++) {
+       for (table_id = 0; table_id < TOTAL_TABLES; table_id++) {
                r = amdgpu_discovery_table_check(adev, discovery_bin, table_id);
                if (r)
                        goto out;
        }
 
+       /*
+        * Resolve the MEM_RESERVED_INFO table once at init time. The table
+        * is optional, so missing it is not a fatal error.
+        */
+       amdgpu_discovery_get_mem_reserved_info_table(adev);
        return 0;
 
 out:
@@ -796,6 +810,8 @@ void amdgpu_discovery_fini(struct amdgpu_device *adev)
 
        kfree(adev->discovery.bin);
        adev->discovery.bin = NULL;
+       /* Cached pointer lives inside discovery.bin; drop it to avoid UAF. */
+       adev->discovery.mem_reserved_table = NULL;
 }
 
 static int amdgpu_discovery_validate_ip(struct amdgpu_device *adev,
@@ -2375,6 +2391,43 @@ int amdgpu_discovery_get_nps_info(struct amdgpu_device 
*adev,
        return 0;
 }
 
+/*
+ * Resolve the MEM_RESERVED_INFO table from the IP discovery binary and
+ * cache it in adev->discovery.mem_reserved_table.
+ * Return: 0 on success, -ENOENT/-EINVAL if the table unavailable.
+ */
+int amdgpu_discovery_get_mem_reserved_info_table(struct amdgpu_device *adev)
+{
+       uint8_t *discovery_bin = adev->discovery.bin;
+       struct table_info *info;
+
+       /* If already queried, do not query again. */
+       if (adev->discovery.mem_reserved_table)
+               return 0;
+
+       if (!discovery_bin) {
+               dev_err(adev->dev, "ip discovery uninitialized\n");
+               return -ENOENT;
+       }
+
+       if (amdgpu_discovery_get_table_info(adev, &info, MEM_RESERVED_INFO)) {
+               dev_dbg(adev->dev, "MEM_RESERVED_INFO table entry not 
present\n");
+               return -EINVAL;
+       }
+
+       if (!le16_to_cpu(info->offset)) {
+               dev_dbg(adev->dev, "MEM_RESERVED_INFO table offset is 0, 
invalid!\n");
+               return -EINVAL;
+       }
+
+       /* Cache for subsequent lookups. */
+       adev->discovery.mem_reserved_table =
+               (struct mem_reserved_info_table_v1_0 *)(discovery_bin + 
le16_to_cpu(info->offset));
+
+       dev_dbg(adev->dev, "MEM_RESERVED_INFO table exist\n");
+       return 0;
+}
+
 static int amdgpu_discovery_set_common_ip_blocks(struct amdgpu_device *adev)
 {
        /* what IP to use for this? */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h
index 5b2b16f68576c..070b404c1944c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h
@@ -25,6 +25,7 @@
 #define __AMDGPU_DISCOVERY__
 
 #include <linux/debugfs.h>
+#include "discovery.h"
 
 #define DISCOVERY_TMR_SIZE      (10 << 10)
 #define DISCOVERY_TMR_OFFSET    (64 << 10)
@@ -39,6 +40,7 @@ struct amdgpu_discovery_info {
        uint32_t size;
        uint8_t *bin;
        bool reserve_tmr;
+       struct mem_reserved_info_table_v1_0 *mem_reserved_table;
 };
 
 void amdgpu_discovery_sysfs_fini(struct amdgpu_device *adev);
@@ -59,4 +61,6 @@ int amdgpu_discovery_sysfs_early_init(struct amdgpu_device 
*adev,
                                       struct pci_dev *pdev);
 void amdgpu_discovery_sysfs_early_fini(struct pci_dev *pdev);
 
+int amdgpu_discovery_get_mem_reserved_info_table(struct amdgpu_device *adev);
+
 #endif /* __AMDGPU_DISCOVERY__ */
-- 
2.55.0

Reply via email to