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.


2f6d75b90ec02ab0aa0bd13675abed1ae1bf7ddc
[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     if (!swap) {
288         PrintError("Cannot allocate in init\n");
289         return -1;
290     }
291
292     swap->vm = vm;
293
294     swap->capacity = capacity;
295
296     swap->swapped_pages = 0;
297     swap->unswapped_pages = 0;
298
299     swap->active = 0;
300     swap->hdr = (union swap_header *)swap;
301
302     swap->swap_base_addr = (addr_t)V3_AllocPages(swap->capacity / 4096);
303
304     if (!swap->swap_base_addr) { 
305         PrintError("Cannot allocate swap space\n");
306         V3_Free(swap);
307         return -1;
308     }
309
310     swap->swap_space = (uint8_t *)V3_VAddr((void *)(swap->swap_base_addr));
311     memset(swap->swap_space, 0, swap->capacity);
312
313     memset(swap->usage_map, 0, ((swap->capacity / 4096) / 8));
314
315     struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, swap);
316
317     if (v3_attach_device(vm, dev) == -1) {
318         PrintError("Could not attach device %s\n", dev_id);
319         return -1;
320     }
321
322     if (v3_dev_connect_blk(vm, v3_cfg_val(frontend_cfg, "tag"), 
323                            &blk_ops, frontend_cfg, swap) == -1) {
324         PrintError("Could not connect %s to frontend %s\n", 
325                    dev_id, v3_cfg_val(frontend_cfg, "tag"));
326         return -1;
327     }
328
329 #ifdef V3_CONFIG_SWAPBYPASS_TELEMETRY
330     if (vm->enable_telemetry == 1) {
331         v3_add_telemetry_cb(vm, telemetry_cb, dev);
332     }
333 #endif
334
335     return 0;
336 }
337
338 device_register("SWAPBYPASS_CACHE", swap_init)