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.


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