blob: fb0b8a89e614aad40bca6ce2f3efe10abb2fbf72 [file] [log] [blame]
Kevin O'Connor18e38b22008-12-10 20:40:13 -05001// Code for handling calls to "post" that are resume related.
2//
Kevin O'Connor14458432009-05-23 18:21:18 -04003// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
Kevin O'Connor18e38b22008-12-10 20:40:13 -05004//
Kevin O'Connorb1b7c2a2009-01-15 20:52:58 -05005// This file may be distributed under the terms of the GNU LGPLv3 license.
Kevin O'Connor18e38b22008-12-10 20:40:13 -05006
Kevin O'Connor9967ab72008-12-18 21:57:33 -05007#include "bregs.h" // struct bregs
Kevin O'Connor392d2aa2013-09-15 00:14:28 -04008#include "config.h" // CONFIG_*
9#include "farptr.h" // FLATPTR_TO_SEGOFF
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040010#include "hw/pci.h" // pci_reboot
11#include "hw/pic.h" // pic_eoi2
12#include "hw/ps2port.h" // i8042_reboot
Kevin O'Connor8b7861c2013-09-15 02:29:06 -040013#include "hw/rtc.h" // rtc_read
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040014#include "output.h" // dprintf
Kevin O'Connor3df600b2013-09-14 19:28:55 -040015#include "stacks.h" // farcall16big
Kevin O'Connor392d2aa2013-09-15 00:14:28 -040016#include "std/bda.h" // struct bios_data_area_s
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -040017#include "string.h" // memset
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040018#include "util.h" // dma_setup
Stefan Bergerb310dfa2015-03-23 14:22:16 -040019#include "tcgbios.h" // tpm_s3_resume
Ben Warren5f4c7b12017-02-20 19:56:19 -080020#include "fw/romfile_loader.h" // romfile_fw_cfg_resume
Kevin O'Connor87b533b2011-07-10 22:35:07 -040021
Kevin O'Connor18e38b22008-12-10 20:40:13 -050022// Handler for post calls that look like a resume.
23void VISIBLE16
Kevin O'Connor87b533b2011-07-10 22:35:07 -040024handle_resume(void)
Kevin O'Connor18e38b22008-12-10 20:40:13 -050025{
Kevin O'Connora0263082012-04-14 20:22:18 -040026 ASSERT16();
Kevin O'Connor8b7861c2013-09-15 02:29:06 -040027 int status = rtc_read(CMOS_RESET_CODE);
28 rtc_write(CMOS_RESET_CODE, 0);
Kevin O'Connor18e38b22008-12-10 20:40:13 -050029 dprintf(1, "In resume (status=%d)\n", status);
30
Kevin O'Connor9e4d41c2013-01-21 12:14:29 -050031 dma_setup();
Kevin O'Connor87b533b2011-07-10 22:35:07 -040032
Kevin O'Connor18e38b22008-12-10 20:40:13 -050033 switch (status) {
Kevin O'Connor87b533b2011-07-10 22:35:07 -040034 case 0x01 ... 0x04:
35 case 0x06 ... 0x09:
36 panic("Unimplemented shutdown status: %02x\n", status);
Kevin O'Connor18e38b22008-12-10 20:40:13 -050037
38 case 0x05:
39 // flush keyboard (issue EOI) and jump via 40h:0067h
Kevin O'Connoraa7c2342013-07-14 15:07:21 -040040 pic_eoi2();
Kevin O'Connor18e38b22008-12-10 20:40:13 -050041 // NO BREAK
42 case 0x0a:
Kevin O'Connor9f985422009-09-09 11:34:39 -040043#define BDA_JUMP (((struct bios_data_area_s *)0)->jump)
Kevin O'Connor18e38b22008-12-10 20:40:13 -050044 // resume execution by jump via 40h:0067h
Kevin O'Connor18e38b22008-12-10 20:40:13 -050045 asm volatile(
Kevin O'Connor590e7152009-01-19 12:53:54 -050046 "movw %w1, %%ds\n"
Kevin O'Connor18e38b22008-12-10 20:40:13 -050047 "ljmpw *%0\n"
Kevin O'Connor9f985422009-09-09 11:34:39 -040048 : : "m"(BDA_JUMP), "r"(SEG_BDA)
Kevin O'Connor18e38b22008-12-10 20:40:13 -050049 );
50 break;
51
52 case 0x0b:
53 // resume execution via IRET via 40h:0067h
54 asm volatile(
Kevin O'Connor590e7152009-01-19 12:53:54 -050055 "movw %w1, %%ds\n"
56 "lssw %0, %%sp\n"
Kevin O'Connor18e38b22008-12-10 20:40:13 -050057 "iretw\n"
Kevin O'Connor9f985422009-09-09 11:34:39 -040058 : : "m"(BDA_JUMP), "r"(SEG_BDA)
Kevin O'Connor18e38b22008-12-10 20:40:13 -050059 );
60 break;
61
62 case 0x0c:
63 // resume execution via RETF via 40h:0067h
64 asm volatile(
Kevin O'Connor590e7152009-01-19 12:53:54 -050065 "movw %w1, %%ds\n"
66 "lssw %0, %%sp\n"
Kevin O'Connor18e38b22008-12-10 20:40:13 -050067 "lretw\n"
Kevin O'Connor9f985422009-09-09 11:34:39 -040068 : : "m"(BDA_JUMP), "r"(SEG_BDA)
Kevin O'Connor18e38b22008-12-10 20:40:13 -050069 );
70 break;
Kevin O'Connor87b533b2011-07-10 22:35:07 -040071
72 default:
73 break;
Kevin O'Connor18e38b22008-12-10 20:40:13 -050074 }
75
Kevin O'Connor87b533b2011-07-10 22:35:07 -040076 // Not a 16bit resume - do remaining checks in 32bit mode
77 asm volatile(
78 "movw %w1, %%ss\n"
79 "movl %0, %%esp\n"
80 "movl $_cfunc32flat_handle_resume32, %%edx\n"
81 "jmp transition32\n"
82 : : "i"(BUILD_S3RESUME_STACK_ADDR), "r"(0), "a"(status)
83 );
Kevin O'Connor18e38b22008-12-10 20:40:13 -050084}
Kevin O'Connor9967ab72008-12-18 21:57:33 -050085
Kevin O'Connor87b533b2011-07-10 22:35:07 -040086// Handle an S3 resume event
87static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -050088s3_resume(void)
Kevin O'Connor9967ab72008-12-18 21:57:33 -050089{
Kevin O'Connorb24c5742009-01-17 21:52:52 -050090 if (!CONFIG_S3_RESUME)
Kevin O'Connor87b533b2011-07-10 22:35:07 -040091 return;
Kevin O'Connorb24c5742009-01-17 21:52:52 -050092
Kevin O'Connor87b533b2011-07-10 22:35:07 -040093 u32 s3_resume_vector = find_resume_vector();
94 if (!s3_resume_vector) {
95 dprintf(1, "No resume vector set!\n");
96 return;
97 }
Kevin O'Connor9967ab72008-12-18 21:57:33 -050098
Gleb Natapovecae9bf2012-01-24 14:33:42 +020099 pic_setup();
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500100 smm_setup();
Paolo Bonzini54e3a882016-07-07 16:00:40 +0200101 smp_resume();
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500102
Marcel Apfelbaum40d020f2014-01-15 14:20:06 +0200103 pci_resume();
104
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400105 /* resume TPM before we may measure option roms */
106 tpm_s3_resume();
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500107 s3_resume_vga();
Kevin O'Connord282af72009-07-04 04:10:32 -0400108
Ben Warren5f4c7b12017-02-20 19:56:19 -0800109 /* Replay any fw_cfg entries that go back to the host */
110 romfile_fw_cfg_resume();
111
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500112 make_bios_readonly();
113
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500114 // Invoke the resume vector.
115 struct bregs br;
116 memset(&br, 0, sizeof(br));
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400117 dprintf(1, "Jump to resume vector (%x)\n", s3_resume_vector);
118 br.code = FLATPTR_TO_SEGOFF((void*)s3_resume_vector);
Kevin O'Connorc7ffbac2012-03-25 11:04:10 -0400119 farcall16big(&br);
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500120}
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400121
122// Attempt to invoke a hard-reboot.
123static void
124tryReboot(void)
125{
126 dprintf(1, "Attempting a hard reboot\n");
127
Kevin O'Connor35516132017-03-03 10:48:45 -0500128 // Use a QEMU specific reboot on QEMU
129 qemu_reboot();
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400130
David Woodhoused338eb92013-02-23 00:24:49 +0000131 // Reboot using ACPI RESET_REG
132 acpi_reboot();
133
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400134 // Try keyboard controller reboot.
135 i8042_reboot();
136
137 // Try PCI 0xcf9 reboot
138 pci_reboot();
139
140 // Try triple fault
141 asm volatile("int3");
142
143 panic("Could not reboot");
144}
145
146void VISIBLE32FLAT
147handle_resume32(int status)
148{
149 ASSERT32FLAT();
150 dprintf(1, "In 32bit resume\n");
151
152 if (status == 0xfe)
153 s3_resume();
154
155 // Must be a soft reboot - invoke a hard reboot.
156 tryReboot();
157}