Hi,
On 5/2/25 4:15 AM, Alejandro Jimenez wrote:
> Caution: External email. Do not open attachments or click links, unless this
> email comes from a known sender and you know the content is safe.
>
>
> Extracting the DTE from a given AMDVIAddressSpace pointer structure is a
> common operation required for syncing the shadow page tables. Implement a
> helper to do it and check for common error conditions.
>
> Signed-off-by: Alejandro Jimenez <[email protected]>
> ---
> hw/i386/amd_iommu.c | 45 ++++++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 40 insertions(+), 5 deletions(-)
>
> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
> index dff6f04c8651..5322a614f5d6 100644
> --- a/hw/i386/amd_iommu.c
> +++ b/hw/i386/amd_iommu.c
> @@ -77,6 +77,18 @@ typedef struct AMDVIIOTLBEntry {
> uint64_t page_mask; /* physical page size */
> } AMDVIIOTLBEntry;
>
> +/*
> + * These 'fault' reasons have an overloaded meaning since they are not only
> + * intended for describing reasons that generate an IO_PAGE_FAULT as per the
> AMD
> + * IOMMU specification, but are also used to signal internal errors in the
> + * emulation code.
> + */
> +typedef enum AMDVIFaultReason {
> + AMDVI_FR_DTE_RTR_ERR = 1, /* Failure to retrieve DTE */
> + AMDVI_FR_DTE_V, /* DTE[V] = 0 */
> + AMDVI_FR_DTE_TV, /* DTE[TV] = 0 */
> +} AMDVIFaultReason;
> +
> uint64_t amdvi_extended_feature_register(AMDVIState *s)
> {
> uint64_t feature = AMDVI_DEFAULT_EXT_FEATURES;
> @@ -492,6 +504,28 @@ static inline uint64_t amdvi_get_pte_entry(AMDVIState
> *s, uint64_t pte_addr,
> return pte;
> }
>
> +static int amdvi_as_to_dte(AMDVIAddressSpace *as, uint64_t *dte)
> +{
> + uint16_t devid = PCI_BUILD_BDF(as->bus_num, as->devfn);
> + AMDVIState *s = as->iommu_state;
> +
> + if (!amdvi_get_dte(s, devid, dte)) {
> + /* Unable to retrieve DTE for devid */
> + return -AMDVI_FR_DTE_RTR_ERR;
> + }
> +
> + if (!(dte[0] & AMDVI_DEV_VALID)) {
> + /* DTE[V] not set, address is passed untranslated for devid */
> + return -AMDVI_FR_DTE_V;
> + }
> +
> + if (!(dte[0] & AMDVI_DEV_TRANSLATION_VALID)) {
> + /* DTE[TV] not set, host page table not valid for devid */
> + return -AMDVI_FR_DTE_TV;
> + }
> + return 0;
> +}
> +
I'm not sure the new amdvi_as_to_dte() helper adds much. It just wraps a
few checks and makes it harder to report faults properly in the future.
Is there a reason this couldn't be handled inline?
> /* log error without aborting since linux seems to be using reserved bits */
> static void amdvi_inval_devtab_entry(AMDVIState *s, uint64_t *cmd)
> {
> @@ -1024,6 +1058,7 @@ static void amdvi_do_translate(AMDVIAddressSpace *as,
> hwaddr addr,
> uint16_t devid = PCI_BUILD_BDF(as->bus_num, as->devfn);
> AMDVIIOTLBEntry *iotlb_entry = amdvi_iotlb_lookup(s, addr, devid);
> uint64_t entry[4];
> + int dte_ret;
>
> if (iotlb_entry) {
> trace_amdvi_iotlb_hit(PCI_BUS_NUM(devid), PCI_SLOT(devid),
> @@ -1035,13 +1070,13 @@ static void amdvi_do_translate(AMDVIAddressSpace *as,
> hwaddr addr,
> return;
> }
>
> - if (!amdvi_get_dte(s, devid, entry)) {
> - return;
> - }
> + dte_ret = amdvi_as_to_dte(as, entry);
>
> - /* devices with V = 0 are not translated */
> - if (!(entry[0] & AMDVI_DEV_VALID)) {
> + if (dte_ret == -AMDVI_FR_DTE_V) {
> + /* DTE[V]=0, address is passed untranslated */
> goto out;
> + } else if (dte_ret == -AMDVI_FR_DTE_TV) {
> + return;
> }
>
> amdvi_page_walk(as, entry, ret,
> --
> 2.43.5
>