@@ -54,6 +54,38 @@ void *vmap(phys_addr_t phys, size_t size)
return mem;
}
+void unvmap(phys_addr_t phys,void * mem, size_t size)
+{
+ unsigned pages;
+ void * p = mem;
+ size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+ pages = size / PAGE_SIZE;
+
+ phys &= ~(unsigned long long)(PAGE_SIZE - 1);
+ while (pages--) {
+ uninstall_page(page_root, phys, p);
+ phys += PAGE_SIZE;
+ p += PAGE_SIZE;
+ }
+ return;
+}
+
+void *revmap(phys_addr_t phys, void * mem, size_t size)
+{
+ void *p = mem;
+ unsigned pages;
+
+ size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+ pages = size / PAGE_SIZE;
+
+ phys &= ~(unsigned long long)(PAGE_SIZE - 1);
+ while (pages--) {
+ install_page(page_root, phys, p);
+ phys += PAGE_SIZE;
+ p += PAGE_SIZE;
+ }
+ return mem;
+}
static void *vm_memalign(size_t alignment, size_t size)
{
void *mem, *p;
@@ -11,7 +11,10 @@ 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);
+extern pteval_t *uninstall_page(pgd_t *pgtable, phys_addr_t phys, void *virt);
void *vmap(phys_addr_t phys, size_t size);
+void *revmap(phys_addr_t phys, void * mem, size_t size);
+void unvmap(phys_addr_t phys,void * mem, size_t size);
#endif
@@ -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;
@@ -16,6 +16,8 @@ static int exceptions;
#define KVM_FEP "ud2; .byte 'k', 'v', 'm';"
#define KVM_FEP_LENGTH 5
static int fep_available = 1;
+static void *insn_page;
+static void *insn_ram;
struct regs {
u64 rax, rbx, rcx, rdx;
@@ -33,6 +35,31 @@ struct insn_desc {
static char st1[] = "abcdefghijklmnop";
+void do_pf_tss(void)
+{
+ printf("PF running\n");
+ revmap(virt_to_phys(insn_page), insn_ram, 4096);
+ 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_stringio(void)
{
unsigned char r = 0;
@@ -714,6 +741,22 @@ static void test_rip_relative(unsigned *mem, char *insn_ram)
report("movb $imm, 0(%%rip)", *mem == 0x10000);
}
+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;
+ unvmap(phys, insn_ram, 4096);
+
+ *mem = 0;
+ asm("callq *%1" : "+m"(*mem) : "r"(insn_ram));
+ report("fetch insn", *mem == 0x10000);
+}
+
static void test_shld_shrd(u32 *mem)
{
*mem = 0x12345678;
@@ -1018,12 +1061,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);
@@ -1068,6 +1110,10 @@ int main(void)
test_sse(mem);
test_mmx(mem);
test_rip_relative(mem, insn_ram);
+ /* fetch insn test need handle #PF in guest */
+ 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);