On 2 September 2013 21:26, Hervé Poussineau <hpous...@reactos.org> wrote: > Richard Henderson a écrit : > >> On 08/23/2013 11:52 AM, Hervé Poussineau wrote: >>> >>> + uint8_t buf[4]; >>> + uint64_t val; >>> + >>> + if (s->contiguous_map == 0) { >>> + /* 64 KB contiguous space for IOs */ >>> + addr &= 0xFFFF; >>> + } else { >>> + /* 8 MB non-contiguous space for IOs */ >>> + addr = (addr & 0x1F) | ((addr & 0x007FFF000) >> 7); >>> + } >>> + >>> + address_space_read(&s->pci_io_as, addr + 0x80000000, buf, size); >>> + memcpy(&val, buf, size); >>> + return val; >> >> >> This memcpy can't be right, especially for big-endian host.
The most immediately obvious problem is that it's not initialized and you're only copying size bytes of data into an 8 byte wide type. Worse, as Richard suggests, on big-endian CPUs you're writing into the upper half of the variable, so when the caller truncates it to 32 bits for a guest CPU word access it will throw away the data completely. > pci_io_as is supposed to contain words/longs in little-endian mode (PCI is > always little-endian). > prep_io_ops endianness is DEVICE_LITTLE_ENDIAN, so, AFAIK, this means that > returned val should be LE. > Why should it break on big-endian hosts? This isn't how the DEVICE_*_ENDIAN work. Memory region read/write callbacks always return their values in host-CPU byte order (ie "return 0x87654321;" returns a value whose least significant byte is 0x21). The DEVICE_*_ENDIAN fields are then used to correctly convert that host-endian value into whatever the CPU needs to see (ie if your CPU is TARGET_WORDS_BIGENDIAN and the device is DEVICE_LITTLE_ENDIAN the memory codepath will insert one bswap operation of the appropriate size). -- PMM