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.


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