]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - jailhouse/ti-jailhouse.git/commitdiff
x86: vtd: Ignore lower two bits when evaluating VTD_REQ_INV_WAIT
authorJan Kiszka <jan.kiszka@siemens.com>
Sun, 27 Jan 2019 14:23:50 +0000 (15:23 +0100)
committerJan Kiszka <jan.kiszka@siemens.com>
Sun, 27 Jan 2019 14:33:39 +0000 (15:33 +0100)
If the guest sets the wait request status address to the top of the
page, we crossed the border to the next page and either wrote some bytes
into a guest page that was previously mapped at page 2 in the temporary
mapping range, or we crashed the hypervisor on a fault if nothing was
mapped before.

Fix this by masking out the two lowest bits of the status address which
are actually reserved according to the Intel manual.

Along that, replace the hard-coded shift value with the right symbolic
constant.

Fixes: 20b09b8625d5 ("x86: Emulate interrupt remapping support to enable x2APIC usage")
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
hypervisor/arch/x86/vtd.c

index 34daa7fd8349ff08ccb7220fe3da864c9cbff816..acaf0e0356afb4efd454f099d7ca65fd47f80fa4 100644 (file)
@@ -411,7 +411,7 @@ static int vtd_emulate_qi_request(unsigned int unit_no,
                                  struct vtd_entry inv_desc)
 {
        unsigned int start, count, n;
-       void *status_page;
+       void *status_addr;
        int result;
 
        switch (inv_desc.lo_word & VTD_REQ_INV_MASK) {
@@ -437,13 +437,14 @@ static int vtd_emulate_qi_request(unsigned int unit_no,
                    !(inv_desc.lo_word & VTD_INV_WAIT_SW))
                        return -EINVAL;
 
-               status_page = paging_get_guest_pages(NULL, inv_desc.hi_word, 1,
+               status_addr = paging_get_guest_pages(NULL, inv_desc.hi_word, 1,
                                                     PAGE_DEFAULT_FLAGS);
-               if (!status_page)
+               if (!status_addr)
                        return -EINVAL;
 
-               *(u32 *)(status_page + (inv_desc.hi_word & ~PAGE_MASK)) =
-                       inv_desc.lo_word >> 32;
+               status_addr += inv_desc.hi_word & PAGE_OFFS_MASK & ~3;
+               *(u32 *)status_addr =
+                       inv_desc.lo_word >> VTD_INV_WAIT_SDATA_SHIFT;
 
                return 0;
        }