1*d62ebcb2Sderaadt /* $OpenBSD: kern_subr.c,v 1.52 2023/01/31 15:18:56 deraadt Exp $ */
2d724e01aSderaadt /* $NetBSD: kern_subr.c,v 1.15 1996/04/09 17:21:56 ragge Exp $ */
3df930be7Sderaadt
4df930be7Sderaadt /*
5df930be7Sderaadt * Copyright (c) 1982, 1986, 1991, 1993
6df930be7Sderaadt * The Regents of the University of California. All rights reserved.
7df930be7Sderaadt * (c) UNIX System Laboratories, Inc.
8df930be7Sderaadt * All or some portions of this file are derived from material licensed
9df930be7Sderaadt * to the University of California by American Telephone and Telegraph
10df930be7Sderaadt * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11df930be7Sderaadt * the permission of UNIX System Laboratories, Inc.
12df930be7Sderaadt *
13df930be7Sderaadt * Redistribution and use in source and binary forms, with or without
14df930be7Sderaadt * modification, are permitted provided that the following conditions
15df930be7Sderaadt * are met:
16df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright
17df930be7Sderaadt * notice, this list of conditions and the following disclaimer.
18df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright
19df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the
20df930be7Sderaadt * documentation and/or other materials provided with the distribution.
2129295d1cSmillert * 3. Neither the name of the University nor the names of its contributors
22df930be7Sderaadt * may be used to endorse or promote products derived from this software
23df930be7Sderaadt * without specific prior written permission.
24df930be7Sderaadt *
25df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35df930be7Sderaadt * SUCH DAMAGE.
36df930be7Sderaadt *
37df930be7Sderaadt * @(#)kern_subr.c 8.3 (Berkeley) 1/21/94
38df930be7Sderaadt */
39df930be7Sderaadt
40df930be7Sderaadt #include <sys/param.h>
41df930be7Sderaadt #include <sys/systm.h>
42df930be7Sderaadt #include <sys/proc.h>
43012ea299Sniklas #include <sys/sched.h>
44df930be7Sderaadt #include <sys/malloc.h>
45df930be7Sderaadt #include <sys/queue.h>
46*d62ebcb2Sderaadt #include <uvm/uvm_extern.h>
47*d62ebcb2Sderaadt
48*d62ebcb2Sderaadt #ifdef PMAP_CHECK_COPYIN
49*d62ebcb2Sderaadt
50*d62ebcb2Sderaadt static inline int check_copyin(struct proc *, const void *, size_t);
51*d62ebcb2Sderaadt extern int _copyinstr(const void *, void *, size_t, size_t *);
52*d62ebcb2Sderaadt extern int _copyin(const void *uaddr, void *kaddr, size_t len);
53*d62ebcb2Sderaadt
54*d62ebcb2Sderaadt /*
55*d62ebcb2Sderaadt * If range overlaps an check_copyin region, return EFAULT
56*d62ebcb2Sderaadt */
57*d62ebcb2Sderaadt static inline int
check_copyin(struct proc * p,const void * vstart,size_t len)58*d62ebcb2Sderaadt check_copyin(struct proc *p, const void *vstart, size_t len)
59*d62ebcb2Sderaadt {
60*d62ebcb2Sderaadt struct vm_map *map = &p->p_vmspace->vm_map;
61*d62ebcb2Sderaadt const vaddr_t start = (vaddr_t)vstart;
62*d62ebcb2Sderaadt const vaddr_t end = start + len;
63*d62ebcb2Sderaadt int i, max;
64*d62ebcb2Sderaadt
65*d62ebcb2Sderaadt /* XXX if the array was sorted, we could shortcut */
66*d62ebcb2Sderaadt max = map->check_copyin_count;
67*d62ebcb2Sderaadt membar_consumer();
68*d62ebcb2Sderaadt for (i = 0; i < max; i++) {
69*d62ebcb2Sderaadt vaddr_t s = map->check_copyin[i].start;
70*d62ebcb2Sderaadt vaddr_t e = map->check_copyin[i].end;
71*d62ebcb2Sderaadt if ((start >= s && start < e) || (end > s && end < e))
72*d62ebcb2Sderaadt return EFAULT;
73*d62ebcb2Sderaadt }
74*d62ebcb2Sderaadt return (0);
75*d62ebcb2Sderaadt }
76*d62ebcb2Sderaadt
77*d62ebcb2Sderaadt int
copyinstr(const void * uaddr,void * kaddr,size_t len,size_t * done)78*d62ebcb2Sderaadt copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done)
79*d62ebcb2Sderaadt {
80*d62ebcb2Sderaadt size_t alen;
81*d62ebcb2Sderaadt int error;
82*d62ebcb2Sderaadt
83*d62ebcb2Sderaadt /*
84*d62ebcb2Sderaadt * Must do the copyin checks after figuring out the string length,
85*d62ebcb2Sderaadt * the buffer size length may cross into another ELF segment
86*d62ebcb2Sderaadt */
87*d62ebcb2Sderaadt error = _copyinstr(uaddr, kaddr, len, &alen);
88*d62ebcb2Sderaadt if (PMAP_CHECK_COPYIN && error == 0)
89*d62ebcb2Sderaadt error = check_copyin(curproc, uaddr, alen);
90*d62ebcb2Sderaadt if (done)
91*d62ebcb2Sderaadt *done = alen;
92*d62ebcb2Sderaadt return (error);
93*d62ebcb2Sderaadt }
94*d62ebcb2Sderaadt
95*d62ebcb2Sderaadt int
copyin(const void * uaddr,void * kaddr,size_t len)96*d62ebcb2Sderaadt copyin(const void *uaddr, void *kaddr, size_t len)
97*d62ebcb2Sderaadt {
98*d62ebcb2Sderaadt int error = 0;
99*d62ebcb2Sderaadt
100*d62ebcb2Sderaadt if (PMAP_CHECK_COPYIN)
101*d62ebcb2Sderaadt error = check_copyin(curproc, uaddr, len);
102*d62ebcb2Sderaadt if (error == 0)
103*d62ebcb2Sderaadt error = _copyin(uaddr, kaddr, len);
104*d62ebcb2Sderaadt return (error);
105*d62ebcb2Sderaadt }
106*d62ebcb2Sderaadt #endif /* PMAP_CHECK_COPYIN */
107f7e5f6f6Sart
108df930be7Sderaadt int
uiomove(void * cp,size_t n,struct uio * uio)109081bf720Smiod uiomove(void *cp, size_t n, struct uio *uio)
110df930be7Sderaadt {
111158fb4f9Sjsg struct iovec *iov;
112906c107fSguenther size_t cnt;
113df930be7Sderaadt int error = 0;
114df930be7Sderaadt
115df930be7Sderaadt #ifdef DIAGNOSTIC
116df930be7Sderaadt if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE)
117df930be7Sderaadt panic("uiomove: mode");
118481e765dSstefan if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
119f7e5f6f6Sart panic("uiomove: proc");
120df930be7Sderaadt #endif
121481e765dSstefan
122481e765dSstefan if (n > uio->uio_resid)
123481e765dSstefan n = uio->uio_resid;
124481e765dSstefan
125481e765dSstefan while (n > 0) {
126df930be7Sderaadt iov = uio->uio_iov;
127df930be7Sderaadt cnt = iov->iov_len;
128df930be7Sderaadt if (cnt == 0) {
129481e765dSstefan KASSERT(uio->uio_iovcnt > 0);
130df930be7Sderaadt uio->uio_iov++;
131df930be7Sderaadt uio->uio_iovcnt--;
132df930be7Sderaadt continue;
133df930be7Sderaadt }
134df930be7Sderaadt if (cnt > n)
135df930be7Sderaadt cnt = n;
136906c107fSguenther switch (uio->uio_segflg) {
137df930be7Sderaadt
138df930be7Sderaadt case UIO_USERSPACE:
1399b1ed563Smpi sched_pause(preempt);
140df930be7Sderaadt if (uio->uio_rw == UIO_READ)
141df930be7Sderaadt error = copyout(cp, iov->iov_base, cnt);
142df930be7Sderaadt else
143df930be7Sderaadt error = copyin(iov->iov_base, cp, cnt);
144df930be7Sderaadt if (error)
145df930be7Sderaadt return (error);
146df930be7Sderaadt break;
147df930be7Sderaadt
148df930be7Sderaadt case UIO_SYSSPACE:
149a91606c1Sart if (uio->uio_rw == UIO_READ)
150a91606c1Sart error = kcopy(cp, iov->iov_base, cnt);
151a91606c1Sart else
152a91606c1Sart error = kcopy(iov->iov_base, cp, cnt);
153a91606c1Sart if (error)
154a91606c1Sart return(error);
155df930be7Sderaadt }
1567cdefcf6Saaron iov->iov_base = (caddr_t)iov->iov_base + cnt;
157df930be7Sderaadt iov->iov_len -= cnt;
158df930be7Sderaadt uio->uio_resid -= cnt;
159df930be7Sderaadt uio->uio_offset += cnt;
16027e97305Stedu cp = (caddr_t)cp + cnt;
161df930be7Sderaadt n -= cnt;
162df930be7Sderaadt }
163df930be7Sderaadt return (error);
164df930be7Sderaadt }
165df930be7Sderaadt
166df930be7Sderaadt /*
167df930be7Sderaadt * Give next character to user as result of read.
168df930be7Sderaadt */
169df930be7Sderaadt int
ureadc(int c,struct uio * uio)170158fb4f9Sjsg ureadc(int c, struct uio *uio)
171df930be7Sderaadt {
172158fb4f9Sjsg struct iovec *iov;
173df930be7Sderaadt
1749b355cb2Smillert if (uio->uio_resid == 0)
1759b355cb2Smillert #ifdef DIAGNOSTIC
1769b355cb2Smillert panic("ureadc: zero resid");
1779b355cb2Smillert #else
1789b355cb2Smillert return (EINVAL);
1799b355cb2Smillert #endif
180df930be7Sderaadt again:
181df930be7Sderaadt if (uio->uio_iovcnt <= 0)
1829b355cb2Smillert #ifdef DIAGNOSTIC
183df930be7Sderaadt panic("ureadc: non-positive iovcnt");
1849b355cb2Smillert #else
1859b355cb2Smillert return (EINVAL);
1869b355cb2Smillert #endif
187df930be7Sderaadt iov = uio->uio_iov;
188df930be7Sderaadt if (iov->iov_len <= 0) {
189df930be7Sderaadt uio->uio_iovcnt--;
190df930be7Sderaadt uio->uio_iov++;
191df930be7Sderaadt goto again;
192df930be7Sderaadt }
193906c107fSguenther switch (uio->uio_segflg) {
194df930be7Sderaadt
195df930be7Sderaadt case UIO_USERSPACE:
1961de66d4eSmiod {
1971de66d4eSmiod char tmp = c;
1981de66d4eSmiod
1991de66d4eSmiod if (copyout(&tmp, iov->iov_base, sizeof(char)) != 0)
200df930be7Sderaadt return (EFAULT);
2011de66d4eSmiod }
202df930be7Sderaadt break;
203df930be7Sderaadt
204df930be7Sderaadt case UIO_SYSSPACE:
205f4e9f33fSderaadt *(char *)iov->iov_base = c;
206df930be7Sderaadt break;
207df930be7Sderaadt }
2087cdefcf6Saaron iov->iov_base = (caddr_t)iov->iov_base + 1;
209df930be7Sderaadt iov->iov_len--;
210df930be7Sderaadt uio->uio_resid--;
211df930be7Sderaadt uio->uio_offset++;
212df930be7Sderaadt return (0);
213df930be7Sderaadt }
214df930be7Sderaadt
215df930be7Sderaadt /*
216df930be7Sderaadt * General routine to allocate a hash table.
217df930be7Sderaadt */
218df930be7Sderaadt void *
hashinit(int elements,int type,int flags,u_long * hashmask)219158fb4f9Sjsg hashinit(int elements, int type, int flags, u_long *hashmask)
22013049928Smillert {
221ffe9e374Smarkus u_long hashsize, i;
222df930be7Sderaadt LIST_HEAD(generic, generic) *hashtbl;
223df930be7Sderaadt
224df930be7Sderaadt if (elements <= 0)
225df930be7Sderaadt panic("hashinit: bad cnt");
2268e8a4c44Santon if ((elements & (elements - 1)) == 0)
2278e8a4c44Santon hashsize = elements;
2288e8a4c44Santon else
229ffe9e374Smarkus for (hashsize = 1; hashsize < elements; hashsize <<= 1)
230df930be7Sderaadt continue;
23147e7ee29Stedu hashtbl = mallocarray(hashsize, sizeof(*hashtbl), type, flags);
232a950bd2dSart if (hashtbl == NULL)
233a950bd2dSart return NULL;
234df930be7Sderaadt for (i = 0; i < hashsize; i++)
235df930be7Sderaadt LIST_INIT(&hashtbl[i]);
236df930be7Sderaadt *hashmask = hashsize - 1;
237df930be7Sderaadt return (hashtbl);
238df930be7Sderaadt }
239df930be7Sderaadt
24054f18723Stedu void
hashfree(void * hash,int elements,int type)24154f18723Stedu hashfree(void *hash, int elements, int type)
24254f18723Stedu {
24354f18723Stedu u_long hashsize;
24454f18723Stedu LIST_HEAD(generic, generic) *hashtbl = hash;
24554f18723Stedu
24654f18723Stedu if (elements <= 0)
24754f18723Stedu panic("hashfree: bad cnt");
2488e8a4c44Santon if ((elements & (elements - 1)) == 0)
2498e8a4c44Santon hashsize = elements;
2508e8a4c44Santon else
25154f18723Stedu for (hashsize = 1; hashsize < elements; hashsize <<= 1)
25254f18723Stedu continue;
25354f18723Stedu
25454f18723Stedu free(hashtbl, type, sizeof(*hashtbl) * hashsize);
25554f18723Stedu }
25654f18723Stedu
257df930be7Sderaadt /*
258ef89f9e6Smpi * "startup hook" types, functions, and variables.
259df930be7Sderaadt */
260df930be7Sderaadt
261ec1f6c03Sniklas struct hook_desc_head startuphook_list =
262ec1f6c03Sniklas TAILQ_HEAD_INITIALIZER(startuphook_list);
263df930be7Sderaadt
264df930be7Sderaadt void *
hook_establish(struct hook_desc_head * head,int tail,void (* fn)(void *),void * arg)265158fb4f9Sjsg hook_establish(struct hook_desc_head *head, int tail, void (*fn)(void *),
266158fb4f9Sjsg void *arg)
267df930be7Sderaadt {
268ec1f6c03Sniklas struct hook_desc *hdp;
269df930be7Sderaadt
27044f3212aStedu hdp = malloc(sizeof(*hdp), M_DEVBUF, M_NOWAIT);
271ec1f6c03Sniklas if (hdp == NULL)
272ec1f6c03Sniklas return (NULL);
273df930be7Sderaadt
274ec1f6c03Sniklas hdp->hd_fn = fn;
275ec1f6c03Sniklas hdp->hd_arg = arg;
276ec1f6c03Sniklas if (tail)
277ec1f6c03Sniklas TAILQ_INSERT_TAIL(head, hdp, hd_list);
278ec1f6c03Sniklas else
279ec1f6c03Sniklas TAILQ_INSERT_HEAD(head, hdp, hd_list);
280df930be7Sderaadt
281ec1f6c03Sniklas return (hdp);
282df930be7Sderaadt }
283df930be7Sderaadt
284df930be7Sderaadt void
hook_disestablish(struct hook_desc_head * head,void * vhook)285158fb4f9Sjsg hook_disestablish(struct hook_desc_head *head, void *vhook)
286df930be7Sderaadt {
287ec1f6c03Sniklas struct hook_desc *hdp;
288df930be7Sderaadt
28956133d81Sart #ifdef DIAGNOSTIC
290ec1f6c03Sniklas for (hdp = TAILQ_FIRST(head); hdp != NULL;
291ec1f6c03Sniklas hdp = TAILQ_NEXT(hdp, hd_list))
292ec1f6c03Sniklas if (hdp == vhook)
293df930be7Sderaadt break;
294ec1f6c03Sniklas if (hdp == NULL)
295e7cd818eSmarco return;
296df930be7Sderaadt #endif
29756133d81Sart hdp = vhook;
29856133d81Sart TAILQ_REMOVE(head, hdp, hd_list);
299fc62de09Stedu free(hdp, M_DEVBUF, sizeof(*hdp));
300df930be7Sderaadt }
301df930be7Sderaadt
302df930be7Sderaadt /*
303ec1f6c03Sniklas * Run hooks. Startup hooks are invoked right after scheduler_start but
304ec1f6c03Sniklas * before root is mounted. Shutdown hooks are invoked immediately before the
305df930be7Sderaadt * system is halted or rebooted, i.e. after file systems unmounted,
306df930be7Sderaadt * after crash dump done, etc.
307df930be7Sderaadt */
308df930be7Sderaadt void
dohooks(struct hook_desc_head * head,int flags)30956133d81Sart dohooks(struct hook_desc_head *head, int flags)
310df930be7Sderaadt {
3117f06f937Sreyk struct hook_desc *hdp, *hdp_temp;
312df930be7Sderaadt
31356133d81Sart if ((flags & HOOK_REMOVE) == 0) {
3147f06f937Sreyk TAILQ_FOREACH_SAFE(hdp, head, hd_list, hdp_temp) {
315ec1f6c03Sniklas (*hdp->hd_fn)(hdp->hd_arg);
316df930be7Sderaadt }
31756133d81Sart } else {
31856133d81Sart while ((hdp = TAILQ_FIRST(head)) != NULL) {
31956133d81Sart TAILQ_REMOVE(head, hdp, hd_list);
32056133d81Sart (*hdp->hd_fn)(hdp->hd_arg);
32156133d81Sart if ((flags & HOOK_FREE) != 0)
322fc62de09Stedu free(hdp, M_DEVBUF, sizeof(*hdp));
32356133d81Sart }
32456133d81Sart }
32556133d81Sart }
326