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.


26f1d6cf35eb4c42c7ab8a0d51b409b874cc52a6
[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 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 * IDE_SECTOR_SIZE;
101     int length = sector_count * IDE_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 * IDE_SECTOR_SIZE;
160     int length = sector_count * IDE_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 / IDE_SECTOR_SIZE;
207 }
208
209 static struct v3_ide_hd_ops hd_ops = {
210     .read = hd_read, 
211     .write = hd_write,
212     .get_capacity = hd_get_capacity,
213 };
214
215
216 static int hd_init(struct vm_device * dev) {
217     struct hd_state * hd = (struct hd_state *)(dev->private_data);
218     char header[64];
219     
220     PrintDebug("Intializing Net HD\n");
221
222     hd->socket = V3_Create_TCP_Socket();
223
224     PrintDebug("HD socket: %d\n", hd->socket);
225     PrintDebug("Connecting to: %s:%d\n", v3_inet_ntoa(hd->ip_addr), hd->port);
226
227     V3_Connect_To_IP(hd->socket, v3_ntohl(hd->ip_addr), hd->port);
228
229     PrintDebug("Connected to NBD server\n");
230
231     //snprintf(header, 64, "V3_NBD_1 %s\n", cd->disk_name);
232     strcpy(header, "V3_NBD_1 ");
233     strncat(header, hd->disk_name, 32);
234     strncat(header, "\n", 1);
235
236
237     if (send_all(hd->socket, header, strlen(header)) == -1) {
238         PrintError("Error connecting to Network Block Device: %s\n", hd->disk_name);
239         return -1;
240     }
241
242     // Cache Capacity
243     {
244         char nbd_cmd[4] = {0,0,0,0};
245
246         nbd_cmd[0] = NBD_CAPACITY_CMD;
247         
248         if (send_all(hd->socket, nbd_cmd, 4) == -1) {
249             PrintError("Error sending capacity command\n");
250             return -1;
251         }
252
253         if (recv_all(hd->socket, (char *)&(hd->capacity), 8) == -1) {
254             PrintError("Error Receiving Capacity\n");
255             return -1;
256         }       
257
258         PrintDebug("Capacity: %p\n", (void *)(hd->capacity));
259     }
260
261     PrintDebug("Registering HD\n");
262
263     if (v3_ide_register_harddisk(hd->ide, hd->bus, hd->drive, "V3-NET-HD", &hd_ops, dev) == -1) {
264         return -1;
265     }
266     
267     PrintDebug("intialization done\n");
268
269     return 0;
270 }
271
272
273 static int hd_deinit(struct vm_device * dev) {
274     return 0;
275 }
276
277 static struct vm_device_ops dev_ops = {
278     .init = hd_init, 
279     .deinit = hd_deinit,
280     .reset = NULL,
281     .start = NULL,
282     .stop = NULL,
283 };
284
285 struct vm_device * v3_create_net_hd(struct vm_device * ide, 
286                                     uint_t bus, uint_t drive, 
287                                     const char * ip_str, uint16_t port, 
288                                     const char * disk_tag) {
289     struct hd_state * hd = (struct hd_state *)V3_Malloc(sizeof(struct hd_state));
290
291     PrintDebug("Registering Net HD at %s:%d disk=%s\n", ip_str, port, disk_tag);
292
293     strncpy(hd->disk_name, disk_tag, sizeof(hd->disk_name));
294     hd->ip_addr = v3_inet_addr(ip_str);
295     hd->port = port;
296
297     hd->ide = ide;
298     hd->bus = bus;
299     hd->drive = drive;
300         
301     struct vm_device * hd_dev = v3_create_device("NET-HD", &dev_ops, hd);
302
303     return hd_dev;
304 }