Skip to content

Commit 4517536

Browse files
halil-pasiccohuck
authored andcommitted
s390x/pci: fix set_ind_atomic
The atomic_cmpxchg() loop is broken because we occasionally end up with old and _old having different values (a legit compiler can generate code that accessed *ind_addr again to pick up a value for _old instead of using the value of old that was already fetched according to the rules of the abstract machine). This means the underlying CS instruction may use a different old (_old) than the one we intended to use if atomic_cmpxchg() performed the xchg part. Let us use volatile to force the rules of the abstract machine for accesses to *ind_addr. Let us also rewrite the loop so, we that the new old is used to compute the new desired value if the xchg part is not performed. Fixes: 8cba80c ("s390: Add PCI bus support") Reported-by: Christian Borntraeger <[email protected]> Signed-off-by: Halil Pasic <[email protected]> Reviewed-by: Christian Borntraeger <[email protected]> Message-Id: <[email protected]> Signed-off-by: Cornelia Huck <[email protected]>
1 parent 1a8242f commit 4517536

File tree

1 file changed

+9
-7
lines changed

1 file changed

+9
-7
lines changed

hw/s390x/s390-pci-bus.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -637,22 +637,24 @@ static AddressSpace *s390_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
637637

638638
static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set)
639639
{
640-
uint8_t ind_old, ind_new;
640+
uint8_t expected, actual;
641641
hwaddr len = 1;
642-
uint8_t *ind_addr;
642+
/* avoid multiple fetches */
643+
uint8_t volatile *ind_addr;
643644

644645
ind_addr = cpu_physical_memory_map(ind_loc, &len, true);
645646
if (!ind_addr) {
646647
s390_pci_generate_error_event(ERR_EVENT_AIRERR, 0, 0, 0, 0);
647648
return -1;
648649
}
650+
actual = *ind_addr;
649651
do {
650-
ind_old = *ind_addr;
651-
ind_new = ind_old | to_be_set;
652-
} while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old);
653-
cpu_physical_memory_unmap(ind_addr, len, 1, len);
652+
expected = actual;
653+
actual = atomic_cmpxchg(ind_addr, expected, expected | to_be_set);
654+
} while (actual != expected);
655+
cpu_physical_memory_unmap((void *)ind_addr, len, 1, len);
654656

655-
return ind_old;
657+
return actual;
656658
}
657659

658660
static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data,

0 commit comments

Comments
 (0)