123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- #include "libcflat.h"
- #include "apic.h"
- #include "asm/io.h"
- #define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */
- #define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */
- #define KBD_CCMD_RESET 0xFE /* CPU reset */
- static inline void kbd_cmd(u8 val)
- {
- while (inb(0x64) & 2);
- outb(val, 0x64);
- }
- static inline u8 kbd_in(void)
- {
- kbd_cmd(KBD_CCMD_READ_OUTPORT);
- while (inb(0x64) & 2);
- return inb(0x60);
- }
- static inline void kbd_out(u8 val)
- {
- kbd_cmd(KBD_CCMD_WRITE_OUTPORT);
- while (inb(0x64) & 2);
- outb(val, 0x60);
- }
- static inline void rtc_out(u8 reg, u8 val)
- {
- outb(reg, 0x70);
- outb(val, 0x71);
- }
- extern char resume_start, resume_end;
- #define state (*(volatile int *)0x2000)
- #define bad (*(volatile int *)0x2004)
- #define resumed (*(volatile int *)0x2008)
- int main(int argc, char **argv)
- {
- volatile u16 *resume_vector_ptr = (u16 *)0x467L;
- char *addr, *resume_vec = (void*)0x1000;
- /* resume execution by indirect jump via 40h:0067h */
- rtc_out(0x0f, 0x0a);
- resume_vector_ptr[0] = ((u32)(ulong)resume_vec);
- resume_vector_ptr[1] = 0;
- for (addr = &resume_start; addr < &resume_end; addr++)
- *resume_vec++ = *addr;
- if (state != 0) {
- /*
- * Strictly speaking this is a firmware problem, but let's check
- * for it as well...
- */
- if (resumed != 1) {
- printf("Uh, resume vector visited %d times?\n", resumed);
- bad |= 2;
- }
- /*
- * Port 92 bit 0 is cleared on system reset. On a soft reset it
- * is left to 1. Use this to distinguish INIT from hard reset.
- */
- if (resumed != 0 && (inb(0x92) & 1) == 0) {
- printf("Uh, hard reset!\n");
- bad |= 1;
- }
- }
- resumed = 0;
- switch (state++) {
- case 0:
- printf("testing port 92 init... ");
- outb(inb(0x92) & ~1, 0x92);
- outb(inb(0x92) | 1, 0x92);
- break;
- case 1:
- printf("testing kbd controller reset... ");
- kbd_cmd(KBD_CCMD_RESET);
- break;
- case 2:
- printf("testing kbd controller init... ");
- kbd_out(kbd_in() & ~1);
- break;
- case 3:
- printf("testing 0xcf9h init... ");
- outb(0, 0xcf9);
- outb(4, 0xcf9);
- break;
- case 4:
- printf("testing init to BSP... ");
- apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL
- | APIC_DM_INIT, 0);
- break;
- case 5:
- exit(bad);
- }
- /* The resume code will get us back to main. */
- asm("cli; hlt");
- __builtin_unreachable();
- }
- asm (
- ".global resume_start\n"
- ".global resume_end\n"
- ".code16\n"
- "resume_start:\n"
- "incb %cs:0x2008\n" // resumed++;
- "mov $0x0f, %al\n" // rtc_out(0x0f, 0x00);
- "out %al, $0x70\n"
- "mov $0x00, %al\n"
- "out %al, $0x71\n"
- "jmp $0xffff, $0x0000\n" // BIOS reset
- "resume_end:\n"
- #ifdef __i386__
- ".code32\n"
- #else
- ".code64\n"
- #endif
- );
|