Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Floppy test cases. |
| 3 | * |
| 4 | * Copyright (c) 2012 Kevin Wolf <kwolf@redhat.com> |
| 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 | |
Peter Maydell | 681c28a | 2016-02-08 18:08:51 +0000 | [diff] [blame] | 25 | #include "qemu/osdep.h" |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 26 | |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 27 | |
Thomas Huth | dd21074 | 2019-09-03 07:50:26 +0200 | [diff] [blame] | 28 | #include "libqtest-single.h" |
Markus Armbruster | 055a1ef | 2018-08-06 08:53:25 +0200 | [diff] [blame] | 29 | #include "qapi/qmp/qdict.h" |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 30 | #include "qemu-common.h" |
| 31 | |
Markus Armbruster | 055a1ef | 2018-08-06 08:53:25 +0200 | [diff] [blame] | 32 | /* TODO actually test the results and get rid of this */ |
| 33 | #define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__)) |
| 34 | |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 35 | #define TEST_IMAGE_SIZE 1440 * 1024 |
| 36 | |
| 37 | #define FLOPPY_BASE 0x3f0 |
| 38 | #define FLOPPY_IRQ 6 |
| 39 | |
| 40 | enum { |
| 41 | reg_sra = 0x0, |
| 42 | reg_srb = 0x1, |
| 43 | reg_dor = 0x2, |
| 44 | reg_msr = 0x4, |
| 45 | reg_dsr = 0x4, |
| 46 | reg_fifo = 0x5, |
| 47 | reg_dir = 0x7, |
| 48 | }; |
| 49 | |
| 50 | enum { |
Pavel Hrdina | 98272db | 2012-07-16 15:48:27 +0200 | [diff] [blame] | 51 | CMD_SENSE_INT = 0x08, |
Kevin Wolf | 67f194b | 2012-09-20 23:20:07 +0200 | [diff] [blame] | 52 | CMD_READ_ID = 0x0a, |
Pavel Hrdina | 98272db | 2012-07-16 15:48:27 +0200 | [diff] [blame] | 53 | CMD_SEEK = 0x0f, |
Hervé Poussineau | 6f442fe | 2012-09-18 23:04:56 +0200 | [diff] [blame] | 54 | CMD_VERIFY = 0x16, |
Pavel Hrdina | 98272db | 2012-07-16 15:48:27 +0200 | [diff] [blame] | 55 | CMD_READ = 0xe6, |
| 56 | CMD_RELATIVE_SEEK_OUT = 0x8f, |
| 57 | CMD_RELATIVE_SEEK_IN = 0xcf, |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 58 | }; |
| 59 | |
| 60 | enum { |
Hervé Poussineau | 5f8ae8e | 2012-09-18 23:02:59 +0200 | [diff] [blame] | 61 | BUSY = 0x10, |
| 62 | NONDMA = 0x20, |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 63 | RQM = 0x80, |
| 64 | DIO = 0x40, |
| 65 | |
| 66 | DSKCHG = 0x80, |
| 67 | }; |
| 68 | |
Stefan Weil | 748bfb4 | 2014-07-07 21:03:38 +0200 | [diff] [blame] | 69 | static char test_image[] = "/tmp/qtest.XXXXXX"; |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 70 | |
| 71 | #define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask)) |
| 72 | #define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0) |
| 73 | |
Pavel Hrdina | 7cd3316 | 2012-05-24 11:02:30 +0200 | [diff] [blame] | 74 | static uint8_t base = 0x70; |
| 75 | |
| 76 | enum { |
| 77 | CMOS_FLOPPY = 0x10, |
| 78 | }; |
| 79 | |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 80 | static void floppy_send(uint8_t byte) |
| 81 | { |
| 82 | uint8_t msr; |
| 83 | |
| 84 | msr = inb(FLOPPY_BASE + reg_msr); |
| 85 | assert_bit_set(msr, RQM); |
| 86 | assert_bit_clear(msr, DIO); |
| 87 | |
| 88 | outb(FLOPPY_BASE + reg_fifo, byte); |
| 89 | } |
| 90 | |
| 91 | static uint8_t floppy_recv(void) |
| 92 | { |
| 93 | uint8_t msr; |
| 94 | |
| 95 | msr = inb(FLOPPY_BASE + reg_msr); |
| 96 | assert_bit_set(msr, RQM | DIO); |
| 97 | |
| 98 | return inb(FLOPPY_BASE + reg_fifo); |
| 99 | } |
| 100 | |
Kevin Wolf | c3cdc1b | 2012-07-16 16:06:56 +0200 | [diff] [blame] | 101 | /* pcn: Present Cylinder Number */ |
| 102 | static void ack_irq(uint8_t *pcn) |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 103 | { |
Pavel Hrdina | 98272db | 2012-07-16 15:48:27 +0200 | [diff] [blame] | 104 | uint8_t ret; |
| 105 | |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 106 | g_assert(get_irq(FLOPPY_IRQ)); |
| 107 | floppy_send(CMD_SENSE_INT); |
| 108 | floppy_recv(); |
Pavel Hrdina | 98272db | 2012-07-16 15:48:27 +0200 | [diff] [blame] | 109 | |
Kevin Wolf | c3cdc1b | 2012-07-16 16:06:56 +0200 | [diff] [blame] | 110 | ret = floppy_recv(); |
| 111 | if (pcn != NULL) { |
| 112 | *pcn = ret; |
| 113 | } |
| 114 | |
| 115 | g_assert(!get_irq(FLOPPY_IRQ)); |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 116 | } |
| 117 | |
Hervé Poussineau | 6f442fe | 2012-09-18 23:04:56 +0200 | [diff] [blame] | 118 | static uint8_t send_read_command(uint8_t cmd) |
Pavel Hrdina | 8b9ef60 | 2012-06-13 15:43:12 +0200 | [diff] [blame] | 119 | { |
| 120 | uint8_t drive = 0; |
| 121 | uint8_t head = 0; |
| 122 | uint8_t cyl = 0; |
| 123 | uint8_t sect_addr = 1; |
| 124 | uint8_t sect_size = 2; |
| 125 | uint8_t eot = 1; |
| 126 | uint8_t gap = 0x1b; |
| 127 | uint8_t gpl = 0xff; |
| 128 | |
| 129 | uint8_t msr = 0; |
| 130 | uint8_t st0; |
| 131 | |
| 132 | uint8_t ret = 0; |
| 133 | |
Hervé Poussineau | 6f442fe | 2012-09-18 23:04:56 +0200 | [diff] [blame] | 134 | floppy_send(cmd); |
Pavel Hrdina | 8b9ef60 | 2012-06-13 15:43:12 +0200 | [diff] [blame] | 135 | floppy_send(head << 2 | drive); |
| 136 | g_assert(!get_irq(FLOPPY_IRQ)); |
| 137 | floppy_send(cyl); |
| 138 | floppy_send(head); |
| 139 | floppy_send(sect_addr); |
| 140 | floppy_send(sect_size); |
| 141 | floppy_send(eot); |
| 142 | floppy_send(gap); |
| 143 | floppy_send(gpl); |
| 144 | |
| 145 | uint8_t i = 0; |
| 146 | uint8_t n = 2; |
| 147 | for (; i < n; i++) { |
| 148 | msr = inb(FLOPPY_BASE + reg_msr); |
| 149 | if (msr == 0xd0) { |
| 150 | break; |
| 151 | } |
| 152 | sleep(1); |
| 153 | } |
| 154 | |
| 155 | if (i >= n) { |
| 156 | return 1; |
| 157 | } |
| 158 | |
| 159 | st0 = floppy_recv(); |
Hervé Poussineau | 075f553 | 2012-09-20 23:07:53 +0200 | [diff] [blame] | 160 | if (st0 != 0x40) { |
Pavel Hrdina | 8b9ef60 | 2012-06-13 15:43:12 +0200 | [diff] [blame] | 161 | ret = 1; |
| 162 | } |
| 163 | |
| 164 | floppy_recv(); |
| 165 | floppy_recv(); |
| 166 | floppy_recv(); |
| 167 | floppy_recv(); |
| 168 | floppy_recv(); |
| 169 | floppy_recv(); |
| 170 | |
| 171 | return ret; |
| 172 | } |
| 173 | |
Hervé Poussineau | 5f8ae8e | 2012-09-18 23:02:59 +0200 | [diff] [blame] | 174 | static uint8_t send_read_no_dma_command(int nb_sect, uint8_t expected_st0) |
| 175 | { |
| 176 | uint8_t drive = 0; |
| 177 | uint8_t head = 0; |
| 178 | uint8_t cyl = 0; |
| 179 | uint8_t sect_addr = 1; |
| 180 | uint8_t sect_size = 2; |
| 181 | uint8_t eot = nb_sect; |
| 182 | uint8_t gap = 0x1b; |
| 183 | uint8_t gpl = 0xff; |
| 184 | |
| 185 | uint8_t msr = 0; |
| 186 | uint8_t st0; |
| 187 | |
| 188 | uint8_t ret = 0; |
| 189 | |
| 190 | floppy_send(CMD_READ); |
| 191 | floppy_send(head << 2 | drive); |
| 192 | g_assert(!get_irq(FLOPPY_IRQ)); |
| 193 | floppy_send(cyl); |
| 194 | floppy_send(head); |
| 195 | floppy_send(sect_addr); |
| 196 | floppy_send(sect_size); |
| 197 | floppy_send(eot); |
| 198 | floppy_send(gap); |
| 199 | floppy_send(gpl); |
| 200 | |
| 201 | uint16_t i = 0; |
| 202 | uint8_t n = 2; |
| 203 | for (; i < n; i++) { |
| 204 | msr = inb(FLOPPY_BASE + reg_msr); |
| 205 | if (msr == (BUSY | NONDMA | DIO | RQM)) { |
| 206 | break; |
| 207 | } |
| 208 | sleep(1); |
| 209 | } |
| 210 | |
| 211 | if (i >= n) { |
| 212 | return 1; |
| 213 | } |
| 214 | |
| 215 | /* Non-DMA mode */ |
| 216 | for (i = 0; i < 512 * 2 * nb_sect; i++) { |
| 217 | msr = inb(FLOPPY_BASE + reg_msr); |
| 218 | assert_bit_set(msr, BUSY | RQM | DIO); |
| 219 | inb(FLOPPY_BASE + reg_fifo); |
| 220 | } |
| 221 | |
Kevin Wolf | 4964e18 | 2015-05-21 15:19:38 +0200 | [diff] [blame] | 222 | msr = inb(FLOPPY_BASE + reg_msr); |
| 223 | assert_bit_set(msr, BUSY | RQM | DIO); |
| 224 | g_assert(get_irq(FLOPPY_IRQ)); |
| 225 | |
Hervé Poussineau | 5f8ae8e | 2012-09-18 23:02:59 +0200 | [diff] [blame] | 226 | st0 = floppy_recv(); |
| 227 | if (st0 != expected_st0) { |
| 228 | ret = 1; |
| 229 | } |
| 230 | |
| 231 | floppy_recv(); |
| 232 | floppy_recv(); |
| 233 | floppy_recv(); |
| 234 | floppy_recv(); |
| 235 | floppy_recv(); |
Kevin Wolf | 4964e18 | 2015-05-21 15:19:38 +0200 | [diff] [blame] | 236 | g_assert(get_irq(FLOPPY_IRQ)); |
Hervé Poussineau | 5f8ae8e | 2012-09-18 23:02:59 +0200 | [diff] [blame] | 237 | floppy_recv(); |
| 238 | |
Kevin Wolf | 4964e18 | 2015-05-21 15:19:38 +0200 | [diff] [blame] | 239 | /* Check that we're back in command phase */ |
| 240 | msr = inb(FLOPPY_BASE + reg_msr); |
| 241 | assert_bit_clear(msr, BUSY | DIO); |
| 242 | assert_bit_set(msr, RQM); |
| 243 | g_assert(!get_irq(FLOPPY_IRQ)); |
| 244 | |
Hervé Poussineau | 5f8ae8e | 2012-09-18 23:02:59 +0200 | [diff] [blame] | 245 | return ret; |
| 246 | } |
| 247 | |
Kevin Wolf | c3cdc1b | 2012-07-16 16:06:56 +0200 | [diff] [blame] | 248 | static void send_seek(int cyl) |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 249 | { |
| 250 | int drive = 0; |
| 251 | int head = 0; |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 252 | |
| 253 | floppy_send(CMD_SEEK); |
| 254 | floppy_send(head << 2 | drive); |
| 255 | g_assert(!get_irq(FLOPPY_IRQ)); |
| 256 | floppy_send(cyl); |
Kevin Wolf | c3cdc1b | 2012-07-16 16:06:56 +0200 | [diff] [blame] | 257 | ack_irq(NULL); |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 258 | } |
| 259 | |
Pavel Hrdina | 7cd3316 | 2012-05-24 11:02:30 +0200 | [diff] [blame] | 260 | static uint8_t cmos_read(uint8_t reg) |
| 261 | { |
| 262 | outb(base + 0, reg); |
| 263 | return inb(base + 1); |
| 264 | } |
| 265 | |
| 266 | static void test_cmos(void) |
| 267 | { |
| 268 | uint8_t cmos; |
| 269 | |
| 270 | cmos = cmos_read(CMOS_FLOPPY); |
John Snow | 62c7625 | 2016-01-22 15:51:04 -0500 | [diff] [blame] | 271 | g_assert(cmos == 0x40 || cmos == 0x50); |
Pavel Hrdina | 7cd3316 | 2012-05-24 11:02:30 +0200 | [diff] [blame] | 272 | } |
| 273 | |
| 274 | static void test_no_media_on_start(void) |
| 275 | { |
| 276 | uint8_t dir; |
| 277 | |
| 278 | /* Media changed bit must be set all time after start if there is |
| 279 | * no media in drive. */ |
| 280 | dir = inb(FLOPPY_BASE + reg_dir); |
| 281 | assert_bit_set(dir, DSKCHG); |
| 282 | dir = inb(FLOPPY_BASE + reg_dir); |
| 283 | assert_bit_set(dir, DSKCHG); |
Kevin Wolf | c3cdc1b | 2012-07-16 16:06:56 +0200 | [diff] [blame] | 284 | send_seek(1); |
Pavel Hrdina | 7cd3316 | 2012-05-24 11:02:30 +0200 | [diff] [blame] | 285 | dir = inb(FLOPPY_BASE + reg_dir); |
| 286 | assert_bit_set(dir, DSKCHG); |
| 287 | dir = inb(FLOPPY_BASE + reg_dir); |
| 288 | assert_bit_set(dir, DSKCHG); |
| 289 | } |
| 290 | |
Pavel Hrdina | 8b9ef60 | 2012-06-13 15:43:12 +0200 | [diff] [blame] | 291 | static void test_read_without_media(void) |
| 292 | { |
| 293 | uint8_t ret; |
| 294 | |
Hervé Poussineau | 6f442fe | 2012-09-18 23:04:56 +0200 | [diff] [blame] | 295 | ret = send_read_command(CMD_READ); |
Pavel Hrdina | 8b9ef60 | 2012-06-13 15:43:12 +0200 | [diff] [blame] | 296 | g_assert(ret == 0); |
| 297 | } |
| 298 | |
Hervé Poussineau | 1f50791 | 2012-09-18 22:48:48 +0200 | [diff] [blame] | 299 | static void test_media_insert(void) |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 300 | { |
| 301 | uint8_t dir; |
| 302 | |
Pavel Hrdina | 7cd3316 | 2012-05-24 11:02:30 +0200 | [diff] [blame] | 303 | /* Insert media in drive. DSKCHK should not be reset until a step pulse |
| 304 | * is sent. */ |
Eric Blake | ccb61bd | 2017-04-27 16:58:20 -0500 | [diff] [blame] | 305 | qmp_discard_response("{'execute':'blockdev-change-medium', 'arguments':{" |
| 306 | " 'id':'floppy0', 'filename': %s, 'format': 'raw' }}", |
Stefan Hajnoczi | 0d1aa05 | 2013-10-30 14:54:32 +0100 | [diff] [blame] | 307 | test_image); |
Pavel Hrdina | 7cd3316 | 2012-05-24 11:02:30 +0200 | [diff] [blame] | 308 | |
| 309 | dir = inb(FLOPPY_BASE + reg_dir); |
| 310 | assert_bit_set(dir, DSKCHG); |
| 311 | dir = inb(FLOPPY_BASE + reg_dir); |
| 312 | assert_bit_set(dir, DSKCHG); |
| 313 | |
Kevin Wolf | c3cdc1b | 2012-07-16 16:06:56 +0200 | [diff] [blame] | 314 | send_seek(0); |
Pavel Hrdina | 59240c3 | 2012-07-04 16:26:04 +0200 | [diff] [blame] | 315 | dir = inb(FLOPPY_BASE + reg_dir); |
| 316 | assert_bit_set(dir, DSKCHG); |
| 317 | dir = inb(FLOPPY_BASE + reg_dir); |
| 318 | assert_bit_set(dir, DSKCHG); |
| 319 | |
| 320 | /* Step to next track should clear DSKCHG bit. */ |
Kevin Wolf | c3cdc1b | 2012-07-16 16:06:56 +0200 | [diff] [blame] | 321 | send_seek(1); |
Pavel Hrdina | 7cd3316 | 2012-05-24 11:02:30 +0200 | [diff] [blame] | 322 | dir = inb(FLOPPY_BASE + reg_dir); |
| 323 | assert_bit_clear(dir, DSKCHG); |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 324 | dir = inb(FLOPPY_BASE + reg_dir); |
| 325 | assert_bit_clear(dir, DSKCHG); |
Hervé Poussineau | 1f50791 | 2012-09-18 22:48:48 +0200 | [diff] [blame] | 326 | } |
| 327 | |
| 328 | static void test_media_change(void) |
| 329 | { |
| 330 | uint8_t dir; |
| 331 | |
| 332 | test_media_insert(); |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 333 | |
| 334 | /* Eject the floppy and check that DSKCHG is set. Reading it out doesn't |
| 335 | * reset the bit. */ |
Stefan Hajnoczi | 0d1aa05 | 2013-10-30 14:54:32 +0100 | [diff] [blame] | 336 | qmp_discard_response("{'execute':'eject', 'arguments':{" |
Eric Blake | ccb61bd | 2017-04-27 16:58:20 -0500 | [diff] [blame] | 337 | " 'id':'floppy0' }}"); |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 338 | |
| 339 | dir = inb(FLOPPY_BASE + reg_dir); |
| 340 | assert_bit_set(dir, DSKCHG); |
| 341 | dir = inb(FLOPPY_BASE + reg_dir); |
| 342 | assert_bit_set(dir, DSKCHG); |
| 343 | |
Kevin Wolf | c3cdc1b | 2012-07-16 16:06:56 +0200 | [diff] [blame] | 344 | send_seek(0); |
Pavel Hrdina | 59240c3 | 2012-07-04 16:26:04 +0200 | [diff] [blame] | 345 | dir = inb(FLOPPY_BASE + reg_dir); |
| 346 | assert_bit_set(dir, DSKCHG); |
| 347 | dir = inb(FLOPPY_BASE + reg_dir); |
| 348 | assert_bit_set(dir, DSKCHG); |
| 349 | |
Kevin Wolf | c3cdc1b | 2012-07-16 16:06:56 +0200 | [diff] [blame] | 350 | send_seek(1); |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 351 | dir = inb(FLOPPY_BASE + reg_dir); |
| 352 | assert_bit_set(dir, DSKCHG); |
| 353 | dir = inb(FLOPPY_BASE + reg_dir); |
| 354 | assert_bit_set(dir, DSKCHG); |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 355 | } |
| 356 | |
Pavel Hrdina | b3ce604 | 2012-07-04 11:18:35 +0200 | [diff] [blame] | 357 | static void test_sense_interrupt(void) |
| 358 | { |
| 359 | int drive = 0; |
| 360 | int head = 0; |
| 361 | int cyl = 0; |
| 362 | int ret = 0; |
| 363 | |
| 364 | floppy_send(CMD_SENSE_INT); |
| 365 | ret = floppy_recv(); |
| 366 | g_assert(ret == 0x80); |
| 367 | |
| 368 | floppy_send(CMD_SEEK); |
| 369 | floppy_send(head << 2 | drive); |
| 370 | g_assert(!get_irq(FLOPPY_IRQ)); |
| 371 | floppy_send(cyl); |
| 372 | |
| 373 | floppy_send(CMD_SENSE_INT); |
| 374 | ret = floppy_recv(); |
| 375 | g_assert(ret == 0x20); |
| 376 | floppy_recv(); |
| 377 | } |
| 378 | |
Pavel Hrdina | 98272db | 2012-07-16 15:48:27 +0200 | [diff] [blame] | 379 | static void test_relative_seek(void) |
| 380 | { |
| 381 | uint8_t drive = 0; |
| 382 | uint8_t head = 0; |
| 383 | uint8_t cyl = 1; |
Kevin Wolf | c3cdc1b | 2012-07-16 16:06:56 +0200 | [diff] [blame] | 384 | uint8_t pcn; |
Pavel Hrdina | 98272db | 2012-07-16 15:48:27 +0200 | [diff] [blame] | 385 | |
| 386 | /* Send seek to track 0 */ |
Kevin Wolf | c3cdc1b | 2012-07-16 16:06:56 +0200 | [diff] [blame] | 387 | send_seek(0); |
Pavel Hrdina | 98272db | 2012-07-16 15:48:27 +0200 | [diff] [blame] | 388 | |
| 389 | /* Send relative seek to increase track by 1 */ |
| 390 | floppy_send(CMD_RELATIVE_SEEK_IN); |
| 391 | floppy_send(head << 2 | drive); |
| 392 | g_assert(!get_irq(FLOPPY_IRQ)); |
| 393 | floppy_send(cyl); |
| 394 | |
Kevin Wolf | c3cdc1b | 2012-07-16 16:06:56 +0200 | [diff] [blame] | 395 | ack_irq(&pcn); |
| 396 | g_assert(pcn == 1); |
Pavel Hrdina | 98272db | 2012-07-16 15:48:27 +0200 | [diff] [blame] | 397 | |
| 398 | /* Send relative seek to decrease track by 1 */ |
| 399 | floppy_send(CMD_RELATIVE_SEEK_OUT); |
| 400 | floppy_send(head << 2 | drive); |
| 401 | g_assert(!get_irq(FLOPPY_IRQ)); |
| 402 | floppy_send(cyl); |
| 403 | |
Kevin Wolf | c3cdc1b | 2012-07-16 16:06:56 +0200 | [diff] [blame] | 404 | ack_irq(&pcn); |
| 405 | g_assert(pcn == 0); |
Pavel Hrdina | 98272db | 2012-07-16 15:48:27 +0200 | [diff] [blame] | 406 | } |
| 407 | |
Kevin Wolf | 67f194b | 2012-09-20 23:20:07 +0200 | [diff] [blame] | 408 | static void test_read_id(void) |
| 409 | { |
| 410 | uint8_t drive = 0; |
| 411 | uint8_t head = 0; |
| 412 | uint8_t cyl; |
| 413 | uint8_t st0; |
Kevin Wolf | 4964e18 | 2015-05-21 15:19:38 +0200 | [diff] [blame] | 414 | uint8_t msr; |
Kevin Wolf | 67f194b | 2012-09-20 23:20:07 +0200 | [diff] [blame] | 415 | |
| 416 | /* Seek to track 0 and check with READ ID */ |
| 417 | send_seek(0); |
| 418 | |
| 419 | floppy_send(CMD_READ_ID); |
| 420 | g_assert(!get_irq(FLOPPY_IRQ)); |
| 421 | floppy_send(head << 2 | drive); |
| 422 | |
Kevin Wolf | 4964e18 | 2015-05-21 15:19:38 +0200 | [diff] [blame] | 423 | msr = inb(FLOPPY_BASE + reg_msr); |
| 424 | if (!get_irq(FLOPPY_IRQ)) { |
| 425 | assert_bit_set(msr, BUSY); |
| 426 | assert_bit_clear(msr, RQM); |
| 427 | } |
| 428 | |
Kevin Wolf | 67f194b | 2012-09-20 23:20:07 +0200 | [diff] [blame] | 429 | while (!get_irq(FLOPPY_IRQ)) { |
| 430 | /* qemu involves a timer with READ ID... */ |
| 431 | clock_step(1000000000LL / 50); |
| 432 | } |
| 433 | |
Kevin Wolf | 4964e18 | 2015-05-21 15:19:38 +0200 | [diff] [blame] | 434 | msr = inb(FLOPPY_BASE + reg_msr); |
| 435 | assert_bit_set(msr, BUSY | RQM | DIO); |
| 436 | |
Kevin Wolf | 67f194b | 2012-09-20 23:20:07 +0200 | [diff] [blame] | 437 | st0 = floppy_recv(); |
| 438 | floppy_recv(); |
| 439 | floppy_recv(); |
| 440 | cyl = floppy_recv(); |
| 441 | head = floppy_recv(); |
| 442 | floppy_recv(); |
Kevin Wolf | 4964e18 | 2015-05-21 15:19:38 +0200 | [diff] [blame] | 443 | g_assert(get_irq(FLOPPY_IRQ)); |
Kevin Wolf | 67f194b | 2012-09-20 23:20:07 +0200 | [diff] [blame] | 444 | floppy_recv(); |
Kevin Wolf | 4964e18 | 2015-05-21 15:19:38 +0200 | [diff] [blame] | 445 | g_assert(!get_irq(FLOPPY_IRQ)); |
Kevin Wolf | 67f194b | 2012-09-20 23:20:07 +0200 | [diff] [blame] | 446 | |
| 447 | g_assert_cmpint(cyl, ==, 0); |
| 448 | g_assert_cmpint(head, ==, 0); |
| 449 | g_assert_cmpint(st0, ==, head << 2); |
| 450 | |
| 451 | /* Seek to track 8 on head 1 and check with READ ID */ |
| 452 | head = 1; |
| 453 | cyl = 8; |
| 454 | |
| 455 | floppy_send(CMD_SEEK); |
| 456 | floppy_send(head << 2 | drive); |
| 457 | g_assert(!get_irq(FLOPPY_IRQ)); |
| 458 | floppy_send(cyl); |
| 459 | g_assert(get_irq(FLOPPY_IRQ)); |
| 460 | ack_irq(NULL); |
| 461 | |
| 462 | floppy_send(CMD_READ_ID); |
| 463 | g_assert(!get_irq(FLOPPY_IRQ)); |
| 464 | floppy_send(head << 2 | drive); |
| 465 | |
Kevin Wolf | 4964e18 | 2015-05-21 15:19:38 +0200 | [diff] [blame] | 466 | msr = inb(FLOPPY_BASE + reg_msr); |
| 467 | if (!get_irq(FLOPPY_IRQ)) { |
| 468 | assert_bit_set(msr, BUSY); |
| 469 | assert_bit_clear(msr, RQM); |
| 470 | } |
| 471 | |
Kevin Wolf | 67f194b | 2012-09-20 23:20:07 +0200 | [diff] [blame] | 472 | while (!get_irq(FLOPPY_IRQ)) { |
| 473 | /* qemu involves a timer with READ ID... */ |
| 474 | clock_step(1000000000LL / 50); |
| 475 | } |
| 476 | |
Kevin Wolf | 4964e18 | 2015-05-21 15:19:38 +0200 | [diff] [blame] | 477 | msr = inb(FLOPPY_BASE + reg_msr); |
| 478 | assert_bit_set(msr, BUSY | RQM | DIO); |
| 479 | |
Kevin Wolf | 67f194b | 2012-09-20 23:20:07 +0200 | [diff] [blame] | 480 | st0 = floppy_recv(); |
| 481 | floppy_recv(); |
| 482 | floppy_recv(); |
| 483 | cyl = floppy_recv(); |
| 484 | head = floppy_recv(); |
| 485 | floppy_recv(); |
Kevin Wolf | 4964e18 | 2015-05-21 15:19:38 +0200 | [diff] [blame] | 486 | g_assert(get_irq(FLOPPY_IRQ)); |
Kevin Wolf | 67f194b | 2012-09-20 23:20:07 +0200 | [diff] [blame] | 487 | floppy_recv(); |
Kevin Wolf | 4964e18 | 2015-05-21 15:19:38 +0200 | [diff] [blame] | 488 | g_assert(!get_irq(FLOPPY_IRQ)); |
Kevin Wolf | 67f194b | 2012-09-20 23:20:07 +0200 | [diff] [blame] | 489 | |
| 490 | g_assert_cmpint(cyl, ==, 8); |
| 491 | g_assert_cmpint(head, ==, 1); |
| 492 | g_assert_cmpint(st0, ==, head << 2); |
| 493 | } |
| 494 | |
Hervé Poussineau | 5f8ae8e | 2012-09-18 23:02:59 +0200 | [diff] [blame] | 495 | static void test_read_no_dma_1(void) |
| 496 | { |
| 497 | uint8_t ret; |
| 498 | |
| 499 | outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08); |
| 500 | send_seek(0); |
Hervé Poussineau | 075f553 | 2012-09-20 23:07:53 +0200 | [diff] [blame] | 501 | ret = send_read_no_dma_command(1, 0x04); |
Hervé Poussineau | 5f8ae8e | 2012-09-18 23:02:59 +0200 | [diff] [blame] | 502 | g_assert(ret == 0); |
| 503 | } |
| 504 | |
| 505 | static void test_read_no_dma_18(void) |
| 506 | { |
| 507 | uint8_t ret; |
| 508 | |
| 509 | outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08); |
| 510 | send_seek(0); |
Hervé Poussineau | 075f553 | 2012-09-20 23:07:53 +0200 | [diff] [blame] | 511 | ret = send_read_no_dma_command(18, 0x04); |
Hervé Poussineau | 5f8ae8e | 2012-09-18 23:02:59 +0200 | [diff] [blame] | 512 | g_assert(ret == 0); |
| 513 | } |
| 514 | |
| 515 | static void test_read_no_dma_19(void) |
| 516 | { |
| 517 | uint8_t ret; |
| 518 | |
| 519 | outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08); |
| 520 | send_seek(0); |
| 521 | ret = send_read_no_dma_command(19, 0x20); |
| 522 | g_assert(ret == 0); |
| 523 | } |
| 524 | |
Hervé Poussineau | 6f442fe | 2012-09-18 23:04:56 +0200 | [diff] [blame] | 525 | static void test_verify(void) |
| 526 | { |
| 527 | uint8_t ret; |
| 528 | |
| 529 | ret = send_read_command(CMD_VERIFY); |
| 530 | g_assert(ret == 0); |
| 531 | } |
| 532 | |
Blue Swirl | 3359847 | 2012-05-17 18:55:58 +0000 | [diff] [blame] | 533 | /* success if no crash or abort */ |
| 534 | static void fuzz_registers(void) |
| 535 | { |
| 536 | unsigned int i; |
| 537 | |
| 538 | for (i = 0; i < 1000; i++) { |
| 539 | uint8_t reg, val; |
| 540 | |
| 541 | reg = (uint8_t)g_test_rand_int_range(0, 8); |
| 542 | val = (uint8_t)g_test_rand_int_range(0, 256); |
| 543 | |
| 544 | outb(FLOPPY_BASE + reg, val); |
| 545 | inb(FLOPPY_BASE + reg); |
| 546 | } |
| 547 | } |
| 548 | |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 549 | int main(int argc, char **argv) |
| 550 | { |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 551 | int fd; |
| 552 | int ret; |
| 553 | |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 554 | /* Create a temporary raw image */ |
| 555 | fd = mkstemp(test_image); |
| 556 | g_assert(fd >= 0); |
| 557 | ret = ftruncate(fd, TEST_IMAGE_SIZE); |
| 558 | g_assert(ret == 0); |
| 559 | close(fd); |
| 560 | |
| 561 | /* Run the tests */ |
| 562 | g_test_init(&argc, &argv, NULL); |
| 563 | |
Eric Blake | ccb61bd | 2017-04-27 16:58:20 -0500 | [diff] [blame] | 564 | qtest_start("-device floppy,id=floppy0"); |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 565 | qtest_irq_intercept_in(global_qtest, "ioapic"); |
Pavel Hrdina | 7cd3316 | 2012-05-24 11:02:30 +0200 | [diff] [blame] | 566 | qtest_add_func("/fdc/cmos", test_cmos); |
| 567 | qtest_add_func("/fdc/no_media_on_start", test_no_media_on_start); |
Pavel Hrdina | 8b9ef60 | 2012-06-13 15:43:12 +0200 | [diff] [blame] | 568 | qtest_add_func("/fdc/read_without_media", test_read_without_media); |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 569 | qtest_add_func("/fdc/media_change", test_media_change); |
Pavel Hrdina | b3ce604 | 2012-07-04 11:18:35 +0200 | [diff] [blame] | 570 | qtest_add_func("/fdc/sense_interrupt", test_sense_interrupt); |
Pavel Hrdina | 98272db | 2012-07-16 15:48:27 +0200 | [diff] [blame] | 571 | qtest_add_func("/fdc/relative_seek", test_relative_seek); |
Kevin Wolf | 67f194b | 2012-09-20 23:20:07 +0200 | [diff] [blame] | 572 | qtest_add_func("/fdc/read_id", test_read_id); |
Hervé Poussineau | 6f442fe | 2012-09-18 23:04:56 +0200 | [diff] [blame] | 573 | qtest_add_func("/fdc/verify", test_verify); |
Hervé Poussineau | 44212dc | 2012-09-18 22:49:30 +0200 | [diff] [blame] | 574 | qtest_add_func("/fdc/media_insert", test_media_insert); |
Hervé Poussineau | 5f8ae8e | 2012-09-18 23:02:59 +0200 | [diff] [blame] | 575 | qtest_add_func("/fdc/read_no_dma_1", test_read_no_dma_1); |
| 576 | qtest_add_func("/fdc/read_no_dma_18", test_read_no_dma_18); |
| 577 | qtest_add_func("/fdc/read_no_dma_19", test_read_no_dma_19); |
Blue Swirl | 3359847 | 2012-05-17 18:55:58 +0000 | [diff] [blame] | 578 | qtest_add_func("/fdc/fuzz-registers", fuzz_registers); |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 579 | |
| 580 | ret = g_test_run(); |
| 581 | |
| 582 | /* Cleanup */ |
Markus Armbruster | 1d9358e | 2013-06-20 08:55:29 +0200 | [diff] [blame] | 583 | qtest_end(); |
Kevin Wolf | 93e9eb6 | 2012-05-08 16:38:37 +0200 | [diff] [blame] | 584 | unlink(test_image); |
| 585 | |
| 586 | return ret; |
| 587 | } |