Statistics
| Branch: | Revision:

root / tests / fdc-test.c @ e4b42e6e

History | View | Annotate | Download (12.6 kB)

1 93e9eb68 Kevin Wolf
/*
2 93e9eb68 Kevin Wolf
 * Floppy test cases.
3 93e9eb68 Kevin Wolf
 *
4 93e9eb68 Kevin Wolf
 * Copyright (c) 2012 Kevin Wolf <kwolf@redhat.com>
5 93e9eb68 Kevin Wolf
 *
6 93e9eb68 Kevin Wolf
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 93e9eb68 Kevin Wolf
 * of this software and associated documentation files (the "Software"), to deal
8 93e9eb68 Kevin Wolf
 * in the Software without restriction, including without limitation the rights
9 93e9eb68 Kevin Wolf
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 93e9eb68 Kevin Wolf
 * copies of the Software, and to permit persons to whom the Software is
11 93e9eb68 Kevin Wolf
 * furnished to do so, subject to the following conditions:
12 93e9eb68 Kevin Wolf
 *
13 93e9eb68 Kevin Wolf
 * The above copyright notice and this permission notice shall be included in
14 93e9eb68 Kevin Wolf
 * all copies or substantial portions of the Software.
15 93e9eb68 Kevin Wolf
 *
16 93e9eb68 Kevin Wolf
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 93e9eb68 Kevin Wolf
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 93e9eb68 Kevin Wolf
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 93e9eb68 Kevin Wolf
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 93e9eb68 Kevin Wolf
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 93e9eb68 Kevin Wolf
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 93e9eb68 Kevin Wolf
 * THE SOFTWARE.
23 93e9eb68 Kevin Wolf
 */
