Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / sun3 / sun3x / mem.c
blob34d7af44131bef3c4689b6eb1aeb1699d9986fa3
1 /* $NetBSD: mem.c,v 1.32 2007/03/04 06:00:55 christos Exp $ */
3 /*
4 * Copyright (c) 1982, 1986, 1990, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * the Systems Programming Group of the University of Utah Computer
9 * Science Department.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
35 * from: @(#)mem.c 8.3 (Berkeley) 1/12/94
38 * Copyright (c) 1988 University of Utah.
40 * This code is derived from software contributed to Berkeley by
41 * the Systems Programming Group of the University of Utah Computer
42 * Science Department.
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions
46 * are met:
47 * 1. Redistributions of source code must retain the above copyright
48 * notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution.
52 * 3. All advertising materials mentioning features or use of this software
53 * must display the following acknowledgement:
54 * This product includes software developed by the University of
55 * California, Berkeley and its contributors.
56 * 4. Neither the name of the University nor the names of its contributors
57 * may be used to endorse or promote products derived from this software
58 * without specific prior written permission.
60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70 * SUCH DAMAGE.
72 * from: @(#)mem.c 8.3 (Berkeley) 1/12/94
76 * Memory special file
79 #include <sys/cdefs.h>
80 __KERNEL_RCSID(0, "$NetBSD: mem.c,v 1.32 2007/03/04 06:00:55 christos Exp $");
82 #include <sys/param.h>
83 #include <sys/systm.h>
84 #include <sys/buf.h>
85 #include <sys/conf.h>
86 #include <sys/malloc.h>
87 #include <sys/proc.h>
88 #include <sys/uio.h>
90 #include <uvm/uvm_extern.h>
92 #include <machine/cpu.h>
93 #include <machine/eeprom.h>
94 #include <machine/leds.h>
95 #include <machine/mon.h>
96 #include <machine/pmap.h>
97 #include <machine/pte.h>
99 #include <sun3/sun3/machdep.h>
101 #define DEV_VME16D16 5 /* minor device 5 is /dev/vme16d16 */
102 #define DEV_VME24D16 6 /* minor device 6 is /dev/vme24d16 */
103 #define DEV_VME32D16 7 /* minor device 7 is /dev/vme32d16 */
104 #define DEV_VME16D32 8 /* minor device 8 is /dev/vme16d32 */
105 #define DEV_VME24D32 9 /* minor device 9 is /dev/vme24d32 */
106 #define DEV_VME32D32 10 /* minor device 10 is /dev/vme32d32 */
107 #define DEV_EEPROM 11 /* minor device 11 is eeprom */
108 #define DEV_LEDS 13 /* minor device 13 is leds */
110 /* XXX - Put this in pmap_pvt.h or something? */
111 extern paddr_t avail_start;
113 static int promacc(void *, int, int);
114 static void *devzeropage;
116 dev_type_read(mmrw);
117 dev_type_ioctl(mmioctl);
118 dev_type_mmap(mmmmap);
120 const struct cdevsw mem_cdevsw = {
121 nullopen, nullclose, mmrw, mmrw, mmioctl,
122 nostop, notty, nopoll, mmmmap, nokqfilter,
125 /*ARGSUSED*/
126 int
127 mmrw(dev_t dev, struct uio *uio, int flags)
129 struct iovec *iov;
130 vaddr_t o, v;
131 int c, rw;
132 int error = 0;
133 static int physlock;
134 vm_prot_t prot;
136 if (minor(dev) == DEV_MEM) {
137 if (vmmap == 0)
138 return (EIO);
139 /* lock against other uses of shared vmmap */
140 while (physlock > 0) {
141 physlock++;
142 error = tsleep((void *)&physlock, PZERO | PCATCH,
143 "mmrw", 0);
144 if (error)
145 return (error);
147 physlock = 1;
149 while (uio->uio_resid > 0 && error == 0) {
150 iov = uio->uio_iov;
151 if (iov->iov_len == 0) {
152 uio->uio_iov++;
153 uio->uio_iovcnt--;
154 if (uio->uio_iovcnt < 0)
155 panic("mmrw");
156 continue;
158 switch (minor(dev)) {
160 case DEV_MEM:
161 v = uio->uio_offset;
162 /* allow reads only in RAM */
163 if (!pmap_pa_exists(v)) {
164 error = EFAULT;
165 goto unlock;
168 * If the offset (physical address) is within the
169 * linearly mapped range (0 .. avail_start) then
170 * we can save some hair by using the /dev/kmem
171 * alias mapping known to exist for this range.
173 if (v < avail_start) {
174 v += KERNBASE;
175 goto use_kmem;
177 /* Temporarily map the memory at vmmap. */
178 prot = uio->uio_rw == UIO_READ ? VM_PROT_READ :
179 VM_PROT_WRITE;
180 pmap_enter(pmap_kernel(), (vaddr_t)vmmap,
181 trunc_page(v), prot, prot|PMAP_WIRED);
182 pmap_update(pmap_kernel());
183 o = v & PGOFSET;
184 c = min(uio->uio_resid, (int)(PAGE_SIZE - o));
185 error = uiomove((char *)vmmap + o, c, uio);
186 pmap_remove(pmap_kernel(), (vaddr_t)vmmap,
187 (vaddr_t)vmmap + PAGE_SIZE);
188 pmap_update(pmap_kernel());
189 break;
191 case DEV_KMEM:
192 v = uio->uio_offset;
193 use_kmem:
195 * One page at a time to simplify access checks.
196 * Note that we can get here from case 0 above!
198 o = v & PGOFSET;
199 c = min(uio->uio_resid, (int)(PAGE_SIZE - o));
200 rw = (uio->uio_rw == UIO_READ) ? B_READ : B_WRITE;
201 if (!(uvm_kernacc((void *)v, c, rw) ||
202 promacc((void *)v, c, rw)))
204 error = EFAULT;
205 /* Note: case 0 can get here, so must unlock! */
206 goto unlock;
208 error = uiomove((void *)v, c, uio);
209 break;
211 case DEV_NULL:
212 if (uio->uio_rw == UIO_WRITE)
213 uio->uio_resid = 0;
214 return (0);
216 case DEV_EEPROM:
217 error = eeprom_uio(uio);
218 /* Yes, return (not break) so EOF works. */
219 return (error);
221 case DEV_ZERO:
222 /* Write to /dev/zero is ignored. */
223 if (uio->uio_rw == UIO_WRITE) {
224 uio->uio_resid = 0;
225 return (0);
228 * On the first call, allocate and zero a page
229 * of memory for use with /dev/zero.
231 if (devzeropage == NULL) {
232 devzeropage = (void *)
233 malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
234 memset(devzeropage, 0, PAGE_SIZE);
236 c = min(iov->iov_len, PAGE_SIZE);
237 error = uiomove(devzeropage, c, uio);
238 break;
240 case DEV_LEDS:
241 error = leds_uio(uio);
242 /* Yes, return (not break) so EOF works. */
243 return (error);
245 default:
246 return (ENXIO);
251 * Note the different location of this label, compared with
252 * other ports. This is because the /dev/mem to /dev/kmem
253 * redirection above jumps here on error to do its unlock.
255 unlock:
256 if (minor(dev) == DEV_MEM) {
257 if (physlock > 1)
258 wakeup((void *)&physlock);
259 physlock = 0;
261 return (error);
264 paddr_t
265 mmmmap(dev_t dev, off_t off, int prot)
268 * Check address validity.
270 if (off & PGOFSET)
271 return (-1);
273 switch (minor(dev)) {
275 case DEV_MEM: /* dev/mem */
276 /* Allow access only in valid memory. */
277 if (!pmap_pa_exists(off))
278 break;
279 return (off);
281 #if 0 /* XXX - NOTYET */
282 /* XXX - Move this to bus_subr.c? */
283 case DEV_VME16D16:
284 if (off & 0xffff0000)
285 break;
286 off |= 0xff0000;
287 /* fall through */
288 case DEV_VME24D16:
289 if (off & 0xff000000)
290 break;
291 off |= 0xff000000;
292 /* fall through */
293 case DEV_VME32D16:
294 return (off | PMAP_VME16);
296 case DEV_VME16D32:
297 if (off & 0xffff0000)
298 break;
299 off |= 0xff0000;
300 /* fall through */
301 case DEV_VME24D32:
302 if (off & 0xff000000)
303 break;
304 off |= 0xff000000;
305 /* fall through */
306 case DEV_VME32D32:
307 return (off | PMAP_VME32);
308 #endif /* XXX */
311 return (-1);
316 * Just like uvm_kernacc(), but for the PROM mappings.
317 * Return non-zero if access at VA is allowed.
319 static int
320 promacc(void *va, int len, int rw)
322 vaddr_t sva, eva;
324 sva = (vaddr_t)va;
325 eva = (vaddr_t)va + len;
327 /* Test for the most common case first. */
328 if (sva < SUN3X_PROM_BASE)
329 return (0);
331 /* Read in the PROM itself is OK. */
332 if ((rw == B_READ) && (eva <= SUN3X_MONEND))
333 return (1);
335 /* PROM data page is OK for read/write. */
336 if ((sva >= SUN3X_MONDATA) &&
337 (eva <= (SUN3X_MONDATA + PAGE_SIZE)))
338 return (1);
340 /* otherwise, not OK to touch */
341 return (0);