Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 53 additions & 4 deletions src/runtime_src/core/edge/drm/zocl/common/zocl_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
#include <linux/module.h>
#include <linux/fpga/fpga-mgr.h>
#include <linux/iommu.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/overflow.h>
#include <linux/pagemap.h>
#include <linux/io.h>
#include <linux/kernel.h>
Expand Down Expand Up @@ -890,6 +893,42 @@ zocl_gem_mmap(struct file *filp, struct vm_area_struct *vma)
return rc;
}

/* Aperture addresses come straight out of the IP_LAYOUT and DEBUG_IP_LAYOUT
* sections of a user supplied xclbin, so they cannot be trusted to describe a
* register window. Refuse anything the kernel knows to be System RAM, which
* would otherwise hand the caller a writable mapping of arbitrary memory.
* Addresses the kernel knows nothing about are still allowed, they are the
* undeclared PL windows the CUs actually live in.
*
* The whole pages the range falls in are checked, since those are what a
* mapping would hand out.
*
* @param addr: start of the register range
* @param size: size of the register range
*
* @return true if the range may be mapped to user space.
*/
bool zocl_apt_range_is_mmio(phys_addr_t addr, size_t size)
{
phys_addr_t start = round_down(addr, PAGE_SIZE);
phys_addr_t last;
size_t len;

if (!size || check_add_overflow(addr, (phys_addr_t)(size - 1), &last))
return false;

last |= (phys_addr_t)(PAGE_SIZE - 1);
len = last - start + 1;
if (!len)
return false;

if (region_intersects(start, len, IORESOURCE_SYSTEM_RAM,
IORES_DESC_NONE) != REGION_DISJOINT)
return false;

return !pfn_valid(PHYS_PFN(start)) && !pfn_valid(PHYS_PFN(last));
}

