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