// do_shmem - create a share memory with addr, len, flags(VM_READ/M_WRITE/VM_STACK) int do_shmem(uintptr_t * addr_store, size_t len, uint32_t mmap_flags) { struct mm_struct *mm = current->mm; if (mm == NULL) { panic("kernel thread call mmap!!.\n"); } if (addr_store == NULL || len == 0) { return -E_INVAL; } int ret = -E_INVAL; uintptr_t addr; lock_mm(mm); if (!copy_from_user(mm, &addr, addr_store, sizeof(uintptr_t), 1)) { goto out_unlock; } uintptr_t start = ROUNDDOWN(addr, PGSIZE), end = ROUNDUP(addr + len, PGSIZE); addr = start, len = end - start; uint32_t vm_flags = VM_READ; if (mmap_flags & MMAP_WRITE) vm_flags |= VM_WRITE; if (mmap_flags & MMAP_STACK) vm_flags |= VM_STACK; ret = -E_NO_MEM; if (addr == 0) { if ((addr = get_unmapped_area(mm, len)) == 0) { goto out_unlock; } } struct shmem_struct *shmem; if ((shmem = shmem_create(len)) == NULL) { goto out_unlock; } if ((ret = mm_map_shmem(mm, addr, vm_flags, shmem, NULL)) != 0) { assert(shmem_ref(shmem) == 0); shmem_destroy(shmem); goto out_unlock; } copy_to_user(mm, addr_store, &addr, sizeof(uintptr_t)); out_unlock: unlock_mm(mm); return ret; }
static void check_mm_shm_swap(void) { size_t nr_free_pages_store = nr_free_pages(); size_t slab_allocated_store = slab_allocated(); int ret, i; for (i = 0; i < max_swap_offset; i ++) { assert(mem_map[i] == SWAP_UNUSED); } extern struct mm_struct *check_mm_struct; assert(check_mm_struct == NULL); struct mm_struct *mm0 = mm_create(), *mm1; assert(mm0 != NULL && list_empty(&(mm0->mmap_list))); struct Page *page = alloc_page(); assert(page != NULL); pde_t *pgdir = page2kva(page); memcpy(pgdir, boot_pgdir, PGSIZE); pgdir[PDX(VPT)] = PADDR(pgdir) | PTE_P | PTE_W; mm0->pgdir = pgdir; check_mm_struct = mm0; lcr3(PADDR(mm0->pgdir)); uint32_t vm_flags = VM_WRITE | VM_READ; uintptr_t addr0, addr1; addr0 = 0; do { if ((ret = mm_map(mm0, addr0, PTSIZE * 4, vm_flags, NULL)) == 0) { break; } addr0 += PTSIZE; } while (addr0 != 0); assert(ret == 0 && addr0 != 0 && mm0->map_count == 1); ret = mm_unmap(mm0, addr0, PTSIZE * 4); assert(ret == 0 && mm0->map_count == 0); struct shmem_struct *shmem = shmem_create(PTSIZE * 2); assert(shmem != NULL && shmem_ref(shmem) == 0); // step1: check share memory struct vma_struct *vma; addr1 = addr0 + PTSIZE * 2; ret = mm_map_shmem(mm0, addr0, vm_flags, shmem, &vma); assert(ret == 0); assert((vma->vm_flags & VM_SHARE) && vma->shmem == shmem && shmem_ref(shmem) == 1); ret = mm_map_shmem(mm0, addr1, vm_flags, shmem, &vma); assert(ret == 0); assert((vma->vm_flags & VM_SHARE) && vma->shmem == shmem && shmem_ref(shmem) == 2); // page fault for (i = 0; i < 4; i ++) { *(char *)(addr0 + i * PGSIZE) = (char)(i * i); } for (i = 0; i < 4; i ++) { assert(*(char *)(addr1 + i * PGSIZE) == (char)(i * i)); } for (i = 0; i < 4; i ++) { *(char *)(addr1 + i * PGSIZE) = (char)(- i * i); } for (i = 0; i < 4; i ++) { assert(*(char *)(addr1 + i * PGSIZE) == (char)(- i * i)); } // check swap ret = swap_out_mm(mm0, 8) + swap_out_mm(mm0, 8); assert(ret == 8 && nr_active_pages == 4 && nr_inactive_pages == 0); refill_inactive_scan(); assert(nr_active_pages == 0 && nr_inactive_pages == 4); // write & read again memset((void *)addr0, 0x77, PGSIZE); for (i = 0; i < PGSIZE; i ++) { assert(*(char *)(addr1 + i) == (char)0x77); } // check unmap ret = mm_unmap(mm0, addr1, PGSIZE * 4); assert(ret == 0); addr0 += 4 * PGSIZE, addr1 += 4 * PGSIZE; *(char *)(addr0) = (char)(0xDC); assert(*(char *)(addr1) == (char)(0xDC)); *(char *)(addr1 + PTSIZE) = (char)(0xDC); assert(*(char *)(addr0 + PTSIZE) == (char)(0xDC)); cprintf("check_mm_shm_swap: step1, share memory ok.\n"); // setup mm1 mm1 = mm_create(); assert(mm1 != NULL); page = alloc_page(); assert(page != NULL); pgdir = page2kva(page); memcpy(pgdir, boot_pgdir, PGSIZE); pgdir[PDX(VPT)] = PADDR(pgdir) | PTE_P | PTE_W; mm1->pgdir = pgdir; ret = dup_mmap(mm1, mm0); assert(ret == 0 && shmem_ref(shmem) == 4); // switch to mm1 check_mm_struct = mm1; lcr3(PADDR(mm1->pgdir)); for (i = 0; i < 4; i ++) { *(char *)(addr0 + i * PGSIZE) = (char)(0x57 + i); } for (i = 0; i < 4; i ++) { assert(*(char *)(addr1 + i * PGSIZE) == (char)(0x57 + i)); } check_mm_struct = mm0; lcr3(PADDR(mm0->pgdir)); for (i = 0; i < 4; i ++) { assert(*(char *)(addr0 + i * PGSIZE) == (char)(0x57 + i)); assert(*(char *)(addr1 + i * PGSIZE) == (char)(0x57 + i)); } swap_out_mm(mm1, 4); exit_mmap(mm1); free_page(kva2page(mm1->pgdir)); mm_destroy(mm1); assert(shmem_ref(shmem) == 2); cprintf("check_mm_shm_swap: step2, dup_mmap ok.\n"); // free memory check_mm_struct = NULL; lcr3(boot_cr3); exit_mmap(mm0); free_page(kva2page(mm0->pgdir)); mm_destroy(mm0); refill_inactive_scan(); page_launder(); for (i = 0; i < max_swap_offset; i ++) { assert(mem_map[i] == SWAP_UNUSED); } assert(nr_free_pages_store == nr_free_pages()); assert(slab_allocated_store == slab_allocated()); cprintf("check_mm_shm_swap() succeeded.\n"); }