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.


7534f1e22307e5f54dadfb5c71726f8df43ae01a
[palacios.git] / palacios / src / devices / ide.c
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 #include <palacios/vmm.h>
21 #include <devices/ide.h>
22 #include "ide-types.h"
23
24 #define PRI_DEFAULT_IRQ 14
25 #define SEC_DEFAULT_IRQ 15
26
27 #define PRI_DATA_PORT         0x1f0
28 #define PRI_FEATURES_PORT     0x1f1
29 #define PRI_SECT_CNT_PORT     0x1f2
30 #define PRI_SECT_NUM_PORT     0x1f3
31 #define PRI_CYL_LOW_PORT      0x1f4
32 #define PRI_CYL_HIGH_PORT     0x1f5
33 #define PRI_DRV_SEL_PORT      0x1f6
34 #define PRI_CMD_PORT          0x1f7
35 #define PRI_CTRL_PORT         0x3f6
36 #define PRI_ADDR_REG_PORT     0x3f7
37
38 #define SEC_DATA_PORT         0x170
39 #define SEC_FEATURES_PORT     0x171
40 #define SEC_SECT_CNT_PORT     0x172
41 #define SEC_SECT_NUM_PORT     0x173
42 #define SEC_CYL_LOW_PORT      0x174
43 #define SEC_CYL_HIGH_PORT     0x175
44 #define SEC_DRV_SEL_PORT      0x176
45 #define SEC_CMD_PORT          0x177
46 #define SEC_CTRL_PORT         0x376
47 #define SEC_ADDR_REG_PORT     0x377
48
49
50
51 static const char * ide_dev_type_strs[] = {"HARDDISK", "CDROM", "NONE"};
52
53
54 static inline const char * device_type_to_str(v3_ide_dev_type_t type) {
55     if (type > 2) {
56         return NULL;
57     }
58
59     return ide_dev_type_strs[type];
60 }
61
62
63
64
65
66 struct ide_drive {
67     // Command Registers
68
69     v3_ide_dev_type_t drive_type;
70
71     union {
72         struct v3_ide_cd_ops * cd_ops;
73         struct v3_ide_hd_ops * hd_ops;
74     };
75
76
77     char model[41];
78
79     uint_t data_offset;
80
81     // data buffer...
82     uint8_t buffer[2048];
83
84     void * private_data;
85
86     uint8_t sector_count;               // 0x1f2,0x172
87     uint8_t sector_num;               // 0x1f3,0x173
88     union {
89         uint16_t cylinder;
90         struct {
91             uint8_t cylinder_low;       // 0x1f4,0x174
92             uint8_t cylinder_high;      // 0x1f5,0x175
93         } __attribute__((packed));
94     } __attribute__((packed));
95
96
97 };
98
99
100
101 struct ide_channel {
102     struct ide_drive drives[2];
103
104     // Command Registers
105     struct ide_error_reg error_reg;     // [read] 0x1f1,0x171
106
107     struct ide_features_reg features;
108
109     struct ide_drive_head_reg drive_head; // 0x1f6,0x176
110
111     struct ide_status_reg status;       // [read] 0x1f7,0x177
112     uint8_t command_reg;                // [write] 0x1f7,0x177
113
114     int irq; // this is temporary until we add PCI support
115
116     // Control Registers
117     struct ide_ctrl_reg ctrl_reg; // [write] 0x3f6,0x376
118 };
119
120
121
122 struct ide_internal {
123     struct ide_channel channels[2];
124 };
125
126
127
128
129 static inline int get_channel_index(ushort_t port) {
130     if (((port & 0xfff8) == 0x1f0) ||
131         ((port & 0xfffe) == 0x3f6)) {
132         return 0;
133     } else if (((port & 0xfff8) == 0x170) ||
134                ((port & 0xfffe) == 0x376)) {
135         return 1;
136     }
137
138     return -1;
139 }
140
141 static inline struct ide_channel * get_selected_channel(struct ide_internal * ide, ushort_t port) {
142     int channel_idx = get_channel_index(port);    
143     return &(ide->channels[channel_idx]);
144 }
145
146 static inline struct ide_drive * get_selected_drive(struct ide_channel * channel) {
147     return &(channel->drives[channel->drive_head.drive_sel]);
148 }
149
150
151 static inline int is_lba_enabled(struct ide_channel * channel) {
152     return channel->drive_head.lba_mode;
153 }
154
155
156 static void ide_raise_irq(struct vm_device * dev, struct ide_channel * channel) {
157     if (channel->ctrl_reg.irq_disable == 0) {
158         v3_raise_irq(dev->vm, channel->irq);
159     }
160 }
161
162
163 static void drive_reset(struct ide_drive * drive) {
164     drive->sector_count = 0x01;
165     drive->sector_num = 0x01;
166     
167     if (drive->drive_type == IDE_CDROM) {
168         drive->cylinder = 0xeb14;
169     } else {
170         drive->cylinder = 0x0000;
171     }
172
173     // Send the reset signal to the connected device callbacks
174     //     channel->drives[0].reset();
175     //    channel->drives[1].reset();
176 }
177
178 static void channel_reset(struct ide_channel * channel) {
179     
180     // set busy and seek complete flags
181     channel->status.val = 0x90;
182
183     // Clear errors
184     channel->error_reg.val = 0x01;
185
186     // clear commands
187     channel->command_reg = 0x00;
188
189     channel->ctrl_reg.irq_disable = 0;
190 }
191
192 static void channel_reset_complete(struct ide_channel * channel) {
193     channel->status.busy = 0;
194     channel->status.ready = 1;
195
196     channel->drive_head.head_num = 0;    
197     
198     drive_reset(&(channel->drives[0]));
199     drive_reset(&(channel->drives[1]));
200 }
201
202
203 static void ide_abort_command(struct vm_device * dev, struct ide_channel * channel) {
204     channel->status.val = 0x41; // Error + ready
205     channel->error_reg.val = 0x04; // No idea...
206
207     ide_raise_irq(dev, channel);
208 }
209
210
211
212
213 // Include the ATAPI interface handlers
214 #include "atapi.h"
215
216
217
218
219 static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
220     struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
221     struct ide_channel * channel = get_selected_channel(ide, port);
222     struct ide_drive * drive = get_selected_drive(channel);
223
224     if (length != 1) {
225         PrintError("Invalid Write Length on IDE command Port %x\n", port);
226         return -1;
227     }
228
229     channel->command_reg = *(uint8_t *)src;
230     
231
232     PrintDebug("IDE: Writing Command Port %x (val=%x)\n", port, *(uint8_t *)src);
233
234     switch (channel->command_reg) {
235         
236         case 0xa0: // ATAPI Command Packet
237             if (drive->drive_type != IDE_CDROM) {
238                 ide_abort_command(dev, channel);
239             }
240             
241             drive->sector_count = 1;
242
243             channel->status.busy = 0;
244             channel->status.write_fault = 0;
245             channel->status.data_req = 1;
246             channel->status.error = 0;
247             
248             drive->data_offset = 0;
249
250         case 0xa1: // ATAPI Identify Device Packet
251             atapi_identify_device(drive);
252
253             channel->error_reg.val = 0;
254             channel->status.val = 0x58; // ready, data_req, seek_complete
255             
256             ide_raise_irq(dev, channel);
257         case 0xec: // Identify Device
258             if (drive->drive_type != IDE_DISK) {
259                 drive_reset(drive);
260
261                 // JRL: Should we abort here?
262                 ide_abort_command(dev, channel);
263             } else {
264                 PrintError("IDE Disks currently not implemented\n");
265                 return -1;
266             }
267             break;
268             
269     }
270
271     return -1;
272 }
273
274
275 static int write_data_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
276     PrintDebug("IDE: Writing Data Port %x (val=%x)\n", port, *(uint8_t *)src);
277     return -1;
278 }
279
280
281 static int read_data_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
282     PrintDebug("IDE: Reading Data Port %x\n", port);
283     return -1;
284 }
285
286 static int write_port_std(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
287     struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
288     struct ide_channel * channel = get_selected_channel(ide, port);
289     struct ide_drive * drive = get_selected_drive(channel);
290             
291     if (length != 1) {
292         PrintError("Invalid Write length on IDE port %x\n", port);
293         return -1;
294     }
295
296     PrintDebug("IDE: Writing Standard Port %x (val=%x)\n", port, *(uint8_t *)src);
297
298
299     switch (port) {
300         // reset and interrupt enable
301         case PRI_CTRL_PORT:
302         case SEC_CTRL_PORT: {
303             struct ide_ctrl_reg * tmp_ctrl = (struct ide_ctrl_reg *)src;
304
305             // only reset channel on a 0->1 reset bit transition
306             if ((!channel->ctrl_reg.soft_reset) && (tmp_ctrl->soft_reset)) {
307                 channel_reset(channel);
308             } else if ((channel->ctrl_reg.soft_reset) && (!tmp_ctrl->soft_reset)) {
309                 channel_reset_complete(channel);
310             }
311
312             channel->ctrl_reg.val = tmp_ctrl->val;          
313             break;
314         }
315         case PRI_FEATURES_PORT:
316         case SEC_FEATURES_PORT:
317             channel->features.val = *(uint8_t *)src;
318             break;
319
320         case PRI_SECT_CNT_PORT:
321         case SEC_SECT_CNT_PORT:
322             drive->sector_count = *(uint8_t *)src;
323             break;
324
325         case PRI_SECT_NUM_PORT:
326         case SEC_SECT_NUM_PORT:
327             drive->sector_num = *(uint8_t *)src;
328
329         case PRI_CYL_LOW_PORT:
330         case SEC_CYL_LOW_PORT:
331             drive->cylinder_low = *(uint8_t *)src;
332             break;
333
334         case PRI_CYL_HIGH_PORT:
335         case SEC_CYL_HIGH_PORT:
336             drive->cylinder_high = *(uint8_t *)src;
337             break;
338
339         case PRI_DRV_SEL_PORT:
340         case SEC_DRV_SEL_PORT: {
341             channel->drive_head.val = *(uint8_t *)src;
342             
343             // make sure the reserved bits are ok..
344             // JRL TODO: check with new ramdisk to make sure this is right...
345             channel->drive_head.val |= 0xa0;
346
347             drive = get_selected_drive(channel);
348
349             // Selecting a non-present device is a no-no
350             if (drive->drive_type == IDE_NONE) {
351                 PrintDebug("Attempting to select a non-present drive\n");
352                 channel->error_reg.abort = 1;
353                 channel->status.error = 1;
354             }
355
356             break;
357         }
358         default:
359             PrintError("IDE: Write to unknown Port %x\n", port);
360             return -1;
361     }
362     return length;
363 }
364
365
366 static int read_port_std(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
367     struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
368     struct ide_channel * channel = get_selected_channel(ide, port);
369     struct ide_drive * drive = get_selected_drive(channel);
370     
371     if (length != 1) {
372         PrintError("Invalid Read length on IDE port %x\n", port);
373         return -1;
374     }
375
376     PrintDebug("IDE: Reading Standard Port %x\n", port);
377
378
379     if ((port == PRI_ADDR_REG_PORT) ||
380         (port == SEC_ADDR_REG_PORT)) {
381         // unused, return 0xff
382         *(uint8_t *)dst = 0xff;
383         return length;
384     }
385
386
387     // if no drive is present just return 0 + reserved bits
388     if (drive->drive_type == IDE_NONE) {
389         if ((port == PRI_DRV_SEL_PORT) ||
390             (port == SEC_DRV_SEL_PORT)) {
391             *(uint8_t *)dst = 0xa0;
392         } else {
393             *(uint8_t *)dst = 0;
394         }
395
396         return length;
397     }
398
399     switch (port) {
400
401         // This is really the error register.
402         case PRI_FEATURES_PORT:
403         case SEC_FEATURES_PORT:
404             *(uint8_t *)dst = channel->error_reg.val;
405             break;
406             
407         case PRI_SECT_CNT_PORT:
408         case SEC_SECT_CNT_PORT:
409             *(uint8_t *)dst = drive->sector_count;
410             break;
411
412         case PRI_SECT_NUM_PORT:
413         case SEC_SECT_NUM_PORT:
414             *(uint8_t *)dst = drive->sector_num;
415             break;
416
417         case PRI_CYL_LOW_PORT:
418         case SEC_CYL_LOW_PORT:
419             *(uint8_t *)dst = drive->cylinder_low;
420             break;
421
422
423         case PRI_CYL_HIGH_PORT:
424         case SEC_CYL_HIGH_PORT:
425             *(uint8_t *)dst = drive->cylinder_high;
426             break;
427
428         case PRI_DRV_SEL_PORT:
429         case SEC_DRV_SEL_PORT:  // hard disk drive and head register 0x1f6
430             *(uint8_t *)dst = channel->drive_head.val;
431             break;
432
433         case PRI_CTRL_PORT:
434         case SEC_CTRL_PORT:
435         case PRI_CMD_PORT:
436         case SEC_CMD_PORT:
437             // Something about lowering interrupts here....
438             *(uint8_t *)dst = channel->status.val;
439             break;
440
441         default:
442             PrintError("Invalid Port: %x\n", port);
443             return -1;
444     }
445
446     PrintDebug("\tVal=%x\n", *(uint8_t *)dst);
447
448     return length;
449 }
450
451
452
453 static void init_drive(struct ide_drive * drive) {
454
455     drive->sector_count = 0x01;
456     drive->sector_num = 0x01;
457     drive->cylinder = 0x0000;
458
459     drive->drive_type = IDE_NONE;
460
461     drive->data_offset = 0;
462     memset(drive->model, 0, sizeof(drive->model));
463     memset(drive->buffer, 0, sizeof(drive->buffer));
464
465     drive->private_data = NULL;
466     drive->cd_ops = NULL;
467 }
468
469 static void init_channel(struct ide_channel * channel) {
470     int i = 0;
471
472     channel->error_reg.val = 0x01;
473     channel->drive_head.val = 0x00;
474     channel->status.val = 0x00;
475     channel->command_reg = 0x00;
476     channel->ctrl_reg.val = 0x08;
477
478
479     for (i = 0; i < 2; i++) {
480         init_drive(&(channel->drives[i]));
481     }
482
483 }
484
485 static void init_ide_state(struct ide_internal * ide) {
486     int i;
487
488     for (i = 0; i < 2; i++) {
489         init_channel(&(ide->channels[i]));
490
491         // JRL: this is a terrible hack...
492         ide->channels[i].irq = PRI_DEFAULT_IRQ + i;
493     }
494 }
495
496
497
498 static int init_ide(struct vm_device * dev) {
499     struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
500
501     PrintDebug("IDE: Initializing IDE\n");
502
503     init_ide_state(ide);
504
505
506     v3_dev_hook_io(dev, PRI_CTRL_PORT, 
507                    &read_port_std, &write_port_std);
508
509     v3_dev_hook_io(dev, PRI_DATA_PORT, 
510                    &read_data_port, &write_data_port);
511     v3_dev_hook_io(dev, PRI_FEATURES_PORT, 
512                    &read_port_std, &write_port_std);
513     v3_dev_hook_io(dev, PRI_SECT_CNT_PORT, 
514                    &read_port_std, &write_port_std);
515     v3_dev_hook_io(dev, PRI_SECT_NUM_PORT, 
516                    &read_port_std, &write_port_std);
517     v3_dev_hook_io(dev, PRI_CYL_LOW_PORT, 
518                    &read_port_std, &write_port_std);
519     v3_dev_hook_io(dev, PRI_CYL_HIGH_PORT, 
520                    &read_port_std, &write_port_std);
521     v3_dev_hook_io(dev, PRI_DRV_SEL_PORT, 
522                    &read_port_std, &write_port_std);
523     v3_dev_hook_io(dev, PRI_CMD_PORT, 
524                    &read_port_std, &write_cmd_port);
525
526
527     v3_dev_hook_io(dev, SEC_CTRL_PORT, 
528                    &read_port_std, &write_port_std);
529
530     v3_dev_hook_io(dev, SEC_DATA_PORT, 
531                    &read_data_port, &write_data_port);
532     v3_dev_hook_io(dev, SEC_FEATURES_PORT, 
533                    &read_port_std, &write_port_std);
534     v3_dev_hook_io(dev, SEC_SECT_CNT_PORT, 
535                    &read_port_std, &write_port_std);
536     v3_dev_hook_io(dev, SEC_SECT_NUM_PORT, 
537                    &read_port_std, &write_port_std);
538     v3_dev_hook_io(dev, SEC_CYL_LOW_PORT, 
539                    &read_port_std, &write_port_std);
540     v3_dev_hook_io(dev, SEC_CYL_HIGH_PORT, 
541                    &read_port_std, &write_port_std);
542     v3_dev_hook_io(dev, SEC_DRV_SEL_PORT, 
543                    &read_port_std, &write_port_std);
544     v3_dev_hook_io(dev, SEC_CMD_PORT, 
545                    &read_port_std, &write_cmd_port);
546   
547   
548
549     v3_dev_hook_io(dev, SEC_ADDR_REG_PORT, 
550                    &read_port_std, &write_port_std);
551
552     v3_dev_hook_io(dev, PRI_ADDR_REG_PORT, 
553                    &read_port_std, &write_port_std);
554
555     return 0;
556 }
557
558
559 static int deinit_ide(struct vm_device * dev) {
560     // unhook io ports....
561     // deregister from PCI?
562     return 0;
563 }
564
565
566 static struct vm_device_ops dev_ops = {
567     .init = init_ide,
568     .deinit = deinit_ide,
569     .reset = NULL,
570     .start = NULL,
571     .stop = NULL,
572 };
573
574
575 struct vm_device *  v3_create_ide() {
576     struct ide_internal * ide  = (struct ide_internal *)V3_Malloc(sizeof(struct ide_internal));  
577     struct vm_device * device = v3_create_device("IDE", &dev_ops, ide);
578
579     //    ide->pci = pci;
580
581     PrintDebug("IDE: Creating IDE bus x 2\n");
582
583     return device;
584 }
585
586
587
588
589
590 int v3_ide_register_cdrom(struct vm_device * ide_dev, 
591                           uint_t bus_num, 
592                           uint_t drive_num,
593                           char * dev_name, 
594                           struct v3_ide_cd_ops * ops, 
595                           void * private_data) {
596
597     struct ide_internal * ide  = (struct ide_internal *)(ide_dev->private_data);  
598     struct ide_channel * channel = NULL;
599     struct ide_drive * drive = NULL;
600
601     V3_ASSERT((bus_num >= 0) && (bus_num < 2));
602     V3_ASSERT((drive_num >= 0) && (drive_num < 2));
603
604     channel = &(ide->channels[bus_num]);
605     drive = &(channel->drives[drive_num]);
606     
607     if (drive->drive_type != IDE_NONE) {
608         PrintError("Device slot (bus=%d, drive=%d) already occupied\n", bus_num, drive_num);
609         return -1;
610     }
611
612     strncpy(drive->model, dev_name, sizeof(drive->model) - 1);
613
614     while (strlen((char *)(drive->model)) < 40) {
615         strcat((char*)(drive->model), " ");
616     }
617
618
619     drive->drive_type = IDE_CDROM;
620
621     drive->cd_ops = ops;
622
623     drive->private_data = private_data;
624
625     return 0;
626 }
627
628
629 int v3_ide_register_harddisk(struct vm_device * ide_dev, 
630                              uint_t bus_num, 
631                              uint_t drive_num, 
632                              char * dev_name, 
633                              struct v3_ide_hd_ops * ops, 
634                              void * private_data) {
635
636     struct ide_internal * ide  = (struct ide_internal *)(ide_dev->private_data);  
637     struct ide_channel * channel = NULL;
638     struct ide_drive * drive = NULL;
639
640     V3_ASSERT((bus_num >= 0) && (bus_num < 2));
641     V3_ASSERT((drive_num >= 0) && (drive_num < 2));
642
643     channel = &(ide->channels[bus_num]);
644     drive = &(channel->drives[drive_num]);
645     
646     if (drive->drive_type != IDE_NONE) {
647         PrintError("Device slot (bus=%d, drive=%d) already occupied\n", bus_num, drive_num);
648         return -1;
649     }
650
651     strncpy(drive->model, dev_name, sizeof(drive->model) - 1);
652
653     drive->drive_type = IDE_DISK;
654
655     drive->hd_ops = ops;
656
657     drive->private_data = private_data;
658
659     return 0;
660 }