blob: 3a26f8458b91e588a5e6f9c0dc08f10a86fb4754 [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
Kevin O'Connor87b533b2011-07-10 22:35:07 -040020
Kevin O'Connor18e38b22008-12-10 20:40:13 -050021// Handler for post calls that look like a resume.
22void VISIBLE16
Kevin O'Connor87b533b2011-07-10 22:35:07 -040023handle_resume(void)
Kevin O'Connor18e38b22008-12-10 20:40:13 -050024{
Kevin O'Connora0263082012-04-14 20:22:18 -040025 ASSERT16();
Kevin O'Connor8b7861c2013-09-15 02:29:06 -040026 int status = rtc_read(CMOS_RESET_CODE);
27 rtc_write(CMOS_RESET_CODE, 0);
Kevin O'Connor18e38b22008-12-10 20:40:13 -050028 dprintf(1, "In resume (status=%d)\n", status);
29
Kevin O'Connor9e4d41c2013-01-21 12:14:29 -050030 dma_setup();
Kevin O'Connor87b533b2011-07-10 22:35:07 -040031
Kevin O'Connor18e38b22008-12-10 20:40:13 -050032 switch (status) {
Kevin O'Connor87b533b2011-07-10 22:35:07 -040033 case 0x01 ... 0x04:
34 case 0x06 ... 0x09:
35 panic("Unimplemented shutdown status: %02x\n", status);
Kevin O'Connor18e38b22008-12-10 20:40:13 -050036
37 case 0x05:
38 // flush keyboard (issue EOI) and jump via 40h:0067h
Kevin O'Connoraa7c2342013-07-14 15:07:21 -040039 pic_eoi2();
Kevin O'Connor18e38b22008-12-10 20:40:13 -050040 // NO BREAK
41 case 0x0a:
Kevin O'Connor9f985422009-09-09 11:34:39 -040042#define BDA_JUMP (((struct bios_data_area_s *)0)->jump)
Kevin O'Connor18e38b22008-12-10 20:40:13 -050043 // resume execution by jump via 40h:0067h
Kevin O'Connor18e38b22008-12-10 20:40:13 -050044 asm volatile(
Kevin O'Connor590e7152009-01-19 12:53:54 -050045 "movw %w1, %%ds\n"
Kevin O'Connor18e38b22008-12-10 20:40:13 -050046 "ljmpw *%0\n"
Kevin O'Connor9f985422009-09-09 11:34:39 -040047 : : "m"(BDA_JUMP), "r"(SEG_BDA)
Kevin O'Connor18e38b22008-12-10 20:40:13 -050048 );
49 break;
50
51 case 0x0b:
52 // resume execution via IRET via 40h:0067h
53 asm volatile(
Kevin O'Connor590e7152009-01-19 12:53:54 -050054 "movw %w1, %%ds\n"
55 "lssw %0, %%sp\n"
Kevin O'Connor18e38b22008-12-10 20:40:13 -050056 "iretw\n"
Kevin O'Connor9f985422009-09-09 11:34:39 -040057 : : "m"(BDA_JUMP), "r"(SEG_BDA)
Kevin O'Connor18e38b22008-12-10 20:40:13 -050058 );
59 break;
60
61 case 0x0c:
62 // resume execution via RETF via 40h:0067h
63 asm volatile(
Kevin O'Connor590e7152009-01-19 12:53:54 -050064 "movw %w1, %%ds\n"
65 "lssw %0, %%sp\n"
Kevin O'Connor18e38b22008-12-10 20:40:13 -050066 "lretw\n"
Kevin O'Connor9f985422009-09-09 11:34:39 -040067 : : "m"(BDA_JUMP), "r"(SEG_BDA)
Kevin O'Connor18e38b22008-12-10 20:40:13 -050068 );
69 break;
Kevin O'Connor87b533b2011-07-10 22:35:07 -040070
71 default:
72 break;
Kevin O'Connor18e38b22008-12-10 20:40:13 -050073 }
74
Kevin O'Connor87b533b2011-07-10 22:35:07 -040075 // Not a 16bit resume - do remaining checks in 32bit mode
76 asm volatile(
77 "movw %w1, %%ss\n"
78 "movl %0, %%esp\n"
79 "movl $_cfunc32flat_handle_resume32, %%edx\n"
80 "jmp transition32\n"
81 : : "i"(BUILD_S3RESUME_STACK_ADDR), "r"(0), "a"(status)
82 );
Kevin O'Connor18e38b22008-12-10 20:40:13 -050083}
Kevin O'Connor9967ab72008-12-18 21:57:33 -050084
Kevin O'Connor87b533b2011-07-10 22:35:07 -040085// Handle an S3 resume event
86static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -050087s3_resume(void)
Kevin O'Connor9967ab72008-12-18 21:57:33 -050088{
Kevin O'Connorb24c5742009-01-17 21:52:52 -050089 if (!CONFIG_S3_RESUME)
Kevin O'Connor87b533b2011-07-10 22:35:07 -040090 return;
Kevin O'Connorb24c5742009-01-17 21:52:52 -050091
Kevin O'Connor87b533b2011-07-10 22:35:07 -040092 u32 s3_resume_vector = find_resume_vector();
93 if (!s3_resume_vector) {
94 dprintf(1, "No resume vector set!\n");
95 return;
96 }
Kevin O'Connor9967ab72008-12-18 21:57:33 -050097
Gleb Natapovecae9bf2012-01-24 14:33:42 +020098 pic_setup();
Kevin O'Connord83c87b2013-01-21 01:14:12 -050099 smm_setup();
Paolo Bonziniba57bed2016-07-07 16:00:40 +0200100 smp_resume();
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500101
Marcel Apfelbaum40d020f2014-01-15 14:20:06 +0200102 pci_resume();
103
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400104 /* resume TPM before we may measure option roms */
105 tpm_s3_resume();
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500106 s3_resume_vga();
Kevin O'Connord282af72009-07-04 04:10:32 -0400107
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500108 make_bios_readonly();
109
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500110 // Invoke the resume vector.
111 struct bregs br;
112 memset(&br, 0, sizeof(br));
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400113 dprintf(1, "Jump to resume vector (%x)\n", s3_resume_vector);
114 br.code = FLATPTR_TO_SEGOFF((void*)s3_resume_vector);
Kevin O'Connorc7ffbac2012-03-25 11:04:10 -0400115 farcall16big(&br);
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500116}
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400117
Kevin O'Connor400c66c2013-02-23 10:37:58 -0500118u8 HaveAttemptedReboot VARLOW;
119
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400120// Attempt to invoke a hard-reboot.
121static void
122tryReboot(void)
123{
Kevin O'Connor400c66c2013-02-23 10:37:58 -0500124 if (HaveAttemptedReboot) {
125 // Hard reboot has failed - try to shutdown machine.
126 dprintf(1, "Unable to hard-reboot machine - attempting shutdown.\n");
127 apm_shutdown();
128 }
129 HaveAttemptedReboot = 1;
130
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400131 dprintf(1, "Attempting a hard reboot\n");
132
133 // Setup for reset on qemu.
Kevin O'Connor897fb112013-02-07 23:32:48 -0500134 qemu_prep_reset();
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400135
David Woodhoused338eb92013-02-23 00:24:49 +0000136 // Reboot using ACPI RESET_REG
137 acpi_reboot();
138
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400139 // Try keyboard controller reboot.
140 i8042_reboot();
141
142 // Try PCI 0xcf9 reboot
143 pci_reboot();
144
145 // Try triple fault
146 asm volatile("int3");
147
148 panic("Could not reboot");
149}
150
151void VISIBLE32FLAT
152handle_resume32(int status)
153{
154 ASSERT32FLAT();
155 dprintf(1, "In 32bit resume\n");
156
157 if (status == 0xfe)
158 s3_resume();
159
160 // Must be a soft reboot - invoke a hard reboot.
161 tryReboot();
162}