Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iommufd fault queue #24

Merged
merged 5 commits into from
Dec 10, 2024
Merged
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
127 changes: 127 additions & 0 deletions examples/iopf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// SPDX-License-Identifier: GPL-2.0-or-later

/*
* This file is part of libvfn.
*
* Copyright (C) 2022 The libvfn Authors. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/

#include <inttypes.h>

#include <sys/mman.h>

#include <linux/iommufd.h>

#include <vfn/vfio.h>
#include <vfn/iommu.h>
#include <vfn/iommu/iommufd.h>
#include <vfn/support.h>

#include "ccan/err/err.h"
#include "ccan/opt/opt.h"
#include "ccan/str/str.h"

#include "common.h"

#define REG_ADDR 0x0
#define REG_CMD 0x8

#define IOVA_BASE 0xfef00000

static struct opt_table opts[] = {
OPT_SUBTABLE(opts_base, NULL),
OPT_ENDTABLE,
};

struct vfio_pci_device pdev;

int main(int argc, char **argv)
{
void *bar0;
uint64_t iova = IOVA_BASE;
ssize_t len;
void *vaddr;

struct iommufd_fault_queue fq;

struct iommu_hwpt_pgfault pgfault;
struct iommu_hwpt_page_response pgresp = {
.code = IOMMUFD_PAGE_RESP_SUCCESS,
};

opt_register_table(opts, NULL);
opt_parse(&argc, argv, opt_log_stderr_exit);

if (show_usage)
opt_usage_and_exit(NULL);

if (streq(bdf, ""))
opt_usage_exit_fail("missing --device parameter");

opt_free_table();

if (vfio_pci_open(&pdev, bdf))
err(1, "failed to open pci device");

if (iommufd_alloc_fault_queue(&fq))
err(1, "could not allocate fault queue");

if (iommufd_set_fault_queue(pdev.dev.ctx, &fq, pdev.dev.fd))
err(1, "could not associate fault queue with device/ioas");

bar0 = vfio_pci_map_bar(&pdev, 0, 0x1000, 0, PROT_READ | PROT_WRITE);
if (!bar0)
err(1, "failed to map bar");

len = pgmap(&vaddr, 0x1000);
if (len < 0)
err(1, "could not allocate aligned memory");

memset(vaddr, 0x42, 0x1000);

mmio_lh_write64(bar0 + REG_ADDR, iova);
mmio_write32(bar0 + REG_CMD, 0x3);

/* wait for page fault */
while (read(fq.fault_fd, &pgfault, sizeof(pgfault)) == 0)
;

printf("handling page fault on addr 0x%llx\n", pgfault.addr);

if (iommu_map_vaddr(pdev.dev.ctx, vaddr, 0x1000, &iova, IOMMU_MAP_FIXED_IOVA))
err(1, "failed to map page");

pgresp.cookie = pgfault.cookie;

if (write(fq.fault_fd, &pgresp, sizeof(pgresp)) < 0)
err(1, "failed to write page response");

while (mmio_read32(bar0 + REG_CMD) & 0x1)
;

memset(vaddr, 0x0, 0x1000);

mmio_write32(bar0 + REG_CMD, 0x1);

while (mmio_read32(bar0 + REG_CMD) & 0x1)
;

for (int i = 0; i < 0x1000; i++) {
uint8_t byte = *(uint8_t *)(vaddr + i);

if (byte != 0x42)
errx(1, "unexpected byte 0x%"PRIx8, byte);
}

return 0;
}
6 changes: 5 additions & 1 deletion examples/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@ examples = {
'regs': ['regs.c'],
}

if config_host.get('HAVE_IOMMU_FAULT_QUEUE_ALLOC', false)
examples += {'iopf': ['iopf.c']}
endif

