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