From: David Matlack <dmatlack@google.com>
To: Irene Wang <yiranirenewang@gmail.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>,
Sean Christopherson <seanjc@google.com>,
Andrew Jones <andrew.jones@linux.dev>,
Thomas Huth <thuth@redhat.com>,
kvm@vger.kernel.org, Yosry Ahmed <yosry@kernel.org>,
Jim Mattson <jmattson@google.com>
Subject: Re: [kvm-unit-tests PATCH v3] x86: pci: Support unaligned register access in PCI config read/write
Date: Thu, 13 Aug 2026 21:30:22 +0000 [thread overview]
Message-ID: <an43bksYniPqk8mp@google.com> (raw)
In-Reply-To: <20260813205742.2752510-2-yiranirenewang@gmail.com>
On 2026-08-13 08:57 PM, Irene Wang wrote:
> Per the PCI Local Bus Specification (Section 3.2.2.3.2, "Configuration
> Mechanism #1"), port 0xCF8 (CONFIG_ADDRESS) requires a DWORD-aligned
> register offset (bits [1:0] = 00b), while byte and word offsets within
> the DWORD must be selected via data port 0xCFC + (reg & 3).
>
> Previously, PCI_CONF1_ADDRESS did not clear bits [1:0], and 8-bit /
> 16-bit helpers always accessed base port 0xCFC directly. This worked
> in QEMU because its PCI host bridge emulation preserves unaligned bits
> in CONFIG_ADDRESS and uses them during CONFIG_DATA accesses. However,
> in strictly spec-compliant VMMs (and potentially real hardware), bits
> [1:0] of 0xCF8 are ignored, causing non-aligned reads/writes at port
> 0xCFC to erroneously target byte 0 of the DWORD. In practice, this
> causes pci_find_dev() to read the vendor ID twice instead of reading
> the vendor ID and device ID.
>
> Fix this by masking `reg` with `~3` in PCI_CONF1_ADDRESS and adding
> the `(reg & 3)` offset to the CONFIG_DATA port for 8-bit and 16-bit
> accessors, ensuring compatibility across QEMU and other VMMs. Additionally,
> add an ASSERT_PCI_CONF1_VALID macro to guard against illegal accesses that
> cross DWORD boundaries.
>
> Assisted-by: Gemini:gemini-3.6-flash
> Reviewed-by: Jim Mattson <jmattson@google.com>
> Signed-off-by: Irene Wang <yiranirenewang@gmail.com>
Looks good aside from the comment nits.
Reviewed-by: David Matlack <dmatlack@google.com>
> ---
> v2 -> v3:
> - Add comment in PCI_CONF1_ADDRESS explicitly explaining that clearing
> bits [1:0] prevents QEMU from double-offsetting accesses (David)
> - Introduce ASSERT_PCI_CONF1_VALID macro checking that access offset +
> access size do not read/write past 4-byte window (David)
>
> Link to v2: https://lore.kernel.org/kvm/20260804232344.2976694-2-yiranirenewang@gmail.com/
> Link to v1: https://lore.kernel.org/kvm/20260730182053.905335-1-yiranirenewang@gmail.com/
> ---
> lib/x86/asm/pci.h | 25 ++++++++++++++++++++-----
> 1 file changed, 20 insertions(+), 5 deletions(-)
>
> diff --git a/lib/x86/asm/pci.h b/lib/x86/asm/pci.h
> index 03e55c27..144a4459 100644
> --- a/lib/x86/asm/pci.h
> +++ b/lib/x86/asm/pci.h
> @@ -9,22 +9,35 @@
> #include "pci.h"
> #include "x86/asm/io.h"
>
> -#define PCI_CONF1_ADDRESS(dev, reg) ((0x1 << 31) | (dev << 8) | reg)
> +/*
> + * Bits [1:0] offset into data port, not address port. Spec compliant
> + * host bridges ignore them in CONFIG_ADDRESS, but QEMU does not; mask them out
> + * here so QEMU doesn't double-offset the access.
> + */
nit: Wrap at 80 chars.
/*
* Bits [1:0] offset into data port, not address port. Spec compliant host
* bridges ignore them in CONFIG_ADDRESS, but QEMU does not; mask them out here
* so QEMU doesn't double-offset the access.
*/
> +#define PCI_CONF1_ADDRESS(dev, reg) ((0x1 << 31) | ((dev) << 8) | ((reg) & ~3))
> +
> +/*
> + * Ensure access offset + size stays within the 4-byte (DWORD) boundary.
> + */
nit: Use /* ... */ style for one-line comments.
/* Ensure access offset + size stays within the 4-byte (DWORD) boundary. */
> +#define ASSERT_PCI_CONF1_VALID(reg, type) \
> + assert(((reg) & 3) + sizeof(type) <= 4)
>
> static inline uint8_t pci_config_readb(pcidevaddr_t dev, uint8_t reg)
> {
> outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8);
> - return inb(0xCFC);
> + return inb(0xCFC + (reg & 3));
> }
>
> static inline uint16_t pci_config_readw(pcidevaddr_t dev, uint8_t reg)
> {
> + ASSERT_PCI_CONF1_VALID(reg, uint16_t);
> outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8);
> - return inw(0xCFC);
> + return inw(0xCFC + (reg & 3));
> }
>
> static inline uint32_t pci_config_readl(pcidevaddr_t dev, uint8_t reg)
> {
> + ASSERT_PCI_CONF1_VALID(reg, uint32_t);
> outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8);
> return inl(0xCFC);
> }
> @@ -33,19 +46,21 @@ static inline void pci_config_writeb(pcidevaddr_t dev, uint8_t reg,
> uint8_t val)
> {
> outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8);
> - outb(val, 0xCFC);
> + outb(val, 0xCFC + (reg & 3));
> }
>
> static inline void pci_config_writew(pcidevaddr_t dev, uint8_t reg,
> uint16_t val)
> {
> + ASSERT_PCI_CONF1_VALID(reg, uint16_t);
> outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8);
> - outw(val, 0xCFC);
> + outw(val, 0xCFC + (reg & 3));
> }
>
> static inline void pci_config_writel(pcidevaddr_t dev, uint8_t reg,
> uint32_t val)
> {
> + ASSERT_PCI_CONF1_VALID(reg, uint32_t);
> outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8);
> outl(val, 0xCFC);
> }
> --
> 2.55.0.691.gc56d675ccc-goog
>
prev parent reply other threads:[~2026-08-13 21:30 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-04 23:23 [kvm-unit-tests PATCH v2] x86: pci: Support unaligned register access in PCI config read/write Irene Wang
2026-08-05 15:36 ` Jim Mattson
2026-08-07 22:47 ` David Matlack
2026-08-13 20:57 ` [kvm-unit-tests PATCH v3] " Irene Wang
2026-08-13 21:30 ` David Matlack [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=an43bksYniPqk8mp@google.com \
--to=dmatlack@google.com \
--cc=andrew.jones@linux.dev \
--cc=jmattson@google.com \
--cc=kvm@vger.kernel.org \
--cc=pbonzini@redhat.com \
--cc=seanjc@google.com \
--cc=thuth@redhat.com \
--cc=yiranirenewang@gmail.com \
--cc=yosry@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox