1 2 /* This file implements the methods of shared memory. */ 3 4 #include <assert.h> 5 6 #include "proto.h" 7 #include "vm.h" 8 #include "region.h" 9 #include "glo.h" 10 11 /* These functions are static so as to not pollute the 12 * global namespace, and are accessed through their function 13 * pointers. 14 */ 15 16 static int shared_unreference(struct phys_region *pr); 17 static int shared_pagefault(struct vmproc *vmp, struct vir_region *region, 18 struct phys_region *ph, int write, vfs_callback_t cb, void *state, 19 int len, int *io); 20 static int shared_sanitycheck(struct phys_region *pr, const char *file, int line); 21 static int shared_writable(struct phys_region *pr); 22 static void shared_delete(struct vir_region *region); 23 static u32_t shared_regionid(struct vir_region *region); 24 static int shared_copy(struct vir_region *vr, struct vir_region *newvr); 25 static int shared_refcount(struct vir_region *vr); 26 static int shared_pt_flags(struct vir_region *vr); 27 28 struct mem_type mem_type_shared = { 29 .name = "shared memory", 30 .ev_copy = shared_copy, 31 .ev_unreference = shared_unreference, 32 .ev_pagefault = shared_pagefault, 33 .ev_sanitycheck = shared_sanitycheck, 34 .ev_delete = shared_delete, 35 .regionid = shared_regionid, 36 .refcount = shared_refcount, 37 .writable = shared_writable, 38 .pt_flags = shared_pt_flags, 39 }; 40 41 static int shared_pt_flags(struct vir_region *vr){ 42 #if defined(__arm__) 43 return ARM_VM_PTE_CACHED; 44 #else 45 return 0; 46 #endif 47 } 48 49 static int shared_unreference(struct phys_region *pr) 50 { 51 return mem_type_anon.ev_unreference(pr); 52 } 53 54 static int getsrc(struct vir_region *region, 55 struct vmproc **vmp, struct vir_region **r) 56 { 57 int srcproc; 58 59 if(region->def_memtype != &mem_type_shared) { 60 printf("shared region hasn't shared type but %s.\n", 61 region->def_memtype->name); 62 return EINVAL; 63 } 64 65 if(!region->param.shared.ep || !region->param.shared.vaddr) { 66 printf("shared region has not defined source region.\n"); 67 util_stacktrace(); 68 return EINVAL; 69 } 70 71 if(vm_isokendpt((endpoint_t) region->param.shared.ep, &srcproc) != OK) { 72 printf("VM: shared memory with missing source process.\n"); 73 util_stacktrace(); 74 return EINVAL; 75 } 76 77 *vmp = &vmproc[srcproc]; 78 79 if(!(*r=map_lookup(*vmp, region->param.shared.vaddr, NULL))) { 80 printf("VM: shared memory with missing vaddr 0x%lx.\n", 81 region->param.shared.vaddr); 82 return EINVAL; 83 } 84 85 if((*r)->def_memtype != &mem_type_anon) { 86 printf("source region hasn't anon type but %s.\n", 87 (*r)->def_memtype->name); 88 return EINVAL; 89 } 90 91 if(region->param.shared.id != (*r)->id) { 92 printf("source region has no matching id\n"); 93 return EINVAL; 94 } 95 96 return OK; 97 } 98 99 static u32_t shared_regionid(struct vir_region *vr) 100 { 101 struct vir_region *src_region; 102 struct vmproc *src_vmp; 103 104 if(getsrc(vr, &src_vmp, &src_region) != OK) 105 return 0; 106 107 return src_region->id; 108 } 109 110 static void shared_delete(struct vir_region *region) 111 { 112 struct vir_region *src_region; 113 struct vmproc *src_vmp; 114 115 if(getsrc(region, &src_vmp, &src_region) != OK) 116 return; 117 118 assert(src_region->remaps > 0); 119 src_region->remaps--; 120 } 121 122 static int shared_pagefault(struct vmproc *vmp, struct vir_region *region, 123 struct phys_region *ph, int write, vfs_callback_t cb, 124 void *state, int statelen, int *io) 125 { 126 struct vir_region *src_region; 127 struct vmproc *src_vmp; 128 struct phys_region *pr; 129 130 if(getsrc(region, &src_vmp, &src_region) != OK) { 131 return EINVAL; 132 } 133 134 assert(ph->ph->phys == MAP_NONE); 135 pb_free(ph->ph); 136 137 if(!(pr = physblock_get(src_region, ph->offset))) { 138 int r; 139 if((r=map_pf(src_vmp, src_region, ph->offset, write, 140 NULL, NULL, 0, io)) != OK) 141 return r; 142 if(!(pr = physblock_get(src_region, ph->offset))) { 143 panic("missing region after pagefault handling"); 144 } 145 } 146 147 pb_link(ph, pr->ph, ph->offset, region); 148 149 return OK; 150 } 151 152 static int shared_sanitycheck(struct phys_region *pr, const char *file, int line) 153 { 154 return OK; 155 } 156 157 static int shared_writable(struct phys_region *pr) 158 { 159 assert(pr->ph->refcount > 0); 160 return pr->ph->phys != MAP_NONE; 161 } 162 163 void shared_setsource(struct vir_region *vr, endpoint_t ep, 164 struct vir_region *src_vr) 165 { 166 struct vmproc *vmp; 167 struct vir_region *srcvr; 168 int id = src_vr->id; 169 vir_bytes vaddr = src_vr->vaddr; 170 171 assert(vr->def_memtype == &mem_type_shared); 172 173 if(!ep || !vaddr || !id) { 174 printf("VM: shared_setsource: zero ep/vaddr/id - ignoring\n"); 175 return; 176 } 177 178 vr->param.shared.ep = ep; 179 vr->param.shared.vaddr = vaddr; 180 vr->param.shared.id = id; 181 182 if(getsrc(vr, &vmp, &srcvr) != OK) 183 panic("initial getsrc failed"); 184 185 assert(srcvr == src_vr); 186 187 srcvr->remaps++; 188 } 189 190 static int shared_copy(struct vir_region *vr, struct vir_region *newvr) 191 { 192 struct vmproc *vmp; 193 struct vir_region *srcvr; 194 195 if(getsrc(vr, &vmp, &srcvr) != OK) 196 panic("copy: original getsrc failed"); 197 198 shared_setsource(newvr, vr->param.shared.ep, srcvr); 199 200 return OK; 201 } 202 203 static int shared_refcount(struct vir_region *vr) 204 { 205 return 1 + vr->remaps; 206 } 207 208