xref: /kvm-unit-tests/x86/s3.c (revision a5d12b9fdcee05c0734adfb1a83baface44ffd08)
1c1bc863aSGleb Natapov #include "libcflat.h"
2*a5d12b9fSPaolo Bonzini #include "x86/acpi.h"
3c1bc863aSGleb Natapov 
4c1bc863aSGleb Natapov u32* find_resume_vector_addr(void)
5c1bc863aSGleb Natapov {
6372e3528SPaolo Bonzini     struct facs_descriptor_rev1 *facs = find_acpi_table_addr(FACS_SIGNATURE);
7372e3528SPaolo Bonzini     if (!facs)
8c1bc863aSGleb Natapov         return 0;
9c1bc863aSGleb Natapov     printf("FACS is at %x\n", facs);
10c1bc863aSGleb Natapov     return &facs->firmware_waking_vector;
11c1bc863aSGleb Natapov }
12c1bc863aSGleb Natapov 
13798b0d95SPaolo Bonzini #define RTC_SECONDS_ALARM       1
14798b0d95SPaolo Bonzini #define RTC_MINUTES_ALARM       3
15798b0d95SPaolo Bonzini #define RTC_HOURS_ALARM         5
16798b0d95SPaolo Bonzini #define RTC_ALARM_DONT_CARE     0xC0
17798b0d95SPaolo Bonzini 
18798b0d95SPaolo Bonzini #define RTC_REG_A               10
19798b0d95SPaolo Bonzini #define RTC_REG_B               11
20798b0d95SPaolo Bonzini #define RTC_REG_C               12
21798b0d95SPaolo Bonzini 
22798b0d95SPaolo Bonzini #define REG_A_UIP               0x80
23798b0d95SPaolo Bonzini #define REG_B_AIE               0x20
24798b0d95SPaolo Bonzini 
25798b0d95SPaolo Bonzini static inline int rtc_in(u8 reg)
26798b0d95SPaolo Bonzini {
27798b0d95SPaolo Bonzini     u8 x = reg;
28798b0d95SPaolo Bonzini     asm volatile("outb %b1, $0x70; inb $0x71, %b0"
290b9e64c4SGleb Natapov 		 : "=a"(x) : "0"(x));
30798b0d95SPaolo Bonzini     return x;
31798b0d95SPaolo Bonzini }
32798b0d95SPaolo Bonzini 
33798b0d95SPaolo Bonzini static inline void rtc_out(u8 reg, u8 val)
34798b0d95SPaolo Bonzini {
35798b0d95SPaolo Bonzini     asm volatile("outb %b1, $0x70; mov %b2, %b1; outb %b1, $0x71"
360b9e64c4SGleb Natapov 		 : "=a"(reg) : "0"(reg), "ri"(val));
37798b0d95SPaolo Bonzini }
38798b0d95SPaolo Bonzini 
39c1bc863aSGleb Natapov extern char resume_start, resume_end;
40c1bc863aSGleb Natapov 
41c1bc863aSGleb Natapov int main(int argc, char **argv)
42c1bc863aSGleb Natapov {
43*a5d12b9fSPaolo Bonzini 	struct fadt_descriptor_rev1 *fadt = find_acpi_table_addr(FACP_SIGNATURE);
44c1bc863aSGleb Natapov 	volatile u32 *resume_vector_ptr = find_resume_vector_addr();
45c1bc863aSGleb Natapov 	char *addr, *resume_vec = (void*)0x1000;
46c1bc863aSGleb Natapov 
47c1bc863aSGleb Natapov 	*resume_vector_ptr = (u32)(ulong)resume_vec;
48c1bc863aSGleb Natapov 
49c1bc863aSGleb Natapov 	printf("resume vector addr is %x\n", resume_vector_ptr);
50c1bc863aSGleb Natapov 	for (addr = &resume_start; addr < &resume_end; addr++)
51c1bc863aSGleb Natapov 		*resume_vec++ = *addr;
52c1bc863aSGleb Natapov 	printf("copy resume code from %x\n", &resume_start);
53798b0d95SPaolo Bonzini 
54798b0d95SPaolo Bonzini 	/* Setup RTC alarm to wake up on the next second.  */
55798b0d95SPaolo Bonzini 	while ((rtc_in(RTC_REG_A) & REG_A_UIP) == 0);
56798b0d95SPaolo Bonzini 	while ((rtc_in(RTC_REG_A) & REG_A_UIP) != 0);
57798b0d95SPaolo Bonzini 	rtc_in(RTC_REG_C);
58798b0d95SPaolo Bonzini 	rtc_out(RTC_SECONDS_ALARM, RTC_ALARM_DONT_CARE);
59798b0d95SPaolo Bonzini 	rtc_out(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE);
60798b0d95SPaolo Bonzini 	rtc_out(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE);
61798b0d95SPaolo Bonzini 	rtc_out(RTC_REG_B, rtc_in(RTC_REG_B) | REG_B_AIE);
62798b0d95SPaolo Bonzini 
63c1bc863aSGleb Natapov 	*(volatile int*)0 = 0;
64*a5d12b9fSPaolo Bonzini 	asm volatile("outw %0, %1" :: "a"((short)0x2400), "d"((short)fadt->pm1a_cnt_blk):"memory");
65c1bc863aSGleb Natapov 	while(1)
66c1bc863aSGleb Natapov 		*(volatile int*)0 = 1;
67c1bc863aSGleb Natapov 
68c1bc863aSGleb Natapov 	return 0;
69c1bc863aSGleb Natapov }
70c1bc863aSGleb Natapov 
71c1bc863aSGleb Natapov asm (
72c1bc863aSGleb Natapov         ".global resume_start\n"
73c1bc863aSGleb Natapov 	".global resume_end\n"
74c1bc863aSGleb Natapov 	".code16\n"
75c1bc863aSGleb Natapov 	"resume_start:\n"
76c1bc863aSGleb Natapov 	"mov 0x0, %eax\n"
77c1bc863aSGleb Natapov 	"mov $0xf4, %dx\n"
78c1bc863aSGleb Natapov 	"out %eax, %dx\n"
79c1bc863aSGleb Natapov 	"1: hlt\n"
80c1bc863aSGleb Natapov 	"jmp 1b\n"
81c1bc863aSGleb Natapov 	"resume_end:\n"
82c1bc863aSGleb Natapov #ifdef __i386__
83c1bc863aSGleb Natapov 	".code32\n"
84c1bc863aSGleb Natapov #else
85c1bc863aSGleb Natapov 	".code64\n"
86c1bc863aSGleb Natapov #endif
87c1bc863aSGleb Natapov     );
88