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