24 93e9eb68 Kevin Wolf
25 93e9eb68 Kevin Wolf
#include <stdint.h>
26 93e9eb68 Kevin Wolf
#include <string.h>
27 93e9eb68 Kevin Wolf
#include <stdio.h>
28 93e9eb68 Kevin Wolf
29 93e9eb68 Kevin Wolf
#include <glib.h>
30 93e9eb68 Kevin Wolf
31 93e9eb68 Kevin Wolf
#include "libqtest.h"
32 93e9eb68 Kevin Wolf
#include "qemu-common.h"
33 93e9eb68 Kevin Wolf
34 93e9eb68 Kevin Wolf
#define TEST_IMAGE_SIZE 1440 * 1024
35 93e9eb68 Kevin Wolf
36 93e9eb68 Kevin Wolf
#define FLOPPY_BASE 0x3f0
37 93e9eb68 Kevin Wolf
#define FLOPPY_IRQ 6
38 93e9eb68 Kevin Wolf
39 93e9eb68 Kevin Wolf
enum {
40 93e9eb68 Kevin Wolf
    reg_sra         = 0x0,
41 93e9eb68 Kevin Wolf
    reg_srb         = 0x1,
42 93e9eb68 Kevin Wolf
    reg_dor         = 0x2,
43 93e9eb68 Kevin Wolf
    reg_msr         = 0x4,
44 93e9eb68 Kevin Wolf
    reg_dsr         = 0x4,
45 93e9eb68 Kevin Wolf
    reg_fifo        = 0x5,
46 93e9eb68 Kevin Wolf
    reg_dir         = 0x7,
47 93e9eb68 Kevin Wolf
};
48 93e9eb68 Kevin Wolf
49 93e9eb68 Kevin Wolf
enum {
50 98272dbb Pavel Hrdina
    CMD_SENSE_INT           = 0x08,
51 67f194bd Kevin Wolf
    CMD_READ_ID             = 0x0a,
52 98272dbb Pavel Hrdina
    CMD_SEEK                = 0x0f,
53 6f442fe8 Hervé Poussineau
    CMD_VERIFY              = 0x16,
54 98272dbb Pavel Hrdina
    CMD_READ                = 0xe6,
55 98272dbb Pavel Hrdina
    CMD_RELATIVE_SEEK_OUT   = 0x8f,
56 98272dbb Pavel Hrdina
    CMD_RELATIVE_SEEK_IN    = 0xcf,
57 93e9eb68 Kevin Wolf
};
58 93e9eb68 Kevin Wolf
59 93e9eb68 Kevin Wolf
enum {
60 5f8ae8e2 Hervé Poussineau
    BUSY    = 0x10,
61 5f8ae8e2 Hervé Poussineau
    NONDMA  = 0x20,
62 93e9eb68 Kevin Wolf
    RQM     = 0x80,
63 93e9eb68 Kevin Wolf
    DIO     = 0x40,
64 93e9eb68 Kevin Wolf
65 93e9eb68 Kevin Wolf
    DSKCHG  = 0x80,
66 93e9eb68 Kevin Wolf
};
67 93e9eb68 Kevin Wolf
68 93e9eb68 Kevin Wolf
char test_image[] = "/tmp/qtest.XXXXXX";
69 93e9eb68 Kevin Wolf
70 93e9eb68 Kevin Wolf
#define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask))
71 93e9eb68 Kevin Wolf
#define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0)
72 93e9eb68 Kevin Wolf
73 7cd33161 Pavel Hrdina
static uint8_t base = 0x70;
74 7cd33161 Pavel Hrdina
75 7cd33161 Pavel Hrdina
enum {
76 7cd33161 Pavel Hrdina
    CMOS_FLOPPY     = 0x10,
77 7cd33161 Pavel Hrdina
};
78 7cd33161 Pavel Hrdina
79 93e9eb68 Kevin Wolf
static void floppy_send(uint8_t byte)
80 93e9eb68 Kevin Wolf
{
81 93e9eb68 Kevin Wolf
    uint8_t msr;
82 93e9eb68 Kevin Wolf
83 93e9eb68 Kevin Wolf
    msr = inb(FLOPPY_BASE + reg_msr);
84 93e9eb68 Kevin Wolf
    assert_bit_set(msr, RQM);
85 93e9eb68 Kevin Wolf
    assert_bit_clear(msr, DIO);
86 93e9eb68 Kevin Wolf
87 93e9eb68 Kevin Wolf
    outb(FLOPPY_BASE + reg_fifo, byte);
88 93e9eb68 Kevin Wolf
}
89 93e9eb68 Kevin Wolf
90 93e9eb68 Kevin Wolf
static uint8_t floppy_recv(void)
91 93e9eb68 Kevin Wolf
{
92 93e9eb68 Kevin Wolf
    uint8_t msr;
93 93e9eb68 Kevin Wolf
94 93e9eb68 Kevin Wolf
    msr = inb(FLOPPY_BASE + reg_msr);
95 93e9eb68 Kevin Wolf
    assert_bit_set(msr, RQM | DIO);
96 93e9eb68 Kevin Wolf
97 93e9eb68 Kevin Wolf
    return inb(FLOPPY_BASE + reg_fifo);
98 93e9eb68 Kevin Wolf
}
99 93e9eb68 Kevin Wolf
100 c3cdc1b0 Kevin Wolf
/* pcn: Present Cylinder Number */
101 c3cdc1b0 Kevin Wolf
static void ack_irq(uint8_t *pcn)
102 93e9eb68 Kevin Wolf
{
103 98272dbb Pavel Hrdina
    uint8_t ret;
104 98272dbb Pavel Hrdina
105 93e9eb68 Kevin Wolf
    g_assert(get_irq(FLOPPY_IRQ));
106 93e9eb68 Kevin Wolf
    floppy_send(CMD_SENSE_INT);
107 93e9eb68 Kevin Wolf
    floppy_recv();
108 c3cdc1b0 Kevin Wolf
109 98272dbb Pavel Hrdina
    ret = floppy_recv();
110 c3cdc1b0 Kevin Wolf
    if (pcn != NULL) {
111 c3cdc1b0 Kevin Wolf
        *pcn = ret;
112 c3cdc1b0 Kevin Wolf
    }
113 98272dbb Pavel Hrdina
114 c3cdc1b0 Kevin Wolf
    g_assert(!get_irq(FLOPPY_IRQ));
115 93e9eb68 Kevin Wolf
}
116 93e9eb68 Kevin Wolf
117 6f442fe8 Hervé Poussineau
static uint8_t send_read_command(uint8_t cmd)
118 8b9ef60d Pavel Hrdina
{
119 8b9ef60d Pavel Hrdina
    uint8_t drive = 0;
120 8b9ef60d Pavel Hrdina
    uint8_t head = 0;
121 8b9ef60d Pavel Hrdina
    uint8_t cyl = 0;
122 8b9ef60d Pavel Hrdina
    uint8_t sect_addr = 1;
123 8b9ef60d Pavel Hrdina
    uint8_t sect_size = 2;
124 8b9ef60d Pavel Hrdina
    uint8_t eot = 1;
125 8b9ef60d Pavel Hrdina
    uint8_t gap = 0x1b;
126 8b9ef60d Pavel Hrdina
    uint8_t gpl = 0xff;
127 8b9ef60d Pavel Hrdina
128 8b9ef60d Pavel Hrdina
    uint8_t msr = 0;
129 8b9ef60d Pavel Hrdina
    uint8_t st0;
130 8b9ef60d Pavel Hrdina
131 8b9ef60d Pavel Hrdina
    uint8_t ret = 0;
132 8b9ef60d Pavel Hrdina
133 6f442fe8 Hervé Poussineau
    floppy_send(cmd);
134 8b9ef60d Pavel Hrdina
    floppy_send(head << 2 | drive);
135 8b9ef60d Pavel Hrdina
    g_assert(!get_irq(FLOPPY_IRQ));
136 8b9ef60d Pavel Hrdina
    floppy_send(cyl);
137 8b9ef60d Pavel Hrdina
    floppy_send(head);
138 8b9ef60d Pavel Hrdina
    floppy_send(sect_addr);
139 8b9ef60d Pavel Hrdina
    floppy_send(sect_size);
140 8b9ef60d Pavel Hrdina
    floppy_send(eot);
141 8b9ef60d Pavel Hrdina
    floppy_send(gap);
142 8b9ef60d Pavel Hrdina
    floppy_send(gpl);
143 8b9ef60d Pavel Hrdina
144 8b9ef60d Pavel Hrdina
    uint8_t i = 0;
145 8b9ef60d Pavel Hrdina
    uint8_t n = 2;
146 8b9ef60d Pavel Hrdina
    for (; i < n; i++) {
147 8b9ef60d Pavel Hrdina
        msr = inb(FLOPPY_BASE + reg_msr);
148 8b9ef60d Pavel Hrdina
        if (msr == 0xd0) {
149 8b9ef60d Pavel Hrdina
            break;
150 8b9ef60d Pavel Hrdina
        }
151 8b9ef60d Pavel Hrdina
        sleep(1);
152 8b9ef60d Pavel Hrdina
    }
153 8b9ef60d Pavel Hrdina
154 8b9ef60d Pavel Hrdina
    if (i >= n) {
155 8b9ef60d Pavel Hrdina
        return 1;
156 8b9ef60d Pavel Hrdina
    }
157 8b9ef60d Pavel Hrdina
158 8b9ef60d Pavel Hrdina
    st0 = floppy_recv();
159 075f5532 Hervé Poussineau
    if (st0 != 0x40) {
160 8b9ef60d Pavel Hrdina
        ret = 1;
161 8b9ef60d Pavel Hrdina
    }
162 8b9ef60d Pavel Hrdina
163 8b9ef60d Pavel Hrdina
    floppy_recv();
164 8b9ef60d Pavel Hrdina
    floppy_recv();
165 8b9ef60d Pavel Hrdina
    floppy_recv();
166 8b9ef60d Pavel Hrdina
    floppy_recv();
167 8b9ef60d Pavel Hrdina
    floppy_recv();
168 8b9ef60d Pavel Hrdina
    floppy_recv();
169 8b9ef60d Pavel Hrdina
170 8b9ef60d Pavel Hrdina
    return ret;
171 8b9ef60d Pavel Hrdina
}
172 8b9ef60d Pavel Hrdina
173 5f8ae8e2 Hervé Poussineau
static uint8_t send_read_no_dma_command(int nb_sect, uint8_t expected_st0)
174 5f8ae8e2 Hervé Poussineau
{
175 5f8ae8e2 Hervé Poussineau
    uint8_t drive = 0;
176 5f8ae8e2 Hervé Poussineau
    uint8_t head = 0;
177 5f8ae8e2 Hervé Poussineau
    uint8_t cyl = 0;
178 5f8ae8e2 Hervé Poussineau
    uint8_t sect_addr = 1;
179 5f8ae8e2 Hervé Poussineau
    uint8_t sect_size = 2;
180 5f8ae8e2 Hervé Poussineau
    uint8_t eot = nb_sect;
181 5f8ae8e2 Hervé Poussineau
    uint8_t gap = 0x1b;
182 5f8ae8e2 Hervé Poussineau
    uint8_t gpl = 0xff;
183 5f8ae8e2 Hervé Poussineau
184 5f8ae8e2 Hervé Poussineau
    uint8_t msr = 0;
185 5f8ae8e2 Hervé Poussineau
    uint8_t st0;
186 5f8ae8e2 Hervé Poussineau
187 5f8ae8e2 Hervé Poussineau
    uint8_t ret = 0;
188 5f8ae8e2 Hervé Poussineau
189 5f8ae8e2 Hervé Poussineau
    floppy_send(CMD_READ);
190 5f8ae8e2 Hervé Poussineau
    floppy_send(head << 2 | drive);
191 5f8ae8e2 Hervé Poussineau
    g_assert(!get_irq(FLOPPY_IRQ));
192 5f8ae8e2 Hervé Poussineau
    floppy_send(cyl);
193 5f8ae8e2 Hervé Poussineau
    floppy_send(head);
194 5f8ae8e2 Hervé Poussineau
    floppy_send(sect_addr);
195 5f8ae8e2 Hervé Poussineau
    floppy_send(sect_size);
196 5f8ae8e2 Hervé Poussineau
    floppy_send(eot);
197 5f8ae8e2 Hervé Poussineau
    floppy_send(gap);
198 5f8ae8e2 Hervé Poussineau
    floppy_send(gpl);
199 5f8ae8e2 Hervé Poussineau
200 5f8ae8e2 Hervé Poussineau
    uint16_t i = 0;
201 5f8ae8e2 Hervé Poussineau
    uint8_t n = 2;
202 5f8ae8e2 Hervé Poussineau
    for (; i < n; i++) {
203 5f8ae8e2 Hervé Poussineau
        msr = inb(FLOPPY_BASE + reg_msr);
204 5f8ae8e2 Hervé Poussineau
        if (msr == (BUSY | NONDMA | DIO | RQM)) {
205 5f8ae8e2 Hervé Poussineau
            break;
206 5f8ae8e2 Hervé Poussineau
        }
207 5f8ae8e2 Hervé Poussineau
        sleep(1);
208 5f8ae8e2 Hervé Poussineau
    }
209 5f8ae8e2 Hervé Poussineau
210 5f8ae8e2 Hervé Poussineau
    if (i >= n) {
211 5f8ae8e2 Hervé Poussineau
        return 1;
212 5f8ae8e2 Hervé Poussineau
    }
213 5f8ae8e2 Hervé Poussineau
214 5f8ae8e2 Hervé Poussineau
    /* Non-DMA mode */
215 5f8ae8e2 Hervé Poussineau
    for (i = 0; i < 512 * 2 * nb_sect; i++) {
216 5f8ae8e2 Hervé Poussineau
        msr = inb(FLOPPY_BASE + reg_msr);
217 5f8ae8e2 Hervé Poussineau
        assert_bit_set(msr, BUSY | RQM | DIO);
218 5f8ae8e2 Hervé Poussineau
        inb(FLOPPY_BASE + reg_fifo);
219 5f8ae8e2 Hervé Poussineau
    }
220 5f8ae8e2 Hervé Poussineau
221 5f8ae8e2 Hervé Poussineau
    st0 = floppy_recv();
222 5f8ae8e2 Hervé Poussineau
    if (st0 != expected_st0) {
223 5f8ae8e2 Hervé Poussineau
        ret = 1;
224 5f8ae8e2 Hervé Poussineau
    }
225 5f8ae8e2 Hervé Poussineau
226 5f8ae8e2 Hervé Poussineau
    floppy_recv();
227 5f8ae8e2 Hervé Poussineau
    floppy_recv();
228 5f8ae8e2 Hervé Poussineau
    floppy_recv();
229 5f8ae8e2 Hervé Poussineau
    floppy_recv();
230 5f8ae8e2 Hervé Poussineau
    floppy_recv();
231 5f8ae8e2 Hervé Poussineau
    floppy_recv();
232 5f8ae8e2 Hervé Poussineau
233 5f8ae8e2 Hervé Poussineau
    return ret;
234 5f8ae8e2 Hervé Poussineau
}
235 5f8ae8e2 Hervé Poussineau
236 c3cdc1b0 Kevin Wolf
static void send_seek(int cyl)
237 93e9eb68 Kevin Wolf
{
238 93e9eb68 Kevin Wolf
    int drive = 0;
239 93e9eb68 Kevin Wolf
    int head = 0;
240 93e9eb68 Kevin Wolf
241 93e9eb68 Kevin Wolf
    floppy_send(CMD_SEEK);
242 93e9eb68 Kevin Wolf
    floppy_send(head << 2 | drive);
243 93e9eb68 Kevin Wolf
    g_assert(!get_irq(FLOPPY_IRQ));
244 93e9eb68 Kevin Wolf
    floppy_send(cyl);
245 c3cdc1b0 Kevin Wolf
    ack_irq(NULL);
246 93e9eb68 Kevin Wolf
}
247 93e9eb68 Kevin Wolf
248 7cd33161 Pavel Hrdina
static uint8_t cmos_read(uint8_t reg)
249 93e9eb68 Kevin Wolf
{
250 7cd33161 Pavel Hrdina
    outb(base + 0, reg);
251 7cd33161 Pavel Hrdina
    return inb(base + 1);
252 7cd33161 Pavel Hrdina
}
253 93e9eb68 Kevin Wolf
254 7cd33161 Pavel Hrdina
static void test_cmos(void)
255 7cd33161 Pavel Hrdina
{
256 7cd33161 Pavel Hrdina
    uint8_t cmos;
257 93e9eb68 Kevin Wolf
258 7cd33161 Pavel Hrdina
    cmos = cmos_read(CMOS_FLOPPY);
259 7cd33161 Pavel Hrdina
    g_assert(cmos == 0x40);
260 7cd33161 Pavel Hrdina
}
261 93e9eb68 Kevin Wolf
262 7cd33161 Pavel Hrdina
static void test_no_media_on_start(void)
263 7cd33161 Pavel Hrdina
{
264 7cd33161 Pavel Hrdina
    uint8_t dir;
265 7cd33161 Pavel Hrdina
266 7cd33161 Pavel Hrdina
    /* Media changed bit must be set all time after start if there is
267 7cd33161 Pavel Hrdina
     * no media in drive. */
268 93e9eb68 Kevin Wolf
    dir = inb(FLOPPY_BASE + reg_dir);
269 93e9eb68 Kevin Wolf
    assert_bit_set(dir, DSKCHG);
270 93e9eb68 Kevin Wolf
    dir = inb(FLOPPY_BASE + reg_dir);
271 93e9eb68 Kevin Wolf
    assert_bit_set(dir, DSKCHG);
272 c3cdc1b0 Kevin Wolf
    send_seek(1);
273 93e9eb68 Kevin Wolf
    dir = inb(FLOPPY_BASE + reg_dir);
274 93e9eb68 Kevin Wolf
    assert_bit_set(dir, DSKCHG);
275 93e9eb68 Kevin Wolf
    dir = inb(FLOPPY_BASE + reg_dir);
276 93e9eb68 Kevin Wolf
    assert_bit_set(dir, DSKCHG);
277 7cd33161 Pavel Hrdina
}
278 7cd33161 Pavel Hrdina
279 8b9ef60d Pavel Hrdina
static void test_read_without_media(void)
280 8b9ef60d Pavel Hrdina
{
281 8b9ef60d Pavel Hrdina
    uint8_t ret;
282 8b9ef60d Pavel Hrdina
283 6f442fe8 Hervé Poussineau
    ret = send_read_command(CMD_READ);
284 8b9ef60d Pavel Hrdina
    g_assert(ret == 0);
285 8b9ef60d Pavel Hrdina
}
286 8b9ef60d Pavel Hrdina
287 1f507913 Hervé Poussineau
static void test_media_insert(void)
288 7cd33161 Pavel Hrdina
{
289 7cd33161 Pavel Hrdina
    uint8_t dir;
290 93e9eb68 Kevin Wolf
291 7cd33161 Pavel Hrdina
    /* Insert media in drive. DSKCHK should not be reset until a step pulse
292 93e9eb68 Kevin Wolf
     * is sent. */
293 93e9eb68 Kevin Wolf
    qmp("{'execute':'change', 'arguments':{ 'device':'floppy0', "
294 93e9eb68 Kevin Wolf
        "'target': '%s' }}", test_image);
295 93e9eb68 Kevin Wolf
    qmp(""); /* ignore event (FIXME open -> open transition?!) */
296 93e9eb68 Kevin Wolf
    qmp(""); /* ignore event */
297 93e9eb68 Kevin Wolf
298 93e9eb68 Kevin Wolf
    dir = inb(FLOPPY_BASE + reg_dir);
299 93e9eb68 Kevin Wolf
    assert_bit_set(dir, DSKCHG);
300 93e9eb68 Kevin Wolf
    dir = inb(FLOPPY_BASE + reg_dir);
301 93e9eb68 Kevin Wolf
    assert_bit_set(dir, DSKCHG);
302 93e9eb68 Kevin Wolf
303 c3cdc1b0 Kevin Wolf
    send_seek(0);
304 59240c34 Pavel Hrdina
    dir = inb(FLOPPY_BASE + reg_dir);
305 59240c34 Pavel Hrdina
    assert_bit_set(dir, DSKCHG);
306 59240c34 Pavel Hrdina
    dir = inb(FLOPPY_BASE + reg_dir);
307 59240c34 Pavel Hrdina
    assert_bit_set(dir, DSKCHG);
308 59240c34 Pavel Hrdina
309 59240c34 Pavel Hrdina
    /* Step to next track should clear DSKCHG bit. */
310 c3cdc1b0 Kevin Wolf
    send_seek(1);
311 93e9eb68 Kevin Wolf
    dir = inb(FLOPPY_BASE + reg_dir);
312 93e9eb68 Kevin Wolf
    assert_bit_clear(dir, DSKCHG);
313 93e9eb68 Kevin Wolf
    dir = inb(FLOPPY_BASE + reg_dir);
314 93e9eb68 Kevin Wolf
    assert_bit_clear(dir, DSKCHG);
315 1f507913 Hervé Poussineau
}
316 1f507913 Hervé Poussineau
317 1f507913 Hervé Poussineau
static void test_media_change(void)
318 1f507913 Hervé Poussineau
{
319 1f507913 Hervé Poussineau
    uint8_t dir;
320 1f507913 Hervé Poussineau
321 1f507913 Hervé Poussineau
    test_media_insert();
322 7cd33161 Pavel Hrdina
323 7cd33161 Pavel Hrdina
    /* Eject the floppy and check that DSKCHG is set. Reading it out doesn't
324 7cd33161 Pavel Hrdina
     * reset the bit. */
325 7cd33161 Pavel Hrdina
    qmp("{'execute':'eject', 'arguments':{ 'device':'floppy0' }}");
326 7cd33161 Pavel Hrdina
    qmp(""); /* ignore event */
327 7cd33161 Pavel Hrdina
328 7cd33161 Pavel Hrdina
    dir = inb(FLOPPY_BASE + reg_dir);
329 7cd33161 Pavel Hrdina
    assert_bit_set(dir, DSKCHG);
330 7cd33161 Pavel Hrdina
    dir = inb(FLOPPY_BASE + reg_dir);
331 7cd33161 Pavel Hrdina
    assert_bit_set(dir, DSKCHG);
332 7cd33161 Pavel Hrdina
333 c3cdc1b0 Kevin Wolf
    send_seek(0);
334 59240c34 Pavel Hrdina
    dir = inb(FLOPPY_BASE + reg_dir);
335 59240c34 Pavel Hrdina
    assert_bit_set(dir, DSKCHG);
336 59240c34 Pavel Hrdina
    dir = inb(FLOPPY_BASE + reg_dir);
337 59240c34 Pavel Hrdina
    assert_bit_set(dir, DSKCHG);
338 59240c34 Pavel Hrdina
339 c3cdc1b0 Kevin Wolf
    send_seek(1);
340 7cd33161 Pavel Hrdina
    dir = inb(FLOPPY_BASE + reg_dir);
341 7cd33161 Pavel Hrdina
    assert_bit_set(dir, DSKCHG);
342 7cd33161 Pavel Hrdina
    dir = inb(FLOPPY_BASE + reg_dir);
343 7cd33161 Pavel Hrdina
    assert_bit_set(dir, DSKCHG);
344 93e9eb68 Kevin Wolf
}
345 93e9eb68 Kevin Wolf
346 b3ce604e Pavel Hrdina
static void test_sense_interrupt(void)
347 b3ce604e Pavel Hrdina
{
348 b3ce604e Pavel Hrdina
    int drive = 0;
349 b3ce604e Pavel Hrdina
    int head = 0;
350 b3ce604e Pavel Hrdina
    int cyl = 0;
351 b3ce604e Pavel Hrdina
    int ret = 0;
352 b3ce604e Pavel Hrdina
353 b3ce604e Pavel Hrdina
    floppy_send(CMD_SENSE_INT);
354 b3ce604e Pavel Hrdina
    ret = floppy_recv();
355 b3ce604e Pavel Hrdina
    g_assert(ret == 0x80);
356 b3ce604e Pavel Hrdina
357 b3ce604e Pavel Hrdina
    floppy_send(CMD_SEEK);
358 b3ce604e Pavel Hrdina
    floppy_send(head << 2 | drive);
359 b3ce604e Pavel Hrdina
    g_assert(!get_irq(FLOPPY_IRQ));
360 b3ce604e Pavel Hrdina
    floppy_send(cyl);
361 b3ce604e Pavel Hrdina
362 b3ce604e Pavel Hrdina
    floppy_send(CMD_SENSE_INT);
363 b3ce604e Pavel Hrdina
    ret = floppy_recv();
364 b3ce604e Pavel Hrdina
    g_assert(ret == 0x20);
365 b3ce604e Pavel Hrdina
    floppy_recv();
366 b3ce604e Pavel Hrdina
}
367 b3ce604e Pavel Hrdina
368 98272dbb Pavel Hrdina
static void test_relative_seek(void)
369 98272dbb Pavel Hrdina
{
370 98272dbb Pavel Hrdina
    uint8_t drive = 0;
371 98272dbb Pavel Hrdina
    uint8_t head = 0;
372 98272dbb Pavel Hrdina
    uint8_t cyl = 1;
373 c3cdc1b0 Kevin Wolf
    uint8_t pcn;
374 98272dbb Pavel Hrdina
375 98272dbb Pavel Hrdina
    /* Send seek to track 0 */
376 c3cdc1b0 Kevin Wolf
    send_seek(0);
377 98272dbb Pavel Hrdina
378 98272dbb Pavel Hrdina
    /* Send relative seek to increase track by 1 */
379 98272dbb Pavel Hrdina
    floppy_send(CMD_RELATIVE_SEEK_IN);
380 98272dbb Pavel Hrdina
    floppy_send(head << 2 | drive);
381 98272dbb Pavel Hrdina
    g_assert(!get_irq(FLOPPY_IRQ));
382 98272dbb Pavel Hrdina
    floppy_send(cyl);
383 98272dbb Pavel Hrdina
384 c3cdc1b0 Kevin Wolf
    ack_irq(&pcn);
385 c3cdc1b0 Kevin Wolf
    g_assert(pcn == 1);
386 98272dbb Pavel Hrdina
387 98272dbb Pavel Hrdina
    /* Send relative seek to decrease track by 1 */
388 98272dbb Pavel Hrdina
    floppy_send(CMD_RELATIVE_SEEK_OUT);
389 98272dbb Pavel Hrdina
    floppy_send(head << 2 | drive);
390 98272dbb Pavel Hrdina
    g_assert(!get_irq(FLOPPY_IRQ));
391 98272dbb Pavel Hrdina
    floppy_send(cyl);
392 98272dbb Pavel Hrdina
393 c3cdc1b0 Kevin Wolf
    ack_irq(&pcn);
394 c3cdc1b0 Kevin Wolf
    g_assert(pcn == 0);
395 98272dbb Pavel Hrdina
}
396 98272dbb Pavel Hrdina
397 67f194bd Kevin Wolf
static void test_read_id(void)
398 67f194bd Kevin Wolf
{
399 67f194bd Kevin Wolf
    uint8_t drive = 0;
400 67f194bd Kevin Wolf
    uint8_t head = 0;
401 67f194bd Kevin Wolf
    uint8_t cyl;
402 67f194bd Kevin Wolf
    uint8_t st0;
403 67f194bd Kevin Wolf
404 67f194bd Kevin Wolf
    /* Seek to track 0 and check with READ ID */
405 67f194bd Kevin Wolf
    send_seek(0);
406 67f194bd Kevin Wolf
407 67f194bd Kevin Wolf
    floppy_send(CMD_READ_ID);
408 67f194bd Kevin Wolf
    g_assert(!get_irq(FLOPPY_IRQ));
409 67f194bd Kevin Wolf
    floppy_send(head << 2 | drive);
410 67f194bd Kevin Wolf
411 67f194bd Kevin Wolf
    while (!get_irq(FLOPPY_IRQ)) {
412 67f194bd Kevin Wolf
        /* qemu involves a timer with READ ID... */
413 67f194bd Kevin Wolf
        clock_step(1000000000LL / 50);
414 67f194bd Kevin Wolf
    }
415 67f194bd Kevin Wolf
416 67f194bd Kevin Wolf
    st0 = floppy_recv();
417 67f194bd Kevin Wolf
    floppy_recv();
418 67f194bd Kevin Wolf
    floppy_recv();
419 67f194bd Kevin Wolf
    cyl = floppy_recv();
420 67f194bd Kevin Wolf
    head = floppy_recv();
421 67f194bd Kevin Wolf
    floppy_recv();
422 67f194bd Kevin Wolf
    floppy_recv();
423 67f194bd Kevin Wolf
424 67f194bd Kevin Wolf
    g_assert_cmpint(cyl, ==, 0);
425 67f194bd Kevin Wolf
    g_assert_cmpint(head, ==, 0);
426 67f194bd Kevin Wolf
    g_assert_cmpint(st0, ==, head << 2);
427 67f194bd Kevin Wolf
428 67f194bd Kevin Wolf
    /* Seek to track 8 on head 1 and check with READ ID */
429 67f194bd Kevin Wolf
    head = 1;
430 67f194bd Kevin Wolf
    cyl = 8;
431 67f194bd Kevin Wolf
432 67f194bd Kevin Wolf
    floppy_send(CMD_SEEK);
433 67f194bd Kevin Wolf
    floppy_send(head << 2 | drive);
434 67f194bd Kevin Wolf
    g_assert(!get_irq(FLOPPY_IRQ));
435 67f194bd Kevin Wolf
    floppy_send(cyl);
436 67f194bd Kevin Wolf
    g_assert(get_irq(FLOPPY_IRQ));
437 67f194bd Kevin Wolf
    ack_irq(NULL);
438 67f194bd Kevin Wolf
439 67f194bd Kevin Wolf
    floppy_send(CMD_READ_ID);
440 67f194bd Kevin Wolf
    g_assert(!get_irq(FLOPPY_IRQ));
441 67f194bd Kevin Wolf
    floppy_send(head << 2 | drive);
442 67f194bd Kevin Wolf
443 67f194bd Kevin Wolf
    while (!get_irq(FLOPPY_IRQ)) {
444 67f194bd Kevin Wolf
        /* qemu involves a timer with READ ID... */
445 67f194bd Kevin Wolf
        clock_step(1000000000LL / 50);
446 67f194bd Kevin Wolf
    }
447 67f194bd Kevin Wolf
448 67f194bd Kevin Wolf
    st0 = floppy_recv();
449 67f194bd Kevin Wolf
    floppy_recv();
450 67f194bd Kevin Wolf
    floppy_recv();
451 67f194bd Kevin Wolf
    cyl = floppy_recv();
452 67f194bd Kevin Wolf
    head = floppy_recv();
453 67f194bd Kevin Wolf
    floppy_recv();
454 67f194bd Kevin Wolf
    floppy_recv();
455 67f194bd Kevin Wolf
456 67f194bd Kevin Wolf
    g_assert_cmpint(cyl, ==, 8);
457 67f194bd Kevin Wolf
    g_assert_cmpint(head, ==, 1);
458 67f194bd Kevin Wolf
    g_assert_cmpint(st0, ==, head << 2);
459 67f194bd Kevin Wolf
}
460 67f194bd Kevin Wolf
461 5f8ae8e2 Hervé Poussineau
static void test_read_no_dma_1(void)
462 5f8ae8e2 Hervé Poussineau
{
463 5f8ae8e2 Hervé Poussineau
    uint8_t ret;
464 5f8ae8e2 Hervé Poussineau
465 5f8ae8e2 Hervé Poussineau
    outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08);
