diff options
| -rw-r--r-- | arch/x86/include/asm/cpufeatures.h | 2 | ||||
| -rw-r--r-- | arch/x86/include/asm/microcode.h | 1 | ||||
| -rw-r--r-- | arch/x86/include/asm/nospec-branch.h | 5 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/intel.c | 3 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/microcode/amd.c | 34 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/microcode/core.c | 76 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/microcode/intel.c | 4 | ||||
| -rw-r--r-- | arch/x86/kernel/vm86_32.c | 3 | ||||
| -rw-r--r-- | kernel/jump_label.c | 3 | ||||
| -rw-r--r-- | tools/testing/selftests/x86/entry_from_vm86.c | 32 |
10 files changed, 108 insertions, 55 deletions
diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index f41079da38c5..d554c11e01ff 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h | |||
| @@ -316,6 +316,7 @@ | |||
| 316 | #define X86_FEATURE_VPCLMULQDQ (16*32+10) /* Carry-Less Multiplication Double Quadword */ | 316 | #define X86_FEATURE_VPCLMULQDQ (16*32+10) /* Carry-Less Multiplication Double Quadword */ |
| 317 | #define X86_FEATURE_AVX512_VNNI (16*32+11) /* Vector Neural Network Instructions */ | 317 | #define X86_FEATURE_AVX512_VNNI (16*32+11) /* Vector Neural Network Instructions */ |
| 318 | #define X86_FEATURE_AVX512_BITALG (16*32+12) /* Support for VPOPCNT[B,W] and VPSHUF-BITQMB instructions */ | 318 | #define X86_FEATURE_AVX512_BITALG (16*32+12) /* Support for VPOPCNT[B,W] and VPSHUF-BITQMB instructions */ |
| 319 | #define X86_FEATURE_TME (16*32+13) /* Intel Total Memory Encryption */ | ||
| 319 | #define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */ | 320 | #define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */ |
| 320 | #define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */ | 321 | #define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */ |
| 321 | #define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */ | 322 | #define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */ |
| @@ -328,6 +329,7 @@ | |||
| 328 | /* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */ | 329 | /* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */ |
| 329 | #define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */ | 330 | #define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */ |
| 330 | #define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */ | 331 | #define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */ |
| 332 | #define X86_FEATURE_PCONFIG (18*32+18) /* Intel PCONFIG */ | ||
| 331 | #define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */ | 333 | #define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */ |
| 332 | #define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */ | 334 | #define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */ |
| 333 | #define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */ | 335 | #define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */ |
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h index 7fb1047d61c7..6cf0e4cb7b97 100644 --- a/arch/x86/include/asm/microcode.h +++ b/arch/x86/include/asm/microcode.h | |||
| @@ -39,6 +39,7 @@ struct device; | |||
| 39 | 39 | ||
| 40 | enum ucode_state { | 40 | enum ucode_state { |
| 41 | UCODE_OK = 0, | 41 | UCODE_OK = 0, |
| 42 | UCODE_NEW, | ||
| 42 | UCODE_UPDATED, | 43 | UCODE_UPDATED, |
| 43 | UCODE_NFOUND, | 44 | UCODE_NFOUND, |
| 44 | UCODE_ERROR, | 45 | UCODE_ERROR, |
diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index d0dabeae0505..f928ad9b143f 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h | |||
| @@ -183,7 +183,10 @@ | |||
| 183 | * otherwise we'll run out of registers. We don't care about CET | 183 | * otherwise we'll run out of registers. We don't care about CET |
| 184 | * here, anyway. | 184 | * here, anyway. |
| 185 | */ | 185 | */ |
| 186 | # define CALL_NOSPEC ALTERNATIVE("call *%[thunk_target]\n", \ | 186 | # define CALL_NOSPEC \ |
| 187 | ALTERNATIVE( \ | ||
| 188 | ANNOTATE_RETPOLINE_SAFE \ | ||
| 189 | "call *%[thunk_target]\n", \ | ||
| 187 | " jmp 904f;\n" \ | 190 | " jmp 904f;\n" \ |
| 188 | " .align 16\n" \ | 191 | " .align 16\n" \ |
| 189 | "901: call 903f;\n" \ | 192 | "901: call 903f;\n" \ |
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 4aa9fd379390..c3af167d0a70 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c | |||
| @@ -105,7 +105,7 @@ static void probe_xeon_phi_r3mwait(struct cpuinfo_x86 *c) | |||
| 105 | /* | 105 | /* |
| 106 | * Early microcode releases for the Spectre v2 mitigation were broken. | 106 | * Early microcode releases for the Spectre v2 mitigation were broken. |
| 107 | * Information taken from; | 107 | * Information taken from; |
| 108 | * - https://newsroom.intel.com/wp-content/uploads/sites/11/2018/01/microcode-update-guidance.pdf | 108 | * - https://newsroom.intel.com/wp-content/uploads/sites/11/2018/03/microcode-update-guidance.pdf |
| 109 | * - https://kb.vmware.com/s/article/52345 | 109 | * - https://kb.vmware.com/s/article/52345 |
| 110 | * - Microcode revisions observed in the wild | 110 | * - Microcode revisions observed in the wild |
| 111 | * - Release note from 20180108 microcode release | 111 | * - Release note from 20180108 microcode release |
| @@ -123,7 +123,6 @@ static const struct sku_microcode spectre_bad_microcodes[] = { | |||
| 123 | { INTEL_FAM6_KABYLAKE_MOBILE, 0x09, 0x80 }, | 123 | { INTEL_FAM6_KABYLAKE_MOBILE, 0x09, 0x80 }, |
| 124 | { INTEL_FAM6_SKYLAKE_X, 0x03, 0x0100013e }, | 124 | { INTEL_FAM6_SKYLAKE_X, 0x03, 0x0100013e }, |
| 125 | { INTEL_FAM6_SKYLAKE_X, 0x04, 0x0200003c }, | 125 | { INTEL_FAM6_SKYLAKE_X, 0x04, 0x0200003c }, |
| 126 | { INTEL_FAM6_SKYLAKE_DESKTOP, 0x03, 0xc2 }, | ||
| 127 | { INTEL_FAM6_BROADWELL_CORE, 0x04, 0x28 }, | 126 | { INTEL_FAM6_BROADWELL_CORE, 0x04, 0x28 }, |
| 128 | { INTEL_FAM6_BROADWELL_GT3E, 0x01, 0x1b }, | 127 | { INTEL_FAM6_BROADWELL_GT3E, 0x01, 0x1b }, |
| 129 | { INTEL_FAM6_BROADWELL_XEON_D, 0x02, 0x14 }, | 128 | { INTEL_FAM6_BROADWELL_XEON_D, 0x02, 0x14 }, |
diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index a998e1a7d46f..48179928ff38 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c | |||
| @@ -339,7 +339,7 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax) | |||
| 339 | return -EINVAL; | 339 | return -EINVAL; |
| 340 | 340 | ||
| 341 | ret = load_microcode_amd(true, x86_family(cpuid_1_eax), desc.data, desc.size); | 341 | ret = load_microcode_amd(true, x86_family(cpuid_1_eax), desc.data, desc.size); |
| 342 | if (ret != UCODE_OK) | 342 | if (ret > UCODE_UPDATED) |
| 343 | return -EINVAL; | 343 | return -EINVAL; |
| 344 | 344 | ||
| 345 | return 0; | 345 | return 0; |
| @@ -683,27 +683,35 @@ static enum ucode_state __load_microcode_amd(u8 family, const u8 *data, | |||
| 683 | static enum ucode_state | 683 | static enum ucode_state |
| 684 | load_microcode_amd(bool save, u8 family, const u8 *data, size_t size) | 684 | load_microcode_amd(bool save, u8 family, const u8 *data, size_t size) |
| 685 | { | 685 | { |
| 686 | struct ucode_patch *p; | ||
| 686 | enum ucode_state ret; | 687 | enum ucode_state ret; |
| 687 | 688 | ||
| 688 | /* free old equiv table */ | 689 | /* free old equiv table */ |
| 689 | free_equiv_cpu_table(); | 690 | free_equiv_cpu_table(); |
| 690 | 691 | ||
| 691 | ret = __load_microcode_amd(family, data, size); | 692 | ret = __load_microcode_amd(family, data, size); |
| 692 | 693 | if (ret != UCODE_OK) { | |
| 693 | if (ret != UCODE_OK) | ||
| 694 | cleanup(); | 694 | cleanup(); |
| 695 | return ret; | ||
| 696 | } | ||
| 695 | 697 | ||
| 696 | #ifdef CONFIG_X86_32 | 698 | p = find_patch(0); |
| 697 | /* save BSP's matching patch for early load */ | 699 | if (!p) { |
| 698 | if (save) { | 700 | return ret; |
| 699 | struct ucode_patch *p = find_patch(0); | 701 | } else { |
| 700 | if (p) { | 702 | if (boot_cpu_data.microcode == p->patch_id) |
| 701 | memset(amd_ucode_patch, 0, PATCH_MAX_SIZE); | 703 | return ret; |
| 702 | memcpy(amd_ucode_patch, p->data, min_t(u32, ksize(p->data), | 704 | |
| 703 | PATCH_MAX_SIZE)); | 705 | ret = UCODE_NEW; |
| 704 | } | ||
| 705 | } | 706 | } |
| 706 | #endif | 707 | |
| 708 | /* save BSP's matching patch for early load */ | ||
| 709 | if (!save) | ||
| 710 | return ret; | ||
| 711 | |||
| 712 | memset(amd_ucode_patch, 0, PATCH_MAX_SIZE); | ||
| 713 | memcpy(amd_ucode_patch, p->data, min_t(u32, ksize(p->data), PATCH_MAX_SIZE)); | ||
| 714 | |||
| 707 | return ret; | 715 | return ret; |
| 708 | } | 716 | } |
| 709 | 717 | ||
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 70ecbc8099c9..10c4fc2c91f8 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c | |||
| @@ -517,7 +517,29 @@ static int check_online_cpus(void) | |||
| 517 | return -EINVAL; | 517 | return -EINVAL; |
| 518 | } | 518 | } |
| 519 | 519 | ||
| 520 | static atomic_t late_cpus; | 520 | static atomic_t late_cpus_in; |
| 521 | static atomic_t late_cpus_out; | ||
| 522 | |||
| 523 | static int __wait_for_cpus(atomic_t *t, long long timeout) | ||
| 524 | { | ||
| 525 | int all_cpus = num_online_cpus(); | ||
| 526 | |||
| 527 | atomic_inc(t); | ||
| 528 | |||
| 529 | while (atomic_read(t) < all_cpus) { | ||
| 530 | if (timeout < SPINUNIT) { | ||
| 531 | pr_err("Timeout while waiting for CPUs rendezvous, remaining: %d\n", | ||
| 532 | all_cpus - atomic_read(t)); | ||
| 533 | return 1; | ||
| 534 | } | ||
| 535 | |||
| 536 | ndelay(SPINUNIT); | ||
| 537 | timeout -= SPINUNIT; | ||
| 538 | |||
| 539 | touch_nmi_watchdog(); | ||
| 540 | } | ||
| 541 | return 0; | ||
| 542 | } | ||
| 521 | 543 | ||
| 522 | /* | 544 | /* |
| 523 | * Returns: | 545 | * Returns: |
| @@ -527,30 +549,16 @@ static atomic_t late_cpus; | |||
| 527 | */ | 549 | */ |
| 528 | static int __reload_late(void *info) | 550 | static int __reload_late(void *info) |
| 529 | { | 551 | { |
| 530 | unsigned int timeout = NSEC_PER_SEC; | ||
| 531 | int all_cpus = num_online_cpus(); | ||
| 532 | int cpu = smp_processor_id(); | 552 | int cpu = smp_processor_id(); |
| 533 | enum ucode_state err; | 553 | enum ucode_state err; |
| 534 | int ret = 0; | 554 | int ret = 0; |
| 535 | 555 | ||
| 536 | atomic_dec(&late_cpus); | ||
| 537 | |||
| 538 | /* | 556 | /* |
| 539 | * Wait for all CPUs to arrive. A load will not be attempted unless all | 557 | * Wait for all CPUs to arrive. A load will not be attempted unless all |
| 540 | * CPUs show up. | 558 | * CPUs show up. |
| 541 | * */ | 559 | * */ |
| 542 | while (atomic_read(&late_cpus)) { | 560 | if (__wait_for_cpus(&late_cpus_in, NSEC_PER_SEC)) |
| 543 | if (timeout < SPINUNIT) { | 561 | return -1; |
| 544 | pr_err("Timeout while waiting for CPUs rendezvous, remaining: %d\n", | ||
| 545 | atomic_read(&late_cpus)); | ||
| 546 | return -1; | ||
| 547 | } | ||
| 548 | |||
| 549 | ndelay(SPINUNIT); | ||
| 550 | timeout -= SPINUNIT; | ||
| 551 | |||
| 552 | touch_nmi_watchdog(); | ||
| 553 | } | ||
| 554 | 562 | ||
| 555 | spin_lock(&update_lock); | 563 | spin_lock(&update_lock); |
| 556 | apply_microcode_local(&err); | 564 | apply_microcode_local(&err); |
| @@ -558,15 +566,22 @@ static int __reload_late(void *info) | |||
| 558 | 566 | ||
| 559 | if (err > UCODE_NFOUND) { | 567 | if (err > UCODE_NFOUND) { |
| 560 | pr_warn("Error reloading microcode on CPU %d\n", cpu); | 568 | pr_warn("Error reloading microcode on CPU %d\n", cpu); |
| 561 | ret = -1; | 569 | return -1; |
| 562 | } else if (err == UCODE_UPDATED) { | 570 | /* siblings return UCODE_OK because their engine got updated already */ |
| 571 | } else if (err == UCODE_UPDATED || err == UCODE_OK) { | ||
| 563 | ret = 1; | 572 | ret = 1; |
| 573 | } else { | ||
| 574 | return ret; | ||
| 564 | } | 575 | } |
| 565 | 576 | ||
| 566 | atomic_inc(&late_cpus); | 577 | /* |
| 567 | 578 | * Increase the wait timeout to a safe value here since we're | |
| 568 | while (atomic_read(&late_cpus) != all_cpus) | 579 | * serializing the microcode update and that could take a while on a |
| 569 | cpu_relax(); | 580 | * large number of CPUs. And that is fine as the *actual* timeout will |
| 581 | * be determined by the last CPU finished updating and thus cut short. | ||
| 582 | */ | ||
| 583 | if (__wait_for_cpus(&late_cpus_out, NSEC_PER_SEC * num_online_cpus())) | ||
| 584 | panic("Timeout during microcode update!\n"); | ||
| 570 | 585 | ||
| 571 | return ret; | 586 | return ret; |
| 572 | } | 587 | } |
| @@ -579,12 +594,11 @@ static int microcode_reload_late(void) | |||
| 579 | { | 594 | { |
| 580 | int ret; | 595 | int ret; |
| 581 | 596 | ||
| 582 | atomic_set(&late_cpus, num_online_cpus()); | 597 | atomic_set(&late_cpus_in, 0); |
| 598 | atomic_set(&late_cpus_out, 0); | ||
| 583 | 599 | ||
| 584 | ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask); | 600 | ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask); |
| 585 | if (ret < 0) | 601 | if (ret > 0) |
| 586 | return ret; | ||
| 587 | else if (ret > 0) | ||
| 588 | microcode_check(); | 602 | microcode_check(); |
| 589 | 603 | ||
| 590 | return ret; | 604 | return ret; |
| @@ -607,7 +621,7 @@ static ssize_t reload_store(struct device *dev, | |||
| 607 | return size; | 621 | return size; |
| 608 | 622 | ||
| 609 | tmp_ret = microcode_ops->request_microcode_fw(bsp, µcode_pdev->dev, true); | 623 | tmp_ret = microcode_ops->request_microcode_fw(bsp, µcode_pdev->dev, true); |
| 610 | if (tmp_ret != UCODE_OK) | 624 | if (tmp_ret != UCODE_NEW) |
| 611 | return size; | 625 | return size; |
| 612 | 626 | ||
| 613 | get_online_cpus(); | 627 | get_online_cpus(); |
| @@ -691,10 +705,8 @@ static enum ucode_state microcode_init_cpu(int cpu, bool refresh_fw) | |||
| 691 | if (system_state != SYSTEM_RUNNING) | 705 | if (system_state != SYSTEM_RUNNING) |
| 692 | return UCODE_NFOUND; | 706 | return UCODE_NFOUND; |
| 693 | 707 | ||
| 694 | ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev, | 708 | ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev, refresh_fw); |
| 695 | refresh_fw); | 709 | if (ustate == UCODE_NEW) { |
| 696 | |||
| 697 | if (ustate == UCODE_OK) { | ||
| 698 | pr_debug("CPU%d updated upon init\n", cpu); | 710 | pr_debug("CPU%d updated upon init\n", cpu); |
| 699 | apply_microcode_on_target(cpu); | 711 | apply_microcode_on_target(cpu); |
| 700 | } | 712 | } |
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 2aded9db1d42..32b8e5724f96 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c | |||
| @@ -862,6 +862,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, | |||
| 862 | unsigned int leftover = size; | 862 | unsigned int leftover = size; |
| 863 | unsigned int curr_mc_size = 0, new_mc_size = 0; | 863 | unsigned int curr_mc_size = 0, new_mc_size = 0; |
| 864 | unsigned int csig, cpf; | 864 | unsigned int csig, cpf; |
| 865 | enum ucode_state ret = UCODE_OK; | ||
| 865 | 866 | ||
| 866 | while (leftover) { | 867 | while (leftover) { |
| 867 | struct microcode_header_intel mc_header; | 868 | struct microcode_header_intel mc_header; |
| @@ -903,6 +904,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, | |||
| 903 | new_mc = mc; | 904 | new_mc = mc; |
| 904 | new_mc_size = mc_size; | 905 | new_mc_size = mc_size; |
| 905 | mc = NULL; /* trigger new vmalloc */ | 906 | mc = NULL; /* trigger new vmalloc */ |
| 907 | ret = UCODE_NEW; | ||
| 906 | } | 908 | } |
| 907 | 909 | ||
| 908 | ucode_ptr += mc_size; | 910 | ucode_ptr += mc_size; |
| @@ -932,7 +934,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, | |||
| 932 | pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n", | 934 | pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n", |
| 933 | cpu, new_rev, uci->cpu_sig.rev); | 935 | cpu, new_rev, uci->cpu_sig.rev); |
| 934 | 936 | ||
| 935 | return UCODE_OK; | 937 | return ret; |
| 936 | } | 938 | } |
| 937 | 939 | ||
| 938 | static int get_ucode_fw(void *to, const void *from, size_t n) | 940 | static int get_ucode_fw(void *to, const void *from, size_t n) |
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index 5edb27f1a2c4..9d0b5af7db91 100644 --- a/arch/x86/kernel/vm86_32.c +++ b/arch/x86/kernel/vm86_32.c | |||
| @@ -727,7 +727,8 @@ void handle_vm86_fault(struct kernel_vm86_regs *regs, long error_code) | |||
| 727 | return; | 727 | return; |
| 728 | 728 | ||
| 729 | check_vip: | 729 | check_vip: |
| 730 | if (VEFLAGS & X86_EFLAGS_VIP) { | 730 | if ((VEFLAGS & (X86_EFLAGS_VIP | X86_EFLAGS_VIF)) == |
| 731 | (X86_EFLAGS_VIP | X86_EFLAGS_VIF)) { | ||
| 731 | save_v86_state(regs, VM86_STI); | 732 | save_v86_state(regs, VM86_STI); |
| 732 | return; | 733 | return; |
| 733 | } | 734 | } |
diff --git a/kernel/jump_label.c b/kernel/jump_label.c index 52a0a7af8640..e7214093dcd1 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c | |||
| @@ -373,7 +373,8 @@ static void __jump_label_update(struct static_key *key, | |||
| 373 | if (kernel_text_address(entry->code)) | 373 | if (kernel_text_address(entry->code)) |
| 374 | arch_jump_label_transform(entry, jump_label_type(entry)); | 374 | arch_jump_label_transform(entry, jump_label_type(entry)); |
| 375 | else | 375 | else |
| 376 | WARN_ONCE(1, "can't patch jump_label at %pS", (void *)entry->code); | 376 | WARN_ONCE(1, "can't patch jump_label at %pS", |
| 377 | (void *)(unsigned long)entry->code); | ||
| 377 | } | 378 | } |
| 378 | } | 379 | } |
| 379 | } | 380 | } |
diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c index 361466a2eaef..ade443a88421 100644 --- a/tools/testing/selftests/x86/entry_from_vm86.c +++ b/tools/testing/selftests/x86/entry_from_vm86.c | |||
| @@ -95,6 +95,10 @@ 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_popf_hlt:\n\t" | ||
| 99 | "push %ax\n\t" | ||
| 100 | "popf\n\t" | ||
| 101 | "hlt\n\t" | ||
| 98 | "vmcode_umip:\n\t" | 102 | "vmcode_umip:\n\t" |
| 99 | /* addressing via displacements */ | 103 | /* addressing via displacements */ |
| 100 | "smsw (2052)\n\t" | 104 | "smsw (2052)\n\t" |
| @@ -124,8 +128,8 @@ asm ( | |||
| 124 | 128 | ||
| 125 | extern unsigned char vmcode[], end_vmcode[]; | 129 | extern unsigned char vmcode[], end_vmcode[]; |
| 126 | extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[], | 130 | extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[], |
| 127 | vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_umip[], | 131 | vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_popf_hlt[], |
| 128 | vmcode_umip_str[], vmcode_umip_sldt[]; | 132 | vmcode_umip[], vmcode_umip_str[], vmcode_umip_sldt[]; |
| 129 | 133 | ||
| 130 | /* Returns false if the test was skipped. */ | 134 | /* Returns false if the test was skipped. */ |
| 131 | static bool do_test(struct vm86plus_struct *v86, unsigned long eip, | 135 | static bool do_test(struct vm86plus_struct *v86, unsigned long eip, |
| @@ -175,7 +179,7 @@ static bool do_test(struct vm86plus_struct *v86, unsigned long eip, | |||
| 175 | (VM86_TYPE(ret) == rettype && VM86_ARG(ret) == retarg)) { | 179 | (VM86_TYPE(ret) == rettype && VM86_ARG(ret) == retarg)) { |
| 176 | printf("[OK]\tReturned correctly\n"); | 180 | printf("[OK]\tReturned correctly\n"); |
| 177 | } else { | 181 | } else { |
| 178 | printf("[FAIL]\tIncorrect return reason\n"); | 182 | printf("[FAIL]\tIncorrect return reason (started at eip = 0x%lx, ended at eip = 0x%lx)\n", eip, v86->regs.eip); |
| 179 | nerrs++; | 183 | nerrs++; |
| 180 | } | 184 | } |
| 181 | 185 | ||
| @@ -264,6 +268,9 @@ int main(void) | |||
| 264 | v86.regs.ds = load_addr / 16; | 268 | v86.regs.ds = load_addr / 16; |
| 265 | v86.regs.es = load_addr / 16; | 269 | v86.regs.es = load_addr / 16; |
| 266 | 270 | ||
| 271 | /* Use the end of the page as our stack. */ | ||
| 272 | v86.regs.esp = 4096; | ||
| 273 | |||
| 267 | assert((v86.regs.cs & 3) == 0); /* Looks like RPL = 0 */ | 274 | assert((v86.regs.cs & 3) == 0); /* Looks like RPL = 0 */ |
| 268 | 275 | ||
| 269 | /* #BR -- should deliver SIG??? */ | 276 | /* #BR -- should deliver SIG??? */ |
| @@ -295,6 +302,23 @@ int main(void) | |||
| 295 | v86.regs.eflags &= ~X86_EFLAGS_IF; | 302 | v86.regs.eflags &= ~X86_EFLAGS_IF; |
| 296 | do_test(&v86, vmcode_sti - vmcode, VM86_STI, 0, "STI with VIP set"); | 303 | do_test(&v86, vmcode_sti - vmcode, VM86_STI, 0, "STI with VIP set"); |
| 297 | 304 | ||
| 305 | /* POPF with VIP set but IF clear: should not trap */ | ||
| 306 | v86.regs.eflags = X86_EFLAGS_VIP; | ||
| 307 | v86.regs.eax = 0; | ||
| 308 | do_test(&v86, vmcode_popf_hlt - vmcode, VM86_UNKNOWN, 0, "POPF with VIP set and IF clear"); | ||
| 309 | |||
| 310 | /* POPF with VIP set and IF set: should trap */ | ||
| 311 | v86.regs.eflags = X86_EFLAGS_VIP; | ||
| 312 | v86.regs.eax = X86_EFLAGS_IF; | ||
| 313 | do_test(&v86, vmcode_popf_hlt - vmcode, VM86_STI, 0, "POPF with VIP and IF set"); | ||
| 314 | |||
| 315 | /* POPF with VIP clear and IF set: should not trap */ | ||
| 316 | v86.regs.eflags = 0; | ||
| 317 | v86.regs.eax = X86_EFLAGS_IF; | ||
| 318 | do_test(&v86, vmcode_popf_hlt - vmcode, VM86_UNKNOWN, 0, "POPF with VIP clear and IF set"); | ||
| 319 | |||
| 320 | v86.regs.eflags = 0; | ||
| 321 | |||
| 298 | /* INT3 -- should cause #BP */ | 322 | /* INT3 -- should cause #BP */ |
| 299 | do_test(&v86, vmcode_int3 - vmcode, VM86_TRAP, 3, "INT3"); | 323 | do_test(&v86, vmcode_int3 - vmcode, VM86_TRAP, 3, "INT3"); |
| 300 | 324 | ||
| @@ -318,7 +342,7 @@ int main(void) | |||
| 318 | clearhandler(SIGSEGV); | 342 | clearhandler(SIGSEGV); |
| 319 | 343 | ||
| 320 | /* Make sure nothing explodes if we fork. */ | 344 | /* Make sure nothing explodes if we fork. */ |
| 321 | if (fork() > 0) | 345 | if (fork() == 0) |
| 322 | return 0; | 346 | return 0; |
| 323 | 347 | ||
| 324 | return (nerrs == 0 ? 0 : 1); | 348 | return (nerrs == 0 ? 0 : 1); |
