static void handler(enum exception_type type, int subtype, void *vaddr, arch_registers_state_t *regs, arch_registers_fpu_state_t *fpuregs) { debug_printf("got exception %d(%d) on %p\n", type, subtype, vaddr); assert(type == EXCEPT_PAGEFAULT); assert(subtype == PAGEFLT_WRITE); uintptr_t addr = (uintptr_t) vaddr; uintptr_t faddr = addr & ~BASE_PAGE_MASK; uintptr_t base = (uintptr_t) cow_vbuf; if (addr < base || addr >= base + BUFSIZE) { debug_printf("unexpected write pagefault on %p\n", vaddr); exit(1); } assert(cow_frame_count); debug_printf("got expected write pagefault on %p, creating copy of page\n", vaddr); // get and map copy of page size_t frame_id = (addr - base) / BASE_PAGE_SIZE; debug_printf("remapping frame %zu\n", frame_id); struct memobj *m = vregion_get_memobj(cow_vregion); assert(m); errval_t err; struct capref retframe; struct capref f = (struct capref) { .cnode = cow_frames, .slot = frame_id }; size_t retoff; struct vregion *vr; void *buf; // copy data from faulting page to new page err = vspace_map_one_frame(&buf, BASE_PAGE_SIZE, f, NULL, &vr); assert(err_is_ok(err)); memcpy(buf, (void *)faddr, BASE_PAGE_SIZE); vregion_destroy(vr); err = m->f.unfill(m, frame_id * BASE_PAGE_SIZE, &retframe, &retoff); assert(err_is_ok(err)); err = m->f.fill(m, frame_id * BASE_PAGE_SIZE, f, BASE_PAGE_SIZE); assert(err_is_ok(err)); err = m->f.pagefault(m, cow_vregion, frame_id * BASE_PAGE_SIZE, 0); assert(err_is_ok(err)); err = m->f.protect(m, cow_vregion, frame_id * BASE_PAGE_SIZE, BASE_PAGE_SIZE, VREGION_FLAGS_READ_WRITE); assert(err_is_ok(err)); }
/** * \brief Destroy the given region * * \return SYS_ERR_OK on success, error code on failure * * \bug This only works if the memobj type is memobj_one_frame. */ errval_t vregion_destroy(struct vregion *vregion) { errval_t err; struct vspace *vspace = vregion_get_vspace(vregion); if (vspace != NULL) { err = vspace_remove_vregion(vspace, vregion); if (err_is_fail(err)) { return err_push(err, LIB_ERR_VSPACE_REMOVE_REGION); } } struct memobj *memobj = vregion_get_memobj(vregion); if (memobj != NULL) { err = memobj->f.unmap_region(memobj, vregion); if (err_is_fail(err)) { return err_push(err, LIB_ERR_MEMOBJ_UNMAP_REGION); } } return SYS_ERR_OK; }