1c1bc863aSGleb Natapov #include "libcflat.h" 2670b1f54SNikos Nikoleris #include "acpi.h" 347546cc7SPaolo Bonzini #include "asm/io.h" 4c1bc863aSGleb Natapov 5798b0d95SPaolo Bonzini #define RTC_SECONDS_ALARM 1 6798b0d95SPaolo Bonzini #define RTC_MINUTES_ALARM 3 7798b0d95SPaolo Bonzini #define RTC_HOURS_ALARM 5 8798b0d95SPaolo Bonzini #define RTC_ALARM_DONT_CARE 0xC0 9798b0d95SPaolo Bonzini 10798b0d95SPaolo Bonzini #define RTC_REG_A 10 11798b0d95SPaolo Bonzini #define RTC_REG_B 11 12798b0d95SPaolo Bonzini #define RTC_REG_C 12 13798b0d95SPaolo Bonzini 14798b0d95SPaolo Bonzini #define REG_A_UIP 0x80 15798b0d95SPaolo Bonzini #define REG_B_AIE 0x20 16798b0d95SPaolo Bonzini 17798b0d95SPaolo Bonzini static inline int rtc_in(u8 reg) 18798b0d95SPaolo Bonzini { 1947546cc7SPaolo Bonzini outb(reg, 0x70); 2047546cc7SPaolo Bonzini return inb(0x71); 21798b0d95SPaolo Bonzini } 22798b0d95SPaolo Bonzini 23798b0d95SPaolo Bonzini static inline void rtc_out(u8 reg, u8 val) 24798b0d95SPaolo Bonzini { 2547546cc7SPaolo Bonzini outb(reg, 0x70); 2647546cc7SPaolo Bonzini outb(val, 0x71); 27798b0d95SPaolo Bonzini } 28798b0d95SPaolo Bonzini 29c1bc863aSGleb Natapov extern char resume_start, resume_end; 30c1bc863aSGleb Natapov 31c1bc863aSGleb Natapov int main(int argc, char **argv) 32c1bc863aSGleb Natapov { 33169f786fSAlexandru Elisei struct acpi_table_fadt_rev1 *fadt = find_acpi_table_addr(FACP_SIGNATURE); 34*10cda508SNikos Nikoleris struct acpi_table_facs_rev1 *facs = find_acpi_table_addr(FACS_SIGNATURE); 35c1bc863aSGleb Natapov char *addr, *resume_vec = (void*)0x1000; 36c1bc863aSGleb Natapov 37*10cda508SNikos Nikoleris assert(facs); 38*10cda508SNikos Nikoleris facs->firmware_waking_vector = (u32)(ulong)resume_vec; 39c1bc863aSGleb Natapov 40*10cda508SNikos Nikoleris printf("FACS is at %p\n", facs); 41*10cda508SNikos Nikoleris printf("resume vector addr is %p\n", &facs->firmware_waking_vector); 42c1bc863aSGleb Natapov for (addr = &resume_start; addr < &resume_end; addr++) 43c1bc863aSGleb Natapov *resume_vec++ = *addr; 44b006d7ebSAndrew Jones printf("copy resume code from %p\n", &resume_start); 45798b0d95SPaolo Bonzini 46d26193a0SRoman Bolshakov printf("PM1a event registers at %" PRIx32 "\n", fadt->pm1a_evt_blk); 4747546cc7SPaolo Bonzini outw(0x400, fadt->pm1a_evt_blk + 2); 4847546cc7SPaolo Bonzini 49798b0d95SPaolo Bonzini /* Setup RTC alarm to wake up on the next second. */ 50798b0d95SPaolo Bonzini while ((rtc_in(RTC_REG_A) & REG_A_UIP) == 0); 51798b0d95SPaolo Bonzini while ((rtc_in(RTC_REG_A) & REG_A_UIP) != 0); 52798b0d95SPaolo Bonzini rtc_in(RTC_REG_C); 53798b0d95SPaolo Bonzini rtc_out(RTC_SECONDS_ALARM, RTC_ALARM_DONT_CARE); 54798b0d95SPaolo Bonzini rtc_out(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE); 55798b0d95SPaolo Bonzini rtc_out(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE); 56798b0d95SPaolo Bonzini rtc_out(RTC_REG_B, rtc_in(RTC_REG_B) | REG_B_AIE); 57798b0d95SPaolo Bonzini 58c1bc863aSGleb Natapov *(volatile int*)0 = 0; 59a5d12b9fSPaolo Bonzini asm volatile("outw %0, %1" :: "a"((short)0x2400), "d"((short)fadt->pm1a_cnt_blk):"memory"); 60c1bc863aSGleb Natapov while(1) 61c1bc863aSGleb Natapov *(volatile int*)0 = 1; 62c1bc863aSGleb Natapov 63c1bc863aSGleb Natapov return 0; 64c1bc863aSGleb Natapov } 65c1bc863aSGleb Natapov 66c1bc863aSGleb Natapov asm ( 67c1bc863aSGleb Natapov ".global resume_start\n" 68c1bc863aSGleb Natapov ".global resume_end\n" 69c1bc863aSGleb Natapov ".code16\n" 70c1bc863aSGleb Natapov "resume_start:\n" 71c1bc863aSGleb Natapov "mov 0x0, %eax\n" 72c1bc863aSGleb Natapov "mov $0xf4, %dx\n" 73c1bc863aSGleb Natapov "out %eax, %dx\n" 74c1bc863aSGleb Natapov "1: hlt\n" 75c1bc863aSGleb Natapov "jmp 1b\n" 76c1bc863aSGleb Natapov "resume_end:\n" 77c1bc863aSGleb Natapov #ifdef __i386__ 78c1bc863aSGleb Natapov ".code32\n" 79c1bc863aSGleb Natapov #else 80c1bc863aSGleb Natapov ".code64\n" 81c1bc863aSGleb Natapov #endif 82c1bc863aSGleb Natapov ); 83