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.


various changes...
[palacios.git] / palacios / src / devices / net_hd.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_hd.h>
22 #include <devices/ide.h>
23 #include <palacios/vmm_socket.h>
24
25 #ifndef CONFIG_DEBUG_IDE
26 #undef PrintDebug
27 #define PrintDebug(fmt, args...)
28 #endif
29
30
31 #define NBD_READ_CMD 0x1
32 #define NBD_WRITE_CMD 0x2
33 #define NBD_CAPACITY_CMD 0x3
34
35 #define NBD_STATUS_OK 0x00
36 #define NBD_STATUS_ERR 0xff
37
38
39 struct hd_state {
40     uint64_t capacity; // in bytes
41
42     int socket;
43
44     uint32_t ip_addr;
45     uint16_t port;
46
47     char disk_name[32];
48
49     struct vm_device * ide;
50
51     uint_t bus;
52     uint_t drive;
53 };
54
55
56 static int send_all(int socket, char * buf, int length) {
57     int bytes_sent = 0;
58     
59     PrintDebug("Sending %d bytes\n", length - bytes_sent);
60     while (bytes_sent < length) {
61         int tmp_bytes = V3_Send(socket, buf + bytes_sent, length - bytes_sent);
62         PrintDebug("Sent %d bytes\n", tmp_bytes);
63         
64         if (tmp_bytes == 0) {
65             PrintError("Connection Closed unexpectedly\n");
66             return -1;
67         }
68         
69         bytes_sent += tmp_bytes;
70     }
71     
72     return 0;
73 }
74
75
76 static int recv_all(int socket, char * buf, int length) {
77     int bytes_read = 0;
78     
79     PrintDebug("Reading %d bytes\n", length - bytes_read);
80     while (bytes_read < length) {
81         int tmp_bytes = V3_Recv(socket, buf + bytes_read, length - bytes_read);
82         PrintDebug("Received %d bytes\n", tmp_bytes);
83         
84         if (tmp_bytes == 0) {
85             PrintError("Connection Closed unexpectedly\n");
86             return -1;
87         }
88         
89         bytes_read += tmp_bytes;
90     }
91     
92     return 0;
93 }
94
95
96 // HDs always read 512 byte blocks... ?
97 static int hd_read(uint8_t * buf, int sector_count, uint64_t lba,  void * private_data) {
98     struct vm_device * hd_dev = (struct vm_device *)private_data;
99     struct hd_state * hd = (struct hd_state *)(hd_dev->private_data);
100     int offset = lba * HD_SECTOR_SIZE;
101     int length = sector_count * HD_SECTOR_SIZE;
102     uint8_t status;
103     uint32_t ret_len = 0;
104     char nbd_cmd[4] = {0,0,0,0};
105
106     nbd_cmd[0] = NBD_READ_CMD;
107     
108     if (send_all(hd->socket, nbd_cmd, 4) == -1) {
109         PrintError("Error sending read command\n");
110         return -1;
111     }
112     
113     if (send_all(hd->socket, (char *)&offset, 8) == -1) {
114         PrintError("Error sending read offset\n");
115         return -1;
116     }
117
118     if (send_all(hd->socket, (char *)&length, 4) == -1) {
119         PrintError("Error sending read length\n");
120         return -1;
121     }
122
123     if (recv_all(hd->socket, (char *)&status, 1) == -1) {
124         PrintError("Error receiving status\n");
125         return -1;
126     }
127
128     if (status != NBD_STATUS_OK) {
129         PrintError("NBD Error....\n");
130         return -1;
131     }
132
133     PrintDebug("Reading Data Ret Length\n");
134
135     if (recv_all(hd->socket, (char *)&ret_len, 4) == -1) {
136         PrintError("Error receiving Return read length\n");
137         return -1;
138     }
139
140     if (ret_len != length) {
141         PrintError("Read length mismatch (req=%d) (result=%d)\n", length, ret_len);
142         return -1;
143     }
144
145     PrintDebug("Reading Data (%d bytes)\n", ret_len);
146
147     if (recv_all(hd->socket, (char *)buf, ret_len) == -1) {
148         PrintError("Read Data Error\n");
149         return -1;
150     }
151
152     return 0;
153 }
154
155
156 static int hd_write(uint8_t * buf, int sector_count, uint64_t lba, void * private_data) {
157     struct vm_device * hd_dev = (struct vm_device *)private_data;
158     struct hd_state * hd = (struct hd_state *)(hd_dev->private_data);
159     int offset = lba * HD_SECTOR_SIZE;
160     int length = sector_count * HD_SECTOR_SIZE;
161     uint8_t status;
162     char nbd_cmd[4] = {0,0,0,0};
163
164     nbd_cmd[0] = NBD_WRITE_CMD;
165
166     if (send_all(hd->socket, nbd_cmd, 4) == -1) {
167         PrintError("Error sending write command\n");
168         return -1;
169     }
170
171     if (send_all(hd->socket, (char *)&offset, 8) == -1) {
172         PrintError("Error sending write offset\n");
173         return -1;
174     }
175
176     if (send_all(hd->socket, (char *)&length, 4) == -1) {
177         PrintError("Error sending write length\n");
178         return -1;
179     }
180
181     PrintDebug("Writing Data (%d bytes)\n", length);
182
183     if (send_all(hd->socket, (char *)buf, length) == -1) {
184         PrintError("Write Data Error\n");
185         return -1;
186     }
187
188     if (recv_all(hd->socket, (char *)&status, 1) == -1) {
189         PrintError("Error receiving status\n");
190         return -1;
191     }
192
193     if (status != NBD_STATUS_OK) {
194         PrintError("NBD Error....\n");
195         return -1;
196     }
197
198     return 0;
199 }
200
201
202 static uint64_t hd_get_capacity(void * private_data) {
203     struct vm_device * hd_dev = (struct vm_device *)private_data;
204     struct hd_state * hd = (struct hd_state *)(hd_dev->private_data);
205
206     return hd->capacity / HD_SECTOR_SIZE;
207 }
208
209 static struct v3_hd_ops hd_ops = {
210     .read = hd_read, 
211     .write = hd_write,
212     .get_capacity = hd_get_capacity,
213 };
214
215
216
217
218
219 static int hd_free(struct vm_device * dev) {
220     return 0;
221 }
222
223 static struct v3_device_ops dev_ops = {
224     .free = hd_free,
225     .reset = NULL,
226     .start = NULL,
227     .stop = NULL,
228 };
229
230
231 static int socket_init(struct hd_state * hd) {
232     char header[64];
233     
234     PrintDebug("Intializing Net HD\n");
235
236     hd->socket = V3_Create_TCP_Socket();
237
238     PrintDebug("HD socket: %d\n", hd->socket);
239     PrintDebug("Connecting to: %s:%d\n", v3_inet_ntoa(hd->ip_addr), hd->port);
240
241     V3_Connect_To_IP(hd->socket, v3_ntohl(hd->ip_addr), hd->port);
242
243     PrintDebug("Connected to NBD server\n");
244
245     //snprintf(header, 64, "V3_NBD_1 %s\n", cd->disk_name);
246     strcpy(header, "V3_NBD_1 ");
247     strncat(header, hd->disk_name, 32);
248     strncat(header, "\n", 1);
249
250
251     if (send_all(hd->socket, header, strlen(header)) == -1) {
252         PrintError("Error connecting to Network Block Device: %s\n", hd->disk_name);
253         return -1;
254     }
255
256     // Cache Capacity
257     {
258         char nbd_cmd[4] = {0,0,0,0};
259
260         nbd_cmd[0] = NBD_CAPACITY_CMD;
261         
262         if (send_all(hd->socket, nbd_cmd, 4) == -1) {
263             PrintError("Error sending capacity command\n");
264             return -1;
265         }
266
267         if (recv_all(hd->socket, (char *)&(hd->capacity), 8) == -1) {
268             PrintError("Error Receiving Capacity\n");
269             return -1;
270         }       
271
272         PrintDebug("Capacity: %p\n", (void *)(hd->capacity));
273     }
274
275
276
277     return 0;
278 }
279
280
281 static int hd_init(struct guest_info * vm, void * cfg_data) {
282     struct hd_state * hd = (struct hd_state *)V3_Malloc(sizeof(struct hd_state));
283     struct net_hd_cfg * cfg = (struct net_hd_cfg *)cfg_data;
284
285     PrintDebug("Registering Net HD at %s:%d disk=%s\n", cfg->ip_str, cfg->port, cfg->disk_tag);
286
287     strncpy(hd->disk_name, cfg->disk_tag, sizeof(hd->disk_name));
288     hd->ip_addr = v3_inet_addr(cfg->ip_str);
289     hd->port = cfg->port;
290
291     hd->ide = v3_find_dev(vm, cfg->ide);
292
293     if (hd->ide == 0) {
294         PrintError("Could not find backend %s\n", cfg->ide);
295         return -1;
296     }
297
298     hd->bus = cfg->bus;
299     hd->drive = cfg->drive;
300         
301     struct vm_device * dev = v3_allocate_device("NET-HD", &dev_ops, hd);
302
303     if (v3_attach_device(vm, dev) == -1) {
304         PrintError("Could not attach device %s\n", "NET-HD");
305         return -1;
306     }
307
308     if (socket_init(hd) == -1) {
309         PrintError("could not initialize network connection\n");
310         return -1;
311     }
312
313
314     PrintDebug("Registering HD\n");
315
316     if (v3_ide_register_harddisk(hd->ide, hd->bus, hd->drive, "V3-NET-HD", &hd_ops, dev) == -1) {
317         return -1;
318     }
319     
320     PrintDebug("intialization done\n");
321
322     return 0;
323 }
324
325
326 device_register("NET-HD", hd_init)