dev: Align BAR0 size to power of 2 for VirtIO devices
When setting the size of a PCI BAR, the kernel only supports powers of two (as per the PCI spec). Previously, the size was incorrectly read by the kernel, and the address ranges assigned to the PCI devices could overlap, resulting in gem5 crashes. We now round up to the next power of two. Kudos to Sergei Trofimov who helped to debug this issue! Change-Id: I54ca399b62ea07c09d4cd989b17dfa670e841bbe Reviewed-by: Anouk Van Laer <anouk.vanlaer@arm.com> Reviewed-by: Sergei Trofimov <sergei.trofimov@arm.com> Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com> Reviewed-on: https://gem5-review.googlesource.com/2580 Reviewed-by: Paul Rosenfeld <prosenfeld@micron.com>
This commit is contained in:
parent
ba00d7449d
commit
d7aef8be96
2 changed files with 45 additions and 2 deletions
|
@ -1,4 +1,16 @@
|
||||||
/*
|
/*
|
||||||
|
* Copyright (c) 2017 ARM Limited
|
||||||
|
* All rights reserved
|
||||||
|
*
|
||||||
|
* The license below extends only to copyright in the software and shall
|
||||||
|
* not be construed as granting a license to any other intellectual
|
||||||
|
* property including but not limited to intellectual property relating
|
||||||
|
* to a hardware implementation of the functionality of the software
|
||||||
|
* licensed hereunder. You may use the software subject to the license
|
||||||
|
* terms below provided that you ensure that this notice is replicated
|
||||||
|
* unmodified and in its entirety in all distributions of the software,
|
||||||
|
* modified or unmodified, in source code or in binary form.
|
||||||
|
*
|
||||||
* Copyright (c) 2003-2005 The Regents of The University of Michigan
|
* Copyright (c) 2003-2005 The Regents of The University of Michigan
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
|
@ -211,4 +223,29 @@ popCount(uint64_t val) {
|
||||||
return (val * sum) >> 56; // horizontal sum
|
return (val * sum) >> 56; // horizontal sum
|
||||||
#endif // defined(__GNUC__) || (defined(__clang__) && __has_builtin(__builtin_popcountl))
|
#endif // defined(__GNUC__) || (defined(__clang__) && __has_builtin(__builtin_popcountl))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Align to the next highest power of two.
|
||||||
|
*
|
||||||
|
* The number passed in is aligned to the next highest power of two,
|
||||||
|
* if it is not already a power of two. Please note that if 0 is
|
||||||
|
* passed in, 0 is returned.
|
||||||
|
*
|
||||||
|
* This code has been modified from the following:
|
||||||
|
* http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
||||||
|
*/
|
||||||
|
inline uint64_t alignToPowerOfTwo(uint64_t val)
|
||||||
|
{
|
||||||
|
val--;
|
||||||
|
val |= val >> 1;
|
||||||
|
val |= val >> 2;
|
||||||
|
val |= val >> 4;
|
||||||
|
val |= val >> 8;
|
||||||
|
val |= val >> 16;
|
||||||
|
val |= val >> 32;
|
||||||
|
val++;
|
||||||
|
|
||||||
|
return val;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // __BASE_BITFIELD_HH__
|
#endif // __BASE_BITFIELD_HH__
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014 ARM Limited
|
* Copyright (c) 2014, 2017 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -39,6 +39,7 @@
|
||||||
|
|
||||||
#include "dev/virtio/pci.hh"
|
#include "dev/virtio/pci.hh"
|
||||||
|
|
||||||
|
#include "base/bitfield.hh"
|
||||||
#include "debug/VIOIface.hh"
|
#include "debug/VIOIface.hh"
|
||||||
#include "mem/packet_access.hh"
|
#include "mem/packet_access.hh"
|
||||||
#include "params/PciVirtIO.hh"
|
#include "params/PciVirtIO.hh"
|
||||||
|
@ -49,7 +50,12 @@ PciVirtIO::PciVirtIO(const Params *params)
|
||||||
{
|
{
|
||||||
// Override the subsystem ID with the device ID from VirtIO
|
// Override the subsystem ID with the device ID from VirtIO
|
||||||
config.subsystemID = htole(vio.deviceId);
|
config.subsystemID = htole(vio.deviceId);
|
||||||
BARSize[0] = BAR0_SIZE_BASE + vio.configSize;
|
|
||||||
|
// The kernel driver expects the BAR size to be an exact power of
|
||||||
|
// two. Nothing else is supported. Therefore, we need to force
|
||||||
|
// that alignment here. We do not touch vio.configSize as this is
|
||||||
|
// used to check accesses later on.
|
||||||
|
BARSize[0] = alignToPowerOfTwo(BAR0_SIZE_BASE + vio.configSize);
|
||||||
|
|
||||||
vio.registerKickCallback(&callbackKick);
|
vio.registerKickCallback(&callbackKick);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue