summaryrefslogtreecommitdiffstats
path: root/virt
diff options
context:
space:
mode:
authorEric Auger <eric.auger@redhat.com>2017-02-07 23:20:04 -0500
committerChristoffer Dall <cdall@linaro.org>2017-05-08 08:38:10 -0400
commit920a7a8fa92ae0ec73c4f6d6f15c01f86017f20d (patch)
treedefb52db0f4aa5110d26cb0d9c54972b1698e924 /virt
parent528297f560add8b7cac2f401d6aeb5bb3d1ef345 (diff)
KVM: arm64: vgic-its: Add infrastructure for table lookup
Add a generic scan_its_table() helper whose role consists in scanning a contiguous table located in guest RAM and applying a callback on each entry. Entries can be handled as linked lists since the callback may return an id offset to the next entry and also indicate whether the entry is the last one. Helper functions also are added to compute the device/event ID offset to the next DTE/ITE. compute_next_devid_offset, compute_next_eventid_offset and scan_table will become static in subsequent patches Signed-off-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Christoffer Dall <cdall@linaro.org> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'virt')
-rw-r--r--virt/kvm/arm/vgic/vgic-its.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 737ba3c9e9be..d5c0057196ae 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -244,6 +244,8 @@ static struct its_ite *find_ite(struct vgic_its *its, u32 device_id,
244 244
245#define VITS_TYPER_IDBITS 16 245#define VITS_TYPER_IDBITS 16
246#define VITS_TYPER_DEVBITS 16 246#define VITS_TYPER_DEVBITS 16
247#define VITS_DTE_MAX_DEVID_OFFSET (BIT(14) - 1)
248#define VITS_ITE_MAX_EVENTID_OFFSET (BIT(16) - 1)
247 249
248/* 250/*
249 * Finds and returns a collection in the ITS collection table. 251 * Finds and returns a collection in the ITS collection table.
@@ -1728,6 +1730,96 @@ out:
1728 return ret; 1730 return ret;
1729} 1731}
1730 1732
1733u32 compute_next_devid_offset(struct list_head *h, struct its_device *dev)
1734{
1735 struct its_device *next;
1736 u32 next_offset;
1737
1738 if (list_is_last(&dev->dev_list, h))
1739 return 0;
1740 next = list_next_entry(dev, dev_list);
1741 next_offset = next->device_id - dev->device_id;
1742
1743 return min_t(u32, next_offset, VITS_DTE_MAX_DEVID_OFFSET);
1744}
1745
1746u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
1747{
1748 struct its_ite *next;
1749 u32 next_offset;
1750
1751 if (list_is_last(&ite->ite_list, h))
1752 return 0;
1753 next = list_next_entry(ite, ite_list);
1754 next_offset = next->event_id - ite->event_id;
1755
1756 return min_t(u32, next_offset, VITS_ITE_MAX_EVENTID_OFFSET);
1757}
1758
1759/**
1760 * entry_fn_t - Callback called on a table entry restore path
1761 * @its: its handle
1762 * @id: id of the entry
1763 * @entry: pointer to the entry
1764 * @opaque: pointer to an opaque data
1765 *
1766 * Return: < 0 on error, 0 if last element was identified, id offset to next
1767 * element otherwise
1768 */
1769typedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry,
1770 void *opaque);
1771
1772/**
1773 * scan_its_table - Scan a contiguous table in guest RAM and applies a function
1774 * to each entry
1775 *
1776 * @its: its handle
1777 * @base: base gpa of the table
1778 * @size: size of the table in bytes
1779 * @esz: entry size in bytes
1780 * @start_id: the ID of the first entry in the table
1781 * (non zero for 2d level tables)
1782 * @fn: function to apply on each entry
1783 *
1784 * Return: < 0 on error, 0 if last element was identified, 1 otherwise
1785 * (the last element may not be found on second level tables)
1786 */
1787int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
1788 int start_id, entry_fn_t fn, void *opaque)
1789{
1790 void *entry = kzalloc(esz, GFP_KERNEL);
1791 struct kvm *kvm = its->dev->kvm;
1792 unsigned long len = size;
1793 int id = start_id;
1794 gpa_t gpa = base;
1795 int ret;
1796
1797 while (len > 0) {
1798 int next_offset;
1799 size_t byte_offset;
1800
1801 ret = kvm_read_guest(kvm, gpa, entry, esz);
1802 if (ret)
1803 goto out;
1804
1805 next_offset = fn(its, id, entry, opaque);
1806 if (next_offset <= 0) {
1807 ret = next_offset;
1808 goto out;
1809 }
1810
1811 byte_offset = next_offset * esz;
1812 id += next_offset;
1813 gpa += byte_offset;
1814 len -= byte_offset;
1815 }
1816 ret = 1;
1817
1818out:
1819 kfree(entry);
1820 return ret;
1821}
1822
1731/** 1823/**
1732 * vgic_its_save_device_tables - Save the device table and all ITT 1824 * vgic_its_save_device_tables - Save the device table and all ITT
1733 * into guest RAM 1825 * into guest RAM