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