summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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