466 5f8ae8e2 Hervé Poussineau
    send_seek(0);
467 075f5532 Hervé Poussineau
    ret = send_read_no_dma_command(1, 0x04);
468 5f8ae8e2 Hervé Poussineau
    g_assert(ret == 0);
469 5f8ae8e2 Hervé Poussineau
}
470 5f8ae8e2 Hervé Poussineau
471 5f8ae8e2 Hervé Poussineau
static void test_read_no_dma_18(void)
472 5f8ae8e2 Hervé Poussineau
{
473 5f8ae8e2 Hervé Poussineau
    uint8_t ret;
474 5f8ae8e2 Hervé Poussineau
475 5f8ae8e2 Hervé Poussineau
    outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08);
476 5f8ae8e2 Hervé Poussineau
    send_seek(0);
477 075f5532 Hervé Poussineau
    ret = send_read_no_dma_command(18, 0x04);
478 5f8ae8e2 Hervé Poussineau
    g_assert(ret == 0);
479 5f8ae8e2 Hervé Poussineau
}
480 5f8ae8e2 Hervé Poussineau
481 5f8ae8e2 Hervé Poussineau
static void test_read_no_dma_19(void)
482 5f8ae8e2 Hervé Poussineau
{
483 5f8ae8e2 Hervé Poussineau
    uint8_t ret;
484 5f8ae8e2 Hervé Poussineau
485 5f8ae8e2 Hervé Poussineau
    outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08);
