xref: /netbsd/sys/arch/sgimips/sgimips/arcemu.c (revision a9ce3a65)
1 /*	$NetBSD: arcemu.c,v 1.24 2018/11/08 06:43:52 msaitoh Exp $	*/
2 
3 /*
4  * Copyright (c) 2004 Steve Rumble
5  * Copyright (c) 2004 Antti Kantee
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: arcemu.c,v 1.24 2018/11/08 06:43:52 msaitoh Exp $");
33 
34 #ifndef _LP64
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 
39 #include <machine/machtype.h>
40 #include <sys/bus.h>
41 
42 #include <dev/cons.h>
43 
44 #include <dev/arcbios/arcbios.h>
45 #include <dev/arcbios/arcbiosvar.h>
46 
47 #include <dev/ic/wd33c93reg.h>
48 
49 #define _ARCEMU_PRIVATE
50 #include <sgimips/sgimips/arcemu.h>
51 #include <sgimips/dev/picreg.h>
52 
53 static struct consdev arcemu_cn = {
54 	NULL,			/* probe */
55 	NULL,			/* init */
56 	NULL,			/* getc */ /* XXX: this would be nice */
57 	arcemu_prom_putc,	/* putc */
58 	nullcnpollc,		/* pollc */
59 	NULL,			/* bell */
60 	NULL,
61 	NULL,
62 	NODEV,
63 	CN_NORMAL,
64 };
65 
66 /*
67  * Emulate various ARCBIOS functions on pre-ARCS sgimips
68  * machines (<= IP17).
69  */
70 static struct arcbios_fv arcemu_v = {
71 	.Load =				ARCEMU_UNIMPL,
72 	.Invoke =			ARCEMU_UNIMPL,
73 	.Execute = 			ARCEMU_UNIMPL,
74 	.Halt =				ARCEMU_UNIMPL,
75 	.PowerDown =			ARCEMU_UNIMPL,
76 	.Restart = 			ARCEMU_UNIMPL,
77 	.Reboot =			ARCEMU_UNIMPL,
78 	.EnterInteractiveMode =		ARCEMU_UNIMPL,
79 	.ReturnFromMain =		0,
80 	.GetPeer =			ARCEMU_UNIMPL,
81 	.GetChild =			ARCEMU_UNIMPL,
82 	.GetParent =			ARCEMU_UNIMPL,
83 	.GetConfigurationData =		ARCEMU_UNIMPL,
84 	.AddChild =			ARCEMU_UNIMPL,
85 	.DeleteComponent =		ARCEMU_UNIMPL,
86 	.GetComponent =			ARCEMU_UNIMPL,
87 	.SaveConfiguration =		ARCEMU_UNIMPL,
88 	.GetSystemId =			ARCEMU_UNIMPL,
89 	.GetMemoryDescriptor =		ARCEMU_UNIMPL,
90 	.Signal =			0,
91 	.GetTime =			ARCEMU_UNIMPL,
92 	.GetRelativeTime =		ARCEMU_UNIMPL,
93 	.GetDirectoryEntry =		ARCEMU_UNIMPL,
94 	.Open =				ARCEMU_UNIMPL,
95 	.Close =			ARCEMU_UNIMPL,
96 	.Read =				ARCEMU_UNIMPL,
97 	.GetReadStatus =		ARCEMU_UNIMPL,
98 	.Write =			ARCEMU_UNIMPL,
99 	.Seek =				ARCEMU_UNIMPL,
100 	.Mount =			ARCEMU_UNIMPL,
101 	.GetEnvironmentVariable =	ARCEMU_UNIMPL,
102 	.SetEnvironmentVariable =	ARCEMU_UNIMPL,
103 	.GetFileInformation =		ARCEMU_UNIMPL,
104 	.SetFileInformation =		ARCEMU_UNIMPL,
105 	.FlushAllCaches =		ARCEMU_UNIMPL
106 };
107 
108 /*
109  * Establish our emulated ARCBIOS vector or return ARCBIOS failure.
110  */
111 int
arcemu_init(const char ** env)112 arcemu_init(const char **env)
113 {
114 	switch ((mach_type = arcemu_identify())) {
115 	case MACH_SGI_IP6 | MACH_SGI_IP10:
116 	case MACH_SGI_IP12:
117 		arcemu_ipN_init(ARCEMU_ENVOK(env) ? env : NULL);
118 		break;
119 
120 	default:
121 		return (1);
122 	}
123 
124 	ARCBIOS = &arcemu_v;
125 
126 	return (0);
127 }
128 
129 /*
130  * Attempt to identify the SGI IP%d platform. This is extra ugly since
131  * we don't yet have badaddr to fall back on.
132  */
133 static int
arcemu_identify(void)134 arcemu_identify(void)
135 {
136 	int mach;
137 
138 	/*
139 	 * Try to write a value to one of IP12's pic(4) graphics DMA registers.
140 	 * This is at the same location as four byte parity strobes on IP6,
141 	 * which appear to always read 0.
142 	 */
143 	*(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(0x1faa0000) = 0xdeadbeef;
144 	DELAY(1000);
145 	if (*(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(0x1faa0000) == 0xdeadbeef)
146 		mach = MACH_SGI_IP12;
147 	else
148 		mach = MACH_SGI_IP6;
149 	*(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(0x1faa0000) = 0;
150 	(void)*(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(0x1faa0000);
151 
152 	return (mach);
153 }
154 
155 static boolean_t
extractenv(const char ** env,const char * key,char * dest,int len)156 extractenv(const char **env, const char *key, char *dest, int len)
157 {
158 	int i;
159 
160 	if (env == NULL)
161 		return (false);
162 
163 	for (i = 0; env[i] != NULL; i++) {
164 		if (strncasecmp(env[i], key, strlen(key)) == 0 &&
165 		    env[i][strlen(key)] == '=') {
166 			strlcpy(dest, strchr(env[i], '=') + 1, len);
167 			return (true);
168 		}
169 	}
170 
171 	return (false);
172 }
173 
174 /* Prom Vectors */
175 static void   (*sgi_prom_reset)(void) = (void *)MIPS_PHYS_TO_KSEG1(0x1fc00000);
176 static void   (*sgi_prom_reinit)(void) =(void *)MIPS_PHYS_TO_KSEG1(0x1fc00018);
177 static int    (*sgi_prom_printf)(const char *, ...) =
178 					 (void *)MIPS_PHYS_TO_KSEG1(0x1fc00080);
179 
180 /*
181  * The following matches IP6's and IP12's NVRAM memory layout
182  */
183 static struct arcemu_nvramdata {
184 	char bootmode;
185 	char state;
186 	char netaddr[16];
187 	char lbaud[5];
188 	char rbaud[5];
189 	char console;
190 	char sccolor[6];
191 	char pgcolor[6];
192 	char lgcolor[6];
193 	char keydb;
194 	char pad0;
195 	char checksum;
196 	char diskless;
197 	char nokdb;
198 	char bootfile[50];
199 	char passwd[17];
200 	char volume[3];
201 	uint8_t enaddr[6];
202 } nvram;
203 
204 static char enaddr[18];
205 
206 static struct arcemu_sgienv {
207 	char dbaud[5];
208 	char rbaud[5];
209 	char bootmode;
210 	char console;
211 	char diskless;
212 	char volume[4];
213 	char cpufreq[3];
214 	char gfx[32];
215 	char netaddr[32];
216 	char dlserver[32];
217 	char osloadoptions[32];
218 } sgienv;
219 
220 /*
221  * EEPROM reading routines. IP6's wiring is sufficiently ugly and the routine
222  * sufficiently small that we just roll our own, rather than contorting the MD
223  * driver.
224  */
225 static void
eeprom_read(uint8_t * eeprom_buf,size_t len,int is_cs56,void (* set_pre)(int),void (* set_cs)(int),void (* set_sk)(int),int (* get_do)(void),void (* set_di)(int))226 eeprom_read(uint8_t *eeprom_buf, size_t len, int is_cs56,
227     void (*set_pre)(int), void (*set_cs)(int), void (*set_sk)(int),
228     int (*get_do)(void), void (*set_di)(int))
229 {
230 	int i, j;
231 
232 	for (i = 0; i < (len / 2); i++) {
233 		uint16_t instr = 0xc000 | (i << ((is_cs56) ? 5 : 7));
234 		uint16_t bitword = 0;
235 
236 		set_di(0);
237 		set_sk(0);
238 		set_pre(0);
239 		set_cs(0);
240 		set_cs(1);
241 		set_sk(1);
242 
243 		for (j = 0; j < ((is_cs56) ? 11 : 9); j++) {
244 			set_di(instr & 0x8000);
245 			set_sk(0);
246 			set_sk(1);
247 			instr <<= 1;
248 		}
249 
250 		set_di(0);
251 
252 		for (j = 0; j < 17; j++) {
253 			bitword = (bitword << 1) | get_do();
254 			set_sk(0);
255 			set_sk(1);
256 		}
257 
258 		eeprom_buf[i * 2 + 0] = bitword >> 8;
259 		eeprom_buf[i * 2 + 1] = bitword & 0xff;
260 
261 		set_sk(0);
262 		set_cs(0);
263 	}
264 }
265 
266 /*
267  * Read the EEPROM. It's not clear which machines have which parts, and
268  * there's a difference in instruction length between the two. We'll try
269  * both and see which doesn't give us garbage.
270  */
271 static void
arcemu_eeprom_read(void)272 arcemu_eeprom_read(void)
273 {
274 	int i;
275 
276 	/* try long instruction length first (the only one I've seen) */
277 	for (i = 1; i >= 0; i--) {
278 		if (mach_type == (MACH_SGI_IP6 | MACH_SGI_IP10)) {
279 			eeprom_read((uint8_t *)&nvram, sizeof(nvram), i,
280 			    ip6_set_pre, ip6_set_cs, ip6_set_sk,
281 			    ip6_get_do,  ip6_set_di);
282 		} else {
283 			eeprom_read((uint8_t *)&nvram, sizeof(nvram), i,
284 			    ip12_set_pre, ip12_set_cs, ip12_set_sk,
285 			    ip12_get_do,  ip12_set_di);
286 		}
287 
288 		if (nvram.enaddr[0] == 0x08 && nvram.enaddr[1] == 0x00 &&
289 		    nvram.enaddr[2] == 0x69)
290 			break;
291 
292 		if (memcmp(nvram.lbaud, "9600\x0", 5) == 0)
293 			break;
294 
295 		if (memcmp(nvram.bootfile, "dksc(", 5) == 0 ||
296 		    memcmp(nvram.bootfile, "bootp(", 6) == 0)
297 			break;
298 	}
299 
300 	/* cache enaddr string */
301 	snprintf(enaddr, sizeof(enaddr), "%02x:%02x:%02x:%02x:%02x:%02x",
302 	    nvram.enaddr[0],
303 	    nvram.enaddr[1],
304 	    nvram.enaddr[2],
305 	    nvram.enaddr[3],
306 	    nvram.enaddr[4],
307 	    nvram.enaddr[5]);
308 }
309 
310 static void
arcemu_ipN_init(const char ** env)311 arcemu_ipN_init(const char **env)
312 {
313 
314 	arcemu_v.GetPeer =		  (intptr_t)arcemu_GetPeer;
315 	arcemu_v.GetChild =		  (intptr_t)arcemu_GetChild;
316 	arcemu_v.GetEnvironmentVariable = (intptr_t)arcemu_GetEnvironmentVariable;
317 
318 	if (mach_type == MACH_SGI_IP6 || mach_type == MACH_SGI_IP10)
319 		arcemu_v.GetMemoryDescriptor = (intptr_t)arcemu_ip6_GetMemoryDescriptor;
320 	else if (mach_type == MACH_SGI_IP12)
321 		arcemu_v.GetMemoryDescriptor = (intptr_t)arcemu_ip12_GetMemoryDescriptor;
322 
323 	arcemu_v.Reboot =                 (intptr_t)sgi_prom_reset;
324 	arcemu_v.PowerDown =		  (intptr_t)sgi_prom_reinit;
325 	arcemu_v.EnterInteractiveMode =   (intptr_t)sgi_prom_reinit;
326 
327 	cn_tab = &arcemu_cn;
328 
329 	arcemu_eeprom_read();
330 
331 	memset(&sgienv, 0, sizeof(sgienv));
332 	extractenv(env, "dbaud", sgienv.dbaud, sizeof(sgienv.dbaud));
333 	extractenv(env, "rbaud", sgienv.rbaud, sizeof(sgienv.rbaud));
334 	extractenv(env, "bootmode",&sgienv.bootmode, sizeof(sgienv.bootmode));
335 	extractenv(env, "console", &sgienv.console, sizeof(sgienv.console));
336 	extractenv(env, "diskless",&sgienv.diskless, sizeof(sgienv.diskless));
337 	extractenv(env, "volume", sgienv.volume, sizeof(sgienv.volume));
338 	extractenv(env, "cpufreq", sgienv.cpufreq, sizeof(sgienv.cpufreq));
339 	extractenv(env, "gfx", sgienv.gfx, sizeof(sgienv.gfx));
340 	extractenv(env, "netaddr", sgienv.netaddr, sizeof(sgienv.netaddr));
341 	extractenv(env, "dlserver", sgienv.dlserver, sizeof(sgienv.dlserver));
342 	extractenv(env, "osloadoptions", sgienv.osloadoptions,
343 	    sizeof(sgienv.osloadoptions));
344 
345 	strcpy(arcbios_sysid_vendor, "SGI");
346 	if (mach_type == MACH_SGI_IP6 || mach_type == MACH_SGI_IP10) {
347 		strcpy(arcbios_system_identifier, "SGI-IP6");
348 		strcpy(arcbios_sysid_product, "IP6");
349 	} else if (mach_type == MACH_SGI_IP12) {
350 		strcpy(arcbios_system_identifier, "SGI-IP12");
351 		strcpy(arcbios_sysid_product, "IP12");
352 	}
353 }
354 
355 static void *
arcemu_GetPeer(void * node)356 arcemu_GetPeer(void *node)
357 {
358 	int i;
359 
360 	if (node == NULL)
361 		return (NULL);
362 
363 	for (i = 0; arcemu_component_tree[i].Class != -1; i++) {
364 		if (&arcemu_component_tree[i] == node &&
365 		     arcemu_component_tree[i+1].Class != -1)
366 			return (&arcemu_component_tree[i+1]);
367 	}
368 
369 	return (NULL);
370 }
371 
372 static void *
arcemu_GetChild(void * node)373 arcemu_GetChild(void *node)
374 {
375 
376 	/*
377 	 * ARCBIOS just walks the entire tree, so we'll represent our
378 	 * emulated tree as a single level and avoid messy hierarchies.
379 	 */
380 	if (node == NULL)
381 		return (&arcemu_component_tree[0]);
382 
383 	return (NULL);
384 }
385 
386 static const char *
arcemu_GetEnvironmentVariable(const char * var)387 arcemu_GetEnvironmentVariable(const char *var)
388 {
389 
390 	/* 'd'ebug (serial), 'g'raphics, 'G'raphics w/ logo */
391 
392 	/* XXX This does not indicate the actual current console */
393 	if (strcasecmp("ConsoleOut", var) == 0) {
394 		/* if no keyboard is attached, we should default to serial */
395 		if (strstr(sgienv.gfx, "dead") != NULL)
396 			return "serial(0)";
397 
398 		switch (nvram.console) {
399 		case 'd':
400 		case 'D':
401 		case 's':
402 		case 'S':
403 			return "serial(0)";
404 		case 'g':
405 		case 'G':
406 			return "video()";
407 		default:
408 			printf("arcemu: unknown console \"%c\", using serial\n",
409 			    nvram.console);
410 			return "serial(0)";
411 		}
412 	}
413 
414 	if (strcasecmp("cpufreq", var) == 0) {
415 		if (sgienv.cpufreq[0] != '\0')
416 			return (sgienv.cpufreq);
417 
418 		/* IP6 is 12, IP10 is 20 */
419 		if (mach_type == MACH_SGI_IP6 || mach_type == MACH_SGI_IP10)
420 			return ("16");
421 
422 		/* IP12 is 30, 33 or 36 */
423 		return ("33");
424 	}
425 
426 	if (strcasecmp("dbaud", var) == 0)
427 		return (nvram.lbaud);
428 
429 	if (strcasecmp("eaddr", var) == 0)
430 		return (enaddr);
431 
432 	if (strcasecmp("gfx", var) == 0) {
433 		if (sgienv.gfx[0] != '\0')
434 			return (sgienv.gfx);
435 	}
436 
437 	/*
438 	 * Ugly Kludge Alert!
439 	 *
440 	 * Since we don't yet have an ip12 bootloader, we can only squish
441 	 * a kernel into the volume header. However, this makes the bootfile
442 	 * something like 'dksc(0,1,8)', which translates into 'sd0i'. Ick.
443 	 * Munge what we return to always map to 'sd0a'. Lord have mercy.
444 	 *
445 	 * makebootdev() can handle "dksc(a,b,c)/netbsd", etc already
446 	 */
447 	if (strcasecmp("OSLoadPartition", var) == 0) {
448 		char *hack;
449 
450 		hack = strstr(nvram.bootfile, ",8)");
451 		if (hack != NULL)
452 			hack[1] = '0';
453 		return (nvram.bootfile);
454 	}
455 
456 	/* pull filename from e.g.: "dksc(0,1,0)netbsd" */
457 	if (strcasecmp("OSLoadFilename", var) == 0) {
458 		char *file;
459 
460 		if ((file = strrchr(nvram.bootfile, ')')) != NULL)
461 			return (file + 1);
462 		else
463 			return (NULL);
464 	}
465 
466 	/*
467 	 * As far as I can tell, old systems had no analogue of OSLoadOptions.
468 	 * So, to allow forcing of single user mode, we accommodate the
469 	 * user setting the ARCBIOSy environment variable "OSLoadOptions" to
470 	 * something other than "auto".
471 	 */
472 	if (strcasecmp("OSLoadOptions", var) == 0) {
473 		if (sgienv.osloadoptions[0] == '\0')
474 			return ("auto");
475 		else
476 			return (sgienv.osloadoptions);
477 	}
478 
479 	return (NULL);
480 }
481 
482 static void *
arcemu_ip6_GetMemoryDescriptor(void * mem)483 arcemu_ip6_GetMemoryDescriptor(void *mem)
484 {
485 	static struct arcbios_mem am;
486 	static int invoc;
487 
488 	unsigned int pages;
489 	u_int8_t memcfg;
490 
491 	if (mem == NULL) {
492 		/*
493 		 * We know pages 0, 1 are occupied, emulate the reserved space.
494 		 */
495 		am.Type = ARCBIOS_MEM_ExceptionBlock;
496 		am.BasePage = 0;
497 		am.PageCount = 2;
498 
499 		invoc = 0;
500 		return (&am);
501 	}
502 
503 	memcfg = *(volatile uint8_t *)MIPS_PHYS_TO_KSEG1(0x1f800000) & 0x1f;
504 	pages = (memcfg & 0x0f) + 1;
505 
506 	/* 4MB or 1MB units? */
507 	if (memcfg & 0x10) {
508 		pages *= 4096;
509 
510 #if 0 // may cause an exception and bring us down in flames; disable until tested
511 		/* check for aliasing and adjust page count if necessary */
512 		volatile uint8_t *tp1, *tp2;
513 		uint8_t tmp;
514 
515 		tp1 = (volatile uint8_t *)MIPS_PHYS_TO_KSEG1((pages - 4096) << 12);
516 		tp2 = tp1 + (4 * 1024 * 1024);
517 
518 		tmp = *tp1;
519 		*tp2 = ~tmp;
520 		if (*tp1 != tmp)
521 			pages -= (3 * 1024);
522 #endif
523 	} else {
524 		pages *= 1024;
525 	}
526 
527 	/*
528 	 * It appears that the PROM's stack is at 0x400000 in physical memory.
529 	 * Don't destroy it, and assume (based on IP12 specs), that the prom bss
530 	 * is below it at 0x380000. This is probably overly conservative.
531 	 *
532 	 * Also note that we preserve the first two pages.
533 	 */
534 	switch (invoc) {
535 	case 0:
536 		/* free: pages [2, 896) */
537 		am.BasePage = 2;
538 		am.PageCount = 894;
539 		am.Type = ARCBIOS_MEM_FreeContiguous;
540 		break;
541 
542 	case 1:
543 		/* prom bss/stack: pages [896, 1023) */
544 		am.BasePage = 896;
545 		am.PageCount = 128;
546 		am.Type = ARCBIOS_MEM_FirmwareTemporary;
547 		break;
548 
549 	case 2:
550 		/* free: pages [1024, ...) */
551 		am.BasePage = 1024;
552 		if (pages < 1024)
553 			am.PageCount = 0;
554 		else
555 			am.PageCount = pages - 1024;
556 		am.Type = ARCBIOS_MEM_FreeContiguous;
557 		break;
558 
559 	default:
560 		return (NULL);
561 	}
562 
563 	invoc++;
564 	return (&am);
565 }
566 
567 static void *
arcemu_ip12_GetMemoryDescriptor(void * mem)568 arcemu_ip12_GetMemoryDescriptor(void *mem)
569 {
570 	static int bank;
571 	u_int32_t memcfg;
572 	static struct arcbios_mem am;
573 
574 	if (mem == NULL) {
575 		/*
576 		 * We know pages 0, 1 are occupied, emulate the reserved space.
577 		 */
578 		am.Type = ARCBIOS_MEM_ExceptionBlock;
579 		am.BasePage = 0;
580 		am.PageCount = 2;
581 
582 		bank = 0;
583 		return (&am);
584 	}
585 
586 	if (bank > 3)
587 		return (NULL);
588 
589 	switch (bank) {
590 	case 0:
591 		memcfg = *(u_int32_t *)
592 		    MIPS_PHYS_TO_KSEG1(PIC_MEMCFG0_PHYSADDR) >> 16;
593 		break;
594 
595 	case 1:
596 		memcfg = *(u_int32_t *)
597 		    MIPS_PHYS_TO_KSEG1(PIC_MEMCFG0_PHYSADDR) & 0xffff;
598 		break;
599 
600 	case 2:
601 		memcfg = *(u_int32_t *)
602 		    MIPS_PHYS_TO_KSEG1(PIC_MEMCFG1_PHYSADDR) >> 16;
603 		break;
604 
605 	case 3:
606 		memcfg = *(u_int32_t *)
607 		    MIPS_PHYS_TO_KSEG1(PIC_MEMCFG1_PHYSADDR) & 0xffff;
608 		break;
609 
610 	default:
611 		memcfg = PIC_MEMCFG_BADADDR;
612 	}
613 
614 	if (memcfg == PIC_MEMCFG_BADADDR) {
615 		am.Type = ARCBIOS_MEM_BadMemory;
616 		am.BasePage =
617 		    PIC_MEMCFG_ADDR(PIC_MEMCFG_BADADDR) / ARCBIOS_PAGESIZE;
618 		am.PageCount = 0;
619 	} else {
620 		am.Type = ARCBIOS_MEM_FreeContiguous;
621 		am.BasePage = PIC_MEMCFG_ADDR(memcfg) / ARCBIOS_PAGESIZE;
622 		am.PageCount = PIC_MEMCFG_SIZ(memcfg) / ARCBIOS_PAGESIZE;
623 
624 		/* pages 0, 1 are occupied (if clause before switch), compensate */
625 		if (am.BasePage == 0) {
626 			am.BasePage = 2;
627 			am.PageCount -= 2;	/* won't overflow */
628 		}
629 	}
630 
631 	bank++;
632 	return (&am);
633 }
634 
635 /*
636  * If this breaks.. well.. then it breaks.
637  */
638 static void
arcemu_prom_putc(dev_t dummy,int c)639 arcemu_prom_putc(dev_t dummy, int c)
640 {
641 	sgi_prom_printf("%c", c);
642 }
643 
644 /* Unimplemented Vector */
645 static void
arcemu_unimpl(void)646 arcemu_unimpl(void)
647 {
648 
649 	panic("arcemu vector not established on IP%d", mach_type);
650 }
651 #endif /* !_LP64 */
652