2011-05-13 04:54:01 +00:00
|
|
|
/*-
|
2017-11-27 15:37:16 +00:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
|
|
|
*
|
2011-05-13 04:54:01 +00:00
|
|
|
* Copyright (c) 2011 NetApp, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* $FreeBSD$
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _PCI_EMUL_H_
|
|
|
|
#define _PCI_EMUL_H_
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/queue.h>
|
|
|
|
#include <sys/kernel.h>
|
2014-01-29 14:56:48 +00:00
|
|
|
#include <sys/_pthreadtypes.h>
|
2011-05-13 04:54:01 +00:00
|
|
|
|
|
|
|
#include <dev/pci/pcireg.h>
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#define PCI_BARMAX PCIR_MAX_BAR_0 /* BAR registers in a Type 0 header */
|
|
|
|
|
|
|
|
struct vmctx;
|
|
|
|
struct pci_devinst;
|
2012-04-28 16:28:00 +00:00
|
|
|
struct memory_region;
|
Initial support for bhyve save and restore.
Save and restore (also known as suspend and resume) permits a snapshot
to be taken of a guest's state that can later be resumed. In the
current implementation, bhyve(8) creates a UNIX domain socket that is
used by bhyvectl(8) to send a request to save a snapshot (and
optionally exit after the snapshot has been taken). A snapshot
currently consists of two files: the first holds a copy of guest RAM,
and the second file holds other guest state such as vCPU register
values and device model state.
To resume a guest, bhyve(8) must be started with a matching pair of
command line arguments to instantiate the same set of device models as
well as a pointer to the saved snapshot.
While the current implementation is useful for several uses cases, it
has a few limitations. The file format for saving the guest state is
tied to the ABI of internal bhyve structures and is not
self-describing (in that it does not communicate the set of device
models present in the system). In addition, the state saved for some
device models closely matches the internal data structures which might
prove a challenge for compatibility of snapshot files across a range
of bhyve versions. The file format also does not currently support
versioning of individual chunks of state. As a result, the current
file format is not a fixed binary format and future revisions to save
and restore will break binary compatiblity of snapshot files. The
goal is to move to a more flexible format that adds versioning,
etc. and at that point to commit to providing a reasonable level of
compatibility. As a result, the current implementation is not enabled
by default. It can be enabled via the WITH_BHYVE_SNAPSHOT=yes option
for userland builds, and the kernel option BHYVE_SHAPSHOT.
Submitted by: Mihai Tiganus, Flavius Anton, Darius Mihai
Submitted by: Elena Mihailescu, Mihai Carabas, Sergiu Weisz
Relnotes: yes
Sponsored by: University Politehnica of Bucharest
Sponsored by: Matthew Grooms (student scholarships)
Sponsored by: iXsystems
Differential Revision: https://reviews.freebsd.org/D19495
2020-05-05 00:02:04 +00:00
|
|
|
struct vm_snapshot_meta;
|
2011-05-13 04:54:01 +00:00
|
|
|
|
|
|
|
struct pci_devemu {
|
|
|
|
char *pe_emu; /* Name of device emulation */
|
|
|
|
|
|
|
|
/* instance creation */
|
2012-10-19 18:11:17 +00:00
|
|
|
int (*pe_init)(struct vmctx *, struct pci_devinst *,
|
|
|
|
char *opts);
|
2011-05-13 04:54:01 +00:00
|
|
|
|
2014-01-02 21:26:59 +00:00
|
|
|
/* ACPI DSDT enumeration */
|
|
|
|
void (*pe_write_dsdt)(struct pci_devinst *);
|
|
|
|
|
2011-05-13 04:54:01 +00:00
|
|
|
/* config space read/write callbacks */
|
|
|
|
int (*pe_cfgwrite)(struct vmctx *ctx, int vcpu,
|
|
|
|
struct pci_devinst *pi, int offset,
|
|
|
|
int bytes, uint32_t val);
|
|
|
|
int (*pe_cfgread)(struct vmctx *ctx, int vcpu,
|
|
|
|
struct pci_devinst *pi, int offset,
|
|
|
|
int bytes, uint32_t *retval);
|
|
|
|
|
2012-10-19 18:11:17 +00:00
|
|
|
/* BAR read/write callbacks */
|
|
|
|
void (*pe_barwrite)(struct vmctx *ctx, int vcpu,
|
|
|
|
struct pci_devinst *pi, int baridx,
|
|
|
|
uint64_t offset, int size, uint64_t value);
|
|
|
|
uint64_t (*pe_barread)(struct vmctx *ctx, int vcpu,
|
|
|
|
struct pci_devinst *pi, int baridx,
|
|
|
|
uint64_t offset, int size);
|
Initial support for bhyve save and restore.
Save and restore (also known as suspend and resume) permits a snapshot
to be taken of a guest's state that can later be resumed. In the
current implementation, bhyve(8) creates a UNIX domain socket that is
used by bhyvectl(8) to send a request to save a snapshot (and
optionally exit after the snapshot has been taken). A snapshot
currently consists of two files: the first holds a copy of guest RAM,
and the second file holds other guest state such as vCPU register
values and device model state.
To resume a guest, bhyve(8) must be started with a matching pair of
command line arguments to instantiate the same set of device models as
well as a pointer to the saved snapshot.
While the current implementation is useful for several uses cases, it
has a few limitations. The file format for saving the guest state is
tied to the ABI of internal bhyve structures and is not
self-describing (in that it does not communicate the set of device
models present in the system). In addition, the state saved for some
device models closely matches the internal data structures which might
prove a challenge for compatibility of snapshot files across a range
of bhyve versions. The file format also does not currently support
versioning of individual chunks of state. As a result, the current
file format is not a fixed binary format and future revisions to save
and restore will break binary compatiblity of snapshot files. The
goal is to move to a more flexible format that adds versioning,
etc. and at that point to commit to providing a reasonable level of
compatibility. As a result, the current implementation is not enabled
by default. It can be enabled via the WITH_BHYVE_SNAPSHOT=yes option
for userland builds, and the kernel option BHYVE_SHAPSHOT.
Submitted by: Mihai Tiganus, Flavius Anton, Darius Mihai
Submitted by: Elena Mihailescu, Mihai Carabas, Sergiu Weisz
Relnotes: yes
Sponsored by: University Politehnica of Bucharest
Sponsored by: Matthew Grooms (student scholarships)
Sponsored by: iXsystems
Differential Revision: https://reviews.freebsd.org/D19495
2020-05-05 00:02:04 +00:00
|
|
|
|
|
|
|
/* Save/restore device state */
|
|
|
|
int (*pe_snapshot)(struct vm_snapshot_meta *meta);
|
|
|
|
int (*pe_pause)(struct vmctx *ctx, struct pci_devinst *pi);
|
|
|
|
int (*pe_resume)(struct vmctx *ctx, struct pci_devinst *pi);
|
2011-05-13 04:54:01 +00:00
|
|
|
};
|
|
|
|
#define PCI_EMUL_SET(x) DATA_SET(pci_devemu_set, x);
|
|
|
|
|
|
|
|
enum pcibar_type {
|
|
|
|
PCIBAR_NONE,
|
|
|
|
PCIBAR_IO,
|
|
|
|
PCIBAR_MEM32,
|
|
|
|
PCIBAR_MEM64,
|
|
|
|
PCIBAR_MEMHI64
|
|
|
|
};
|
|
|
|
|
|
|
|
struct pcibar {
|
|
|
|
enum pcibar_type type; /* io or memory */
|
|
|
|
uint64_t size;
|
|
|
|
uint64_t addr;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define PI_NAMESZ 40
|
|
|
|
|
2012-04-28 16:28:00 +00:00
|
|
|
struct msix_table_entry {
|
|
|
|
uint64_t addr;
|
|
|
|
uint32_t msg_data;
|
|
|
|
uint32_t vector_control;
|
|
|
|
} __packed;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In case the structure is modified to hold extra information, use a define
|
|
|
|
* for the size that should be emulated.
|
|
|
|
*/
|
2013-01-21 22:07:05 +00:00
|
|
|
#define MSIX_TABLE_ENTRY_SIZE 16
|
2013-01-30 04:30:36 +00:00
|
|
|
#define MAX_MSIX_TABLE_ENTRIES 2048
|
2014-02-18 19:00:15 +00:00
|
|
|
#define PBA_SIZE(msgnum) (roundup2((msgnum), 64) / 8)
|
2012-04-28 16:28:00 +00:00
|
|
|
|
2014-01-29 14:56:48 +00:00
|
|
|
enum lintr_stat {
|
|
|
|
IDLE,
|
|
|
|
ASSERTED,
|
|
|
|
PENDING
|
|
|
|
};
|
|
|
|
|
2011-05-13 04:54:01 +00:00
|
|
|
struct pci_devinst {
|
|
|
|
struct pci_devemu *pi_d;
|
|
|
|
struct vmctx *pi_vmctx;
|
|
|
|
uint8_t pi_bus, pi_slot, pi_func;
|
|
|
|
char pi_name[PI_NAMESZ];
|
|
|
|
int pi_bar_getsize;
|
2014-02-18 03:00:20 +00:00
|
|
|
int pi_prevcap;
|
|
|
|
int pi_capend;
|
2011-05-13 04:54:01 +00:00
|
|
|
|
2014-01-29 14:56:48 +00:00
|
|
|
struct {
|
|
|
|
int8_t pin;
|
|
|
|
enum lintr_stat state;
|
2014-05-15 14:16:55 +00:00
|
|
|
int pirq_pin;
|
2014-01-29 14:56:48 +00:00
|
|
|
int ioapic_irq;
|
|
|
|
pthread_mutex_t lock;
|
|
|
|
} pi_lintr;
|
|
|
|
|
2011-05-13 04:54:01 +00:00
|
|
|
struct {
|
2013-12-16 19:59:31 +00:00
|
|
|
int enabled;
|
|
|
|
uint64_t addr;
|
|
|
|
uint64_t msg_data;
|
|
|
|
int maxmsgnum;
|
2011-05-13 04:54:01 +00:00
|
|
|
} pi_msi;
|
|
|
|
|
2012-04-28 16:28:00 +00:00
|
|
|
struct {
|
|
|
|
int enabled;
|
|
|
|
int table_bar;
|
|
|
|
int pba_bar;
|
2014-02-18 19:00:15 +00:00
|
|
|
uint32_t table_offset;
|
2012-04-28 16:28:00 +00:00
|
|
|
int table_count;
|
2014-02-18 19:00:15 +00:00
|
|
|
uint32_t pba_offset;
|
|
|
|
int pba_size;
|
2013-01-30 04:30:36 +00:00
|
|
|
int function_mask;
|
2013-01-21 22:07:05 +00:00
|
|
|
struct msix_table_entry *table; /* allocated at runtime */
|
2016-04-13 18:39:33 +00:00
|
|
|
void *pba_page;
|
|
|
|
int pba_page_offset;
|
2012-04-28 16:28:00 +00:00
|
|
|
} pi_msix;
|
|
|
|
|
2011-05-13 04:54:01 +00:00
|
|
|
void *pi_arg; /* devemu-private data */
|
|
|
|
|
|
|
|
u_char pi_cfgdata[PCI_REGMAX + 1];
|
|
|
|
struct pcibar pi_bar[PCI_BARMAX + 1];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct msicap {
|
|
|
|
uint8_t capid;
|
|
|
|
uint8_t nextptr;
|
|
|
|
uint16_t msgctrl;
|
|
|
|
uint32_t addrlo;
|
|
|
|
uint32_t addrhi;
|
|
|
|
uint16_t msgdata;
|
|
|
|
} __packed;
|
2016-07-06 16:02:15 +00:00
|
|
|
static_assert(sizeof(struct msicap) == 14, "compile-time assertion failed");
|
2011-05-13 04:54:01 +00:00
|
|
|
|
2012-04-28 16:28:00 +00:00
|
|
|
struct msixcap {
|
|
|
|
uint8_t capid;
|
|
|
|
uint8_t nextptr;
|
|
|
|
uint16_t msgctrl;
|
2013-01-21 22:07:05 +00:00
|
|
|
uint32_t table_info; /* bar index and offset within it */
|
|
|
|
uint32_t pba_info; /* bar index and offset within it */
|
2012-04-28 16:28:00 +00:00
|
|
|
} __packed;
|
2016-07-06 16:02:15 +00:00
|
|
|
static_assert(sizeof(struct msixcap) == 12, "compile-time assertion failed");
|
2012-04-28 16:28:00 +00:00
|
|
|
|
2013-02-15 18:41:36 +00:00
|
|
|
struct pciecap {
|
|
|
|
uint8_t capid;
|
|
|
|
uint8_t nextptr;
|
|
|
|
uint16_t pcie_capabilities;
|
|
|
|
|
|
|
|
uint32_t dev_capabilities; /* all devices */
|
|
|
|
uint16_t dev_control;
|
|
|
|
uint16_t dev_status;
|
|
|
|
|
|
|
|
uint32_t link_capabilities; /* devices with links */
|
|
|
|
uint16_t link_control;
|
|
|
|
uint16_t link_status;
|
|
|
|
|
|
|
|
uint32_t slot_capabilities; /* ports with slots */
|
|
|
|
uint16_t slot_control;
|
|
|
|
uint16_t slot_status;
|
|
|
|
|
|
|
|
uint16_t root_control; /* root ports */
|
|
|
|
uint16_t root_capabilities;
|
|
|
|
uint32_t root_status;
|
|
|
|
|
|
|
|
uint32_t dev_capabilities2; /* all devices */
|
|
|
|
uint16_t dev_control2;
|
|
|
|
uint16_t dev_status2;
|
|
|
|
|
|
|
|
uint32_t link_capabilities2; /* devices with links */
|
|
|
|
uint16_t link_control2;
|
|
|
|
uint16_t link_status2;
|
|
|
|
|
|
|
|
uint32_t slot_capabilities2; /* ports with slots */
|
|
|
|
uint16_t slot_control2;
|
|
|
|
uint16_t slot_status2;
|
|
|
|
} __packed;
|
2016-07-06 16:02:15 +00:00
|
|
|
static_assert(sizeof(struct pciecap) == 60, "compile-time assertion failed");
|
2013-02-15 18:41:36 +00:00
|
|
|
|
2014-05-15 14:16:55 +00:00
|
|
|
typedef void (*pci_lintr_cb)(int b, int s, int pin, int pirq_pin,
|
|
|
|
int ioapic_irq, void *arg);
|
2014-01-29 14:56:48 +00:00
|
|
|
|
2013-07-04 05:35:56 +00:00
|
|
|
int init_pci(struct vmctx *ctx);
|
2012-05-03 03:11:27 +00:00
|
|
|
void pci_callback(void);
|
2012-10-19 18:11:17 +00:00
|
|
|
int pci_emul_alloc_bar(struct pci_devinst *pdi, int idx,
|
2012-05-03 03:11:27 +00:00
|
|
|
enum pcibar_type type, uint64_t size);
|
|
|
|
int pci_emul_add_msicap(struct pci_devinst *pi, int msgnum);
|
2013-02-15 18:41:36 +00:00
|
|
|
int pci_emul_add_pciecap(struct pci_devinst *pi, int pcie_device_type);
|
2020-05-25 06:25:31 +00:00
|
|
|
void pci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes,
|
|
|
|
uint32_t val, uint8_t capoff, int capid);
|
2019-06-07 15:53:27 +00:00
|
|
|
void pci_emul_cmd_changed(struct pci_devinst *pi, uint16_t old);
|
2012-05-03 03:11:27 +00:00
|
|
|
void pci_generate_msi(struct pci_devinst *pi, int msgnum);
|
2012-10-19 18:11:17 +00:00
|
|
|
void pci_generate_msix(struct pci_devinst *pi, int msgnum);
|
2012-05-03 03:11:27 +00:00
|
|
|
void pci_lintr_assert(struct pci_devinst *pi);
|
|
|
|
void pci_lintr_deassert(struct pci_devinst *pi);
|
2014-05-15 14:16:55 +00:00
|
|
|
void pci_lintr_request(struct pci_devinst *pi);
|
2012-05-03 03:11:27 +00:00
|
|
|
int pci_msi_enabled(struct pci_devinst *pi);
|
2012-10-19 18:11:17 +00:00
|
|
|
int pci_msix_enabled(struct pci_devinst *pi);
|
2013-02-01 02:41:47 +00:00
|
|
|
int pci_msix_table_bar(struct pci_devinst *pi);
|
|
|
|
int pci_msix_pba_bar(struct pci_devinst *pi);
|
2016-07-08 21:30:18 +00:00
|
|
|
int pci_msi_maxmsgnum(struct pci_devinst *pi);
|
2014-01-27 22:26:15 +00:00
|
|
|
int pci_parse_slot(char *opt);
|
2018-08-22 20:23:08 +00:00
|
|
|
void pci_print_supported_devices();
|
2012-05-03 03:11:27 +00:00
|
|
|
void pci_populate_msicap(struct msicap *cap, int msgs, int nextptr);
|
2013-01-30 04:30:36 +00:00
|
|
|
int pci_emul_add_msixcap(struct pci_devinst *pi, int msgnum, int barnum);
|
|
|
|
int pci_emul_msix_twrite(struct pci_devinst *pi, uint64_t offset, int size,
|
|
|
|
uint64_t value);
|
|
|
|
uint64_t pci_emul_msix_tread(struct pci_devinst *pi, uint64_t offset, int size);
|
2014-02-14 21:34:08 +00:00
|
|
|
int pci_count_lintr(int bus);
|
|
|
|
void pci_walk_lintr(int bus, pci_lintr_cb cb, void *arg);
|
2014-01-02 21:26:59 +00:00
|
|
|
void pci_write_dsdt(void);
|
2014-08-08 03:49:01 +00:00
|
|
|
uint64_t pci_ecfg_base(void);
|
2014-05-02 04:51:31 +00:00
|
|
|
int pci_bus_configured(int bus);
|
Initial support for bhyve save and restore.
Save and restore (also known as suspend and resume) permits a snapshot
to be taken of a guest's state that can later be resumed. In the
current implementation, bhyve(8) creates a UNIX domain socket that is
used by bhyvectl(8) to send a request to save a snapshot (and
optionally exit after the snapshot has been taken). A snapshot
currently consists of two files: the first holds a copy of guest RAM,
and the second file holds other guest state such as vCPU register
values and device model state.
To resume a guest, bhyve(8) must be started with a matching pair of
command line arguments to instantiate the same set of device models as
well as a pointer to the saved snapshot.
While the current implementation is useful for several uses cases, it
has a few limitations. The file format for saving the guest state is
tied to the ABI of internal bhyve structures and is not
self-describing (in that it does not communicate the set of device
models present in the system). In addition, the state saved for some
device models closely matches the internal data structures which might
prove a challenge for compatibility of snapshot files across a range
of bhyve versions. The file format also does not currently support
versioning of individual chunks of state. As a result, the current
file format is not a fixed binary format and future revisions to save
and restore will break binary compatiblity of snapshot files. The
goal is to move to a more flexible format that adds versioning,
etc. and at that point to commit to providing a reasonable level of
compatibility. As a result, the current implementation is not enabled
by default. It can be enabled via the WITH_BHYVE_SNAPSHOT=yes option
for userland builds, and the kernel option BHYVE_SHAPSHOT.
Submitted by: Mihai Tiganus, Flavius Anton, Darius Mihai
Submitted by: Elena Mihailescu, Mihai Carabas, Sergiu Weisz
Relnotes: yes
Sponsored by: University Politehnica of Bucharest
Sponsored by: Matthew Grooms (student scholarships)
Sponsored by: iXsystems
Differential Revision: https://reviews.freebsd.org/D19495
2020-05-05 00:02:04 +00:00
|
|
|
#ifdef BHYVE_SNAPSHOT
|
|
|
|
int pci_snapshot(struct vm_snapshot_meta *meta);
|
|
|
|
int pci_pause(struct vmctx *ctx, const char *dev_name);
|
|
|
|
int pci_resume(struct vmctx *ctx, const char *dev_name);
|
|
|
|
#endif
|
2011-05-13 04:54:01 +00:00
|
|
|
|
|
|
|
static __inline void
|
|
|
|
pci_set_cfgdata8(struct pci_devinst *pi, int offset, uint8_t val)
|
|
|
|
{
|
|
|
|
assert(offset <= PCI_REGMAX);
|
|
|
|
*(uint8_t *)(pi->pi_cfgdata + offset) = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __inline void
|
|
|
|
pci_set_cfgdata16(struct pci_devinst *pi, int offset, uint16_t val)
|
|
|
|
{
|
|
|
|
assert(offset <= (PCI_REGMAX - 1) && (offset & 1) == 0);
|
|
|
|
*(uint16_t *)(pi->pi_cfgdata + offset) = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __inline void
|
|
|
|
pci_set_cfgdata32(struct pci_devinst *pi, int offset, uint32_t val)
|
|
|
|
{
|
|
|
|
assert(offset <= (PCI_REGMAX - 3) && (offset & 3) == 0);
|
|
|
|
*(uint32_t *)(pi->pi_cfgdata + offset) = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __inline uint8_t
|
|
|
|
pci_get_cfgdata8(struct pci_devinst *pi, int offset)
|
|
|
|
{
|
|
|
|
assert(offset <= PCI_REGMAX);
|
|
|
|
return (*(uint8_t *)(pi->pi_cfgdata + offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
static __inline uint16_t
|
|
|
|
pci_get_cfgdata16(struct pci_devinst *pi, int offset)
|
|
|
|
{
|
|
|
|
assert(offset <= (PCI_REGMAX - 1) && (offset & 1) == 0);
|
|
|
|
return (*(uint16_t *)(pi->pi_cfgdata + offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
static __inline uint32_t
|
|
|
|
pci_get_cfgdata32(struct pci_devinst *pi, int offset)
|
|
|
|
{
|
|
|
|
assert(offset <= (PCI_REGMAX - 3) && (offset & 3) == 0);
|
|
|
|
return (*(uint32_t *)(pi->pi_cfgdata + offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* _PCI_EMUL_H_ */
|