xref: /kvm-unit-tests/x86/init.c (revision 55601383cca6221889c5641e4bf6cfdbb855b213)
122238c82SPaolo Bonzini #include "libcflat.h"
222238c82SPaolo Bonzini #include "apic.h"
3*55601383SAlexander Gordeev #include "asm/io.h"
422238c82SPaolo Bonzini 
522238c82SPaolo Bonzini #define KBD_CCMD_READ_OUTPORT   0xD0    /* read output port */
622238c82SPaolo Bonzini #define KBD_CCMD_WRITE_OUTPORT  0xD1    /* write output port */
722238c82SPaolo Bonzini #define KBD_CCMD_RESET          0xFE    /* CPU reset */
822238c82SPaolo Bonzini 
kbd_cmd(u8 val)922238c82SPaolo Bonzini static inline void kbd_cmd(u8 val)
1022238c82SPaolo Bonzini {
1122238c82SPaolo Bonzini     while (inb(0x64) & 2);
1222238c82SPaolo Bonzini     outb(val, 0x64);
1322238c82SPaolo Bonzini }
1422238c82SPaolo Bonzini 
kbd_in(void)1522238c82SPaolo Bonzini static inline u8 kbd_in(void)
1622238c82SPaolo Bonzini {
1722238c82SPaolo Bonzini     kbd_cmd(KBD_CCMD_READ_OUTPORT);
1822238c82SPaolo Bonzini     while (inb(0x64) & 2);
1922238c82SPaolo Bonzini     return inb(0x60);
2022238c82SPaolo Bonzini }
2122238c82SPaolo Bonzini 
kbd_out(u8 val)2222238c82SPaolo Bonzini static inline void kbd_out(u8 val)
2322238c82SPaolo Bonzini {
2422238c82SPaolo Bonzini     kbd_cmd(KBD_CCMD_WRITE_OUTPORT);
2522238c82SPaolo Bonzini     while (inb(0x64) & 2);
2622238c82SPaolo Bonzini     outb(val, 0x60);
2722238c82SPaolo Bonzini }
2822238c82SPaolo Bonzini 
rtc_out(u8 reg,u8 val)2922238c82SPaolo Bonzini static inline void rtc_out(u8 reg, u8 val)
3022238c82SPaolo Bonzini {
3122238c82SPaolo Bonzini     outb(reg, 0x70);
3222238c82SPaolo Bonzini     outb(val, 0x71);
3322238c82SPaolo Bonzini }
3422238c82SPaolo Bonzini 
3522238c82SPaolo Bonzini extern char resume_start, resume_end;
3622238c82SPaolo Bonzini 
3722238c82SPaolo Bonzini #define state (*(volatile int *)0x2000)
3822238c82SPaolo Bonzini #define bad (*(volatile int *)0x2004)
3922238c82SPaolo Bonzini #define resumed (*(volatile int *)0x2008)
4022238c82SPaolo Bonzini 
main(int argc,char ** argv)4122238c82SPaolo Bonzini int main(int argc, char **argv)
4222238c82SPaolo Bonzini {
4322238c82SPaolo Bonzini 	volatile u16 *resume_vector_ptr = (u16 *)0x467L;
4422238c82SPaolo Bonzini 	char *addr, *resume_vec = (void*)0x1000;
4522238c82SPaolo Bonzini 
4622238c82SPaolo Bonzini 	/* resume execution by indirect jump via 40h:0067h */
4722238c82SPaolo Bonzini 	rtc_out(0x0f, 0x0a);
4822238c82SPaolo Bonzini 	resume_vector_ptr[0] = ((u32)(ulong)resume_vec);
4922238c82SPaolo Bonzini 	resume_vector_ptr[1] = 0;
5022238c82SPaolo Bonzini 
5122238c82SPaolo Bonzini 	for (addr = &resume_start; addr < &resume_end; addr++)
5222238c82SPaolo Bonzini 		*resume_vec++ = *addr;
5322238c82SPaolo Bonzini 
5422238c82SPaolo Bonzini 	if (state != 0) {
5522238c82SPaolo Bonzini 		/*
5622238c82SPaolo Bonzini 		 * Strictly speaking this is a firmware problem, but let's check
5722238c82SPaolo Bonzini 		 * for it as well...
5822238c82SPaolo Bonzini 		 */
5922238c82SPaolo Bonzini 		if (resumed != 1) {
6022238c82SPaolo Bonzini 			printf("Uh, resume vector visited %d times?\n", resumed);
6122238c82SPaolo Bonzini 			bad |= 2;
6222238c82SPaolo Bonzini 		}
6322238c82SPaolo Bonzini 		/*
6422238c82SPaolo Bonzini 		 * Port 92 bit 0 is cleared on system reset.  On a soft reset it
6522238c82SPaolo Bonzini 		 * is left to 1.  Use this to distinguish INIT from hard reset.
6622238c82SPaolo Bonzini 		 */
6722238c82SPaolo Bonzini 		if (resumed != 0 && (inb(0x92) & 1) == 0) {
6822238c82SPaolo Bonzini 			printf("Uh, hard reset!\n");
6922238c82SPaolo Bonzini 			bad |= 1;
7022238c82SPaolo Bonzini 		}
7122238c82SPaolo Bonzini 	}
7222238c82SPaolo Bonzini 
7322238c82SPaolo Bonzini 	resumed = 0;
7422238c82SPaolo Bonzini 
7522238c82SPaolo Bonzini 	switch (state++) {
7622238c82SPaolo Bonzini 	case 0:
7722238c82SPaolo Bonzini 		printf("testing port 92 init... ");
7822238c82SPaolo Bonzini 		outb(inb(0x92) & ~1, 0x92);
7922238c82SPaolo Bonzini 		outb(inb(0x92) | 1, 0x92);
8022238c82SPaolo Bonzini 		break;
8122238c82SPaolo Bonzini 
8222238c82SPaolo Bonzini 	case 1:
8322238c82SPaolo Bonzini 		printf("testing kbd controller reset... ");
8422238c82SPaolo Bonzini 		kbd_cmd(KBD_CCMD_RESET);
8522238c82SPaolo Bonzini 		break;
8622238c82SPaolo Bonzini 
8722238c82SPaolo Bonzini 	case 2:
8822238c82SPaolo Bonzini 		printf("testing kbd controller init... ");
8922238c82SPaolo Bonzini 		kbd_out(kbd_in() & ~1);
9022238c82SPaolo Bonzini 		break;
9122238c82SPaolo Bonzini 
9222238c82SPaolo Bonzini 	case 3:
9322238c82SPaolo Bonzini 		printf("testing 0xcf9h init... ");
9422238c82SPaolo Bonzini 		outb(0, 0xcf9);
9522238c82SPaolo Bonzini 		outb(4, 0xcf9);
9622238c82SPaolo Bonzini 		break;
9722238c82SPaolo Bonzini 
9822238c82SPaolo Bonzini 	case 4:
9922238c82SPaolo Bonzini 		printf("testing init to BSP... ");
10022238c82SPaolo Bonzini 		apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL
10122238c82SPaolo Bonzini 			      | APIC_DM_INIT, 0);
10222238c82SPaolo Bonzini 		break;
10322238c82SPaolo Bonzini 
10422238c82SPaolo Bonzini 	case 5:
10522238c82SPaolo Bonzini 		exit(bad);
10622238c82SPaolo Bonzini 	}
10722238c82SPaolo Bonzini 
10822238c82SPaolo Bonzini 	/* The resume code will get us back to main.  */
10922238c82SPaolo Bonzini 	asm("cli; hlt");
1106e74d079SJan Kiszka 	__builtin_unreachable();
11122238c82SPaolo Bonzini }
11222238c82SPaolo Bonzini 
11322238c82SPaolo Bonzini asm (
11422238c82SPaolo Bonzini 	".global resume_start\n"
11522238c82SPaolo Bonzini 	".global resume_end\n"
11622238c82SPaolo Bonzini 	".code16\n"
11722238c82SPaolo Bonzini 	"resume_start:\n"
11822238c82SPaolo Bonzini 	"incb %cs:0x2008\n"		// resumed++;
11922238c82SPaolo Bonzini 	"mov $0x0f, %al\n"		// rtc_out(0x0f, 0x00);
12022238c82SPaolo Bonzini 	"out %al, $0x70\n"
12122238c82SPaolo Bonzini 	"mov $0x00, %al\n"
12222238c82SPaolo Bonzini 	"out %al, $0x71\n"
12322238c82SPaolo Bonzini 	"jmp $0xffff, $0x0000\n"	// BIOS reset
12422238c82SPaolo Bonzini 	"resume_end:\n"
12522238c82SPaolo Bonzini #ifdef __i386__
12622238c82SPaolo Bonzini 	".code32\n"
12722238c82SPaolo Bonzini #else
12822238c82SPaolo Bonzini 	".code64\n"
12922238c82SPaolo Bonzini #endif
13022238c82SPaolo Bonzini     );
131