xref: /minix/minix/kernel/arch/i386/arch_reset.c (revision 045e0ed3)
1 
2 #include "kernel/kernel.h"
3 
4 #include <ctype.h>
5 #include <string.h>
6 #include <machine/cmos.h>
7 #include <machine/bios.h>
8 #include <machine/cpu.h>
9 #include <minix/portio.h>
10 #include <minix/cpufeature.h>
11 #include <sys/reboot.h>
12 #include <assert.h>
13 #include <signal.h>
14 
15 #include <minix/u64.h>
16 
17 #include "archconst.h"
18 #include "arch_proto.h"
19 #include "serial.h"
20 #include "oxpcie.h"
21 #include "direct_utils.h"
22 #include <machine/multiboot.h>
23 
24 #ifdef USE_ACPI
25 #include "acpi.h"
26 #endif
27 
28 #define     KBCMDP          4       /* kbd controller port (O) */
29 #define      KBC_PULSE0     0xfe    /* pulse output bit 0 */
30 #define      IO_KBD          0x060           /* 8042 Keyboard */
31 
32 int cpu_has_tsc;
33 
34 void
35 reset(void)
36 {
37         uint8_t b;
38         /*
39          * The keyboard controller has 4 random output pins, one of which is
40          * connected to the RESET pin on the CPU in many PCs.  We tell the
41          * keyboard controller to pulse this line a couple of times.
42          */
43         outb(IO_KBD + KBCMDP, KBC_PULSE0);
44         busy_delay_ms(100);
45         outb(IO_KBD + KBCMDP, KBC_PULSE0);
46         busy_delay_ms(100);
47 
48         /*
49          * Attempt to force a reset via the Reset Control register at
50          * I/O port 0xcf9.  Bit 2 forces a system reset when it
51          * transitions from 0 to 1.  Bit 1 selects the type of reset
52          * to attempt: 0 selects a "soft" reset, and 1 selects a
53          * "hard" reset.  We try a "hard" reset.  The first write sets
54          * bit 1 to select a "hard" reset and clears bit 2.  The
55          * second write forces a 0 -> 1 transition in bit 2 to trigger
56          * a reset.
57          */
58         outb(0xcf9, 0x2);
59         outb(0xcf9, 0x6);
60         busy_delay_ms(500);  /* wait 0.5 sec to see if that did it */
61 
62         /*
63          * Attempt to force a reset via the Fast A20 and Init register
64          * at I/O port 0x92.  Bit 1 serves as an alternate A20 gate.
65          * Bit 0 asserts INIT# when set to 1.  We are careful to only
66          * preserve bit 1 while setting bit 0.  We also must clear bit
67          * 0 before setting it if it isn't already clear.
68          */
69         b = inb(0x92);
70         if (b != 0xff) {
71                 if ((b & 0x1) != 0)
72                         outb(0x92, b & 0xfe);
73                 outb(0x92, b | 0x1);
74                 busy_delay_ms(500);  /* wait 0.5 sec to see if that did it */
75         }
76 
77 	/* Triple fault */
78 	x86_triplefault();
79 
80 	/* Give up on resetting */
81 	while(1) {
82 		;
83 	}
84 }
85 
86 static __dead void
87 halt(void)
88 {
89 	for ( ; ; )
90 		halt_cpu();
91 }
92 
93 static __dead void
94 poweroff(void)
95 {
96 	const char *shutdown_str;
97 
98 #ifdef USE_ACPI
99 	acpi_poweroff();
100 #endif
101 	/* Bochs/QEMU poweroff */
102 	shutdown_str = "Shutdown";
103         while (*shutdown_str) outb(0x8900, *(shutdown_str++));
104 
105 	/* VMware magic power off; likely to halt CPU */
106 	poweroff_vmware_clihlt();
107 
108 	/* fallback option: hang */
109 	halt();
110 }
111 
112 __dead void arch_shutdown(int how)
113 {
114 	unsigned char unused_ch;
115 	/* Mask all interrupts, including the clock. */
116 	outb( INT_CTLMASK, ~0);
117 
118 	/* Empty buffer */
119 	while(direct_read_char(&unused_ch))
120 		;
121 
122 	if(kinfo.minix_panicing) {
123 		/* Printing is done synchronously over serial. */
124 		if (kinfo.do_serial_debug)
125 			reset();
126 
127 		/* Print accumulated diagnostics buffer and reset. */
128 		direct_cls();
129 		direct_print("Minix panic. System diagnostics buffer:\n\n");
130 		direct_print(kmess.kmess_buf);
131 		direct_print("\nSystem has panicked, press any key to reboot");
132 		while (!direct_read_char(&unused_ch))
133 			;
134 		reset();
135 	}
136 
137 	if((how & RB_POWERDOWN) == RB_POWERDOWN) {
138 		/* Power off if possible, hang otherwise */
139 		poweroff();
140 		NOT_REACHABLE;
141 	}
142 
143 	if(how & RB_HALT) {
144 		/* Hang */
145 		for (; ; ) halt_cpu();
146 		NOT_REACHABLE;
147 	}
148 
149 	/* Reset the system by forcing a processor shutdown.
150 	 * First stop the BIOS memory test by setting a soft
151 	 * reset flag.
152 	 */
153 	reset();
154 	NOT_REACHABLE;
155 }
156 
157 #ifdef DEBUG_SERIAL
158 void ser_putc(char c)
159 {
160         int i;
161         int lsr, thr;
162 
163 #if CONFIG_OXPCIE
164         oxpcie_putc(c);
165 #else
166         lsr= COM1_LSR;
167         thr= COM1_THR;
168         for (i= 0; i<100000; i++)
169         {
170                 if (inb( lsr) & LSR_THRE)
171                         break;
172         }
173         outb( thr, c);
174 #endif
175 }
176 
177 #endif
178