|
|
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.