1d21b4f12SGleb Natapov #include "libcflat.h" 2d21b4f12SGleb Natapov #include "desc.h" 3d21b4f12SGleb Natapov #include "apic-defs.h" 4d21b4f12SGleb Natapov #include "apic.h" 5d21b4f12SGleb Natapov #include "processor.h" 6*ce71ddc7SGleb Natapov #include "vm.h" 7d21b4f12SGleb Natapov 8d21b4f12SGleb Natapov #define xstr(s) str(s) 9d21b4f12SGleb Natapov #define str(s) #s 10d21b4f12SGleb Natapov 11d21b4f12SGleb Natapov static volatile int test_count; 12d21b4f12SGleb Natapov static volatile unsigned int test_divider; 13d21b4f12SGleb Natapov 14*ce71ddc7SGleb Natapov static char *fault_addr; 15*ce71ddc7SGleb Natapov static ulong fault_phys; 16*ce71ddc7SGleb Natapov 17d21b4f12SGleb Natapov static int g_fail; 18d21b4f12SGleb Natapov static int g_tests; 19d21b4f12SGleb Natapov 20d21b4f12SGleb Natapov static inline void io_delay(void) 21d21b4f12SGleb Natapov { 22d21b4f12SGleb Natapov } 23d21b4f12SGleb Natapov 24d21b4f12SGleb Natapov static void report(const char *msg, int pass) 25d21b4f12SGleb Natapov { 26d21b4f12SGleb Natapov ++g_tests; 27d21b4f12SGleb Natapov printf("%s: %s\n", msg, (pass ? "PASS" : "FAIL")); 28d21b4f12SGleb Natapov if (!pass) 29d21b4f12SGleb Natapov ++g_fail; 30d21b4f12SGleb Natapov } 31d21b4f12SGleb Natapov 32d21b4f12SGleb Natapov static void nmi_tss(void) 33d21b4f12SGleb Natapov { 34d21b4f12SGleb Natapov start: 35d21b4f12SGleb Natapov printf("NMI task is running\n"); 36d21b4f12SGleb Natapov print_current_tss_info(); 37d21b4f12SGleb Natapov test_count++; 38d21b4f12SGleb Natapov asm volatile ("iret"); 39d21b4f12SGleb Natapov goto start; 40d21b4f12SGleb Natapov } 41d21b4f12SGleb Natapov 42d21b4f12SGleb Natapov static void de_tss(void) 43d21b4f12SGleb Natapov { 44d21b4f12SGleb Natapov start: 45d21b4f12SGleb Natapov printf("DE task is running\n"); 46d21b4f12SGleb Natapov print_current_tss_info(); 47d21b4f12SGleb Natapov test_divider = 10; 48d21b4f12SGleb Natapov test_count++; 49d21b4f12SGleb Natapov asm volatile ("iret"); 50d21b4f12SGleb Natapov goto start; 51d21b4f12SGleb Natapov } 52d21b4f12SGleb Natapov 53d21b4f12SGleb Natapov static void of_tss(void) 54d21b4f12SGleb Natapov { 55d21b4f12SGleb Natapov start: 56d21b4f12SGleb Natapov printf("OF task is running\n"); 57d21b4f12SGleb Natapov print_current_tss_info(); 58d21b4f12SGleb Natapov test_count++; 59d21b4f12SGleb Natapov asm volatile ("iret"); 60d21b4f12SGleb Natapov goto start; 61d21b4f12SGleb Natapov } 62d21b4f12SGleb Natapov 63d21b4f12SGleb Natapov static void bp_tss(void) 64d21b4f12SGleb Natapov { 65d21b4f12SGleb Natapov start: 66d21b4f12SGleb Natapov printf("BP task is running\n"); 67d21b4f12SGleb Natapov print_current_tss_info(); 68d21b4f12SGleb Natapov test_count++; 69d21b4f12SGleb Natapov asm volatile ("iret"); 70d21b4f12SGleb Natapov goto start; 71d21b4f12SGleb Natapov } 72d21b4f12SGleb Natapov 73*ce71ddc7SGleb Natapov void do_pf_tss(ulong *error_code) 74*ce71ddc7SGleb Natapov { 75*ce71ddc7SGleb Natapov printf("PF task is running %x %x\n", error_code, *(ulong*)error_code); 76*ce71ddc7SGleb Natapov print_current_tss_info(); 77*ce71ddc7SGleb Natapov if (*(ulong*)error_code == 0x2) /* write access, not present */ 78*ce71ddc7SGleb Natapov test_count++; 79*ce71ddc7SGleb Natapov install_pte(phys_to_virt(read_cr3()), 1, fault_addr, 80*ce71ddc7SGleb Natapov fault_phys | PTE_PRESENT | PTE_WRITE, 0); 81*ce71ddc7SGleb Natapov } 82*ce71ddc7SGleb Natapov 83*ce71ddc7SGleb Natapov extern void pf_tss(void); 84*ce71ddc7SGleb Natapov 85*ce71ddc7SGleb Natapov asm ( 86*ce71ddc7SGleb Natapov "pf_tss: \n\t" 87*ce71ddc7SGleb Natapov "push %esp \n\t" 88*ce71ddc7SGleb Natapov "call do_pf_tss \n\t" 89*ce71ddc7SGleb Natapov "add $4, %esp \n\t" 90*ce71ddc7SGleb Natapov "iret\n\t" 91*ce71ddc7SGleb Natapov "jmp pf_tss\n\t" 92*ce71ddc7SGleb Natapov ); 93*ce71ddc7SGleb Natapov 94d21b4f12SGleb Natapov static void jmp_tss(void) 95d21b4f12SGleb Natapov { 96d21b4f12SGleb Natapov start: 97d21b4f12SGleb Natapov printf("JMP to task succeeded\n"); 98d21b4f12SGleb Natapov print_current_tss_info(); 99d21b4f12SGleb Natapov test_count++; 100d21b4f12SGleb Natapov asm volatile ("ljmp $" xstr(TSS_MAIN) ", $0"); 101d21b4f12SGleb Natapov goto start; 102d21b4f12SGleb Natapov } 103d21b4f12SGleb Natapov 104d21b4f12SGleb Natapov static void irq_tss(void) 105d21b4f12SGleb Natapov { 106d21b4f12SGleb Natapov start: 107d21b4f12SGleb Natapov printf("IRQ task is running\n"); 108d21b4f12SGleb Natapov print_current_tss_info(); 109d21b4f12SGleb Natapov test_count++; 110d21b4f12SGleb Natapov asm volatile ("iret"); 111d21b4f12SGleb Natapov test_count++; 112d21b4f12SGleb Natapov printf("IRQ task restarts after iret.\n"); 113d21b4f12SGleb Natapov goto start; 114d21b4f12SGleb Natapov } 115d21b4f12SGleb Natapov 116d21b4f12SGleb Natapov int main() 117d21b4f12SGleb Natapov { 118d21b4f12SGleb Natapov unsigned int res; 119d21b4f12SGleb Natapov 120*ce71ddc7SGleb Natapov setup_vm(); 121d21b4f12SGleb Natapov setup_idt(); 122d21b4f12SGleb Natapov setup_gdt(); 123d21b4f12SGleb Natapov setup_tss32(); 124d21b4f12SGleb Natapov 125d21b4f12SGleb Natapov /* test that int $2 triggers task gate */ 126d21b4f12SGleb Natapov test_count = 0; 127d21b4f12SGleb Natapov set_intr_task_gate(2, nmi_tss); 128d21b4f12SGleb Natapov printf("Triggering nmi 2\n"); 129d21b4f12SGleb Natapov asm volatile ("int $2"); 130d21b4f12SGleb Natapov printf("Return from nmi %d\n", test_count); 131d21b4f12SGleb Natapov report("NMI int $2", test_count == 1); 132d21b4f12SGleb Natapov 133d21b4f12SGleb Natapov /* test that external NMI triggers task gate */ 134d21b4f12SGleb Natapov test_count = 0; 135d21b4f12SGleb Natapov set_intr_task_gate(2, nmi_tss); 136d21b4f12SGleb Natapov printf("Triggering nmi through APIC\n"); 137d21b4f12SGleb Natapov apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0); 138d21b4f12SGleb Natapov io_delay(); 139d21b4f12SGleb Natapov printf("Return from APIC nmi\n"); 140d21b4f12SGleb Natapov report("NMI external", test_count == 1); 141d21b4f12SGleb Natapov 142d21b4f12SGleb Natapov /* test that external interrupt triggesr task gate */ 143d21b4f12SGleb Natapov test_count = 0; 144d21b4f12SGleb Natapov printf("Trigger IRQ from APIC\n"); 145d21b4f12SGleb Natapov set_intr_task_gate(0xf0, irq_tss); 146d21b4f12SGleb Natapov irq_enable(); 147d21b4f12SGleb Natapov apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT | 0xf0, 0); 148d21b4f12SGleb Natapov io_delay(); 149d21b4f12SGleb Natapov irq_disable(); 150d21b4f12SGleb Natapov printf("Return from APIC IRQ\n"); 151d21b4f12SGleb Natapov report("IRQ external", test_count == 1); 152d21b4f12SGleb Natapov 153d21b4f12SGleb Natapov /* test that HW exception triggesr task gate */ 154d21b4f12SGleb Natapov set_intr_task_gate(0, de_tss); 155d21b4f12SGleb Natapov printf("Try to devide by 0\n"); 156d21b4f12SGleb Natapov asm volatile ("divl %3": "=a"(res) 157d21b4f12SGleb Natapov : "d"(0), "a"(1500), "m"(test_divider)); 158d21b4f12SGleb Natapov printf("Result is %d\n", res); 159d21b4f12SGleb Natapov report("DE exeption", res == 150); 160d21b4f12SGleb Natapov 161d21b4f12SGleb Natapov /* test if call HW exeption DE by int $0 triggers task gate */ 162d21b4f12SGleb Natapov test_count = 0; 163d21b4f12SGleb Natapov set_intr_task_gate(0, de_tss); 164d21b4f12SGleb Natapov printf("Call int 0\n"); 165d21b4f12SGleb Natapov asm volatile ("int $0"); 166d21b4f12SGleb Natapov printf("Return from int 0\n"); 167d21b4f12SGleb Natapov report("int $0", test_count == 1); 168d21b4f12SGleb Natapov 169d21b4f12SGleb Natapov /* test if HW exception OF triggers task gate */ 170d21b4f12SGleb Natapov test_count = 0; 171d21b4f12SGleb Natapov set_intr_task_gate(4, of_tss); 172d21b4f12SGleb Natapov printf("Call into\n"); 173d21b4f12SGleb Natapov asm volatile ("addb $127, %b0\ninto"::"a"(127)); 174d21b4f12SGleb Natapov printf("Return from into\n"); 175d21b4f12SGleb Natapov report("OF exeption", test_count); 176d21b4f12SGleb Natapov 177d21b4f12SGleb Natapov /* test if HW exception BP triggers task gate */ 178d21b4f12SGleb Natapov test_count = 0; 179d21b4f12SGleb Natapov set_intr_task_gate(3, bp_tss); 180d21b4f12SGleb Natapov printf("Call int 3\n"); 181d21b4f12SGleb Natapov asm volatile ("int $3"); 182d21b4f12SGleb Natapov printf("Return from int 3\n"); 183d21b4f12SGleb Natapov report("BP exeption", test_count == 1); 184d21b4f12SGleb Natapov 185*ce71ddc7SGleb Natapov /* 186*ce71ddc7SGleb Natapov * test that PF triggers task gate and error code is placed on 187*ce71ddc7SGleb Natapov * exception task's stack 188*ce71ddc7SGleb Natapov */ 189*ce71ddc7SGleb Natapov fault_addr = alloc_vpage(); 190*ce71ddc7SGleb Natapov fault_phys = (ulong)virt_to_phys(alloc_page()); 191*ce71ddc7SGleb Natapov test_count = 0; 192*ce71ddc7SGleb Natapov set_intr_task_gate(14, pf_tss); 193*ce71ddc7SGleb Natapov printf("Access unmapped page\n"); 194*ce71ddc7SGleb Natapov *fault_addr = 0; 195*ce71ddc7SGleb Natapov printf("Return from pf tss\n"); 196*ce71ddc7SGleb Natapov report("PF exeption", test_count == 1); 197*ce71ddc7SGleb Natapov 198d21b4f12SGleb Natapov /* test that calling a task by lcall works */ 199d21b4f12SGleb Natapov test_count = 0; 200d21b4f12SGleb Natapov set_intr_task_gate(0, irq_tss); 201d21b4f12SGleb Natapov printf("Calling task by lcall\n"); 202d21b4f12SGleb Natapov /* hlt opcode is 0xf4 I use destination IP 0xf4f4f4f4 to catch 203d21b4f12SGleb Natapov incorrect instruction length calculation */ 204d21b4f12SGleb Natapov asm volatile("lcall $" xstr(TSS_INTR) ", $0xf4f4f4f4"); 205d21b4f12SGleb Natapov printf("Return from call\n"); 206d21b4f12SGleb Natapov report("lcall", test_count == 1); 207d21b4f12SGleb Natapov 208d21b4f12SGleb Natapov /* call the same task again and check that it restarted after iret */ 209d21b4f12SGleb Natapov test_count = 0; 210d21b4f12SGleb Natapov asm volatile("lcall $" xstr(TSS_INTR) ", $0xf4f4f4f4"); 211d21b4f12SGleb Natapov report("lcall2", test_count == 2); 212d21b4f12SGleb Natapov 213d21b4f12SGleb Natapov /* test that calling a task by ljmp works */ 214d21b4f12SGleb Natapov test_count = 0; 215d21b4f12SGleb Natapov set_intr_task_gate(0, jmp_tss); 216d21b4f12SGleb Natapov printf("Jumping to a task by ljmp\n"); 217d21b4f12SGleb Natapov asm volatile ("ljmp $" xstr(TSS_INTR) ", $0xf4f4f4f4"); 218d21b4f12SGleb Natapov printf("Jump back succeeded\n"); 219d21b4f12SGleb Natapov report("ljmp", test_count == 1); 220d21b4f12SGleb Natapov 221d21b4f12SGleb Natapov printf("\nsummary: %d tests, %d failures\n", g_tests, g_fail); 222d21b4f12SGleb Natapov 223d21b4f12SGleb Natapov return g_fail != 0; 224d21b4f12SGleb Natapov } 225