⬢ DragonFlyBSD Kernel Audit
DF-2305 / fwpcictl.c
← back to finding ↓ download raw
/*
 * fwpcictl.c -- userland driver for the fwohci_pci.c verification rig
 * (/dev/fwpcictl0, root-only).  Targets DF-2304 / DF-2305 / DF-2306.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include "fwpci_harness.h"

static void
usage(void)
{
	fprintf(stderr,
	    "usage: fwpcictl attach [dpafail|dmatagfail|irqfail ...]\n"
	    "       fwpcictl probe <vendor> <device> <class> <subclass> <progif>\n"
	    "       fwpcictl verbose <0|1>\n"
	    "       fwpcictl stats\n"
	    "       fwpcictl forcedetach\n");
	exit(1);
}

static void
print_attach(const char *tag, struct fwp_attachreq *ar)
{
	u_int i;

	printf("%s: attach rc=%d mode=0x%x\n", tag, (int)ar->rc, ar->mode);
	printf("%s: resource deltas: MEM %u/%u  IRQ %u/%u  "
	    "setup_intr %u teardown %u live_handlers=%u\n",
	    tag, ar->mem_allocs, ar->mem_releases, ar->irq_allocs,
	    ar->irq_releases, ar->intr_setups, ar->intr_teardowns,
	    ar->live_handlers);
	printf("%s: interposers: dpa_calls=%u dmatag_calls=%u "
	    "mem_conflict_fails=%u\n",
	    tag, ar->dpa_calls, ar->dmatag_calls, ar->mem_conflict_fails);
	printf("%s: device_delete_child calls: %u\n", tag, ar->dellog_n);
	for (i = 0; i < ar->dellog_n && i < FWP_DELOG_MAX; i++)
		printf("%s:   delete#%u: fwohci_pci.c:%u child=0x%llx rc=%d\n",
		    tag, i, ar->del_lines[i],
		    (unsigned long long)ar->del_childs[i],
		    (int)ar->del_rcs[i]);
}

int
main(int argc, char **argv)
{
	struct fwp_attachreq ar;
	struct fwp_probereq pr;
	struct fwp_ctlreq cr;
	int fd, i;

	if (argc < 2)
		usage();
	fd = open("/dev/fwpcictl0", O_RDWR);
	if (fd < 0) {
		perror("open /dev/fwpcictl0");
		exit(1);
	}

	if (!strcmp(argv[1], "attach")) {
		memset(&ar, 0, sizeof(ar));
		for (i = 2; i < argc; i++) {
			if (!strcmp(argv[i], "dpafail"))
				ar.mode |= FWP_MODE_DPAFAIL;
			else if (!strcmp(argv[i], "dmatagfail"))
				ar.mode |= FWP_MODE_DMATAGFAIL;
			else if (!strcmp(argv[i], "irqfail"))
				ar.mode |= FWP_MODE_IRQFAIL;
			else
				usage();
		}
		if (ioctl(fd, FWPCI_IOC_ATTACH, &ar) < 0) {
			perror("ioctl ATTACH");
			exit(1);
		}
		print_attach("ATTACH", &ar);
	} else if (!strcmp(argv[1], "probe")) {
		if (argc != 7)
			usage();
		memset(&pr, 0, sizeof(pr));
		pr.vendor = (u_int32_t)strtoul(argv[2], NULL, 0);
		pr.device = (u_int32_t)strtoul(argv[3], NULL, 0);
		pr.class = (u_int32_t)strtoul(argv[4], NULL, 0);
		pr.subclass = (u_int32_t)strtoul(argv[5], NULL, 0);
		pr.progif = (u_int32_t)strtoul(argv[6], NULL, 0);
		if (ioctl(fd, FWPCI_IOC_PROBE, &pr) < 0) {
			perror("ioctl PROBE");
			exit(1);
		}
		printf("PROBE: rc=%d\n", (int)pr.rc);
	} else if (!strcmp(argv[1], "verbose")) {
		if (argc != 3)
			usage();
		memset(&cr, 0, sizeof(cr));
		cr.op = 2;
		cr.arg = (u_int32_t)strtoul(argv[2], NULL, 0);
		if (ioctl(fd, FWPCI_IOC_CTL, &cr) < 0) {
			perror("ioctl CTL(verbose)");
			exit(1);
		}
		printf("VERBOSE: bootverbose=%u rc=%d\n", cr.arg, (int)cr.rc);
	} else if (!strcmp(argv[1], "stats")) {
		memset(&cr, 0, sizeof(cr));
		cr.op = 3;
		if (ioctl(fd, FWPCI_IOC_CTL, &cr) < 0) {
			perror("ioctl CTL(stats)");
			exit(1);
		}
		printf("STATS: MEM %u/%u IRQ %u/%u setup %u teardown %u "
		    "live=%u conflicts=%u deletes=%u\n",
		    cr.mem_allocs, cr.mem_releases, cr.irq_allocs,
		    cr.irq_releases, cr.intr_setups, cr.intr_teardowns,
		    cr.live_handlers, cr.mem_conflict_fails, cr.dellog_n);
	} else if (!strcmp(argv[1], "forcedetach")) {
		memset(&cr, 0, sizeof(cr));
		cr.op = 1;
		if (ioctl(fd, FWPCI_IOC_CTL, &cr) < 0) {
			perror("ioctl CTL(forcedetach)");
			exit(1);
		}
		printf("FORCEDETACH: rc=%d\n", (int)cr.rc);
	} else
		usage();
	close(fd);
	return (0);
}