Home | History | Annotate | Line # | Download | only in sgimips
      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
    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
    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
    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
    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
    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
    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 *
    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 *
    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 *
    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 *
    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 *
    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
    639 arcemu_prom_putc(dev_t dummy, int c)
    640 {
    641 	sgi_prom_printf("%c", c);
    642 }
    643 
    644 /* Unimplemented Vector */
    645 static void
    646 arcemu_unimpl(void)
    647 {
    648 
    649 	panic("arcemu vector not established on IP%d", mach_type);
    650 }
    651 #endif /* !_LP64 */
    652