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.


remove extraneous dos linefeeds from scheduling files
[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(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "Initializing Swap space by not writing page multiples. This sucks...\n");
202             return -1;
203         }
204
205         swap->active = 1;
206
207         PrintDebug(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "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(void * 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 };
251
252
253 #ifdef V3_CONFIG_SWAPBYPASS_TELEMETRY
254 static void telemetry_cb(struct v3_vm_info * vm, void * private_data, char * hdr) {
255     struct vm_device * dev = (struct vm_device *)private_data;
256     struct swap_state * swap = (struct swap_state *)(dev->private_data);
257
258     V3_Print(vm, VCORE_NONE, "%sSwap Device:\n", hdr);
259     V3_Print(vm, VCORE_NONE, "%s\tPages Swapped in=%d\n", hdr, swap->pages_in);
260     V3_Print(vm, VCORE_NONE, "%s\tPages Swapped out=%d\n", hdr, swap->pages_out);
261
262 }
263 #endif
264
265
266
267
268
269 static int swap_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
270     struct swap_state * swap = NULL;
271     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
272     uint32_t capacity = atoi(v3_cfg_val(cfg, "size")) * 1024 * 1024;
273     char * dev_id = v3_cfg_val(cfg, "ID");
274
275     if (!frontend_cfg) {
276         PrintError(vm, VCORE_NONE, "Initializing sym swap without a frontend device\n");
277         return -1;
278     }
279
280     PrintDebug(vm, VCORE_NONE, "Creating Swap Device (size=%dMB)\n", capacity / (1024 * 1024));
281
282     swap = (struct swap_state *)V3_Malloc(sizeof(struct swap_state) + ((capacity / 4096) / 8));
283
284     if (!swap) {
285         PrintError(vm, VCORE_NONE, "Cannot allocate in init\n");
286         return -1;
287     }
288
289     swap->vm = vm;
290
291     swap->capacity = capacity;
292
293     swap->swapped_pages = 0;
294     swap->unswapped_pages = 0;
295
296     swap->active = 0;
297     swap->hdr = (union swap_header *)swap;
298
299     swap->swap_base_addr = (addr_t)V3_AllocPages(swap->capacity / 4096);
300
301     if (!swap->swap_base_addr) { 
302         PrintError(vm, VCORE_NONE, "Cannot allocate swap space\n");
303         V3_Free(swap);
304         return -1;
305     }
306
307     swap->swap_space = (uint8_t *)V3_VAddr((void *)(swap->swap_base_addr));
308     memset(swap->swap_space, 0, swap->capacity);
309
310     memset(swap->usage_map, 0, ((swap->capacity / 4096) / 8));
311
312     struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, swap);
313
314     if (v3_attach_device(vm, dev) == -1) {
315         PrintError(vm, VCORE_NONE, "Could not attach device %s\n", dev_id);
316         return -1;
317     }
318
319     if (v3_dev_connect_blk(vm, v3_cfg_val(frontend_cfg, "tag"), 
320                            &blk_ops, frontend_cfg, swap) == -1) {
321         PrintError(vm, VCORE_NONE, "Could not connect %s to frontend %s\n", 
322                    dev_id, v3_cfg_val(frontend_cfg, "tag"));
323         return -1;
324     }
325
326 #ifdef V3_CONFIG_SWAPBYPASS_TELEMETRY
327     if (vm->enable_telemetry == 1) {
328         v3_add_telemetry_cb(vm, telemetry_cb, dev);
329     }
330 #endif
331
332     return 0;
333 }
334
335 device_register("SWAPBYPASS_CACHE", swap_init)