diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/testing/selftests/x86/entry_from_vm86.c | 73 |
1 files changed, 72 insertions, 1 deletions
diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c index d075ea0e5ca1..f7d9ceac7e06 100644 --- a/tools/testing/selftests/x86/entry_from_vm86.c +++ b/tools/testing/selftests/x86/entry_from_vm86.c | |||
| @@ -95,6 +95,22 @@ asm ( | |||
| 95 | "int3\n\t" | 95 | "int3\n\t" |
| 96 | "vmcode_int80:\n\t" | 96 | "vmcode_int80:\n\t" |
| 97 | "int $0x80\n\t" | 97 | "int $0x80\n\t" |
| 98 | "vmcode_umip:\n\t" | ||
| 99 | /* addressing via displacements */ | ||
| 100 | "smsw (2052)\n\t" | ||
| 101 | "sidt (2054)\n\t" | ||
| 102 | "sgdt (2060)\n\t" | ||
| 103 | /* addressing via registers */ | ||
| 104 | "mov $2066, %bx\n\t" | ||
| 105 | "smsw (%bx)\n\t" | ||
| 106 | "mov $2068, %bx\n\t" | ||
| 107 | "sidt (%bx)\n\t" | ||
| 108 | "mov $2074, %bx\n\t" | ||
| 109 | "sgdt (%bx)\n\t" | ||
| 110 | /* register operands, only for smsw */ | ||
| 111 | "smsw %ax\n\t" | ||
| 112 | "mov %ax, (2080)\n\t" | ||
| 113 | "int3\n\t" | ||
| 98 | ".size vmcode, . - vmcode\n\t" | 114 | ".size vmcode, . - vmcode\n\t" |
| 99 | "end_vmcode:\n\t" | 115 | "end_vmcode:\n\t" |
| 100 | ".code32\n\t" | 116 | ".code32\n\t" |
| @@ -103,7 +119,7 @@ asm ( | |||
| 103 | 119 | ||
| 104 | extern unsigned char vmcode[], end_vmcode[]; | 120 | extern unsigned char vmcode[], end_vmcode[]; |
| 105 | extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[], | 121 | extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[], |
| 106 | vmcode_sti[], vmcode_int3[], vmcode_int80[]; | 122 | vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_umip[]; |
| 107 | 123 | ||
| 108 | /* Returns false if the test was skipped. */ | 124 | /* Returns false if the test was skipped. */ |
| 109 | static bool do_test(struct vm86plus_struct *v86, unsigned long eip, | 125 | static bool do_test(struct vm86plus_struct *v86, unsigned long eip, |
| @@ -160,6 +176,58 @@ static bool do_test(struct vm86plus_struct *v86, unsigned long eip, | |||
| 160 | return true; | 176 | return true; |
| 161 | } | 177 | } |
| 162 | 178 | ||
| 179 | void do_umip_tests(struct vm86plus_struct *vm86, unsigned char *test_mem) | ||
| 180 | { | ||
| 181 | struct table_desc { | ||
| 182 | unsigned short limit; | ||
| 183 | unsigned long base; | ||
| 184 | } __attribute__((packed)); | ||
| 185 | |||
| 186 | /* Initialize variables with arbitrary values */ | ||
| 187 | struct table_desc gdt1 = { .base = 0x3c3c3c3c, .limit = 0x9999 }; | ||
| 188 | struct table_desc gdt2 = { .base = 0x1a1a1a1a, .limit = 0xaeae }; | ||
| 189 | struct table_desc idt1 = { .base = 0x7b7b7b7b, .limit = 0xf1f1 }; | ||
| 190 | struct table_desc idt2 = { .base = 0x89898989, .limit = 0x1313 }; | ||
| 191 | unsigned short msw1 = 0x1414, msw2 = 0x2525, msw3 = 3737; | ||
| 192 | |||
| 193 | /* UMIP -- exit with INT3 unless kernel emulation did not trap #GP */ | ||
| 194 | do_test(vm86, vmcode_umip - vmcode, VM86_TRAP, 3, "UMIP tests"); | ||
| 195 | |||
| 196 | /* Results from displacement-only addressing */ | ||
| 197 | msw1 = *(unsigned short *)(test_mem + 2052); | ||
| 198 | memcpy(&idt1, test_mem + 2054, sizeof(idt1)); | ||
| 199 | memcpy(&gdt1, test_mem + 2060, sizeof(gdt1)); | ||
| 200 | |||
| 201 | /* Results from register-indirect addressing */ | ||
| 202 | msw2 = *(unsigned short *)(test_mem + 2066); | ||
| 203 | memcpy(&idt2, test_mem + 2068, sizeof(idt2)); | ||
| 204 | memcpy(&gdt2, test_mem + 2074, sizeof(gdt2)); | ||
| 205 | |||
| 206 | /* Results when using register operands */ | ||
| 207 | msw3 = *(unsigned short *)(test_mem + 2080); | ||
| 208 | |||
| 209 | printf("[INFO]\tResult from SMSW:[0x%04x]\n", msw1); | ||
| 210 | printf("[INFO]\tResult from SIDT: limit[0x%04x]base[0x%08lx]\n", | ||
| 211 | idt1.limit, idt1.base); | ||
| 212 | printf("[INFO]\tResult from SGDT: limit[0x%04x]base[0x%08lx]\n", | ||
| 213 | gdt1.limit, gdt1.base); | ||
| 214 | |||
| 215 | if (msw1 != msw2 || msw1 != msw3) | ||
| 216 | printf("[FAIL]\tAll the results of SMSW should be the same.\n"); | ||
| 217 | else | ||
| 218 | printf("[PASS]\tAll the results from SMSW are identical.\n"); | ||
| 219 | |||
| 220 | if (memcmp(&gdt1, &gdt2, sizeof(gdt1))) | ||
| 221 | printf("[FAIL]\tAll the results of SGDT should be the same.\n"); | ||
| 222 | else | ||
| 223 | printf("[PASS]\tAll the results from SGDT are identical.\n"); | ||
| 224 | |||
| 225 | if (memcmp(&idt1, &idt2, sizeof(idt1))) | ||
| 226 | printf("[FAIL]\tAll the results of SIDT should be the same.\n"); | ||
| 227 | else | ||
| 228 | printf("[PASS]\tAll the results from SIDT are identical.\n"); | ||
| 229 | } | ||
| 230 | |||
| 163 | int main(void) | 231 | int main(void) |
| 164 | { | 232 | { |
| 165 | struct vm86plus_struct v86; | 233 | struct vm86plus_struct v86; |
| @@ -218,6 +286,9 @@ int main(void) | |||
| 218 | v86.regs.eax = (unsigned int)-1; | 286 | v86.regs.eax = (unsigned int)-1; |
| 219 | do_test(&v86, vmcode_int80 - vmcode, VM86_INTx, 0x80, "int80"); | 287 | do_test(&v86, vmcode_int80 - vmcode, VM86_INTx, 0x80, "int80"); |
| 220 | 288 | ||
| 289 | /* UMIP -- should exit with INTx 0x80 unless UMIP was not disabled */ | ||
| 290 | do_umip_tests(&v86, addr); | ||
| 291 | |||
| 221 | /* Execute a null pointer */ | 292 | /* Execute a null pointer */ |
| 222 | v86.regs.cs = 0; | 293 | v86.regs.cs = 0; |
| 223 | v86.regs.ss = 0; | 294 | v86.regs.ss = 0; |
