|
|
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: {
1.1.1.2 root 303: CPUState *env;
1.1 root 304: char buf[1024];
305: SetIRQFunc *set_irq;
306: void *pic;
307: m48t59_t *nvram;
1.1.1.5 ! root 308: int unin_memory;
1.1 root 309: int linux_boot, i;
310: unsigned long bios_offset, vga_bios_offset;
311: uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
312: ppc_def_t *def;
313: PCIBus *pci_bus;
314: const char *arch_name;
315: int vga_bios_size, bios_size;
316:
317: linux_boot = (kernel_filename != NULL);
318:
1.1.1.2 root 319: /* init CPUs */
320: env = cpu_init();
321: register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
322:
323: /* Register CPU as a 74x/75x */
324: /* XXX: CPU model (or PVR) should be provided on command line */
325: // ppc_find_by_name("750gx", &def); // Linux boot OK
326: // ppc_find_by_name("750fx", &def); // Linux boot OK
327: /* Linux does not boot on 750cxe (and probably other 750cx based)
328: * because it assumes it has 8 IBAT & DBAT pairs as it only have 4.
329: */
330: // ppc_find_by_name("750cxe", &def);
331: // ppc_find_by_name("750p", &def);
332: // ppc_find_by_name("740p", &def);
333: ppc_find_by_name("750", &def);
334: // ppc_find_by_name("740", &def);
335: // ppc_find_by_name("G3", &def);
336: // ppc_find_by_name("604r", &def);
337: // ppc_find_by_name("604e", &def);
338: // ppc_find_by_name("604", &def);
339: if (def == NULL) {
340: cpu_abort(env, "Unable to find PowerPC CPU definition\n");
341: }
342: cpu_ppc_register(env, def);
343:
344: /* Set time-base frequency to 100 Mhz */
345: cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
346:
347: env->osi_call = vga_osi_call;
348:
1.1 root 349: /* allocate RAM */
350: cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
351:
352: /* allocate and load BIOS */
353: bios_offset = ram_size + vga_ram_size;
354: snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
355: bios_size = load_image(buf, phys_ram_base + bios_offset);
356: if (bios_size < 0 || bios_size > BIOS_SIZE) {
357: fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf);
358: exit(1);
359: }
360: bios_size = (bios_size + 0xfff) & ~0xfff;
361: cpu_register_physical_memory((uint32_t)(-bios_size),
362: bios_size, bios_offset | IO_MEM_ROM);
363:
364: /* allocate and load VGA BIOS */
365: vga_bios_offset = bios_offset + bios_size;
366: snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
367: vga_bios_size = load_image(buf, phys_ram_base + vga_bios_offset + 8);
368: if (vga_bios_size < 0) {
369: /* if no bios is present, we can still work */
370: fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n", buf);
371: vga_bios_size = 0;
372: } else {
373: /* set a specific header (XXX: find real Apple format for NDRV
374: drivers) */
375: phys_ram_base[vga_bios_offset] = 'N';
376: phys_ram_base[vga_bios_offset + 1] = 'D';
377: phys_ram_base[vga_bios_offset + 2] = 'R';
378: phys_ram_base[vga_bios_offset + 3] = 'V';
379: cpu_to_be32w((uint32_t *)(phys_ram_base + vga_bios_offset + 4),
380: vga_bios_size);
381: vga_bios_size += 8;
382: }
383: vga_bios_size = (vga_bios_size + 0xfff) & ~0xfff;
384:
385: if (linux_boot) {
386: kernel_base = KERNEL_LOAD_ADDR;
387: /* now we can load the kernel */
388: kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
389: if (kernel_size < 0) {
390: fprintf(stderr, "qemu: could not load kernel '%s'\n",
391: kernel_filename);
392: exit(1);
393: }
394: /* load initrd */
395: if (initrd_filename) {
396: initrd_base = INITRD_LOAD_ADDR;
397: initrd_size = load_image(initrd_filename,
398: phys_ram_base + initrd_base);
399: if (initrd_size < 0) {
400: fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
401: initrd_filename);
402: exit(1);
403: }
404: } else {
405: initrd_base = 0;
406: initrd_size = 0;
407: }
408: boot_device = 'm';
409: } else {
410: kernel_base = 0;
411: kernel_size = 0;
412: initrd_base = 0;
413: initrd_size = 0;
414: }
415:
416: if (is_heathrow) {
417: isa_mem_base = 0x80000000;
418:
419: /* Register 2 MB of ISA IO space */
1.1.1.5 ! root 420: isa_mmio_init(0xfe000000, 0x00200000);
! 421:
1.1 root 422: /* init basic PC hardware */
1.1.1.4 root 423: pic = heathrow_pic_init(&heathrow_pic_mem_index);
424: set_irq = heathrow_pic_set_irq;
425: pci_bus = pci_grackle_init(0xfec00000, pic);
1.1.1.5 ! root 426: pci_vga_init(pci_bus, ds, phys_ram_base + ram_size,
! 427: ram_size, vga_ram_size,
! 428: vga_bios_offset, vga_bios_size);
1.1 root 429:
430: /* XXX: suppress that */
431: isa_pic = pic_init(pic_irq_request, NULL);
432:
433: /* XXX: use Mac Serial port */
1.1.1.2 root 434: serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
1.1 root 435:
436: for(i = 0; i < nb_nics; i++) {
1.1.1.3 root 437: if (!nd_table[i].model)
438: nd_table[i].model = "ne2k_pci";
1.1.1.5 ! root 439: pci_nic_init(pci_bus, &nd_table[i], -1);
1.1 root 440: }
441:
442: pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
443:
444: /* cuda also initialize ADB */
445: cuda_mem_index = cuda_init(set_irq, pic, 0x12);
446:
447: adb_kbd_init(&adb_bus);
448: adb_mouse_init(&adb_bus);
449:
450: {
451: MacIONVRAMState *nvr;
452: nvr = macio_nvram_init();
453: pmac_format_nvram_partition(nvr->data, 0x2000);
454: }
455:
456: macio_init(pci_bus, 0x0017);
457:
1.1.1.2 root 458: nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
1.1 root 459:
460: arch_name = "HEATHROW";
461: } else {
462: isa_mem_base = 0x80000000;
463:
464: /* Register 8 MB of ISA IO space */
1.1.1.5 ! root 465: isa_mmio_init(0xf2000000, 0x00800000);
1.1 root 466:
467: /* UniN init */
468: unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL);
469: cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory);
470:
1.1.1.4 root 471: pic = openpic_init(NULL, &openpic_mem_index, 1, &env);
472: set_irq = openpic_set_irq;
473: pci_bus = pci_pmac_init(pic);
1.1 root 474: /* init basic PC hardware */
1.1.1.5 ! root 475: pci_vga_init(pci_bus, ds, phys_ram_base + ram_size,
! 476: ram_size, vga_ram_size,
! 477: vga_bios_offset, vga_bios_size);
1.1 root 478:
479: /* XXX: suppress that */
480: isa_pic = pic_init(pic_irq_request, NULL);
481:
482: /* XXX: use Mac Serial port */
1.1.1.2 root 483: serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
1.1 root 484:
485: for(i = 0; i < nb_nics; i++) {
1.1.1.5 ! root 486: pci_ne2000_init(pci_bus, &nd_table[i], -1);
1.1 root 487: }
488:
489: #if 1
490: ide0_mem_index = pmac_ide_init(&bs_table[0], set_irq, pic, 0x13);
491: ide1_mem_index = pmac_ide_init(&bs_table[2], set_irq, pic, 0x14);
492: #else
493: pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
494: #endif
495: /* cuda also initialize ADB */
496: cuda_mem_index = cuda_init(set_irq, pic, 0x19);
497:
498: adb_kbd_init(&adb_bus);
499: adb_mouse_init(&adb_bus);
500:
501: macio_init(pci_bus, 0x0022);
502:
1.1.1.2 root 503: nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
1.1 root 504:
505: arch_name = "MAC99";
506: }
1.1.1.4 root 507:
508: if (usb_enabled) {
509: usb_ohci_init(pci_bus, 3, -1);
510: }
511:
1.1 root 512: if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
513: graphic_depth = 15;
514:
515: PPC_NVRAM_set_params(nvram, NVRAM_SIZE, arch_name, ram_size, boot_device,
516: kernel_base, kernel_size,
517: kernel_cmdline,
518: initrd_base, initrd_size,
519: /* XXX: need an option to load a NVRAM image */
520: 0,
521: graphic_width, graphic_height, graphic_depth);
522: /* No PCI init: the BIOS will do it */
523:
524: /* Special port to get debug messages from Open-Firmware */
525: register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
526: }
527:
528: static void ppc_core99_init(int ram_size, int vga_ram_size, int boot_device,
529: DisplayState *ds, const char **fd_filename,
530: int snapshot,
531: const char *kernel_filename,
532: const char *kernel_cmdline,
533: const char *initrd_filename)
534: {
535: ppc_chrp_init(ram_size, vga_ram_size, boot_device,
536: ds, fd_filename, snapshot,
537: kernel_filename, kernel_cmdline,
538: initrd_filename, 0);
539: }
540:
541: static void ppc_heathrow_init(int ram_size, int vga_ram_size, int boot_device,
542: DisplayState *ds, const char **fd_filename,
543: int snapshot,
544: const char *kernel_filename,
545: const char *kernel_cmdline,
546: const char *initrd_filename)
547: {
548: ppc_chrp_init(ram_size, vga_ram_size, boot_device,
549: ds, fd_filename, snapshot,
550: kernel_filename, kernel_cmdline,
551: initrd_filename, 1);
552: }
553:
554: QEMUMachine core99_machine = {
555: "mac99",
556: "Mac99 based PowerMAC",
557: ppc_core99_init,
558: };
559:
560: QEMUMachine heathrow_machine = {
561: "g3bw",
562: "Heathrow based PowerMAC",
563: ppc_heathrow_init,
564: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.