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