/* This function map two types of kernel address to user space.
* The first type is pysical registers of a hardware IP, like CUs.
* The second type is GEM buffer.
Expand All @@ -908,7 +947,7 @@ static int zocl_mmap(struct file *filp, struct vm_area_struct *vma)
struct drm_zocl_bo *bo = NULL;
unsigned long vsize;
phys_addr_t phy_addr;
int apt_idx;
unsigned long apt_idx;
int rc;

/* A GEM buffer object has a fake mmap offset start from page offset
Expand Down Expand Up @@ -949,17 +988,27 @@ static int zocl_mmap(struct file *filp, struct vm_area_struct *vma)
* Could not map from the middle of an aperture.
*/
apt_idx = vma->vm_pgoff;
if (apt_idx < 0 || apt_idx >= zdev->cu_subdev.num_apts) {
if (apt_idx >= zdev->cu_subdev.num_apts) {
DRM_ERROR("The offset is not in the apertures list\n");
return -EINVAL;
}
phy_addr = apts[apt_idx].addr;
vma->vm_pgoff = phy_addr >> PAGE_SHIFT;
if (phy_addr == EMPTY_APT_VALUE) {
DRM_ERROR("Aperture %lu is not in use\n", apt_idx);
return -EINVAL;
}

vsize = vma->vm_end - vma->vm_start;
if (vsize > zdev->cu_subdev.apertures[apt_idx].size)
if (vsize > apts[apt_idx].size)
return -EINVAL;

if (!zocl_apt_range_is_mmio(phy_addr, vsize)) {
DRM_ERROR("Aperture %lu at %pa is not a register window\n",
apt_idx, &phy_addr);
return -EINVAL;
}

vma->vm_pgoff = phy_addr >> PAGE_SHIFT;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)
vma->vm_flags |= VM_IO;
Expand Down
63 changes: 41 additions & 22 deletions src/runtime_src/core/edge/drm/zocl/common/zocl_xclbin.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ update_max_apt_number(struct drm_zocl_dev *zdev)
* @param slot_idx: Specific slot index
*
*/
static void
void
zocl_clean_aperture(struct drm_zocl_dev *zdev, u32 slot_idx)
{
int apt_idx = 0;
Expand Down Expand Up @@ -339,9 +339,28 @@ zocl_update_apertures(struct drm_zocl_dev *zdev, struct drm_zocl_slot *slot)
/* Now update the aperture for the new xclbin */
if (slot->ip) {
for (i = 0; i < slot->ip->m_count; ++i) {
size_t apt_size = CU_SIZE;

ip = &slot->ip->m_ip_data[i];
if (ip->m_base_address == EMPTY_APT_VALUE)
continue;

strncpy(kname, ip->m_name, sizeof(kname));
kname[sizeof(kname)-1] = '\0';
kname_p = &kname[0];
strncpy(kname, strsep(&kname_p, ":"), sizeof(kname));
kname[sizeof(kname)-1] = '\0';
krnl_info = zocl_query_kernel(slot, kname);
if (krnl_info && krnl_info->range >= CU_SIZE)
apt_size = krnl_info->range;

if (!zocl_apt_range_is_mmio(ip->m_base_address,
apt_size)) {
DRM_WARN("IP %s at 0x%llx is not a register window, no aperture\n",
kname, ip->m_base_address);
continue;
}

apt_idx = get_next_free_apt_index(zdev);
if (apt_idx < 0) {
DRM_ERROR("No more free apertures\n");
Expand All @@ -350,18 +369,8 @@ zocl_update_apertures(struct drm_zocl_dev *zdev, struct drm_zocl_slot *slot)
apt = &zdev->cu_subdev.apertures[apt_idx];

apt->addr = ip->m_base_address;

strncpy(kname, ip->m_name, sizeof(kname));
kname[sizeof(kname)-1] = '\0';
kname_p = &kname[0];
strncpy(kname, strsep(&kname_p, ":"), sizeof(kname));
kname[sizeof(kname)-1] = '\0';
krnl_info = zocl_query_kernel(slot, kname);
if (krnl_info && krnl_info->range >= CU_SIZE)
apt->size = krnl_info->range;
else
apt->size = CU_SIZE;
apt->prop = ip->properties;
apt->size = apt_size;
apt->prop = ip->properties;
apt->cu_idx = -1;
apt->slot_idx = slot->slot_idx;
}
Expand All @@ -371,7 +380,23 @@ zocl_update_apertures(struct drm_zocl_dev *zdev, struct drm_zocl_slot *slot)

if (slot->debug_ip) {
for (i = 0; i < slot->debug_ip->m_count; ++i) {
size_t apt_size = _64KB;

dbg_ip = &slot->debug_ip->m_debug_ip_data[i];
if (dbg_ip->m_type == AXI_MONITOR_FIFO_LITE
|| dbg_ip->m_type == AXI_MONITOR_FIFO_FULL)
/* FIFO_LITE has 4KB and FIFO FULL has 8KB
* address range. Use both 8K is okay.
*/
apt_size = _8KB;

if (!zocl_apt_range_is_mmio(dbg_ip->m_base_address,
apt_size)) {
DRM_WARN("Debug IP at 0x%llx is not a register window, no aperture\n",
dbg_ip->m_base_address);
continue;
}

apt_idx = get_next_free_apt_index(zdev);
if (apt_idx < 0) {
DRM_ERROR("No more free apertures\n");
Expand All @@ -380,16 +405,10 @@ zocl_update_apertures(struct drm_zocl_dev *zdev, struct drm_zocl_slot *slot)
apt = &zdev->cu_subdev.apertures[apt_idx];

apt->addr = dbg_ip->m_base_address;
apt->size = apt_size;
apt->prop = 0;
apt->cu_idx = -1;
apt->slot_idx = slot->slot_idx;
if (dbg_ip->m_type == AXI_MONITOR_FIFO_LITE
|| dbg_ip->m_type == AXI_MONITOR_FIFO_FULL)
/* FIFO_LITE has 4KB and FIFO FULL has 8KB
* address range. Use both 8K is okay.
*/
apt->size = _8KB;
else
/* Others debug IPs have 64KB address range*/
apt->size = _64KB;
}
/* Update num_apts based on current index */
update_max_apt_number(zdev);
Expand Down
12 changes: 10 additions & 2 deletions src/runtime_src/core/edge/drm/zocl/edge/zocl_edge_xclbin.c
Original file line number Diff line number Diff line change
Expand Up @@ -407,18 +407,26 @@ zocl_xclbin_read_axlf(struct drm_zocl_dev *zdev, struct drm_zocl_axlf *axlf_obj,
/* Create the CUs for this slot (after INTC refresh so CUs register correctly) */
ret = zocl_create_cu(zdev, slot);
if (ret)
goto out0;
goto out_apt;

ret = zocl_kds_update(zdev, slot, &axlf_obj->kds_cfg);
if (ret)
goto out0;
goto out_apt;
}

DRM_INFO("xclbin %pUb successfully loaded to slot %d\n",
zocl_xclbin_get_uuid(slot), slot_id);

goto done;

out_apt:
/* Only reached once the apertures hold this xclbin, drop them so a
* failed load cannot leave a mappable address behind. The earlier
* error paths must not come here, they can still be serving the
* previous xclbin.
*/
zocl_clean_aperture(zdev, slot->slot_idx);

out0:
/* The old overlay or PL may be gone, drop the stale CUs and IRQ routing. */
if (dt_overlay_dirty) {
Expand Down
1 change: 1 addition & 0 deletions src/runtime_src/core/edge/drm/zocl/include/zocl_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ zocl_get_zdev(void)
return NULL;
return platform_get_drvdata(pdev);
}
bool zocl_apt_range_is_mmio(phys_addr_t addr, size_t size);
int get_apt_index_by_addr(struct drm_zocl_dev *zdev, phys_addr_t addr);
int get_apt_index_by_addr_and_slot(struct drm_zocl_dev *zdev, phys_addr_t addr, int slot_idx);
int get_apt_index_by_cu_idx(struct drm_zocl_dev *zdev, int cu_idx);
Expand Down
1 change: 1 addition & 0 deletions src/runtime_src/core/edge/drm/zocl/include/zocl_xclbin.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ int zocl_offsetof_sect(enum axlf_section_kind kind, void *sect,
int zocl_read_sect(enum axlf_section_kind kind, void *sect,
struct axlf *axlf_full, char __user *xclbin_ptr);
int zocl_update_apertures(struct drm_zocl_dev *zdev, struct drm_zocl_slot *slot);
void zocl_clean_aperture(struct drm_zocl_dev *zdev, u32 slot_idx);
void zocl_destroy_cu_slot(struct drm_zocl_dev *zdev, u32 slot_idx);
int zocl_create_cu(struct drm_zocl_dev *zdev, struct drm_zocl_slot *slot);
void zocl_slot_remove_xclbin_overlay(struct drm_zocl_dev *zdev,
Expand Down
Loading