1c1bc863aSGleb Natapov #include "libcflat.h" 2*a5d12b9fSPaolo Bonzini #include "x86/acpi.h" 3c1bc863aSGleb Natapov 4c1bc863aSGleb Natapov u32* find_resume_vector_addr(void) 5c1bc863aSGleb Natapov { 6372e3528SPaolo Bonzini struct facs_descriptor_rev1 *facs = find_acpi_table_addr(FACS_SIGNATURE); 7372e3528SPaolo Bonzini if (!facs) 8c1bc863aSGleb Natapov return 0; 9c1bc863aSGleb Natapov printf("FACS is at %x\n", facs); 10c1bc863aSGleb Natapov return &facs->firmware_waking_vector; 11c1bc863aSGleb Natapov } 12c1bc863aSGleb Natapov 13798b0d95SPaolo Bonzini #define RTC_SECONDS_ALARM 1 14798b0d95SPaolo Bonzini #define RTC_MINUTES_ALARM 3 15798b0d95SPaolo Bonzini #define RTC_HOURS_ALARM 5 16798b0d95SPaolo Bonzini #define RTC_ALARM_DONT_CARE 0xC0 17798b0d95SPaolo Bonzini 18798b0d95SPaolo Bonzini #define RTC_REG_A 10 19798b0d95SPaolo Bonzini #define RTC_REG_B 11 20798b0d95SPaolo Bonzini #define RTC_REG_C 12 21798b0d95SPaolo Bonzini 22798b0d95SPaolo Bonzini #define REG_A_UIP 0x80 23798b0d95SPaolo Bonzini #define REG_B_AIE 0x20 24798b0d95SPaolo Bonzini 25798b0d95SPaolo Bonzini static inline int rtc_in(u8 reg) 26798b0d95SPaolo Bonzini { 27798b0d95SPaolo Bonzini u8 x = reg; 28798b0d95SPaolo Bonzini asm volatile("outb %b1, $0x70; inb $0x71, %b0" 290b9e64c4SGleb Natapov : "=a"(x) : "0"(x)); 30798b0d95SPaolo Bonzini return x; 31798b0d95SPaolo Bonzini } 32798b0d95SPaolo Bonzini 33798b0d95SPaolo Bonzini static inline void rtc_out(u8 reg, u8 val) 34798b0d95SPaolo Bonzini { 35798b0d95SPaolo Bonzini asm volatile("outb %b1, $0x70; mov %b2, %b1; outb %b1, $0x71" 360b9e64c4SGleb Natapov : "=a"(reg) : "0"(reg), "ri"(val)); 37798b0d95SPaolo Bonzini } 38798b0d95SPaolo Bonzini 39c1bc863aSGleb Natapov extern char resume_start, resume_end; 40c1bc863aSGleb Natapov 41c1bc863aSGleb Natapov int main(int argc, char **argv) 42c1bc863aSGleb Natapov { 43*a5d12b9fSPaolo Bonzini struct fadt_descriptor_rev1 *fadt = find_acpi_table_addr(FACP_SIGNATURE); 44c1bc863aSGleb Natapov volatile u32 *resume_vector_ptr = find_resume_vector_addr(); 45c1bc863aSGleb Natapov char *addr, *resume_vec = (void*)0x1000; 46c1bc863aSGleb Natapov 47c1bc863aSGleb Natapov *resume_vector_ptr = (u32)(ulong)resume_vec; 48c1bc863aSGleb Natapov 49c1bc863aSGleb Natapov printf("resume vector addr is %x\n", resume_vector_ptr); 50c1bc863aSGleb Natapov for (addr = &resume_start; addr < &resume_end; addr++) 51c1bc863aSGleb Natapov *resume_vec++ = *addr; 52c1bc863aSGleb Natapov printf("copy resume code from %x\n", &resume_start); 53798b0d95SPaolo Bonzini 54798b0d95SPaolo Bonzini /* Setup RTC alarm to wake up on the next second. */ 55798b0d95SPaolo Bonzini while ((rtc_in(RTC_REG_A) & REG_A_UIP) == 0); 56798b0d95SPaolo Bonzini while ((rtc_in(RTC_REG_A) & REG_A_UIP) != 0); 57798b0d95SPaolo Bonzini rtc_in(RTC_REG_C); 58798b0d95SPaolo Bonzini rtc_out(RTC_SECONDS_ALARM, RTC_ALARM_DONT_CARE); 59798b0d95SPaolo Bonzini rtc_out(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE); 60798b0d95SPaolo Bonzini rtc_out(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE); 61798b0d95SPaolo Bonzini rtc_out(RTC_REG_B, rtc_in(RTC_REG_B) | REG_B_AIE); 62798b0d95SPaolo Bonzini 63c1bc863aSGleb Natapov *(volatile int*)0 = 0; 64*a5d12b9fSPaolo Bonzini asm volatile("outw %0, %1" :: "a"((short)0x2400), "d"((short)fadt->pm1a_cnt_blk):"memory"); 65c1bc863aSGleb Natapov while(1) 66c1bc863aSGleb Natapov *(volatile int*)0 = 1; 67c1bc863aSGleb Natapov 68c1bc863aSGleb Natapov return 0; 69c1bc863aSGleb Natapov } 70c1bc863aSGleb Natapov 71c1bc863aSGleb Natapov asm ( 72c1bc863aSGleb Natapov ".global resume_start\n" 73c1bc863aSGleb Natapov ".global resume_end\n" 74c1bc863aSGleb Natapov ".code16\n" 75c1bc863aSGleb Natapov "resume_start:\n" 76c1bc863aSGleb Natapov "mov 0x0, %eax\n" 77c1bc863aSGleb Natapov "mov $0xf4, %dx\n" 78c1bc863aSGleb Natapov "out %eax, %dx\n" 79c1bc863aSGleb Natapov "1: hlt\n" 80c1bc863aSGleb Natapov "jmp 1b\n" 81c1bc863aSGleb Natapov "resume_end:\n" 82c1bc863aSGleb Natapov #ifdef __i386__ 83c1bc863aSGleb Natapov ".code32\n" 84c1bc863aSGleb Natapov #else 85c1bc863aSGleb Natapov ".code64\n" 86c1bc863aSGleb Natapov #endif 87c1bc863aSGleb Natapov ); 88