Statistics
| Branch: | Revision:

root / hw / esp.c @ 192c7bd9

History | View | Annotate | Download (10 kB)

1
/*
2
 * QEMU ESP emulation
3
 * 
4
 * Copyright (c) 2005 Fabrice Bellard
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
#include "vl.h"
25

    
26
/* debug ESP card */
27
//#define DEBUG_ESP
28

    
29
#ifdef DEBUG_ESP
30
#define DPRINTF(fmt, args...) \
31
do { printf("ESP: " fmt , ##args); } while (0)
32
#else
33
#define DPRINTF(fmt, args...)
34
#endif
35

    
36
#define ESPDMA_REGS 4
37
#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
38
#define ESP_MAXREG 0x3f
39

    
40
typedef struct ESPState {
41
    BlockDriverState **bd;
42
    uint8_t rregs[ESP_MAXREG];
43
    uint8_t wregs[ESP_MAXREG];
44
    int irq;
45
    uint32_t espdmaregs[ESPDMA_REGS];
46
    uint32_t ti_size;
47
    int ti_dir;
48
    uint8_t ti_buf[65536];
49
} ESPState;
50

    
51
#define STAT_DO 0x00
52
#define STAT_DI 0x01
53
#define STAT_CD 0x02
54
#define STAT_ST 0x03
55
#define STAT_MI 0x06
56
#define STAT_MO 0x07
57

    
58
#define STAT_TC 0x10
59
#define STAT_IN 0x80
60

    
61
#define INTR_FC 0x08
62
#define INTR_BS 0x10
63
#define INTR_DC 0x20
64

    
65
#define SEQ_0 0x0
66
#define SEQ_CD 0x4
67

    
68
static void handle_satn(ESPState *s)
69
{
70
    uint8_t buf[32];
71
    uint32_t dmaptr, dmalen;
72
    unsigned int i;
73
    int64_t nb_sectors;
74
    int target;
75

    
76
    dmaptr = iommu_translate(s->espdmaregs[1]);
77
    dmalen = s->wregs[0] | (s->wregs[1] << 8);
78
    DPRINTF("Select with ATN at %8.8x len %d\n", dmaptr, dmalen);
79
    DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
80
    cpu_physical_memory_read(dmaptr, buf, dmalen);
81
    for (i = 0; i < dmalen; i++) {
82
        DPRINTF("Command %2.2x\n", buf[i]);
83
    }
84
    s->ti_dir = 0;
85
    s->ti_size = 0;
86
    target = s->wregs[4] & 7;
87

    
88
    if (target > 4 || !s->bd[target]) { // No such drive
89
        s->rregs[4] = STAT_IN;
90
        s->rregs[5] = INTR_DC;
91
        s->rregs[6] = SEQ_0;
92
        s->espdmaregs[0] |= 1;
93
        pic_set_irq(s->irq, 1);
94
        return;
95
    }
96
    switch (buf[1]) {
97
    case 0x0:
98
        DPRINTF("Test Unit Ready (len %d)\n", buf[5]);
99
        break;
100
    case 0x12:
101
        DPRINTF("Inquiry (len %d)\n", buf[5]);
102
        memset(s->ti_buf, 0, 36);
103
        if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
104
            s->ti_buf[0] = 5;
105
            memcpy(&s->ti_buf[16], "QEMU CDROM     ", 16);
106
        } else {
107
            s->ti_buf[0] = 0;
108
            memcpy(&s->ti_buf[16], "QEMU HARDDISK  ", 16);
109
        }
110
        memcpy(&s->ti_buf[8], "QEMU   ", 8);
111
        s->ti_buf[2] = 1;
112
        s->ti_buf[3] = 2;
113
        s->ti_dir = 1;
114
        s->ti_size = 36;
115
        break;
116
    case 0x1a:
117
        DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[3], buf[5]);
118
        break;
119
    case 0x25:
120
        DPRINTF("Read Capacity (len %d)\n", buf[5]);
121
        memset(s->ti_buf, 0, 8);
122
        bdrv_get_geometry(s->bd[target], &nb_sectors);
123
        s->ti_buf[0] = (nb_sectors >> 24) & 0xff;
124
        s->ti_buf[1] = (nb_sectors >> 16) & 0xff;
125
        s->ti_buf[2] = (nb_sectors >> 8) & 0xff;
126
        s->ti_buf[3] = nb_sectors & 0xff;
127
        s->ti_buf[4] = 0;
128
        s->ti_buf[5] = 0;
129
        s->ti_buf[6] = 2;
130
        s->ti_buf[7] = 0;
131
        s->ti_dir = 1;
132
        s->ti_size = 8;
133
        break;
134
    case 0x28:
135
        {
136
            int64_t offset, len;
137

    
138
            offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
139
            len = (buf[8] << 8) | buf[9];
140
            DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len);
141
            bdrv_read(s->bd[target], offset, s->ti_buf, len);
142
            s->ti_dir = 1;
143
            s->ti_size = len * 512;
144
            break;
145
        }
146
    case 0x2a:
147
        {
148
            int64_t offset, len;
149

    
150
            offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
151
            len = (buf[8] << 8) | buf[9];
152
            DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len);
153
            bdrv_write(s->bd[target], offset, s->ti_buf, len);
154
            s->ti_dir = 0;
155
            s->ti_size = len * 512;
156
            break;
157
        }
