17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5ad23a2dbSjohansen * Common Development and Distribution License (the "License"). 6ad23a2dbSjohansen * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22ad23a2dbSjohansen * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 277c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD 317c478bd9Sstevel@tonic-gate * under license from the Regents of the University of California. 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate /* 357c478bd9Sstevel@tonic-gate * VM - segment for non-faulting loads. 367c478bd9Sstevel@tonic-gate */ 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #include <sys/types.h> 397c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 407c478bd9Sstevel@tonic-gate #include <sys/param.h> 417c478bd9Sstevel@tonic-gate #include <sys/mman.h> 427c478bd9Sstevel@tonic-gate #include <sys/errno.h> 437c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 447c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 457c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 467c478bd9Sstevel@tonic-gate #include <sys/proc.h> 477c478bd9Sstevel@tonic-gate #include <sys/conf.h> 487c478bd9Sstevel@tonic-gate #include <sys/debug.h> 497c478bd9Sstevel@tonic-gate #include <sys/archsystm.h> 507c478bd9Sstevel@tonic-gate #include <sys/lgrp.h> 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate #include <vm/page.h> 537c478bd9Sstevel@tonic-gate #include <vm/hat.h> 547c478bd9Sstevel@tonic-gate #include <vm/as.h> 557c478bd9Sstevel@tonic-gate #include <vm/seg.h> 567c478bd9Sstevel@tonic-gate #include <vm/vpage.h> 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate /* 597c478bd9Sstevel@tonic-gate * Private seg op routines. 607c478bd9Sstevel@tonic-gate */ 617c478bd9Sstevel@tonic-gate static int segnf_dup(struct seg *seg, struct seg *newseg); 627c478bd9Sstevel@tonic-gate static int segnf_unmap(struct seg *seg, caddr_t addr, size_t len); 637c478bd9Sstevel@tonic-gate static void segnf_free(struct seg *seg); 647c478bd9Sstevel@tonic-gate static faultcode_t segnf_nomap(void); 657c478bd9Sstevel@tonic-gate static int segnf_setprot(struct seg *seg, caddr_t addr, 667c478bd9Sstevel@tonic-gate size_t len, uint_t prot); 677c478bd9Sstevel@tonic-gate static int segnf_checkprot(struct seg *seg, caddr_t addr, 687c478bd9Sstevel@tonic-gate size_t len, uint_t prot); 697c478bd9Sstevel@tonic-gate static void segnf_badop(void); 707c478bd9Sstevel@tonic-gate static int segnf_nop(void); 717c478bd9Sstevel@tonic-gate static int segnf_getprot(struct seg *seg, caddr_t addr, 727c478bd9Sstevel@tonic-gate size_t len, uint_t *protv); 737c478bd9Sstevel@tonic-gate static u_offset_t segnf_getoffset(struct seg *seg, caddr_t addr); 747c478bd9Sstevel@tonic-gate static int segnf_gettype(struct seg *seg, caddr_t addr); 757c478bd9Sstevel@tonic-gate static int segnf_getvp(struct seg *seg, caddr_t addr, struct vnode **vpp); 767c478bd9Sstevel@tonic-gate static void segnf_dump(struct seg *seg); 777c478bd9Sstevel@tonic-gate static int segnf_pagelock(struct seg *seg, caddr_t addr, size_t len, 787c478bd9Sstevel@tonic-gate struct page ***ppp, enum lock_type type, enum seg_rw rw); 797c478bd9Sstevel@tonic-gate static int segnf_setpagesize(struct seg *seg, caddr_t addr, size_t len, 807c478bd9Sstevel@tonic-gate uint_t szc); 817c478bd9Sstevel@tonic-gate static int segnf_getmemid(struct seg *seg, caddr_t addr, memid_t *memidp); 827c478bd9Sstevel@tonic-gate static lgrp_mem_policy_info_t *segnf_getpolicy(struct seg *seg, 837c478bd9Sstevel@tonic-gate caddr_t addr); 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate struct seg_ops segnf_ops = { 877c478bd9Sstevel@tonic-gate segnf_dup, 887c478bd9Sstevel@tonic-gate segnf_unmap, 897c478bd9Sstevel@tonic-gate segnf_free, 907c478bd9Sstevel@tonic-gate (faultcode_t (*)(struct hat *, struct seg *, caddr_t, size_t, 917c478bd9Sstevel@tonic-gate enum fault_type, enum seg_rw)) 927c478bd9Sstevel@tonic-gate segnf_nomap, /* fault */ 937c478bd9Sstevel@tonic-gate (faultcode_t (*)(struct seg *, caddr_t)) 947c478bd9Sstevel@tonic-gate segnf_nomap, /* faulta */ 957c478bd9Sstevel@tonic-gate segnf_setprot, 967c478bd9Sstevel@tonic-gate segnf_checkprot, 977c478bd9Sstevel@tonic-gate (int (*)())segnf_badop, /* kluster */ 987c478bd9Sstevel@tonic-gate (size_t (*)(struct seg *))NULL, /* swapout */ 997c478bd9Sstevel@tonic-gate (int (*)(struct seg *, caddr_t, size_t, int, uint_t)) 1007c478bd9Sstevel@tonic-gate segnf_nop, /* sync */ 1017c478bd9Sstevel@tonic-gate (size_t (*)(struct seg *, caddr_t, size_t, char *)) 1027c478bd9Sstevel@tonic-gate segnf_nop, /* incore */ 1037c478bd9Sstevel@tonic-gate (int (*)(struct seg *, caddr_t, size_t, int, int, ulong_t *, size_t)) 1047c478bd9Sstevel@tonic-gate segnf_nop, /* lockop */ 1057c478bd9Sstevel@tonic-gate segnf_getprot, 1067c478bd9Sstevel@tonic-gate segnf_getoffset, 1077c478bd9Sstevel@tonic-gate segnf_gettype, 1087c478bd9Sstevel@tonic-gate segnf_getvp, 1097c478bd9Sstevel@tonic-gate (int (*)(struct seg *, caddr_t, size_t, uint_t)) 1107c478bd9Sstevel@tonic-gate segnf_nop, /* advise */ 1117c478bd9Sstevel@tonic-gate segnf_dump, 1127c478bd9Sstevel@tonic-gate segnf_pagelock, 1137c478bd9Sstevel@tonic-gate segnf_setpagesize, 1147c478bd9Sstevel@tonic-gate segnf_getmemid, 1157c478bd9Sstevel@tonic-gate segnf_getpolicy, 1167c478bd9Sstevel@tonic-gate }; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate /* 1197c478bd9Sstevel@tonic-gate * vnode and page for the page of zeros we use for the nf mappings. 1207c478bd9Sstevel@tonic-gate */ 1217c478bd9Sstevel@tonic-gate static kmutex_t segnf_lock; 122ad23a2dbSjohansen static struct vnode nfvp; 123ad23a2dbSjohansen static struct page **nfpp; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate #define addr_to_vcolor(addr) \ 1267c478bd9Sstevel@tonic-gate (shm_alignment) ? \ 1277c478bd9Sstevel@tonic-gate ((int)(((uintptr_t)(addr) & (shm_alignment - 1)) >> PAGESHIFT)) : 0 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate /* 1307c478bd9Sstevel@tonic-gate * We try to limit the number of Non-fault segments created. 1317c478bd9Sstevel@tonic-gate * Non fault segments are created to optimize sparc V9 code which uses 1327c478bd9Sstevel@tonic-gate * the sparc nonfaulting load ASI (ASI_PRIMARY_NOFAULT). 1337c478bd9Sstevel@tonic-gate * 1347c478bd9Sstevel@tonic-gate * There are several reasons why creating too many non-fault segments 1357c478bd9Sstevel@tonic-gate * could cause problems. 1367c478bd9Sstevel@tonic-gate * 1377c478bd9Sstevel@tonic-gate * First, excessive allocation of kernel resources for the seg 1387c478bd9Sstevel@tonic-gate * structures and the HAT data to map the zero pages. 1397c478bd9Sstevel@tonic-gate * 1407c478bd9Sstevel@tonic-gate * Secondly, creating nofault segments actually uses up user virtual 1417c478bd9Sstevel@tonic-gate * address space. This makes it unavailable for subsequent mmap(0, ...) 1427c478bd9Sstevel@tonic-gate * calls which use as_gap() to find empty va regions. Creation of too 1437c478bd9Sstevel@tonic-gate * many nofault segments could thus interfere with the ability of the 1447c478bd9Sstevel@tonic-gate * runtime linker to load a shared object. 1457c478bd9Sstevel@tonic-gate */ 1467c478bd9Sstevel@tonic-gate #define MAXSEGFORNF (10000) 1477c478bd9Sstevel@tonic-gate #define MAXNFSEARCH (5) 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate /* 1517c478bd9Sstevel@tonic-gate * Must be called from startup() 1527c478bd9Sstevel@tonic-gate */ 1537c478bd9Sstevel@tonic-gate void 1547c478bd9Sstevel@tonic-gate segnf_init() 1557c478bd9Sstevel@tonic-gate { 1567c478bd9Sstevel@tonic-gate mutex_init(&segnf_lock, NULL, MUTEX_DEFAULT, NULL); 1577c478bd9Sstevel@tonic-gate } 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate /* 1617c478bd9Sstevel@tonic-gate * Create a no-fault segment. 1627c478bd9Sstevel@tonic-gate * 1637c478bd9Sstevel@tonic-gate * The no-fault segment is not technically necessary, as the code in 1647c478bd9Sstevel@tonic-gate * nfload() in trap.c will emulate the SPARC instruction and load 1657c478bd9Sstevel@tonic-gate * a value of zero in the destination register. 1667c478bd9Sstevel@tonic-gate * 1677c478bd9Sstevel@tonic-gate * However, this code tries to put a page of zero's at the nofault address 1687c478bd9Sstevel@tonic-gate * so that subsequent non-faulting loads to the same page will not 1697c478bd9Sstevel@tonic-gate * trap with a tlb miss. 1707c478bd9Sstevel@tonic-gate * 1717c478bd9Sstevel@tonic-gate * In order to help limit the number of segments we merge adjacent nofault 1727c478bd9Sstevel@tonic-gate * segments into a single segment. If we get a large number of segments 1737c478bd9Sstevel@tonic-gate * we'll also try to delete a random other nf segment. 1747c478bd9Sstevel@tonic-gate */ 1757c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1767c478bd9Sstevel@tonic-gate int 1777c478bd9Sstevel@tonic-gate segnf_create(struct seg *seg, void *argsp) 1787c478bd9Sstevel@tonic-gate { 1797c478bd9Sstevel@tonic-gate uint_t prot; 1807c478bd9Sstevel@tonic-gate pgcnt_t vacpgs; 1817c478bd9Sstevel@tonic-gate u_offset_t off = 0; 1827c478bd9Sstevel@tonic-gate caddr_t vaddr = NULL; 1837c478bd9Sstevel@tonic-gate int i, color; 1847c478bd9Sstevel@tonic-gate struct seg *s1; 1857c478bd9Sstevel@tonic-gate struct seg *s2; 1867c478bd9Sstevel@tonic-gate size_t size; 1877c478bd9Sstevel@tonic-gate struct as *as = seg->s_as; 1887c478bd9Sstevel@tonic-gate 189*dc32d872SJosef 'Jeff' Sipek ASSERT(as && AS_WRITE_HELD(as)); 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /* 1927c478bd9Sstevel@tonic-gate * Need a page per virtual color or just 1 if no vac. 1937c478bd9Sstevel@tonic-gate */ 1947c478bd9Sstevel@tonic-gate mutex_enter(&segnf_lock); 195ad23a2dbSjohansen if (nfpp == NULL) { 1967c478bd9Sstevel@tonic-gate struct seg kseg; 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate vacpgs = 1; 1997c478bd9Sstevel@tonic-gate if (shm_alignment > PAGESIZE) { 2007c478bd9Sstevel@tonic-gate vacpgs = shm_alignment >> PAGESHIFT; 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate 203ad23a2dbSjohansen nfpp = kmem_alloc(sizeof (*nfpp) * vacpgs, KM_SLEEP); 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate kseg.s_as = &kas; 2067c478bd9Sstevel@tonic-gate for (i = 0; i < vacpgs; i++, off += PAGESIZE, 2077c478bd9Sstevel@tonic-gate vaddr += PAGESIZE) { 208ad23a2dbSjohansen nfpp[i] = page_create_va(&nfvp, off, PAGESIZE, 2097c478bd9Sstevel@tonic-gate PG_WAIT | PG_NORELOC, &kseg, vaddr); 210ad23a2dbSjohansen page_io_unlock(nfpp[i]); 211ad23a2dbSjohansen page_downgrade(nfpp[i]); 212ad23a2dbSjohansen pagezero(nfpp[i], 0, PAGESIZE); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate mutex_exit(&segnf_lock); 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate hat_map(as->a_hat, seg->s_base, seg->s_size, HAT_MAP); 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate /* 2207c478bd9Sstevel@tonic-gate * s_data can't be NULL because of ASSERTS in the common vm code. 2217c478bd9Sstevel@tonic-gate */ 2227c478bd9Sstevel@tonic-gate seg->s_ops = &segnf_ops; 2237c478bd9Sstevel@tonic-gate seg->s_data = seg; 2247c478bd9Sstevel@tonic-gate seg->s_flags |= S_PURGE; 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate mutex_enter(&as->a_contents); 2277c478bd9Sstevel@tonic-gate as->a_flags |= AS_NEEDSPURGE; 2287c478bd9Sstevel@tonic-gate mutex_exit(&as->a_contents); 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate prot = PROT_READ; 2317c478bd9Sstevel@tonic-gate color = addr_to_vcolor(seg->s_base); 2327c478bd9Sstevel@tonic-gate if (as != &kas) 2337c478bd9Sstevel@tonic-gate prot |= PROT_USER; 234ad23a2dbSjohansen hat_memload(as->a_hat, seg->s_base, nfpp[color], 2357c478bd9Sstevel@tonic-gate prot | HAT_NOFAULT, HAT_LOAD); 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate /* 2387c478bd9Sstevel@tonic-gate * At this point see if we can concatenate a segment to 2397c478bd9Sstevel@tonic-gate * a non-fault segment immediately before and/or after it. 2407c478bd9Sstevel@tonic-gate */ 2417c478bd9Sstevel@tonic-gate if ((s1 = AS_SEGPREV(as, seg)) != NULL && 2427c478bd9Sstevel@tonic-gate s1->s_ops == &segnf_ops && 2437c478bd9Sstevel@tonic-gate s1->s_base + s1->s_size == seg->s_base) { 2447c478bd9Sstevel@tonic-gate size = s1->s_size; 2457c478bd9Sstevel@tonic-gate seg_free(s1); 2467c478bd9Sstevel@tonic-gate seg->s_base -= size; 2477c478bd9Sstevel@tonic-gate seg->s_size += size; 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate if ((s2 = AS_SEGNEXT(as, seg)) != NULL && 2517c478bd9Sstevel@tonic-gate s2->s_ops == &segnf_ops && 2527c478bd9Sstevel@tonic-gate seg->s_base + seg->s_size == s2->s_base) { 2537c478bd9Sstevel@tonic-gate size = s2->s_size; 2547c478bd9Sstevel@tonic-gate seg_free(s2); 2557c478bd9Sstevel@tonic-gate seg->s_size += size; 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate /* 2597c478bd9Sstevel@tonic-gate * if we already have a lot of segments, try to delete some other 2607c478bd9Sstevel@tonic-gate * nofault segment to reduce the probability of uncontrolled segment 2617c478bd9Sstevel@tonic-gate * creation. 2627c478bd9Sstevel@tonic-gate * 2637c478bd9Sstevel@tonic-gate * the code looks around quickly (no more than MAXNFSEARCH segments 2647c478bd9Sstevel@tonic-gate * each way) for another NF segment and then deletes it. 2657c478bd9Sstevel@tonic-gate */ 2667c478bd9Sstevel@tonic-gate if (avl_numnodes(&as->a_segtree) > MAXSEGFORNF) { 2677c478bd9Sstevel@tonic-gate size = 0; 2687c478bd9Sstevel@tonic-gate s2 = NULL; 2697c478bd9Sstevel@tonic-gate s1 = AS_SEGPREV(as, seg); 2707c478bd9Sstevel@tonic-gate while (size++ < MAXNFSEARCH && s1 != NULL) { 2717c478bd9Sstevel@tonic-gate if (s1->s_ops == &segnf_ops) 2727c478bd9Sstevel@tonic-gate s2 = s1; 2737c478bd9Sstevel@tonic-gate s1 = AS_SEGPREV(s1->s_as, seg); 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate if (s2 == NULL) { 2767c478bd9Sstevel@tonic-gate s1 = AS_SEGNEXT(as, seg); 2777c478bd9Sstevel@tonic-gate while (size-- > 0 && s1 != NULL) { 2787c478bd9Sstevel@tonic-gate if (s1->s_ops == &segnf_ops) 2797c478bd9Sstevel@tonic-gate s2 = s1; 2807c478bd9Sstevel@tonic-gate s1 = AS_SEGNEXT(as, seg); 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate if (s2 != NULL) 2847c478bd9Sstevel@tonic-gate seg_unmap(s2); 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate return (0); 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate /* 2917c478bd9Sstevel@tonic-gate * Never really need "No fault" segments, so they aren't dup'd. 2927c478bd9Sstevel@tonic-gate */ 2937c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2947c478bd9Sstevel@tonic-gate static int 2957c478bd9Sstevel@tonic-gate segnf_dup(struct seg *seg, struct seg *newseg) 2967c478bd9Sstevel@tonic-gate { 2977c478bd9Sstevel@tonic-gate panic("segnf_dup"); 2987c478bd9Sstevel@tonic-gate return (0); 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate /* 3027c478bd9Sstevel@tonic-gate * Split a segment at addr for length len. 3037c478bd9Sstevel@tonic-gate */ 3047c478bd9Sstevel@tonic-gate static int 3057c478bd9Sstevel@tonic-gate segnf_unmap(struct seg *seg, caddr_t addr, size_t len) 3067c478bd9Sstevel@tonic-gate { 307*dc32d872SJosef 'Jeff' Sipek ASSERT(seg->s_as && AS_WRITE_HELD(seg->s_as)); 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate /* 3107c478bd9Sstevel@tonic-gate * Check for bad sizes. 3117c478bd9Sstevel@tonic-gate */ 3127c478bd9Sstevel@tonic-gate if (addr < seg->s_base || addr + len > seg->s_base + seg->s_size || 3137c478bd9Sstevel@tonic-gate (len & PAGEOFFSET) || ((uintptr_t)addr & PAGEOFFSET)) { 3147c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "segnf_unmap: bad unmap size"); 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate /* 3187c478bd9Sstevel@tonic-gate * Unload any hardware translations in the range to be taken out. 3197c478bd9Sstevel@tonic-gate */ 3207c478bd9Sstevel@tonic-gate hat_unload(seg->s_as->a_hat, addr, len, HAT_UNLOAD_UNMAP); 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate if (addr == seg->s_base && len == seg->s_size) { 3237c478bd9Sstevel@tonic-gate /* 3247c478bd9Sstevel@tonic-gate * Freeing entire segment. 3257c478bd9Sstevel@tonic-gate */ 3267c478bd9Sstevel@tonic-gate seg_free(seg); 3277c478bd9Sstevel@tonic-gate } else if (addr == seg->s_base) { 3287c478bd9Sstevel@tonic-gate /* 3297c478bd9Sstevel@tonic-gate * Freeing the beginning of the segment. 3307c478bd9Sstevel@tonic-gate */ 3317c478bd9Sstevel@tonic-gate seg->s_base += len; 3327c478bd9Sstevel@tonic-gate seg->s_size -= len; 3337c478bd9Sstevel@tonic-gate } else if (addr + len == seg->s_base + seg->s_size) { 3347c478bd9Sstevel@tonic-gate /* 3357c478bd9Sstevel@tonic-gate * Freeing the end of the segment. 3367c478bd9Sstevel@tonic-gate */ 3377c478bd9Sstevel@tonic-gate seg->s_size -= len; 3387c478bd9Sstevel@tonic-gate } else { 3397c478bd9Sstevel@tonic-gate /* 3407c478bd9Sstevel@tonic-gate * The section to go is in the middle of the segment, so we 3417c478bd9Sstevel@tonic-gate * have to cut it into two segments. We shrink the existing 3427c478bd9Sstevel@tonic-gate * "seg" at the low end, and create "nseg" for the high end. 3437c478bd9Sstevel@tonic-gate */ 3447c478bd9Sstevel@tonic-gate caddr_t nbase = addr + len; 3457c478bd9Sstevel@tonic-gate size_t nsize = (seg->s_base + seg->s_size) - nbase; 3467c478bd9Sstevel@tonic-gate struct seg *nseg; 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate /* 3497c478bd9Sstevel@tonic-gate * Trim down "seg" before trying to stick "nseg" into the as. 3507c478bd9Sstevel@tonic-gate */ 3517c478bd9Sstevel@tonic-gate seg->s_size = addr - seg->s_base; 3527c478bd9Sstevel@tonic-gate nseg = seg_alloc(seg->s_as, nbase, nsize); 3537c478bd9Sstevel@tonic-gate if (nseg == NULL) 3547c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "segnf_unmap: seg_alloc failed"); 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate /* 3577c478bd9Sstevel@tonic-gate * s_data can't be NULL because of ASSERTs in common VM code. 3587c478bd9Sstevel@tonic-gate */ 3597c478bd9Sstevel@tonic-gate nseg->s_ops = seg->s_ops; 3607c478bd9Sstevel@tonic-gate nseg->s_data = nseg; 3617c478bd9Sstevel@tonic-gate nseg->s_flags |= S_PURGE; 3627c478bd9Sstevel@tonic-gate mutex_enter(&seg->s_as->a_contents); 3637c478bd9Sstevel@tonic-gate seg->s_as->a_flags |= AS_NEEDSPURGE; 3647c478bd9Sstevel@tonic-gate mutex_exit(&seg->s_as->a_contents); 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate return (0); 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate /* 3717c478bd9Sstevel@tonic-gate * Free a segment. 3727c478bd9Sstevel@tonic-gate */ 3737c478bd9Sstevel@tonic-gate static void 3747c478bd9Sstevel@tonic-gate segnf_free(struct seg *seg) 3757c478bd9Sstevel@tonic-gate { 376*dc32d872SJosef 'Jeff' Sipek ASSERT(seg->s_as && AS_WRITE_HELD(seg->s_as)); 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate /* 3807c478bd9Sstevel@tonic-gate * No faults allowed on segnf. 3817c478bd9Sstevel@tonic-gate */ 3827c478bd9Sstevel@tonic-gate static faultcode_t 3837c478bd9Sstevel@tonic-gate segnf_nomap(void) 3847c478bd9Sstevel@tonic-gate { 3857c478bd9Sstevel@tonic-gate return (FC_NOMAP); 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3897c478bd9Sstevel@tonic-gate static int 3907c478bd9Sstevel@tonic-gate segnf_setprot(struct seg *seg, caddr_t addr, size_t len, uint_t prot) 3917c478bd9Sstevel@tonic-gate { 392*dc32d872SJosef 'Jeff' Sipek ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as)); 3937c478bd9Sstevel@tonic-gate return (EACCES); 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3977c478bd9Sstevel@tonic-gate static int 3987c478bd9Sstevel@tonic-gate segnf_checkprot(struct seg *seg, caddr_t addr, size_t len, uint_t prot) 3997c478bd9Sstevel@tonic-gate { 4007c478bd9Sstevel@tonic-gate uint_t sprot; 401*dc32d872SJosef 'Jeff' Sipek ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as)); 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate sprot = seg->s_as == &kas ? PROT_READ : PROT_READ|PROT_USER; 4047c478bd9Sstevel@tonic-gate return ((prot & sprot) == prot ? 0 : EACCES); 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate static void 4087c478bd9Sstevel@tonic-gate segnf_badop(void) 4097c478bd9Sstevel@tonic-gate { 4107c478bd9Sstevel@tonic-gate panic("segnf_badop"); 4117c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate static int 4157c478bd9Sstevel@tonic-gate segnf_nop(void) 4167c478bd9Sstevel@tonic-gate { 4177c478bd9Sstevel@tonic-gate return (0); 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate static int 4217c478bd9Sstevel@tonic-gate segnf_getprot(struct seg *seg, caddr_t addr, size_t len, uint_t *protv) 4227c478bd9Sstevel@tonic-gate { 4237c478bd9Sstevel@tonic-gate size_t pgno = seg_page(seg, addr + len) - seg_page(seg, addr) + 1; 4247c478bd9Sstevel@tonic-gate size_t p; 425*dc32d872SJosef 'Jeff' Sipek ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as)); 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate for (p = 0; p < pgno; ++p) 4287c478bd9Sstevel@tonic-gate protv[p] = PROT_READ; 4297c478bd9Sstevel@tonic-gate return (0); 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4337c478bd9Sstevel@tonic-gate static u_offset_t 4347c478bd9Sstevel@tonic-gate segnf_getoffset(struct seg *seg, caddr_t addr) 4357c478bd9Sstevel@tonic-gate { 436*dc32d872SJosef 'Jeff' Sipek ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as)); 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate return ((u_offset_t)0); 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4427c478bd9Sstevel@tonic-gate static int 4437c478bd9Sstevel@tonic-gate segnf_gettype(struct seg *seg, caddr_t addr) 4447c478bd9Sstevel@tonic-gate { 445*dc32d872SJosef 'Jeff' Sipek ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as)); 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate return (MAP_SHARED); 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4517c478bd9Sstevel@tonic-gate static int 4527c478bd9Sstevel@tonic-gate segnf_getvp(struct seg *seg, caddr_t addr, struct vnode **vpp) 4537c478bd9Sstevel@tonic-gate { 454*dc32d872SJosef 'Jeff' Sipek ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as)); 4557c478bd9Sstevel@tonic-gate 456ad23a2dbSjohansen *vpp = &nfvp; 4577c478bd9Sstevel@tonic-gate return (0); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate /* 4617c478bd9Sstevel@tonic-gate * segnf pages are not dumped, so we just return 4627c478bd9Sstevel@tonic-gate */ 4637c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4647c478bd9Sstevel@tonic-gate static void 4657c478bd9Sstevel@tonic-gate segnf_dump(struct seg *seg) 4667c478bd9Sstevel@tonic-gate {} 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4697c478bd9Sstevel@tonic-gate static int 4707c478bd9Sstevel@tonic-gate segnf_pagelock(struct seg *seg, caddr_t addr, size_t len, 4717c478bd9Sstevel@tonic-gate struct page ***ppp, enum lock_type type, enum seg_rw rw) 4727c478bd9Sstevel@tonic-gate { 4737c478bd9Sstevel@tonic-gate return (ENOTSUP); 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4777c478bd9Sstevel@tonic-gate static int 4787c478bd9Sstevel@tonic-gate segnf_setpagesize(struct seg *seg, caddr_t addr, size_t len, 4797c478bd9Sstevel@tonic-gate uint_t szc) 4807c478bd9Sstevel@tonic-gate { 4817c478bd9Sstevel@tonic-gate return (ENOTSUP); 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4857c478bd9Sstevel@tonic-gate static int 4867c478bd9Sstevel@tonic-gate segnf_getmemid(struct seg *seg, caddr_t addr, memid_t *memidp) 4877c478bd9Sstevel@tonic-gate { 4887c478bd9Sstevel@tonic-gate return (ENODEV); 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4927c478bd9Sstevel@tonic-gate static lgrp_mem_policy_info_t * 4937c478bd9Sstevel@tonic-gate segnf_getpolicy(struct seg *seg, caddr_t addr) 4947c478bd9Sstevel@tonic-gate { 4957c478bd9Sstevel@tonic-gate return (NULL); 4967c478bd9Sstevel@tonic-gate } 497