blob: a5465d8774fa7fd2051520359f406288f2d7fdad [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();
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500100
Marcel Apfelbaum40d020f2014-01-15 14:20:06 +0200101 pci_resume();
102
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400103 /* resume TPM before we may measure option roms */
104 tpm_s3_resume();
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500105 s3_resume_vga();
Kevin O'Connord282af72009-07-04 04:10:32 -0400106
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500107 make_bios_readonly();
108
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500109 // Invoke the resume vector.
110 struct bregs br;
111 memset(&br, 0, sizeof(br));
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400112 dprintf(1, "Jump to resume vector (%x)\n", s3_resume_vector);
113 br.code = FLATPTR_TO_SEGOFF((void*)s3_resume_vector);
Kevin O'Connorc7ffbac2012-03-25 11:04:10 -0400114 farcall16big(&br);
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500115}
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400116
Kevin O'Connor400c66c2013-02-23 10:37:58 -0500117u8 HaveAttemptedReboot VARLOW;
118
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400119// Attempt to invoke a hard-reboot.
120static void
121tryReboot(void)
122{
Kevin O'Connor400c66c2013-02-23 10:37:58 -0500123 if (HaveAttemptedReboot) {
124 // Hard reboot has failed - try to shutdown machine.
125 dprintf(1, "Unable to hard-reboot machine - attempting shutdown.\n");
126 apm_shutdown();
127 }
128 HaveAttemptedReboot = 1;
129
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400130 dprintf(1, "Attempting a hard reboot\n");
131
132 // Setup for reset on qemu.
Kevin O'Connor897fb112013-02-07 23:32:48 -0500133 qemu_prep_reset();
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400134
David Woodhoused338eb92013-02-23 00:24:49 +0000135 // Reboot using ACPI RESET_REG
136 acpi_reboot();
137
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400138 // Try keyboard controller reboot.
139 i8042_reboot();
140
141 // Try PCI 0xcf9 reboot
142 pci_reboot();
143
144 // Try triple fault
145 asm volatile("int3");
146
147 panic("Could not reboot");
148}
149
150void VISIBLE32FLAT
151handle_resume32(int status)
152{
153 ASSERT32FLAT();
154 dprintf(1, "In 32bit resume\n");
155
156 if (status == 0xfe)
157 s3_resume();
158
159 // Must be a soft reboot - invoke a hard reboot.
160 tryReboot();
161}