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.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
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.
14 * Author: Jack Lange <jarusl@cs.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_dev_mgr.h>
22 #include <palacios/vmm_swapbypass.h>
23 #include <palacios/vm_guest.h>
26 #ifdef V3_CONFIG_SWAPBYPASS_TELEMETRY
27 #include <palacios/vmm_telemetry.h>
31 /* This is the first page that linux writes to the swap area */
32 /* Taken from Linux */
35 char reserved[PAGE_SIZE - 10];
36 char magic[10]; /* SWAP-SPACE or SWAPSPACE2 */
39 char bootbits[1024]; /* Space for disklabel etc. */
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];
58 uint_t unswapped_pages;
61 union swap_header * hdr;
63 #ifdef V3_CONFIG_SWAPBYPASS_TELEMETRY
71 addr_t swap_base_addr;
73 struct v3_vm_info * vm;
75 uint8_t usage_map[0]; // This must be the last structure member
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;
86 swap->usage_map[major] |= (1 << minor);
88 swap->usage_map[major] &= ~(1 << minor);
92 static inline int get_index_usage(struct swap_state * swap, uint32_t index) {
93 int major = index / 8;
94 int minor = index % 8;
96 return (swap->usage_map[major] & (1 << minor));
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);
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;
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;
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));
129 static uint64_t swap_get_capacity(void * private_data) {
130 struct swap_state * swap = (struct swap_state *)private_data;
132 PrintDebug(VM_NONE, VCORE_NONE, "SymSwap: Getting Capacity %d\n", (uint32_t)(swap->capacity));
134 return swap->capacity;
138 static struct v3_swap_ops swap_ops = {
139 .get_swap_entry = get_swap_entry,
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;
151 PrintDebug(VM_NONE, VCORE_NONE, "SymSwap: Reading %d bytes to %p from %p\n", length,
152 buf, (void *)(swap->swap_space + offset));
156 PrintError(VM_NONE, VCORE_NONE, "Swapping in length that is not a page multiple\n");
159 memcpy(buf, swap->swap_space + offset, length);
161 swap->unswapped_pages += (length / 4096);
163 if ((swap->active == 1) && (offset != 0)) {
165 // Notify the shadow paging layer
167 #ifdef V3_CONFIG_SWAPBYPASS_TELEMETRY
168 swap->pages_in += length / 4096;
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);
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;
189 PrintDebug(VM_NONE, VCORE_NONE, "SymSwap: Writing %d bytes to %p from %p\n", length,
190 (void *)(swap->swap_space + offset), buf);
194 PrintError(VM_NONE, VCORE_NONE, "Swapping out length that is not a page multiple\n");
197 if ((swap->active == 0) && (offset == 0)) {
198 // This is the swap header page
200 if (length != 4096) {
201 PrintError(VM_NONE, VCORE_NONE, "Initializing Swap space by not writing page multiples. This sucks...\n");
207 PrintDebug(VM_NONE, VCORE_NONE, "Swap Type=%d (magic=%s)\n", swap->hdr->info.type, swap->hdr->magic.magic);
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");
215 memcpy(swap->swap_space + offset, buf, length);
217 swap->swapped_pages += (length / 4096);
219 if ((swap->active == 1) && (offset != 0)) {
222 #ifdef V3_CONFIG_SWAPBYPASS_TELEMETRY
223 swap->pages_out += length / 4096;
226 for (i = 0; i < length; i += 4096) {
227 set_index_usage(swap, get_swap_index_from_offset(offset + i), 1);
235 static int swap_free(void * dev) {
240 static struct v3_dev_blk_ops blk_ops = {
243 .get_capacity = swap_get_capacity,
248 static struct v3_device_ops dev_ops = {
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);
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);
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");
276 PrintError(vm, VCORE_NONE, "Initializing sym swap without a frontend device\n");
280 PrintDebug(vm, VCORE_NONE, "Creating Swap Device (size=%dMB)\n", capacity / (1024 * 1024));
282 swap = (struct swap_state *)V3_Malloc(sizeof(struct swap_state) + ((capacity / 4096) / 8));
285 PrintError(vm, VCORE_NONE, "Cannot allocate in init\n");
291 swap->capacity = capacity;
293 swap->swapped_pages = 0;
294 swap->unswapped_pages = 0;
297 swap->hdr = (union swap_header *)swap;
299 swap->swap_base_addr = (addr_t)V3_AllocPages(swap->capacity / 4096);
301 if (!swap->swap_base_addr) {
302 PrintError(vm, VCORE_NONE, "Cannot allocate swap space\n");
307 swap->swap_space = (uint8_t *)V3_VAddr((void *)(swap->swap_base_addr));
308 memset(swap->swap_space, 0, swap->capacity);
310 memset(swap->usage_map, 0, ((swap->capacity / 4096) / 8));
312 struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, swap);
314 if (v3_attach_device(vm, dev) == -1) {
315 PrintError(vm, VCORE_NONE, "Could not attach device %s\n", dev_id);
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"));
326 #ifdef V3_CONFIG_SWAPBYPASS_TELEMETRY
327 if (vm->enable_telemetry == 1) {
328 v3_add_telemetry_cb(vm, telemetry_cb, dev);
335 device_register("SWAPBYPASS_CACHE", swap_init)