1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/promif_impl.h>
30 #include <sys/uadmin.h>
31 #include <sys/machsystm.h>
32 #include <sys/hypervisor_api.h>
33 
34 #ifdef _KMDB
35 
36 extern int kmdb_dpi_get_master_cpuid(void);
37 extern void kmdb_dpi_kernpanic(int cpuid);
38 extern void prom_reboot(char *bootstr);
39 
40 #define	PIL_DECL(p)
41 #define	PIL_SET7(p)
42 #define	PIL_REST(p)
43 
44 #else
45 
46 extern int vx_handler(cell_t *argument_array);
47 
48 #define	PIL_DECL(p) int p
49 #define	PIL_SET7(p) (p = spl7())
50 #define	PIL_REST(p) (splx(p))
51 
52 #endif
53 
54 #define	PROMIF_ENTER	0
55 #define	PROMIF_EXIT	1
56 
57 #define	PROMIF_ISPRINT(c)	(((c) >= ' ') && ((c) <= '~'))
58 
59 static void promif_mon(int mode);
60 
61 /*ARGSUSED*/
62 int
63 promif_enter_mon(void *p)
64 {
65 	PIL_DECL(pil);
66 
67 	PIL_SET7(pil);
68 
69 	prom_printf("\n");
70 
71 #ifdef _KMDB
72 	promif_mon(PROMIF_ENTER);
73 #else
74 	idle_other_cpus();
75 	promif_mon(PROMIF_ENTER);
76 	resume_other_cpus();
77 #endif
78 
79 	PIL_REST(pil);
80 
81 	return (0);
82 }
83 
84 /*ARGSUSED*/
85 int
86 promif_exit_to_mon(void *p)
87 {
88 	PIL_DECL(pil);
89 
90 	PIL_SET7(pil);
91 
92 	prom_printf("Program terminated\n");
93 
94 	promif_mon(PROMIF_EXIT);
95 
96 	PIL_REST(pil);
97 
98 	return (0);
99 }
100 
101 static void
102 promif_mon(int mode)
103 {
104 	char		cmd;
105 	char		*prompt;
106 	boolean_t	invalid_option;
107 #ifdef _KMDB
108 	static char	*exit_prompt  = "r)eboot, h)alt? ";
109 #else
110 	char		value[ 8 ];	/* holds "true" or "false" */
111 	char		*boot_msg;
112 	static char	*null_msg = ".\" \"";
113 	static char	*ignore_msg =
114 	    "cr .\" Ignoring auto-boot? setting for this boot.\" cr";
115 	static char	*exit_prompt  = "r)eboot, o)k prompt, h)alt? ";
116 #endif
117 	static char	*enter_prompt = "c)ontinue, s)ync, r)eboot, h)alt? ";
118 
119 	prompt = (mode == PROMIF_EXIT) ? exit_prompt : enter_prompt;
120 
121 	for (;;) {
122 		prom_printf("%s", prompt);
123 
124 		while (hv_cngetchar((uint8_t *)&cmd) != H_EOK)
125 			;
126 
127 		prom_printf("%c\n", cmd);
128 
129 		invalid_option = B_FALSE;
130 
131 		switch (cmd) {
132 
133 		case 'r':
134 			/*
135 			 * Ideally, we would store the boot command string
136 			 * as we do in promif_reboot().  However, at this
137 			 * point the kernel is single-threaded and running
138 			 * at a high PIL.  This environment precludes
139 			 * setting ldom variables.
140 			 */
141 			prom_printf("Resetting...\n");
142 
143 			(void) hv_mach_sir();
144 
145 			/* should not return */
146 			ASSERT(0);
147 			break;
148 
149 		case 'h':
150 			(void) hv_mach_exit(0);
151 			ASSERT(0);
152 
153 			break;
154 
155 #ifndef _KMDB
156 		case 'o':
157 			/*
158 			 * This option gives the user an "ok" prompt after
159 			 * the system reset regardless of the value of
160 			 * auto-boot?  We offer this option because halt(1m)
161 			 * doesn't leave the user at the ok prompt (as it
162 			 * does on non-ldoms systems).  If auto-boot? is
163 			 * true tell user we are overriding the setting
164 			 * for this boot only.
165 			 */
166 			if (mode == PROMIF_EXIT) {
167 				bzero(value, sizeof (value));
168 				(void) promif_stree_getprop(prom_optionsnode(),
169 				    "auto-boot?", value);
170 				boot_msg = strcmp(value, "true") ? null_msg :
171 					ignore_msg;
172 				(void) promif_ldom_setprop("reboot-command",
173 				    boot_msg, strlen(boot_msg) + 1);
174 				(void) hv_mach_sir();
175 			} else {
176 				invalid_option = B_TRUE;
177 			}
178 			break;
179 #endif
180 
181 		case '\r':
182 			break;
183 
184 		case 's':
185 			if (mode == PROMIF_ENTER) {
186 #ifdef _KMDB
187 				kmdb_dpi_kernpanic(kmdb_dpi_get_master_cpuid());
188 #else
189 				cell_t arg = p1275_ptr2cell("sync");
190 				(void) vx_handler(&arg);
191 #endif
192 			} else {
193 				invalid_option = B_TRUE;
194 			}
195 			break;
196 
197 		case 'c':
198 			if (mode == PROMIF_ENTER) {
199 				return;
200 			} else {
201 				invalid_option = B_TRUE;
202 			}
203 			break;
204 
205 		default:
206 			invalid_option = B_TRUE;
207 			break;
208 		}
209 
210 		if (invalid_option && PROMIF_ISPRINT(cmd))
211 			prom_printf("invalid option (%c)\n", cmd);
212 	}
213 
214 	_NOTE(NOTREACHED)
215 }
216