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