qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

hw/m68k: add a dummy SWIM floppy controller

SWIM (Sander-Wozniak Integrated Machine) is the floppy controller of
the 680x0 Macintosh.

This patch introduces only the basic support: it allows to switch from
IWM (Integrated WOZ Machine) mode to the SWIM mode and makes the linux
driver happy.

It cannot read any floppy image.

Co-developed-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Reviewed-by: Hervé Poussineau <hpoussin@reactos.org>
Message-Id: <20191026164546.30020-10-laurent@vivier.eu>

+572
+2
MAINTAINERS
··· 923 923 F: hw/misc/mac_via.c 924 924 F: hw/nubus/* 925 925 F: hw/display/macfb.c 926 + F: hw/block/swim.c 926 927 F: include/hw/misc/mac_via.h 927 928 F: include/hw/nubus/* 928 929 F: include/hw/display/macfb.h 930 + F: include/hw/block/swim.h 929 931 930 932 MicroBlaze Machines 931 933 -------------------
+3
hw/block/Kconfig
··· 37 37 # Only PCI devices are provided for now 38 38 default y if VIRTIO_PCI 39 39 depends on VIRTIO && VHOST_USER && LINUX 40 + 41 + config SWIM 42 + bool
+1
hw/block/Makefile.objs
··· 8 8 common-obj-$(CONFIG_ECC) += ecc.o 9 9 common-obj-$(CONFIG_ONENAND) += onenand.o 10 10 common-obj-$(CONFIG_NVME_PCI) += nvme.o 11 + common-obj-$(CONFIG_SWIM) += swim.o 11 12 12 13 obj-$(CONFIG_SH4) += tc58128.o 13 14
+489
hw/block/swim.c
··· 1 + /* 2 + * QEMU Macintosh floppy disk controller emulator (SWIM) 3 + * 4 + * Copyright (c) 2014-2018 Laurent Vivier <laurent@vivier.eu> 5 + * 6 + * This work is licensed under the terms of the GNU GPL, version 2. See 7 + * the COPYING file in the top-level directory. 8 + * 9 + * Only the basic support: it allows to switch from IWM (Integrated WOZ 10 + * Machine) mode to the SWIM mode and makes the linux driver happy. 11 + */ 12 + 13 + #include "qemu/osdep.h" 14 + #include "qemu/main-loop.h" 15 + #include "qapi/error.h" 16 + #include "sysemu/block-backend.h" 17 + #include "hw/sysbus.h" 18 + #include "migration/vmstate.h" 19 + #include "hw/block/block.h" 20 + #include "hw/block/swim.h" 21 + #include "hw/qdev-properties.h" 22 + 23 + /* IWM registers */ 24 + 25 + #define IWM_PH0L 0 26 + #define IWM_PH0H 1 27 + #define IWM_PH1L 2 28 + #define IWM_PH1H 3 29 + #define IWM_PH2L 4 30 + #define IWM_PH2H 5 31 + #define IWM_PH3L 6 32 + #define IWM_PH3H 7 33 + #define IWM_MTROFF 8 34 + #define IWM_MTRON 9 35 + #define IWM_INTDRIVE 10 36 + #define IWM_EXTDRIVE 11 37 + #define IWM_Q6L 12 38 + #define IWM_Q6H 13 39 + #define IWM_Q7L 14 40 + #define IWM_Q7H 15 41 + 42 + /* SWIM registers */ 43 + 44 + #define SWIM_WRITE_DATA 0 45 + #define SWIM_WRITE_MARK 1 46 + #define SWIM_WRITE_CRC 2 47 + #define SWIM_WRITE_PARAMETER 3 48 + #define SWIM_WRITE_PHASE 4 49 + #define SWIM_WRITE_SETUP 5 50 + #define SWIM_WRITE_MODE0 6 51 + #define SWIM_WRITE_MODE1 7 52 + 53 + #define SWIM_READ_DATA 8 54 + #define SWIM_READ_MARK 9 55 + #define SWIM_READ_ERROR 10 56 + #define SWIM_READ_PARAMETER 11 57 + #define SWIM_READ_PHASE 12 58 + #define SWIM_READ_SETUP 13 59 + #define SWIM_READ_STATUS 14 60 + #define SWIM_READ_HANDSHAKE 15 61 + 62 + #define REG_SHIFT 9 63 + 64 + #define SWIM_MODE_IWM 0 65 + #define SWIM_MODE_SWIM 1 66 + 67 + /* bits in phase register */ 68 + 69 + #define SWIM_SEEK_NEGATIVE 0x074 70 + #define SWIM_STEP 0x071 71 + #define SWIM_MOTOR_ON 0x072 72 + #define SWIM_MOTOR_OFF 0x076 73 + #define SWIM_INDEX 0x073 74 + #define SWIM_EJECT 0x077 75 + #define SWIM_SETMFM 0x171 76 + #define SWIM_SETGCR 0x175 77 + #define SWIM_RELAX 0x033 78 + #define SWIM_LSTRB 0x008 79 + #define SWIM_CA_MASK 0x077 80 + 81 + /* Select values for swim_select and swim_readbit */ 82 + 83 + #define SWIM_READ_DATA_0 0x074 84 + #define SWIM_TWOMEG_DRIVE 0x075 85 + #define SWIM_SINGLE_SIDED 0x076 86 + #define SWIM_DRIVE_PRESENT 0x077 87 + #define SWIM_DISK_IN 0x170 88 + #define SWIM_WRITE_PROT 0x171 89 + #define SWIM_TRACK_ZERO 0x172 90 + #define SWIM_TACHO 0x173 91 + #define SWIM_READ_DATA_1 0x174 92 + #define SWIM_MFM_MODE 0x175 93 + #define SWIM_SEEK_COMPLETE 0x176 94 + #define SWIM_ONEMEG_MEDIA 0x177 95 + 96 + /* Bits in handshake register */ 97 + 98 + #define SWIM_MARK_BYTE 0x01 99 + #define SWIM_CRC_ZERO 0x02 100 + #define SWIM_RDDATA 0x04 101 + #define SWIM_SENSE 0x08 102 + #define SWIM_MOTEN 0x10 103 + #define SWIM_ERROR 0x20 104 + #define SWIM_DAT2BYTE 0x40 105 + #define SWIM_DAT1BYTE 0x80 106 + 107 + /* bits in setup register */ 108 + 109 + #define SWIM_S_INV_WDATA 0x01 110 + #define SWIM_S_3_5_SELECT 0x02 111 + #define SWIM_S_GCR 0x04 112 + #define SWIM_S_FCLK_DIV2 0x08 113 + #define SWIM_S_ERROR_CORR 0x10 114 + #define SWIM_S_IBM_DRIVE 0x20 115 + #define SWIM_S_GCR_WRITE 0x40 116 + #define SWIM_S_TIMEOUT 0x80 117 + 118 + /* bits in mode register */ 119 + 120 + #define SWIM_CLFIFO 0x01 121 + #define SWIM_ENBL1 0x02 122 + #define SWIM_ENBL2 0x04 123 + #define SWIM_ACTION 0x08 124 + #define SWIM_WRITE_MODE 0x10 125 + #define SWIM_HEDSEL 0x20 126 + #define SWIM_MOTON 0x80 127 + 128 + static void fd_recalibrate(FDrive *drive) 129 + { 130 + } 131 + 132 + static void swim_change_cb(void *opaque, bool load, Error **errp) 133 + { 134 + FDrive *drive = opaque; 135 + 136 + if (!load) { 137 + blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort); 138 + } else { 139 + if (!blkconf_apply_backend_options(drive->conf, 140 + blk_is_read_only(drive->blk), false, 141 + errp)) { 142 + return; 143 + } 144 + } 145 + } 146 + 147 + static const BlockDevOps swim_block_ops = { 148 + .change_media_cb = swim_change_cb, 149 + }; 150 + 151 + static Property swim_drive_properties[] = { 152 + DEFINE_PROP_INT32("unit", SWIMDrive, unit, -1), 153 + DEFINE_BLOCK_PROPERTIES(SWIMDrive, conf), 154 + DEFINE_PROP_END_OF_LIST(), 155 + }; 156 + 157 + static void swim_drive_realize(DeviceState *qdev, Error **errp) 158 + { 159 + SWIMDrive *dev = SWIM_DRIVE(qdev); 160 + SWIMBus *bus = SWIM_BUS(qdev->parent_bus); 161 + FDrive *drive; 162 + int ret; 163 + 164 + if (dev->unit == -1) { 165 + for (dev->unit = 0; dev->unit < SWIM_MAX_FD; dev->unit++) { 166 + drive = &bus->ctrl->drives[dev->unit]; 167 + if (!drive->blk) { 168 + break; 169 + } 170 + } 171 + } 172 + 173 + if (dev->unit >= SWIM_MAX_FD) { 174 + error_setg(errp, "Can't create floppy unit %d, bus supports " 175 + "only %d units", dev->unit, SWIM_MAX_FD); 176 + return; 177 + } 178 + 179 + drive = &bus->ctrl->drives[dev->unit]; 180 + if (drive->blk) { 181 + error_setg(errp, "Floppy unit %d is in use", dev->unit); 182 + return; 183 + } 184 + 185 + if (!dev->conf.blk) { 186 + /* Anonymous BlockBackend for an empty drive */ 187 + dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL); 188 + ret = blk_attach_dev(dev->conf.blk, qdev); 189 + assert(ret == 0); 190 + } 191 + 192 + blkconf_blocksizes(&dev->conf); 193 + if (dev->conf.logical_block_size != 512 || 194 + dev->conf.physical_block_size != 512) 195 + { 196 + error_setg(errp, "Physical and logical block size must " 197 + "be 512 for floppy"); 198 + return; 199 + } 200 + 201 + /* 202 + * rerror/werror aren't supported by fdc and therefore not even registered 203 + * with qdev. So set the defaults manually before they are used in 204 + * blkconf_apply_backend_options(). 205 + */ 206 + dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO; 207 + dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO; 208 + 209 + if (!blkconf_apply_backend_options(&dev->conf, 210 + blk_is_read_only(dev->conf.blk), 211 + false, errp)) { 212 + return; 213 + } 214 + 215 + /* 216 + * 'enospc' is the default for -drive, 'report' is what blk_new() gives us 217 + * for empty drives. 218 + */ 219 + if (blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC && 220 + blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_REPORT) { 221 + error_setg(errp, "fdc doesn't support drive option werror"); 222 + return; 223 + } 224 + if (blk_get_on_error(dev->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) { 225 + error_setg(errp, "fdc doesn't support drive option rerror"); 226 + return; 227 + } 228 + 229 + drive->conf = &dev->conf; 230 + drive->blk = dev->conf.blk; 231 + drive->swimctrl = bus->ctrl; 232 + 233 + blk_set_dev_ops(drive->blk, &swim_block_ops, drive); 234 + } 235 + 236 + static void swim_drive_class_init(ObjectClass *klass, void *data) 237 + { 238 + DeviceClass *k = DEVICE_CLASS(klass); 239 + k->realize = swim_drive_realize; 240 + set_bit(DEVICE_CATEGORY_STORAGE, k->categories); 241 + k->bus_type = TYPE_SWIM_BUS; 242 + k->props = swim_drive_properties; 243 + k->desc = "virtual SWIM drive"; 244 + } 245 + 246 + static const TypeInfo swim_drive_info = { 247 + .name = TYPE_SWIM_DRIVE, 248 + .parent = TYPE_DEVICE, 249 + .instance_size = sizeof(SWIMDrive), 250 + .class_init = swim_drive_class_init, 251 + }; 252 + 253 + static const TypeInfo swim_bus_info = { 254 + .name = TYPE_SWIM_BUS, 255 + .parent = TYPE_BUS, 256 + .instance_size = sizeof(SWIMBus), 257 + }; 258 + 259 + static void iwmctrl_write(void *opaque, hwaddr reg, uint64_t value, 260 + unsigned size) 261 + { 262 + SWIMCtrl *swimctrl = opaque; 263 + 264 + reg >>= REG_SHIFT; 265 + 266 + swimctrl->regs[reg >> 1] = reg & 1; 267 + 268 + if (swimctrl->regs[IWM_Q6] && 269 + swimctrl->regs[IWM_Q7]) { 270 + if (swimctrl->regs[IWM_MTR]) { 271 + /* data register */ 272 + swimctrl->iwm_data = value; 273 + } else { 274 + /* mode register */ 275 + swimctrl->iwm_mode = value; 276 + /* detect sequence to switch from IWM mode to SWIM mode */ 277 + switch (swimctrl->iwm_switch) { 278 + case 0: 279 + if (value == 0x57) { 280 + swimctrl->iwm_switch++; 281 + } 282 + break; 283 + case 1: 284 + if (value == 0x17) { 285 + swimctrl->iwm_switch++; 286 + } 287 + break; 288 + case 2: 289 + if (value == 0x57) { 290 + swimctrl->iwm_switch++; 291 + } 292 + break; 293 + case 3: 294 + if (value == 0x57) { 295 + swimctrl->mode = SWIM_MODE_SWIM; 296 + swimctrl->iwm_switch = 0; 297 + } 298 + break; 299 + } 300 + } 301 + } 302 + } 303 + 304 + static uint64_t iwmctrl_read(void *opaque, hwaddr reg, unsigned size) 305 + { 306 + SWIMCtrl *swimctrl = opaque; 307 + 308 + reg >>= REG_SHIFT; 309 + 310 + swimctrl->regs[reg >> 1] = reg & 1; 311 + 312 + return 0; 313 + } 314 + 315 + static void swimctrl_write(void *opaque, hwaddr reg, uint64_t value, 316 + unsigned size) 317 + { 318 + SWIMCtrl *swimctrl = opaque; 319 + 320 + if (swimctrl->mode == SWIM_MODE_IWM) { 321 + iwmctrl_write(opaque, reg, value, size); 322 + return; 323 + } 324 + 325 + reg >>= REG_SHIFT; 326 + 327 + switch (reg) { 328 + case SWIM_WRITE_PHASE: 329 + swimctrl->swim_phase = value; 330 + break; 331 + case SWIM_WRITE_MODE0: 332 + swimctrl->swim_mode &= ~value; 333 + break; 334 + case SWIM_WRITE_MODE1: 335 + swimctrl->swim_mode |= value; 336 + break; 337 + case SWIM_WRITE_DATA: 338 + case SWIM_WRITE_MARK: 339 + case SWIM_WRITE_CRC: 340 + case SWIM_WRITE_PARAMETER: 341 + case SWIM_WRITE_SETUP: 342 + break; 343 + } 344 + } 345 + 346 + static uint64_t swimctrl_read(void *opaque, hwaddr reg, unsigned size) 347 + { 348 + SWIMCtrl *swimctrl = opaque; 349 + uint32_t value = 0; 350 + 351 + if (swimctrl->mode == SWIM_MODE_IWM) { 352 + return iwmctrl_read(opaque, reg, size); 353 + } 354 + 355 + reg >>= REG_SHIFT; 356 + 357 + switch (reg) { 358 + case SWIM_READ_PHASE: 359 + value = swimctrl->swim_phase; 360 + break; 361 + case SWIM_READ_HANDSHAKE: 362 + if (swimctrl->swim_phase == SWIM_DRIVE_PRESENT) { 363 + /* always answer "no drive present" */ 364 + value = SWIM_SENSE; 365 + } 366 + break; 367 + case SWIM_READ_DATA: 368 + case SWIM_READ_MARK: 369 + case SWIM_READ_ERROR: 370 + case SWIM_READ_PARAMETER: 371 + case SWIM_READ_SETUP: 372 + case SWIM_READ_STATUS: 373 + break; 374 + } 375 + 376 + return value; 377 + } 378 + 379 + static const MemoryRegionOps swimctrl_mem_ops = { 380 + .write = swimctrl_write, 381 + .read = swimctrl_read, 382 + .endianness = DEVICE_NATIVE_ENDIAN, 383 + }; 384 + 385 + static void sysbus_swim_reset(DeviceState *d) 386 + { 387 + SWIM *sys = SWIM(d); 388 + SWIMCtrl *ctrl = &sys->ctrl; 389 + int i; 390 + 391 + ctrl->mode = 0; 392 + ctrl->iwm_switch = 0; 393 + for (i = 0; i < 8; i++) { 394 + ctrl->regs[i] = 0; 395 + } 396 + ctrl->iwm_data = 0; 397 + ctrl->iwm_mode = 0; 398 + ctrl->swim_phase = 0; 399 + ctrl->swim_mode = 0; 400 + for (i = 0; i < SWIM_MAX_FD; i++) { 401 + fd_recalibrate(&ctrl->drives[i]); 402 + } 403 + } 404 + 405 + static void sysbus_swim_init(Object *obj) 406 + { 407 + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 408 + SWIM *sbs = SWIM(obj); 409 + SWIMCtrl *swimctrl = &sbs->ctrl; 410 + 411 + memory_region_init_io(&swimctrl->iomem, obj, &swimctrl_mem_ops, swimctrl, 412 + "swim", 0x2000); 413 + sysbus_init_mmio(sbd, &swimctrl->iomem); 414 + } 415 + 416 + static void sysbus_swim_realize(DeviceState *dev, Error **errp) 417 + { 418 + SWIM *sys = SWIM(dev); 419 + SWIMCtrl *swimctrl = &sys->ctrl; 420 + 421 + qbus_create_inplace(&swimctrl->bus, sizeof(SWIMBus), TYPE_SWIM_BUS, dev, 422 + NULL); 423 + swimctrl->bus.ctrl = swimctrl; 424 + } 425 + 426 + static const VMStateDescription vmstate_fdrive = { 427 + .name = "fdrive", 428 + .version_id = 1, 429 + .minimum_version_id = 1, 430 + .fields = (VMStateField[]) { 431 + VMSTATE_END_OF_LIST() 432 + }, 433 + }; 434 + 435 + static const VMStateDescription vmstate_swim = { 436 + .name = "swim", 437 + .version_id = 1, 438 + .minimum_version_id = 1, 439 + .fields = (VMStateField[]) { 440 + VMSTATE_INT32(mode, SWIMCtrl), 441 + /* IWM mode */ 442 + VMSTATE_INT32(iwm_switch, SWIMCtrl), 443 + VMSTATE_UINT16_ARRAY(regs, SWIMCtrl, 8), 444 + VMSTATE_UINT8(iwm_data, SWIMCtrl), 445 + VMSTATE_UINT8(iwm_mode, SWIMCtrl), 446 + /* SWIM mode */ 447 + VMSTATE_UINT8(swim_phase, SWIMCtrl), 448 + VMSTATE_UINT8(swim_mode, SWIMCtrl), 449 + /* Drives */ 450 + VMSTATE_STRUCT_ARRAY(drives, SWIMCtrl, SWIM_MAX_FD, 1, 451 + vmstate_fdrive, FDrive), 452 + VMSTATE_END_OF_LIST() 453 + }, 454 + }; 455 + 456 + static const VMStateDescription vmstate_sysbus_swim = { 457 + .name = "SWIM", 458 + .version_id = 1, 459 + .fields = (VMStateField[]) { 460 + VMSTATE_STRUCT(ctrl, SWIM, 0, vmstate_swim, SWIMCtrl), 461 + VMSTATE_END_OF_LIST() 462 + } 463 + }; 464 + 465 + static void sysbus_swim_class_init(ObjectClass *oc, void *data) 466 + { 467 + DeviceClass *dc = DEVICE_CLASS(oc); 468 + 469 + dc->realize = sysbus_swim_realize; 470 + dc->reset = sysbus_swim_reset; 471 + dc->vmsd = &vmstate_sysbus_swim; 472 + } 473 + 474 + static const TypeInfo sysbus_swim_info = { 475 + .name = TYPE_SWIM, 476 + .parent = TYPE_SYS_BUS_DEVICE, 477 + .instance_size = sizeof(SWIM), 478 + .instance_init = sysbus_swim_init, 479 + .class_init = sysbus_swim_class_init, 480 + }; 481 + 482 + static void swim_register_types(void) 483 + { 484 + type_register_static(&sysbus_swim_info); 485 + type_register_static(&swim_bus_info); 486 + type_register_static(&swim_drive_info); 487 + } 488 + 489 + type_init(swim_register_types)
+1
hw/m68k/Kconfig
··· 18 18 select MAC_VIA 19 19 select NUBUS 20 20 select MACFB 21 + select SWIM
+76
include/hw/block/swim.h
··· 1 + /* 2 + * QEMU Macintosh floppy disk controller emulator (SWIM) 3 + * 4 + * Copyright (c) 2014-2018 Laurent Vivier <laurent@vivier.eu> 5 + * 6 + * This work is licensed under the terms of the GNU GPL, version 2. See 7 + * the COPYING file in the top-level directory. 8 + * 9 + */ 10 + 11 + #ifndef SWIM_H 12 + #define SWIM_H 13 + 14 + #include "qemu/osdep.h" 15 + #include "hw/sysbus.h" 16 + 17 + #define SWIM_MAX_FD 2 18 + 19 + typedef struct SWIMDrive SWIMDrive; 20 + typedef struct SWIMBus SWIMBus; 21 + typedef struct SWIMCtrl SWIMCtrl; 22 + 23 + #define TYPE_SWIM_DRIVE "swim-drive" 24 + #define SWIM_DRIVE(obj) OBJECT_CHECK(SWIMDrive, (obj), TYPE_SWIM_DRIVE) 25 + 26 + struct SWIMDrive { 27 + DeviceState qdev; 28 + int32_t unit; 29 + BlockConf conf; 30 + }; 31 + 32 + #define TYPE_SWIM_BUS "swim-bus" 33 + #define SWIM_BUS(obj) OBJECT_CHECK(SWIMBus, (obj), TYPE_SWIM_BUS) 34 + 35 + struct SWIMBus { 36 + BusState bus; 37 + struct SWIMCtrl *ctrl; 38 + }; 39 + 40 + typedef struct FDrive { 41 + SWIMCtrl *swimctrl; 42 + BlockBackend *blk; 43 + BlockConf *conf; 44 + } FDrive; 45 + 46 + struct SWIMCtrl { 47 + MemoryRegion iomem; 48 + FDrive drives[SWIM_MAX_FD]; 49 + int mode; 50 + /* IWM mode */ 51 + int iwm_switch; 52 + uint16_t regs[8]; 53 + #define IWM_PH0 0 54 + #define IWM_PH1 1 55 + #define IWM_PH2 2 56 + #define IWM_PH3 3 57 + #define IWM_MTR 4 58 + #define IWM_DRIVE 5 59 + #define IWM_Q6 6 60 + #define IWM_Q7 7 61 + uint8_t iwm_data; 62 + uint8_t iwm_mode; 63 + /* SWIM mode */ 64 + uint8_t swim_phase; 65 + uint8_t swim_mode; 66 + SWIMBus bus; 67 + }; 68 + 69 + #define TYPE_SWIM "swim" 70 + #define SWIM(obj) OBJECT_CHECK(SWIM, (obj), TYPE_SWIM) 71 + 72 + typedef struct SWIM { 73 + SysBusDevice parent_obj; 74 + SWIMCtrl ctrl; 75 + } SWIM; 76 + #endif