xref: /openbsd-src/sys/arch/loongson/loongson/pmon.c (revision 363ad0d3d177ba23a0070b38cd0b620d8452b00d)
1 /*	$OpenBSD: pmon.c,v 1.8 2017/05/21 14:22:36 visa Exp $	*/
2 
3 /*
4  * Copyright (c) 2009, 2012 Miodrag Vallat.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/proc.h>
22 
23 #include <machine/cpu.h>
24 #include <machine/pmon.h>
25 
26 int	pmon_argc;
27 int32_t	*pmon_argv;
28 int32_t	*pmon_envp;
29 vaddr_t pmon_envbase;
30 int	pmon_envtype;
31 
32 void
pmon_init(int32_t argc,int32_t argv,int32_t envp,int32_t callvec,uint32_t prid)33 pmon_init(int32_t argc, int32_t argv, int32_t envp, int32_t callvec,
34     uint32_t prid)
35 {
36 	pmon_callvec = callvec;
37 
38 	pmon_argc = argc;
39 	/* sign extend pointers */
40 	pmon_argv = (int32_t *)(vaddr_t)argv;
41 	pmon_envp = (int32_t *)(vaddr_t)envp;
42 
43 	/*
44 	 * Those ``smart'' brains at Lemote have decided to change the way
45 	 * system information is passed from PMON to the kernel: earlier
46 	 * PMON versions pass the usual environment array, while newer
47 	 * versions pass a struct, without any form of magic number in it
48 	 * (beginner's mistake #1).
49 	 *
50 	 * Of course, to make things worse, quoting
51 	 * http://www.linux-mips.org/archives/linux-mips/2012-08/msg00233.html :
52 	 * ``All Loongson-based machines support this new interface except
53 	 * 2E/2F series.''
54 	 *
55 	 * This is obviously not true, there are 3A systems which pass the
56 	 * good old environment variables around... I have such a system here.
57 	 */
58 
59 	switch (prid & 0xff) {
60 	case 0x02:	/* 2E */
61 	case 0x03:	/* 2F */
62 		pmon_envtype = PMON_ENVTYPE_ENVP;
63 		pmon_envbase = CKSEG1_BASE;
64 		break;
65 	default:
66 	    {
67 		struct pmon_env *env = (struct pmon_env *)pmon_envp;
68 
69 		/*
70 		 * `pmon_envp' either points to an EFI struct or to a
71 		 * NULL-terminated array of 32-bit pointers.
72 		 *
73 		 * Since the EFI struct starts with a few 64 bit pointers,
74 		 * it should be easy to figure out which flavour we are
75 		 * facing by checking the top 32 bits of these 64 bit
76 		 * pointers.
77 		 *
78 		 * However, not all of these pointers are actually initialized
79 		 * by the firmware (beginner's mistake #2).  Therefore, we can
80 		 * only safely check the first two fields of the `smbios'
81 		 * struct:
82 		 * - the version number must be small
83 		 * - the `vga bios' pointer must point to the kseg0 segment.
84 		 *
85 		 * Of course, I can reasonably expect these assumptions to
86 		 * be broken in future systems.  Where would be the fun if
87 		 * not?
88 		 */
89 		if (env->efi.bios.version < 0x2000 &&
90 		    env->efi.bios.vga_bios >= CKSEG0_BASE &&
91 		    env->efi.bios.vga_bios < CKSEG0_BASE + CKSEG_SIZE) {
92 			pmon_envtype = PMON_ENVTYPE_EFI;
93 		} else {
94 			pmon_envtype = PMON_ENVTYPE_ENVP;
95 			pmon_envbase = CKSEG0_BASE;
96 		}
97 	    }
98 		break;
99 	}
100 
101 	/*
102 	 * Figure out where the environment pointers are supposed to live.
103 	 * Loongson 2[EF] systems use uncached memory, while 2G onwards
104 	 * apparently use cached memory.
105 	 */
106 	if (pmon_envtype == PMON_ENVTYPE_ENVP) {
107 		pmon_envbase = (uint64_t)*pmon_envp < CKSEG1_BASE ?
108 		    CKSEG0_BASE : CKSEG1_BASE;
109 	}
110 }
111 
112 const char *
pmon_getarg(const int argno)113 pmon_getarg(const int argno)
114 {
115 	if (argno < 0 || argno >= pmon_argc)
116 		return NULL;
117 
118 	return (const char *)(vaddr_t)pmon_argv[argno];
119 }
120 
121 int
pmon_getenvtype()122 pmon_getenvtype()
123 {
124 	return pmon_envtype;
125 }
126 
127 const char *
pmon_getenv(const char * var)128 pmon_getenv(const char *var)
129 {
130 	int32_t *envptr = pmon_envp;
131 	const char *envstr;
132 	size_t varlen;
133 
134 	if (envptr == NULL || pmon_envtype != PMON_ENVTYPE_ENVP)
135 		return NULL;
136 
137 	varlen = strlen(var);
138 	while (*envptr != 0) {
139 		envstr = (const char *)(vaddr_t)*envptr;
140 		/*
141 		 * There is a PMON2000 bug, at least on Lemote Yeeloong,
142 		 * which causes it to override part of the environment
143 		 * pointers array with the environment data itself.
144 		 *
145 		 * This only happens on cold boot, and if the BSD kernel
146 		 * is loaded without symbols (i.e. no option -k passed
147 		 * to the boot command).
148 		 *
149 		 * Until a suitable workaround is found or the bug is
150 		 * fixed, ignore broken environment information and
151 		 * tell the user (in case this prevents us from finding
152 		 * important information).
153 		 */
154 		if ((vaddr_t)envstr - pmon_envbase >= CKSEG_SIZE) {
155 			printf("WARNING! CORRUPTED ENVIRONMENT!\n");
156 			printf("Unable to search for \"%s\".\n", var);
157 #ifdef _STANDALONE
158 			printf("If boot fails, power-cycle the machine.\n");
159 #else
160 			printf("If the kernel fails to identify the system"
161 			    " type, please boot it again with `-k' option.\n");
162 #endif
163 
164 			/* terminate environment for further calls */
165 			*envptr = 0;
166 			break;
167 		}
168 		if (strncmp(envstr, var, varlen) == 0 &&
169 		    envstr[varlen] == '=')
170 			return envstr + varlen + 1;
171 		envptr++;
172 	}
173 
174 	return NULL;
175 }
176 
177 const struct pmon_env_reset *
pmon_get_env_reset(void)178 pmon_get_env_reset(void)
179 {
180 	struct pmon_env *env = (struct pmon_env *)pmon_envp;
181 
182 	if (pmon_envtype != PMON_ENVTYPE_EFI)
183 		return NULL;
184 
185 	return &env->reset;
186 }
187 
188 const struct pmon_env_smbios *
pmon_get_env_smbios(void)189 pmon_get_env_smbios(void)
190 {
191 	struct pmon_env *env = (struct pmon_env *)pmon_envp;
192 
193 	if (pmon_envtype != PMON_ENVTYPE_EFI)
194 		return NULL;
195 
196 	return &env->efi.bios;
197 }
198 
199 const struct pmon_env_mem *
pmon_get_env_mem(void)200 pmon_get_env_mem(void)
201 {
202 	struct pmon_env *env = (struct pmon_env *)pmon_envp;
203 	uint64_t va = (uint64_t)&env->efi.bios.ptrs;
204 
205 	if (pmon_envtype != PMON_ENVTYPE_EFI)
206 		return NULL;
207 
208 	return (const struct pmon_env_mem *)
209 	    (va + env->efi.bios.ptrs.offs_mem);
210 }
211 
212 const struct pmon_env_cpu *
pmon_get_env_cpu(void)213 pmon_get_env_cpu(void)
214 {
215 	struct pmon_env *env = (struct pmon_env *)pmon_envp;
216 	uint64_t va = (uint64_t)&env->efi.bios.ptrs;
217 
218 	if (pmon_envtype != PMON_ENVTYPE_EFI)
219 		return NULL;
220 
221 	return (const struct pmon_env_cpu *)
222 	    (va + env->efi.bios.ptrs.offs_cpu);
223 }
224 
225 const struct pmon_env_sys *
pmon_get_env_sys(void)226 pmon_get_env_sys(void)
227 {
228 	struct pmon_env *env = (struct pmon_env *)pmon_envp;
229 	uint64_t va = (uint64_t)&env->efi.bios.ptrs;
230 
231 	if (pmon_envtype != PMON_ENVTYPE_EFI)
232 		return NULL;
233 
234 	return (const struct pmon_env_sys *)
235 	    (va + env->efi.bios.ptrs.offs_sys);
236 }
237 
238 const struct pmon_env_irq *
pmon_get_env_irq(void)239 pmon_get_env_irq(void)
240 {
241 	struct pmon_env *env = (struct pmon_env *)pmon_envp;
242 	uint64_t va = (uint64_t)&env->efi.bios.ptrs;
243 
244 	if (pmon_envtype != PMON_ENVTYPE_EFI)
245 		return NULL;
246 
247 	return (const struct pmon_env_irq *)
248 	    (va + env->efi.bios.ptrs.offs_irq);
249 }
250 
251 const struct pmon_env_iface *
pmon_get_env_iface(void)252 pmon_get_env_iface(void)
253 {
254 	struct pmon_env *env = (struct pmon_env *)pmon_envp;
255 	uint64_t va = (uint64_t)&env->efi.bios.ptrs;
256 
257 	if (pmon_envtype != PMON_ENVTYPE_EFI)
258 		return NULL;
259 
260 	return (const struct pmon_env_iface *)
261 	    (va + env->efi.bios.ptrs.offs_iface);
262 }
263 
264 const struct pmon_env_special *
pmon_get_env_special(void)265 pmon_get_env_special(void)
266 {
267 	struct pmon_env *env = (struct pmon_env *)pmon_envp;
268 	uint64_t va = (uint64_t)&env->efi.bios.ptrs;
269 
270 	if (pmon_envtype != PMON_ENVTYPE_EFI)
271 		return NULL;
272 
273 	return (const struct pmon_env_special *)
274 	    (va + env->efi.bios.ptrs.offs_special);
275 }
276 
277 const struct pmon_env_device *
pmon_get_env_device(void)278 pmon_get_env_device(void)
279 {
280 	struct pmon_env *env = (struct pmon_env *)pmon_envp;
281 	uint64_t va = (uint64_t)&env->efi.bios.ptrs;
282 
283 	if (pmon_envtype != PMON_ENVTYPE_EFI)
284 		return NULL;
285 
286 	return (const struct pmon_env_device *)
287 	    (va + env->efi.bios.ptrs.offs_device);
288 }
289