1 /* $NetBSD: arcemu.c,v 1.27 2026/06/11 06:30:55 rumble 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.27 2026/06/11 06:30:55 rumble 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/sgimips/prom.h> 52 #include <sgimips/dev/picreg.h> 53 54 static struct consdev arcemu_cn = { 55 NULL, /* probe */ 56 NULL, /* init */ 57 NULL, /* getc */ /* XXX: this would be nice */ 58 arcemu_prom_putc, /* putc */ 59 nullcnpollc, /* pollc */ 60 NULL, /* bell */ 61 NULL, 62 NULL, 63 NODEV, 64 CN_NORMAL, 65 }; 66 67 /* 68 * Emulate various ARCBIOS functions on pre-ARCS sgimips 69 * machines (<= IP17). 70 */ 71 static struct arcbios_fv arcemu_v = { 72 .Load = ARCEMU_UNIMPL, 73 .Invoke = ARCEMU_UNIMPL, 74 .Execute = ARCEMU_UNIMPL, 75 .Halt = ARCEMU_UNIMPL, 76 .PowerDown = ARCEMU_UNIMPL, 77 .Restart = ARCEMU_UNIMPL, 78 .Reboot = ARCEMU_UNIMPL, 79 .EnterInteractiveMode = ARCEMU_UNIMPL, 80 .ReturnFromMain = 0, 81 .GetPeer = ARCEMU_UNIMPL, 82 .GetChild = ARCEMU_UNIMPL, 83 .GetParent = ARCEMU_UNIMPL, 84 .GetConfigurationData = ARCEMU_UNIMPL, 85 .AddChild = ARCEMU_UNIMPL, 86 .DeleteComponent = ARCEMU_UNIMPL, 87 .GetComponent = ARCEMU_UNIMPL, 88 .SaveConfiguration = ARCEMU_UNIMPL, 89 .GetSystemId = ARCEMU_UNIMPL, 90 .GetMemoryDescriptor = ARCEMU_UNIMPL, 91 .Signal = 0, 92 .GetTime = ARCEMU_UNIMPL, 93 .GetRelativeTime = ARCEMU_UNIMPL, 94 .GetDirectoryEntry = ARCEMU_UNIMPL, 95 .Open = ARCEMU_UNIMPL, 96 .Close = ARCEMU_UNIMPL, 97 .Read = ARCEMU_UNIMPL, 98 .GetReadStatus = ARCEMU_UNIMPL, 99 .Write = ARCEMU_UNIMPL, 100 .Seek = ARCEMU_UNIMPL, 101 .Mount = ARCEMU_UNIMPL, 102 .GetEnvironmentVariable = ARCEMU_UNIMPL, 103 .SetEnvironmentVariable = ARCEMU_UNIMPL, 104 .GetFileInformation = ARCEMU_UNIMPL, 105 .SetFileInformation = ARCEMU_UNIMPL, 106 .FlushAllCaches = ARCEMU_UNIMPL 107 }; 108 109 /* 110 * Establish our emulated ARCBIOS vector or return ARCBIOS failure. 111 */ 112 int 113 arcemu_init(const char **env) 114 { 115 switch ((mach_type = arcemu_identify())) { 116 case MACH_SGI_IP6 | MACH_SGI_IP10: 117 case MACH_SGI_IP12: 118 arcemu_ipN_init(ARCEMU_ENVOK(env) ? env : NULL); 119 break; 120 121 default: 122 return (1); 123 } 124 125 ARCBIOS = &arcemu_v; 126 127 return (0); 128 } 129 130 /* 131 * Attempt to identify the SGI IP%d platform. 132 */ 133 static int 134 arcemu_identify(void) 135 { 136 /* 137 * Since all pre-ARCS machines have PROMs at the same address, we just 138 * scan it for known IP-specific substrings. The smallest PROM is 139 * apparently 1Mbit, so we initially search only the first 128KB as 140 * badaddr isn't usable yet. 141 */ 142 static struct { 143 const char *pattern; 144 int mach_type; 145 } patterns[] = { 146 { "IP12/GR2 PROM", MACH_SGI_IP12 }, 147 { "IP6 Processor", MACH_SGI_IP6 }, 148 { " PROM IP6 ", MACH_SGI_IP6 }, 149 { " PROM IP4 ", MACH_SGI_IP4 }, 150 { " IP 9 ", MACH_SGI_IP9 }, 151 { " IP 7 ", MACH_SGI_IP7 }, 152 { " IP 5 ", MACH_SGI_IP5 }, 153 { NULL, -1 }, 154 }; 155 156 int mach = -1; 157 for (int i = 1; i < 3; i++) { 158 for (int j = 0; patterns[j].pattern != NULL; j++) { 159 int len = i * 128 * 1024; 160 if (memmem((void*)MIPS_PHYS_TO_KSEG1(0x1fc00000), len, 161 patterns[j].pattern, 162 strlen(patterns[j].pattern)) != NULL) { 163 mach = patterns[j].mach_type; 164 break; 165 } 166 } 167 } 168 169 if (mach == -1) { 170 sgi_prom_printf("Failed to identify Pre-ARCBIOS machine. " 171 "Assuming IP12.\n"); 172 return (MACH_SGI_IP12); 173 } 174 175 sgi_prom_printf("Pre-ARCBIOS machine identified as IP%d\n", 176 mach); 177 return (mach); 178 } 179 180 static boolean_t 181 extractenv(const char **env, const char *key, char *dest, int len) 182 { 183 int i; 184 185 if (env == NULL) 186 return (false); 187 188 for (i = 0; env[i] != NULL; i++) { 189 if (strncasecmp(env[i], key, strlen(key)) == 0 && 190 env[i][strlen(key)] == '=') { 191 strlcpy(dest, strchr(env[i], '=') + 1, len); 192 return (true); 193 } 194 } 195 196 return (false); 197 } 198 199 /* 200 * The following matches IP6's and IP12's NVRAM memory layout 201 */ 202 static struct arcemu_nvramdata { 203 char bootmode; 204 char state; 205 char netaddr[16]; 206 char lbaud[5]; 207 char rbaud[5]; 208 char console; 209 char sccolor[6]; 210 char pgcolor[6]; 211 char lgcolor[6]; 212 char keydb; 213 char pad0; 214 char checksum; 215 char diskless; 216 char nokdb; 217 char bootfile[50]; 218 char passwd[17]; 219 char volume[3]; 220 uint8_t enaddr[6]; 221 } nvram; 222 223 static char enaddr[18]; 224 225 static struct arcemu_sgienv { 226 char dbaud[5]; 227 char rbaud[5]; 228 char bootmode; 229 char console; 230 char diskless; 231 char volume[4]; 232 char cpufreq[3]; 233 char gfx[32]; 234 char netaddr[32]; 235 char dlserver[32]; 236 char osloadoptions[32]; 237 } sgienv; 238 239 /* 240 * EEPROM reading routines. IP6's wiring is sufficiently ugly and the routine 241 * sufficiently small that we just roll our own, rather than contorting the MD 242 * driver. 243 */ 244 static void 245 eeprom_read(uint8_t *eeprom_buf, size_t len, int is_cs56, 246 void (*set_pre)(int), void (*set_cs)(int), void (*set_sk)(int), 247 int (*get_do)(void), void (*set_di)(int)) 248 { 249 int i, j; 250 251 for (i = 0; i < (len / 2); i++) { 252 uint16_t instr = 0xc000 | (i << ((is_cs56) ? 5 : 7)); 253 uint16_t bitword = 0; 254 255 set_di(0); 256 set_sk(0); 257 set_pre(0); 258 set_cs(0); 259 set_cs(1); 260 set_sk(1); 261 262 for (j = 0; j < ((is_cs56) ? 11 : 9); j++) { 263 set_di(instr & 0x8000); 264 set_sk(0); 265 set_sk(1); 266 instr <<= 1; 267 } 268 269 set_di(0); 270 271 for (j = 0; j < 17; j++) { 272 bitword = (bitword << 1) | get_do(); 273 set_sk(0); 274 set_sk(1); 275 } 276 277 eeprom_buf[i * 2 + 0] = bitword >> 8; 278 eeprom_buf[i * 2 + 1] = bitword & 0xff; 279 280 set_sk(0); 281 set_cs(0); 282 } 283 } 284 285 /* 286 * Read the EEPROM. It's not clear which machines have which parts, and 287 * there's a difference in instruction length between the two. We'll try 288 * both and see which doesn't give us garbage. 289 */ 290 static void 291 arcemu_eeprom_read(void) 292 { 293 int i; 294 295 /* try long instruction length first (the only one I've seen) */ 296 for (i = 1; i >= 0; i--) { 297 if (mach_type == (MACH_SGI_IP6 | MACH_SGI_IP10)) { 298 eeprom_read((uint8_t *)&nvram, sizeof(nvram), i, 299 ip6_set_pre, ip6_set_cs, ip6_set_sk, 300 ip6_get_do, ip6_set_di); 301 } else { 302 eeprom_read((uint8_t *)&nvram, sizeof(nvram), i, 303 ip12_set_pre, ip12_set_cs, ip12_set_sk, 304 ip12_get_do, ip12_set_di); 305 } 306 307 if (nvram.enaddr[0] == 0x08 && nvram.enaddr[1] == 0x00 && 308 nvram.enaddr[2] == 0x69) 309 break; 310 311 if (memcmp(nvram.lbaud, "9600\x0", 5) == 0) 312 break; 313 314 if (memcmp(nvram.bootfile, "dksc(", 5) == 0 || 315 memcmp(nvram.bootfile, "bootp(", 6) == 0) 316 break; 317 } 318 319 /* cache enaddr string */ 320 snprintf(enaddr, sizeof(enaddr), "%02x:%02x:%02x:%02x:%02x:%02x", 321 nvram.enaddr[0], 322 nvram.enaddr[1], 323 nvram.enaddr[2], 324 nvram.enaddr[3], 325 nvram.enaddr[4], 326 nvram.enaddr[5]); 327 } 328 329 static void 330 arcemu_ipN_init(const char **env) 331 { 332 333 arcemu_v.GetPeer = (intptr_t)arcemu_GetPeer; 334 arcemu_v.GetChild = (intptr_t)arcemu_GetChild; 335 arcemu_v.GetEnvironmentVariable = (intptr_t)arcemu_GetEnvironmentVariable; 336 337 if (mach_type == MACH_SGI_IP6 || mach_type == MACH_SGI_IP10) 338 arcemu_v.GetMemoryDescriptor = (intptr_t)arcemu_ip6_GetMemoryDescriptor; 339 else if (mach_type == MACH_SGI_IP12) 340 arcemu_v.GetMemoryDescriptor = (intptr_t)arcemu_ip12_GetMemoryDescriptor; 341 342 arcemu_v.Reboot = (intptr_t)sgi_prom_reset; 343 arcemu_v.PowerDown = (intptr_t)sgi_prom_reinit; 344 arcemu_v.EnterInteractiveMode = (intptr_t)sgi_prom_reinit; 345 346 cn_tab = &arcemu_cn; 347 348 arcemu_eeprom_read(); 349 350 memset(&sgienv, 0, sizeof(sgienv)); 351 extractenv(env, "dbaud", sgienv.dbaud, sizeof(sgienv.dbaud)); 352 extractenv(env, "rbaud", sgienv.rbaud, sizeof(sgienv.rbaud)); 353 extractenv(env, "bootmode",&sgienv.bootmode, sizeof(sgienv.bootmode)); 354 extractenv(env, "console", &sgienv.console, sizeof(sgienv.console)); 355 extractenv(env, "diskless",&sgienv.diskless, sizeof(sgienv.diskless)); 356 extractenv(env, "volume", sgienv.volume, sizeof(sgienv.volume)); 357 extractenv(env, "cpufreq", sgienv.cpufreq, sizeof(sgienv.cpufreq)); 358 extractenv(env, "gfx", sgienv.gfx, sizeof(sgienv.gfx)); 359 extractenv(env, "netaddr", sgienv.netaddr, sizeof(sgienv.netaddr)); 360 extractenv(env, "dlserver", sgienv.dlserver, sizeof(sgienv.dlserver)); 361 extractenv(env, "osloadoptions", sgienv.osloadoptions, 362 sizeof(sgienv.osloadoptions)); 363 364 strcpy(arcbios_sysid_vendor, "SGI"); 365 if (mach_type == MACH_SGI_IP6 || mach_type == MACH_SGI_IP10) { 366 strcpy(arcbios_system_identifier, "SGI-IP6"); 367 strcpy(arcbios_sysid_product, "IP6"); 368 } else if (mach_type == MACH_SGI_IP12) { 369 strcpy(arcbios_system_identifier, "SGI-IP12"); 370 strcpy(arcbios_sysid_product, "IP12"); 371 } 372 } 373 374 static void * 375 arcemu_GetPeer(void *node) 376 { 377 int i; 378 379 if (node == NULL) 380 return (NULL); 381 382 for (i = 0; arcemu_component_tree[i].Class != -1; i++) { 383 if (&arcemu_component_tree[i] == node && 384 arcemu_component_tree[i+1].Class != -1) 385 return (&arcemu_component_tree[i+1]); 386 } 387 388 return (NULL); 389 } 390 391 static void * 392 arcemu_GetChild(void *node) 393 { 394 395 /* 396 * ARCBIOS just walks the entire tree, so we'll represent our 397 * emulated tree as a single level and avoid messy hierarchies. 398 */ 399 if (node == NULL) 400 return (&arcemu_component_tree[0]); 401 402 return (NULL); 403 } 404 405 static const char * 406 arcemu_GetEnvironmentVariable(const char *var) 407 { 408 409 /* 'd'ebug (serial), 'g'raphics, 'G'raphics w/ logo */ 410 411 /* XXX This does not indicate the actual current console */ 412 if (strcasecmp("ConsoleOut", var) == 0) { 413 /* if no keyboard is attached, we should default to serial */ 414 if (strstr(sgienv.gfx, "dead") != NULL) 415 return "serial(0)"; 416 417 switch (nvram.console) { 418 case 'd': 419 case 'D': 420 case 's': 421 case 'S': 422 return "serial(0)"; 423 case 'g': 424 case 'G': 425 return "video()"; 426 default: 427 printf("arcemu: unknown console \"%c\", using serial\n", 428 nvram.console); 429 return "serial(0)"; 430 } 431 } 432 433 if (strcasecmp("cpufreq", var) == 0) { 434 if (sgienv.cpufreq[0] != '\0') 435 return (sgienv.cpufreq); 436 437 /* IP6 is 12, IP10 is 20 */ 438 if (mach_type == MACH_SGI_IP6 || mach_type == MACH_SGI_IP10) 439 return ("16"); 440 441 /* IP12 is 30, 33 or 36 */ 442 return ("33"); 443 } 444 445 if (strcasecmp("dbaud", var) == 0) 446 return (nvram.lbaud); 447 448 if (strcasecmp("eaddr", var) == 0) 449 return (enaddr); 450 451 if (strcasecmp("gfx", var) == 0) { 452 if (sgienv.gfx[0] != '\0') 453 return (sgienv.gfx); 454 } 455 456 /* 457 * Ugly Kludge Alert! 458 * 459 * Since we don't yet have an ip12 bootloader, we can only squish 460 * a kernel into the volume header. However, this makes the bootfile 461 * something like 'dksc(0,1,8)', which translates into 'sd0i'. Ick. 462 * Munge what we return to always map to 'sd0a'. Lord have mercy. 463 * 464 * makebootdev() can handle "dksc(a,b,c)/netbsd", etc already 465 */ 466 if (strcasecmp("OSLoadPartition", var) == 0) { 467 char *hack; 468 469 hack = strstr(nvram.bootfile, ",8)"); 470 if (hack != NULL) 471 hack[1] = '0'; 472 return (nvram.bootfile); 473 } 474 475 /* pull filename from e.g.: "dksc(0,1,0)netbsd" */ 476 if (strcasecmp("OSLoadFilename", var) == 0) { 477 char *file; 478 479 if ((file = strrchr(nvram.bootfile, ')')) != NULL) 480 return (file + 1); 481 else 482 return (NULL); 483 } 484 485 /* 486 * As far as I can tell, old systems had no analogue of OSLoadOptions. 487 * So, to allow forcing of single user mode, we accommodate the 488 * user setting the ARCBIOSy environment variable "OSLoadOptions" to 489 * something other than "auto". 490 */ 491 if (strcasecmp("OSLoadOptions", var) == 0) { 492 if (sgienv.osloadoptions[0] == '\0') 493 return ("auto"); 494 else 495 return (sgienv.osloadoptions); 496 } 497 498 return (NULL); 499 } 500 501 static void * 502 arcemu_ip6_GetMemoryDescriptor(void *mem) 503 { 504 static struct arcbios_mem am; 505 static int invoc; 506 507 unsigned int pages; 508 u_int8_t memcfg; 509 510 if (mem == NULL) { 511 /* 512 * We know pages 0, 1 are occupied, emulate the reserved space. 513 */ 514 am.Type = ARCBIOS_MEM_ExceptionBlock; 515 am.BasePage = 0; 516 am.PageCount = 2; 517 518 invoc = 0; 519 return (&am); 520 } 521 522 memcfg = *(volatile uint8_t *)MIPS_PHYS_TO_KSEG1(0x1f800000) & 0x1f; 523 pages = (memcfg & 0x0f) + 1; 524 525 /* 4MB or 1MB units? */ 526 if (memcfg & 0x10) { 527 pages *= 4096; 528 529 #if 0 // may cause an exception and bring us down in flames; disable until tested 530 /* check for aliasing and adjust page count if necessary */ 531 volatile uint8_t *tp1, *tp2; 532 uint8_t tmp; 533 534 tp1 = (volatile uint8_t *)MIPS_PHYS_TO_KSEG1((pages - 4096) << 12); 535 tp2 = tp1 + (4 * 1024 * 1024); 536 537 tmp = *tp1; 538 *tp2 = ~tmp; 539 if (*tp1 != tmp) 540 pages -= (3 * 1024); 541 #endif 542 } else { 543 pages *= 1024; 544 } 545 546 /* 547 * It appears that the PROM's stack is at 0x400000 in physical memory. 548 * Don't destroy it, and assume (based on IP12 specs), that the prom bss 549 * is below it at 0x380000. This is probably overly conservative. 550 * 551 * Also note that we preserve the first two pages. 552 */ 553 switch (invoc) { 554 case 0: 555 /* free: pages [2, 896) */ 556 am.BasePage = 2; 557 am.PageCount = 894; 558 am.Type = ARCBIOS_MEM_FreeContiguous; 559 break; 560 561 case 1: 562 /* prom bss/stack: pages [896, 1023) */ 563 am.BasePage = 896; 564 am.PageCount = 128; 565 am.Type = ARCBIOS_MEM_FirmwareTemporary; 566 break; 567 568 case 2: 569 /* free: pages [1024, ...) */ 570 am.BasePage = 1024; 571 if (pages < 1024) 572 am.PageCount = 0; 573 else 574 am.PageCount = pages - 1024; 575 am.Type = ARCBIOS_MEM_FreeContiguous; 576 break; 577 578 default: 579 return (NULL); 580 } 581 582 invoc++; 583 return (&am); 584 } 585 586 static struct arcbios_mem 587 arcemu_mem(int type, int base, int count) 588 { 589 struct arcbios_mem am = { 590 .Type = type, 591 .BasePage = base, 592 .PageCount = count 593 }; 594 return am; 595 } 596 597 /* 598 * Real ARCBIOS reports the first 2 pages as 'Exception' and 'SystemParameter' 599 * blocks. We just use one descriptor for both. 600 * 601 * Real ARCBIOS also reports where the kernel was loaded as LoadedProgram, but 602 * we can just advertise it as free memory here (machdep code sorts out where 603 * the kernel is anyway). 604 */ 605 static void * 606 arcemu_ip12_GetMemoryDescriptor(void *mem) 607 { 608 static int call_num = 0; 609 static struct arcbios_mem am[8]; 610 static int num_am = 0; 611 612 if (num_am == 0) { 613 u_int32_t memcfg; 614 615 /* 616 * Pages [896,1024) -- 3.5MiB to 4MiB -- are PROM bss and stack. 617 * That should always be within a single bank, but on very low 618 * memory systems it might be in bank 1 instead of bank 0. 619 */ 620 621 for (int bank = 0; bank < 4; bank++) { 622 /* 623 * 'volatile' prevents the compiler from emitting 624 * 16-bit loads. 625 */ 626 switch (bank) { 627 case 0: 628 memcfg = *(volatile u_int32_t *) 629 MIPS_PHYS_TO_KSEG1(PIC_MEMCFG0_PHYSADDR) >> 16; 630 break; 631 632 case 1: 633 memcfg = *(volatile u_int32_t *) 634 MIPS_PHYS_TO_KSEG1(PIC_MEMCFG0_PHYSADDR) & 0xffff; 635 break; 636 637 case 2: 638 memcfg = *(volatile u_int32_t *) 639 MIPS_PHYS_TO_KSEG1(PIC_MEMCFG1_PHYSADDR) >> 16; 640 break; 641 642 case 3: 643 memcfg = *(volatile u_int32_t *) 644 MIPS_PHYS_TO_KSEG1(PIC_MEMCFG1_PHYSADDR) & 0xffff; 645 break; 646 } 647 648 const int pgsize = ARCBIOS_PAGESIZE; 649 int bp = PIC_MEMCFG_ADDR(memcfg) / pgsize; 650 int pc = PIC_MEMCFG_SIZ(memcfg) / pgsize; 651 int ep = bp + pc; 652 653 const int BadMemory = ARCBIOS_MEM_BadMemory; 654 const int FreeMemory = ARCBIOS_MEM_FreeContiguous; 655 const int ExceptionBlock = ARCBIOS_MEM_ExceptionBlock; 656 const int PromMemory = ARCBIOS_MEM_FirmwareTemporary; 657 658 if (memcfg == PIC_MEMCFG_BADADDR) { 659 sgi_prom_printf("Bank %d: No RAM present\n", bank); 660 am[num_am++] = arcemu_mem(BadMemory, bp, 0); 661 } else if (bp >= 1024) { 662 sgi_prom_printf("Bank %d base 0x%x pages %d\n", 663 bank, bp, pc); 664 am[num_am++] = arcemu_mem(FreeMemory, bp, pc); 665 } else { 666 sgi_prom_printf("Bank %d base 0x%x pages %d", 667 bank, bp, pc); 668 669 int reserved = 0; 670 671 /* Exclude exception block. */ 672 if (bp == 0) { 673 am[num_am++] = arcemu_mem( 674 ExceptionBlock, 0, 2); 675 bp += 2; 676 pc -= 2; 677 reserved += 2; 678 } 679 680 /* Exclude PROM bss/stack. */ 681 if (bp < 896 && ep >= 1024) { 682 am[num_am++] = arcemu_mem( 683 FreeMemory, bp, 896 - bp); 684 am[num_am++] = arcemu_mem( 685 PromMemory, 896, 128); 686 am[num_am++] = arcemu_mem( 687 FreeMemory, 1024, ep - 1024); 688 reserved += 128; 689 } else { 690 am[num_am++] = arcemu_mem( 691 FreeMemory, bp, pc); 692 } 693 694 if (reserved > 0) { 695 sgi_prom_printf(" (%d reserved)", 696 reserved); 697 } 698 sgi_prom_printf("\n"); 699 700 } 701 } 702 703 } 704 705 return ((call_num < num_am) ? &am[call_num++] : NULL); 706 } 707 708 /* 709 * If this breaks.. well.. then it breaks. 710 */ 711 static void 712 arcemu_prom_putc(dev_t dummy, int c) 713 { 714 sgi_prom_printf("%c", c); 715 } 716 717 /* Unimplemented Vector */ 718 static void 719 arcemu_unimpl(void) 720 { 721 722 panic("arcemu vector not established on IP%d", mach_type); 723 } 724 #endif /* !_LP64 */ 725