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.


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