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