158
    default:
159
        DPRINTF("Unknown command (%2.2x)\n", buf[1]);
160
        break;
161
    }
162
    s->rregs[4] = STAT_IN | STAT_TC | STAT_DI;
163
    s->rregs[5] = INTR_BS | INTR_FC;
164
    s->rregs[6] = SEQ_CD;
165
    s->espdmaregs[0] |= 1;
166
    pic_set_irq(s->irq, 1);
167
}
168

    
169
static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len)
170
{
171
    uint32_t dmaptr, dmalen;
172

    
173
    dmaptr = iommu_translate(s->espdmaregs[1]);
174
    dmalen = s->wregs[0] | (s->wregs[1] << 8);
175
    DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
176
    cpu_physical_memory_write(dmaptr, buf, len);
177
    s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
178
    s->rregs[5] = INTR_BS | INTR_FC;
179
    s->rregs[6] = SEQ_CD;
180
    s->espdmaregs[0] |= 1;
181
    pic_set_irq(s->irq, 1);
182

    
183
}
184
static const uint8_t okbuf[] = {0, 0};
185

    
186
static void handle_ti(ESPState *s)
187
{
188
    uint32_t dmaptr, dmalen;
189
    unsigned int i;
190

    
191
    dmaptr = iommu_translate(s->espdmaregs[1]);
192
    dmalen = s->wregs[0] | (s->wregs[1] << 8);
193
    DPRINTF("Transfer Information at %8.8x len %d\n", dmaptr, dmalen);
194
    DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
195
    for (i = 0; i < s->ti_size; i++) {
196
        dmaptr = iommu_translate(s->espdmaregs[1] + i);
197
        if (s->ti_dir)
198
            cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1);
199
        else
200
            cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1);
201
    }
202
    s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
203
    s->rregs[5] = INTR_BS;
204
    s->rregs[6] = 0;
205
    s->espdmaregs[0] |= 1;
206
    pic_set_irq(s->irq, 1);