486 5f8ae8e2 Hervé Poussineau
    send_seek(0);
487 5f8ae8e2 Hervé Poussineau
    ret = send_read_no_dma_command(19, 0x20);
488 5f8ae8e2 Hervé Poussineau
    g_assert(ret == 0);
489 5f8ae8e2 Hervé Poussineau
}
490 5f8ae8e2 Hervé Poussineau
491 6f442fe8 Hervé Poussineau
static void test_verify(void)
492 6f442fe8 Hervé Poussineau
{
493 6f442fe8 Hervé Poussineau
    uint8_t ret;
494 6f442fe8 Hervé Poussineau
495 6f442fe8 Hervé Poussineau
    ret = send_read_command(CMD_VERIFY);
496 6f442fe8 Hervé Poussineau
    g_assert(ret == 0);
497 6f442fe8 Hervé Poussineau
}
498 6f442fe8 Hervé Poussineau
499 3359847e Blue Swirl
/* success if no crash or abort */
500 3359847e Blue Swirl
static void fuzz_registers(void)
501 3359847e Blue Swirl
{
502 3359847e Blue Swirl
    unsigned int i;
503 3359847e Blue Swirl
504 3359847e Blue Swirl
    for (i = 0; i < 1000; i++) {
505 3359847e Blue Swirl
        uint8_t reg, val;
506 3359847e Blue Swirl
507 3359847e Blue Swirl
        reg = (uint8_t)g_test_rand_int_range(0, 8);
508 3359847e Blue Swirl
        val = (uint8_t)g_test_rand_int_range(0, 256);
509 3359847e Blue Swirl
510 3359847e Blue Swirl
        outb(FLOPPY_BASE + reg, val);
511 3359847e Blue Swirl
        inb(FLOPPY_BASE + reg);
512 3359847e Blue Swirl
    }
513 3359847e Blue Swirl
}
514 3359847e Blue Swirl
515 93e9eb68 Kevin Wolf
int main(int argc, char **argv)
516 93e9eb68 Kevin Wolf
{
517 93e9eb68 Kevin Wolf
    const char *arch = qtest_get_arch();
518 93e9eb68 Kevin Wolf
    char *cmdline;
519 93e9eb68 Kevin Wolf
    int fd;
520 93e9eb68 Kevin Wolf
    int ret;
521 93e9eb68 Kevin Wolf
522 93e9eb68 Kevin Wolf
    /* Check architecture */
523 93e9eb68 Kevin Wolf
    if (strcmp(arch, "i386") && strcmp(arch, "x86_64")) {
524 93e9eb68 Kevin Wolf
        g_test_message("Skipping test for non-x86\n");
525 93e9eb68 Kevin Wolf
        return 0;
526 93e9eb68 Kevin Wolf
    }
527 93e9eb68 Kevin Wolf
528 93e9eb68 Kevin Wolf
    /* Create a temporary raw image */
529 93e9eb68 Kevin Wolf
    fd = mkstemp(test_image);
530 93e9eb68 Kevin Wolf
    g_assert(fd >= 0);
531 93e9eb68 Kevin Wolf
    ret = ftruncate(fd, TEST_IMAGE_SIZE);
532 93e9eb68 Kevin Wolf
    g_assert(ret == 0);
533 93e9eb68 Kevin Wolf
    close(fd);
534 93e9eb68 Kevin Wolf
535 93e9eb68 Kevin Wolf
    /* Run the tests */
536 93e9eb68 Kevin Wolf
    g_test_init(&argc, &argv, NULL);
537 93e9eb68 Kevin Wolf
538 7cd33161 Pavel Hrdina
    cmdline = g_strdup_printf("-vnc none ");
539 93e9eb68 Kevin Wolf
540 93e9eb68 Kevin Wolf
    qtest_start(cmdline);
541 93e9eb68 Kevin Wolf
    qtest_irq_intercept_in(global_qtest, "ioapic");
542 7cd33161 Pavel Hrdina
    qtest_add_func("/fdc/cmos", test_cmos);
543 7cd33161 Pavel Hrdina
    qtest_add_func("/fdc/no_media_on_start", test_no_media_on_start);
544 8b9ef60d Pavel Hrdina
    qtest_add_func("/fdc/read_without_media", test_read_without_media);
545 93e9eb68 Kevin Wolf
    qtest_add_func("/fdc/media_change", test_media_change);
546 b3ce604e Pavel Hrdina
    qtest_add_func("/fdc/sense_interrupt", test_sense_interrupt);
547 98272dbb Pavel Hrdina
    qtest_add_func("/fdc/relative_seek", test_relative_seek);
548 67f194bd Kevin Wolf
    qtest_add_func("/fdc/read_id", test_read_id);
549 6f442fe8 Hervé Poussineau
    qtest_add_func("/fdc/verify", test_verify);
550 44212dcc Hervé Poussineau
    qtest_add_func("/fdc/media_insert", test_media_insert);
551 5f8ae8e2 Hervé Poussineau
    qtest_add_func("/fdc/read_no_dma_1", test_read_no_dma_1);
552 5f8ae8e2 Hervé Poussineau
    qtest_add_func("/fdc/read_no_dma_18", test_read_no_dma_18);
553 5f8ae8e2 Hervé Poussineau
    qtest_add_func("/fdc/read_no_dma_19", test_read_no_dma_19);
554 3359847e Blue Swirl
    qtest_add_func("/fdc/fuzz-registers", fuzz_registers);
555 93e9eb68 Kevin Wolf
556 93e9eb68 Kevin Wolf
    ret = g_test_run();
557 93e9eb68 Kevin Wolf
558 93e9eb68 Kevin Wolf
    /* Cleanup */
559 93e9eb68 Kevin Wolf
    qtest_quit(global_qtest);
560 93e9eb68 Kevin Wolf
    unlink(test_image);
561 93e9eb68 Kevin Wolf
562 93e9eb68 Kevin Wolf
    return ret;
563 93e9eb68 Kevin Wolf
}