]>
Commit | Line | Data |
---|---|---|
04e7ca8d LV |
1 | /* |
2 | * QEMU Motorla 680x0 Macintosh hardware System Emulator | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
5 | * of this software and associated documentation files (the "Software"), to deal | |
6 | * in the Software without restriction, including without limitation the rights | |
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
8 | * copies of the Software, and to permit persons to whom the Software is | |
9 | * furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
20 | * THE SOFTWARE. | |
21 | */ | |
22 | ||
23 | #include "qemu/osdep.h" | |
24 | #include "qemu/units.h" | |
2c65db5e | 25 | #include "qemu/datadir.h" |
693869a6 | 26 | #include "qemu/guest-random.h" |
04e7ca8d LV |
27 | #include "sysemu/sysemu.h" |
28 | #include "cpu.h" | |
04e7ca8d | 29 | #include "hw/boards.h" |
95264861 | 30 | #include "hw/or-irq.h" |
04e7ca8d LV |
31 | #include "elf.h" |
32 | #include "hw/loader.h" | |
33 | #include "ui/console.h" | |
04e7ca8d LV |
34 | #include "hw/char/escc.h" |
35 | #include "hw/sysbus.h" | |
36 | #include "hw/scsi/esp.h" | |
382d71af LV |
37 | #include "standard-headers/asm-m68k/bootinfo.h" |
38 | #include "standard-headers/asm-m68k/bootinfo-mac.h" | |
04e7ca8d | 39 | #include "bootinfo.h" |
a8019229 | 40 | #include "hw/m68k/q800.h" |
8e093280 | 41 | #include "hw/m68k/q800-glue.h" |
04e7ca8d | 42 | #include "hw/misc/mac_via.h" |
e2fd695e | 43 | #include "hw/misc/djmemc.h" |
bdc2c77d | 44 | #include "hw/misc/iosb.h" |
04e7ca8d LV |
45 | #include "hw/input/adb.h" |
46 | #include "hw/nubus/mac-nubus-bridge.h" | |
47 | #include "hw/display/macfb.h" | |
48 | #include "hw/block/swim.h" | |
49 | #include "net/net.h" | |
50 | #include "qapi/error.h" | |
cc37d98b | 51 | #include "qemu/error-report.h" |
04e7ca8d LV |
52 | #include "sysemu/qtest.h" |
53 | #include "sysemu/runstate.h" | |
54 | #include "sysemu/reset.h" | |
07e39012 | 55 | #include "migration/vmstate.h" |
04e7ca8d | 56 | |
e24e58e8 | 57 | #define MACROM_ADDR 0x40800000 |
04e7ca8d LV |
58 | #define MACROM_SIZE 0x00100000 |
59 | ||
60 | #define MACROM_FILENAME "MacROM.bin" | |
61 | ||
653901ca LV |
62 | #define IO_BASE 0x50000000 |
63 | #define IO_SLICE 0x00040000 | |
f18a2886 | 64 | #define IO_SLICE_MASK (IO_SLICE - 1) |
653901ca LV |
65 | #define IO_SIZE 0x04000000 |
66 | ||
67 | #define VIA_BASE (IO_BASE + 0x00000) | |
68 | #define SONIC_PROM_BASE (IO_BASE + 0x08000) | |
69 | #define SONIC_BASE (IO_BASE + 0x0a000) | |
70 | #define SCC_BASE (IO_BASE + 0x0c020) | |
e2fd695e | 71 | #define DJMEMC_BASE (IO_BASE + 0x0e000) |
653901ca LV |
72 | #define ESP_BASE (IO_BASE + 0x10000) |
73 | #define ESP_PDMA (IO_BASE + 0x10100) | |
74 | #define ASC_BASE (IO_BASE + 0x14000) | |
bdc2c77d | 75 | #define IOSB_BASE (IO_BASE + 0x18000) |
653901ca LV |
76 | #define SWIM_BASE (IO_BASE + 0x1E000) |
77 | ||
408c5733 MCA |
78 | #define SONIC_PROM_SIZE 0x1000 |
79 | ||
04e7ca8d LV |
80 | /* |
81 | * the video base, whereas it a Nubus address, | |
82 | * is needed by the kernel to have early display and | |
83 | * thus provided by the bootloader | |
84 | */ | |
df8abbba | 85 | #define VIDEO_BASE 0xf9000000 |
04e7ca8d LV |
86 | |
87 | #define MAC_CLOCK 3686418 | |
88 | ||
5ef25141 MCA |
89 | /* |
90 | * Slot 0x9 is reserved for use by the in-built framebuffer whilst only | |
91 | * slots 0xc, 0xd and 0xe physically exist on the Quadra 800 | |
92 | */ | |
93 | #define Q800_NUBUS_SLOTS_AVAILABLE (BIT(0x9) | BIT(0xc) | BIT(0xd) | \ | |
94 | BIT(0xe)) | |
95 | ||
e993af36 MCA |
96 | /* Quadra 800 machine ID */ |
97 | #define Q800_MACHINE_ID 0xa55a2bad | |
98 | ||
07e39012 | 99 | |
04e7ca8d LV |
100 | static void main_cpu_reset(void *opaque) |
101 | { | |
fbbbe7eb | 102 | M68kCPU *cpu = opaque; |
04e7ca8d LV |
103 | CPUState *cs = CPU(cpu); |
104 | ||
105 | cpu_reset(cs); | |
106 | cpu->env.aregs[7] = ldl_phys(cs->as, 0); | |
107 | cpu->env.pc = ldl_phys(cs->as, 4); | |
108 | } | |
109 | ||
fbbbe7eb JD |
110 | static void rerandomize_rng_seed(void *opaque) |
111 | { | |
112 | struct bi_record *rng_seed = opaque; | |
113 | qemu_guest_getrandom_nofail((void *)rng_seed->data + 2, | |
114 | be16_to_cpu(*(uint16_t *)rng_seed->data)); | |
115 | } | |
116 | ||
e24e58e8 JD |
117 | static uint8_t fake_mac_rom[] = { |
118 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
119 | ||
120 | /* offset: 0xa - mac_reset */ | |
121 | ||
122 | /* via2[vDirB] |= VIA2B_vPower */ | |
123 | 0x20, 0x7C, 0x50, 0xF0, 0x24, 0x00, /* moveal VIA2_BASE+vDirB,%a0 */ | |
124 | 0x10, 0x10, /* moveb %a0@,%d0 */ | |
125 | 0x00, 0x00, 0x00, 0x04, /* orib #4,%d0 */ | |
126 | 0x10, 0x80, /* moveb %d0,%a0@ */ | |
127 | ||
128 | /* via2[vBufB] &= ~VIA2B_vPower */ | |
129 | 0x20, 0x7C, 0x50, 0xF0, 0x20, 0x00, /* moveal VIA2_BASE+vBufB,%a0 */ | |
130 | 0x10, 0x10, /* moveb %a0@,%d0 */ | |
131 | 0x02, 0x00, 0xFF, 0xFB, /* andib #-5,%d0 */ | |
132 | 0x10, 0x80, /* moveb %d0,%a0@ */ | |
133 | ||
134 | /* while (true) ; */ | |
135 | 0x60, 0xFE /* bras [self] */ | |
136 | }; | |
137 | ||
f18a2886 MCA |
138 | static MemTxResult macio_alias_read(void *opaque, hwaddr addr, uint64_t *data, |
139 | unsigned size, MemTxAttrs attrs) | |
140 | { | |
141 | MemTxResult r; | |
142 | uint32_t val; | |
143 | ||
144 | addr &= IO_SLICE_MASK; | |
145 | addr |= IO_BASE; | |
146 | ||
147 | switch (size) { | |
148 | case 4: | |
149 | val = address_space_ldl_be(&address_space_memory, addr, attrs, &r); | |
150 | break; | |
151 | case 2: | |
152 | val = address_space_lduw_be(&address_space_memory, addr, attrs, &r); | |
153 | break; | |
154 | case 1: | |
155 | val = address_space_ldub(&address_space_memory, addr, attrs, &r); | |
156 | break; | |
157 | default: | |
158 | g_assert_not_reached(); | |
159 | } | |
160 | ||
161 | *data = val; | |
162 | return r; | |
163 | } | |
164 | ||
165 | static MemTxResult macio_alias_write(void *opaque, hwaddr addr, uint64_t value, | |
166 | unsigned size, MemTxAttrs attrs) | |
167 | { | |
168 | MemTxResult r; | |
169 | ||
170 | addr &= IO_SLICE_MASK; | |
171 | addr |= IO_BASE; | |
172 | ||
173 | switch (size) { | |
174 | case 4: | |
175 | address_space_stl_be(&address_space_memory, addr, value, attrs, &r); | |
176 | break; | |
177 | case 2: | |
178 | address_space_stw_be(&address_space_memory, addr, value, attrs, &r); | |
179 | break; | |
180 | case 1: | |
181 | address_space_stb(&address_space_memory, addr, value, attrs, &r); | |
182 | break; | |
183 | default: | |
184 | g_assert_not_reached(); | |
185 | } | |
186 | ||
187 | return r; | |
188 | } | |
189 | ||
190 | static const MemoryRegionOps macio_alias_ops = { | |
191 | .read_with_attrs = macio_alias_read, | |
192 | .write_with_attrs = macio_alias_write, | |
193 | .endianness = DEVICE_BIG_ENDIAN, | |
194 | .valid = { | |
195 | .min_access_size = 1, | |
196 | .max_access_size = 4, | |
197 | }, | |
198 | }; | |
199 | ||
e993af36 MCA |
200 | static uint64_t machine_id_read(void *opaque, hwaddr addr, unsigned size) |
201 | { | |
202 | return Q800_MACHINE_ID; | |
203 | } | |
204 | ||
205 | static void machine_id_write(void *opaque, hwaddr addr, uint64_t val, | |
206 | unsigned size) | |
207 | { | |
208 | return; | |
209 | } | |
210 | ||
211 | static const MemoryRegionOps machine_id_ops = { | |
212 | .read = machine_id_read, | |
213 | .write = machine_id_write, | |
214 | .endianness = DEVICE_BIG_ENDIAN, | |
215 | .valid = { | |
216 | .min_access_size = 4, | |
217 | .max_access_size = 4, | |
218 | }, | |
219 | }; | |
220 | ||
1a514d3a | 221 | static void q800_machine_init(MachineState *machine) |
04e7ca8d | 222 | { |
36e2e338 | 223 | Q800MachineState *m = Q800_MACHINE(machine); |
04e7ca8d LV |
224 | int linux_boot; |
225 | int32_t kernel_size; | |
226 | uint64_t elf_entry; | |
227 | char *filename; | |
228 | int bios_size; | |
229 | ram_addr_t initrd_base; | |
230 | int32_t initrd_size; | |
408c5733 MCA |
231 | MemoryRegion *dp8393x_prom = g_new(MemoryRegion, 1); |
232 | uint8_t *prom; | |
408c5733 | 233 | int i, checksum; |
df8abbba | 234 | MacFbMode *macfb_mode; |
04e7ca8d LV |
235 | ram_addr_t ram_size = machine->ram_size; |
236 | const char *kernel_filename = machine->kernel_filename; | |
237 | const char *initrd_filename = machine->initrd_filename; | |
238 | const char *kernel_cmdline = machine->kernel_cmdline; | |
1684273c | 239 | const char *bios_name = machine->firmware ?: MACROM_FILENAME; |
04e7ca8d LV |
240 | hwaddr parameters_base; |
241 | CPUState *cs; | |
242 | DeviceState *dev; | |
04e7ca8d LV |
243 | SysBusESPState *sysbus_esp; |
244 | ESPState *esp; | |
245 | SysBusDevice *sysbus; | |
246 | BusState *adb_bus; | |
247 | NubusBus *nubus; | |
eb064db9 | 248 | DriveInfo *dinfo; |
693869a6 | 249 | uint8_t rng_seed[32]; |
04e7ca8d LV |
250 | |
251 | linux_boot = (kernel_filename != NULL); | |
252 | ||
253 | if (ram_size > 1 * GiB) { | |
254 | error_report("Too much memory for this machine: %" PRId64 " MiB, " | |
255 | "maximum 1024 MiB", ram_size / MiB); | |
256 | exit(1); | |
257 | } | |
258 | ||
259 | /* init CPUs */ | |
36e2e338 MCA |
260 | object_initialize_child(OBJECT(machine), "cpu", &m->cpu, machine->cpu_type); |
261 | qdev_realize(DEVICE(&m->cpu), NULL, &error_fatal); | |
262 | qemu_register_reset(main_cpu_reset, &m->cpu); | |
04e7ca8d | 263 | |
653901ca | 264 | /* RAM */ |
8591a179 | 265 | memory_region_add_subregion(get_system_memory(), 0, machine->ram); |
04e7ca8d | 266 | |
7527c52f MCA |
267 | /* |
268 | * Create container for all IO devices | |
269 | */ | |
270 | memory_region_init(&m->macio, OBJECT(machine), "mac-io", IO_SLICE); | |
271 | memory_region_add_subregion(get_system_memory(), IO_BASE, &m->macio); | |
272 | ||
653901ca LV |
273 | /* |
274 | * Memory from IO_BASE to IO_BASE + IO_SLICE is repeated | |
275 | * from IO_BASE + IO_SLICE to IO_BASE + IO_SIZE | |
276 | */ | |
f18a2886 MCA |
277 | memory_region_init_io(&m->macio_alias, OBJECT(machine), &macio_alias_ops, |
278 | &m->macio, "mac-io.alias", IO_SIZE - IO_SLICE); | |
279 | memory_region_add_subregion(get_system_memory(), IO_BASE + IO_SLICE, | |
280 | &m->macio_alias); | |
653901ca | 281 | |
e993af36 MCA |
282 | memory_region_init_io(&m->machine_id, NULL, &machine_id_ops, NULL, |
283 | "Machine ID", 4); | |
284 | memory_region_add_subregion(get_system_memory(), 0x5ffffffc, | |
285 | &m->machine_id); | |
286 | ||
04e7ca8d | 287 | /* IRQ Glue */ |
1ecc6ec1 MCA |
288 | object_initialize_child(OBJECT(machine), "glue", &m->glue, TYPE_GLUE); |
289 | object_property_set_link(OBJECT(&m->glue), "cpu", OBJECT(&m->cpu), | |
36e2e338 | 290 | &error_abort); |
1ecc6ec1 | 291 | sysbus_realize(SYS_BUS_DEVICE(&m->glue), &error_fatal); |
04e7ca8d | 292 | |
e2fd695e MCA |
293 | /* djMEMC memory controller */ |
294 | object_initialize_child(OBJECT(machine), "djmemc", &m->djmemc, | |
295 | TYPE_DJMEMC); | |
296 | sysbus = SYS_BUS_DEVICE(&m->djmemc); | |
297 | sysbus_realize_and_unref(sysbus, &error_fatal); | |
298 | memory_region_add_subregion(&m->macio, DJMEMC_BASE - IO_BASE, | |
299 | sysbus_mmio_get_region(sysbus, 0)); | |
300 | ||
bdc2c77d MCA |
301 | /* IOSB subsystem */ |
302 | object_initialize_child(OBJECT(machine), "iosb", &m->iosb, TYPE_IOSB); | |
303 | sysbus = SYS_BUS_DEVICE(&m->iosb); | |
304 | sysbus_realize_and_unref(sysbus, &error_fatal); | |
305 | memory_region_add_subregion(&m->macio, IOSB_BASE - IO_BASE, | |
306 | sysbus_mmio_get_region(sysbus, 0)); | |
307 | ||
02a68a3e | 308 | /* VIA 1 */ |
6d32c064 MCA |
309 | object_initialize_child(OBJECT(machine), "via1", &m->via1, |
310 | TYPE_MOS6522_Q800_VIA1); | |
eb064db9 LV |
311 | dinfo = drive_get(IF_MTD, 0, 0); |
312 | if (dinfo) { | |
6d32c064 MCA |
313 | qdev_prop_set_drive(DEVICE(&m->via1), "drive", |
314 | blk_by_legacy_dinfo(dinfo)); | |
eb064db9 | 315 | } |
6d32c064 MCA |
316 | sysbus = SYS_BUS_DEVICE(&m->via1); |
317 | sysbus_realize(sysbus, &error_fatal); | |
f18a2886 MCA |
318 | memory_region_add_subregion(&m->macio, VIA_BASE - IO_BASE, |
319 | sysbus_mmio_get_region(sysbus, 1)); | |
1ecc6ec1 MCA |
320 | sysbus_connect_irq(sysbus, 0, |
321 | qdev_get_gpio_in(DEVICE(&m->glue), GLUE_IRQ_IN_VIA1)); | |
a85d18aa | 322 | /* A/UX mode */ |
6d32c064 | 323 | qdev_connect_gpio_out(DEVICE(&m->via1), 0, |
1ecc6ec1 MCA |
324 | qdev_get_gpio_in_named(DEVICE(&m->glue), |
325 | "auxmode", 0)); | |
02a68a3e | 326 | |
6d32c064 | 327 | adb_bus = qdev_get_child_bus(DEVICE(&m->via1), "adb.0"); |
3e80f690 MA |
328 | dev = qdev_new(TYPE_ADB_KEYBOARD); |
329 | qdev_realize_and_unref(dev, adb_bus, &error_fatal); | |
330 | dev = qdev_new(TYPE_ADB_MOUSE); | |
331 | qdev_realize_and_unref(dev, adb_bus, &error_fatal); | |
04e7ca8d | 332 | |
02a68a3e | 333 | /* VIA 2 */ |
d7942e16 MCA |
334 | object_initialize_child(OBJECT(machine), "via2", &m->via2, |
335 | TYPE_MOS6522_Q800_VIA2); | |
336 | sysbus = SYS_BUS_DEVICE(&m->via2); | |
337 | sysbus_realize(sysbus, &error_fatal); | |
f18a2886 MCA |
338 | memory_region_add_subregion(&m->macio, VIA_BASE - IO_BASE + VIA_SIZE, |
339 | sysbus_mmio_get_region(sysbus, 1)); | |
1ecc6ec1 MCA |
340 | sysbus_connect_irq(sysbus, 0, |
341 | qdev_get_gpio_in(DEVICE(&m->glue), GLUE_IRQ_IN_VIA2)); | |
02a68a3e | 342 | |
04e7ca8d LV |
343 | /* MACSONIC */ |
344 | ||
345 | if (nb_nics > 1) { | |
346 | error_report("q800 can only have one ethernet interface"); | |
347 | exit(1); | |
348 | } | |
349 | ||
350 | qemu_check_nic_model(&nd_table[0], "dp83932"); | |
351 | ||
352 | /* | |
353 | * MacSonic driver needs an Apple MAC address | |
354 | * Valid prefix are: | |
355 | * 00:05:02 Apple | |
356 | * 00:80:19 Dayna Communications, Inc. | |
357 | * 00:A0:40 Apple | |
358 | * 08:00:07 Apple | |
359 | * (Q800 use the last one) | |
360 | */ | |
361 | nd_table[0].macaddr.a[0] = 0x08; | |
362 | nd_table[0].macaddr.a[1] = 0x00; | |
363 | nd_table[0].macaddr.a[2] = 0x07; | |
364 | ||
804ae67e MCA |
365 | object_initialize_child(OBJECT(machine), "dp8393x", &m->dp8393x, |
366 | TYPE_DP8393X); | |
367 | dev = DEVICE(&m->dp8393x); | |
04e7ca8d LV |
368 | qdev_set_nic_properties(dev, &nd_table[0]); |
369 | qdev_prop_set_uint8(dev, "it_shift", 2); | |
370 | qdev_prop_set_bit(dev, "big_endian", true); | |
5325cc34 MA |
371 | object_property_set_link(OBJECT(dev), "dma_mr", |
372 | OBJECT(get_system_memory()), &error_abort); | |
04e7ca8d | 373 | sysbus = SYS_BUS_DEVICE(dev); |
804ae67e | 374 | sysbus_realize(sysbus, &error_fatal); |
f18a2886 MCA |
375 | memory_region_add_subregion(&m->macio, SONIC_BASE - IO_BASE, |
376 | sysbus_mmio_get_region(sysbus, 0)); | |
1ecc6ec1 MCA |
377 | sysbus_connect_irq(sysbus, 0, |
378 | qdev_get_gpio_in(DEVICE(&m->glue), GLUE_IRQ_IN_SONIC)); | |
04e7ca8d | 379 | |
408c5733 MCA |
380 | memory_region_init_rom(dp8393x_prom, NULL, "dp8393x-q800.prom", |
381 | SONIC_PROM_SIZE, &error_fatal); | |
382 | memory_region_add_subregion(get_system_memory(), SONIC_PROM_BASE, | |
383 | dp8393x_prom); | |
384 | ||
385 | /* Add MAC address with valid checksum to PROM */ | |
386 | prom = memory_region_get_ram_ptr(dp8393x_prom); | |
387 | checksum = 0; | |
388 | for (i = 0; i < 6; i++) { | |
2f0e10a4 | 389 | prom[i] = revbit8(nd_table[0].macaddr.a[i]); |
846feac2 | 390 | checksum ^= prom[i]; |
408c5733 MCA |
391 | } |
392 | prom[7] = 0xff - checksum; | |
393 | ||
04e7ca8d LV |
394 | /* SCC */ |
395 | ||
836126c7 MCA |
396 | object_initialize_child(OBJECT(machine), "escc", &m->escc, |
397 | TYPE_ESCC); | |
398 | dev = DEVICE(&m->escc); | |
04e7ca8d LV |
399 | qdev_prop_set_uint32(dev, "disabled", 0); |
400 | qdev_prop_set_uint32(dev, "frequency", MAC_CLOCK); | |
401 | qdev_prop_set_uint32(dev, "it_shift", 1); | |
402 | qdev_prop_set_bit(dev, "bit_swap", true); | |
403 | qdev_prop_set_chr(dev, "chrA", serial_hd(0)); | |
404 | qdev_prop_set_chr(dev, "chrB", serial_hd(1)); | |
405 | qdev_prop_set_uint32(dev, "chnBtype", 0); | |
406 | qdev_prop_set_uint32(dev, "chnAtype", 0); | |
04e7ca8d | 407 | sysbus = SYS_BUS_DEVICE(dev); |
836126c7 | 408 | sysbus_realize(sysbus, &error_fatal); |
95264861 PM |
409 | |
410 | /* Logically OR both its IRQs together */ | |
1a7a3f00 MCA |
411 | object_initialize_child(OBJECT(machine), "escc_orgate", &m->escc_orgate, |
412 | TYPE_OR_IRQ); | |
413 | object_property_set_int(OBJECT(&m->escc_orgate), "num-lines", 2, | |
414 | &error_fatal); | |
415 | dev = DEVICE(&m->escc_orgate); | |
416 | qdev_realize(dev, NULL, &error_fatal); | |
417 | sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(dev, 0)); | |
418 | sysbus_connect_irq(sysbus, 1, qdev_get_gpio_in(dev, 1)); | |
419 | qdev_connect_gpio_out(dev, 0, | |
1ecc6ec1 MCA |
420 | qdev_get_gpio_in(DEVICE(&m->glue), |
421 | GLUE_IRQ_IN_ESCC)); | |
f18a2886 MCA |
422 | memory_region_add_subregion(&m->macio, SCC_BASE - IO_BASE, |
423 | sysbus_mmio_get_region(sysbus, 0)); | |
04e7ca8d LV |
424 | |
425 | /* SCSI */ | |
426 | ||
e78d17ca MCA |
427 | object_initialize_child(OBJECT(machine), "esp", &m->esp, |
428 | TYPE_SYSBUS_ESP); | |
429 | sysbus_esp = SYSBUS_ESP(&m->esp); | |
04e7ca8d LV |
430 | esp = &sysbus_esp->esp; |
431 | esp->dma_memory_read = NULL; | |
432 | esp->dma_memory_write = NULL; | |
433 | esp->dma_opaque = NULL; | |
434 | sysbus_esp->it_shift = 4; | |
435 | esp->dma_enabled = 1; | |
04e7ca8d | 436 | |
e78d17ca MCA |
437 | sysbus = SYS_BUS_DEVICE(&m->esp); |
438 | sysbus_realize(sysbus, &error_fatal); | |
b793b4ef | 439 | /* SCSI and SCSI data IRQs are negative edge triggered */ |
d7942e16 MCA |
440 | sysbus_connect_irq(sysbus, 0, |
441 | qemu_irq_invert( | |
442 | qdev_get_gpio_in(DEVICE(&m->via2), | |
443 | VIA2_IRQ_SCSI_BIT))); | |
444 | sysbus_connect_irq(sysbus, 1, | |
445 | qemu_irq_invert( | |
446 | qdev_get_gpio_in(DEVICE(&m->via2), | |
447 | VIA2_IRQ_SCSI_DATA_BIT))); | |
f18a2886 MCA |
448 | memory_region_add_subregion(&m->macio, ESP_BASE - IO_BASE, |
449 | sysbus_mmio_get_region(sysbus, 0)); | |
450 | memory_region_add_subregion(&m->macio, ESP_PDMA - IO_BASE, | |
451 | sysbus_mmio_get_region(sysbus, 1)); | |
04e7ca8d LV |
452 | |
453 | scsi_bus_legacy_handle_cmdline(&esp->bus); | |
454 | ||
455 | /* SWIM floppy controller */ | |
456 | ||
01f35a4f MCA |
457 | object_initialize_child(OBJECT(machine), "swim", &m->swim, |
458 | TYPE_SWIM); | |
459 | sysbus = SYS_BUS_DEVICE(&m->swim); | |
460 | sysbus_realize(sysbus, &error_fatal); | |
f18a2886 | 461 | memory_region_add_subregion(&m->macio, SWIM_BASE - IO_BASE, |
01f35a4f | 462 | sysbus_mmio_get_region(sysbus, 0)); |
04e7ca8d LV |
463 | |
464 | /* NuBus */ | |
465 | ||
36df1c5a MCA |
466 | object_initialize_child(OBJECT(machine), "mac-nubus-bridge", |
467 | &m->mac_nubus_bridge, | |
468 | TYPE_MAC_NUBUS_BRIDGE); | |
469 | sysbus = SYS_BUS_DEVICE(&m->mac_nubus_bridge); | |
470 | dev = DEVICE(&m->mac_nubus_bridge); | |
471 | qdev_prop_set_uint32(DEVICE(&m->mac_nubus_bridge), "slot-available-mask", | |
5ef25141 | 472 | Q800_NUBUS_SLOTS_AVAILABLE); |
36df1c5a MCA |
473 | sysbus_realize(sysbus, &error_fatal); |
474 | memory_region_add_subregion(get_system_memory(), | |
475 | MAC_NUBUS_FIRST_SLOT * NUBUS_SUPER_SLOT_SIZE, | |
476 | sysbus_mmio_get_region(sysbus, 0)); | |
477 | memory_region_add_subregion(get_system_memory(), | |
478 | NUBUS_SLOT_BASE + | |
479 | MAC_NUBUS_FIRST_SLOT * NUBUS_SLOT_SIZE, | |
480 | sysbus_mmio_get_region(sysbus, 1)); | |
efd0c37e | 481 | qdev_connect_gpio_out(dev, 9, |
d7942e16 | 482 | qdev_get_gpio_in_named(DEVICE(&m->via2), "nubus-irq", |
efd0c37e MCA |
483 | VIA2_NUBUS_IRQ_INTVIDEO)); |
484 | for (i = 1; i < VIA2_NUBUS_IRQ_NB; i++) { | |
b297843e | 485 | qdev_connect_gpio_out(dev, 9 + i, |
d7942e16 MCA |
486 | qdev_get_gpio_in_named(DEVICE(&m->via2), |
487 | "nubus-irq", | |
b297843e MCA |
488 | VIA2_NUBUS_IRQ_9 + i)); |
489 | } | |
490 | ||
f7c6e12e MCA |
491 | /* |
492 | * Since the framebuffer in slot 0x9 uses a separate IRQ, wire the unused | |
493 | * IRQ via GLUE for use by SONIC Ethernet in classic mode | |
494 | */ | |
1ecc6ec1 | 495 | qdev_connect_gpio_out(DEVICE(&m->glue), GLUE_IRQ_NUBUS_9, |
d7942e16 | 496 | qdev_get_gpio_in_named(DEVICE(&m->via2), "nubus-irq", |
f7c6e12e MCA |
497 | VIA2_NUBUS_IRQ_9)); |
498 | ||
464085e8 | 499 | nubus = NUBUS_BUS(qdev_get_child_bus(dev, "nubus-bus.0")); |
04e7ca8d LV |
500 | |
501 | /* framebuffer in nubus slot #9 */ | |
502 | ||
7a1f3acb MCA |
503 | object_initialize_child(OBJECT(machine), "macfb", &m->macfb, |
504 | TYPE_NUBUS_MACFB); | |
505 | dev = DEVICE(&m->macfb); | |
efd0c37e | 506 | qdev_prop_set_uint32(dev, "slot", 9); |
04e7ca8d LV |
507 | qdev_prop_set_uint32(dev, "width", graphic_width); |
508 | qdev_prop_set_uint32(dev, "height", graphic_height); | |
509 | qdev_prop_set_uint8(dev, "depth", graphic_depth); | |
a56c12fb | 510 | if (graphic_width == 1152 && graphic_height == 870) { |
4317c518 MCA |
511 | qdev_prop_set_uint8(dev, "display", MACFB_DISPLAY_APPLE_21_COLOR); |
512 | } else { | |
513 | qdev_prop_set_uint8(dev, "display", MACFB_DISPLAY_VGA); | |
514 | } | |
7a1f3acb | 515 | qdev_realize(dev, BUS(nubus), &error_fatal); |
04e7ca8d | 516 | |
df8abbba MCA |
517 | macfb_mode = (NUBUS_MACFB(dev)->macfb).mode; |
518 | ||
36e2e338 | 519 | cs = CPU(&m->cpu); |
04e7ca8d LV |
520 | if (linux_boot) { |
521 | uint64_t high; | |
281ac13e JD |
522 | void *param_blob, *param_ptr, *param_rng_seed; |
523 | ||
524 | if (kernel_cmdline) { | |
525 | param_blob = g_malloc(strlen(kernel_cmdline) + 1024); | |
526 | } else { | |
527 | param_blob = g_malloc(1024); | |
528 | } | |
529 | ||
04e7ca8d | 530 | kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, |
6cdda0ff | 531 | &elf_entry, NULL, &high, NULL, 1, |
04e7ca8d LV |
532 | EM_68K, 0, 0); |
533 | if (kernel_size < 0) { | |
534 | error_report("could not load kernel '%s'", kernel_filename); | |
535 | exit(1); | |
536 | } | |
537 | stl_phys(cs->as, 4, elf_entry); /* reset initial PC */ | |
538 | parameters_base = (high + 1) & ~1; | |
281ac13e JD |
539 | param_ptr = param_blob; |
540 | ||
541 | BOOTINFO1(param_ptr, BI_MACHTYPE, MACH_MAC); | |
542 | BOOTINFO1(param_ptr, BI_FPUTYPE, FPU_68040); | |
543 | BOOTINFO1(param_ptr, BI_MMUTYPE, MMU_68040); | |
544 | BOOTINFO1(param_ptr, BI_CPUTYPE, CPU_68040); | |
545 | BOOTINFO1(param_ptr, BI_MAC_CPUID, CPUB_68040); | |
546 | BOOTINFO1(param_ptr, BI_MAC_MODEL, MAC_MODEL_Q800); | |
547 | BOOTINFO1(param_ptr, | |
04e7ca8d | 548 | BI_MAC_MEMSIZE, ram_size >> 20); /* in MB */ |
281ac13e JD |
549 | BOOTINFO2(param_ptr, BI_MEMCHUNK, 0, ram_size); |
550 | BOOTINFO1(param_ptr, BI_MAC_VADDR, | |
df8abbba | 551 | VIDEO_BASE + macfb_mode->offset); |
281ac13e JD |
552 | BOOTINFO1(param_ptr, BI_MAC_VDEPTH, graphic_depth); |
553 | BOOTINFO1(param_ptr, BI_MAC_VDIM, | |
04e7ca8d | 554 | (graphic_height << 16) | graphic_width); |
281ac13e JD |
555 | BOOTINFO1(param_ptr, BI_MAC_VROW, macfb_mode->stride); |
556 | BOOTINFO1(param_ptr, BI_MAC_SCCBASE, SCC_BASE); | |
04e7ca8d | 557 | |
0b9b41fb | 558 | memory_region_init_ram_ptr(&m->rom, NULL, "m68k_fake_mac.rom", |
e24e58e8 | 559 | sizeof(fake_mac_rom), fake_mac_rom); |
0b9b41fb MCA |
560 | memory_region_set_readonly(&m->rom, true); |
561 | memory_region_add_subregion(get_system_memory(), MACROM_ADDR, &m->rom); | |
e24e58e8 | 562 | |
04e7ca8d | 563 | if (kernel_cmdline) { |
281ac13e | 564 | BOOTINFOSTR(param_ptr, BI_COMMAND_LINE, |
04e7ca8d LV |
565 | kernel_cmdline); |
566 | } | |
567 | ||
693869a6 | 568 | /* Pass seed to RNG. */ |
281ac13e | 569 | param_rng_seed = param_ptr; |
693869a6 | 570 | qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); |
281ac13e | 571 | BOOTINFODATA(param_ptr, BI_RNG_SEED, |
693869a6 JD |
572 | rng_seed, sizeof(rng_seed)); |
573 | ||
04e7ca8d LV |
574 | /* load initrd */ |
575 | if (initrd_filename) { | |
576 | initrd_size = get_image_size(initrd_filename); | |
577 | if (initrd_size < 0) { | |
578 | error_report("could not load initial ram disk '%s'", | |
579 | initrd_filename); | |
580 | exit(1); | |
581 | } | |
582 | ||
583 | initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK; | |
584 | load_image_targphys(initrd_filename, initrd_base, | |
585 | ram_size - initrd_base); | |
281ac13e | 586 | BOOTINFO2(param_ptr, BI_RAMDISK, initrd_base, |
04e7ca8d LV |
587 | initrd_size); |
588 | } else { | |
589 | initrd_base = 0; | |
590 | initrd_size = 0; | |
591 | } | |
281ac13e JD |
592 | BOOTINFO0(param_ptr, BI_LAST); |
593 | rom_add_blob_fixed_as("bootinfo", param_blob, param_ptr - param_blob, | |
594 | parameters_base, cs->as); | |
fbbbe7eb JD |
595 | qemu_register_reset_nosnapshotload(rerandomize_rng_seed, |
596 | rom_ptr_for_as(cs->as, parameters_base, | |
597 | param_ptr - param_blob) + | |
598 | (param_rng_seed - param_blob)); | |
281ac13e | 599 | g_free(param_blob); |
04e7ca8d LV |
600 | } else { |
601 | uint8_t *ptr; | |
602 | /* allocate and load BIOS */ | |
0b9b41fb | 603 | memory_region_init_rom(&m->rom, NULL, "m68k_mac.rom", MACROM_SIZE, |
04e7ca8d | 604 | &error_abort); |
04e7ca8d | 605 | filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); |
0b9b41fb | 606 | memory_region_add_subregion(get_system_memory(), MACROM_ADDR, &m->rom); |
04e7ca8d LV |
607 | |
608 | /* Load MacROM binary */ | |
609 | if (filename) { | |
610 | bios_size = load_image_targphys(filename, MACROM_ADDR, MACROM_SIZE); | |
611 | g_free(filename); | |
612 | } else { | |
613 | bios_size = -1; | |
614 | } | |
615 | ||
616 | /* Remove qtest_enabled() check once firmware files are in the tree */ | |
617 | if (!qtest_enabled()) { | |
0969e00b | 618 | if (bios_size <= 0 || bios_size > MACROM_SIZE) { |
04e7ca8d LV |
619 | error_report("could not load MacROM '%s'", bios_name); |
620 | exit(1); | |
621 | } | |
622 | ||
0969e00b LV |
623 | ptr = rom_ptr(MACROM_ADDR, bios_size); |
624 | assert(ptr != NULL); | |
04e7ca8d LV |
625 | stl_phys(cs->as, 0, ldl_p(ptr)); /* reset initial SP */ |
626 | stl_phys(cs->as, 4, | |
627 | MACROM_ADDR + ldl_p(ptr + 4)); /* reset initial PC */ | |
628 | } | |
629 | } | |
630 | } | |
631 | ||
f3582410 | 632 | static GlobalProperty hw_compat_q800[] = { |
26fcbf00 | 633 | { "scsi-hd", "quirk_mode_page_vendor_specific_apple", "on" }, |
0fc37ada MCA |
634 | { "scsi-hd", "vendor", " SEAGATE" }, |
635 | { "scsi-hd", "product", " ST225N" }, | |
636 | { "scsi-hd", "ver", "1.0 " }, | |
26fcbf00 MCA |
637 | { "scsi-cd", "quirk_mode_page_apple_vendor", "on" }, |
638 | { "scsi-cd", "quirk_mode_sense_rom_use_dbd", "on" }, | |
639 | { "scsi-cd", "quirk_mode_page_vendor_specific_apple", "on" }, | |
640 | { "scsi-cd", "quirk_mode_page_truncated", "on" }, | |
74518fb6 MCA |
641 | { "scsi-cd", "vendor", "MATSHITA" }, |
642 | { "scsi-cd", "product", "CD-ROM CR-8005" }, | |
643 | { "scsi-cd", "ver", "1.0k" }, | |
f3582410 MCA |
644 | }; |
645 | static const size_t hw_compat_q800_len = G_N_ELEMENTS(hw_compat_q800); | |
646 | ||
36e2e338 MCA |
647 | static const char *q800_machine_valid_cpu_types[] = { |
648 | M68K_CPU_TYPE_NAME("m68040"), | |
649 | NULL | |
650 | }; | |
651 | ||
04e7ca8d LV |
652 | static void q800_machine_class_init(ObjectClass *oc, void *data) |
653 | { | |
654 | MachineClass *mc = MACHINE_CLASS(oc); | |
1a514d3a | 655 | |
04e7ca8d | 656 | mc->desc = "Macintosh Quadra 800"; |
1a514d3a | 657 | mc->init = q800_machine_init; |
04e7ca8d | 658 | mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040"); |
36e2e338 | 659 | mc->valid_cpu_types = q800_machine_valid_cpu_types; |
04e7ca8d | 660 | mc->max_cpus = 1; |
04e7ca8d | 661 | mc->block_default_type = IF_SCSI; |
8591a179 | 662 | mc->default_ram_id = "m68k_mac.ram"; |
f3582410 | 663 | compat_props_add(mc->compat_props, hw_compat_q800, hw_compat_q800_len); |
04e7ca8d LV |
664 | } |
665 | ||
666 | static const TypeInfo q800_machine_typeinfo = { | |
667 | .name = MACHINE_TYPE_NAME("q800"), | |
668 | .parent = TYPE_MACHINE, | |
a8019229 | 669 | .instance_size = sizeof(Q800MachineState), |
04e7ca8d LV |
670 | .class_init = q800_machine_class_init, |
671 | }; | |
672 | ||
673 | static void q800_machine_register_types(void) | |
674 | { | |
675 | type_register_static(&q800_machine_typeinfo); | |
676 | } | |
677 | ||
678 | type_init(q800_machine_register_types) |