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.


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