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.


integrated 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     uint8_t usage_map[0]; // This must be the last structure member
73 };
74
75
76
77
78 static inline void set_index_usage(struct swap_state * swap, uint32_t index, int used) {
79     int major = index / 8;
80     int minor = index % 8;
81
82     if (used) {
83         swap->usage_map[major] |= (1 << minor);
84     } else {
85         swap->usage_map[major] &= ~(1 << minor);
86     }
87 }
88
89 static inline int get_index_usage(struct swap_state * swap, uint32_t index) {
90     int major = index / 8;
91     int minor = index % 8;
92
93     return (swap->usage_map[major] & (1 << minor));
94 }
95
96
97 static inline uint32_t get_swap_index_from_offset(uint32_t offset) {
98     // CAREFUL: The index might be offset by 1, because the first 4K is the header
99     return (offset / 4096);
100 }
101
102
103 /*
104   static inline uint32_t get_swap_index(uint32_t offset) {
105   // CAREFUL: The index might be offset by 1, because the first 4K is the header
106   return (swap_addr - swap->swap_space) / 4096;
107   }
108 */
109
110
111 static inline void * get_swap_entry(uint32_t pg_index, void * private_data) {
112     struct vm_device * dev = (struct vm_device *)private_data;
113     struct swap_state * swap = (struct swap_state *)(dev->private_data);
114     void * pg_addr = NULL;
115     // int ret = 0;
116
117     //    if ((ret = get_index_usage(swap, pg_index))) {
118     // CAREFUL: The index might be offset by 1, because the first 4K is the header
119     pg_addr = (void *)(swap->swap_space + (pg_index * 4096));
120     //    }
121
122     return pg_addr;
123 }
124
125
126
127 static uint64_t swap_get_capacity(void * private_data) {
128     struct vm_device * dev = (struct vm_device *)private_data;
129     struct swap_state * swap = (struct swap_state *)(dev->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 vm_device * dev = (struct vm_device *)private_data;
145     struct swap_state * swap = (struct swap_state *)(dev->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 CONFIG_SYMBIOTIC_SWAP_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(dev->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 vm_device * dev = (struct vm_device *)private_data;
185     struct swap_state * swap = (struct swap_state *)(dev->private_data);
186     uint32_t offset = lba;
187     uint32_t length = num_bytes;
188
189     /*
190       PrintDebug("SymSwap: Writing %d bytes to %p from %p\n", length, 
191       (void *)(swap->swap_space + offset), buf);
192     */
193
194     if (length % 4096) {
195         PrintError("Swapping out length that is not a page multiple\n");
196     }
197
198     if ((swap->active == 0) && (offset == 0)) {
199         // This is the swap header page
200
201         if (length != 4096) {
202             PrintError("Initializing Swap space by not writing page multiples. This sucks...\n");
203             return -1;
204         }
205
206         swap->active = 1;
207
208         PrintDebug("Swap Type=%d (magic=%s)\n", swap->hdr->info.type, swap->hdr->magic.magic);
209
210         if (v3_register_swap_disk(dev->vm, swap->hdr->info.type, &swap_ops, dev) == -1) {
211             PrintError("Error registering symbiotic swap disk\n");
212             return -1;
213         }
214     }
215
216     memcpy(swap->swap_space + offset, buf, length);
217
218     swap->swapped_pages += (length / 4096);
219
220     if ((swap->active == 1) && (offset != 0)) {
221         int i = 0;
222
223 #ifdef CONFIG_SYMBIOTIC_SWAP_TELEMETRY
224         swap->pages_out += length / 4096;
225 #endif
226
227         for (i = 0; i < length; i += 4096) {
228             set_index_usage(swap, get_swap_index_from_offset(offset + i), 1);
229         }
230     }
231
232     return 0;
233 }
234
235
236 static int swap_free(struct vm_device * dev) {
237     return -1;
238 }
239
240
241 static struct v3_dev_blk_ops blk_ops = {
242     .read = swap_read, 
243     .write = swap_write, 
244     .get_capacity = swap_get_capacity,
245 };
246
247
248
249 static struct v3_device_ops dev_ops = {
250     .free = swap_free,
251     .reset = NULL,
252     .start = NULL,
253     .stop = NULL,
254 };
255
256
257 #ifdef CONFIG_SYMBIOTIC_SWAP_TELEMETRY
258 static void telemetry_cb(struct guest_info * info, void * private_data, char * hdr) {
259     struct vm_device * dev = (struct vm_device *)private_data;
260     struct swap_state * swap = (struct swap_state *)(dev->private_data);
261
262     V3_Print("%sSwap Device:\n", hdr);
263     V3_Print("%s\tPages Swapped in=%d\n", hdr, swap->pages_in);
264     V3_Print("%s\tPages Swapped out=%d\n", hdr, swap->pages_out);
265
266 }
267 #endif
268
269
270
271
272
273 static int swap_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
274     struct swap_state * swap = NULL;
275     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
276     uint32_t capacity = atoi(v3_cfg_val(cfg, "size")) * 1024 * 1024;
277     char * name = v3_cfg_val(cfg, "name");
278
279     if (!frontend_cfg) {
280         PrintError("Initializing sym swap without a frontend device\n");
281         return -1;
282     }
283
284     PrintDebug("Creating Swap Device\n");
285
286     swap = (struct swap_state *)V3_Malloc(sizeof(struct swap_state) + ((capacity / 4096) / 8));
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)