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