|
|
1.1 ! root 1: /* ! 2: * QEMU PPC CHRP/PMAC hardware System Emulator ! 3: * ! 4: * Copyright (c) 2004 Fabrice Bellard ! 5: * ! 6: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 7: * of this software and associated documentation files (the "Software"), to deal ! 8: * in the Software without restriction, including without limitation the rights ! 9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 10: * copies of the Software, and to permit persons to whom the Software is ! 11: * furnished to do so, subject to the following conditions: ! 12: * ! 13: * The above copyright notice and this permission notice shall be included in ! 14: * all copies or substantial portions of the Software. ! 15: * ! 16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 22: * THE SOFTWARE. ! 23: */ ! 24: #include "vl.h" ! 25: ! 26: #define BIOS_FILENAME "ppc_rom.bin" ! 27: #define VGABIOS_FILENAME "video.x" ! 28: #define NVRAM_SIZE 0x2000 ! 29: ! 30: #define KERNEL_LOAD_ADDR 0x01000000 ! 31: #define INITRD_LOAD_ADDR 0x01800000 ! 32: ! 33: /* MacIO devices (mapped inside the MacIO address space): CUDA, DBDMA, ! 34: NVRAM */ ! 35: ! 36: static int dbdma_mem_index; ! 37: static int cuda_mem_index; ! 38: static int ide0_mem_index = -1; ! 39: static int ide1_mem_index = -1; ! 40: static int openpic_mem_index = -1; ! 41: static int heathrow_pic_mem_index = -1; ! 42: static int macio_nvram_mem_index = -1; ! 43: ! 44: /* DBDMA: currently no op - should suffice right now */ ! 45: ! 46: static void dbdma_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) ! 47: { ! 48: printf("%s: 0x%08x <= 0x%08x\n", __func__, addr, value); ! 49: } ! 50: ! 51: static void dbdma_writew (void *opaque, target_phys_addr_t addr, uint32_t value) ! 52: { ! 53: } ! 54: ! 55: static void dbdma_writel (void *opaque, target_phys_addr_t addr, uint32_t value) ! 56: { ! 57: } ! 58: ! 59: static uint32_t dbdma_readb (void *opaque, target_phys_addr_t addr) ! 60: { ! 61: printf("%s: 0x%08x => 0x00000000\n", __func__, addr); ! 62: return 0; ! 63: } ! 64: ! 65: static uint32_t dbdma_readw (void *opaque, target_phys_addr_t addr) ! 66: { ! 67: return 0; ! 68: } ! 69: ! 70: static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr) ! 71: { ! 72: return 0; ! 73: } ! 74: ! 75: static CPUWriteMemoryFunc *dbdma_write[] = { ! 76: &dbdma_writeb, ! 77: &dbdma_writew, ! 78: &dbdma_writel, ! 79: }; ! 80: ! 81: static CPUReadMemoryFunc *dbdma_read[] = { ! 82: &dbdma_readb, ! 83: &dbdma_readw, ! 84: &dbdma_readl, ! 85: }; ! 86: ! 87: /* macio style NVRAM device */ ! 88: typedef struct MacIONVRAMState { ! 89: uint8_t data[0x2000]; ! 90: } MacIONVRAMState; ! 91: ! 92: static void macio_nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) ! 93: { ! 94: MacIONVRAMState *s = opaque; ! 95: addr = (addr >> 4) & 0x1fff; ! 96: s->data[addr] = value; ! 97: // printf("macio_nvram_writeb %04x = %02x\n", addr, value); ! 98: } ! 99: ! 100: static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr) ! 101: { ! 102: MacIONVRAMState *s = opaque; ! 103: uint32_t value; ! 104: ! 105: addr = (addr >> 4) & 0x1fff; ! 106: value = s->data[addr]; ! 107: // printf("macio_nvram_readb %04x = %02x\n", addr, value); ! 108: return value; ! 109: } ! 110: ! 111: static CPUWriteMemoryFunc *macio_nvram_write[] = { ! 112: &macio_nvram_writeb, ! 113: &macio_nvram_writeb, ! 114: &macio_nvram_writeb, ! 115: }; ! 116: ! 117: static CPUReadMemoryFunc *macio_nvram_read[] = { ! 118: &macio_nvram_readb, ! 119: &macio_nvram_readb, ! 120: &macio_nvram_readb, ! 121: }; ! 122: ! 123: static MacIONVRAMState *macio_nvram_init(void) ! 124: { ! 125: MacIONVRAMState *s; ! 126: s = qemu_mallocz(sizeof(MacIONVRAMState)); ! 127: if (!s) ! 128: return NULL; ! 129: macio_nvram_mem_index = cpu_register_io_memory(0, macio_nvram_read, ! 130: macio_nvram_write, s); ! 131: return s; ! 132: } ! 133: ! 134: static void macio_map(PCIDevice *pci_dev, int region_num, ! 135: uint32_t addr, uint32_t size, int type) ! 136: { ! 137: if (heathrow_pic_mem_index >= 0) { ! 138: cpu_register_physical_memory(addr + 0x00000, 0x1000, ! 139: heathrow_pic_mem_index); ! 140: } ! 141: cpu_register_physical_memory(addr + 0x08000, 0x1000, dbdma_mem_index); ! 142: cpu_register_physical_memory(addr + 0x16000, 0x2000, cuda_mem_index); ! 143: if (ide0_mem_index >= 0) ! 144: cpu_register_physical_memory(addr + 0x1f000, 0x1000, ide0_mem_index); ! 145: if (ide1_mem_index >= 0) ! 146: cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index); ! 147: if (openpic_mem_index >= 0) { ! 148: cpu_register_physical_memory(addr + 0x40000, 0x40000, ! 149: openpic_mem_index); ! 150: } ! 151: if (macio_nvram_mem_index >= 0) ! 152: cpu_register_physical_memory(addr + 0x60000, 0x20000, macio_nvram_mem_index); ! 153: } ! 154: ! 155: static void macio_init(PCIBus *bus, int device_id) ! 156: { ! 157: PCIDevice *d; ! 158: ! 159: d = pci_register_device(bus, "macio", sizeof(PCIDevice), ! 160: -1, NULL, NULL); ! 161: /* Note: this code is strongly inspirated from the corresponding code ! 162: in PearPC */ ! 163: d->config[0x00] = 0x6b; // vendor_id ! 164: d->config[0x01] = 0x10; ! 165: d->config[0x02] = device_id; ! 166: d->config[0x03] = device_id >> 8; ! 167: ! 168: d->config[0x0a] = 0x00; // class_sub = pci2pci ! 169: d->config[0x0b] = 0xff; // class_base = bridge ! 170: d->config[0x0e] = 0x00; // header_type ! 171: ! 172: d->config[0x3d] = 0x01; // interrupt on pin 1 ! 173: ! 174: dbdma_mem_index = cpu_register_io_memory(0, dbdma_read, dbdma_write, NULL); ! 175: ! 176: pci_register_io_region(d, 0, 0x80000, ! 177: PCI_ADDRESS_SPACE_MEM, macio_map); ! 178: } ! 179: ! 180: /* UniN device */ ! 181: static void unin_writel (void *opaque, target_phys_addr_t addr, uint32_t value) ! 182: { ! 183: } ! 184: ! 185: static uint32_t unin_readl (void *opaque, target_phys_addr_t addr) ! 186: { ! 187: return 0; ! 188: } ! 189: ! 190: static CPUWriteMemoryFunc *unin_write[] = { ! 191: &unin_writel, ! 192: &unin_writel, ! 193: &unin_writel, ! 194: }; ! 195: ! 196: static CPUReadMemoryFunc *unin_read[] = { ! 197: &unin_readl, ! 198: &unin_readl, ! 199: &unin_readl, ! 200: }; ! 201: ! 202: /* temporary frame buffer OSI calls for the video.x driver. The right ! 203: solution is to modify the driver to use VGA PCI I/Os */ ! 204: static int vga_osi_call(CPUState *env) ! 205: { ! 206: static int vga_vbl_enabled; ! 207: int linesize; ! 208: ! 209: // printf("osi_call R5=%d\n", env->gpr[5]); ! 210: ! 211: /* same handler as PearPC, coming from the original MOL video ! 212: driver. */ ! 213: switch(env->gpr[5]) { ! 214: case 4: ! 215: break; ! 216: case 28: /* set_vmode */ ! 217: if (env->gpr[6] != 1 || env->gpr[7] != 0) ! 218: env->gpr[3] = 1; ! 219: else ! 220: env->gpr[3] = 0; ! 221: break; ! 222: case 29: /* get_vmode_info */ ! 223: if (env->gpr[6] != 0) { ! 224: if (env->gpr[6] != 1 || env->gpr[7] != 0) { ! 225: env->gpr[3] = 1; ! 226: break; ! 227: } ! 228: } ! 229: env->gpr[3] = 0; ! 230: env->gpr[4] = (1 << 16) | 1; /* num_vmodes, cur_vmode */ ! 231: env->gpr[5] = (1 << 16) | 0; /* num_depths, cur_depth_mode */ ! 232: env->gpr[6] = (graphic_width << 16) | graphic_height; /* w, h */ ! 233: env->gpr[7] = 85 << 16; /* refresh rate */ ! 234: env->gpr[8] = (graphic_depth + 7) & ~7; /* depth (round to byte) */ ! 235: linesize = ((graphic_depth + 7) >> 3) * graphic_width; ! 236: linesize = (linesize + 3) & ~3; ! 237: env->gpr[9] = (linesize << 16) | 0; /* row_bytes, offset */ ! 238: break; ! 239: case 31: /* set_video power */ ! 240: env->gpr[3] = 0; ! 241: break; ! 242: case 39: /* video_ctrl */ ! 243: if (env->gpr[6] == 0 || env->gpr[6] == 1) ! 244: vga_vbl_enabled = env->gpr[6]; ! 245: env->gpr[3] = 0; ! 246: break; ! 247: case 47: ! 248: break; ! 249: case 59: /* set_color */ ! 250: /* R6 = index, R7 = RGB */ ! 251: env->gpr[3] = 0; ! 252: break; ! 253: case 64: /* get color */ ! 254: /* R6 = index */ ! 255: env->gpr[3] = 0; ! 256: break; ! 257: case 116: /* set hwcursor */ ! 258: /* R6 = x, R7 = y, R8 = visible, R9 = data */ ! 259: break; ! 260: default: ! 261: fprintf(stderr, "unsupported OSI call R5=%08x\n", env->gpr[5]); ! 262: break; ! 263: } ! 264: return 1; /* osi_call handled */ ! 265: } ! 266: ! 267: /* XXX: suppress that */ ! 268: static void pic_irq_request(void *opaque, int level) ! 269: { ! 270: } ! 271: ! 272: static uint8_t nvram_chksum(const uint8_t *buf, int n) ! 273: { ! 274: int sum, i; ! 275: sum = 0; ! 276: for(i = 0; i < n; i++) ! 277: sum += buf[i]; ! 278: return (sum & 0xff) + (sum >> 8); ! 279: } ! 280: ! 281: /* set a free Mac OS NVRAM partition */ ! 282: void pmac_format_nvram_partition(uint8_t *buf, int len) ! 283: { ! 284: char partition_name[12] = "wwwwwwwwwwww"; ! 285: ! 286: buf[0] = 0x7f; /* free partition magic */ ! 287: buf[1] = 0; /* checksum */ ! 288: buf[2] = len >> 8; ! 289: buf[3] = len; ! 290: memcpy(buf + 4, partition_name, 12); ! 291: buf[1] = nvram_chksum(buf, 16); ! 292: } ! 293: ! 294: /* PowerPC CHRP hardware initialisation */ ! 295: static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, ! 296: DisplayState *ds, const char **fd_filename, ! 297: int snapshot, ! 298: const char *kernel_filename, ! 299: const char *kernel_cmdline, ! 300: const char *initrd_filename, ! 301: int is_heathrow) ! 302: { ! 303: char buf[1024]; ! 304: SetIRQFunc *set_irq; ! 305: void *pic; ! 306: m48t59_t *nvram; ! 307: int PPC_io_memory, unin_memory; ! 308: int linux_boot, i; ! 309: unsigned long bios_offset, vga_bios_offset; ! 310: uint32_t kernel_base, kernel_size, initrd_base, initrd_size; ! 311: ppc_def_t *def; ! 312: PCIBus *pci_bus; ! 313: const char *arch_name; ! 314: int vga_bios_size, bios_size; ! 315: ! 316: linux_boot = (kernel_filename != NULL); ! 317: ! 318: /* allocate RAM */ ! 319: cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); ! 320: ! 321: /* allocate and load BIOS */ ! 322: bios_offset = ram_size + vga_ram_size; ! 323: snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); ! 324: bios_size = load_image(buf, phys_ram_base + bios_offset); ! 325: if (bios_size < 0 || bios_size > BIOS_SIZE) { ! 326: fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf); ! 327: exit(1); ! 328: } ! 329: bios_size = (bios_size + 0xfff) & ~0xfff; ! 330: cpu_register_physical_memory((uint32_t)(-bios_size), ! 331: bios_size, bios_offset | IO_MEM_ROM); ! 332: ! 333: /* allocate and load VGA BIOS */ ! 334: vga_bios_offset = bios_offset + bios_size; ! 335: snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); ! 336: vga_bios_size = load_image(buf, phys_ram_base + vga_bios_offset + 8); ! 337: if (vga_bios_size < 0) { ! 338: /* if no bios is present, we can still work */ ! 339: fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n", buf); ! 340: vga_bios_size = 0; ! 341: } else { ! 342: /* set a specific header (XXX: find real Apple format for NDRV ! 343: drivers) */ ! 344: phys_ram_base[vga_bios_offset] = 'N'; ! 345: phys_ram_base[vga_bios_offset + 1] = 'D'; ! 346: phys_ram_base[vga_bios_offset + 2] = 'R'; ! 347: phys_ram_base[vga_bios_offset + 3] = 'V'; ! 348: cpu_to_be32w((uint32_t *)(phys_ram_base + vga_bios_offset + 4), ! 349: vga_bios_size); ! 350: vga_bios_size += 8; ! 351: } ! 352: vga_bios_size = (vga_bios_size + 0xfff) & ~0xfff; ! 353: ! 354: if (linux_boot) { ! 355: kernel_base = KERNEL_LOAD_ADDR; ! 356: /* now we can load the kernel */ ! 357: kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base); ! 358: if (kernel_size < 0) { ! 359: fprintf(stderr, "qemu: could not load kernel '%s'\n", ! 360: kernel_filename); ! 361: exit(1); ! 362: } ! 363: /* load initrd */ ! 364: if (initrd_filename) { ! 365: initrd_base = INITRD_LOAD_ADDR; ! 366: initrd_size = load_image(initrd_filename, ! 367: phys_ram_base + initrd_base); ! 368: if (initrd_size < 0) { ! 369: fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", ! 370: initrd_filename); ! 371: exit(1); ! 372: } ! 373: } else { ! 374: initrd_base = 0; ! 375: initrd_size = 0; ! 376: } ! 377: boot_device = 'm'; ! 378: } else { ! 379: kernel_base = 0; ! 380: kernel_size = 0; ! 381: initrd_base = 0; ! 382: initrd_size = 0; ! 383: } ! 384: /* Register CPU as a 74x/75x */ ! 385: /* XXX: CPU model (or PVR) should be provided on command line */ ! 386: // ppc_find_by_name("750gx", &def); // Linux boot OK ! 387: // ppc_find_by_name("750fx", &def); // Linux boot OK ! 388: /* Linux does not boot on 750cxe (and probably other 750cx based) ! 389: * because it assumes it has 8 IBAT & DBAT pairs as it only have 4. ! 390: */ ! 391: // ppc_find_by_name("750cxe", &def); ! 392: // ppc_find_by_name("750p", &def); ! 393: // ppc_find_by_name("740p", &def); ! 394: ppc_find_by_name("750", &def); ! 395: // ppc_find_by_name("740", &def); ! 396: // ppc_find_by_name("G3", &def); ! 397: // ppc_find_by_name("604r", &def); ! 398: // ppc_find_by_name("604e", &def); ! 399: // ppc_find_by_name("604", &def); ! 400: if (def == NULL) { ! 401: cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n"); ! 402: } ! 403: cpu_ppc_register(cpu_single_env, def); ! 404: ! 405: /* Set time-base frequency to 100 Mhz */ ! 406: cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); ! 407: ! 408: cpu_single_env->osi_call = vga_osi_call; ! 409: ! 410: if (is_heathrow) { ! 411: isa_mem_base = 0x80000000; ! 412: pci_bus = pci_grackle_init(0xfec00000); ! 413: ! 414: /* Register 2 MB of ISA IO space */ ! 415: PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); ! 416: cpu_register_physical_memory(0xfe000000, 0x00200000, PPC_io_memory); ! 417: ! 418: /* init basic PC hardware */ ! 419: vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ! 420: ram_size, vga_ram_size, ! 421: vga_bios_offset, vga_bios_size); ! 422: pic = heathrow_pic_init(&heathrow_pic_mem_index); ! 423: set_irq = heathrow_pic_set_irq; ! 424: pci_set_pic(pci_bus, set_irq, pic); ! 425: ! 426: /* XXX: suppress that */ ! 427: isa_pic = pic_init(pic_irq_request, NULL); ! 428: ! 429: /* XXX: use Mac Serial port */ ! 430: serial_init(0x3f8, 4, serial_hds[0]); ! 431: ! 432: for(i = 0; i < nb_nics; i++) { ! 433: pci_ne2000_init(pci_bus, &nd_table[i]); ! 434: } ! 435: ! 436: pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); ! 437: ! 438: /* cuda also initialize ADB */ ! 439: cuda_mem_index = cuda_init(set_irq, pic, 0x12); ! 440: ! 441: adb_kbd_init(&adb_bus); ! 442: adb_mouse_init(&adb_bus); ! 443: ! 444: { ! 445: MacIONVRAMState *nvr; ! 446: nvr = macio_nvram_init(); ! 447: pmac_format_nvram_partition(nvr->data, 0x2000); ! 448: } ! 449: ! 450: macio_init(pci_bus, 0x0017); ! 451: ! 452: nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE); ! 453: ! 454: arch_name = "HEATHROW"; ! 455: } else { ! 456: isa_mem_base = 0x80000000; ! 457: pci_bus = pci_pmac_init(); ! 458: ! 459: /* Register 8 MB of ISA IO space */ ! 460: PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); ! 461: cpu_register_physical_memory(0xF2000000, 0x00800000, PPC_io_memory); ! 462: ! 463: /* UniN init */ ! 464: unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL); ! 465: cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory); ! 466: ! 467: /* init basic PC hardware */ ! 468: vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ! 469: ram_size, vga_ram_size, ! 470: vga_bios_offset, vga_bios_size); ! 471: pic = openpic_init(NULL, &openpic_mem_index, 1); ! 472: set_irq = openpic_set_irq; ! 473: pci_set_pic(pci_bus, set_irq, pic); ! 474: ! 475: /* XXX: suppress that */ ! 476: isa_pic = pic_init(pic_irq_request, NULL); ! 477: ! 478: /* XXX: use Mac Serial port */ ! 479: serial_init(0x3f8, 4, serial_hds[0]); ! 480: ! 481: for(i = 0; i < nb_nics; i++) { ! 482: pci_ne2000_init(pci_bus, &nd_table[i]); ! 483: } ! 484: ! 485: #if 1 ! 486: ide0_mem_index = pmac_ide_init(&bs_table[0], set_irq, pic, 0x13); ! 487: ide1_mem_index = pmac_ide_init(&bs_table[2], set_irq, pic, 0x14); ! 488: #else ! 489: pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); ! 490: #endif ! 491: /* cuda also initialize ADB */ ! 492: cuda_mem_index = cuda_init(set_irq, pic, 0x19); ! 493: ! 494: adb_kbd_init(&adb_bus); ! 495: adb_mouse_init(&adb_bus); ! 496: ! 497: macio_init(pci_bus, 0x0022); ! 498: ! 499: nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE); ! 500: ! 501: arch_name = "MAC99"; ! 502: } ! 503: ! 504: if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) ! 505: graphic_depth = 15; ! 506: ! 507: PPC_NVRAM_set_params(nvram, NVRAM_SIZE, arch_name, ram_size, boot_device, ! 508: kernel_base, kernel_size, ! 509: kernel_cmdline, ! 510: initrd_base, initrd_size, ! 511: /* XXX: need an option to load a NVRAM image */ ! 512: 0, ! 513: graphic_width, graphic_height, graphic_depth); ! 514: /* No PCI init: the BIOS will do it */ ! 515: ! 516: /* Special port to get debug messages from Open-Firmware */ ! 517: register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL); ! 518: } ! 519: ! 520: static void ppc_core99_init(int ram_size, int vga_ram_size, int boot_device, ! 521: DisplayState *ds, const char **fd_filename, ! 522: int snapshot, ! 523: const char *kernel_filename, ! 524: const char *kernel_cmdline, ! 525: const char *initrd_filename) ! 526: { ! 527: ppc_chrp_init(ram_size, vga_ram_size, boot_device, ! 528: ds, fd_filename, snapshot, ! 529: kernel_filename, kernel_cmdline, ! 530: initrd_filename, 0); ! 531: } ! 532: ! 533: static void ppc_heathrow_init(int ram_size, int vga_ram_size, int boot_device, ! 534: DisplayState *ds, const char **fd_filename, ! 535: int snapshot, ! 536: const char *kernel_filename, ! 537: const char *kernel_cmdline, ! 538: const char *initrd_filename) ! 539: { ! 540: ppc_chrp_init(ram_size, vga_ram_size, boot_device, ! 541: ds, fd_filename, snapshot, ! 542: kernel_filename, kernel_cmdline, ! 543: initrd_filename, 1); ! 544: } ! 545: ! 546: QEMUMachine core99_machine = { ! 547: "mac99", ! 548: "Mac99 based PowerMAC", ! 549: ppc_core99_init, ! 550: }; ! 551: ! 552: QEMUMachine heathrow_machine = { ! 553: "g3bw", ! 554: "Heathrow based PowerMAC", ! 555: ppc_heathrow_init, ! 556: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.