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.


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