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.


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