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.


IDE hard drive works past grub
[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->cd_ops->read(drive->data_buf, 1, drive->current_lba, drive->private_data);
132     
133     if (ret == -1) {
134         PrintError("IDE: Error reading CD block (LBA=%p)\n", (void *)(addr_t)(drive->current_lba));
135         return -1;
136     }
137
138     return 0;
139 }
140
141
142 static int atapi_update_data_buf(struct vm_device * dev, struct ide_channel * channel) {
143     struct ide_drive * drive = get_selected_drive(channel);    
144     
145     switch (drive->cd_state.atapi_cmd) {
146         case 0x28: // read(10)
147         case 0xa8: // read(12)
148
149             // Update lba address to point to next block
150             drive->current_lba++;
151
152             // read the next block
153             return atapi_read_chunk(dev, channel);
154
155         default:
156             PrintError("Unhandled ATAPI command in update buffer %x\n", drive->cd_state.atapi_cmd);
157             return -1;
158     }
159
160     return 0;
161 }
162
163 static int atapi_read10(struct vm_device * dev, struct ide_channel * channel) {
164     struct ide_drive * drive = get_selected_drive(channel);
165     struct atapi_read10_cmd * cmd = (struct atapi_read10_cmd *)(drive->data_buf);
166     uint32_t lba =  be_to_le_32(cmd->lba);
167     uint16_t xfer_len = be_to_le_16(cmd->xfer_len);
168
169     PrintDebug("READ10: XferLen=%d\n", xfer_len);
170
171     /* Check if cd is ready
172      * if not: atapi_cmd_error(... ATAPI_SEN_NOT_RDY, ASC_MEDIA_NOT_PRESENT)
173      */
174     
175     if (xfer_len == 0) {
176         atapi_cmd_nop(dev, channel);
177         return 0;
178     }
179     
180     if (lba + xfer_len > drive->cd_ops->get_capacity(drive->private_data)) {
181         PrintError("IDE: xfer len exceeded capacity (lba=%d) (xfer_len=%d) (ReadEnd=%d) (capacity=%d)\n", 
182                    lba, xfer_len, lba + xfer_len, 
183                    drive->cd_ops->get_capacity(drive->private_data));
184         atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_LOG_BLK_OOR);
185         ide_raise_irq(dev, channel);
186         return 0;
187     }
188         
189     //    PrintDebug("Reading %d blocks from LBA 0x%x\n", xfer_len, lba);
190     
191     drive->current_lba = lba;
192         
193     // Update the request length value in the cylinder registers
194         
195     if (atapi_read_chunk(dev, channel) == -1) {
196         PrintError("IDE: Could not read initial chunk from CD\n");
197         return -1;
198     }
199         
200     drive->transfer_length = xfer_len * ATAPI_BLOCK_SIZE;
201     drive->transfer_index = 0;
202         
203     // Length of ATAPI buffer sits in cylinder registers
204     // This is weird... The host sets this value to say what it would like to transfer, 
205     // if it is larger than the correct size, the device shrinks it to the correct size
206     if (atapi_update_req_len(dev, channel, ATAPI_BLOCK_SIZE) == -1) {
207         PrintError("Could not update initial request length\n");
208         return -1;
209     }
210     
211     ide_raise_irq(dev, channel);
212
213     return 0;
214 }
215
216
217
218 static void atapi_req_sense(struct vm_device * dev, struct ide_channel * channel) {
219     struct ide_drive * drive = get_selected_drive(channel);
220
221     memcpy(drive->data_buf, drive->cd_state.sense.buf, sizeof(drive->cd_state.sense.buf));
222    
223     atapi_setup_cmd_resp(dev, channel, 18);
224 }
225
226
227
228 static int atapi_get_capacity(struct vm_device * dev, struct ide_channel * channel) {
229     struct ide_drive * drive = get_selected_drive(channel);
230     struct atapi_rd_capacity_resp * resp = (struct atapi_rd_capacity_resp *)(drive->data_buf);
231     uint32_t capacity = drive->cd_ops->get_capacity(drive->private_data);
232
233     resp->lba = le_to_be_32(capacity);
234     resp->block_len = le_to_be_32(ATAPI_BLOCK_SIZE);
235
236     atapi_setup_cmd_resp(dev, channel, sizeof(struct atapi_rd_capacity_resp));
237
238     return 0;
239 }
240
241 static int atapi_get_config(struct vm_device * dev, struct ide_channel * channel) {
242     struct ide_drive * drive = get_selected_drive(channel);
243     struct atapi_config_cmd * cmd = (struct atapi_config_cmd *)(drive->data_buf);
244     uint16_t alloc_len = be_to_le_16(cmd->alloc_len);
245     struct atapi_config_resp * resp = (struct atapi_config_resp *)(drive->data_buf);
246     int xfer_len = 8;
247
248     memset(resp, 0, sizeof(struct atapi_config_resp));
249
250     resp->data_len = le_to_be_32(xfer_len - 4);
251
252     if (alloc_len < xfer_len) {
253         xfer_len = alloc_len;
254     }
255     
256     atapi_setup_cmd_resp(dev, channel, xfer_len);
257     
258     return 0;
259 }
260
261
262 static int atapi_read_toc(struct vm_device * dev, struct ide_channel * channel) {
263     struct ide_drive * drive = get_selected_drive(channel);
264     struct atapi_rd_toc_cmd * cmd = (struct atapi_rd_toc_cmd *)(drive->data_buf);
265     uint16_t alloc_len = be_to_le_16(cmd->alloc_len);
266     struct atapi_rd_toc_resp * resp = (struct atapi_rd_toc_resp *)(drive->data_buf);
267
268     int xfer_len = 12;
269
270     memset(resp, 0, sizeof(struct atapi_rd_toc_resp));
271     
272     resp->data_len = le_to_be_16(10);
273     resp->first_track_num = 1;
274     resp->last_track_num = 1;
275
276     // we don't handle multi session
277     // we'll just treat it the same as single session
278     if ((cmd->format == 0) || (cmd->format == 1)) {
279         memset(&(resp->track_descs[0]), 0, 8);
280         
281         if (alloc_len < xfer_len) {
282             xfer_len = alloc_len;
283         }
284
285         atapi_setup_cmd_resp(dev, channel, xfer_len);
286     } else {
287         PrintError("Unhandled Format (%d)\n", cmd->format);
288         return -1;
289     }
290
291     return 0;
292 }
293
294
295 static int atapi_mode_sense_cur_values(struct vm_device * dev, struct ide_channel * channel, 
296                                        struct atapi_mode_sense_cmd * sense_cmd) {
297     struct ide_drive * drive = get_selected_drive(channel);
298     struct atapi_mode_sense_hdr * hdr = (struct atapi_mode_sense_hdr *)(drive->data_buf);
299     uint_t resp_len = sizeof(struct atapi_mode_sense_hdr);
300     uint16_t alloc_len = be_to_le_16(sense_cmd->alloc_len);
301     PrintDebug("Page Code: %x\n", sense_cmd->page_code);
302     PrintDebug("Alloc len: %d\n", alloc_len);
303
304     switch (sense_cmd->page_code) {
305
306         case 0x01: {    // error recovery
307             struct atapi_error_recovery * err = NULL;
308             err = (struct atapi_error_recovery *)(drive->data_buf + 
309                                                   sizeof(struct atapi_mode_sense_hdr));
310
311             memcpy(err, &(drive->cd_state.err_recovery), sizeof(struct atapi_error_recovery));
312
313             resp_len += sizeof(struct atapi_error_recovery);
314
315             hdr->mode_data_len = le_to_be_16(resp_len - 2);
316             
317             break;
318         }
319         case 0x2a: { // CDROM caps and mech. status
320             struct atapi_cdrom_caps * caps = NULL;
321             caps = (struct atapi_cdrom_caps *)(drive->data_buf + sizeof(struct atapi_mode_sense_hdr));
322             
323
324             memset(caps, 0, sizeof(struct atapi_cdrom_caps));
325
326             resp_len += sizeof(struct atapi_cdrom_caps);
327
328             hdr->mode_data_len = le_to_be_16(resp_len - 2);
329
330             caps->page_code = 0x2a;
331             caps->page_len = 0x12;
332             caps->mode2_form1 = 1;
333             caps->mode2_form2 = 1;
334             caps->multisession = 1;
335             caps->isrc = 1;
336             caps->upc = 1;
337
338             /* JRL TODO: These are dynamic caps */
339             caps->lock = 1;
340             caps->lock_state = 0;
341             caps->eject = 1;
342
343             caps->lmt = 1;
344             caps->obsolete1 = le_to_be_16(0x2c2);
345             caps->num_vols_supp = le_to_be_16(2);
346
347             caps->lun_buf_size = le_to_be_16(512);
348             caps->obsolete2 = le_to_be_16(0x2c2);
349
350             break;
351         }
352         case 0x0d:
353         case 0x0e:
354         case 0x3f:
355         default:
356             PrintError("ATAPI: Mode sense Page Code not supported (%x)\n", sense_cmd->page_code);
357             atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
358             ide_raise_irq(dev, channel);
359             return 0;
360     }
361
362
363     // We do this after error checking, because its only valid if everything worked
364     memset(hdr, 0, sizeof(struct atapi_mode_sense_hdr));
365     hdr->media_type_code = 0x70;
366
367     PrintDebug("resp_len=%d\n", resp_len);
368
369     drive->transfer_length = (resp_len > alloc_len) ? alloc_len : resp_len;
370     drive->transfer_index = 0;
371     atapi_update_req_len(dev, channel, drive->transfer_length);
372
373     ide_raise_irq(dev, channel);
374
375     return 0;
376 }
377
378
379 static int atapi_mode_sense(struct vm_device * dev, struct ide_channel * channel) {
380     struct ide_drive * drive = get_selected_drive(channel);
381     struct atapi_mode_sense_cmd * sense_cmd = (struct atapi_mode_sense_cmd *)(drive->data_buf);
382
383     switch (sense_cmd->page_ctrl) {
384         case 0x00: // Current values
385             return atapi_mode_sense_cur_values(dev, channel, sense_cmd);
386         case 0x01: // Changeable values
387         case 0x02: // default values
388         case 0x03: // saved values
389         default:
390             PrintError("ATAPI: Mode sense mode not supported (%x)\n", sense_cmd->page_ctrl);
391             return -1;
392     }
393     return 0;
394 }
395
396
397 static int atapi_handle_packet(struct vm_device * dev, struct ide_channel * channel) {
398    struct ide_drive * drive = get_selected_drive(channel);
399    uint8_t cmd = drive->data_buf[0];
400
401    PrintDebug("IDE: ATAPI Command %x\n", cmd);
402
403    drive->cd_state.atapi_cmd = cmd;
404
405    switch (cmd) {
406        case 0x00: // test unit ready
407            atapi_cmd_nop(dev, channel);
408
409            /* if drive not ready: 
410               atapi_cmd_error(... ATAPI_SEN_NOT_RDY, ASC_MEDIA_NOT_PRESENT)
411            */
412            break;
413        case 0x03: // request sense
414            atapi_req_sense(dev, channel);
415            break;
416
417        case 0x28: // read(10)
418            if (atapi_read10(dev, channel) == -1) {
419                PrintError("IDE: Error in ATAPI read (%x)\n", cmd);
420                return -1;
421            }
422            break;
423
424        case 0x5a: // mode sense
425            if (atapi_mode_sense(dev, channel) == -1) {
426                PrintError("IDE: Error in ATAPI mode sense (%x)\n", cmd);
427                return -1;
428            }
429            break;
430
431
432        case 0x25: // read cdrom capacity
433            if (atapi_get_capacity(dev, channel) == -1) {
434                PrintError("IDE: Error getting CDROM capacity (%x)\n", cmd);
435                return -1;
436            }
437            break;
438
439
440        case 0x43: // read TOC
441            if (atapi_read_toc(dev, channel) == -1) {
442                PrintError("IDE: Error getting CDROM TOC (%x)\n", cmd);
443                return -1;
444            }
445            break;
446
447        case 0x46: // get configuration
448            if (atapi_get_config(dev, channel) == -1) {
449                PrintError("IDE: Error getting CDROM Configuration (%x)\n", cmd);
450                return -1;
451            }
452            break;
453
454        case 0x51: // read disk info
455            // no-op to keep the Linux CD-ROM driver happy
456            PrintDebug("Error: Read disk info no-op to keep the Linux CD-ROM driver happy\n");
457            atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
458            ide_raise_irq(dev, channel);
459            break;
460
461
462
463        case 0xa8: // read(12)
464
465
466        case 0x1b: // start/stop drive
467        case 0xbd: // mechanism status 
468        case 0x12: // inquiry
469
470        case 0xbe: // read cd
471
472
473
474        case 0x2b: // seek
475        case 0x1e: // lock door
476        case 0x42: // read sub-channel
477
478
479            
480        case 0x55: // mode select
481        case 0xa6: // load/unload cd
482        case 0x4b: // pause/resume
483        case 0x45: // play audio
484        case 0x47: // play audio msf
485        case 0xbc: // play cd
486        case 0xb9: // read cd msf
487        case 0x44: // read header
488        case 0xba: // scan
489        case 0xbb: // set cd speed
490        case 0x4e: // stop play/scan
491  
492        case 0x4a: // ???
493        default:
494            PrintError("Unhandled ATAPI command %x\n", cmd);
495            atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
496            ide_raise_irq(dev, channel);
497            return -1;
498    }
499    
500    return 0;
501 }
502
503
504 static void atapi_identify_device(struct ide_drive * drive) {
505     struct ide_drive_id * drive_id = (struct ide_drive_id *)(drive->data_buf);
506     const char* serial_number = " VT00001\0\0\0\0\0\0\0\0\0\0\0\0";
507     const char* firmware = "ALPHA1  ";
508
509     drive->transfer_length = 512;
510     drive->transfer_index = 0;
511
512
513     memset(drive_id->buf, 0, sizeof(drive_id->buf));
514
515     drive_id->fixed_drive = 1;
516     drive_id->removable_media = 1;
517
518     // Black magic...
519     drive_id->disk_speed1 = 1;
520     drive_id->disk_speed3 = 1;
521
522     drive_id->cdrom_flag = 1;
523
524     // These buffers do not contain a terminating "\0"
525     memcpy(drive_id->serial_num, serial_number, strlen(serial_number));
526     memcpy(drive_id->firmware_rev, firmware, strlen(firmware));
527     memcpy(drive_id->model_num, drive->model, 40);
528
529     // 32 bits access
530     drive_id->dword_io = 1;
531
532     // enable DMA access
533     drive_id->dma_enable = 1;
534
535     // enable LBA access
536     drive_id->lba_enable = 1;
537     
538     drive_id->rw_multiples = 0x80ff;
539
540     // words 64-70, 54-58 valid
541     drive_id->field_valid = 0x0007; // DMA + pkg cmd valid
542
543     // copied from CFA540A
544     drive_id->buf[63] = 0x0103; // variable (DMA stuff)
545     //drive_id->buf[63] = 0x0000; // variable (DMA stuff)
546     
547     //    drive_id->buf[64] = 0x0001; // PIO
548     drive_id->buf[65] = 0x00b4;
549     drive_id->buf[66] = 0x00b4;
550     drive_id->buf[67] = 0x012c;
551     drive_id->buf[68] = 0x00b4;
552
553     drive_id->buf[71] = 30; // faked
554     drive_id->buf[72] = 30; // faked
555
556     //    drive_id->buf[80] = 0x1e; // supports up to ATA/ATAPI-4
557     drive_id->major_rev_num = 0x0040; // supports up to ATA/ATAPI-6
558
559     drive_id->dma_ultra = 0x2020; // Ultra_DMA_Mode_5_Selected | Ultra_DMA_Mode_5_Supported;
560 }