Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


refactoring to the point of compilation
[palacios.git] / palacios / src / devices / atapi.h
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #define ATAPI_PACKET_SIZE 12
21
22 #include "atapi-types.h"
23
24
25 /* ATAPI sucks...
26  * The OS will write to the cylinder register the number of bytes it wants to read 
27  * however the device can change that value 
28  * 
29  */
30 static int atapi_update_req_len(struct vm_device * dev, struct ide_channel * channel, uint_t xfer_len) {
31     struct ide_drive * drive = get_selected_drive(channel);
32
33     //   PrintDebug("Updating request length (pre=%d)\n", drive->req_len);
34
35     if (drive->req_len == 0) {
36         PrintError("ATAPI Error: request of length 0\n");
37         return -1;
38     }
39
40
41     channel->status.busy = 0;
42     channel->status.data_req = 1;
43     channel->status.error = 0;
44
45     drive->irq_flags.io_dir = 1;
46     drive->irq_flags.c_d = 0;
47
48     // make count even
49     if (drive->req_len % 2) {
50         drive->req_len -= 1;
51     }
52
53     // if the device can't return as much as the OS requested
54     if (drive->req_len > xfer_len) {
55         drive->req_len = xfer_len;
56     }
57
58     //    PrintDebug("Updating request length (post=%d)\n", drive->req_len);
59
60     return 0;
61 }
62
63
64
65 // This is for simple commands that don't need to sanity check the req_len
66 static void atapi_setup_cmd_resp(struct vm_device * dev, struct ide_channel * channel, uint_t xfer_len) {
67     struct ide_drive * drive = get_selected_drive(channel);
68
69     drive->transfer_length = xfer_len;
70     drive->transfer_index = 0;
71     drive->req_len = drive->transfer_length;
72
73     drive->irq_flags.io_dir = 1;
74     drive->irq_flags.c_d = 0;
75
76     channel->status.busy = 0;
77     channel->status.data_req = 1;
78     channel->status.error = 0;
79
80     ide_raise_irq(dev, channel);
81 }
82
83 static void atapi_cmd_error(struct vm_device * dev, struct ide_channel * channel, 
84                      atapi_sense_key_t  sense_key, atapi_add_sense_code_t asc) {
85     struct ide_drive * drive = get_selected_drive(channel);
86
87     // overload error register with ATAPI value
88     channel->error_reg.val = sense_key << 4;
89     
90     channel->status.busy = 0;
91     channel->status.ready = 1;
92     channel->status.write_fault = 0;
93     channel->status.data_req = 0;
94     channel->status.error = 1;
95   
96     drive->cd_state.sense.header = 0xf0;
97     drive->cd_state.sense.rsvd1 = 0x00;
98     drive->cd_state.sense.read_len = 0x0a;
99     drive->cd_state.sense.sense_key = sense_key;
100     drive->cd_state.sense.asc = asc;
101
102
103     drive->irq_flags.io_dir = 1;
104     drive->irq_flags.c_d = 1;
105     drive->irq_flags.rel = 0;
106
107     ide_raise_irq(dev, channel);
108 }
109
110
111 static void atapi_cmd_nop(struct vm_device * dev, struct ide_channel * channel) {
112     struct ide_drive * drive = get_selected_drive(channel);
113
114     channel->status.busy = 0;
115     channel->status.ready = 1;
116     channel->status.data_req = 0;
117     channel->status.error = 0;
118
119     drive->irq_flags.io_dir = 1;
120     drive->irq_flags.c_d = 1;
121     drive->irq_flags.rel = 0;
122
123     ide_raise_irq(dev, channel);
124 }
125
126
127
128 static int atapi_read_chunk(struct vm_device * dev, struct ide_channel * channel) {
129     struct ide_drive * drive = get_selected_drive(channel);
130
131     int ret = drive->ops->read(drive->data_buf, drive->current_lba * ATAPI_BLOCK_SIZE, ATAPI_BLOCK_SIZE, 
132 drive->private_data);
133     
134     if (ret == -1) {
135         PrintError("IDE: Error reading CD block (LBA=%p)\n", (void *)(addr_t)(drive->current_lba));
136         return -1;
137     }
138
139     return 0;
140 }
141
142
143 static int atapi_update_data_buf(struct vm_device * dev, struct ide_channel * channel) {
144     struct ide_drive * drive = get_selected_drive(channel);    
145     
146     switch (drive->cd_state.atapi_cmd) {
147         case 0x28: // read(10)
148         case 0xa8: // read(12)
149
150             // Update lba address to point to next block
151             drive->current_lba++;
152
153             // read the next block
154             return atapi_read_chunk(dev, channel);
155
156         default:
157             PrintError("Unhandled ATAPI command in update buffer %x\n", drive->cd_state.atapi_cmd);
158             return -1;
159     }
160
161     return 0;
162 }
163
164 static int atapi_read10(struct guest_info * core, 
165                         struct vm_device * dev, 
166                         struct ide_channel * channel) {
167     struct ide_drive * drive = get_selected_drive(channel);
168     struct atapi_read10_cmd * cmd = (struct atapi_read10_cmd *)(drive->data_buf);
169     uint32_t lba =  be_to_le_32(cmd->lba);
170     uint16_t xfer_len = be_to_le_16(cmd->xfer_len);
171
172     PrintDebug("READ10: XferLen=%d\n", xfer_len);
173
174     /* Check if cd is ready
175      * if not: atapi_cmd_error(... ATAPI_SEN_NOT_RDY, ASC_MEDIA_NOT_PRESENT)
176      */
177     
178     if (xfer_len == 0) {
179         atapi_cmd_nop(dev, channel);
180         return 0;
181     }
182     
183     if (lba + xfer_len > drive->ops->get_capacity(drive->private_data)) {
184         PrintError("IDE: xfer len exceeded capacity (lba=%d) (xfer_len=%d) (ReadEnd=%d) (capacity=%d)\n", 
185                    lba, xfer_len, lba + xfer_len, 
186                    (uint32_t)drive->ops->get_capacity(drive->private_data));
187         atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_LOG_BLK_OOR);
188         ide_raise_irq(dev, channel);
189         return 0;
190     }
191         
192     //    PrintDebug("Reading %d blocks from LBA 0x%x\n", xfer_len, lba);
193     
194     drive->current_lba = lba;
195         
196     // Update the request length value in the cylinder registers
197     drive->transfer_length = xfer_len * ATAPI_BLOCK_SIZE;
198     drive->transfer_index = 0;  
199
200     if (channel->features.dma) {
201
202         if (channel->dma_status.active == 1) {
203             if (dma_read(core, dev, channel) == -1) {
204                 PrintError("Error in DMA read for CD Read10 command\n");
205                 return -1;
206             }
207         }
208         return 0;
209     }
210
211     if (atapi_read_chunk(dev, channel) == -1) {
212         PrintError("IDE: Could not read initial chunk from CD\n");
213         return -1;
214     }
215         
216     // Length of ATAPI buffer sits in cylinder registers
217     // This is weird... The host sets this value to say what it would like to transfer, 
218     // if it is larger than the correct size, the device shrinks it to the correct size
219     if (atapi_update_req_len(dev, channel, ATAPI_BLOCK_SIZE) == -1) {
220         PrintError("Could not update initial request length\n");
221         return -1;
222     }
223     
224     ide_raise_irq(dev, channel);
225
226     return 0;
227 }
228
229
230
231 static void atapi_req_sense(struct vm_device * dev, struct ide_channel * channel) {
232     struct ide_drive * drive = get_selected_drive(channel);
233
234     memcpy(drive->data_buf, drive->cd_state.sense.buf, sizeof(drive->cd_state.sense.buf));
235    
236     atapi_setup_cmd_resp(dev, channel, 18);
237 }
238
239
240
241 static int atapi_get_capacity(struct vm_device * dev, struct ide_channel * channel) {
242     struct ide_drive * drive = get_selected_drive(channel);
243     struct atapi_rd_capacity_resp * resp = (struct atapi_rd_capacity_resp *)(drive->data_buf);
244     uint32_t capacity = drive->ops->get_capacity(drive->private_data);
245
246     resp->lba = le_to_be_32(capacity);
247     resp->block_len = le_to_be_32(ATAPI_BLOCK_SIZE);
248
249     atapi_setup_cmd_resp(dev, channel, sizeof(struct atapi_rd_capacity_resp));
250
251     return 0;
252 }
253
254 static int atapi_get_config(struct vm_device * dev, struct ide_channel * channel) {
255     struct ide_drive * drive = get_selected_drive(channel);
256     struct atapi_config_cmd * cmd = (struct atapi_config_cmd *)(drive->data_buf);
257     uint16_t alloc_len = be_to_le_16(cmd->alloc_len);
258     struct atapi_config_resp * resp = (struct atapi_config_resp *)(drive->data_buf);
259     int xfer_len = 8;
260
261     memset(resp, 0, sizeof(struct atapi_config_resp));
262
263     resp->data_len = le_to_be_32(xfer_len - 4);
264
265     if (alloc_len < xfer_len) {
266         xfer_len = alloc_len;
267     }
268     
269     atapi_setup_cmd_resp(dev, channel, xfer_len);
270     
271     return 0;
272 }
273
274
275 static int atapi_read_toc(struct vm_device * dev, struct ide_channel * channel) {
276     struct ide_drive * drive = get_selected_drive(channel);
277     struct atapi_rd_toc_cmd * cmd = (struct atapi_rd_toc_cmd *)(drive->data_buf);
278     uint16_t alloc_len = be_to_le_16(cmd->alloc_len);
279     struct atapi_rd_toc_resp * resp = (struct atapi_rd_toc_resp *)(drive->data_buf);
280
281     int xfer_len = 12;
282
283     memset(resp, 0, sizeof(struct atapi_rd_toc_resp));
284     
285     resp->data_len = le_to_be_16(10);
286     resp->first_track_num = 1;
287     resp->last_track_num = 1;
288
289     // we don't handle multi session
290     // we'll just treat it the same as single session
291     if ((cmd->format == 0) || (cmd->format == 1)) {
292         memset(&(resp->track_descs[0]), 0, 8);
293         
294         if (alloc_len < xfer_len) {
295             xfer_len = alloc_len;
296         }
297
298         atapi_setup_cmd_resp(dev, channel, xfer_len);
299     } else {
300         PrintError("Unhandled Format (%d)\n", cmd->format);
301         return -1;
302     }
303
304     return 0;
305 }
306
307
308 static int atapi_mode_sense_cur_values(struct vm_device * dev, struct ide_channel * channel, 
309                                        struct atapi_mode_sense_cmd * sense_cmd) {
310     struct ide_drive * drive = get_selected_drive(channel);
311     struct atapi_mode_sense_hdr * hdr = (struct atapi_mode_sense_hdr *)(drive->data_buf);
312     uint_t resp_len = sizeof(struct atapi_mode_sense_hdr);
313     uint16_t alloc_len = be_to_le_16(sense_cmd->alloc_len);
314     PrintDebug("Page Code: %x\n", sense_cmd->page_code);
315     PrintDebug("Alloc len: %d\n", alloc_len);
316
317     switch (sense_cmd->page_code) {
318
319         case 0x01: {    // error recovery
320             struct atapi_error_recovery * err = NULL;
321             err = (struct atapi_error_recovery *)(drive->data_buf + 
322                                                   sizeof(struct atapi_mode_sense_hdr));
323
324             memcpy(err, &(drive->cd_state.err_recovery), sizeof(struct atapi_error_recovery));
325
326             resp_len += sizeof(struct atapi_error_recovery);
327
328             hdr->mode_data_len = le_to_be_16(resp_len - 2);
329             
330             break;
331         }
332         case 0x2a: { // CDROM caps and mech. status
333             struct atapi_cdrom_caps * caps = NULL;
334             caps = (struct atapi_cdrom_caps *)(drive->data_buf + sizeof(struct atapi_mode_sense_hdr));
335             
336
337             memset(caps, 0, sizeof(struct atapi_cdrom_caps));
338
339             resp_len += sizeof(struct atapi_cdrom_caps);
340
341             hdr->mode_data_len = le_to_be_16(resp_len - 2);
342
343             caps->page_code = 0x2a;
344             caps->page_len = 0x12;
345             caps->mode2_form1 = 1;
346             caps->mode2_form2 = 1;
347             caps->multisession = 1;
348             caps->isrc = 1;
349             caps->upc = 1;
350
351             /* JRL TODO: These are dynamic caps */
352             caps->lock = 1;
353             caps->lock_state = 0;
354             caps->eject = 1;
355
356             caps->lmt = 1;
357             caps->obsolete1 = le_to_be_16(0x2c2);
358             caps->num_vols_supp = le_to_be_16(2);
359
360             caps->lun_buf_size = le_to_be_16(512);
361             caps->obsolete2 = le_to_be_16(0x2c2);
362
363             break;
364         }
365         case 0x0d:
366         case 0x0e:
367         case 0x3f:
368         default:
369             PrintError("ATAPI: Mode sense Page Code not supported (%x)\n", sense_cmd->page_code);
370             atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
371             ide_raise_irq(dev, channel);
372             return 0;
373     }
374
375
376     // We do this after error checking, because its only valid if everything worked
377     memset(hdr, 0, sizeof(struct atapi_mode_sense_hdr));
378     hdr->media_type_code = 0x70;
379
380     PrintDebug("resp_len=%d\n", resp_len);
381
382     drive->transfer_length = (resp_len > alloc_len) ? alloc_len : resp_len;
383     drive->transfer_index = 0;
384     atapi_update_req_len(dev, channel, drive->transfer_length);
385
386     ide_raise_irq(dev, channel);
387
388     return 0;
389 }
390
391
392 static int atapi_mode_sense(struct vm_device * dev, struct ide_channel * channel) {
393     struct ide_drive * drive = get_selected_drive(channel);
394     struct atapi_mode_sense_cmd * sense_cmd = (struct atapi_mode_sense_cmd *)(drive->data_buf);
395
396     switch (sense_cmd->page_ctrl) {
397         case 0x00: // Current values
398             return atapi_mode_sense_cur_values(dev, channel, sense_cmd);
399         case 0x01: // Changeable values
400         case 0x02: // default values
401         case 0x03: // saved values
402         default:
403             PrintError("ATAPI: Mode sense mode not supported (%x)\n", sense_cmd->page_ctrl);
404             return -1;
405     }
406     return 0;
407 }
408
409
410 static int atapi_inquiry(struct vm_device * dev, struct ide_channel * channel) {
411     struct ide_drive * drive = get_selected_drive(channel);
412     struct atapi_inquiry_cmd * inquiry_cmd = (struct atapi_inquiry_cmd *)(drive->data_buf);
413     uint16_t alloc_len = be_to_le_16(inquiry_cmd->alloc_len);
414     struct atapi_inquiry_resp * resp = (struct atapi_inquiry_resp *)(drive->data_buf);
415     int xfer_len = sizeof(struct atapi_inquiry_resp);
416     const char * vendor_id = "VTAB    ";
417     const char * product_id = "Turbo CD-ROM    ";
418     const char * product_rev = "1.0 ";
419
420     memset(resp, 0, sizeof(struct atapi_inquiry_resp));
421     
422     resp->dev_type = DEV_TYPE_CDROM;
423     resp->removable_media = 1;
424     resp->resp_data_fmt = 0x1;
425     resp->atapi_trans_ver = 0x2;
426     resp->additional_len = 31;
427
428     memcpy(resp->t10_vendor_id, vendor_id, strlen(vendor_id));
429     memcpy(resp->product_id, product_id, strlen(product_id));
430     memcpy(resp->product_rev, product_rev, strlen(product_rev));
431     
432     if (alloc_len < xfer_len) {
433         xfer_len = alloc_len;
434     }
435
436     atapi_setup_cmd_resp(dev, channel, xfer_len);
437
438     return 0;
439 }
440
441
442 static int atapi_cmd_is_data_op(uint8_t cmd) {
443     switch (cmd) {
444         case 0x28: // read (10)
445         case 0xa8: // read (12)
446         case 0x2a: // write (10)
447         case 0xaa: // write (12)
448             return 1;
449         default:
450             return 0;
451     } 
452 }
453
454
455 static int atapi_handle_packet(struct guest_info * core, struct vm_device * dev, struct ide_channel * channel) {
456    struct ide_drive * drive = get_selected_drive(channel);
457    uint8_t cmd = drive->data_buf[0];
458
459    PrintDebug("IDE: ATAPI Command %x\n", cmd);
460
461    drive->cd_state.atapi_cmd = cmd;
462
463    switch (cmd) {
464        case 0x00: // test unit ready
465            atapi_cmd_nop(dev, channel);
466
467            /* if drive not ready: 
468               atapi_cmd_error(... ATAPI_SEN_NOT_RDY, ASC_MEDIA_NOT_PRESENT)
469            */
470            break;
471        case 0x03: // request sense
472            atapi_req_sense(dev, channel);
473            break;
474
475        case 0x1e: // lock door
476            atapi_cmd_nop(dev, channel);
477            break;
478
479        case 0x28: // read(10)
480            if (atapi_read10(core, dev, channel) == -1) {
481                PrintError("IDE: Error in ATAPI read (%x)\n", cmd);
482                return -1;
483            }
484            break;
485
486        case 0x5a: // mode sense
487            if (atapi_mode_sense(dev, channel) == -1) {
488                PrintError("IDE: Error in ATAPI mode sense (%x)\n", cmd);
489                return -1;
490            }
491            break;
492
493
494        case 0x25: // read cdrom capacity
495            if (atapi_get_capacity(dev, channel) == -1) {
496                PrintError("IDE: Error getting CDROM capacity (%x)\n", cmd);
497                return -1;
498            }
499            break;
500
501
502        case 0x43: // read TOC
503            if (atapi_read_toc(dev, channel) == -1) {
504                PrintError("IDE: Error getting CDROM TOC (%x)\n", cmd);
505                return -1;
506            }
507            break;
508
509        case 0x46: // get configuration
510            if (atapi_get_config(dev, channel) == -1) {
511                PrintError("IDE: Error getting CDROM Configuration (%x)\n", cmd);
512                return -1;
513            }
514            break;
515
516
517        case 0x4a: // Get Status/event
518        case 0x51: // read disk info
519            // no-op to keep the Linux CD-ROM driver happy
520            PrintDebug("Error: Read disk info no-op to keep the Linux CD-ROM driver happy\n");
521            atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
522            ide_raise_irq(dev, channel);
523            break;
524
525        case 0x12: // inquiry
526            if (atapi_inquiry(dev, channel) == -1) {
527                PrintError("IDE: Error in ATAPI inquiry (%x)\n", cmd);
528                return -1;
529            }
530            break;
531
532        case 0xa8: // read(12)
533
534
535        case 0x1b: // start/stop drive
536        case 0xbd: // mechanism status 
537
538        case 0xbe: // read cd
539
540
541
542        case 0x2b: // seek
543
544        case 0x42: // read sub-channel
545
546
547            
548        case 0x55: // mode select
549        case 0xa6: // load/unload cd
550        case 0x4b: // pause/resume
551        case 0x45: // play audio
552        case 0x47: // play audio msf
553        case 0xbc: // play cd
554        case 0xb9: // read cd msf
555        case 0x44: // read header
556        case 0xba: // scan
557        case 0xbb: // set cd speed
558        case 0x4e: // stop play/scan
559
560        default:
561            PrintError("Unhandled ATAPI command %x\n", cmd);
562            atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
563            ide_raise_irq(dev, channel);
564            return -1;
565    }
566    
567    return 0;
568 }
569
570
571 static void atapi_identify_device(struct ide_drive * drive) {
572     struct ide_drive_id * drive_id = (struct ide_drive_id *)(drive->data_buf);
573     const char* serial_number = " VT00001\0\0\0\0\0\0\0\0\0\0\0\0";
574     const char* firmware = "ALPHA1  ";
575
576     drive->transfer_length = 512;
577     drive->transfer_index = 0;
578
579
580     memset(drive_id->buf, 0, sizeof(drive_id->buf));
581
582     drive_id->fixed_drive = 1;
583     drive_id->removable_media = 1;
584
585     // Black magic...
586     drive_id->disk_speed1 = 1;
587     drive_id->disk_speed3 = 1;
588
589     drive_id->cdrom_flag = 1;
590
591     // These buffers do not contain a terminating "\0"
592     memcpy(drive_id->serial_num, serial_number, strlen(serial_number));
593     memcpy(drive_id->firmware_rev, firmware, strlen(firmware));
594     memcpy(drive_id->model_num, drive->model, 40);
595
596     // 32 bits access
597     drive_id->dword_io = 1;
598
599     // enable DMA access
600     drive_id->dma_enable = 1;
601
602     // enable LBA access
603     drive_id->lba_enable = 1;
604     
605     drive_id->rw_multiples = 0x80ff;
606
607     // words 64-70, 54-58 valid
608     drive_id->field_valid = 0x0007; // DMA + pkg cmd valid
609
610     // copied from CFA540A
611     drive_id->buf[63] = 0x0103; // variable (DMA stuff)
612     //drive_id->buf[63] = 0x0000; // variable (DMA stuff)
613     
614     //    drive_id->buf[64] = 0x0001; // PIO
615     drive_id->buf[65] = 0x00b4;
616     drive_id->buf[66] = 0x00b4;
617     drive_id->buf[67] = 0x012c;
618     drive_id->buf[68] = 0x00b4;
619
620     drive_id->buf[71] = 30; // faked
621     drive_id->buf[72] = 30; // faked
622
623     //    drive_id->buf[80] = 0x1e; // supports up to ATA/ATAPI-4
624     drive_id->major_rev_num = 0x0040; // supports up to ATA/ATAPI-6
625
626     drive_id->dma_ultra = 0x2020; // Ultra_DMA_Mode_5_Selected | Ultra_DMA_Mode_5_Supported;
627 }