pci_emul.c revision 234761
1/*-
2 * Copyright (c) 2011 NetApp, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <sys/param.h>
33#include <sys/linker_set.h>
34
35#include <ctype.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <strings.h>
40#include <assert.h>
41
42#include <machine/vmm.h>
43#include <vmmapi.h>
44
45#include "fbsdrun.h"
46#include "inout.h"
47#include "pci_emul.h"
48#include "instruction_emul.h"
49
50#define CONF1_ADDR_PORT    0x0cf8
51#define CONF1_DATA_PORT    0x0cfc
52
53#define	CFGWRITE(pi,off,val,b)						\
54do {									\
55	if ((b) == 1) {							\
56		pci_set_cfgdata8((pi),(off),(val));			\
57	} else if ((b) == 2) {						\
58		pci_set_cfgdata16((pi),(off),(val));			\
59	} else {							\
60		pci_set_cfgdata32((pi),(off),(val));			\
61	}								\
62} while (0)
63
64#define MAXSLOTS	32
65
66static struct slotinfo {
67	char *si_name;
68	char *si_param;
69	struct pci_devinst *si_devi;
70	int si_titled;
71	int  si_pslot;
72	char si_prefix;
73	char si_suffix;
74} pci_slotinfo[MAXSLOTS];
75
76/*
77 * NetApp specific:
78 * struct used to build an in-core OEM table to supply device names
79 * to driver instances
80 */
81static struct mptable_pci_devnames {
82#define MPT_HDR_BASE	0
83#define MPT_HDR_NAME	2
84	uint16_t  md_hdrtype;
85	uint16_t  md_entries;
86	uint16_t  md_cksum;
87	uint16_t  md_pad;
88#define MPT_NTAP_SIG	\
89	((uint32_t)(('P' << 24) | ('A' << 16) | ('T' << 8) | 'N'))
90	uint32_t  md_sig;
91	uint32_t  md_rsvd;
92	struct mptable_pci_slotinfo {
93		uint16_t mds_type;
94		uint16_t mds_phys_slot;
95		uint8_t  mds_bus;
96		uint8_t  mds_slot;
97		uint8_t  mds_func;
98		uint8_t  mds_pad;
99		uint16_t mds_vid;
100		uint16_t mds_did;
101		uint8_t  mds_suffix[4];
102		uint8_t  mds_prefix[4];
103		uint32_t mds_rsvd[3];
104	} md_slotinfo[MAXSLOTS];
105} pci_devnames;
106
107SET_DECLARE(pci_devemu_set, struct pci_devemu);
108
109static uint64_t pci_emul_iobase;
110static uint64_t pci_emul_membase32;
111static uint64_t pci_emul_membase64;
112
113#define	PCI_EMUL_IOBASE		0x2000
114#define	PCI_EMUL_IOLIMIT	0x10000
115
116#define	PCI_EMUL_MEMBASE32	(lomem_sz)
117#define	PCI_EMUL_MEMLIMIT32	0xE0000000		/* 3.5GB */
118
119#define	PCI_EMUL_MEMBASE64	0xD000000000UL
120#define	PCI_EMUL_MEMLIMIT64	0xFD00000000UL
121
122static int pci_emul_devices;
123static int devname_elems;
124
125/*
126 * I/O access
127 */
128
129/*
130 * Slot options are in the form:
131 *
132 *  <slot>,<emul>[,<config>]
133 *
134 *  slot is 0..31
135 *  emul is a string describing the type of PCI device e.g. virtio-net
136 *  config is an optional string, depending on the device, that can be
137 *  used for configuration.
138 *   Examples are:
139 *     1,virtio-net,tap0
140 *     3,dummy
141 */
142static void
143pci_parse_slot_usage(char *aopt)
144{
145	printf("Invalid PCI slot info field \"%s\"\n", aopt);
146	free(aopt);
147}
148
149void
150pci_parse_slot(char *opt)
151{
152	char *slot, *emul, *config;
153	char *str, *cpy;
154	int snum;
155
156	str = cpy = strdup(opt);
157	config = NULL;
158
159	slot = strsep(&str, ",");
160	emul = strsep(&str, ",");
161	if (str != NULL) {
162		config = strsep(&str, ",");
163	}
164
165	if (emul == NULL) {
166		pci_parse_slot_usage(cpy);
167		return;
168	}
169
170	snum = 255;
171	snum = atoi(slot);
172	if (snum < 0 || snum >= MAXSLOTS) {
173		pci_parse_slot_usage(cpy);
174	} else {
175		pci_slotinfo[snum].si_name = emul;
176		pci_slotinfo[snum].si_param = config;
177	}
178}
179
180
181/*
182 *
183 * PCI MPTable names are of the form:
184 *
185 *  <slot>,[prefix]<digit><suffix>
186 *
187 *  .. with <prefix> an alphabetic char, <digit> a 1 or 2-digit string,
188 * and <suffix> a single char.
189 *
190 *  Examples:
191 *    1,e0c
192 *    4,e0P
193 *    6,43a
194 *    7,0f
195 *    10,1
196 *    12,e0M
197 *    2,12a
198 *
199 *  Note that this is NetApp-specific, but is ignored on other o/s's.
200 */
201static void
202pci_parse_name_usage(char *aopt)
203{
204	printf("Invalid PCI slot name field \"%s\"\n", aopt);
205}
206
207void
208pci_parse_name(char *opt)
209{
210	char csnum[4];
211	char *namestr;
212	char *slotend;
213	char prefix, suffix;
214	int i;
215	int pslot;
216	int snum;
217
218	pslot = -1;
219	prefix = suffix = 0;
220	slotend = strchr(opt, ',');
221
222	/*
223	 * A comma must be present, and can't be the first character
224	 * or no slot would be present. Also, the slot number can't be
225	 * more than 2 characters.
226	 */
227	if (slotend == NULL || slotend == opt || (slotend - opt > 2)) {
228		pci_parse_name_usage(opt);
229		return;
230	}
231
232	for (i = 0; i < (slotend - opt); i++) {
233		csnum[i] = opt[i];
234	}
235	csnum[i] = '\0';
236
237	snum = 255;
238	snum = atoi(csnum);
239	if (snum < 0 || snum >= MAXSLOTS) {
240		pci_parse_name_usage(opt);
241		return;
242	}
243
244	namestr = slotend + 1;
245
246	if (strlen(namestr) > 3) {
247		pci_parse_name_usage(opt);
248		return;
249	}
250
251	if (isalpha(*namestr)) {
252		prefix = *namestr++;
253	}
254
255	if (!isdigit(*namestr)) {
256		pci_parse_name_usage(opt);
257	} else {
258		pslot = *namestr++ - '0';
259		if (isnumber(*namestr)) {
260			pslot = 10*pslot + *namestr++ - '0';
261
262		}
263		if (isalpha(*namestr) && *(namestr + 1) == 0) {
264			suffix = *namestr;
265			pci_slotinfo[snum].si_titled = 1;
266			pci_slotinfo[snum].si_pslot = pslot;
267			pci_slotinfo[snum].si_prefix = prefix;
268			pci_slotinfo[snum].si_suffix = suffix;
269
270		} else {
271			pci_parse_name_usage(opt);
272		}
273	}
274}
275
276static void
277pci_add_mptable_name(struct slotinfo *si)
278{
279	struct mptable_pci_slotinfo *ms;
280
281	/*
282	 * If naming information has been supplied for this slot, populate
283	 * the next available mptable OEM entry
284	 */
285	if (si->si_titled) {
286		ms = &pci_devnames.md_slotinfo[devname_elems];
287
288		ms->mds_type = MPT_HDR_NAME;
289		ms->mds_phys_slot = si->si_pslot;
290		ms->mds_bus = si->si_devi->pi_bus;
291		ms->mds_slot = si->si_devi->pi_slot;
292		ms->mds_func = si->si_devi->pi_func;
293		ms->mds_vid = pci_get_cfgdata16(si->si_devi, PCIR_VENDOR);
294		ms->mds_did = pci_get_cfgdata16(si->si_devi, PCIR_DEVICE);
295		ms->mds_suffix[0] = si->si_suffix;
296		ms->mds_prefix[0] = si->si_prefix;
297
298		devname_elems++;
299	}
300}
301
302static void
303pci_finish_mptable_names(void)
304{
305	int size;
306
307	if (devname_elems) {
308		pci_devnames.md_hdrtype = MPT_HDR_BASE;
309		pci_devnames.md_entries = devname_elems;
310		pci_devnames.md_cksum = 0; /* XXX */
311		pci_devnames.md_sig = MPT_NTAP_SIG;
312
313		size = (uintptr_t)&pci_devnames.md_slotinfo[devname_elems] -
314			(uintptr_t)&pci_devnames;
315
316		fbsdrun_add_oemtbl(&pci_devnames, size);
317	}
318}
319
320static int
321pci_emul_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
322		 uint32_t *eax, void *arg)
323{
324	struct pci_devinst *pdi = arg;
325	struct pci_devemu *pe = pdi->pi_d;
326	int offset, i;
327
328	for (i = 0; i <= PCI_BARMAX; i++) {
329		if (pdi->pi_bar[i].type == PCIBAR_IO &&
330		    port >= pdi->pi_bar[i].addr &&
331		    port + bytes <= pdi->pi_bar[i].addr + pdi->pi_bar[i].size) {
332			offset = port - pdi->pi_bar[i].addr;
333			if (in)
334				*eax = (*pe->pe_ior)(pdi, i, offset, bytes);
335			else
336				(*pe->pe_iow)(pdi, i, offset, bytes, *eax);
337			return (0);
338		}
339	}
340	return (-1);
341}
342
343static int
344pci_emul_alloc_resource(uint64_t *baseptr, uint64_t limit, uint64_t size,
345			uint64_t *addr)
346{
347	uint64_t base;
348
349	assert((size & (size - 1)) == 0);	/* must be a power of 2 */
350
351	base = roundup2(*baseptr, size);
352
353	if (base + size <= limit) {
354		*addr = base;
355		*baseptr = base + size;
356		return (0);
357	} else
358		return (-1);
359}
360
361int
362pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, uint64_t hostbase,
363		   enum pcibar_type type, uint64_t size)
364{
365	int i, error;
366	uint64_t *baseptr, limit, addr, mask, lobits, bar;
367	struct inout_port iop;
368
369	assert(idx >= 0 && idx <= PCI_BARMAX);
370
371	if ((size & (size - 1)) != 0)
372		size = 1UL << flsl(size);	/* round up to a power of 2 */
373
374	switch (type) {
375	case PCIBAR_NONE:
376		baseptr = NULL;
377		addr = mask = lobits = 0;
378		break;
379	case PCIBAR_IO:
380		baseptr = &pci_emul_iobase;
381		limit = PCI_EMUL_IOLIMIT;
382		mask = PCIM_BAR_IO_BASE;
383		lobits = PCIM_BAR_IO_SPACE;
384		break;
385	case PCIBAR_MEM64:
386		/*
387		 * XXX
388		 * Some drivers do not work well if the 64-bit BAR is allocated
389		 * above 4GB. Allow for this by allocating small requests under
390		 * 4GB unless then allocation size is larger than some arbitrary
391		 * number (32MB currently).
392		 */
393		if (size > 32 * 1024 * 1024) {
394			/*
395			 * XXX special case for device requiring peer-peer DMA
396			 */
397			if (size == 0x100000000UL)
398				baseptr = &hostbase;
399			else
400				baseptr = &pci_emul_membase64;
401			limit = PCI_EMUL_MEMLIMIT64;
402			mask = PCIM_BAR_MEM_BASE;
403			lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64 |
404				 PCIM_BAR_MEM_PREFETCH;
405			break;
406		}
407		/* fallthrough */
408	case PCIBAR_MEM32:
409		baseptr = &pci_emul_membase32;
410		limit = PCI_EMUL_MEMLIMIT32;
411		mask = PCIM_BAR_MEM_BASE;
412		lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32;
413		break;
414	default:
415		printf("pci_emul_alloc_base: invalid bar type %d\n", type);
416		assert(0);
417	}
418
419	if (baseptr != NULL) {
420		error = pci_emul_alloc_resource(baseptr, limit, size, &addr);
421		if (error != 0)
422			return (error);
423	}
424
425	pdi->pi_bar[idx].type = type;
426	pdi->pi_bar[idx].addr = addr;
427	pdi->pi_bar[idx].size = size;
428
429	/* Initialize the BAR register in config space */
430	bar = (addr & mask) | lobits;
431	pci_set_cfgdata32(pdi, PCIR_BAR(idx), bar);
432
433	if (type == PCIBAR_MEM64) {
434		assert(idx + 1 <= PCI_BARMAX);
435		pdi->pi_bar[idx + 1].type = PCIBAR_MEMHI64;
436		pci_set_cfgdata32(pdi, PCIR_BAR(idx + 1), bar >> 32);
437	}
438
439	/* add a handler to intercept accesses to the I/O bar */
440	if (type == PCIBAR_IO) {
441		iop.name = pdi->pi_name;
442		iop.flags = IOPORT_F_INOUT;
443		iop.handler = pci_emul_handler;
444		iop.arg = pdi;
445
446		for (i = 0; i < size; i++) {
447			iop.port = addr + i;
448			register_inout(&iop);
449		}
450	}
451
452	return (0);
453}
454
455#define	CAP_START_OFFSET	0x40
456static int
457pci_emul_add_capability(struct pci_devinst *pi, u_char *capdata, int caplen)
458{
459	int i, capoff, capid, reallen;
460	uint16_t sts;
461
462	static u_char endofcap[4] = {
463		PCIY_RESERVED, 0, 0, 0
464	};
465
466	assert(caplen > 0 && capdata[0] != PCIY_RESERVED);
467
468	reallen = roundup2(caplen, 4);		/* dword aligned */
469
470	sts = pci_get_cfgdata16(pi, PCIR_STATUS);
471	if ((sts & PCIM_STATUS_CAPPRESENT) == 0) {
472		capoff = CAP_START_OFFSET;
473		pci_set_cfgdata8(pi, PCIR_CAP_PTR, capoff);
474		pci_set_cfgdata16(pi, PCIR_STATUS, sts|PCIM_STATUS_CAPPRESENT);
475	} else {
476		capoff = pci_get_cfgdata8(pi, PCIR_CAP_PTR);
477		while (1) {
478			assert((capoff & 0x3) == 0);
479			capid = pci_get_cfgdata8(pi, capoff);
480			if (capid == PCIY_RESERVED)
481				break;
482			capoff = pci_get_cfgdata8(pi, capoff + 1);
483		}
484	}
485
486	/* Check if we have enough space */
487	if (capoff + reallen + sizeof(endofcap) > PCI_REGMAX + 1)
488		return (-1);
489
490	/* Copy the capability */
491	for (i = 0; i < caplen; i++)
492		pci_set_cfgdata8(pi, capoff + i, capdata[i]);
493
494	/* Set the next capability pointer */
495	pci_set_cfgdata8(pi, capoff + 1, capoff + reallen);
496
497	/* Copy of the reserved capability which serves as the end marker */
498	for (i = 0; i < sizeof(endofcap); i++)
499		pci_set_cfgdata8(pi, capoff + reallen + i, endofcap[i]);
500
501	return (0);
502}
503
504static struct pci_devemu *
505pci_emul_finddev(char *name)
506{
507	struct pci_devemu **pdpp, *pdp;
508
509	SET_FOREACH(pdpp, pci_devemu_set) {
510		pdp = *pdpp;
511		if (!strcmp(pdp->pe_emu, name)) {
512			return (pdp);
513		}
514	}
515
516	return (NULL);
517}
518
519static void
520pci_emul_init(struct vmctx *ctx, struct pci_devemu *pde, int slot, char *params)
521{
522	struct pci_devinst *pdi;
523	pdi = malloc(sizeof(struct pci_devinst));
524	bzero(pdi, sizeof(*pdi));
525
526	pdi->pi_vmctx = ctx;
527	pdi->pi_bus = 0;
528	pdi->pi_slot = slot;
529	pdi->pi_func = 0;
530	pdi->pi_d = pde;
531	snprintf(pdi->pi_name, PI_NAMESZ, "%s-pci-%d", pde->pe_emu, slot);
532
533	/* Disable legacy interrupts */
534	pci_set_cfgdata8(pdi, PCIR_INTLINE, 255);
535	pci_set_cfgdata8(pdi, PCIR_INTPIN, 0);
536
537	pci_set_cfgdata8(pdi, PCIR_COMMAND,
538		    PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
539
540	if ((*pde->pe_init)(ctx, pdi, params) != 0) {
541		free(pdi);
542	} else {
543		pci_emul_devices++;
544		pci_slotinfo[slot].si_devi = pdi;
545	}
546}
547
548void
549pci_populate_msicap(struct msicap *msicap, int msgnum, int nextptr)
550{
551	int mmc;
552
553	CTASSERT(sizeof(struct msicap) == 14);
554
555	/* Number of msi messages must be a power of 2 between 1 and 32 */
556	assert((msgnum & (msgnum - 1)) == 0 && msgnum >= 1 && msgnum <= 32);
557	mmc = ffs(msgnum) - 1;
558
559	bzero(msicap, sizeof(struct msicap));
560	msicap->capid = PCIY_MSI;
561	msicap->nextptr = nextptr;
562	msicap->msgctrl = PCIM_MSICTRL_64BIT | (mmc << 1);
563}
564
565int
566pci_emul_add_msicap(struct pci_devinst *pi, int msgnum)
567{
568	struct msicap msicap;
569
570	pci_populate_msicap(&msicap, msgnum, 0);
571
572	return (pci_emul_add_capability(pi, (u_char *)&msicap, sizeof(msicap)));
573}
574
575void
576msixcap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
577		 int bytes, uint32_t val)
578{
579	uint16_t msgctrl, rwmask;
580	int off, table_bar;
581
582	off = offset - capoff;
583	table_bar = pi->pi_msix.table_bar;
584	/* Message Control Register */
585	if (off == 2 && bytes == 2) {
586		rwmask = PCIM_MSIXCTRL_MSIX_ENABLE | PCIM_MSIXCTRL_FUNCTION_MASK;
587		msgctrl = pci_get_cfgdata16(pi, offset);
588		msgctrl &= ~rwmask;
589		msgctrl |= val & rwmask;
590		val = msgctrl;
591
592		pi->pi_msix.enabled = val & PCIM_MSIXCTRL_MSIX_ENABLE;
593	}
594
595	CFGWRITE(pi, offset, val, bytes);
596}
597
598void
599msicap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
600		int bytes, uint32_t val)
601{
602	uint16_t msgctrl, rwmask, msgdata, mme;
603	uint32_t addrlo;
604
605	/*
606	 * If guest is writing to the message control register make sure
607	 * we do not overwrite read-only fields.
608	 */
609	if ((offset - capoff) == 2 && bytes == 2) {
610		rwmask = PCIM_MSICTRL_MME_MASK | PCIM_MSICTRL_MSI_ENABLE;
611		msgctrl = pci_get_cfgdata16(pi, offset);
612		msgctrl &= ~rwmask;
613		msgctrl |= val & rwmask;
614		val = msgctrl;
615
616		addrlo = pci_get_cfgdata32(pi, capoff + 4);
617		if (msgctrl & PCIM_MSICTRL_64BIT)
618			msgdata = pci_get_cfgdata16(pi, capoff + 12);
619		else
620			msgdata = pci_get_cfgdata16(pi, capoff + 8);
621
622		/*
623		 * XXX check delivery mode, destination mode etc
624		 */
625		mme = msgctrl & PCIM_MSICTRL_MME_MASK;
626		pi->pi_msi.enabled = msgctrl & PCIM_MSICTRL_MSI_ENABLE ? 1 : 0;
627		if (pi->pi_msi.enabled) {
628			pi->pi_msi.cpu = (addrlo >> 12) & 0xff;
629			pi->pi_msi.vector = msgdata & 0xff;
630			pi->pi_msi.msgnum = 1 << (mme >> 4);
631		} else {
632			pi->pi_msi.cpu = 0;
633			pi->pi_msi.vector = 0;
634			pi->pi_msi.msgnum = 0;
635		}
636	}
637
638	CFGWRITE(pi, offset, val, bytes);
639}
640
641/*
642 * This function assumes that 'coff' is in the capabilities region of the
643 * config space.
644 */
645static void
646pci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes, uint32_t val)
647{
648	int capid;
649	uint8_t capoff, nextoff;
650
651	/* Do not allow un-aligned writes */
652	if ((offset & (bytes - 1)) != 0)
653		return;
654
655	/* Find the capability that we want to update */
656	capoff = CAP_START_OFFSET;
657	while (1) {
658		capid = pci_get_cfgdata8(pi, capoff);
659		if (capid == PCIY_RESERVED)
660			break;
661
662		nextoff = pci_get_cfgdata8(pi, capoff + 1);
663		if (offset >= capoff && offset < nextoff)
664			break;
665
666		capoff = nextoff;
667	}
668	assert(offset >= capoff);
669
670	/*
671	 * Capability ID and Next Capability Pointer are readonly
672	 */
673	if (offset == capoff || offset == capoff + 1)
674		return;
675
676	switch (capid) {
677	case PCIY_MSI:
678		msicap_cfgwrite(pi, capoff, offset, bytes, val);
679		break;
680	default:
681		break;
682	}
683}
684
685static int
686pci_emul_iscap(struct pci_devinst *pi, int offset)
687{
688	int found;
689	uint16_t sts;
690	uint8_t capid, lastoff;
691
692	found = 0;
693	sts = pci_get_cfgdata16(pi, PCIR_STATUS);
694	if ((sts & PCIM_STATUS_CAPPRESENT) != 0) {
695		lastoff = pci_get_cfgdata8(pi, PCIR_CAP_PTR);
696		while (1) {
697			assert((lastoff & 0x3) == 0);
698			capid = pci_get_cfgdata8(pi, lastoff);
699			if (capid == PCIY_RESERVED)
700				break;
701			lastoff = pci_get_cfgdata8(pi, lastoff + 1);
702		}
703		if (offset >= CAP_START_OFFSET && offset <= lastoff)
704			found = 1;
705	}
706	return (found);
707}
708
709void
710init_pci(struct vmctx *ctx)
711{
712	struct pci_devemu *pde;
713	struct slotinfo *si;
714	int i;
715
716	pci_emul_iobase = PCI_EMUL_IOBASE;
717	pci_emul_membase32 = PCI_EMUL_MEMBASE32;
718	pci_emul_membase64 = PCI_EMUL_MEMBASE64;
719
720	si = pci_slotinfo;
721
722	for (i = 0; i < MAXSLOTS; i++, si++) {
723		if (si->si_name != NULL) {
724			pde = pci_emul_finddev(si->si_name);
725			if (pde != NULL) {
726				pci_emul_init(ctx, pde, i, si->si_param);
727				pci_add_mptable_name(si);
728			}
729		}
730	}
731	pci_finish_mptable_names();
732}
733
734int
735pci_msi_enabled(struct pci_devinst *pi)
736{
737	return (pi->pi_msi.enabled);
738}
739
740int
741pci_msi_msgnum(struct pci_devinst *pi)
742{
743	if (pi->pi_msi.enabled)
744		return (pi->pi_msi.msgnum);
745	else
746		return (0);
747}
748
749void
750pci_generate_msi(struct pci_devinst *pi, int msg)
751{
752
753	if (pci_msi_enabled(pi) && msg < pci_msi_msgnum(pi)) {
754		vm_lapic_irq(pi->pi_vmctx,
755			     pi->pi_msi.cpu,
756			     pi->pi_msi.vector + msg);
757	}
758}
759
760static int cfgbus, cfgslot, cfgfunc, cfgoff;
761
762static int
763pci_emul_cfgaddr(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
764		 uint32_t *eax, void *arg)
765{
766	uint32_t x;
767
768	assert(!in);
769
770	if (bytes != 4)
771		return (-1);
772
773	x = *eax;
774	cfgoff = x & PCI_REGMAX;
775	cfgfunc = (x >> 8) & PCI_FUNCMAX;
776	cfgslot = (x >> 11) & PCI_SLOTMAX;
777	cfgbus = (x >> 16) & PCI_BUSMAX;
778
779	return (0);
780}
781INOUT_PORT(pci_cfgaddr, CONF1_ADDR_PORT, IOPORT_F_OUT, pci_emul_cfgaddr);
782
783static int
784pci_emul_cfgdata(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
785		 uint32_t *eax, void *arg)
786{
787	struct pci_devinst *pi;
788	struct pci_devemu *pe;
789	int coff, idx;
790	uint64_t mask, bar;
791
792	assert(bytes == 1 || bytes == 2 || bytes == 4);
793
794	pi = pci_slotinfo[cfgslot].si_devi;
795	coff = cfgoff + (port - CONF1_DATA_PORT);
796
797#if 0
798	printf("pcicfg-%s from 0x%0x of %d bytes (%d/%d/%d)\n\r",
799		in ? "read" : "write", coff, bytes, cfgbus, cfgslot, cfgfunc);
800#endif
801
802	if (pi == NULL || cfgfunc != 0) {
803		if (in)
804			*eax = 0xffffffff;
805		return (0);
806	}
807
808	pe = pi->pi_d;
809
810	/*
811	 * Config read
812	 */
813	if (in) {
814		/* Let the device emulation override the default handler */
815		if (pe->pe_cfgread != NULL &&
816		    (*pe->pe_cfgread)(ctx, vcpu, pi, coff, bytes, eax) == 0)
817			return (0);
818
819		if (bytes == 1)
820			*eax = pci_get_cfgdata8(pi, coff);
821		else if (bytes == 2)
822			*eax = pci_get_cfgdata16(pi, coff);
823		else
824			*eax = pci_get_cfgdata32(pi, coff);
825	} else {
826		/* Let the device emulation override the default handler */
827		if (pe->pe_cfgwrite != NULL &&
828		    (*pe->pe_cfgwrite)(ctx, vcpu, pi, coff, bytes, *eax) == 0)
829			return (0);
830
831		/*
832		 * Special handling for write to BAR registers
833		 */
834		if (coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1)) {
835			/*
836			 * Ignore writes to BAR registers that are not
837			 * 4-byte aligned.
838			 */
839			if (bytes != 4 || (coff & 0x3) != 0)
840				return (0);
841			idx = (coff - PCIR_BAR(0)) / 4;
842			switch (pi->pi_bar[idx].type) {
843			case PCIBAR_NONE:
844				bar = 0;
845				break;
846			case PCIBAR_IO:
847				mask = ~(pi->pi_bar[idx].size - 1);
848				mask &= PCIM_BAR_IO_BASE;
849				bar = (*eax & mask) | PCIM_BAR_IO_SPACE;
850				break;
851			case PCIBAR_MEM32:
852				mask = ~(pi->pi_bar[idx].size - 1);
853				mask &= PCIM_BAR_MEM_BASE;
854				bar = *eax & mask;
855				bar |= PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32;
856				break;
857			case PCIBAR_MEM64:
858				mask = ~(pi->pi_bar[idx].size - 1);
859				mask &= PCIM_BAR_MEM_BASE;
860				bar = *eax & mask;
861				bar |= PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64 |
862				       PCIM_BAR_MEM_PREFETCH;
863				break;
864			case PCIBAR_MEMHI64:
865				mask = ~(pi->pi_bar[idx - 1].size - 1);
866				mask &= PCIM_BAR_MEM_BASE;
867				bar = ((uint64_t)*eax << 32) & mask;
868				bar = bar >> 32;
869				break;
870			default:
871				assert(0);
872			}
873			pci_set_cfgdata32(pi, coff, bar);
874
875			if (pi->pi_bar[idx].handler) {
876				pi->pi_bar[idx].handler(pi, idx, bar);
877			}
878
879		} else if (pci_emul_iscap(pi, coff)) {
880			pci_emul_capwrite(pi, coff, bytes, *eax);
881		} else {
882			CFGWRITE(pi, coff, *eax, bytes);
883		}
884	}
885
886	return (0);
887}
888
889INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+0, IOPORT_F_INOUT, pci_emul_cfgdata);
890INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+1, IOPORT_F_INOUT, pci_emul_cfgdata);
891INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+2, IOPORT_F_INOUT, pci_emul_cfgdata);
892INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+3, IOPORT_F_INOUT, pci_emul_cfgdata);
893
894/*
895 * I/O ports to configure PCI IRQ routing. We ignore all writes to it.
896 */
897static int
898pci_irq_port_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
899		     uint32_t *eax, void *arg)
900{
901	assert(in == 0);
902	return (0);
903}
904INOUT_PORT(pci_irq, 0xC00, IOPORT_F_OUT, pci_irq_port_handler);
905INOUT_PORT(pci_irq, 0xC01, IOPORT_F_OUT, pci_irq_port_handler);
906
907#define PCI_EMUL_TEST
908#ifdef PCI_EMUL_TEST
909/*
910 * Define a dummy test device
911 */
912#define DREGSZ	20
913struct pci_emul_dsoftc {
914	uint8_t   regs[DREGSZ];
915};
916
917#define	PCI_EMUL_MSGS	4
918
919static int
920pci_emul_dinit(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
921{
922	int error;
923	struct pci_emul_dsoftc *sc;
924
925	sc = malloc(sizeof(struct pci_emul_dsoftc));
926	memset(sc, 0, sizeof(struct pci_emul_dsoftc));
927
928	pi->pi_arg = sc;
929
930	pci_set_cfgdata16(pi, PCIR_DEVICE, 0x0001);
931	pci_set_cfgdata16(pi, PCIR_VENDOR, 0x10DD);
932	pci_set_cfgdata8(pi, PCIR_CLASS, 0x02);
933
934	error = pci_emul_alloc_bar(pi, 0, 0, PCIBAR_IO, DREGSZ);
935	assert(error == 0);
936
937	error = pci_emul_add_msicap(pi, PCI_EMUL_MSGS);
938	assert(error == 0);
939
940	return (0);
941}
942
943static void
944pci_emul_diow(struct pci_devinst *pi, int baridx, int offset, int size,
945	      uint32_t value)
946{
947	int i;
948	struct pci_emul_dsoftc *sc = pi->pi_arg;
949
950	if (offset + size > DREGSZ) {
951		printf("diow: too large, offset %d size %d\n", offset, size);
952		return;
953	}
954
955	if (size == 1) {
956		sc->regs[offset] = value & 0xff;
957	} else if (size == 2) {
958		*(uint16_t *)&sc->regs[offset] = value & 0xffff;
959	} else {
960		*(uint32_t *)&sc->regs[offset] = value;
961	}
962
963	/*
964	 * Special magic value to generate an interrupt
965	 */
966	if (offset == 4 && size == 4 && pci_msi_enabled(pi))
967		pci_generate_msi(pi, value % pci_msi_msgnum(pi));
968
969	if (value == 0xabcdef) {
970		for (i = 0; i < pci_msi_msgnum(pi); i++)
971			pci_generate_msi(pi, i);
972	}
973}
974
975static uint32_t
976pci_emul_dior(struct pci_devinst *pi, int baridx, int offset, int size)
977{
978	struct pci_emul_dsoftc *sc = pi->pi_arg;
979	uint32_t value;
980
981	if (offset + size > DREGSZ) {
982		printf("dior: too large, offset %d size %d\n", offset, size);
983		return (0);
984	}
985
986	if (size == 1) {
987		value = sc->regs[offset];
988	} else if (size == 2) {
989		value = *(uint16_t *) &sc->regs[offset];
990	} else {
991		value = *(uint32_t *) &sc->regs[offset];
992	}
993
994	return (value);
995}
996
997struct pci_devemu pci_dummy = {
998	.pe_emu = "dummy",
999	.pe_init = pci_emul_dinit,
1000	.pe_iow = pci_emul_diow,
1001	.pe_ior = pci_emul_dior
1002};
1003PCI_EMUL_SET(pci_dummy);
1004
1005#endif /* PCI_EMUL_TEST */
1006