foreach example, sources : examples
executable(example, [example_sources, sources],
dependencies: [libnvme],
link_with: [ccan_lib, vfn_lib],
include_directories: [ccan_inc, vfn_inc],
include_directories: [ccan_inc, vfn_inc, linux_headers],
)
endforeach
26 changes: 26 additions & 0 deletions include/vfn/iommu/iommufd.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later or MIT */

/*
* This file is part of libvfn.
*
* Copyright (C) 2022 The libvfn Authors. All Rights Reserved.
*
* This library (libvfn) is dual licensed under the GNU Lesser General
* Public License version 2.1 or later or the MIT license. See the
* COPYING and LICENSE files for more information.
*/

#ifndef LIBVFN_IOMMU_IOMMUFD_H
#define LIBVFN_IOMMU_IOMMUFD_H

#ifdef IOMMU_FAULT_QUEUE_ALLOC
struct iommufd_fault_queue {
int fault_id;
int fault_fd;
};

int iommufd_alloc_fault_queue(struct iommufd_fault_queue *fq);
int iommufd_set_fault_queue(struct iommu_ctx *ctx, struct iommufd_fault_queue *fq, int devfd);
#endif

#endif /* LIBVFN_IOMMU_IOMMUFD_H */
1 change: 1 addition & 0 deletions include/vfn/iommu/meson.build
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
vfn_iommu_headers = files([
'context.h',
'dma.h',
'iommufd.h',
])

install_headers(vfn_iommu_headers, subdir: 'vfn/iommu')
Expand Down
15 changes: 13 additions & 2 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ if get_option('debug')
add_project_arguments(['-DDEBUG'], language: ['c', 'cpp'])
endif

linux_headers = include_directories(get_option('linux-headers'))

##
## Programs
## --------
Expand All @@ -36,6 +38,7 @@ endif
perl = find_program('perl')
trace_pl = find_program('scripts/trace.pl')


##
## Compiler Configuration
## ----------------------
Expand Down Expand Up @@ -64,8 +67,14 @@ config_host.set('NVME_AQ_QSIZE', get_option('aq_qsize'),
description: 'admin command queue size')

config_host.set('HAVE_VFIO_DEVICE_BIND_IOMMUFD',
cc.has_header_symbol('linux/vfio.h', 'VFIO_DEVICE_BIND_IOMMUFD'),
description: 'weather VFIO_DEVICE_BIND_IOMMUFD is defined in linux/vfio.h')
cc.has_header_symbol('linux/vfio.h', 'VFIO_DEVICE_BIND_IOMMUFD',
include_directories: linux_headers),
description: 'if VFIO_DEVICE_BIND_IOMMUFD is defined in linux/vfio.h')

config_host.set('HAVE_IOMMU_FAULT_QUEUE_ALLOC',
cc.has_header_symbol('linux/iommufd.h', 'IOMMU_FAULT_QUEUE_ALLOC',
include_directories: linux_headers),
description: 'if IOMMU_FAULT_QUEUE_ALLOC is defined in linux/iommufd.h')

subdir('internal')

Expand All @@ -74,6 +83,7 @@ add_project_arguments([
], language: 'c',
)


##
## Optional dependencies
## ---------------------
Expand Down Expand Up @@ -171,4 +181,5 @@ summary_info += {'Debugging': get_option('debug')}
summary_info += {'Documentation': build_docs}
summary_info += {'Profiling': get_option('profiling')}
summary_info += {'iommufd': config_host.get('HAVE_VFIO_DEVICE_BIND_IOMMUFD')}
summary_info += {'iommufd fault queue': config_host.get('HAVE_IOMMU_FAULT_QUEUE_ALLOC')}
summary(summary_info, bool_yn: true, section: 'Features')
3 changes: 3 additions & 0 deletions meson_options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ option('docs', type: 'feature', value: 'auto',

option('trace-events-file', type: 'string', value: 'config/trace-events-all',
description: 'trace events file')

option('linux-headers', type: 'string', value: '',
description: 'path to linux headers')
Loading
Loading