1 #include "libcflat.h" 2 #include "x86/acpi.h" 3 #include "asm/io.h" 4 5 static u32* find_resume_vector_addr(void) 6 { 7 struct facs_descriptor_rev1 *facs = find_acpi_table_addr(FACS_SIGNATURE); 8 if (!facs) 9 return 0; 10 printf("FACS is at %p\n", facs); 11 return &facs->firmware_waking_vector; 12 } 13 14 #define RTC_SECONDS_ALARM 1 15 #define RTC_MINUTES_ALARM 3 16 #define RTC_HOURS_ALARM 5 17 #define RTC_ALARM_DONT_CARE 0xC0 18 19 #define RTC_REG_A 10 20 #define RTC_REG_B 11 21 #define RTC_REG_C 12 22 23 #define REG_A_UIP 0x80 24 #define REG_B_AIE 0x20 25 26 static inline int rtc_in(u8 reg) 27 { 28 outb(reg, 0x70); 29 return inb(0x71); 30 } 31 32 static inline void rtc_out(u8 reg, u8 val) 33 { 34 outb(reg, 0x70); 35 outb(val, 0x71); 36 } 37 38 extern char resume_start, resume_end; 39 40 int main(int argc, char **argv) 41 { 42 struct fadt_descriptor_rev1 *fadt = find_acpi_table_addr(FACP_SIGNATURE); 43 volatile u32 *resume_vector_ptr = find_resume_vector_addr(); 44 char *addr, *resume_vec = (void*)0x1000; 45 46 *resume_vector_ptr = (u32)(ulong)resume_vec; 47 48 printf("resume vector addr is %p\n", resume_vector_ptr); 49 for (addr = &resume_start; addr < &resume_end; addr++) 50 *resume_vec++ = *addr; 51 printf("copy resume code from %p\n", &resume_start); 52 53 printf("PM1a event registers at %" PRIx32 "\n", fadt->pm1a_evt_blk); 54 outw(0x400, fadt->pm1a_evt_blk + 2); 55 56 /* Setup RTC alarm to wake up on the next second. */ 57 while ((rtc_in(RTC_REG_A) & REG_A_UIP) == 0); 58 while ((rtc_in(RTC_REG_A) & REG_A_UIP) != 0); 59 rtc_in(RTC_REG_C); 60 rtc_out(RTC_SECONDS_ALARM, RTC_ALARM_DONT_CARE); 61 rtc_out(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE); 62 rtc_out(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE); 63 rtc_out(RTC_REG_B, rtc_in(RTC_REG_B) | REG_B_AIE); 64 65 *(volatile int*)0 = 0; 66 asm volatile("outw %0, %1" :: "a"((short)0x2400), "d"((short)fadt->pm1a_cnt_blk):"memory"); 67 while(1) 68 *(volatile int*)0 = 1; 69 70 return 0; 71 } 72 73 asm ( 74 ".global resume_start\n" 75 ".global resume_end\n" 76 ".code16\n" 77 "resume_start:\n" 78 "mov 0x0, %eax\n" 79 "mov $0xf4, %dx\n" 80 "out %eax, %dx\n" 81 "1: hlt\n" 82 "jmp 1b\n" 83 "resume_end:\n" 84 #ifdef __i386__ 85 ".code32\n" 86 #else 87 ".code64\n" 88 #endif 89 ); 90