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