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.


initial commit of 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     uint8_t data_port;                  // 0x1f0,0x170
68     struct ide_error_reg error_reg;     // [read] 0x1f1,0x171
69     uint8_t sector_count;               // 0x1f2,0x172
70     uint8_t sector_num;               // 0x1f3,0x173
71
72     union {
73         uint16_t cylinder;
74         struct {
75             uint8_t cylinder_low;       // 0x1f4,0x174
76             uint8_t cylinder_high;      // 0x1f5,0x175
77         } __attribute__((packed));
78     } __attribute__((packed));
79
80     struct ide_drive_head_reg drive_head; // 0x1f6,0x176
81
82     struct ide_status_reg status;       // [read] 0x1f7,0x177
83     uint8_t command_reg;                // [write] 0x1f7,0x177
84
85
86     // Control Registers
87     struct ide_drive_ctrl_reg ctrl_reg; // [write] 0x3f6,0x376
88
89
90
91     ide_dev_type_t drive_type;
92
93 };
94
95
96
97 struct ide_channel {
98     struct ide_drive drives[2];
99
100     int drive_sel;
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_sel]);
131 }
132
133
134
135 static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
136     PrintDebug("IDE: Writing Command Port %x (val=%x)\n", port, *(uint8_t *)src);
137     return -1;
138 }
139
140
141 static int write_data_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
142     PrintDebug("IDE: Writing Data Port %x (val=%x)\n", port, *(uint8_t *)src);
143     return -1;
144 }
145
146
147 static int read_data_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
148     PrintDebug("IDE: Reading Data Port %x\n", port);
149     return -1;
150 }
151
152 static int write_port_std(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
153     PrintDebug("IDE: Writing Standard Port %x (val=%x)\n", port, *(uint8_t *)src);
154     return -1;
155 }
156
157
158 static int read_port_std(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
159     struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
160     struct ide_channel * channel = get_selected_channel(ide, port);
161     struct ide_drive * drive = get_selected_drive(channel);
162     
163     if (length != 1) {
164         PrintError("Invalid Read length on IDE port %x\n", port);
165         return -1;
166     }
167
168     PrintDebug("IDE: Reading Standard Port %x\n", port);
169
170
171     if ((port == PRI_ADDR_REG_PORT) ||
172         (port == SEC_ADDR_REG_PORT)) {
173         // unused, return 0xff
174         *(uint8_t *)dst = 0xff;
175         return length;
176     }
177
178
179     // if no drive is present just return 0 + reserved bits
180     if (drive->drive_type == IDE_NONE) {
181         if ((port == PRI_DRV_SEL_PORT) ||
182             (port == SEC_DRV_SEL_PORT)) {
183             *(uint8_t *)dst = 0xa0;
184         } else {
185             *(uint8_t *)dst = 0;
186         }
187
188         return length;
189     }
190
191     switch (port) {
192
193         // This is really the error register.
194         case PRI_FEATURES_PORT:
195         case SEC_FEATURES_PORT:
196             *(uint8_t *)dst = drive->error_reg.val;
197             break;
198             
199         case PRI_SECT_CNT_PORT:
200         case SEC_SECT_CNT_PORT:
201             *(uint8_t *)dst = drive->sector_count;
202             break;
203
204         case PRI_SECT_NUM_PORT:
205         case SEC_SECT_NUM_PORT:
206             *(uint8_t *)dst = drive->sector_num;
207             break;
208
209         case PRI_CYL_LOW_PORT:
210         case SEC_CYL_LOW_PORT:
211             *(uint8_t *)dst = drive->cylinder_low;
212             break;
213
214
215         case PRI_CYL_HIGH_PORT:
216         case SEC_CYL_HIGH_PORT:
217             *(uint8_t *)dst = drive->cylinder_high;
218             break;
219
220         case PRI_DRV_SEL_PORT:
221         case SEC_DRV_SEL_PORT:  // hard disk drive and head register 0x1f6
222             *(uint8_t *)dst = drive->drive_head.val;
223             break;
224
225         case PRI_CTRL_PORT:
226         case SEC_CTRL_PORT:
227         case PRI_CMD_PORT:
228         case SEC_CMD_PORT:
229             // Something about lowering interrupts here....
230             *(uint8_t *)dst = drive->status.val;
231             break;
232
233         default:
234             PrintError("Invalid Port: %x\n", port);
235             return -1;
236     }
237
238     return length;
239 }
240
241
242
243 static void init_drive(struct ide_drive * drive) {
244     drive->data_port = 0x00;
245     drive->error_reg.val = 0x01;
246     drive->sector_count = 0x01;
247     drive->sector_num = 0x01;
248     drive->cylinder = 0x0000;
249     drive->drive_head.val = 0x00;
250
251     drive->status.val = 0x00;
252     drive->command_reg = 0x00;
253
254     drive->ctrl_reg.val = 0x08;
255
256     drive->drive_type = IDE_NONE;
257
258 }
259
260 static void init_channel(struct ide_channel * channel) {
261     int i = 0;
262
263     for (i = 0; i < 2; i++) {
264         init_drive(&(channel->drives[i]));
265     }
266
267     channel->drive_sel = 0;
268 }
269
270 static void init_ide_state(struct ide_internal * ide) {
271     int i;
272
273     for (i = 0; i < 2; i++) {
274         init_channel(&(ide->channels[i]));
275     }
276 }
277
278
279
280 static int init_ide(struct vm_device * dev) {
281     struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
282
283     PrintDebug("IDE: Initializing IDE\n");
284
285     init_ide_state(ide);
286
287
288     v3_dev_hook_io(dev, PRI_CTRL_PORT, 
289                    &read_port_std, &write_port_std);
290
291     v3_dev_hook_io(dev, PRI_DATA_PORT, 
292                    &read_data_port, &write_data_port);
293     v3_dev_hook_io(dev, PRI_FEATURES_PORT, 
294                    &read_port_std, &write_port_std);
295     v3_dev_hook_io(dev, PRI_SECT_CNT_PORT, 
296                    &read_port_std, &write_port_std);
297     v3_dev_hook_io(dev, PRI_SECT_NUM_PORT, 
298                    &read_port_std, &write_port_std);
299     v3_dev_hook_io(dev, PRI_CYL_LOW_PORT, 
300                    &read_port_std, &write_port_std);
301     v3_dev_hook_io(dev, PRI_CYL_HIGH_PORT, 
302                    &read_port_std, &write_port_std);
303     v3_dev_hook_io(dev, PRI_DRV_SEL_PORT, 
304                    &read_port_std, &write_port_std);
305     v3_dev_hook_io(dev, PRI_CMD_PORT, 
306                    &read_port_std, &write_cmd_port);
307
308
309     v3_dev_hook_io(dev, SEC_CTRL_PORT, 
310                    &read_port_std, &write_port_std);
311
312     v3_dev_hook_io(dev, SEC_DATA_PORT, 
313                    &read_data_port, &write_data_port);
314     v3_dev_hook_io(dev, SEC_FEATURES_PORT, 
315                    &read_port_std, &write_port_std);
316     v3_dev_hook_io(dev, SEC_SECT_CNT_PORT, 
317                    &read_port_std, &write_port_std);
318     v3_dev_hook_io(dev, SEC_SECT_NUM_PORT, 
319                    &read_port_std, &write_port_std);
320     v3_dev_hook_io(dev, SEC_CYL_LOW_PORT, 
321                    &read_port_std, &write_port_std);
322     v3_dev_hook_io(dev, SEC_CYL_HIGH_PORT, 
323                    &read_port_std, &write_port_std);
324     v3_dev_hook_io(dev, SEC_DRV_SEL_PORT, 
325                    &read_port_std, &write_port_std);
326     v3_dev_hook_io(dev, SEC_CMD_PORT, 
327                    &read_port_std, &write_cmd_port);
328   
329   
330
331     v3_dev_hook_io(dev, SEC_ADDR_REG_PORT, 
332                    &read_port_std, &write_port_std);
333
334     v3_dev_hook_io(dev, PRI_ADDR_REG_PORT, 
335                    &read_port_std, &write_port_std);
336
337     return 0;
338 }
339
340
341 static int deinit_ide(struct vm_device * dev) {
342     // unhook io ports....
343     // deregister from PCI?
344     return 0;
345 }
346
347
348 static struct vm_device_ops dev_ops = {
349     .init = init_ide,
350     .deinit = deinit_ide,
351     .reset = NULL,
352     .start = NULL,
353     .stop = NULL,
354 };
355
356
357 struct vm_device *  v3_create_ide() {
358     struct ide_internal * ide  = (struct ide_internal *)V3_Malloc(sizeof(struct ide_internal));  
359     struct vm_device * device = v3_create_device("IDE", &dev_ops, ide);
360
361     //    ide->pci = pci;
362
363     PrintDebug("IDE: Creating IDE bus x 2\n");
364
365     return device;
366 }