// SPDX-License-Identifier: GPL-2.0-only /* * entry_from_vm86.c - tests kernel entries from vm86 mode * Copyright (c) 2014-2015 Andrew Lutomirski * * This exercises a few paths that need to special-case vm86 mode.
*/
/* Returns false if the test was skipped. */ staticbool do_test(struct vm86plus_struct *v86, unsignedlong eip, unsignedint rettype, unsignedint retarg, constchar *text)
{ long ret;
printf("[RUN]\t%s from vm86 mode\n", text);
v86->regs.eip = eip;
ret = vm86(VM86_ENTER, v86);
printf("[INFO]\tExited vm86 mode due to #%s\n", trapname);
} elseif (VM86_TYPE(ret) == VM86_UNKNOWN) {
printf("[INFO]\tExited vm86 mode due to unhandled GP fault\n");
} elseif (VM86_TYPE(ret) == VM86_TRAP) {
printf("[INFO]\tExited vm86 mode due to a trap (arg=%ld)\n",
VM86_ARG(ret));
} elseif (VM86_TYPE(ret) == VM86_SIGNAL) {
printf("[INFO]\tExited vm86 mode due to a signal\n");
} elseif (VM86_TYPE(ret) == VM86_STI) {
printf("[INFO]\tExited vm86 mode due to STI\n");
} else {
printf("[INFO]\tExited vm86 mode due to type %ld, arg %ld\n",
VM86_TYPE(ret), VM86_ARG(ret));
}
/* Results when using register operands */
msw3 = *(unsignedshort *)(test_mem + 2080);
printf("[INFO]\tResult from SMSW:[0x%04x]\n", msw1);
printf("[INFO]\tResult from SIDT: limit[0x%04x]base[0x%08lx]\n",
idt1.limit, idt1.base);
printf("[INFO]\tResult from SGDT: limit[0x%04x]base[0x%08lx]\n",
gdt1.limit, gdt1.base);
if (msw1 != msw2 || msw1 != msw3)
printf("[FAIL]\tAll the results of SMSW should be the same.\n"); else
printf("[PASS]\tAll the results from SMSW are identical.\n");
if (memcmp(&gdt1, &gdt2, sizeof(gdt1)))
printf("[FAIL]\tAll the results of SGDT should be the same.\n"); else
printf("[PASS]\tAll the results from SGDT are identical.\n");
if (memcmp(&idt1, &idt2, sizeof(idt1)))
printf("[FAIL]\tAll the results of SIDT should be the same.\n"); else
printf("[PASS]\tAll the results from SIDT are identical.\n");
/* * SYSENTER -- should cause #GP or #UD depending on CPU. * Expected return type -1 means that we shouldn't validate * the vm86 return value. This will avoid problems on non-SEP * CPUs.
*/
sethandler(SIGILL, sighandler, 0);
do_test(&v86, vmcode_sysenter - vmcode, -1, 0, "SYSENTER");
clearhandler(SIGILL);
/* * SYSCALL would be a disaster in VM86 mode. Fortunately, * there is no kernel that both enables SYSCALL and sets * EFER.SCE, so it's #UD on all systems. But vm86 is * buggy (or has a "feature"), so the SIGILL will actually * be delivered.
*/
sethandler(SIGILL, sighandler, 0);
do_test(&v86, vmcode_syscall - vmcode, VM86_SIGNAL, 0, "SYSCALL");
clearhandler(SIGILL);
/* STI with VIP set */
v86.regs.eflags |= X86_EFLAGS_VIP;
v86.regs.eflags &= ~X86_EFLAGS_IF;
do_test(&v86, vmcode_sti - vmcode, VM86_STI, 0, "STI with VIP set");
/* POPF with VIP set but IF clear: should not trap */
v86.regs.eflags = X86_EFLAGS_VIP;
v86.regs.eax = 0;
do_test(&v86, vmcode_popf_hlt - vmcode, VM86_UNKNOWN, 0, "POPF with VIP set and IF clear");
/* POPF with VIP set and IF set: should trap */
v86.regs.eflags = X86_EFLAGS_VIP;
v86.regs.eax = X86_EFLAGS_IF;
do_test(&v86, vmcode_popf_hlt - vmcode, VM86_STI, 0, "POPF with VIP and IF set");
/* POPF with VIP clear and IF set: should not trap */
v86.regs.eflags = 0;
v86.regs.eax = X86_EFLAGS_IF;
do_test(&v86, vmcode_popf_hlt - vmcode, VM86_UNKNOWN, 0, "POPF with VIP clear and IF set");
v86.regs.eflags = 0;
/* INT3 -- should cause #BP */
do_test(&v86, vmcode_int3 - vmcode, VM86_TRAP, 3, "INT3");
/* INT80 -- should exit with "INTx 0x80" */
v86.regs.eax = (unsignedint)-1;
do_test(&v86, vmcode_int80 - vmcode, VM86_INTx, 0x80, "int80");
/* UMIP -- should exit with INTx 0x80 unless UMIP was not disabled */
do_umip_tests(&v86, addr);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.