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.


updates to net cd
[palacios.git] / palacios / src / devices / net_cd.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/net_cd.h>
22 #include <devices/ide.h>
23 #include <palacios/vmm_socket.h>
24
25 /* #ifndef DEBUG_IDE */
26 /* #undef PrintDebug */
27 /* #define PrintDebug(fmt, args...) */
28 /* #endif */
29
30
31
32 #define NBD_READ_CMD 0x1
33 #define NBD_WRITE_CMD 0x2
34 #define NBD_CAPACITY_CMD 0x3
35
36
37
38 #define NBD_STATUS_OK 0x00
39 #define NBD_STATUS_ERR 0xff
40
41 struct cd_state {
42     uint64_t capacity; // in bytes
43
44     int socket;
45
46     uint32_t ip_addr;
47     uint16_t port;
48
49     char disk_name[32];
50
51     struct vm_device * ide;
52
53     uint_t bus;
54     uint_t drive;
55 };
56
57
58 static int send_all(int socket, char * buf, int length) {
59     int bytes_sent = 0;
60     
61     while (bytes_sent < length) {
62         PrintDebug("Sending %d bytes\n", length - bytes_sent);
63         int tmp_bytes = V3_Send(socket, buf + bytes_sent, length - bytes_sent);
64         PrintDebug("Sent %d bytes\n", tmp_bytes);
65         
66         if (tmp_bytes == 0) {
67             return -1;
68         }
69         
70         bytes_sent += tmp_bytes;
71     }
72     
73     return 0;
74 }
75
76
77 static int recv_all(int socket, char * buf, int length) {
78     int bytes_read = 0;
79     
80     while (bytes_read < length) {
81         PrintDebug("Reading %d bytes\n", length - bytes_read);
82         int tmp_bytes = V3_Recv(socket, buf + bytes_read, length - bytes_read);
83         PrintDebug("Received %d bytes\n", tmp_bytes);
84         
85         if (tmp_bytes == 0) {
86             return -1;
87         }
88         
89         bytes_read += tmp_bytes;
90     }
91     
92     return 0;
93 }
94
95 // CDs always read 2048 byte blocks... ?
96 static int cd_read(uint8_t * buf, int block_count, uint64_t lba,  void * private_data) {
97     struct vm_device * cd_dev = (struct vm_device *)private_data;
98     struct cd_state * cd = (struct cd_state *)(cd_dev->private_data);
99     uint64_t offset = lba * ATAPI_BLOCK_SIZE;
100     int length = block_count * ATAPI_BLOCK_SIZE;
101     uint8_t status;
102     uint32_t ret_len = 0;
103     char nbd_cmd[4] = {0,0,0,0};
104
105     nbd_cmd[0] = NBD_READ_CMD;
106     
107     if (send_all(cd->socket, nbd_cmd, 4) == -1) {
108         PrintError("Error sending capacity command\n");
109         return -1;
110     }
111     
112     if (send_all(cd->socket, (char *)&offset, 8) == -1) {
113         PrintError("Error sending read offset\n");
114         return -1;
115     }
116
117     if (send_all(cd->socket, (char *)&length, 4) == -1) {
118         PrintError("Error sending read length\n");
119         return -1;
120     }
121
122     if (recv_all(cd->socket, (char *)&status, 1) == -1) {
123         PrintError("Error receiving status\n");
124         return -1;
125     }
126
127     if (status != NBD_STATUS_OK) {
128         PrintError("NBD Error....\n");
129         return -1;
130     }
131
132     PrintDebug("Reading Data Ret Length\n");
133
134     if (recv_all(cd->socket, (char *)&ret_len, 4) == -1) {
135         PrintError("Error receiving Return read length\n");
136         return -1;
137     }
138
139     if (ret_len != length) {
140         PrintError("Read length mismatch (req=%d) (result=%d)\n", length, ret_len);
141         return -1;
142     }
143
144     PrintDebug("Reading Data\n");
145
146     if (recv_all(cd->socket, (char *)buf, ret_len) == -1) {
147         PrintError("Read Data Error\n");
148         return -1;
149     }
150     
151     return 0;
152 }
153
154
155 static uint32_t cd_get_capacity(void * private_data) {
156     struct vm_device * cd_dev = (struct vm_device *)private_data;
157     struct cd_state * cd = (struct cd_state *)(cd_dev->private_data);
158
159     return cd->capacity / ATAPI_BLOCK_SIZE;
160 }
161
162 static struct v3_ide_cd_ops cd_ops = {
163     .read = cd_read, 
164     .get_capacity = cd_get_capacity,
165 };
166
167
168 static int cd_init(struct vm_device * dev) {
169     struct cd_state * cd = (struct cd_state *)(dev->private_data);
170     char header[64];
171     
172     PrintDebug("Intializing Net CD\n");
173
174     cd->socket = V3_Create_TCP_Socket();
175
176     PrintDebug("CD socket: %d\n", cd->socket);
177     PrintDebug("Connecting to: %s:%d\n", v3_inet_ntoa(cd->ip_addr), cd->port);
178
179     V3_Connect_To_IP(cd->socket, v3_ntohl(cd->ip_addr), cd->port);
180
181
182     PrintDebug("Connected to NBD server\n");
183
184     //snprintf(header, 64, "V3_NBD_1 %s\n", cd->disk_name);
185     strcpy(header, "V3_NBD_1 ");
186     strncat(header, cd->disk_name, 32);
187     strncat(header, "\n", 1);
188
189
190     if (send_all(cd->socket, header, strlen(header)) == -1) {
191         PrintError("Error connecting to Network Block Device: %s\n", cd->disk_name);
192         return -1;
193     }
194
195     // Cache Capacity
196     {
197         char nbd_cmd[4] = {0,0,0,0};
198
199         nbd_cmd[0] = NBD_CAPACITY_CMD;
200         
201         if (send_all(cd->socket, nbd_cmd, 4) == -1) {
202             PrintError("Error sending capacity command\n");
203             return -1;
204         }
205
206         if (recv_all(cd->socket, (char *)&(cd->capacity), 8) == -1) {
207             PrintError("Error Receiving Capacity\n");
208             return -1;
209         }       
210
211         PrintDebug("Capacity: %p\n", (void *)(cd->capacity));
212     }
213
214
215     PrintDebug("Registering CD\n");
216
217     if (v3_ide_register_cdrom(cd->ide, cd->bus, cd->drive, "NET-CD", &cd_ops, dev) == -1) {
218         return -1;
219     }
220
221     PrintDebug("intialization done\n");
222     
223     return 0;
224 }
225
226
227 static int cd_deinit(struct vm_device * dev) {
228     return 0;
229 }
230
231 static struct vm_device_ops dev_ops = {
232     .init = cd_init, 
233     .deinit = cd_deinit,
234     .reset = NULL,
235     .start = NULL,
236     .stop = NULL,
237 };
238
239 struct vm_device * v3_create_net_cd(struct vm_device * ide, 
240                                     uint_t bus, uint_t drive, 
241                                     const char * ip_str, uint16_t port, 
242                                     const char * disk_tag) {
243     struct cd_state * cd = (struct cd_state *)V3_Malloc(sizeof(struct cd_state));
244
245     PrintDebug("Registering Net CD at %s:%d disk=%s\n", ip_str, port, disk_tag);
246
247     strncpy(cd->disk_name, disk_tag, sizeof(cd->disk_name));
248     cd->ip_addr = v3_inet_addr(ip_str);
249     cd->port = port;
250
251     cd->ide = ide;
252     cd->bus = bus;
253     cd->drive = drive;
254         
255     struct vm_device * cd_dev = v3_create_device("NET-CD", &dev_ops, cd);
256
257     return cd_dev;
258 }