@@ -36,18 +36,28 @@ void init_alloc_vpage(void *top)
vfree_top = top;
}
-void *vmap(phys_addr_t phys, size_t size)
+/*
+ * op: VMAP_MAP
+ * VMAP_UNMAP
+ * VMAP_REMAP
+ */
+void *vmap(phys_addr_t phys, void *vmem, size_t size, int op)
{
void *mem, *p;
unsigned pages;
size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
pages = size / PAGE_SIZE;
- mem = p = alloc_vpages(pages);
-
+ if (op == VMAP_MAP)
+ mem = p = alloc_vpages(pages);
+ else
+ mem = p = vmem;
phys &= ~(unsigned long long)(PAGE_SIZE - 1);
while (pages--) {
- install_page(page_root, phys, p);
+ if (op == VMAP_UNMAP)
+ install_page(page_root, phys, p);
+ else
+ uninstall_page(page_root, phys, p);
phys += PAGE_SIZE;
p += PAGE_SIZE;
}
@@ -3,6 +3,11 @@
#include <asm/page.h>
+/* vmap op type */
+#define VMAP_MAP 0
+#define VMAP_UNMAP 1
+#define VMAP_REMAP 2
+
extern void *alloc_vpages(ulong nr);
extern void *alloc_vpage(void);
extern void init_alloc_vpage(void *top);
@@ -11,7 +16,7 @@ extern void setup_vm(void);
extern void *setup_mmu(phys_addr_t top);
extern phys_addr_t virt_to_pte_phys(pgd_t *pgtable, void *virt);
extern pteval_t *install_page(pgd_t *pgtable, phys_addr_t phys, void *virt);
-
-void *vmap(phys_addr_t phys, size_t size);
+extern pteval_t *uninstall_page(pgd_t *pgtable, phys_addr_t phys, void *virt);
+void *vmap(phys_addr_t phys, void * vmem, size_t size, int op);
#endif
@@ -116,5 +116,5 @@ void __iomem *ioremap(phys_addr_t phys_addr, size_t size)
* mappings would be uncached - and may help us find bugs when we
* properly map that way.
*/
- return vmap(phys_addr, size) + offset;
+ return vmap(phys_addr, NULL, size, VMAP_MAP) + offset;
}
@@ -100,6 +100,11 @@ pteval_t *install_page(pgd_t *cr3, phys_addr_t phys, void *virt)
return install_pte(cr3, 1, virt, phys | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK, 0);
}
+pteval_t *uninstall_page(pgd_t *cr3, phys_addr_t phys, void *virt)
+{
+ return install_pte(cr3, 1, virt, phys | PT_WRITABLE_MASK | PT_USER_MASK, 0);
+}
+
void install_pages(pgd_t *cr3, phys_addr_t phys, size_t len, void *virt)
{
phys_addr_t max = (u64)len + (u64)phys;
@@ -11,6 +11,8 @@
#define TESTDEV_IO_PORT 0xe0
static int exceptions;
+static void *insn_page;
+static void *insn_ram;
/* Forced emulation prefix, used to invoke the emulator unconditionally. */
#define KVM_FEP "ud2; .byte 'k', 'v', 'm';"
@@ -33,6 +35,49 @@ struct insn_desc {
static char st1[] = "abcdefghijklmnop";
+void do_pf_tss(void);
+void do_pf_tss(void)
+{
+ printf("PF running\n");
+ vmap(virt_to_phys(insn_page), insn_ram, 4096, VMAP_REMAP);
+ invlpg(insn_ram);
+}
+
+extern void pf_tss(void);
+
+asm ("pf_tss: \n\t"
+#ifdef __x86_64__
+ // no task on x86_64, save/restore caller-save regs
+ "push %rax; push %rcx; push %rdx; push %rsi; push %rdi\n"
+ "push %r8; push %r9; push %r10; push %r11\n"
+#endif
+ "call do_pf_tss \n\t"
+#ifdef __x86_64__
+ "pop %r11; pop %r10; pop %r9; pop %r8\n"
+ "pop %rdi; pop %rsi; pop %rdx; pop %rcx; pop %rax\n"
+#endif
+ "add $"S", %"R "sp\n\t" // discard error code
+ "iret"W" \n\t"
+ "jmp pf_tss\n\t"
+ );
+
+static void test_fetch_insn(unsigned *mem,unsigned long phys, char *insn_ram)
+{
+ /* movb $1, mem+2(%rip) */
+ insn_ram[0] = 0xc6;
+ insn_ram[1] = 0x05;
+ *(unsigned *)&insn_ram[2] = 2 + (char *)mem - (insn_ram + 7);
+ insn_ram[6] = 0x01;
+ /* ret */
+ insn_ram[7] = 0xc3;
+
+ vmap(phys, insn_ram, 4096, VMAP_UNMAP);
+
+ *mem = 0;
+ asm("callq *%1" : "+m"(*mem) : "r"(insn_ram));
+ report("fetch ", *mem == 0x10000);
+}
+
static void test_stringio(void)
{
unsigned char r = 0;
@@ -1018,12 +1063,11 @@ static void record_no_fep(struct ex_regs *regs)
int main(void)
{
void *mem;
- void *insn_page;
- void *insn_ram;
unsigned long t1, t2;
setup_vm();
setup_idt();
+ setup_alt_stack();
handle_exception(UD_VECTOR, record_no_fep);
asm(KVM_FEP "nop");
handle_exception(UD_VECTOR, 0);
@@ -1033,7 +1077,7 @@ int main(void)
// install the page twice to test cross-page mmio
install_page((void *)read_cr3(), IORAM_BASE_PHYS, mem + 4096);
insn_page = alloc_page();
- insn_ram = vmap(virt_to_phys(insn_page), 4096);
+ insn_ram = vmap(virt_to_phys(insn_page), NULL, 4096, VMAP_MAP);
// test mov reg, r/m and mov r/m, reg
t1 = 0x123456789abcdef;
@@ -1068,6 +1112,8 @@ int main(void)
test_sse(mem);
test_mmx(mem);
test_rip_relative(mem, insn_ram);
+ set_intr_alt_stack(14, pf_tss);
+ test_fetch_insn(mem, virt_to_phys(insn_page), insn_ram);
test_shld_shrd(mem);
//test_lgdt_lidt(mem);
test_sreg(mem);
the test case is for "kvm/x86: fix a fetch fault emulation" . KVM internal error. Suberror: 1 emulation failure RAX=0000000000463fe8 RBX=ffffffffffffd000 RCX=000000000000000c RDX=0000000000464006 RSI=0000000000000001 RDI=0000000000463000 RBP=0000000000452ce0 RSP=0000000000452c78 R8 =0000000000000000 R9 =0000000000410d7f R10=0000000000000000 R11=0000000000000000 R12=ffffffffffffe000 R13=1111111111111111 R14=3333333333333333 R15=00000000a06d39e8 RIP=ffffffffffffd000 RFL=00010002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0 ES =0010 0000000000000000 ffffffff 00c09300 DPL=0 DS [-WA] CS =0008 0000000000000000 ffffffff 00a09b00 DPL=0 CS64 [-RA] SS =0010 0000000000000000 ffffffff 00c09300 DPL=0 DS [-WA] v1 --> v2: simply some functions. Signed-off-by: Peng Hao <peng.hao2@zte.com.cn> --- lib/vmalloc.c | 18 ++++++++++++++---- lib/vmalloc.h | 9 +++++++-- lib/x86/io.c | 2 +- lib/x86/vm.c | 5 +++++ x86/emulator.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 76 insertions(+), 10 deletions(-)