int exec_sigcode_map(struct proc *p, struct emul *e) { vsize_t sz; sz = (vaddr_t)e->e_esigcode - (vaddr_t)e->e_sigcode; /* * If we don't have a sigobject for this emulation, create one. * * sigobject is an anonymous memory object (just like SYSV shared * memory) that we keep a permanent reference to and that we map * in all processes that need this sigcode. The creation is simple, * we create an object, add a permanent reference to it, map it in * kernel space, copy out the sigcode to it and unmap it. * Then we map it with PROT_READ|PROT_EXEC into the process just * the way sys_mmap would map it. */ if (e->e_sigobject == NULL) { vaddr_t va; int r; e->e_sigobject = uao_create(sz, 0); uao_reference(e->e_sigobject); /* permanent reference */ va = vm_map_min(kernel_map); /* hint */ if ((r = uvm_map(kernel_map, &va, round_page(sz), e->e_sigobject, 0, 0, UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, UVM_INH_SHARE, UVM_ADV_RANDOM, 0)))) { uao_detach(e->e_sigobject); return (ENOMEM); } memcpy((void *)va, e->e_sigcode, sz); uvm_unmap(kernel_map, va, va + round_page(sz)); } /* Just a hint to uvm_mmap where to put it. */ p->p_sigcode = uvm_map_hint(p, VM_PROT_READ|VM_PROT_EXECUTE); uao_reference(e->e_sigobject); if (uvm_map(&p->p_vmspace->vm_map, &p->p_sigcode, round_page(sz), e->e_sigobject, 0, 0, UVM_MAPFLAG(UVM_PROT_RX, UVM_PROT_RX, UVM_INH_SHARE, UVM_ADV_RANDOM, 0))) { uao_detach(e->e_sigobject); return (ENOMEM); } return (0); }
/* * vmcmd_map_readvn(): * handle vmcmd which specifies that a vnode should be read from. * appropriate for non-demand-paged text/data segments, i.e. impure * objects (a la OMAGIC and NMAGIC). */ int vmcmd_map_readvn(struct lwp *l, struct exec_vmcmd *cmd) { struct proc *p = l->l_proc; int error; long diff; if (cmd->ev_len == 0) return 0; diff = cmd->ev_addr - trunc_page(cmd->ev_addr); cmd->ev_addr -= diff; /* required by uvm_map */ cmd->ev_offset -= diff; cmd->ev_len += diff; error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr, round_page(cmd->ev_len), NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_FIXED|UVM_FLAG_OVERLAY|UVM_FLAG_COPYONW)); if (error) return error; return vmcmd_readvn(l, cmd); }
void uvm_km_init(vaddr_t start, vaddr_t end) { vaddr_t base = VM_MIN_KERNEL_ADDRESS; /* * next, init kernel memory objects. */ /* kernel_object: for pageable anonymous kernel memory */ uao_init(); uvm.kernel_object = uao_create(VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS, UAO_FLAG_KERNOBJ); /* * init the map and reserve already allocated kernel space * before installing. */ uvm_map_setup(&kernel_map_store, base, end, VM_MAP_PAGEABLE); kernel_map_store.pmap = pmap_kernel(); if (base != start && uvm_map(&kernel_map_store, &base, start - base, NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_NONE, UVM_ADV_RANDOM,UVM_FLAG_FIXED)) != 0) panic("uvm_km_init: could not reserve space for kernel"); /* * install! */ kernel_map = &kernel_map_store; }
int vmcmd_map_zero(struct lwp *l, struct exec_vmcmd *cmd) { struct proc *p = l->l_proc; int error; long diff; vm_prot_t prot, maxprot; diff = cmd->ev_addr - trunc_page(cmd->ev_addr); cmd->ev_addr -= diff; /* required by uvm_map */ cmd->ev_len += diff; prot = cmd->ev_prot; maxprot = UVM_PROT_ALL; #ifdef PAX_MPROTECT pax_mprotect(l, &prot, &maxprot); #endif /* PAX_MPROTECT */ error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr, round_page(cmd->ev_len), NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(prot, maxprot, UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_FIXED|UVM_FLAG_COPYONW)); if (cmd->ev_flags & VMCMD_STACK) curproc->p_vmspace->vm_issize += atop(round_page(cmd->ev_len)); return error; }
vaddr_t uvm_km_valloc_align(struct vm_map *map, vsize_t size, vsize_t align) { vaddr_t kva; UVMHIST_FUNC("uvm_km_valloc"); UVMHIST_CALLED(maphist); UVMHIST_LOG(maphist, "(map=%p, size=0x%lx)", map, size, 0,0); KASSERT(vm_map_pmap(map) == pmap_kernel()); size = round_page(size); kva = vm_map_min(map); /* hint */ /* * allocate some virtual space. will be demand filled by kernel_object. */ if (__predict_false(uvm_map(map, &kva, size, uvm.kernel_object, UVM_UNKNOWN_OFFSET, align, UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_NONE, UVM_ADV_RANDOM, 0)) != 0)) { UVMHIST_LOG(maphist, "<- done (no VM)", 0,0,0,0); return(0); } UVMHIST_LOG(maphist, "<- done (kva=0x%lx)", kva,0,0,0); return(kva); }
int exec_sigcode_map(struct process *pr, struct emul *e) { vsize_t sz; sz = (vaddr_t)e->e_esigcode - (vaddr_t)e->e_sigcode; /* * If we don't have a sigobject for this emulation, create one. * * sigobject is an anonymous memory object (just like SYSV shared * memory) that we keep a permanent reference to and that we map * in all processes that need this sigcode. The creation is simple, * we create an object, add a permanent reference to it, map it in * kernel space, copy out the sigcode to it and unmap it. * Then we map it with PROT_READ|PROT_EXEC into the process just * the way sys_mmap would map it. */ if (e->e_sigobject == NULL) { vaddr_t va; int r; e->e_sigobject = uao_create(sz, 0); uao_reference(e->e_sigobject); /* permanent reference */ if ((r = uvm_map(kernel_map, &va, round_page(sz), e->e_sigobject, 0, 0, UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE, MAP_INHERIT_SHARE, MADV_RANDOM, 0)))) { uao_detach(e->e_sigobject); return (ENOMEM); } memcpy((void *)va, e->e_sigcode, sz); uvm_unmap(kernel_map, va, va + round_page(sz)); } pr->ps_sigcode = 0; /* no hint */ uao_reference(e->e_sigobject); if (uvm_map(&pr->ps_vmspace->vm_map, &pr->ps_sigcode, round_page(sz), e->e_sigobject, 0, 0, UVM_MAPFLAG(PROT_READ | PROT_EXEC, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_INHERIT_COPY, MADV_RANDOM, UVM_FLAG_COPYONW))) { uao_detach(e->e_sigobject); return (ENOMEM); } return (0); }
int vmcmd_map_pagedvn(struct lwp *l, struct exec_vmcmd *cmd) { struct uvm_object *uobj; struct vnode *vp = cmd->ev_vp; struct proc *p = l->l_proc; int error; vm_prot_t prot, maxprot; KASSERT(vp->v_iflag & VI_TEXT); /* * map the vnode in using uvm_map. */ if (cmd->ev_len == 0) return(0); if (cmd->ev_offset & PAGE_MASK) return(EINVAL); if (cmd->ev_addr & PAGE_MASK) return(EINVAL); if (cmd->ev_len & PAGE_MASK) return(EINVAL); prot = cmd->ev_prot; maxprot = UVM_PROT_ALL; #ifdef PAX_MPROTECT pax_mprotect(l, &prot, &maxprot); #endif /* PAX_MPROTECT */ /* * check the file system's opinion about mmapping the file */ error = VOP_MMAP(vp, prot, l->l_cred); if (error) return error; if ((vp->v_vflag & VV_MAPPED) == 0) { vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); vp->v_vflag |= VV_MAPPED; VOP_UNLOCK(vp, 0); } /* * do the map, reference the object for this map entry */ uobj = &vp->v_uobj; vref(vp); error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr, cmd->ev_len, uobj, cmd->ev_offset, 0, UVM_MAPFLAG(prot, maxprot, UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_COPYONW|UVM_FLAG_FIXED)); if (error) { uobj->pgops->pgo_detach(uobj); } return error; }
int vmcmd_map_pagedvn(struct proc *p, struct exec_vmcmd *cmd) { /* * note that if you're going to map part of a process as being * paged from a vnode, that vnode had damn well better be marked as * VTEXT. that's handled in the routine which sets up the vmcmd to * call this routine. */ struct uvm_object *uobj; int error; /* * map the vnode in using uvm_map. */ if (cmd->ev_len == 0) return (0); if (cmd->ev_offset & PAGE_MASK) return (EINVAL); if (cmd->ev_addr & PAGE_MASK) return (EINVAL); if (cmd->ev_len & PAGE_MASK) return (EINVAL); /* * first, attach to the object */ uobj = uvn_attach(cmd->ev_vp, PROT_READ | PROT_EXEC); if (uobj == NULL) return (ENOMEM); /* * do the map */ error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr, cmd->ev_len, uobj, cmd->ev_offset, 0, UVM_MAPFLAG(cmd->ev_prot, PROT_MASK, MAP_INHERIT_COPY, MADV_NORMAL, UVM_FLAG_COPYONW|UVM_FLAG_FIXED)); /* * check for error */ if (error) { /* * error: detach from object */ uobj->pgops->pgo_detach(uobj); } return (error); }
int vmcmd_map_zero(struct proc *p, struct exec_vmcmd *cmd) { if (cmd->ev_len == 0) return (0); cmd->ev_addr = trunc_page(cmd->ev_addr); /* required by uvm_map */ return (uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr, round_page(cmd->ev_len), NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(cmd->ev_prot, PROT_MASK, MAP_INHERIT_COPY, MADV_NORMAL, UVM_FLAG_FIXED|UVM_FLAG_COPYONW))); }
caddr_t stackgap_init(struct proc *p) { struct process *pr = p->p_p; if (pr->ps_stackgap == 0) { if (uvm_map(&pr->ps_vmspace->vm_map, &pr->ps_stackgap, round_page(STACKGAPLEN), NULL, 0, 0, UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE, MAP_INHERIT_COPY, MADV_RANDOM, UVM_FLAG_COPYONW))) sigexit(p, SIGILL); } return (caddr_t)pr->ps_stackgap; }
void buf_mem_init(vsize_t size) { TAILQ_INIT(&buf_valist); buf_kva_start = vm_map_min(kernel_map); if (uvm_map(kernel_map, &buf_kva_start, size, NULL, UVM_UNKNOWN_OFFSET, PAGE_SIZE, UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, UVM_ADV_NORMAL, 0))) panic("bufinit: can't reserve VM for buffers"); buf_kva_end = buf_kva_start + size; buf_object = &buf_object_store; uvm_objinit(buf_object, NULL, 1); }
/* * uvm_km_suballoc: allocate a submap in the kernel map. once a submap * is allocated all references to that area of VM must go through it. this * allows the locking of VAs in kernel_map to be broken up into regions. * * => if `fixed' is true, *min specifies where the region described * by the submap must start * => if submap is non NULL we use that as the submap, otherwise we * alloc a new map */ struct vm_map * uvm_km_suballoc(struct vm_map *map, vaddr_t *min, vaddr_t *max, vsize_t size, int flags, boolean_t fixed, struct vm_map *submap) { int mapflags = UVM_FLAG_NOMERGE | (fixed ? UVM_FLAG_FIXED : 0); size = round_page(size); /* round up to pagesize */ /* * first allocate a blank spot in the parent map */ if (uvm_map(map, min, size, NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_NONE, UVM_ADV_RANDOM, mapflags)) != 0) { panic("uvm_km_suballoc: unable to allocate space in parent map"); } /* * set VM bounds (min is filled in by uvm_map) */ *max = *min + size; /* * add references to pmap and create or init the submap */ pmap_reference(vm_map_pmap(map)); if (submap == NULL) { submap = uvm_map_create(vm_map_pmap(map), *min, *max, flags); if (submap == NULL) panic("uvm_km_suballoc: unable to create submap"); } else { uvm_map_setup(submap, *min, *max, flags); submap->pmap = vm_map_pmap(map); } /* * now let uvm_map_submap plug in it... */ if (uvm_map_submap(map, *min, *max, submap) != 0) panic("uvm_km_suballoc: submap allocation failed"); return(submap); }
int vmcmd_map_zero(struct proc *p, struct exec_vmcmd *cmd) { int error; if (cmd->ev_len == 0) return (0); cmd->ev_addr = trunc_page(cmd->ev_addr); /* required by uvm_map */ error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr, round_page(cmd->ev_len), NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(cmd->ev_prot, UVM_PROT_ALL, UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_FIXED|UVM_FLAG_COPYONW)); if (error) return error; return (0); }
int vmcmd_map_readvn(struct proc *p, struct exec_vmcmd *cmd) { int error; vm_prot_t prot; if (cmd->ev_len == 0) return (0); prot = cmd->ev_prot; cmd->ev_addr = trunc_page(cmd->ev_addr); /* required by uvm_map */ error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr, round_page(cmd->ev_len), NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(prot | UVM_PROT_WRITE, UVM_PROT_ALL, UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_FIXED|UVM_FLAG_OVERLAY|UVM_FLAG_COPYONW)); if (error) return (error); error = vn_rdwr(UIO_READ, cmd->ev_vp, (caddr_t)cmd->ev_addr, cmd->ev_len, cmd->ev_offset, UIO_USERSPACE, IO_UNIT, p->p_ucred, NULL, p); if (error) return (error); if (cmd->ev_prot != (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE)) { /* * we had to map in the area at PROT_ALL so that vn_rdwr() * could write to it. however, the caller seems to want * it mapped read-only, so now we are going to have to call * uvm_map_protect() to fix up the protection. ICK. */ return (uvm_map_protect(&p->p_vmspace->vm_map, trunc_page(cmd->ev_addr), round_page(cmd->ev_addr + cmd->ev_len), prot, FALSE)); } return (0); }
vaddr_t uvm_km_valloc_prefer_wait(struct vm_map *map, vsize_t size, voff_t prefer) { vaddr_t kva; UVMHIST_FUNC("uvm_km_valloc_prefer_wait"); UVMHIST_CALLED(maphist); UVMHIST_LOG(maphist, "(map=%p, size=0x%lx)", map, size, 0,0); KASSERT(vm_map_pmap(map) == pmap_kernel()); size = round_page(size); if (size > vm_map_max(map) - vm_map_min(map)) return(0); while (1) { kva = vm_map_min(map); /* hint */ /* * allocate some virtual space. will be demand filled * by kernel_object. */ if (__predict_true(uvm_map(map, &kva, size, uvm.kernel_object, prefer, 0, UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_NONE, UVM_ADV_RANDOM, 0)) == 0)) { UVMHIST_LOG(maphist,"<- done (kva=0x%lx)", kva,0,0,0); return(kva); } /* * failed. sleep for a while (on map) */ UVMHIST_LOG(maphist,"<<<sleeping>>>",0,0,0,0); tsleep((caddr_t)map, PVM, "vallocwait", 0); } /*NOTREACHED*/ }
/* * Machine-dependent startup code */ void cpu_startup() { unsigned i; caddr_t v; long sz; int base, residual; #ifdef DEBUG extern int pmapdebug; int opmapdebug = pmapdebug; #endif vaddr_t minaddr, maxaddr; vsize_t size; extern struct user *proc0paddr; #ifdef DEBUG pmapdebug = 0; #endif proc0.p_addr = proc0paddr; /* * Good {morning,afternoon,evening,night}. */ printf(version); /*identifycpu();*/ printf("total memory = %d\n", physmem * PAGE_SIZE); /* * Find out how much space we need, allocate it, * and then give everything true virtual addresses. */ sz = (long)allocsys(NULL); if ((v = (caddr_t)uvm_km_alloc(kernel_map, round_page(sz))) == 0) panic("startup: no room for %lx bytes of tables", sz); if (allocsys(v) - v != sz) panic("startup: table size inconsistency"); /* * allocate virtual and physical memory for the buffers. */ size = MAXBSIZE * nbuf; /* # bytes for buffers */ /* allocate VM for buffers... area is not managed by VM system */ if (uvm_map(kernel_map, (vaddr_t *) &buffers, round_page(size), NULL, UVM_UNKNOWN_OFFSET, UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, UVM_ADV_NORMAL, 0)) != 0) panic("cpu_startup: cannot allocate VM for buffers"); minaddr = (vaddr_t) buffers; if ((bufpages / nbuf) >= btoc(MAXBSIZE)) { bufpages = btoc(MAXBSIZE) * nbuf; /* do not overallocate RAM */ } base = bufpages / nbuf; residual = bufpages % nbuf; /* now allocate RAM for buffers */ for (i = 0 ; i < nbuf ; i++) { vaddr_t curbuf; vsize_t curbufsize; struct vm_page *pg; /* * each buffer has MAXBSIZE bytes of VM space allocated. of * that MAXBSIZE space we allocate and map (base+1) pages * for the first "residual" buffers, and then we allocate * "base" pages for the rest. */ curbuf = (vaddr_t) buffers + (i * MAXBSIZE); curbufsize = NBPG * ((i < residual) ? (base+1) : base); while (curbufsize) { pg = uvm_pagealloc(NULL, 0, NULL, 0); if (pg == NULL) panic("cpu_startup: " "not enough RAM for buffer cache"); pmap_enter(kernel_map->pmap, curbuf, VM_PAGE_TO_PHYS(pg), VM_PROT_READ|VM_PROT_WRITE, VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED); curbuf += PAGE_SIZE; curbufsize -= PAGE_SIZE; } } pmap_update(); /* * Allocate a submap for exec arguments. This map effectively * limits the number of processes exec'ing at any time. */ exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 16*NCARGS, VM_MAP_PAGEABLE, FALSE, NULL); /* * Finally, allocate mbuf cluster submap. */ mb_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, VM_MBUF_SIZE, VM_MAP_INTRSAFE, FALSE, NULL); #ifdef DEBUG pmapdebug = opmapdebug; #endif printf("avail memory = %ld\n", (long)uvmexp.free * PAGE_SIZE); printf("using %d buffers containing %ld of memory\n", nbuf, (long)bufpages * PAGE_SIZE); /* * Set up buffers, so they can be used to read disk labels. */ bufinit(); #if 0 pmap_redzone(); #endif }
vaddr_t uvm_km_kmemalloc(struct vm_map *map, struct uvm_object *obj, vsize_t size, int flags) { vaddr_t kva, loopva; voff_t offset; struct vm_page *pg; int mapflags; UVMHIST_FUNC("uvm_km_kmemalloc"); UVMHIST_CALLED(maphist); UVMHIST_LOG(maphist," (map=%p, obj=%p, size=0x%lx, flags=%d)", map, obj, size, flags); KASSERT(vm_map_pmap(map) == pmap_kernel()); /* * we cannot yet make pmap_enter() not sleep * and thus demand that we are called with NOWAIT in that case */ KASSERT(!((flags & UVM_KMF_NOWAIT) && obj)); /* * setup for call */ mapflags = flags & UVM_KMF_NOWAIT? UVM_FLAG_NOWAIT : 0; mapflags |= flags & UVM_KMF_TRYLOCK; size = round_page(size); kva = vm_map_min(map); /* hint */ /* * allocate some virtual space */ if (__predict_false(uvm_map(map, &kva, size, obj, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, UVM_INH_NONE, UVM_ADV_RANDOM, mapflags)) != 0)) { UVMHIST_LOG(maphist, "<- done (no VM)",0,0,0,0); return(0); } /* * if all we wanted was VA, return now */ if (flags & UVM_KMF_VALLOC) { UVMHIST_LOG(maphist,"<- done valloc (kva=0x%lx)", kva,0,0,0); return(kva); } /* * recover object offset from virtual address */ if (obj != NULL) offset = kva - vm_map_min(kernel_map); else offset = 0; UVMHIST_LOG(maphist, " kva=0x%lx, offset=0x%lx", kva, offset,0,0); /* * now allocate and map in the memory... note that we are the only ones * whom should ever get a handle on this area of VM. */ loopva = kva; while (loopva != kva + size) { pg = uvm_pagealloc(obj, offset, NULL, 0); if (pg) { atomic_clearbits_int(&pg->pg_flags, PG_BUSY); UVM_PAGE_OWN(pg, NULL); } if (__predict_false(pg == NULL)) { if ((flags & UVM_KMF_NOWAIT) || ((flags & UVM_KMF_CANFAIL) && uvmexp.swpgonly == uvmexp.swpages)) { /* free everything! */ uvm_unmap(map, kva, kva + size); return (0); } else { uvm_wait("km_getwait2"); /* sleep here */ continue; } } /* * map it in: note that we call pmap_enter with the map and * object unlocked in case we are kmem_map. * * pager mappings that must not sleep here will incidently * be installed using pmap_kenter_pa() and thus not sleep! */ if (obj == NULL) { pmap_kenter_pa(loopva, VM_PAGE_TO_PHYS(pg), UVM_PROT_RW); } else { pmap_enter(map->pmap, loopva, VM_PAGE_TO_PHYS(pg), UVM_PROT_RW, PMAP_WIRED | VM_PROT_READ | VM_PROT_WRITE); } loopva += PAGE_SIZE; offset += PAGE_SIZE; } pmap_update(pmap_kernel()); UVMHIST_LOG(maphist,"<- done (kva=0x%lx)", kva,0,0,0); return(kva); }
/* * cpu_startup: allocate memory for variable-sized tables, * initialize cpu, and do autoconfiguration. * * This is called early in init_main.c:main(), after the * kernel memory allocator is ready for use, but before * the creation of processes 1,2, and mountroot, etc. */ void cpu_startup() { caddr_t v; int sz, i; vsize_t size; int base, residual; vaddr_t minaddr, maxaddr; char pbuf[9]; /* * Initialize message buffer (for kernel printf). * This is put in physical pages four through seven * so it will always be in the same place after a * reboot. (physical pages 0-3 are reserved by the PROM * for its vector table and other stuff.) * Its mapping was prepared in pmap_bootstrap(). * Also, offset some to avoid PROM scribbles. */ v = (caddr_t) (NBPG * 4); msgbufaddr = (caddr_t)(v + MSGBUFOFF); initmsgbuf(msgbufaddr, MSGBUFSIZE); #ifdef DDB { extern int end[]; extern char *esym; ddb_init(end[0], end + 1, (int*)esym); } #endif /* DDB */ /* * Good {morning,afternoon,evening,night}. */ printf(version); identifycpu(); fputype = FPU_NONE; #ifdef FPU_EMULATE printf("fpu: emulator\n"); #else printf("fpu: no math support\n"); #endif format_bytes(pbuf, sizeof(pbuf), ctob(physmem)); printf("total memory = %s\n", pbuf); /* * XXX fredette - we force a small number of buffers * to help me debug this on my low-memory machine. * this should go away at some point, allowing the * normal automatic buffer-sizing to happen. */ bufpages = 37; /* * Get scratch page for dumpsys(). */ if ((dumppage = uvm_km_alloc(kernel_map, NBPG)) == 0) panic("startup: alloc dumppage"); /* * Find out how much space we need, allocate it, * and then give everything true virtual addresses. */ sz = (int)allocsys(NULL, NULL); if ((v = (caddr_t)uvm_km_alloc(kernel_map, round_page(sz))) == 0) panic("startup: no room for tables"); if (allocsys(v, NULL) - v != sz) panic("startup: table size inconsistency"); /* * Now allocate buffers proper. They are different than the above * in that they usually occupy more virtual memory than physical. */ size = MAXBSIZE * nbuf; if (uvm_map(kernel_map, (vaddr_t *) &buffers, round_page(size), NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, UVM_ADV_NORMAL, 0)) != 0) panic("startup: cannot allocate VM for buffers"); minaddr = (vaddr_t)buffers; if ((bufpages / nbuf) >= btoc(MAXBSIZE)) { /* don't want to alloc more physical mem than needed */ bufpages = btoc(MAXBSIZE) * nbuf; } base = bufpages / nbuf; residual = bufpages % nbuf; for (i = 0; i < nbuf; i++) { vsize_t curbufsize; vaddr_t curbuf; struct vm_page *pg; /* * Each buffer has MAXBSIZE bytes of VM space allocated. Of * that MAXBSIZE space, we allocate and map (base+1) pages * for the first "residual" buffers, and then we allocate * "base" pages for the rest. */ curbuf = (vaddr_t) buffers + (i * MAXBSIZE); curbufsize = NBPG * ((i < residual) ? (base+1) : base); while (curbufsize) { pg = uvm_pagealloc(NULL, 0, NULL, 0); if (pg == NULL) panic("cpu_startup: not enough memory for " "buffer cache"); pmap_kenter_pa(curbuf, VM_PAGE_TO_PHYS(pg), VM_PROT_READ|VM_PROT_WRITE); curbuf += PAGE_SIZE; curbufsize -= PAGE_SIZE; } } pmap_update(pmap_kernel()); /* * Allocate a submap for exec arguments. This map effectively * limits the number of processes exec'ing at any time. */ exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, NCARGS, VM_MAP_PAGEABLE, FALSE, NULL); /* * We don't use a submap for physio, and use a separate map * for DVMA allocations. Our vmapbuf just maps pages into * the kernel map (any kernel mapping is OK) and then the * device drivers clone the kernel mappings into DVMA space. */ /* * Finally, allocate mbuf cluster submap. */ mb_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, nmbclusters * mclbytes, VM_MAP_INTRSAFE, FALSE, NULL); format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free)); printf("avail memory = %s\n", pbuf); format_bytes(pbuf, sizeof(pbuf), bufpages * NBPG); printf("using %d buffers containing %s of memory\n", nbuf, pbuf); /* * Allocate a virtual page (for use by /dev/mem) * This page is handed to pmap_enter() therefore * it has to be in the normal kernel VA range. */ vmmap = uvm_km_valloc_wait(kernel_map, NBPG); /* * Allocate dma map for devices on the bus. */ dvmamap = extent_create("dvmamap", DVMA_MAP_BASE, DVMA_MAP_BASE + DVMA_MAP_AVAIL, M_DEVBUF, 0, 0, EX_NOWAIT); if (dvmamap == NULL) panic("unable to allocate DVMA map"); /* * Set up CPU-specific registers, cache, etc. */ initcpu(); /* * Set up buffers, so they can be used to read disk labels. */ bufinit(); }
/* * Machine-dependent startup code */ void cpu_startup() { caddr_t v, v2; unsigned long sz; int x; vaddr_t minaddr, maxaddr; vsize_t size; char buf[160]; /* about 2 line */ char pbuf[9]; /* * Initialize error message buffer (et end of core). */ msgbuf_vaddr = uvm_km_valloc(kernel_map, x86_64_round_page(MSGBUFSIZE)); if (msgbuf_vaddr == 0) panic("failed to valloc msgbuf_vaddr"); /* msgbuf_paddr was init'd in pmap */ for (x = 0; x < btoc(MSGBUFSIZE); x++) pmap_kenter_pa((vaddr_t)msgbuf_vaddr + x * PAGE_SIZE, msgbuf_paddr + x * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE); initmsgbuf((caddr_t)msgbuf_vaddr, round_page(MSGBUFSIZE)); printf("%s", version); printf("cpu0: %s", cpu_model); if (cpu_tsc_freq != 0) printf(", %ld.%02ld MHz", (cpu_tsc_freq + 4999) / 1000000, ((cpu_tsc_freq + 4999) / 10000) % 100); printf("\n"); if ((cpu_feature & CPUID_MASK1) != 0) { bitmask_snprintf(cpu_feature, CPUID_FLAGS1, buf, sizeof(buf)); printf("cpu0: features %s\n", buf); } if ((cpu_feature & CPUID_MASK2) != 0) { bitmask_snprintf(cpu_feature, CPUID_FLAGS2, buf, sizeof(buf)); printf("cpu0: features %s\n", buf); } if (cpuid_level >= 3 && ((cpu_feature & CPUID_PN) != 0)) { printf("cpu0: serial number %04X-%04X-%04X-%04X-%04X-%04X\n", cpu_serial[0] / 65536, cpu_serial[0] % 65536, cpu_serial[1] / 65536, cpu_serial[1] % 65536, cpu_serial[2] / 65536, cpu_serial[2] % 65536); } format_bytes(pbuf, sizeof(pbuf), ptoa(physmem)); printf("total memory = %s\n", pbuf); /* * Find out how much space we need, allocate it, * and then give everything true virtual addresses. */ sz = (unsigned long)allocsys(NULL, NULL); if ((v = (caddr_t)uvm_km_zalloc(kernel_map, round_page(sz))) == 0) panic("startup: no room for tables"); v2 = allocsys(v, NULL); if ((v2 - v) != sz) panic("startup: table size inconsistency"); /* * Allocate virtual address space for the buffers. The area * is not managed by the VM system. */ size = MAXBSIZE * nbuf; if (uvm_map(kernel_map, (vaddr_t *) &buffers, round_page(size), NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, UVM_ADV_NORMAL, 0)) != 0) panic("cpu_startup: cannot allocate VM for buffers"); minaddr = (vaddr_t)buffers; if ((bufpages / nbuf) >= btoc(MAXBSIZE)) { /* don't want to alloc more physical mem than needed */ bufpages = btoc(MAXBSIZE) * nbuf; } /* * XXX We defer allocation of physical pages for buffers until * XXX after autoconfiguration has run. We must do this because * XXX on system with large amounts of memory or with large * XXX user-configured buffer caches, the buffer cache will eat * XXX up all of the lower 16M of RAM. This prevents ISA DMA * XXX maps from allocating bounce pages. * * XXX Note that nothing can use buffer cache buffers until after * XXX autoconfiguration completes!! * * XXX This is a hack, and needs to be replaced with a better * XXX solution! [email protected], December 6, 1997 */ /* * Allocate a submap for exec arguments. This map effectively * limits the number of processes exec'ing at any time. */ exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 16*NCARGS, VM_MAP_PAGEABLE, FALSE, NULL); /* * Allocate a submap for physio */ phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, VM_PHYS_SIZE, 0, FALSE, NULL); /* * Finally, allocate mbuf cluster submap. */ mb_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, nmbclusters * mclbytes, VM_MAP_INTRSAFE, FALSE, NULL); /* * XXX Buffer cache pages haven't yet been allocated, so * XXX we need to account for those pages when printing * XXX the amount of free memory. */ format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free - bufpages)); printf("avail memory = %s\n", pbuf); format_bytes(pbuf, sizeof(pbuf), bufpages * PAGE_SIZE); printf("using %d buffers containing %s of memory\n", nbuf, pbuf); /* Safe for i/o port / memory space allocation to use malloc now. */ x86_64_bus_space_mallocok(); }
void ubc_init(void) { struct ubc_map *umap; vaddr_t va; int i; /* * init ubc_object. * alloc and init ubc_map's. * init inactive queues. * alloc and init hashtable. * map in ubc_object. */ simple_lock_init(&ubc_object.uobj.vmobjlock); ubc_object.uobj.pgops = &ubc_pager; TAILQ_INIT(&ubc_object.uobj.memq); ubc_object.uobj.uo_npages = 0; ubc_object.uobj.uo_refs = UVM_OBJ_KERN; ubc_object.umap = malloc(ubc_nwins * sizeof(struct ubc_map), M_TEMP, M_NOWAIT); bzero(ubc_object.umap, ubc_nwins * sizeof(struct ubc_map)); va = (vaddr_t)1L; #ifdef PMAP_PREFER PMAP_PREFER(0, &va); if (va < UBC_WINSIZE) { va = UBC_WINSIZE; } ubc_nqueues = va / UBC_WINSIZE; if (ubc_nqueues != 1) { ubc_release_unmap = TRUE; } #endif ubc_object.inactive = malloc(UBC_NQUEUES * sizeof(struct ubc_inactive_head), M_TEMP, M_NOWAIT); for (i = 0; i < UBC_NQUEUES; i++) { TAILQ_INIT(&ubc_object.inactive[i]); } for (i = 0; i < ubc_nwins; i++) { umap = &ubc_object.umap[i]; TAILQ_INSERT_TAIL(&ubc_object.inactive[i & (UBC_NQUEUES - 1)], umap, inactive); } ubc_object.hash = hashinit(ubc_nwins, HASH_LIST, M_TEMP, M_NOWAIT, &ubc_object.hashmask); for (i = 0; i <= ubc_object.hashmask; i++) { LIST_INIT(&ubc_object.hash[i]); } if (uvm_map(kernel_map, (vaddr_t *)&ubc_object.kva, ubc_nwins * UBC_WINSIZE, &ubc_object.uobj, 0, (vsize_t)va, UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_NONE, UVM_ADV_RANDOM, UVM_FLAG_NOMERGE)) != KERN_SUCCESS) { panic("ubc_init: failed to map ubc_object\n"); } UVMHIST_INIT(ubchist, 300); }
void ubc_init(void) { struct ubc_map *umap; vaddr_t va; int i; /* * Make sure ubc_winshift is sane. */ if (ubc_winshift < PAGE_SHIFT) ubc_winshift = PAGE_SHIFT; /* * init ubc_object. * alloc and init ubc_map's. * init inactive queues. * alloc and init hashtable. * map in ubc_object. */ simple_lock_init(&ubc_object.uobj.vmobjlock); ubc_object.uobj.pgops = &ubc_pager; TAILQ_INIT(&ubc_object.uobj.memq); ubc_object.uobj.uo_npages = 0; ubc_object.uobj.uo_refs = UVM_OBJ_KERN; ubc_object.umap = malloc(ubc_nwins * sizeof(struct ubc_map), M_TEMP, M_NOWAIT); if (ubc_object.umap == NULL) panic("ubc_init: failed to allocate ubc_map"); memset(ubc_object.umap, 0, ubc_nwins * sizeof(struct ubc_map)); if (ubc_winshift < PAGE_SHIFT) { ubc_winshift = PAGE_SHIFT; } va = (vaddr_t)1L; #ifdef PMAP_PREFER PMAP_PREFER(0, &va); ubc_nqueues = va >> ubc_winshift; if (ubc_nqueues == 0) { ubc_nqueues = 1; } if (ubc_nqueues != 1) { ubc_release_unmap = TRUE; } #endif ubc_winsize = 1 << ubc_winshift; ubc_object.inactive = malloc(UBC_NQUEUES * sizeof(struct ubc_inactive_head), M_TEMP, M_NOWAIT); if (ubc_object.inactive == NULL) panic("ubc_init: failed to allocate inactive queue heads"); for (i = 0; i < UBC_NQUEUES; i++) { TAILQ_INIT(&ubc_object.inactive[i]); } for (i = 0; i < ubc_nwins; i++) { umap = &ubc_object.umap[i]; TAILQ_INSERT_TAIL(&ubc_object.inactive[i & (UBC_NQUEUES - 1)], umap, inactive); } ubc_object.hash = hashinit(ubc_nwins, HASH_LIST, M_TEMP, M_NOWAIT, &ubc_object.hashmask); for (i = 0; i <= ubc_object.hashmask; i++) { LIST_INIT(&ubc_object.hash[i]); } if (uvm_map(kernel_map, (vaddr_t *)&ubc_object.kva, ubc_nwins << ubc_winshift, &ubc_object.uobj, 0, (vsize_t)va, UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_NONE, UVM_ADV_RANDOM, UVM_FLAG_NOMERGE)) != 0) { panic("ubc_init: failed to map ubc_object\n"); } UVMHIST_INIT(ubchist, 300); }
/* * Allocate memory for variable-sized tables, */ void cpu_startup() { unsigned i; int base, residual; vaddr_t minaddr, maxaddr; vsize_t size; char pbuf[9]; /* * Good {morning,afternoon,evening,night}. */ printf(version); printf("%s\n", cpu_model); format_bytes(pbuf, sizeof(pbuf), ctob(physmem)); printf("%s memory", pbuf); /* * Allocate virtual address space for file I/O buffers. * Note they are different than the array of headers, 'buf', * and usually occupy more virtual memory than physical. */ size = MAXBSIZE * nbuf; if (uvm_map(kernel_map, (vaddr_t *)&buffers, round_page(size), NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, UVM_ADV_NORMAL, 0)) != 0) panic("startup: cannot allocate VM for buffers"); minaddr = (vaddr_t)buffers; base = bufpages / nbuf; residual = bufpages % nbuf; for (i = 0; i < nbuf; i++) { vsize_t curbufsize; vaddr_t curbuf; struct vm_page *pg; /* * Each buffer has MAXBSIZE bytes of VM space allocated. Of * that MAXBSIZE space, we allocate and map (base+1) pages * for the first "residual" buffers, and then we allocate * "base" pages for the rest. */ curbuf = (vaddr_t) buffers + (i * MAXBSIZE); curbufsize = NBPG * ((i < residual) ? (base + 1) : base); while (curbufsize) { pg = uvm_pagealloc(NULL, 0, NULL, 0); if (pg == NULL) panic("cpu_startup: not enough memory for " "buffer cache"); pmap_kenter_pa(curbuf, VM_PAGE_TO_PHYS(pg), VM_PROT_READ|VM_PROT_WRITE); curbuf += PAGE_SIZE; curbufsize -= PAGE_SIZE; } } pmap_update(pmap_kernel()); /* * Allocate a submap for exec arguments. This map effectively * limits the number of processes exec'ing at any time. */ exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL); /* * Allocate a submap for physio. */ phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, VM_PHYS_SIZE, 0, FALSE, NULL); /* * (No need to allocate an mbuf cluster submap. Mbuf clusters * are allocated via the pool allocator, and we use KSEG to * map those pages.) */ format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free)); printf(", %s free", pbuf); format_bytes(pbuf, sizeof(pbuf), bufpages * NBPG); printf(", %s in %d buffers\n", pbuf, nbuf); /* * Set up buffers, so they can be used to read disk labels. */ bufinit(); }
void cpu_startup() { caddr_t v; int sz, i; vsize_t size; int base, residual; vaddr_t minaddr, maxaddr, uarea_pages; /* * Initialize error message buffer (at end of core). * avail_end was pre-decremented in luna88k_bootstrap() to compensate. */ for (i = 0; i < btoc(MSGBUFSIZE); i++) pmap_kenter_pa((paddr_t)msgbufp + i * NBPG, avail_end + i * NBPG, VM_PROT_READ | VM_PROT_WRITE); pmap_update(pmap_kernel()); initmsgbuf((caddr_t)msgbufp, round_page(MSGBUFSIZE)); /* Determine the machine type from FUSE ROM data */ get_fuse_rom_data(); if (strncmp(fuse_rom_data, "MNAME=LUNA88K+", 14) == 0) { machtype = LUNA_88K2; } /* Determine the 'auto-boot' device from NVRAM data */ get_nvram_data(); get_autoboot_device(); /* * Good {morning,afternoon,evening,night}. */ printf(version); identifycpu(); printf("real mem = %d\n", ctob(physmem)); /* * Check front DIP switch setting */ printf("dipsw = 0x%x\n", dipswitch); /* Check DIP switch 1 - 1 */ if ((0x8000 & dipswitch) == 0) { boothowto |= RB_SINGLE; } /* Check DIP switch 1 - 3 */ if ((0x2000 & dipswitch) == 0) { boothowto |= RB_ASKNAME; } /* Check DIP switch 1 - 4 */ if ((0x1000 & dipswitch) == 0) { boothowto |= RB_CONFIG; } /* * Check frame buffer depth. */ switch (hwplanebits) { case 0: /* No frame buffer */ case 1: case 4: case 8: break; default: printf("unexpected frame buffer depth = %d\n", hwplanebits); hwplanebits = 0; break; } #if 0 /* just for test */ /* * Get boot arguments */ { char buf[256]; char **p = (volatile char **)0x00001120; strncpy(buf, *p, 256); if (buf[255] != '\0') buf[255] = '\0'; printf("boot arg: (0x%x) %s\n", *p, buf); } #endif /* * Find out how much space we need, allocate it, * and then give everything true virtual addresses. */ sz = (int)allocsys((caddr_t)0); if ((v = (caddr_t)uvm_km_zalloc(kernel_map, round_page(sz))) == 0) panic("startup: no room for tables"); if (allocsys(v) - v != sz) panic("startup: table size inconsistency"); /* * Grab UADDR virtual address */ uarea_pages = UADDR; uvm_map(kernel_map, (vaddr_t *)&uarea_pages, USPACE, NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, UVM_ADV_NORMAL, 0)); if (uarea_pages != UADDR) panic("uarea_pages %lx: UADDR not free", uarea_pages); /* * Grab the OBIO space that we hardwired in pmap_bootstrap */ obiova = OBIO_START; uvm_map(kernel_map, (vaddr_t *)&obiova, OBIO_SIZE, NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, UVM_ADV_NORMAL, 0)); if (obiova != OBIO_START) panic("obiova %lx: OBIO not free", obiova); /* * Now allocate buffers proper. They are different than the above * in that they usually occupy more virtual memory than physical. */ size = MAXBSIZE * nbuf; if (uvm_map(kernel_map, (vaddr_t *) &buffers, round_page(size), NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, UVM_ADV_NORMAL, 0))) panic("cpu_startup: cannot allocate VM for buffers"); minaddr = (vaddr_t)buffers; if ((bufpages / nbuf) >= btoc(MAXBSIZE)) { /* don't want to alloc more physical mem than needed */ bufpages = btoc(MAXBSIZE) * nbuf; } base = bufpages / nbuf; residual = bufpages % nbuf; for (i = 0; i < nbuf; i++) { vsize_t curbufsize; vaddr_t curbuf; struct vm_page *pg; /* * Each buffer has MAXBSIZE bytes of VM space allocated. Of * that MAXBSIZE space, we allocate and map (base+1) pages * for the first "residual" buffers, and then we allocate * "base" pages for the rest. */ curbuf = (vaddr_t)buffers + (i * MAXBSIZE); curbufsize = PAGE_SIZE * ((i < residual) ? (base+1) : base); while (curbufsize) { pg = uvm_pagealloc(NULL, 0, NULL, 0); if (pg == NULL) panic("cpu_startup: not enough memory for " "buffer cache"); pmap_kenter_pa(curbuf, VM_PAGE_TO_PHYS(pg), VM_PROT_READ | VM_PROT_WRITE); curbuf += PAGE_SIZE; curbufsize -= PAGE_SIZE; } } pmap_update(pmap_kernel()); /* * Allocate a submap for exec arguments. This map effectively * limits the number of processes exec'ing at any time. */ exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL); /* * Allocate map for physio. */ phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, VM_PHYS_SIZE, 0, FALSE, NULL); printf("avail mem = %ld (%d pages)\n", ptoa(uvmexp.free), uvmexp.free); printf("using %d buffers containing %d bytes of memory\n", nbuf, bufpages * PAGE_SIZE); /* * Set up buffers, so they can be used to read disk labels. */ bufinit(); /* * Initialize the autovectored interrupt list. */ isrinit(); /* * Configure the system. */ if (boothowto & RB_CONFIG) { #ifdef BOOT_CONFIG user_config(); #else printf("kernel does not support -c; continuing..\n"); #endif } /* * Say hello to the world on LCD. */ greeting(); }
void uvm_init(void) { vaddr_t kvm_start, kvm_end; /* * step 0: ensure that the hardware set the page size */ if (uvmexp.pagesize == 0) { panic("uvm_init: page size not set"); } /* * step 1: set up stats. */ averunnable.fscale = FSCALE; /* * step 2: init the page sub-system. this includes allocating the * vm_page structures, and setting up all the page queues (and * locks). available memory will be put in the "free" queue. * kvm_start and kvm_end will be set to the area of kernel virtual * memory which is available for general use. */ uvm_page_init(&kvm_start, &kvm_end); /* * step 3: init the map sub-system. allocates the static pool of * vm_map_entry structures that are used for "special" kernel maps * (e.g. kernel_map, kmem_map, etc...). */ uvm_map_init(); /* * step 4: setup the kernel's virtual memory data structures. this * includes setting up the kernel_map/kernel_object and the kmem_map/ * kmem_object. */ uvm_km_init(kvm_start, kvm_end); /* * step 5: init the pmap module. the pmap module is free to allocate * memory for its private use (e.g. pvlists). */ pmap_init(); /* * step 6: init the kernel memory allocator. after this call the * kernel memory allocator (malloc) can be used. */ kmeminit(); /* * step 6.5: init the dma allocator, which is backed by pools. */ dma_alloc_init(); /* * step 7: init all pagers and the pager_map. */ uvm_pager_init(); /* * step 8: init anonymous memory system */ amap_init(); /* init amap module */ /* * step 9: init uvm_km_page allocator memory. */ uvm_km_page_init(); /* * the VM system is now up! now that malloc is up we can * enable paging of kernel objects. */ uao_create(VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS, UAO_FLAG_KERNSWAP); /* * reserve some unmapped space for malloc/pool use after free usage */ #ifdef DEADBEEF0 kvm_start = trunc_page(DEADBEEF0) - PAGE_SIZE; if (uvm_map(kernel_map, &kvm_start, 3 * PAGE_SIZE, NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, UVM_ADV_RANDOM, UVM_FLAG_FIXED))) panic("uvm_init: cannot reserve dead beef @0x%x", DEADBEEF0); #endif #ifdef DEADBEEF1 kvm_start = trunc_page(DEADBEEF1) - PAGE_SIZE; if (uvm_map(kernel_map, &kvm_start, 3 * PAGE_SIZE, NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, UVM_ADV_RANDOM, UVM_FLAG_FIXED))) panic("uvm_init: cannot reserve dead beef @0x%x", DEADBEEF1); #endif /* * init anonymous memory systems */ uvm_anon_init(); #ifndef SMALL_KERNEL /* * Switch kernel and kmem_map over to a best-fit allocator, * instead of walking the tree. */ uvm_map_set_uaddr(kernel_map, &kernel_map->uaddr_any[3], uaddr_bestfit_create(vm_map_min(kernel_map), vm_map_max(kernel_map))); uvm_map_set_uaddr(kmem_map, &kmem_map->uaddr_any[3], uaddr_bestfit_create(vm_map_min(kmem_map), vm_map_max(kmem_map))); #endif /* !SMALL_KERNEL */ }
int sys_shmat(struct proc *p, void *v, register_t *retval) { struct sys_shmat_args /* { syscallarg(int) shmid; syscallarg(const void *) shmaddr; syscallarg(int) shmflg; } */ *uap = v; int error, i, flags; struct ucred *cred = p->p_ucred; struct shmid_ds *shmseg; struct shmmap_head *shmmap_h; struct shmmap_state *shmmap_s; struct shm_handle *shm_handle; vaddr_t attach_va; vm_prot_t prot; vsize_t size; shmmap_h = (struct shmmap_head *)p->p_vmspace->vm_shm; if (shmmap_h == NULL) { size = sizeof(int) + shminfo.shmseg * sizeof(struct shmmap_state); shmmap_h = malloc(size, M_SHM, M_WAITOK); shmmap_h->shmseg = shminfo.shmseg; for (i = 0, shmmap_s = shmmap_h->state; i < shmmap_h->shmseg; i++, shmmap_s++) shmmap_s->shmid = -1; p->p_vmspace->vm_shm = (caddr_t)shmmap_h; } shmseg = shm_find_segment_by_shmid(SCARG(uap, shmid)); if (shmseg == NULL) return (EINVAL); error = ipcperm(cred, &shmseg->shm_perm, (SCARG(uap, shmflg) & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W); if (error) return (error); for (i = 0, shmmap_s = shmmap_h->state; i < shmmap_h->shmseg; i++) { if (shmmap_s->shmid == -1) break; shmmap_s++; } if (i >= shmmap_h->shmseg) return (EMFILE); size = round_page(shmseg->shm_segsz); prot = VM_PROT_READ; if ((SCARG(uap, shmflg) & SHM_RDONLY) == 0) prot |= VM_PROT_WRITE; flags = MAP_ANON | MAP_SHARED; if (SCARG(uap, shmaddr)) { flags |= MAP_FIXED; if (SCARG(uap, shmflg) & SHM_RND) attach_va = (vaddr_t)SCARG(uap, shmaddr) & ~(SHMLBA-1); else if (((vaddr_t)SCARG(uap, shmaddr) & (SHMLBA-1)) == 0) attach_va = (vaddr_t)SCARG(uap, shmaddr); else return (EINVAL); } else attach_va = 0; shm_handle = shmseg->shm_internal; uao_reference(shm_handle->shm_object); error = uvm_map(&p->p_vmspace->vm_map, &attach_va, size, shm_handle->shm_object, 0, 0, UVM_MAPFLAG(prot, prot, UVM_INH_SHARE, UVM_ADV_RANDOM, 0)); if (error) { uao_detach(shm_handle->shm_object); return (error); } shmmap_s->va = attach_va; shmmap_s->shmid = SCARG(uap, shmid); shmseg->shm_lpid = p->p_p->ps_pid; shmseg->shm_atime = time_second; shmseg->shm_nattch++; *retval = attach_va; return (0); }
int uvm_mmap(struct vm_map *map, vaddr_t *addr, vsize_t size, vm_prot_t prot, vm_prot_t maxprot, int flags, int advice, struct uvm_object *uobj, voff_t foff, vsize_t locklimit) { vaddr_t align = 0; int error; uvm_flag_t uvmflag = 0; /* * check params */ if (size == 0) return 0; if (foff & PAGE_MASK) return EINVAL; if ((prot & maxprot) != prot) return EINVAL; /* * for non-fixed mappings, round off the suggested address. * for fixed mappings, check alignment and zap old mappings. */ if ((flags & MAP_FIXED) == 0) { *addr = round_page(*addr); } else { if (*addr & PAGE_MASK) return EINVAL; uvmflag |= UVM_FLAG_FIXED; (void) uvm_unmap(map, *addr, *addr + size); } /* * Try to see if any requested alignment can even be attemped. * Make sure we can express the alignment (asking for a >= 4GB * alignment on an ILP32 architecure make no sense) and the * alignment is at least for a page sized quanitiy. If the * request was for a fixed mapping, make sure supplied address * adheres to the request alignment. */ align = (flags & MAP_ALIGNMENT_MASK) >> MAP_ALIGNMENT_SHIFT; if (align) { if (align >= sizeof(vaddr_t) * NBBY) return EINVAL; align = 1L << align; if (align < PAGE_SIZE) return EINVAL; if (align >= vm_map_max(map)) return ENOMEM; if (flags & MAP_FIXED) { if ((*addr & (align-1)) != 0) return EINVAL; align = 0; } } /* * check resource limits */ if (!VM_MAP_IS_KERNEL(map) && (((rlim_t)curproc->p_vmspace->vm_map.size + (rlim_t)size) > curproc->p_rlimit[RLIMIT_AS].rlim_cur)) return ENOMEM; /* * handle anon vs. non-anon mappings. for non-anon mappings attach * to underlying vm object. */ if (flags & MAP_ANON) { KASSERT(uobj == NULL); foff = UVM_UNKNOWN_OFFSET; if ((flags & MAP_SHARED) == 0) /* XXX: defer amap create */ uvmflag |= UVM_FLAG_COPYONW; else /* shared: create amap now */ uvmflag |= UVM_FLAG_OVERLAY; } else { KASSERT(uobj != NULL); if ((flags & MAP_SHARED) == 0) { uvmflag |= UVM_FLAG_COPYONW; } } uvmflag = UVM_MAPFLAG(prot, maxprot, (flags & MAP_SHARED) ? UVM_INH_SHARE : UVM_INH_COPY, advice, uvmflag); error = uvm_map(map, addr, size, uobj, foff, align, uvmflag); if (error) { if (uobj) uobj->pgops->pgo_detach(uobj); return error; } /* * POSIX 1003.1b -- if our address space was configured * to lock all future mappings, wire the one we just made. * * Also handle the MAP_WIRED flag here. */ if (prot == VM_PROT_NONE) { /* * No more work to do in this case. */ return 0; } if ((flags & MAP_WIRED) != 0 || (map->flags & VM_MAP_WIREFUTURE) != 0) { vm_map_lock(map); if (atop(size) + uvmexp.wired > uvmexp.wiredmax || (locklimit != 0 && size + ptoa(pmap_wired_count(vm_map_pmap(map))) > locklimit)) { vm_map_unlock(map); uvm_unmap(map, *addr, *addr + size); return ENOMEM; } /* * uvm_map_pageable() always returns the map unlocked. */ error = uvm_map_pageable(map, *addr, *addr + size, false, UVM_LK_ENTER); if (error) { uvm_unmap(map, *addr, *addr + size); return error; } return 0; } return 0; }
void setup_buffers(vaddr_t *maxaddr) { vsize_t size; vaddr_t addr; int base, residual, left, chunk, i; struct pglist pgs, saved_pgs; struct vm_page *pg; int rv; size = MAXBSIZE * nbuf; addr = vm_map_min(kernel_map); if ((rv = uvm_map(kernel_map, &addr, round_page(size), NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, UVM_ADV_NORMAL, 0)))) panic("cpu_startup: cannot allocate VM for buffers %d", rv); buffers = (char *)addr; base = bufpages / nbuf; residual = bufpages % nbuf; if (base >= MAXBSIZE / PAGE_SIZE) { /* don't want to alloc more physical mem than needed */ base = MAXBSIZE / PAGE_SIZE; residual = 0; } /* * In case we might need DMA bouncing we have to make sure there * is some memory below 16MB available. On machines with many * pages reserved for the buffer cache we risk filling all of that * area with buffer pages. We still want much of the buffers * reside there as that lowers the probability of them needing to * bounce, but we have to set aside some space for DMA buffers too. * * The current strategy is to grab hold of one 3MB chunk below 16MB * first, which we are saving for DMA buffers, then try to get * one chunk at a time for fs buffers, until that is not possible * anymore, at which point we get the rest wherever we may find it. * After that we give our saved area back. That will guarantee at * least 3MB below 16MB left for drivers' attach routines, among * them isadma. However we still have a potential problem of PCI * devices attached earlier snatching that memory. This can be * solved by making the PCI DMA memory allocation routines go for * memory above 16MB first. */ left = bufpages; /* * First, save ISA DMA bounce buffer area so we won't lose that * capability. */ TAILQ_INIT(&saved_pgs); TAILQ_INIT(&pgs); if (!ALLOC_PGS(CHUNKSZ, ISADMA_LIMIT, saved_pgs)) { /* * Then, grab as much ISA DMAable memory as possible * for the buffer cache as it is nice to not need to * bounce all buffer I/O. */ for (left = bufpages; left > 0; left -= chunk) { chunk = min(left, CHUNKSZ / PAGE_SIZE); if (ALLOC_PGS(chunk * PAGE_SIZE, ISADMA_LIMIT, pgs)) break; } } /* * If we need more pages for the buffer cache, get them from anywhere. */ if (left > 0 && ALLOC_PGS(left * PAGE_SIZE, avail_end, pgs)) panic("cannot get physical memory for buffer cache"); /* * Finally, give back the ISA DMA bounce buffer area, so it can be * allocated by the isadma driver later. */ if (!TAILQ_EMPTY(&saved_pgs)) FREE_PGS(saved_pgs); pg = TAILQ_FIRST(&pgs); for (i = 0; i < nbuf; i++) { /* * First <residual> buffers get (base+1) physical pages * allocated for them. The rest get (base) physical pages. * * The rest of each buffer occupies virtual space, * but has no physical memory allocated for it. */ addr = (vaddr_t)buffers + i * MAXBSIZE; for (size = PAGE_SIZE * (i < residual ? base + 1 : base); size > 0; size -= PAGE_SIZE, addr += PAGE_SIZE) { pmap_kenter_pa(addr, VM_PAGE_TO_PHYS(pg), VM_PROT_READ|VM_PROT_WRITE); pg = TAILQ_NEXT(pg, pageq); } } pmap_update(pmap_kernel()); }
vaddr_t uvm_km_alloc1(struct vm_map *map, vsize_t size, vsize_t align, boolean_t zeroit) { vaddr_t kva, loopva; voff_t offset; struct vm_page *pg; UVMHIST_FUNC("uvm_km_alloc1"); UVMHIST_CALLED(maphist); UVMHIST_LOG(maphist,"(map=%p, size=0x%lx)", map, size,0,0); KASSERT(vm_map_pmap(map) == pmap_kernel()); size = round_page(size); kva = vm_map_min(map); /* hint */ /* * allocate some virtual space */ if (__predict_false(uvm_map(map, &kva, size, uvm.kernel_object, UVM_UNKNOWN_OFFSET, align, UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_NONE, UVM_ADV_RANDOM, 0)) != 0)) { UVMHIST_LOG(maphist,"<- done (no VM)",0,0,0,0); return(0); } /* * recover object offset from virtual address */ offset = kva - vm_map_min(kernel_map); UVMHIST_LOG(maphist," kva=0x%lx, offset=0x%lx", kva, offset,0,0); /* * now allocate the memory. we must be careful about released pages. */ loopva = kva; while (size) { simple_lock(&uvm.kernel_object->vmobjlock); pg = uvm_pagelookup(uvm.kernel_object, offset); /* * if we found a page in an unallocated region, it must be * released */ if (pg) { if ((pg->pg_flags & PG_RELEASED) == 0) panic("uvm_km_alloc1: non-released page"); atomic_setbits_int(&pg->pg_flags, PG_WANTED); UVM_UNLOCK_AND_WAIT(pg, &uvm.kernel_object->vmobjlock, FALSE, "km_alloc", 0); continue; /* retry */ } /* allocate ram */ pg = uvm_pagealloc(uvm.kernel_object, offset, NULL, 0); if (pg) { atomic_clearbits_int(&pg->pg_flags, PG_BUSY); UVM_PAGE_OWN(pg, NULL); } simple_unlock(&uvm.kernel_object->vmobjlock); if (__predict_false(pg == NULL)) { if (curproc == uvm.pagedaemon_proc) { /* * It is unfeasible for the page daemon to * sleep for memory, so free what we have * allocated and fail. */ uvm_unmap(map, kva, loopva - kva); return (NULL); } else { uvm_wait("km_alloc1w"); /* wait for memory */ continue; } } /* * map it in; note we're never called with an intrsafe * object, so we always use regular old pmap_enter(). */ pmap_enter(map->pmap, loopva, VM_PAGE_TO_PHYS(pg), UVM_PROT_ALL, PMAP_WIRED | VM_PROT_READ | VM_PROT_WRITE); loopva += PAGE_SIZE; offset += PAGE_SIZE; size -= PAGE_SIZE; } pmap_update(map->pmap); /* * zero on request (note that "size" is now zero due to the above loop * so we need to subtract kva from loopva to reconstruct the size). */ if (zeroit) memset((caddr_t)kva, 0, loopva - kva); UVMHIST_LOG(maphist,"<- done (kva=0x%lx)", kva,0,0,0); return(kva); }
void uvm_init() { vaddr_t kvm_start, kvm_end; /* * step 0: ensure that the hardware set the page size */ if (uvmexp.pagesize == 0) { panic("uvm_init: page size not set"); } /* * step 1: zero the uvm structure */ memset(&uvm, 0, sizeof(uvm)); averunnable.fscale = FSCALE; /* * step 2: init the page sub-system. this includes allocating the * vm_page structures, and setting up all the page queues (and * locks). available memory will be put in the "free" queue. * kvm_start and kvm_end will be set to the area of kernel virtual * memory which is available for general use. */ uvm_page_init(&kvm_start, &kvm_end); /* * step 3: init the map sub-system. allocates the static pool of * vm_map_entry structures that are used for "special" kernel maps * (e.g. kernel_map, kmem_map, etc...). */ uvm_map_init(); /* * step 4: setup the kernel's virtual memory data structures. this * includes setting up the kernel_map/kernel_object and the kmem_map/ * kmem_object. */ uvm_km_init(kvm_start, kvm_end); /* * step 5: init the pmap module. the pmap module is free to allocate * memory for its private use (e.g. pvlists). */ pmap_init(); /* * step 6: init the kernel memory allocator. after this call the * kernel memory allocator (malloc) can be used. */ uvm_km_page_init(); kmeminit(); #if !defined(__HAVE_PMAP_DIRECT) kthread_create_deferred(uvm_km_createthread, NULL); #endif /* * step 7: init all pagers and the pager_map. */ uvm_pager_init(); /* * step 8: init anonymous memory system */ amap_init(); /* init amap module */ /* * the VM system is now up! now that malloc is up we can resize the * <obj,off> => <page> hash table for general use and enable paging * of kernel objects. */ uvm_page_rehash(); uao_create(VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS, UAO_FLAG_KERNSWAP); /* * reserve some unmapped space for malloc/pool use after free usage */ #ifdef DEADBEEF0 kvm_start = trunc_page(DEADBEEF0) - PAGE_SIZE; if (uvm_map(kernel_map, &kvm_start, 3 * PAGE_SIZE, NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, UVM_ADV_RANDOM, UVM_FLAG_FIXED))) panic("uvm_init: cannot reserve dead beef @0x%x\n", DEADBEEF0); #endif #ifdef DEADBEEF1 kvm_start = trunc_page(DEADBEEF1) - PAGE_SIZE; if (uvm_map(kernel_map, &kvm_start, 3 * PAGE_SIZE, NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, UVM_ADV_RANDOM, UVM_FLAG_FIXED))) panic("uvm_init: cannot reserve dead beef @0x%x\n", DEADBEEF1); #endif /* * init anonymous memory systems */ uvm_anon_init(); }
/* * Machine-dependent startup code */ void cpu_startup() { caddr_t v; int sz; #ifdef DEBUG extern int pmapdebug; int opmapdebug = pmapdebug; #endif vaddr_t minaddr, maxaddr; extern struct user *proc0paddr; #ifdef DEBUG pmapdebug = 0; #endif if (CPU_ISSUN4M) { extern int stackgap_random; stackgap_random = STACKGAP_RANDOM_SUN4M; } /* * fix message buffer mapping, note phys addr of msgbuf is 0 */ pmap_map(MSGBUF_VA, 0, MSGBUFSIZE, VM_PROT_READ|VM_PROT_WRITE); initmsgbuf((caddr_t)(MSGBUF_VA + (CPU_ISSUN4 ? 4096 : 0)), MSGBUFSIZE); proc0.p_addr = proc0paddr; /* * Good {morning,afternoon,evening,night}. */ printf(version); /*identifycpu();*/ printf("real mem = %u (%uMB)\n", ptoa(physmem), ptoa(physmem)/1024/1024); /* * Find out how much space we need, allocate it, * and then give everything true virtual addresses. */ sz = (int)allocsys((caddr_t)0); if ((v = (caddr_t)uvm_km_alloc(kernel_map, round_page(sz))) == 0) panic("startup: no room for tables"); if (allocsys(v) - v != sz) panic("startup: table size inconsistency"); /* * Determine how many buffers to allocate. * We allocate bufcachepercent% of memory for buffer space. */ if (bufpages == 0) bufpages = physmem * bufcachepercent / 100; /* Restrict to at most 25% filled kvm */ if (bufpages > (VM_MAX_KERNEL_ADDRESS-VM_MIN_KERNEL_ADDRESS) / PAGE_SIZE / 4) bufpages = (VM_MAX_KERNEL_ADDRESS-VM_MIN_KERNEL_ADDRESS) / PAGE_SIZE / 4; /* * Allocate a submap for exec arguments. This map effectively * limits the number of processes exec'ing at any time. */ minaddr = vm_map_min(kernel_map); exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 16*NCARGS, VM_MAP_PAGEABLE, FALSE, NULL); /* * Allocate a map for physio. Others use a submap of the kernel * map, but we want one completely separate, even though it uses * the same pmap. */ dvma_base = CPU_ISSUN4M ? DVMA4M_BASE : DVMA_BASE; dvma_end = CPU_ISSUN4M ? DVMA4M_END : DVMA_END; #if defined(SUN4M) if (CPU_ISSUN4M) { /* * The DVMA space we want partially overrides kernel_map. * Allocate it in kernel_map as well to prevent it from being * used for other things. */ if (uvm_map(kernel_map, &dvma_base, vm_map_max(kernel_map) - dvma_base, NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, UVM_ADV_NORMAL, 0))) panic("startup: can not steal dvma map"); } #endif phys_map = uvm_map_create(pmap_kernel(), dvma_base, dvma_end, VM_MAP_INTRSAFE); if (phys_map == NULL) panic("unable to create DVMA map"); /* * Allocate DVMA space and dump into a privately managed * resource map for double mappings which is usable from * interrupt contexts. */ if (uvm_km_valloc_wait(phys_map, (dvma_end-dvma_base)) != dvma_base) panic("unable to allocate from DVMA map"); dvmamap_extent = extent_create("dvmamap", dvma_base, dvma_end, M_DEVBUF, NULL, 0, EX_NOWAIT); if (dvmamap_extent == 0) panic("unable to allocate extent for dvma"); #ifdef DEBUG pmapdebug = opmapdebug; #endif printf("avail mem = %lu (%luMB)\n", ptoa(uvmexp.free), ptoa(uvmexp.free)/1024/1024); /* * Set up buffers, so they can be used to read disk labels. */ bufinit(); /* Early interrupt handlers initialization */ intr_init(); }