xref: /qemu/hw/block/swim.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
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 "system/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 #include "trace.h"
23 
24 
25 /* IWM latch bits */
26 
27 #define IWMLB_PHASE0            0
28 #define IWMLB_PHASE1            1
29 #define IWMLB_PHASE2            2
30 #define IWMLB_PHASE3            3
31 #define IWMLB_MOTORON           4
32 #define IWMLB_DRIVESEL          5
33 #define IWMLB_L6                6
34 #define IWMLB_L7                7
35 
36 /* IWM registers */
37 
38 #define IWM_READALLONES         0
39 #define IWM_READDATA            1
40 #define IWM_READSTATUS0         2
41 #define IWM_READSTATUS1         3
42 #define IWM_READWHANDSHAKE0     4
43 #define IWM_READWHANDSHAKE1     5
44 #define IWM_WRITESETMODE        6
45 #define IWM_WRITEDATA           7
46 
47 /* SWIM registers */
48 
49 #define SWIM_WRITE_DATA         0
50 #define SWIM_WRITE_MARK         1
51 #define SWIM_WRITE_CRC          2
52 #define SWIM_WRITE_PARAMETER    3
53 #define SWIM_WRITE_PHASE        4
54 #define SWIM_WRITE_SETUP        5
55 #define SWIM_WRITE_MODE0        6
56 #define SWIM_WRITE_MODE1        7
57 
58 #define SWIM_READ_DATA          8
59 #define SWIM_READ_MARK          9
60 #define SWIM_READ_ERROR         10
61 #define SWIM_READ_PARAMETER     11
62 #define SWIM_READ_PHASE         12
63 #define SWIM_READ_SETUP         13
64 #define SWIM_READ_STATUS        14
65 #define SWIM_READ_HANDSHAKE     15
66 
67 #define REG_SHIFT               9
68 
69 #define SWIM_MODE_STATUS_BIT    6
70 #define SWIM_MODE_IWM           0
71 #define SWIM_MODE_ISM           1
72 
73 /* bits in phase register */
74 
75 #define SWIM_SEEK_NEGATIVE   0x074
76 #define SWIM_STEP            0x071
77 #define SWIM_MOTOR_ON        0x072
78 #define SWIM_MOTOR_OFF       0x076
79 #define SWIM_INDEX           0x073
80 #define SWIM_EJECT           0x077
81 #define SWIM_SETMFM          0x171
82 #define SWIM_SETGCR          0x175
83 #define SWIM_RELAX           0x033
84 #define SWIM_LSTRB           0x008
85 #define SWIM_CA_MASK         0x077
86 
87 /* Select values for swim_select and swim_readbit */
88 
89 #define SWIM_READ_DATA_0     0x074
90 #define SWIM_TWOMEG_DRIVE    0x075
91 #define SWIM_SINGLE_SIDED    0x076
92 #define SWIM_DRIVE_PRESENT   0x077
93 #define SWIM_DISK_IN         0x170
94 #define SWIM_WRITE_PROT      0x171
95 #define SWIM_TRACK_ZERO      0x172
96 #define SWIM_TACHO           0x173
97 #define SWIM_READ_DATA_1     0x174
98 #define SWIM_MFM_MODE        0x175
99 #define SWIM_SEEK_COMPLETE   0x176
100 #define SWIM_ONEMEG_MEDIA    0x177
101 
102 /* Bits in handshake register */
103 
104 #define SWIM_MARK_BYTE       0x01
105 #define SWIM_CRC_ZERO        0x02
106 #define SWIM_RDDATA          0x04
107 #define SWIM_SENSE           0x08
108 #define SWIM_MOTEN           0x10
109 #define SWIM_ERROR           0x20
110 #define SWIM_DAT2BYTE        0x40
111 #define SWIM_DAT1BYTE        0x80
112 
113 /* bits in setup register */
114 
115 #define SWIM_S_INV_WDATA     0x01
116 #define SWIM_S_3_5_SELECT    0x02
117 #define SWIM_S_GCR           0x04
118 #define SWIM_S_FCLK_DIV2     0x08
119 #define SWIM_S_ERROR_CORR    0x10
120 #define SWIM_S_IBM_DRIVE     0x20
121 #define SWIM_S_GCR_WRITE     0x40
122 #define SWIM_S_TIMEOUT       0x80
123 
124 /* bits in mode register */
125 
126 #define SWIM_CLFIFO          0x01
127 #define SWIM_ENBL1           0x02
128 #define SWIM_ENBL2           0x04
129 #define SWIM_ACTION          0x08
130 #define SWIM_WRITE_MODE      0x10
131 #define SWIM_HEDSEL          0x20
132 #define SWIM_MOTON           0x80
133 
134 static const char *iwm_reg_names[] = {
135     "READALLONES", "READDATA", "READSTATUS0", "READSTATUS1",
136     "READWHANDSHAKE0", "READWHANDSHAKE1", "WRITESETMODE", "WRITEDATA"
137 };
138 
139 static const char *ism_reg_names[] = {
140     "WRITE_DATA", "WRITE_MARK", "WRITE_CRC", "WRITE_PARAMETER",
141     "WRITE_PHASE", "WRITE_SETUP", "WRITE_MODE0", "WRITE_MODE1",
142     "READ_DATA", "READ_MARK", "READ_ERROR", "READ_PARAMETER",
143     "READ_PHASE", "READ_SETUP", "READ_STATUS", "READ_HANDSHAKE"
144 };
145 
fd_recalibrate(FDrive * drive)146 static void fd_recalibrate(FDrive *drive)
147 {
148 }
149 
swim_change_cb(void * opaque,bool load,Error ** errp)150 static void swim_change_cb(void *opaque, bool load, Error **errp)
151 {
152     FDrive *drive = opaque;
153 
154     if (!load) {
155         blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort);
156     } else {
157         if (!blkconf_apply_backend_options(drive->conf,
158                                            !blk_supports_write_perm(drive->blk),
159                                            false, errp)) {
160             return;
161         }
162     }
163 }
164 
165 static const BlockDevOps swim_block_ops = {
166     .change_media_cb = swim_change_cb,
167 };
168 
169 static const Property swim_drive_properties[] = {
170     DEFINE_PROP_INT32("unit", SWIMDrive, unit, -1),
171     DEFINE_BLOCK_PROPERTIES(SWIMDrive, conf),
172 };
173 
swim_drive_realize(DeviceState * qdev,Error ** errp)174 static void swim_drive_realize(DeviceState *qdev, Error **errp)
175 {
176     SWIMDrive *dev = SWIM_DRIVE(qdev);
177     SWIMBus *bus = SWIM_BUS(qdev->parent_bus);
178     FDrive *drive;
179     int ret;
180 
181     if (dev->unit == -1) {
182         for (dev->unit = 0; dev->unit < SWIM_MAX_FD; dev->unit++) {
183             drive = &bus->ctrl->drives[dev->unit];
184             if (!drive->blk) {
185                 break;
186             }
187         }
188     }
189 
190     if (dev->unit >= SWIM_MAX_FD) {
191         error_setg(errp, "Can't create floppy unit %d, bus supports "
192                    "only %d units", dev->unit, SWIM_MAX_FD);
193         return;
194     }
195 
196     drive = &bus->ctrl->drives[dev->unit];
197     if (drive->blk) {
198         error_setg(errp, "Floppy unit %d is in use", dev->unit);
199         return;
200     }
201 
202     if (!dev->conf.blk) {
203         /* Anonymous BlockBackend for an empty drive */
204         dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
205         ret = blk_attach_dev(dev->conf.blk, qdev);
206         assert(ret == 0);
207     }
208 
209     if (!blkconf_blocksizes(&dev->conf, errp)) {
210         return;
211     }
212 
213     if (dev->conf.logical_block_size != 512 ||
214         dev->conf.physical_block_size != 512)
215     {
216         error_setg(errp, "Physical and logical block size must "
217                    "be 512 for floppy");
218         return;
219     }
220 
221     /*
222      * rerror/werror aren't supported by fdc and therefore not even registered
223      * with qdev. So set the defaults manually before they are used in
224      * blkconf_apply_backend_options().
225      */
226     dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO;
227     dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO;
228 
229     if (!blkconf_apply_backend_options(&dev->conf,
230                                        !blk_supports_write_perm(dev->conf.blk),
231                                        false, errp)) {
232         return;
233     }
234 
235     /*
236      * 'enospc' is the default for -drive, 'report' is what blk_new() gives us
237      * for empty drives.
238      */
239     if (blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC &&
240         blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_REPORT) {
241         error_setg(errp, "fdc doesn't support drive option werror");
242         return;
243     }
244     if (blk_get_on_error(dev->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
245         error_setg(errp, "fdc doesn't support drive option rerror");
246         return;
247     }
248 
249     drive->conf = &dev->conf;
250     drive->blk = dev->conf.blk;
251     drive->swimctrl = bus->ctrl;
252 
253     blk_set_dev_ops(drive->blk, &swim_block_ops, drive);
254 }
255 
swim_drive_class_init(ObjectClass * klass,const void * data)256 static void swim_drive_class_init(ObjectClass *klass, const void *data)
257 {
258     DeviceClass *k = DEVICE_CLASS(klass);
259     k->realize = swim_drive_realize;
260     set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
261     k->bus_type = TYPE_SWIM_BUS;
262     device_class_set_props(k, swim_drive_properties);
263     k->desc = "virtual SWIM drive";
264 }
265 
266 static const TypeInfo swim_drive_info = {
267     .name = TYPE_SWIM_DRIVE,
268     .parent = TYPE_DEVICE,
269     .instance_size = sizeof(SWIMDrive),
270     .class_init = swim_drive_class_init,
271 };
272 
273 static const TypeInfo swim_bus_info = {
274     .name = TYPE_SWIM_BUS,
275     .parent = TYPE_BUS,
276     .instance_size = sizeof(SWIMBus),
277 };
278 
iwmctrl_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)279 static void iwmctrl_write(void *opaque, hwaddr addr, uint64_t value,
280                           unsigned size)
281 {
282     SWIMCtrl *swimctrl = opaque;
283     uint8_t latch, reg, ism_bit;
284 
285     addr >>= REG_SHIFT;
286 
287     /* A3-A1 select a latch, A0 specifies the value */
288     latch = (addr >> 1) & 7;
289     if (addr & 1) {
290         swimctrl->iwm_latches |= (1 << latch);
291     } else {
292         swimctrl->iwm_latches &= ~(1 << latch);
293     }
294 
295     reg = (swimctrl->iwm_latches & 0xc0) >> 5 |
296           (swimctrl->iwm_latches & 0x10) >> 4;
297 
298     swimctrl->iwmregs[reg] = value;
299     trace_swim_iwmctrl_write(reg, iwm_reg_names[reg], size, value);
300 
301     switch (reg) {
302     case IWM_WRITESETMODE:
303         /* detect sequence to switch from IWM mode to SWIM mode */
304         ism_bit = (value & (1 << SWIM_MODE_STATUS_BIT));
305 
306         switch (swimctrl->iwm_switch) {
307         case 0:
308             if (ism_bit) {    /* 1 */
309                 swimctrl->iwm_switch++;
310             }
311             break;
312         case 1:
313             if (!ism_bit) {   /* 0 */
314                 swimctrl->iwm_switch++;
315             }
316             break;
317         case 2:
318             if (ism_bit) {    /* 1 */
319                 swimctrl->iwm_switch++;
320             }
321             break;
322         case 3:
323             if (ism_bit) {    /* 1 */
324                 swimctrl->iwm_switch++;
325 
326                 swimctrl->mode = SWIM_MODE_ISM;
327                 swimctrl->swim_mode |= (1 << SWIM_MODE_STATUS_BIT);
328                 swimctrl->iwm_switch = 0;
329                 trace_swim_switch_to_ism();
330 
331                 /* Switch to ISM registers */
332                 memory_region_del_subregion(&swimctrl->swim, &swimctrl->iwm);
333                 memory_region_add_subregion(&swimctrl->swim, 0x0,
334                                             &swimctrl->ism);
335             }
336             break;
337         }
338         break;
339     default:
340         break;
341     }
342 }
343 
iwmctrl_read(void * opaque,hwaddr addr,unsigned size)344 static uint64_t iwmctrl_read(void *opaque, hwaddr addr, unsigned size)
345 {
346     SWIMCtrl *swimctrl = opaque;
347     uint8_t latch, reg, value;
348 
349     addr >>= REG_SHIFT;
350 
351     /* A3-A1 select a latch, A0 specifies the value */
352     latch = (addr >> 1) & 7;
353     if (addr & 1) {
354         swimctrl->iwm_latches |= (1 << latch);
355     } else {
356         swimctrl->iwm_latches &= ~(1 << latch);
357     }
358 
359     reg = (swimctrl->iwm_latches & 0xc0) >> 5 |
360           (swimctrl->iwm_latches & 0x10) >> 4;
361 
362     switch (reg) {
363     case IWM_READALLONES:
364         value = 0xff;
365         break;
366     default:
367         value = 0;
368         break;
369     }
370 
371     trace_swim_iwmctrl_read(reg, iwm_reg_names[reg], size, value);
372     return value;
373 }
374 
375 static const MemoryRegionOps swimctrl_iwm_ops = {
376     .write = iwmctrl_write,
377     .read = iwmctrl_read,
378     .endianness = DEVICE_BIG_ENDIAN,
379 };
380 
ismctrl_write(void * opaque,hwaddr reg,uint64_t value,unsigned size)381 static void ismctrl_write(void *opaque, hwaddr reg, uint64_t value,
382                           unsigned size)
383 {
384     SWIMCtrl *swimctrl = opaque;
385 
386     reg >>= REG_SHIFT;
387 
388     trace_swim_ismctrl_write(reg, ism_reg_names[reg], size, value);
389 
390     switch (reg) {
391     case SWIM_WRITE_PHASE:
392         swimctrl->swim_phase = value;
393         break;
394     case SWIM_WRITE_MODE0:
395         swimctrl->swim_mode &= ~value;
396         /* Any access to MODE0 register resets PRAM index */
397         swimctrl->pram_idx = 0;
398 
399         if (!(swimctrl->swim_mode & (1 << SWIM_MODE_STATUS_BIT))) {
400             /* Clearing the mode bit switches to IWM mode */
401             swimctrl->mode = SWIM_MODE_IWM;
402             swimctrl->iwm_latches = 0;
403             trace_swim_switch_to_iwm();
404 
405             /* Switch to IWM registers */
406             memory_region_del_subregion(&swimctrl->swim, &swimctrl->ism);
407             memory_region_add_subregion(&swimctrl->swim, 0x0,
408                                         &swimctrl->iwm);
409         }
410         break;
411     case SWIM_WRITE_MODE1:
412         swimctrl->swim_mode |= value;
413         break;
414     case SWIM_WRITE_PARAMETER:
415         swimctrl->pram[swimctrl->pram_idx++] = value;
416         swimctrl->pram_idx &= 0xf;
417         break;
418     case SWIM_WRITE_DATA:
419     case SWIM_WRITE_MARK:
420     case SWIM_WRITE_CRC:
421     case SWIM_WRITE_SETUP:
422         break;
423     }
424 }
425 
ismctrl_read(void * opaque,hwaddr reg,unsigned size)426 static uint64_t ismctrl_read(void *opaque, hwaddr reg, unsigned size)
427 {
428     SWIMCtrl *swimctrl = opaque;
429     uint32_t value = 0;
430 
431     reg >>= REG_SHIFT;
432 
433     switch (reg) {
434     case SWIM_READ_PHASE:
435         value = swimctrl->swim_phase;
436         break;
437     case SWIM_READ_HANDSHAKE:
438         if (swimctrl->swim_phase == SWIM_DRIVE_PRESENT) {
439             /* always answer "no drive present" */
440             value = SWIM_SENSE;
441         }
442         break;
443     case SWIM_READ_PARAMETER:
444         value = swimctrl->pram[swimctrl->pram_idx++];
445         swimctrl->pram_idx &= 0xf;
446         break;
447     case SWIM_READ_STATUS:
448         value = swimctrl->swim_status & ~(1 << SWIM_MODE_STATUS_BIT);
449         if (swimctrl->swim_mode == SWIM_MODE_ISM) {
450             value |= (1 << SWIM_MODE_STATUS_BIT);
451         }
452         break;
453     case SWIM_READ_DATA:
454     case SWIM_READ_MARK:
455     case SWIM_READ_ERROR:
456     case SWIM_READ_SETUP:
457         break;
458     }
459 
460     trace_swim_ismctrl_read(reg, ism_reg_names[reg], size, value);
461     return value;
462 }
463 
464 static const MemoryRegionOps swimctrl_ism_ops = {
465     .write = ismctrl_write,
466     .read = ismctrl_read,
467     .endianness = DEVICE_BIG_ENDIAN,
468 };
469 
sysbus_swim_reset(DeviceState * d)470 static void sysbus_swim_reset(DeviceState *d)
471 {
472     Swim *sys = SWIM(d);
473     SWIMCtrl *ctrl = &sys->ctrl;
474     int i;
475 
476     ctrl->mode = 0;
477     ctrl->iwm_switch = 0;
478     memset(ctrl->iwmregs, 0, sizeof(ctrl->iwmregs));
479 
480     ctrl->swim_phase = 0;
481     ctrl->swim_mode = 0;
482     memset(ctrl->ismregs, 0, sizeof(ctrl->ismregs));
483     for (i = 0; i < SWIM_MAX_FD; i++) {
484         fd_recalibrate(&ctrl->drives[i]);
485     }
486 }
487 
sysbus_swim_init(Object * obj)488 static void sysbus_swim_init(Object *obj)
489 {
490     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
491     Swim *sbs = SWIM(obj);
492     SWIMCtrl *swimctrl = &sbs->ctrl;
493 
494     memory_region_init(&swimctrl->swim, obj, "swim", 0x2000);
495     memory_region_init_io(&swimctrl->iwm, obj, &swimctrl_iwm_ops, swimctrl,
496                           "iwm", 0x2000);
497     memory_region_init_io(&swimctrl->ism, obj, &swimctrl_ism_ops, swimctrl,
498                           "ism", 0x2000);
499     sysbus_init_mmio(sbd, &swimctrl->swim);
500 }
501 
sysbus_swim_realize(DeviceState * dev,Error ** errp)502 static void sysbus_swim_realize(DeviceState *dev, Error **errp)
503 {
504     Swim *sys = SWIM(dev);
505     SWIMCtrl *swimctrl = &sys->ctrl;
506 
507     qbus_init(&swimctrl->bus, sizeof(SWIMBus), TYPE_SWIM_BUS, dev, NULL);
508     swimctrl->bus.ctrl = swimctrl;
509 
510     /* Default register set is IWM */
511     memory_region_add_subregion(&swimctrl->swim, 0x0, &swimctrl->iwm);
512 }
513 
514 static const VMStateDescription vmstate_fdrive = {
515     .name = "fdrive",
516     .version_id = 1,
517     .minimum_version_id = 1,
518     .fields = (const VMStateField[]) {
519         VMSTATE_END_OF_LIST()
520     },
521 };
522 
523 static const VMStateDescription vmstate_swim = {
524     .name = "swim",
525     .version_id = 1,
526     .minimum_version_id = 1,
527     .fields = (const VMStateField[]) {
528         VMSTATE_INT32(mode, SWIMCtrl),
529         /* IWM mode */
530         VMSTATE_INT32(iwm_switch, SWIMCtrl),
531         VMSTATE_UINT8(iwm_latches, SWIMCtrl),
532         VMSTATE_UINT8_ARRAY(iwmregs, SWIMCtrl, 8),
533         /* SWIM mode */
534         VMSTATE_UINT8_ARRAY(ismregs, SWIMCtrl, 16),
535         VMSTATE_UINT8(swim_phase, SWIMCtrl),
536         VMSTATE_UINT8(swim_mode, SWIMCtrl),
537         /* Drives */
538         VMSTATE_STRUCT_ARRAY(drives, SWIMCtrl, SWIM_MAX_FD, 1,
539                              vmstate_fdrive, FDrive),
540         VMSTATE_END_OF_LIST()
541     },
542 };
543 
544 static const VMStateDescription vmstate_sysbus_swim = {
545     .name = "SWIM",
546     .version_id = 1,
547     .fields = (const VMStateField[]) {
548         VMSTATE_STRUCT(ctrl, Swim, 0, vmstate_swim, SWIMCtrl),
549         VMSTATE_END_OF_LIST()
550     }
551 };
552 
sysbus_swim_class_init(ObjectClass * oc,const void * data)553 static void sysbus_swim_class_init(ObjectClass *oc, const void *data)
554 {
555     DeviceClass *dc = DEVICE_CLASS(oc);
556 
557     dc->realize = sysbus_swim_realize;
558     device_class_set_legacy_reset(dc, sysbus_swim_reset);
559     dc->vmsd = &vmstate_sysbus_swim;
560 }
561 
562 static const TypeInfo sysbus_swim_info = {
563     .name          = TYPE_SWIM,
564     .parent        = TYPE_SYS_BUS_DEVICE,
565     .instance_size = sizeof(Swim),
566     .instance_init = sysbus_swim_init,
567     .class_init    = sysbus_swim_class_init,
568 };
569 
swim_register_types(void)570 static void swim_register_types(void)
571 {
572     type_register_static(&sysbus_swim_info);
573     type_register_static(&swim_bus_info);
574     type_register_static(&swim_drive_info);
575 }
576 
577 type_init(swim_register_types)
578