Spaces:
Runtime error
Runtime error
File size: 2,689 Bytes
8df6da4 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
#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
);
|