1 #include "libcflat.h" 2 3 struct rsdp_descriptor { /* Root System Descriptor Pointer */ 4 u64 signature; /* ACPI signature, contains "RSD PTR " */ 5 u8 checksum; /* To make sum of struct == 0 */ 6 u8 oem_id [6]; /* OEM identification */ 7 u8 revision; /* Must be 0 for 1.0, 2 for 2.0 */ 8 u32 rsdt_physical_address; /* 32-bit physical address of RSDT */ 9 u32 length; /* XSDT Length in bytes including hdr */ 10 u64 xsdt_physical_address; /* 64-bit physical address of XSDT */ 11 u8 extended_checksum; /* Checksum of entire table */ 12 u8 reserved [3]; /* Reserved field must be 0 */ 13 }; 14 15 #define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \ 16 u32 signature; /* ACPI signature (4 ASCII characters) */ \ 17 u32 length; /* Length of table, in bytes, including header */ \ 18 u8 revision; /* ACPI Specification minor version # */ \ 19 u8 checksum; /* To make sum of entire table == 0 */ \ 20 u8 oem_id [6]; /* OEM identification */ \ 21 u8 oem_table_id [8]; /* OEM table identification */ \ 22 u32 oem_revision; /* OEM revision number */ \ 23 u8 asl_compiler_id [4]; /* ASL compiler vendor ID */ \ 24 u32 asl_compiler_revision; /* ASL compiler revision number */ 25 26 #define RSDT_SIGNATURE 0x54445352 27 struct rsdt_descriptor_rev1 { 28 ACPI_TABLE_HEADER_DEF 29 u32 table_offset_entry[0]; 30 }; 31 32 #define FACP_SIGNATURE 0x50434146 // FACP 33 struct fadt_descriptor_rev1 34 { 35 ACPI_TABLE_HEADER_DEF /* ACPI common table header */ 36 u32 firmware_ctrl; /* Physical address of FACS */ 37 u32 dsdt; /* Physical address of DSDT */ 38 u8 model; /* System Interrupt Model */ 39 u8 reserved1; /* Reserved */ 40 u16 sci_int; /* System vector of SCI interrupt */ 41 u32 smi_cmd; /* Port address of SMI command port */ 42 u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */ 43 u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */ 44 u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ 45 u8 reserved2; /* Reserved - must be zero */ 46 u32 pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */ 47 u32 pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */ 48 u32 pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ 49 u32 pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ 50 u32 pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ 51 u32 pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ 52 u32 gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ 53 u32 gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ 54 u8 pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ 55 u8 pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ 56 u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ 57 u8 pm_tmr_len; /* Byte Length of ports at pm_tm_blk */ 58 u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ 59 u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ 60 u8 gpe1_base; /* Offset in gpe model where gpe1 events start */ 61 u8 reserved3; /* Reserved */ 62 u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ 63 u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ 64 u16 flush_size; /* Size of area read to flush caches */ 65 u16 flush_stride; /* Stride used in flushing caches */ 66 u8 duty_offset; /* Bit location of duty cycle field in p_cnt reg */ 67 u8 duty_width; /* Bit width of duty cycle field in p_cnt reg */ 68 u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ 69 u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ 70 u8 century; /* Index to century in RTC CMOS RAM */ 71 u8 reserved4; /* Reserved */ 72 u8 reserved4a; /* Reserved */ 73 u8 reserved4b; /* Reserved */ 74 }; 75 76 #define FACS_SIGNATURE 0x53434146 // FACS 77 struct facs_descriptor_rev1 78 { 79 u32 signature; /* ACPI Signature */ 80 u32 length; /* Length of structure, in bytes */ 81 u32 hardware_signature; /* Hardware configuration signature */ 82 u32 firmware_waking_vector; /* ACPI OS waking vector */ 83 u32 global_lock; /* Global Lock */ 84 u32 S4bios_f : 1; /* Indicates if S4BIOS support is present */ 85 u32 reserved1 : 31; /* Must be 0 */ 86 u8 resverved3 [40]; /* Reserved - must be zero */ 87 }; 88 89 u32* find_resume_vector_addr(void) 90 { 91 unsigned long addr; 92 struct rsdp_descriptor *rsdp; 93 struct rsdt_descriptor_rev1 *rsdt; 94 void *end; 95 int i; 96 97 for(addr = 0xf0000; addr < 0x100000; addr += 16) { 98 rsdp = (void*)addr; 99 if (rsdp->signature == 0x2052545020445352LL) 100 break; 101 } 102 if (addr == 0x100000) { 103 printf("Can't find RSDP\n"); 104 return 0; 105 } 106 107 printf("RSDP is at %x\n", rsdp); 108 rsdt = (void*)(ulong)rsdp->rsdt_physical_address; 109 if (!rsdt || rsdt->signature != RSDT_SIGNATURE) 110 return 0; 111 112 printf("RSDT is at %x\n", rsdt); 113 114 end = (void*)rsdt + rsdt->length; 115 for (i=0; (void*)&rsdt->table_offset_entry[i] < end; i++) { 116 struct fadt_descriptor_rev1 *fadt = (void*)(ulong)rsdt->table_offset_entry[i]; 117 struct facs_descriptor_rev1 *facs; 118 if (!fadt || fadt->signature != FACP_SIGNATURE) 119 continue; 120 printf("FADT is at %x\n", fadt); 121 facs = (void*)(ulong)fadt->firmware_ctrl; 122 if (!facs || facs->signature != FACS_SIGNATURE) 123 return 0; 124 printf("FACS is at %x\n", facs); 125 return &facs->firmware_waking_vector; 126 } 127 return 0; 128 } 129 130 #define RTC_SECONDS_ALARM 1 131 #define RTC_MINUTES_ALARM 3 132 #define RTC_HOURS_ALARM 5 133 #define RTC_ALARM_DONT_CARE 0xC0 134 135 #define RTC_REG_A 10 136 #define RTC_REG_B 11 137 #define RTC_REG_C 12 138 139 #define REG_A_UIP 0x80 140 #define REG_B_AIE 0x20 141 142 static inline int rtc_in(u8 reg) 143 { 144 u8 x = reg; 145 asm volatile("outb %b1, $0x70; inb $0x71, %b0" 146 : "+a"(x) : "0"(x)); 147 return x; 148 } 149 150 static inline void rtc_out(u8 reg, u8 val) 151 { 152 asm volatile("outb %b1, $0x70; mov %b2, %b1; outb %b1, $0x71" 153 : "+a"(reg) : "0"(reg), "ri"(val)); 154 } 155 156 extern char resume_start, resume_end; 157 158 int main(int argc, char **argv) 159 { 160 volatile u32 *resume_vector_ptr = find_resume_vector_addr(); 161 char *addr, *resume_vec = (void*)0x1000; 162 163 *resume_vector_ptr = (u32)(ulong)resume_vec; 164 165 printf("resume vector addr is %x\n", resume_vector_ptr); 166 for (addr = &resume_start; addr < &resume_end; addr++) 167 *resume_vec++ = *addr; 168 printf("copy resume code from %x\n", &resume_start); 169 170 /* Setup RTC alarm to wake up on the next second. */ 171 while ((rtc_in(RTC_REG_A) & REG_A_UIP) == 0); 172 while ((rtc_in(RTC_REG_A) & REG_A_UIP) != 0); 173 rtc_in(RTC_REG_C); 174 rtc_out(RTC_SECONDS_ALARM, RTC_ALARM_DONT_CARE); 175 rtc_out(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE); 176 rtc_out(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE); 177 rtc_out(RTC_REG_B, rtc_in(RTC_REG_B) | REG_B_AIE); 178 179 *(volatile int*)0 = 0; 180 asm volatile("out %0, %1" :: "a"(0x2400), "d"((short)0xb004):"memory"); 181 while(1) 182 *(volatile int*)0 = 1; 183 184 return 0; 185 } 186 187 asm ( 188 ".global resume_start\n" 189 ".global resume_end\n" 190 ".code16\n" 191 "resume_start:\n" 192 "mov 0x0, %eax\n" 193 "mov $0xf4, %dx\n" 194 "out %eax, %dx\n" 195 "1: hlt\n" 196 "jmp 1b\n" 197 "resume_end:\n" 198 #ifdef __i386__ 199 ".code32\n" 200 #else 201 ".code64\n" 202 #endif 203 ); 204