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.


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