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