4390fb59c43941354cfc14d606f0862685b085ca
[seabios.git] / src / resume.c
1 // Code for handling calls to "post" that are resume related.
2 //
3 // Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
4 //
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
6
7 #include "util.h" // dprintf
8 #include "ioport.h" // outb
9 #include "pic.h" // eoi_pic2
10 #include "biosvar.h" // struct bios_data_area_s
11 #include "bregs.h" // struct bregs
12 #include "acpi.h" // find_resume_vector
13 #include "ps2port.h" // i8042_reboot
14 #include "pci.h" // pci_reboot
15 #include "cmos.h" // inb_cmos
16
17 // Indicator if POST phase has been run.
18 int HaveRunPost VAR16VISIBLE;
19
20 // Reset DMA controller
21 void
22 init_dma(void)
23 {
24     // first reset the DMA controllers
25     outb(0, PORT_DMA1_MASTER_CLEAR);
26     outb(0, PORT_DMA2_MASTER_CLEAR);
27
28     // then initialize the DMA controllers
29     outb(0xc0, PORT_DMA2_MODE_REG);
30     outb(0x00, PORT_DMA2_MASK_REG);
31 }
32
33 // Handler for post calls that look like a resume.
34 void VISIBLE16
35 handle_resume(void)
36 {
37     debug_serial_setup();
38     int status = inb_cmos(CMOS_RESET_CODE);
39     outb_cmos(0, CMOS_RESET_CODE);
40     dprintf(1, "In resume (status=%d)\n", status);
41
42     init_dma();
43
44     switch (status) {
45     case 0x01 ... 0x04:
46     case 0x06 ... 0x09:
47         panic("Unimplemented shutdown status: %02x\n", status);
48
49     case 0x05:
50         // flush keyboard (issue EOI) and jump via 40h:0067h
51         eoi_pic2();
52         // NO BREAK
53     case 0x0a:
54 #define BDA_JUMP (((struct bios_data_area_s *)0)->jump)
55         // resume execution by jump via 40h:0067h
56         asm volatile(
57             "movw %w1, %%ds\n"
58             "ljmpw *%0\n"
59             : : "m"(BDA_JUMP), "r"(SEG_BDA)
60             );
61         break;
62
63     case 0x0b:
64         // resume execution via IRET via 40h:0067h
65         asm volatile(
66             "movw %w1, %%ds\n"
67             "lssw %0, %%sp\n"
68             "iretw\n"
69             : : "m"(BDA_JUMP), "r"(SEG_BDA)
70             );
71         break;
72
73     case 0x0c:
74         // resume execution via RETF via 40h:0067h
75         asm volatile(
76             "movw %w1, %%ds\n"
77             "lssw %0, %%sp\n"
78             "lretw\n"
79             : : "m"(BDA_JUMP), "r"(SEG_BDA)
80             );
81         break;
82
83     default:
84         break;
85     }
86
87     // Not a 16bit resume - do remaining checks in 32bit mode
88     asm volatile(
89         "movw %w1, %%ss\n"
90         "movl %0, %%esp\n"
91         "movl $_cfunc32flat_handle_resume32, %%edx\n"
92         "jmp transition32\n"
93         : : "i"(BUILD_S3RESUME_STACK_ADDR), "r"(0), "a"(status)
94         );
95 }
96
97 // Handle an S3 resume event
98 static void
99 s3_resume(void)
100 {
101     if (!CONFIG_S3_RESUME)
102         return;
103
104     u32 s3_resume_vector = find_resume_vector();
105     if (!s3_resume_vector) {
106         dprintf(1, "No resume vector set!\n");
107         return;
108     }
109
110     smm_init();
111
112     s3_resume_vga_init();
113
114     make_bios_readonly();
115
116     // Invoke the resume vector.
117     struct bregs br;
118     memset(&br, 0, sizeof(br));
119     dprintf(1, "Jump to resume vector (%x)\n", s3_resume_vector);
120     br.code = FLATPTR_TO_SEGOFF((void*)s3_resume_vector);
121     call16big(&br);
122 }
123
124 // Attempt to invoke a hard-reboot.
125 static void
126 tryReboot(void)
127 {
128     dprintf(1, "Attempting a hard reboot\n");
129
130     // Setup for reset on qemu.
131     if (! CONFIG_COREBOOT) {
132         qemu_prep_reset();
133         if (HaveRunPost)
134             apm_shutdown();
135     }
136
137     // Try keyboard controller reboot.
138     i8042_reboot();
139
140     // Try PCI 0xcf9 reboot
141     pci_reboot();
142
143     // Try triple fault
144     asm volatile("int3");
145
146     panic("Could not reboot");
147 }
148
149 void VISIBLE32FLAT
150 handle_resume32(int status)
151 {
152     ASSERT32FLAT();
153     dprintf(1, "In 32bit resume\n");
154
155     if (status == 0xfe)
156         s3_resume();
157
158     // Must be a soft reboot - invoke a hard reboot.
159     tryReboot();
160 }