|
27 | 27 | #include <asm/vm86.h> /* struct vm86 */
|
28 | 28 | #include <asm/mmu_context.h> /* vma_pkey() */
|
29 | 29 | #include <asm/efi.h> /* efi_recover_from_page_fault()*/
|
| 30 | +#include <asm/desc.h> /* store_idt(), ... */ |
30 | 31 |
|
31 | 32 | #define CREATE_TRACE_POINTS
|
32 | 33 | #include <asm/trace/exceptions.h>
|
@@ -571,10 +572,53 @@ static int is_f00f_bug(struct pt_regs *regs, unsigned long address)
|
571 | 572 | return 0;
|
572 | 573 | }
|
573 | 574 |
|
| 575 | +static void show_ldttss(const struct desc_ptr *gdt, const char *name, u16 index) |
| 576 | +{ |
| 577 | + u32 offset = (index >> 3) * sizeof(struct desc_struct); |
| 578 | + unsigned long addr; |
| 579 | + struct ldttss_desc desc; |
| 580 | + |
| 581 | + if (index == 0) { |
| 582 | + pr_alert("%s: NULL\n", name); |
| 583 | + return; |
| 584 | + } |
| 585 | + |
| 586 | + if (offset + sizeof(struct ldttss_desc) >= gdt->size) { |
| 587 | + pr_alert("%s: 0x%hx -- out of bounds\n", name, index); |
| 588 | + return; |
| 589 | + } |
| 590 | + |
| 591 | + if (probe_kernel_read(&desc, (void *)(gdt->address + offset), |
| 592 | + sizeof(struct ldttss_desc))) { |
| 593 | + pr_alert("%s: 0x%hx -- GDT entry is not readable\n", |
| 594 | + name, index); |
| 595 | + return; |
| 596 | + } |
| 597 | + |
| 598 | + addr = desc.base0 | (desc.base1 << 16) | (desc.base2 << 24); |
| 599 | +#ifdef CONFIG_X86_64 |
| 600 | + addr |= ((u64)desc.base3 << 32); |
| 601 | +#endif |
| 602 | + pr_alert("%s: 0x%hx -- base=0x%lx limit=0x%x\n", |
| 603 | + name, index, addr, (desc.limit0 | (desc.limit1 << 16))); |
| 604 | +} |
| 605 | + |
| 606 | +static void errstr(unsigned long ec, char *buf, unsigned long mask, |
| 607 | + const char *txt) |
| 608 | +{ |
| 609 | + if (ec & mask) { |
| 610 | + if (buf[0]) |
| 611 | + strcat(buf, " "); |
| 612 | + strcat(buf, txt); |
| 613 | + } |
| 614 | +} |
| 615 | + |
574 | 616 | static void
|
575 | 617 | show_fault_oops(struct pt_regs *regs, unsigned long error_code,
|
576 | 618 | unsigned long address)
|
577 | 619 | {
|
| 620 | + char errtxt[64]; |
| 621 | + |
578 | 622 | if (!oops_may_print())
|
579 | 623 | return;
|
580 | 624 |
|
@@ -602,6 +646,46 @@ show_fault_oops(struct pt_regs *regs, unsigned long error_code,
|
602 | 646 | address < PAGE_SIZE ? "NULL pointer dereference" : "paging request",
|
603 | 647 | (void *)address);
|
604 | 648 |
|
| 649 | + errtxt[0] = 0; |
| 650 | + errstr(error_code, errtxt, X86_PF_PROT, "PROT"); |
| 651 | + errstr(error_code, errtxt, X86_PF_WRITE, "WRITE"); |
| 652 | + errstr(error_code, errtxt, X86_PF_USER, "USER"); |
| 653 | + errstr(error_code, errtxt, X86_PF_RSVD, "RSVD"); |
| 654 | + errstr(error_code, errtxt, X86_PF_INSTR, "INSTR"); |
| 655 | + errstr(error_code, errtxt, X86_PF_PK, "PK"); |
| 656 | + pr_alert("HW error: %s\n", error_code ? errtxt : |
| 657 | + "normal kernel read fault"); |
| 658 | + if (!(error_code & X86_PF_USER) && user_mode(regs)) { |
| 659 | + struct desc_ptr idt, gdt; |
| 660 | + u16 ldtr, tr; |
| 661 | + |
| 662 | + pr_alert("This was a system access from user code\n"); |
| 663 | + |
| 664 | + /* |
| 665 | + * This can happen for quite a few reasons. The more obvious |
| 666 | + * ones are faults accessing the GDT, or LDT. Perhaps |
| 667 | + * surprisingly, if the CPU tries to deliver a benign or |
| 668 | + * contributory exception from user code and gets a page fault |
| 669 | + * during delivery, the page fault can be delivered as though |
| 670 | + * it originated directly from user code. This could happen |
| 671 | + * due to wrong permissions on the IDT, GDT, LDT, TSS, or |
| 672 | + * kernel or IST stack. |
| 673 | + */ |
| 674 | + store_idt(&idt); |
| 675 | + |
| 676 | + /* Usable even on Xen PV -- it's just slow. */ |
| 677 | + native_store_gdt(&gdt); |
| 678 | + |
| 679 | + pr_alert("IDT: 0x%lx (limit=0x%hx) GDT: 0x%lx (limit=0x%hx)\n", |
| 680 | + idt.address, idt.size, gdt.address, gdt.size); |
| 681 | + |
| 682 | + store_ldt(ldtr); |
| 683 | + show_ldttss(&gdt, "LDTR", ldtr); |
| 684 | + |
| 685 | + store_tr(tr); |
| 686 | + show_ldttss(&gdt, "TR", tr); |
| 687 | + } |
| 688 | + |
605 | 689 | dump_pagetable(address);
|
606 | 690 | }
|
607 | 691 |
|
|
0 commit comments