1 #include "libcflat.h" 2 #include "apic.h" 3 #include "asm/io.h" 4 5 #define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */ 6 #define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */ 7 #define KBD_CCMD_RESET 0xFE /* CPU reset */ 8 9 static inline void kbd_cmd(u8 val) 10 { 11 while (inb(0x64) & 2); 12 outb(val, 0x64); 13 } 14 15 static inline u8 kbd_in(void) 16 { 17 kbd_cmd(KBD_CCMD_READ_OUTPORT); 18 while (inb(0x64) & 2); 19 return inb(0x60); 20 } 21 22 static inline void kbd_out(u8 val) 23 { 24 kbd_cmd(KBD_CCMD_WRITE_OUTPORT); 25 while (inb(0x64) & 2); 26 outb(val, 0x60); 27 } 28 29 static inline void rtc_out(u8 reg, u8 val) 30 { 31 outb(reg, 0x70); 32 outb(val, 0x71); 33 } 34 35 extern char resume_start, resume_end; 36 37 #define state (*(volatile int *)0x2000) 38 #define bad (*(volatile int *)0x2004) 39 #define resumed (*(volatile int *)0x2008) 40 41 int main(int argc, char **argv) 42 { 43 volatile u16 *resume_vector_ptr = (u16 *)0x467L; 44 char *addr, *resume_vec = (void*)0x1000; 45 46 /* resume execution by indirect jump via 40h:0067h */ 47 rtc_out(0x0f, 0x0a); 48 resume_vector_ptr[0] = ((u32)(ulong)resume_vec); 49 resume_vector_ptr[1] = 0; 50 51 for (addr = &resume_start; addr < &resume_end; addr++) 52 *resume_vec++ = *addr; 53 54 if (state != 0) { 55 /* 56 * Strictly speaking this is a firmware problem, but let's check 57 * for it as well... 58 */ 59 if (resumed != 1) { 60 printf("Uh, resume vector visited %d times?\n", resumed); 61 bad |= 2; 62 } 63 /* 64 * Port 92 bit 0 is cleared on system reset. On a soft reset it 65 * is left to 1. Use this to distinguish INIT from hard reset. 66 */ 67 if (resumed != 0 && (inb(0x92) & 1) == 0) { 68 printf("Uh, hard reset!\n"); 69 bad |= 1; 70 } 71 } 72 73 resumed = 0; 74 75 switch (state++) { 76 case 0: 77 printf("testing port 92 init... "); 78 outb(inb(0x92) & ~1, 0x92); 79 outb(inb(0x92) | 1, 0x92); 80 break; 81 82 case 1: 83 printf("testing kbd controller reset... "); 84 kbd_cmd(KBD_CCMD_RESET); 85 break; 86 87 case 2: 88 printf("testing kbd controller init... "); 89 kbd_out(kbd_in() & ~1); 90 break; 91 92 case 3: 93 printf("testing 0xcf9h init... "); 94 outb(0, 0xcf9); 95 outb(4, 0xcf9); 96 break; 97 98 case 4: 99 printf("testing init to BSP... "); 100 apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL 101 | APIC_DM_INIT, 0); 102 break; 103 104 case 5: 105 exit(bad); 106 } 107 108 /* The resume code will get us back to main. */ 109 asm("cli; hlt"); 110 __builtin_unreachable(); 111 } 112 113 asm ( 114 ".global resume_start\n" 115 ".global resume_end\n" 116 ".code16\n" 117 "resume_start:\n" 118 "incb %cs:0x2008\n" // resumed++; 119 "mov $0x0f, %al\n" // rtc_out(0x0f, 0x00); 120 "out %al, $0x70\n" 121 "mov $0x00, %al\n" 122 "out %al, $0x71\n" 123 "jmp $0xffff, $0x0000\n" // BIOS reset 124 "resume_end:\n" 125 #ifdef __i386__ 126 ".code32\n" 127 #else 128 ".code64\n" 129 #endif 130 ); 131