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.


bug fix to check for illegal memory ranges
[palacios.git] / palacios / src / devices / swapbypass_cache.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 <palacios/vmm_dev_mgr.h>
22 #include <palacios/vmm_swapbypass.h>
23 #include <palacios/vm_guest.h>
24
25
26 #ifdef V3_CONFIG_SWAPBYPASS_TELEMETRY
27 #include <palacios/vmm_telemetry.h>
28 #endif
29
30
31 /* This is the first page that linux writes to the swap area */
32 /* Taken from Linux */
33 union swap_header {
34     struct {
35         char reserved[PAGE_SIZE - 10];
36         char magic[10];                 /* SWAP-SPACE or SWAPSPACE2 */
37     } magic;
38     struct {
39         char                    bootbits[1024]; /* Space for disklabel etc. */
40         uint32_t                version;
41         uint32_t                last_page;
42         uint32_t                nr_badpages;
43         unsigned char           sws_uuid[16];
44         unsigned char           sws_volume[16];
45         uint32_t                type;           // The index into the swap_map
46         uint32_t                padding[116];
47         //              uint32_t                padding[117];
48         uint32_t                badpages[1];
49     } info;
50 };
51
52
53
54 struct swap_state {
55     int active;
56
57     uint_t swapped_pages;
58     uint_t unswapped_pages;
59
60
61     union swap_header * hdr;
62
63 #ifdef V3_CONFIG_SWAPBYPASS_TELEMETRY
64     uint32_t pages_in;
65     uint32_t pages_out;
66 #endif
67
68
69     uint64_t capacity;
70     uint8_t * swap_space;
71     addr_t swap_base_addr;
72
73     struct v3_vm_info * vm;
74
75     uint8_t usage_map[0]; // This must be the last structure member
76 };
77
78
79
80
81 static inline void set_index_usage(struct swap_state * swap, uint32_t index, int used) {
82     int major = index / 8;
83     int minor = index % 8;
84
85     if (used) {
86         swap->usage_map[major] |= (1 << minor);
87     } else {
88         swap->usage_map[major] &= ~(1 << minor);
89     }
90 }
91
92 static inline int get_index_usage(struct swap_state * swap, uint32_t index) {
93     int major = index / 8;
94     int minor = index % 8;
95
96     return (swap->usage_map[major] & (1 << minor));
97 }
98
99
100 static inline uint32_t get_swap_index_from_offset(uint32_t offset) {
101     // CAREFUL: The index might be offset by 1, because the first 4K is the header
102     return (offset / 4096);
103 }
104
105
106 /*
107   static inline uint32_t get_swap_index(uint32_t offset) {
108   // CAREFUL: The index might be offset by 1, because the first 4K is the header
109   return (swap_addr - swap->swap_space) / 4096;
110   }
111 */
112
113
114 static inline void * get_swap_entry(uint32_t pg_index, void * private_data) {
115     struct swap_state * swap = (struct swap_state *)private_data;
116     void * pg_addr = NULL;
117     // int ret = 0;
118
119     //    if ((ret = get_index_usage(swap, pg_index))) {
120     // CAREFUL: The index might be offset by 1, because the first 4K is the header
121     pg_addr = (void *)(swap->swap_space + (pg_index * 4096));
122     //    }
123
124     return pg_addr;
125 }
126
127
128
129 static uint64_t swap_get_capacity(void * private_data) {
130     struct swap_state * swap = (struct swap_state *)private_data;
131
132     PrintDebug("SymSwap: Getting Capacity %d\n", (uint32_t)(swap->capacity));
133
134     return swap->capacity;
135 }
136
137
138 static struct v3_swap_ops swap_ops = {
139     .get_swap_entry = get_swap_entry,
140 };
141
142
143
144 static int swap_read(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) {
145     struct swap_state * swap = (struct swap_state *)private_data;
146     uint32_t offset = lba;
147     uint32_t length = num_bytes;
148
149   
150       
151     PrintDebug("SymSwap: Reading %d bytes to %p from %p\n", length,
152                buf, (void *)(swap->swap_space + offset));
153         
154
155     if (length % 4096) {
156         PrintError("Swapping in length that is not a page multiple\n");
157     }
158
159     memcpy(buf, swap->swap_space + offset, length);
160
161     swap->unswapped_pages += (length / 4096);
162
163     if ((swap->active == 1) && (offset != 0)) {
164         int i = 0;
165         // Notify the shadow paging layer
166
167 #ifdef V3_CONFIG_SWAPBYPASS_TELEMETRY
168         swap->pages_in += length / 4096;
169 #endif
170
171         for (i = 0; i < length; i += 4096) {
172             set_index_usage(swap, get_swap_index_from_offset(offset + i), 0);
173             v3_swap_in_notify(swap->vm, get_swap_index_from_offset(offset + i), swap->hdr->info.type);
174         }
175     }
176
177     return 0;
178 }
179
180
181
182
183 static int swap_write(uint8_t * buf,  uint64_t lba, uint64_t num_bytes, void * private_data) {
184     struct swap_state * swap = (struct swap_state *)private_data;
185     uint32_t offset = lba;
186     uint32_t length = num_bytes;
187
188     /*
189       PrintDebug("SymSwap: Writing %d bytes to %p from %p\n", length, 
190       (void *)(swap->swap_space + offset), buf);
191     */
192
193     if (length % 4096) {
194         PrintError("Swapping out length that is not a page multiple\n");
195     }
196
197     if ((swap->active == 0) && (offset == 0)) {
198         // This is the swap header page
199
200         if (length != 4096) {
201             PrintError("Initializing Swap space by not writing page multiples. This sucks...\n");
202             return -1;
203         }
204
205         swap->active = 1;
206
207         PrintDebug("Swap Type=%d (magic=%s)\n", swap->hdr->info.type, swap->hdr->magic.magic);
208
209         if (v3_register_swap_disk(swap->vm, swap->hdr->info.type, &swap_ops, swap) == -1) {
210             PrintError("Error registering symbiotic swap disk\n");
211             return -1;
212         }
213     }
214
215     memcpy(swap->swap_space + offset, buf, length);
216
217     swap->swapped_pages += (length / 4096);
218
219     if ((swap->active == 1) && (offset != 0)) {
220         int i = 0;
221
222 #ifdef V3_CONFIG_SWAPBYPASS_TELEMETRY
223         swap->pages_out += length / 4096;
224 #endif
225
226         for (i = 0; i < length; i += 4096) {
227             set_index_usage(swap, get_swap_index_from_offset(offset + i), 1);
228         }
229     }
230
231     return 0;
232 }
233
234
235 static int swap_free(struct vm_device * dev) {
236     return -1;
237 }
238
239
240 static struct v3_dev_blk_ops blk_ops = {
241     .read = swap_read, 
242     .write = swap_write, 
243     .get_capacity = swap_get_capacity,
244 };
245
246
247
248 static struct v3_device_ops dev_ops = {
249     .free = swap_free,
250     .reset = NULL,
251     .start = NULL,
252     .stop = NULL,
253 };
254
255
256 #ifdef V3_CONFIG_SWAPBYPASS_TELEMETRY
257 static void telemetry_cb(struct v3_vm_info * vm, void * private_data, char * hdr) {
258     struct vm_device * dev = (struct vm_device *)private_data;
259     struct swap_state * swap = (struct swap_state *)(dev->private_data);
260
261     V3_Print("%sSwap Device:\n", hdr);
262     V3_Print("%s\tPages Swapped in=%d\n", hdr, swap->pages_in);
263     V3_Print("%s\tPages Swapped out=%d\n", hdr, swap->pages_out);
264
265 }
266 #endif
267
268
269
270
271
272 static int swap_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
273     struct swap_state * swap = NULL;
274     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
275     uint32_t capacity = atoi(v3_cfg_val(cfg, "size")) * 1024 * 1024;
276     char * dev_id = v3_cfg_val(cfg, "ID");
277
278     if (!frontend_cfg) {
279         PrintError("Initializing sym swap without a frontend device\n");
280         return -1;
281     }
282
283     PrintDebug("Creating Swap Device (size=%dMB)\n", capacity / (1024 * 1024));
284
285     swap = (struct swap_state *)V3_Malloc(sizeof(struct swap_state) + ((capacity / 4096) / 8));
286
287     swap->vm = vm;
288
289     swap->capacity = capacity;
290
291     swap->swapped_pages = 0;
292     swap->unswapped_pages = 0;
293
294     swap->active = 0;
295     swap->hdr = (union swap_header *)swap;
296
297     swap->swap_base_addr = (addr_t)V3_AllocPages(swap->capacity / 4096);
298     swap->swap_space = (uint8_t *)V3_VAddr((void *)(swap->swap_base_addr));
299     memset(swap->swap_space, 0, swap->capacity);
300
301     memset(swap->usage_map, 0, ((swap->capacity / 4096) / 8));
302
303     struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, swap);
304
305     if (v3_attach_device(vm, dev) == -1) {
306         PrintError("Could not attach device %s\n", dev_id);
307         return -1;
308     }
309
310     if (v3_dev_connect_blk(vm, v3_cfg_val(frontend_cfg, "tag"), 
311                            &blk_ops, frontend_cfg, swap) == -1) {
312         PrintError("Could not connect %s to frontend %s\n", 
313                    dev_id, v3_cfg_val(frontend_cfg, "tag"));
314         return -1;
315     }
316
317 #ifdef V3_CONFIG_SWAPBYPASS_TELEMETRY
318     if (vm->enable_telemetry == 1) {
319         v3_add_telemetry_cb(vm, telemetry_cb, dev);
320     }
321 #endif
322
323     return 0;
324 }
325
326 device_register("SWAPBYPASS_CACHE", swap_init)