]> Git Repo - qemu.git/blame - hw/esp.c
Avoid buffer overflow when sending slirp packets.
[qemu.git] / hw / esp.c
CommitLineData
6f7e9aec
FB
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 */
2f275b8f 27//#define DEBUG_ESP
6f7e9aec
FB
28
29#ifdef DEBUG_ESP
30#define DPRINTF(fmt, args...) \
31do { printf("ESP: " fmt , ##args); } while (0)
9e61bde5
FB
32#define pic_set_irq(irq, level) \
33do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0)
6f7e9aec
FB
34#else
35#define DPRINTF(fmt, args...)
36#endif
37
38#define ESPDMA_REGS 4
39#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
40#define ESP_MAXREG 0x3f
4f6200f0
FB
41#define TI_BUFSZ 65536
42#define DMA_VER 0xa0000000
9e61bde5
FB
43#define DMA_INTR 1
44#define DMA_INTREN 0x10
4f6200f0 45#define DMA_LOADED 0x04000000
6f7e9aec
FB
46
47typedef struct ESPState {
48 BlockDriverState **bd;
2f275b8f
FB
49 uint8_t rregs[ESP_MAXREG];
50 uint8_t wregs[ESP_MAXREG];
6f7e9aec
FB
51 int irq;
52 uint32_t espdmaregs[ESPDMA_REGS];
2f275b8f 53 uint32_t ti_size;
4f6200f0 54 uint32_t ti_rptr, ti_wptr;
2f275b8f 55 int ti_dir;
4f6200f0
FB
56 uint8_t ti_buf[TI_BUFSZ];
57 int dma;
6f7e9aec
FB
58} ESPState;
59
2f275b8f
FB
60#define STAT_DO 0x00
61#define STAT_DI 0x01
62#define STAT_CD 0x02
63#define STAT_ST 0x03
64#define STAT_MI 0x06
65#define STAT_MO 0x07
66
67#define STAT_TC 0x10
68#define STAT_IN 0x80
69
70#define INTR_FC 0x08
71#define INTR_BS 0x10
72#define INTR_DC 0x20
9e61bde5 73#define INTR_RST 0x80
2f275b8f
FB
74
75#define SEQ_0 0x0
76#define SEQ_CD 0x4
77
b9788fc4
FB
78/* XXX: stolen from ide.c, move to common ATAPI/SCSI library */
79static void lba_to_msf(uint8_t *buf, int lba)
80{
81 lba += 150;
82 buf[0] = (lba / 75) / 60;
83 buf[1] = (lba / 75) % 60;
84 buf[2] = lba % 75;
85}
86
87static inline void cpu_to_ube16(uint8_t *buf, int val)
88{
89 buf[0] = val >> 8;
90 buf[1] = val;
91}
92
93static inline void cpu_to_ube32(uint8_t *buf, unsigned int val)
94{
95 buf[0] = val >> 24;
96 buf[1] = val >> 16;
97 buf[2] = val >> 8;
98 buf[3] = val;
99}
100
101/* same toc as bochs. Return -1 if error or the toc length */
102/* XXX: check this */
103static int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track)
104{
105 uint8_t *q;
106 int len;
107
108 if (start_track > 1 && start_track != 0xaa)
109 return -1;
110 q = buf + 2;
111 *q++ = 1; /* first session */
112 *q++ = 1; /* last session */
113 if (start_track <= 1) {
114 *q++ = 0; /* reserved */
115 *q++ = 0x14; /* ADR, control */
116 *q++ = 1; /* track number */
117 *q++ = 0; /* reserved */
118 if (msf) {
119 *q++ = 0; /* reserved */
120 lba_to_msf(q, 0);
121 q += 3;
122 } else {
123 /* sector 0 */
124 cpu_to_ube32(q, 0);
125 q += 4;
126 }
127 }
128 /* lead out track */
129 *q++ = 0; /* reserved */
130 *q++ = 0x16; /* ADR, control */
131 *q++ = 0xaa; /* track number */
132 *q++ = 0; /* reserved */
133 if (msf) {
134 *q++ = 0; /* reserved */
135 lba_to_msf(q, nb_sectors);
136 q += 3;
137 } else {
138 cpu_to_ube32(q, nb_sectors);
139 q += 4;
140 }
141 len = q - buf;
142 cpu_to_ube16(buf, len - 2);
143 return len;
144}
145
146/* mostly same info as PearPc */
147static int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf,
148 int session_num)
149{
150 uint8_t *q;
151 int len;
152
153 q = buf + 2;
154 *q++ = 1; /* first session */
155 *q++ = 1; /* last session */
156
157 *q++ = 1; /* session number */
158 *q++ = 0x14; /* data track */
159 *q++ = 0; /* track number */
160 *q++ = 0xa0; /* lead-in */
161 *q++ = 0; /* min */
162 *q++ = 0; /* sec */
163 *q++ = 0; /* frame */
164 *q++ = 0;
165 *q++ = 1; /* first track */
166 *q++ = 0x00; /* disk type */
167 *q++ = 0x00;
168
169 *q++ = 1; /* session number */
170 *q++ = 0x14; /* data track */
171 *q++ = 0; /* track number */
172 *q++ = 0xa1;
173 *q++ = 0; /* min */
174 *q++ = 0; /* sec */
175 *q++ = 0; /* frame */
176 *q++ = 0;
177 *q++ = 1; /* last track */
178 *q++ = 0x00;
179 *q++ = 0x00;
180
181 *q++ = 1; /* session number */
182 *q++ = 0x14; /* data track */
183 *q++ = 0; /* track number */
184 *q++ = 0xa2; /* lead-out */
185 *q++ = 0; /* min */
186 *q++ = 0; /* sec */
187 *q++ = 0; /* frame */
188 if (msf) {
189 *q++ = 0; /* reserved */
190 lba_to_msf(q, nb_sectors);
191 q += 3;
192 } else {
193 cpu_to_ube32(q, nb_sectors);
194 q += 4;
195 }
196
197 *q++ = 1; /* session number */
198 *q++ = 0x14; /* ADR, control */
199 *q++ = 0; /* track number */
200 *q++ = 1; /* point */
201 *q++ = 0; /* min */
202 *q++ = 0; /* sec */
203 *q++ = 0; /* frame */
204 if (msf) {
205 *q++ = 0;
206 lba_to_msf(q, 0);
207 q += 3;
208 } else {
209 *q++ = 0;
210 *q++ = 0;
211 *q++ = 0;
212 *q++ = 0;
213 }
214
215 len = q - buf;
216 cpu_to_ube16(buf, len - 2);
217 return len;
218}
219
2f275b8f
FB
220static void handle_satn(ESPState *s)
221{
222 uint8_t buf[32];
223 uint32_t dmaptr, dmalen;
224 unsigned int i;
225 int64_t nb_sectors;
226 int target;
227
2f275b8f 228 dmalen = s->wregs[0] | (s->wregs[1] << 8);
4f6200f0
FB
229 target = s->wregs[4] & 7;
230 DPRINTF("Select with ATN len %d target %d\n", dmalen, target);
231 if (s->dma) {
232 dmaptr = iommu_translate(s->espdmaregs[1]);
233 DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr);
234 cpu_physical_memory_read(dmaptr, buf, dmalen);
235 } else {
236 buf[0] = 0;
237 memcpy(&buf[1], s->ti_buf, dmalen);
238 dmalen++;
239 }
2f275b8f
FB
240 for (i = 0; i < dmalen; i++) {
241 DPRINTF("Command %2.2x\n", buf[i]);
242 }
243 s->ti_dir = 0;
244 s->ti_size = 0;
4f6200f0
FB
245 s->ti_rptr = 0;
246 s->ti_wptr = 0;
2f275b8f 247
9e61bde5 248 if (target >= 4 || !s->bd[target]) { // No such drive
2f275b8f
FB
249 s->rregs[4] = STAT_IN;
250 s->rregs[5] = INTR_DC;
251 s->rregs[6] = SEQ_0;
9e61bde5 252 s->espdmaregs[0] |= DMA_INTR;
2f275b8f
FB
253 pic_set_irq(s->irq, 1);
254 return;
255 }
256 switch (buf[1]) {
257 case 0x0:
258 DPRINTF("Test Unit Ready (len %d)\n", buf[5]);
259 break;
260 case 0x12:
261 DPRINTF("Inquiry (len %d)\n", buf[5]);
262 memset(s->ti_buf, 0, 36);
263 if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
264 s->ti_buf[0] = 5;
265 memcpy(&s->ti_buf[16], "QEMU CDROM ", 16);
266 } else {
267 s->ti_buf[0] = 0;
268 memcpy(&s->ti_buf[16], "QEMU HARDDISK ", 16);
269 }
270 memcpy(&s->ti_buf[8], "QEMU ", 8);
271 s->ti_buf[2] = 1;
272 s->ti_buf[3] = 2;
b9788fc4 273 s->ti_buf[4] = 32;
2f275b8f
FB
274 s->ti_dir = 1;
275 s->ti_size = 36;
276 break;
277 case 0x1a:
278 DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[3], buf[5]);
279 break;
280 case 0x25:
281 DPRINTF("Read Capacity (len %d)\n", buf[5]);
282 memset(s->ti_buf, 0, 8);
283 bdrv_get_geometry(s->bd[target], &nb_sectors);
284 s->ti_buf[0] = (nb_sectors >> 24) & 0xff;
285 s->ti_buf[1] = (nb_sectors >> 16) & 0xff;
286 s->ti_buf[2] = (nb_sectors >> 8) & 0xff;
287 s->ti_buf[3] = nb_sectors & 0xff;
288 s->ti_buf[4] = 0;
289 s->ti_buf[5] = 0;
4f6200f0
FB
290 if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM)
291 s->ti_buf[6] = 8; // sector size 2048
292 else
293 s->ti_buf[6] = 2; // sector size 512
2f275b8f
FB
294 s->ti_buf[7] = 0;
295 s->ti_dir = 1;
296 s->ti_size = 8;
297 break;
298 case 0x28:
299 {
300 int64_t offset, len;
301
4f6200f0
FB
302 if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
303 offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4;
304 len = ((buf[8] << 8) | buf[9]) * 4;
305 s->ti_size = len * 2048;
306 } else {
307 offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
308 len = (buf[8] << 8) | buf[9];
309 s->ti_size = len * 512;
310 }
2f275b8f
FB
311 DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len);
312 bdrv_read(s->bd[target], offset, s->ti_buf, len);
4f6200f0 313 // XXX error handling
2f275b8f 314 s->ti_dir = 1;
2f275b8f
FB
315 break;
316 }
317 case 0x2a:
318 {
319 int64_t offset, len;
320
4f6200f0
FB
321 if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
322 offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4;
323 len = ((buf[8] << 8) | buf[9]) * 4;
324 s->ti_size = len * 2048;
325 } else {
326 offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
327 len = (buf[8] << 8) | buf[9];
328 s->ti_size = len * 512;
329 }
2f275b8f
FB
330 DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len);
331 bdrv_write(s->bd[target], offset, s->ti_buf, len);
4f6200f0 332 // XXX error handling
2f275b8f 333 s->ti_dir = 0;
2f275b8f
FB
334 break;
335 }
b9788fc4
FB
336 case 0x43:
337 {
338 int start_track, format, msf, len;
339
340 msf = buf[2] & 2;
341 format = buf[3] & 0xf;
342 start_track = buf[7];
343 bdrv_get_geometry(s->bd[target], &nb_sectors);
344 DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
345 switch(format) {
346 case 0:
347 len = cdrom_read_toc(nb_sectors, buf, msf, start_track);
348 if (len < 0)
349 goto error_cmd;
350 s->ti_size = len;
351 break;
352 case 1:
353 /* multi session : only a single session defined */
354 memset(buf, 0, 12);
355 buf[1] = 0x0a;
356 buf[2] = 0x01;
357 buf[3] = 0x01;
358 s->ti_size = 12;
359 break;
360 case 2:
361 len = cdrom_read_toc_raw(nb_sectors, buf, msf, start_track);
362 if (len < 0)
363 goto error_cmd;
364 s->ti_size = len;
365 break;
366 default:
367 error_cmd:
368 DPRINTF("Read TOC error\n");
369 // XXX error handling
370 break;
371 }
372 s->ti_dir = 1;
373 break;
374 }
2f275b8f 375 default:
4f6200f0 376 DPRINTF("Unknown SCSI command (%2.2x)\n", buf[1]);
2f275b8f
FB
377 break;
378 }
379 s->rregs[4] = STAT_IN | STAT_TC | STAT_DI;
380 s->rregs[5] = INTR_BS | INTR_FC;
381 s->rregs[6] = SEQ_CD;
9e61bde5 382 s->espdmaregs[0] |= DMA_INTR;
2f275b8f
FB
383 pic_set_irq(s->irq, 1);
384}
385
386static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len)
387{
388 uint32_t dmaptr, dmalen;
389
2f275b8f 390 dmalen = s->wregs[0] | (s->wregs[1] << 8);
4f6200f0
FB
391 DPRINTF("Transfer status len %d\n", dmalen);
392 if (s->dma) {
393 dmaptr = iommu_translate(s->espdmaregs[1]);
394 DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
395 cpu_physical_memory_write(dmaptr, buf, len);
396 s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
397 s->rregs[5] = INTR_BS | INTR_FC;
398 s->rregs[6] = SEQ_CD;
4f6200f0
FB
399 } else {
400 memcpy(s->ti_buf, buf, len);
401 s->ti_size = dmalen;
402 s->ti_rptr = 0;
403 s->ti_wptr = 0;
9e61bde5 404 s->rregs[7] = dmalen;
4f6200f0 405 }
9e61bde5 406 s->espdmaregs[0] |= DMA_INTR;
2f275b8f
FB
407 pic_set_irq(s->irq, 1);
408
409}
4f6200f0 410
2f275b8f
FB
411static const uint8_t okbuf[] = {0, 0};
412
413static void handle_ti(ESPState *s)
414{
415 uint32_t dmaptr, dmalen;
416 unsigned int i;
417
2f275b8f 418 dmalen = s->wregs[0] | (s->wregs[1] << 8);
4f6200f0
FB
419 DPRINTF("Transfer Information len %d\n", dmalen);
420 if (s->dma) {
421 dmaptr = iommu_translate(s->espdmaregs[1]);
422 DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr);
423 for (i = 0; i < s->ti_size; i++) {
424 dmaptr = iommu_translate(s->espdmaregs[1] + i);
425 if (s->ti_dir)
426 cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1);
427 else
428 cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1);
429 }
430 s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
431 s->rregs[5] = INTR_BS;
432 s->rregs[6] = 0;
9e61bde5 433 s->espdmaregs[0] |= DMA_INTR;
4f6200f0
FB
434 } else {
435 s->ti_size = dmalen;
436 s->ti_rptr = 0;
437 s->ti_wptr = 0;
9e61bde5 438 s->rregs[7] = dmalen;
4f6200f0 439 }
2f275b8f
FB
440 pic_set_irq(s->irq, 1);
441}
442
6f7e9aec
FB
443static void esp_reset(void *opaque)
444{
445 ESPState *s = opaque;
2f275b8f
FB
446 memset(s->rregs, 0, ESP_MAXREG);
447 s->rregs[0x0e] = 0x4; // Indicate fas100a
6f7e9aec
FB
448 memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
449}
450
451static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
452{
453 ESPState *s = opaque;
454 uint32_t saddr;
455
456 saddr = (addr & ESP_MAXREG) >> 2;
9e61bde5 457 DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
6f7e9aec 458 switch (saddr) {
4f6200f0
FB
459 case 2:
460 // FIFO
461 if (s->ti_size > 0) {
462 s->ti_size--;
463 s->rregs[saddr] = s->ti_buf[s->ti_rptr++];
464 pic_set_irq(s->irq, 1);
465 }
466 if (s->ti_size == 0) {
467 s->ti_rptr = 0;
468 s->ti_wptr = 0;
469 }
470 break;
9e61bde5
FB
471 case 5:
472 // interrupt
473 // Clear status bits except TC
474 s->rregs[4] &= STAT_TC;
475 pic_set_irq(s->irq, 0);
476 s->espdmaregs[0] &= ~DMA_INTR;
477 break;
6f7e9aec
FB
478 default:
479 break;
480 }
2f275b8f 481 return s->rregs[saddr];
6f7e9aec
FB
482}
483
484static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
485{
486 ESPState *s = opaque;
487 uint32_t saddr;
488
489 saddr = (addr & ESP_MAXREG) >> 2;
2f275b8f 490 DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
6f7e9aec 491 switch (saddr) {
4f6200f0
FB
492 case 0:
493 case 1:
494 s->rregs[saddr] = val;
495 break;
496 case 2:
497 // FIFO
498 s->ti_size++;
499 s->ti_buf[s->ti_wptr++] = val & 0xff;
500 break;
6f7e9aec 501 case 3:
4f6200f0 502 s->rregs[saddr] = val;
6f7e9aec 503 // Command
4f6200f0
FB
504 if (val & 0x80) {
505 s->dma = 1;
506 } else {
507 s->dma = 0;
508 }
6f7e9aec
FB
509 switch(val & 0x7f) {
510 case 0:
2f275b8f
FB
511 DPRINTF("NOP (%2.2x)\n", val);
512 break;
513 case 1:
514 DPRINTF("Flush FIFO (%2.2x)\n", val);
9e61bde5 515 //s->ti_size = 0;
2f275b8f 516 s->rregs[5] = INTR_FC;
9e61bde5 517 s->rregs[6] = 0;
6f7e9aec
FB
518 break;
519 case 2:
2f275b8f 520 DPRINTF("Chip reset (%2.2x)\n", val);
6f7e9aec
FB
521 esp_reset(s);
522 break;
523 case 3:
2f275b8f 524 DPRINTF("Bus reset (%2.2x)\n", val);
9e61bde5
FB
525 s->rregs[5] = INTR_RST;
526 if (!(s->wregs[8] & 0x40)) {
527 s->espdmaregs[0] |= DMA_INTR;
528 pic_set_irq(s->irq, 1);
529 }
2f275b8f
FB
530 break;
531 case 0x10:
532 handle_ti(s);
533 break;
534 case 0x11:
535 DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
536 dma_write(s, okbuf, 2);
537 break;
538 case 0x12:
539 DPRINTF("Message Accepted (%2.2x)\n", val);
540 dma_write(s, okbuf, 2);
541 s->rregs[5] = INTR_DC;
542 s->rregs[6] = 0;
6f7e9aec
FB
543 break;
544 case 0x1a:
2f275b8f 545 DPRINTF("Set ATN (%2.2x)\n", val);
6f7e9aec
FB
546 break;
547 case 0x42:
2f275b8f
FB
548 handle_satn(s);
549 break;
550 case 0x43:
551 DPRINTF("Set ATN & stop (%2.2x)\n", val);
552 handle_satn(s);
553 break;
554 default:
4f6200f0 555 DPRINTF("Unhandled ESP command (%2.2x)\n", val);
6f7e9aec
FB
556 break;
557 }
558 break;
559 case 4 ... 7:
6f7e9aec 560 break;
4f6200f0
FB
561 case 8:
562 s->rregs[saddr] = val;
563 break;
564 case 9 ... 10:
565 break;
9e61bde5
FB
566 case 11:
567 s->rregs[saddr] = val & 0x15;
568 break;
569 case 12 ... 15:
4f6200f0
FB
570 s->rregs[saddr] = val;
571 break;
6f7e9aec 572 default:
6f7e9aec
FB
573 break;
574 }
2f275b8f 575 s->wregs[saddr] = val;
6f7e9aec
FB
576}
577
578static CPUReadMemoryFunc *esp_mem_read[3] = {
579 esp_mem_readb,
580 esp_mem_readb,
581 esp_mem_readb,
582};
583
584static CPUWriteMemoryFunc *esp_mem_write[3] = {
585 esp_mem_writeb,
586 esp_mem_writeb,
587 esp_mem_writeb,
588};
589
590static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
591{
592 ESPState *s = opaque;
593 uint32_t saddr;
594
595 saddr = (addr & ESPDMA_MAXADDR) >> 2;
4f6200f0
FB
596 DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]);
597
6f7e9aec
FB
598 return s->espdmaregs[saddr];
599}
600
601static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
602{
603 ESPState *s = opaque;
604 uint32_t saddr;
605
606 saddr = (addr & ESPDMA_MAXADDR) >> 2;
4f6200f0 607 DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val);
2f275b8f
FB
608 switch (saddr) {
609 case 0:
9e61bde5 610 if (!(val & DMA_INTREN))
2f275b8f 611 pic_set_irq(s->irq, 0);
4f6200f0
FB
612 if (val & 0x80) {
613 esp_reset(s);
614 } else if (val & 0x40) {
615 val &= ~0x40;
616 } else if (val == 0)
617 val = 0x40;
618 val &= 0x0fffffff;
619 val |= DMA_VER;
2f275b8f 620 break;
4f6200f0
FB
621 case 1:
622 s->espdmaregs[0] = DMA_LOADED;
623 break;
2f275b8f
FB
624 default:
625 break;
626 }
6f7e9aec
FB
627 s->espdmaregs[saddr] = val;
628}
629
630static CPUReadMemoryFunc *espdma_mem_read[3] = {
631 espdma_mem_readl,
632 espdma_mem_readl,
633 espdma_mem_readl,
634};
635
636static CPUWriteMemoryFunc *espdma_mem_write[3] = {
637 espdma_mem_writel,
638 espdma_mem_writel,
639 espdma_mem_writel,
640};
641
642static void esp_save(QEMUFile *f, void *opaque)
643{
644 ESPState *s = opaque;
2f275b8f
FB
645 unsigned int i;
646
647 qemu_put_buffer(f, s->rregs, ESP_MAXREG);
648 qemu_put_buffer(f, s->wregs, ESP_MAXREG);
649 qemu_put_be32s(f, &s->irq);
650 for (i = 0; i < ESPDMA_REGS; i++)
651 qemu_put_be32s(f, &s->espdmaregs[i]);
4f6200f0
FB
652 qemu_put_be32s(f, &s->ti_size);
653 qemu_put_be32s(f, &s->ti_rptr);
654 qemu_put_be32s(f, &s->ti_wptr);
655 qemu_put_be32s(f, &s->ti_dir);
656 qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
657 qemu_put_be32s(f, &s->dma);
6f7e9aec
FB
658}
659
660static int esp_load(QEMUFile *f, void *opaque, int version_id)
661{
662 ESPState *s = opaque;
2f275b8f 663 unsigned int i;
6f7e9aec
FB
664
665 if (version_id != 1)
666 return -EINVAL;
667
2f275b8f
FB
668 qemu_get_buffer(f, s->rregs, ESP_MAXREG);
669 qemu_get_buffer(f, s->wregs, ESP_MAXREG);
670 qemu_get_be32s(f, &s->irq);
671 for (i = 0; i < ESPDMA_REGS; i++)
672 qemu_get_be32s(f, &s->espdmaregs[i]);
4f6200f0
FB
673 qemu_get_be32s(f, &s->ti_size);
674 qemu_get_be32s(f, &s->ti_rptr);
675 qemu_get_be32s(f, &s->ti_wptr);
676 qemu_get_be32s(f, &s->ti_dir);
677 qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
678 qemu_get_be32s(f, &s->dma);
2f275b8f 679
6f7e9aec
FB
680 return 0;
681}
682
683void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr)
684{
685 ESPState *s;
686 int esp_io_memory, espdma_io_memory;
687
688 s = qemu_mallocz(sizeof(ESPState));
689 if (!s)
690 return;
691
692 s->bd = bd;
693 s->irq = irq;
694
695 esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
696 cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
697
698 espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s);
699 cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);
700
701 esp_reset(s);
702
703 register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
704 qemu_register_reset(esp_reset, s);
705}
706
This page took 0.13434 seconds and 4 git commands to generate.