207
}
208

    
209
static void esp_reset(void *opaque)
210
{
211
    ESPState *s = opaque;
212
    memset(s->rregs, 0, ESP_MAXREG);
213
    s->rregs[0x0e] = 0x4; // Indicate fas100a
214
    memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
215
}
216

    
217
static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
218
{
219
    ESPState *s = opaque;
220
    uint32_t saddr;
221

    
222
    saddr = (addr & ESP_MAXREG) >> 2;
223
    switch (saddr) {
224
    default:
225
        break;
226
    }
227
    DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
228
    return s->rregs[saddr];
229
}
230

    
231
static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
232
{
233
    ESPState *s = opaque;
234
    uint32_t saddr;
235

    
236
    saddr = (addr & ESP_MAXREG) >> 2;
237
    DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
238
    switch (saddr) {
239
    case 3:
240
        // Command
241
        switch(val & 0x7f) {
242
        case 0:
243
            DPRINTF("NOP (%2.2x)\n", val);
244
            break;
245
        case 1:
246
            DPRINTF("Flush FIFO (%2.2x)\n", val);
247
            s->rregs[6] = 0;
248
            s->rregs[5] = INTR_FC;
249
            break;
250
        case 2:
251
            DPRINTF("Chip reset (%2.2x)\n", val);
252
            esp_reset(s);
253
            break;
254
        case 3:
255
            DPRINTF("Bus reset (%2.2x)\n", val);
256
            break;
257
        case 0x10:
258
            handle_ti(s);
259
            break;
260
        case 0x11:
261
            DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
262
            dma_write(s, okbuf, 2);
263
            break;
264
        case 0x12:
265
            DPRINTF("Message Accepted (%2.2x)\n", val);
266
            dma_write(s, okbuf, 2);
267
            s->rregs[5] = INTR_DC;
268
            s->rregs[6] = 0;
269
            break;
270
        case 0x1a:
271
            DPRINTF("Set ATN (%2.2x)\n", val);
272
            break;
273
        case 0x42:
274
            handle_satn(s);
275
            break;
276
        case 0x43:
277
            DPRINTF("Set ATN & stop (%2.2x)\n", val);
278
            handle_satn(s);
279
            break;
280
        default:
281
            DPRINTF("Unhandled command (%2.2x)\n", val);
282
            break;
283
        }
284
        break;
285
    case 4 ... 7:
286
    case 9 ... 0xf:
287
        break;
288
    default:
289
        break;
290
    }
291
    s->wregs[saddr] = val;
292
}
293

    
294
static CPUReadMemoryFunc *esp_mem_read[3] = {
295
    esp_mem_readb,
296
    esp_mem_readb,
297
    esp_mem_readb,
298
};
299

    
300
static CPUWriteMemoryFunc *esp_mem_write[3] = {
301
    esp_mem_writeb,
302
    esp_mem_writeb,
303
    esp_mem_writeb,
304
};
305

    
306
static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
307
{
308
    ESPState *s = opaque;
309
    uint32_t saddr;
310

    
311
    saddr = (addr & ESPDMA_MAXADDR) >> 2;
312
    DPRINTF("read dmareg[%d]: 0x%2.2x\n", saddr, s->espdmaregs[saddr]);
313
    return s->espdmaregs[saddr];
314
}
315

    
316
static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
317
{
318
    ESPState *s = opaque;
319
    uint32_t saddr;
320

    
321
    saddr = (addr & ESPDMA_MAXADDR) >> 2;
322
    DPRINTF("write dmareg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->espdmaregs[saddr], val);
323
    switch (saddr) {
324
    case 0:
325
        if (!(val & 0x10))
326
            pic_set_irq(s->irq, 0);
327
        break;
328
    default:
329
        break;
330
    }
331
    s->espdmaregs[saddr] = val;
332
}
333

    
334
static CPUReadMemoryFunc *espdma_mem_read[3] = {
335
    espdma_mem_readl,
336
    espdma_mem_readl,
337
    espdma_mem_readl,
338
};
339

    
340
static CPUWriteMemoryFunc *espdma_mem_write[3] = {
341
    espdma_mem_writel,
342
    espdma_mem_writel,
343
    espdma_mem_writel,
344
};
345

    
346
static void esp_save(QEMUFile *f, void *opaque)
347
{
348
    ESPState *s = opaque;
349
    unsigned int i;
350

    
351
    qemu_put_buffer(f, s->rregs, ESP_MAXREG);
352
    qemu_put_buffer(f, s->wregs, ESP_MAXREG);
353
    qemu_put_be32s(f, &s->irq);
354
    for (i = 0; i < ESPDMA_REGS; i++)
355
        qemu_put_be32s(f, &s->espdmaregs[i]);
356
}
357

    
358
static int esp_load(QEMUFile *f, void *opaque, int version_id)
359
{
360
    ESPState *s = opaque;
361
    unsigned int i;
362
    
363
    if (version_id != 1)
364
        return -EINVAL;
365

    
366
    qemu_get_buffer(f, s->rregs, ESP_MAXREG);
367
    qemu_get_buffer(f, s->wregs, ESP_MAXREG);
368
    qemu_get_be32s(f, &s->irq);
369
    for (i = 0; i < ESPDMA_REGS; i++)
370
        qemu_get_be32s(f, &s->espdmaregs[i]);
371

    
372
    return 0;
373
}
374

    
375
void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr)
376
{
377
    ESPState *s;
378
    int esp_io_memory, espdma_io_memory;
379

    
380
    s = qemu_mallocz(sizeof(ESPState));
381
    if (!s)
382
        return;
383

    
384
    s->bd = bd;
385
    s->irq = irq;
386

    
387
    esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
388
    cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
389

    
390
    espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s);
391
    cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);
392

    
393
    esp_reset(s);
394

    
395
    register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
396
    qemu_register_reset(esp_reset, s);
397
}
398