blob: 96c63d5b4ffbc1a1c289fb01e45da6ece9fd61f9 [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'Connor18e38b22008-12-10 20:40:13 -05007#include "biosvar.h" // struct bios_data_area_s
Kevin O'Connor9967ab72008-12-18 21:57:33 -05008#include "bregs.h" // struct bregs
Kevin O'Connor5d369d82013-09-02 20:48:46 -04009#include "hw/cmos.h" // inb_cmos
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
13#include "ioport.h" // outb
14#include "output.h" // dprintf
Kevin O'Connor3df600b2013-09-14 19:28:55 -040015#include "stacks.h" // farcall16big
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -040016#include "string.h" // memset
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040017#include "util.h" // dma_setup
Kevin O'Connor87b533b2011-07-10 22:35:07 -040018
19// Indicator if POST phase has been run.
Kevin O'Connor89a2f962013-02-18 23:36:03 -050020int HaveRunPost VARFSEG;
Kevin O'Connor18e38b22008-12-10 20:40:13 -050021
22// Reset DMA controller
23void
Kevin O'Connor9e4d41c2013-01-21 12:14:29 -050024dma_setup(void)
Kevin O'Connor18e38b22008-12-10 20:40:13 -050025{
26 // first reset the DMA controllers
27 outb(0, PORT_DMA1_MASTER_CLEAR);
28 outb(0, PORT_DMA2_MASTER_CLEAR);
29
30 // then initialize the DMA controllers
31 outb(0xc0, PORT_DMA2_MODE_REG);
32 outb(0x00, PORT_DMA2_MASK_REG);
33}
34
35// Handler for post calls that look like a resume.
36void VISIBLE16
Kevin O'Connor87b533b2011-07-10 22:35:07 -040037handle_resume(void)
Kevin O'Connor18e38b22008-12-10 20:40:13 -050038{
Kevin O'Connora0263082012-04-14 20:22:18 -040039 ASSERT16();
Kevin O'Connord83c87b2013-01-21 01:14:12 -050040 debug_serial_preinit();
Kevin O'Connor87b533b2011-07-10 22:35:07 -040041 int status = inb_cmos(CMOS_RESET_CODE);
42 outb_cmos(0, CMOS_RESET_CODE);
Kevin O'Connor18e38b22008-12-10 20:40:13 -050043 dprintf(1, "In resume (status=%d)\n", status);
44
Kevin O'Connor9e4d41c2013-01-21 12:14:29 -050045 dma_setup();
Kevin O'Connor87b533b2011-07-10 22:35:07 -040046
Kevin O'Connor18e38b22008-12-10 20:40:13 -050047 switch (status) {
Kevin O'Connor87b533b2011-07-10 22:35:07 -040048 case 0x01 ... 0x04:
49 case 0x06 ... 0x09:
50 panic("Unimplemented shutdown status: %02x\n", status);
Kevin O'Connor18e38b22008-12-10 20:40:13 -050051
52 case 0x05:
53 // flush keyboard (issue EOI) and jump via 40h:0067h
Kevin O'Connoraa7c2342013-07-14 15:07:21 -040054 pic_eoi2();
Kevin O'Connor18e38b22008-12-10 20:40:13 -050055 // NO BREAK
56 case 0x0a:
Kevin O'Connor9f985422009-09-09 11:34:39 -040057#define BDA_JUMP (((struct bios_data_area_s *)0)->jump)
Kevin O'Connor18e38b22008-12-10 20:40:13 -050058 // resume execution by jump via 40h:0067h
Kevin O'Connor18e38b22008-12-10 20:40:13 -050059 asm volatile(
Kevin O'Connor590e7152009-01-19 12:53:54 -050060 "movw %w1, %%ds\n"
Kevin O'Connor18e38b22008-12-10 20:40:13 -050061 "ljmpw *%0\n"
Kevin O'Connor9f985422009-09-09 11:34:39 -040062 : : "m"(BDA_JUMP), "r"(SEG_BDA)
Kevin O'Connor18e38b22008-12-10 20:40:13 -050063 );
64 break;
65
66 case 0x0b:
67 // resume execution via IRET via 40h:0067h
68 asm volatile(
Kevin O'Connor590e7152009-01-19 12:53:54 -050069 "movw %w1, %%ds\n"
70 "lssw %0, %%sp\n"
Kevin O'Connor18e38b22008-12-10 20:40:13 -050071 "iretw\n"
Kevin O'Connor9f985422009-09-09 11:34:39 -040072 : : "m"(BDA_JUMP), "r"(SEG_BDA)
Kevin O'Connor18e38b22008-12-10 20:40:13 -050073 );
74 break;
75
76 case 0x0c:
77 // resume execution via RETF via 40h:0067h
78 asm volatile(
Kevin O'Connor590e7152009-01-19 12:53:54 -050079 "movw %w1, %%ds\n"
80 "lssw %0, %%sp\n"
Kevin O'Connor18e38b22008-12-10 20:40:13 -050081 "lretw\n"
Kevin O'Connor9f985422009-09-09 11:34:39 -040082 : : "m"(BDA_JUMP), "r"(SEG_BDA)
Kevin O'Connor18e38b22008-12-10 20:40:13 -050083 );
84 break;
Kevin O'Connor87b533b2011-07-10 22:35:07 -040085
86 default:
87 break;
Kevin O'Connor18e38b22008-12-10 20:40:13 -050088 }
89
Kevin O'Connor87b533b2011-07-10 22:35:07 -040090 // Not a 16bit resume - do remaining checks in 32bit mode
91 asm volatile(
92 "movw %w1, %%ss\n"
93 "movl %0, %%esp\n"
94 "movl $_cfunc32flat_handle_resume32, %%edx\n"
95 "jmp transition32\n"
96 : : "i"(BUILD_S3RESUME_STACK_ADDR), "r"(0), "a"(status)
97 );
Kevin O'Connor18e38b22008-12-10 20:40:13 -050098}
Kevin O'Connor9967ab72008-12-18 21:57:33 -050099
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400100// Handle an S3 resume event
101static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500102s3_resume(void)
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500103{
Kevin O'Connorb24c5742009-01-17 21:52:52 -0500104 if (!CONFIG_S3_RESUME)
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400105 return;
Kevin O'Connorb24c5742009-01-17 21:52:52 -0500106
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400107 u32 s3_resume_vector = find_resume_vector();
108 if (!s3_resume_vector) {
109 dprintf(1, "No resume vector set!\n");
110 return;
111 }
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500112
Gleb Natapovecae9bf2012-01-24 14:33:42 +0200113 pic_setup();
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500114 smm_setup();
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500115
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500116 s3_resume_vga();
Kevin O'Connord282af72009-07-04 04:10:32 -0400117
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500118 make_bios_readonly();
119
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500120 // Invoke the resume vector.
121 struct bregs br;
122 memset(&br, 0, sizeof(br));
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400123 dprintf(1, "Jump to resume vector (%x)\n", s3_resume_vector);
124 br.code = FLATPTR_TO_SEGOFF((void*)s3_resume_vector);
Kevin O'Connorc7ffbac2012-03-25 11:04:10 -0400125 farcall16big(&br);
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500126}
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400127
Kevin O'Connor400c66c2013-02-23 10:37:58 -0500128u8 HaveAttemptedReboot VARLOW;
129
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400130// Attempt to invoke a hard-reboot.
131static void
132tryReboot(void)
133{
Kevin O'Connor400c66c2013-02-23 10:37:58 -0500134 if (HaveAttemptedReboot) {
135 // Hard reboot has failed - try to shutdown machine.
136 dprintf(1, "Unable to hard-reboot machine - attempting shutdown.\n");
137 apm_shutdown();
138 }
139 HaveAttemptedReboot = 1;
140
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400141 dprintf(1, "Attempting a hard reboot\n");
142
143 // Setup for reset on qemu.
Kevin O'Connor897fb112013-02-07 23:32:48 -0500144 qemu_prep_reset();
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400145
David Woodhoused338eb92013-02-23 00:24:49 +0000146 // Reboot using ACPI RESET_REG
147 acpi_reboot();
148
Kevin O'Connor87b533b2011-07-10 22:35:07 -0400149 // Try keyboard controller reboot.
150 i8042_reboot();
151
152 // Try PCI 0xcf9 reboot
153 pci_reboot();
154
155 // Try triple fault
156 asm volatile("int3");
157
158 panic("Could not reboot");
159}
160
161void VISIBLE32FLAT
162handle_resume32(int status)
163{
164 ASSERT32FLAT();
165 dprintf(1, "In 32bit resume\n");
166
167 if (status == 0xfe)
168 s3_resume();
169
170 // Must be a soft reboot - invoke a hard reboot.
171 tryReboot();
172}