| #include "libcflat.h" | |
| #include "acpi.h" | |
| #include "asm/io.h" | |
| #define RTC_SECONDS_ALARM 1 | |
| #define RTC_MINUTES_ALARM 3 | |
| #define RTC_HOURS_ALARM 5 | |
| #define RTC_ALARM_DONT_CARE 0xC0 | |
| #define RTC_REG_A 10 | |
| #define RTC_REG_B 11 | |
| #define RTC_REG_C 12 | |
| #define REG_A_UIP 0x80 | |
| #define REG_B_AIE 0x20 | |
| static inline int rtc_in(u8 reg) | |
| { | |
| outb(reg, 0x70); | |
| return inb(0x71); | |
| } | |
| static inline void rtc_out(u8 reg, u8 val) | |
| { | |
| outb(reg, 0x70); | |
| outb(val, 0x71); | |
| } | |
| extern char resume_start, resume_end; | |
| int main(int argc, char **argv) | |
| { | |
| struct acpi_table_facs_rev1 *facs = find_acpi_table_addr(FACS_SIGNATURE); | |
| struct acpi_table_fadt *fadt = find_acpi_table_addr(FACP_SIGNATURE); | |
| char *addr, *resume_vec = (void*)0x1000; | |
| assert(facs); | |
| facs->firmware_waking_vector = (u32)(ulong)resume_vec; | |
| printf("FACS is at %p\n", facs); | |
| printf("resume vector addr is %p\n", &facs->firmware_waking_vector); | |
| for (addr = &resume_start; addr < &resume_end; addr++) | |
| *resume_vec++ = *addr; | |
| printf("copy resume code from %p\n", &resume_start); | |
| printf("PM1a event registers at %" PRIx32 "\n", fadt->pm1a_evt_blk); | |
| outw(0x400, fadt->pm1a_evt_blk + 2); | |
| /* Setup RTC alarm to wake up on the next second. */ | |
| while ((rtc_in(RTC_REG_A) & REG_A_UIP) == 0); | |
| while ((rtc_in(RTC_REG_A) & REG_A_UIP) != 0); | |
| rtc_in(RTC_REG_C); | |
| rtc_out(RTC_SECONDS_ALARM, RTC_ALARM_DONT_CARE); | |
| rtc_out(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE); | |
| rtc_out(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE); | |
| rtc_out(RTC_REG_B, rtc_in(RTC_REG_B) | REG_B_AIE); | |
| *(volatile int*)0 = 0; | |
| asm volatile("outw %0, %1" :: "a"((short)0x2400), "d"((short)fadt->pm1a_cnt_blk):"memory"); | |
| while(1) | |
| *(volatile int*)0 = 1; | |
| return 0; | |
| } | |
| asm ( | |
| ".global resume_start\n" | |
| ".global resume_end\n" | |
| ".code16\n" | |
| "resume_start:\n" | |
| "mov 0x0, %eax\n" | |
| "mov $0xf4, %dx\n" | |
| "out %eax, %dx\n" | |
| "1: hlt\n" | |
| "jmp 1b\n" | |
| "resume_end:\n" | |
| #ifdef __i386__ | |
| ".code32\n" | |
| #else | |
| ".code64\n" | |
| #endif | |
| ); |