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)
Jack Lange [Wed, 19 Aug 2009 18:45:12 +0000 (13:45 -0500)]
palacios/include/palacios/vmm_sym_swap.h
palacios/src/devices/sym_swap.c
palacios/src/palacios/vmm_config.c
palacios/src/palacios/vmm_shadow_paging_32.h
palacios/src/palacios/vmm_sym_swap.c

index cb0b41d..6bb3788 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <palacios/vmm_types.h>
 #include <palacios/vmm_paging.h>
+#include <palacios/vmm_hashtable.h>
 
 
 struct v3_swap_ops {
@@ -43,24 +44,31 @@ struct v3_swap_dev {
 
 struct v3_sym_swap_state {
     struct v3_swap_dev devs[256];
+
+    // shadow pointers
+    struct hashtable * shdw_ptr_ht;
 };
 
 
+
 static inline int is_swapped_pte32(pte32_t * pte) {
     return ((pte->present == 0) && (*(uint32_t *)pte != 0));
 }
 
 
 
-
 int v3_init_sym_swap(struct guest_info * info);
 
-addr_t v3_get_swapped_pg_addr(struct guest_info * info, pte32_t * pte);
-
 int v3_register_swap_disk(struct guest_info * info, int dev_index, 
                          struct v3_swap_ops * ops, void * private_data);
 
-int v3_swap_out_notify(struct guest_info * info, int pg_index, int dev_index);
+int v3_swap_in_notify(struct guest_info * info, int pg_index, int dev_index);
+
+
+addr_t v3_get_swapped_pg_addr(struct guest_info * info, pte32_t * shadow_pte, pte32_t * guest_pte);
+
+int v3_swap_flush(struct guest_info * info);
+
 
 #endif
 #endif
index d0442d7..35b46cc 100644 (file)
@@ -58,6 +58,8 @@ struct swap_state {
     uint_t unswapped_pages;
 
 
+    union swap_header * hdr;
+
     uint64_t capacity;
     uint8_t * swap_space;
     addr_t swap_base_addr;
@@ -82,7 +84,8 @@ static inline void set_index_usage(struct swap_state * swap, uint32_t index, int
 static inline int get_index_usage(struct swap_state * swap, uint32_t index) {
     int major = index / 8;
     int minor = index % 8;
-    return swap->usage_map[major] & (1 << minor);
+
+    return (swap->usage_map[major] & (1 << minor));
 }
 
 
@@ -101,10 +104,12 @@ static inline uint32_t get_swap_index_from_offset(uint32_t offset) {
 
 
 static inline void * get_swap_entry(uint32_t pg_index, void * private_data) {
-    struct swap_state * swap = (struct swap_state *)private_data;
+    struct vm_device * dev = (struct vm_device *)private_data;
+    struct swap_state * swap = (struct swap_state *)(dev->private_data);
     void * pg_addr = NULL;
+    int ret = 0;
 
-    if (get_index_usage(swap, pg_index)) {
+    if ((ret = get_index_usage(swap, pg_index))) {
        // CAREFUL: The index might be offset by 1, because the first 4K is the header
        pg_addr = (void *)(swap->swap_space + (pg_index * 4096));
     }
@@ -136,10 +141,12 @@ static int swap_read(uint8_t * buf, int sector_count, uint64_t lba,  void * priv
     uint32_t offset = lba * HD_SECTOR_SIZE;
     uint32_t length = sector_count * HD_SECTOR_SIZE;
 
-    
-    PrintDebug("SymSwap: Reading %d bytes to %p from %p\n", length,
-              buf, (void *)(swap->swap_space + offset));
-    
+  
+    /*  
+       PrintDebug("SymSwap: Reading %d bytes to %p from %p\n", length,
+       buf, (void *)(swap->swap_space + offset));
+    */
+
     if (length % 4096) {
        PrintError("Swapping in length that is not a page multiple\n");
     }
@@ -148,12 +155,15 @@ static int swap_read(uint8_t * buf, int sector_count, uint64_t lba,  void * priv
 
     swap->unswapped_pages += (length / 4096);
 
-    set_index_usage(swap, get_swap_index_from_offset(offset), 0);
-
-
-    // Notify the shadow paging layer
-
-    PrintDebug("Swapped in %d pages\n", length / 4096);
+    if ((swap->active == 1) && (offset != 0)) {
+       int i = 0;
+       // Notify the shadow paging layer
+       PrintDebug("Swapped in %d pages\n", length / 4096);
+       for (i = 0; i < length; i += 4096) {
+           set_index_usage(swap, get_swap_index_from_offset(offset + i), 0);
+           v3_swap_in_notify(dev->vm, get_swap_index_from_offset(offset + i), swap->hdr->info.type);
+       }
+    }
 
     return 0;
 }
@@ -178,7 +188,6 @@ static int swap_write(uint8_t * buf, int sector_count, uint64_t lba, void * priv
 
     if ((swap->active == 0) && (offset == 0)) {
        // This is the swap header page
-       union swap_header * hdr = (union swap_header *)buf;
 
        if (length != 4096) {
            PrintError("Initializing Swap space by not writing page multiples. This sucks...\n");
@@ -187,22 +196,26 @@ static int swap_write(uint8_t * buf, int sector_count, uint64_t lba, void * priv
 
        swap->active = 1;
 
-       PrintDebug("Swap Type=%d (magic=%s)\n", hdr->info.type, hdr->magic.magic);
+       PrintDebug("Swap Type=%d (magic=%s)\n", swap->hdr->info.type, swap->hdr->magic.magic);
 
-       if (v3_register_swap_disk(dev->vm, hdr->info.type, &swap_ops, dev) == -1) {
+       if (v3_register_swap_disk(dev->vm, swap->hdr->info.type, &swap_ops, dev) == -1) {
            PrintError("Error registering symbiotic swap disk\n");
            return -1;
        }
-
     }
 
     memcpy(swap->swap_space + offset, buf, length);
 
     swap->swapped_pages += (length / 4096);
 
-    set_index_usage(swap, get_swap_index_from_offset(offset), 1);
+    if ((swap->active == 1) && (offset != 0)) {
+       int i = 0;
+       PrintDebug("Swapped out %d pages\n", length / 4096);
 
-    PrintDebug("Swapped out %d pages\n", length / 4096);
+       for (i = 0; i < length; i += 4096) {
+           set_index_usage(swap, get_swap_index_from_offset(offset + i), 1);
+       }
+    }
 
     return 0;
 }
@@ -258,6 +271,8 @@ static int swap_init(struct guest_info * vm, void * cfg_data) {
     swap->unswapped_pages = 0;
 
     swap->active = 0;
+    swap->hdr = (union swap_header *)swap;
+
 
     swap->swap_base_addr = (addr_t)V3_AllocPages(swap->capacity / 4096);
     swap->swap_space = (uint8_t *)V3_VAddr((void *)(swap->swap_base_addr));
@@ -278,6 +293,4 @@ static int swap_init(struct guest_info * vm, void * cfg_data) {
     return 0;
 }
 
-
-
 device_register("SYM_SWAP", swap_init)
index b9c60c8..b6e5587 100644 (file)
 #include <palacios/vmm_hypercall.h>
 #include <palacios/vmm_dev_mgr.h>
 
+#ifdef CONFIG_SYMBIOTIC_SWAP
+#include <palacios/vmm_sym_swap.h>
+#endif
+
 
 #include <devices/generic.h>
 #include <devices/ide.h>
 #include <devices/video.h>
 
 
+
+
 #include <palacios/vmm_host_events.h>
 
-#define USE_GENERIC 1
 
 
 #include <palacios/vmm_socket.h>
@@ -85,6 +90,11 @@ int v3_pre_config_guest(struct guest_info * info, struct v3_vm_config * config_p
     
     v3_init_hypercall_map(info);
 
+#ifdef CONFIG_SYMBIOTIC_SWAP
+    v3_init_sym_swap(info);
+#endif
+
+
 
     // Initialize the memory map
     v3_init_shadow_map(info);
@@ -229,7 +239,7 @@ static int setup_devices(struct guest_info * info, struct v3_vm_config * config_
     v3_create_device(info, "IOAPIC", "LAPIC");
     v3_create_device(info, "VMNET", NULL);
     
-    int use_generic = USE_GENERIC;
+
 
     if (config_ptr->enable_pci == 1) {
        struct ide_cfg ide_config = {"PCI", "PIIX3"};
@@ -331,9 +341,9 @@ static int setup_devices(struct guest_info * info, struct v3_vm_config * config_
 
 
 
-    if (use_generic) {
+#ifdef CONFIG_GENERIC
        configure_generic(info, config_ptr);
-    }
+#endif
 
     // This should go last because it requires information about the Harddrives
     v3_create_device(info, "NVRAM", "IDE");
@@ -345,7 +355,7 @@ static int setup_devices(struct guest_info * info, struct v3_vm_config * config_
 
 
 
-
+#ifdef CONFIG_GENERIC
 static int configure_generic(struct guest_info * info, struct v3_vm_config * config_ptr) {
     PrintDebug("Creating Generic Device\n");
     v3_create_device(info, "GENERIC", NULL);
@@ -461,3 +471,4 @@ static int configure_generic(struct guest_info * info, struct v3_vm_config * con
     
     return 0;
 }
+#endif
index 4614232..2760400 100644 (file)
@@ -33,6 +33,10 @@ static inline int activate_shadow_pt_32(struct guest_info * info) {
     shadow_cr3->pwt = guest_cr3->pwt;
     shadow_cr3->pcd = guest_cr3->pcd;
   
+#ifdef CONFIG_SYMBIOTIC_SWAP
+    v3_swap_flush(info);
+#endif
+
     return 0;
 }
 
@@ -228,9 +232,29 @@ static int handle_pte_shadow_pagefault_32(struct guest_info * info, addr_t fault
        if (is_swapped_pte32(guest_pte)) {
            PrintError("Page fault on swapped out page (pte=%x)\n", *(uint32_t *)guest_pte);
 
-           if (inject_guest_pf(info, fault_addr, error_code) == -1) {
-               PrintError("Could not inject guest page fault\n");
-               return -1;
+           addr_t swp_pg_addr = v3_get_swapped_pg_addr(info, shadow_pte, guest_pte);
+
+           if (swp_pg_addr == 0) {
+               if (inject_guest_pf(info, fault_addr, error_code) == -1) {
+                   PrintError("Could not inject guest page fault\n");
+                   return -1;
+               }
+           } else {
+               /* 
+                *  Setup shadow paging state
+                */
+               
+               /* We need some way to check permissions.... */
+
+               shadow_pte->accessed = 1;
+               shadow_pte->writable = 1;
+               shadow_pte->write_through = 0;
+               shadow_pte->cache_disable = 0;
+               shadow_pte->global_page = 0;
+               shadow_pte->user_page = 1;
+               shadow_pte->present = 1;
+               
+               shadow_pte->page_base_addr = swp_pg_addr;
            }
        } else {
            if (inject_guest_pf(info, fault_addr, error_code) == -1) {
index 7748ee4..216894a 100644 (file)
 
 
 #include <palacios/vmm_sym_swap.h>
+#include <palacios/vmm_list.h>
+
+
+// This is a hack and 32 bit linux specific.... need to fix...
+struct swap_pte {
+    uint32_t present    : 1;
+    uint32_t dev_index  : 8;
+    uint32_t pg_index   : 23;
+};
+
+
+struct shadow_pointer {
+    uint32_t pg_index;
+    uint32_t dev_index;
+
+    pte32_t * shadow_pte;
+    
+    addr_t guest_pte;
+    
+    struct list_head node;
+};
+
+
+static uint_t swap_hash_fn(addr_t key) {
+    return v3_hash_long(key, 32);
+}
+
+
+static int swap_eq_fn(addr_t key1, addr_t key2) {
+    return (key1 == key2);
+}
 
-// this is hardcoded in linux, but we should expose it via a sym interface
-#define SWAP_DEV_SHIFT 5 
 
-int v3_init_sym_swap(struct guest_info * info) {
 
+static inline uint32_t get_pg_index(pte32_t * pte) {
+    return ((struct swap_pte *)pte)->pg_index;
+}
+
+
+static inline uint32_t get_dev_index(pte32_t * pte) {
+    return ((struct swap_pte *)pte)->dev_index;
+}
+
+
+
+int v3_init_sym_swap(struct guest_info * info) {
     memset(&(info->swap_state), 0, sizeof(struct v3_sym_swap_state));
+    info->swap_state.shdw_ptr_ht = v3_create_htable(0, swap_hash_fn, swap_eq_fn);
+
+    PrintDebug("Initialized Symbiotic Swap\n");
 
     return 0;
 }
@@ -44,17 +87,104 @@ int v3_register_swap_disk(struct guest_info * info, int dev_index,
 }
 
 
-addr_t v3_get_swapped_pg_addr(struct guest_info * info, pte32_t * pte) {
+
+
+int v3_swap_in_notify(struct guest_info * info, int pg_index, int dev_index) {
+    struct list_head * shdw_ptr_list = NULL;
     struct v3_sym_swap_state * swap_state = &(info->swap_state);
-    uint32_t dev_index = *(uint32_t *)pte & ((1 << SWAP_DEV_SHIFT) - 1);
-    uint32_t pg_index = (*(uint32_t *)pte) >> SWAP_DEV_SHIFT;
-    struct v3_swap_dev * swp_dev = &(swap_state->devs[dev_index]);
+    struct shadow_pointer * tmp_shdw_ptr = NULL;
+    struct shadow_pointer * shdw_ptr = NULL;
+    struct swap_pte guest_pte = {0, dev_index, pg_index};
 
-    return (addr_t)swp_dev->ops->get_swap_entry(pg_index, swp_dev->private_data);
+    shdw_ptr_list = (struct list_head * )v3_htable_search(swap_state->shdw_ptr_ht, *(addr_t *)&(guest_pte));
+
+    if (shdw_ptr_list == NULL) {
+       return 0;
+    }
+
+    list_for_each_entry_safe(shdw_ptr, tmp_shdw_ptr, shdw_ptr_list, node) {
+       if ((shdw_ptr->pg_index == pg_index) &&
+           (shdw_ptr->dev_index == dev_index)) {
+
+           // Trigger faults for next shadow access
+           shdw_ptr->shadow_pte->present = 0;
+
+           // Delete entry from list
+           list_del(&(shdw_ptr->node));
+           V3_Free(shdw_ptr);
+       }
+    }
+
+    return 0;
 }
 
 
 
-int v3_swap_out_notify(struct guest_info * info, int pg_index, int dev_index) {
-    return -1;
+int v3_swap_flush(struct guest_info * info) {
+    struct v3_sym_swap_state * swap_state = &(info->swap_state);
+    struct hashtable_iter * ht_iter = v3_create_htable_iter(swap_state->shdw_ptr_ht);
+
+    PrintDebug("Flushing Symbiotic Swap table\n");
+
+    while (ht_iter->entry) {
+       struct shadow_pointer * tmp_shdw_ptr = NULL;
+       struct shadow_pointer * shdw_ptr = NULL;
+       struct list_head * shdw_ptr_list = (struct list_head *)v3_htable_get_iter_value(ht_iter);
+
+       // delete all swapped entries
+       // we can leave the list_head structures and reuse them for the next round
+       
+       list_for_each_entry_safe(shdw_ptr, tmp_shdw_ptr, shdw_ptr_list, node) {
+           // Trigger faults for next shadow access
+           shdw_ptr->shadow_pte->present = 0;
+           
+           // Delete entry from list
+           list_del(&(shdw_ptr->node));
+           V3_Free(shdw_ptr);      
+       }
+
+       v3_htable_iter_advance(ht_iter);
+    }
+
+    return 0;
+}
+
+
+addr_t v3_get_swapped_pg_addr(struct guest_info * info, pte32_t * shadow_pte, pte32_t * guest_pte) {
+    struct list_head * shdw_ptr_list = NULL;
+    struct v3_sym_swap_state * swap_state = &(info->swap_state);
+    struct shadow_pointer * shdw_ptr = NULL;
+    void * swp_page_ptr = NULL;
+    int dev_index = get_dev_index(guest_pte);
+    struct v3_swap_dev * swp_dev = &(swap_state->devs[dev_index]);
+
+    if (! swp_dev->present ) {
+       return 0;
+    }
+
+    swp_page_ptr = swp_dev->ops->get_swap_entry(get_pg_index(guest_pte), swp_dev->private_data);
+
+    if (swp_page_ptr == NULL) {
+       PrintError("Swapped out page not found on swap device\n");
+       return 0;
+    }
+
+    shdw_ptr_list = (struct list_head *)v3_htable_search(swap_state->shdw_ptr_ht, (addr_t)*(uint32_t *)guest_pte);
+
+    if (shdw_ptr_list == NULL) {
+       shdw_ptr_list = (struct list_head *)V3_Malloc(sizeof(struct list_head *));
+       INIT_LIST_HEAD(shdw_ptr_list);
+    }
+
+    shdw_ptr = (struct shadow_pointer *)V3_Malloc(sizeof(struct shadow_pointer));
+
+    shdw_ptr->shadow_pte = shadow_pte;
+    shdw_ptr->guest_pte = *(uint32_t *)guest_pte;
+    shdw_ptr->pg_index = get_pg_index(guest_pte);
+    shdw_ptr->dev_index = get_dev_index(guest_pte);
+
+    // We don't check for conflicts, because it should not happen...
+    list_add(&(shdw_ptr->node), shdw_ptr_list);
+
+    return PAGE_BASE_ADDR((addr_t)V3_PAddr(swp_page_ptr));
 }