1 /* $NetBSD: ofrom.c,v 1.29 2021/01/27 03:10:21 thorpej Exp $ */
2
3 /*
4 * Copyright 1998
5 * Digital Equipment Corporation. All rights reserved.
6 *
7 * This software is furnished under license and may be used and
8 * copied only in accordance with the following terms and conditions.
9 * Subject to these conditions, you may download, copy, install,
10 * use, modify and distribute this software in source and/or binary
11 * form. No title or ownership is transferred hereby.
12 *
13 * 1) Any source code used, modified or distributed must reproduce
14 * and retain this copyright notice and list of conditions as
15 * they appear in the source file.
16 *
17 * 2) No right is granted to use any trade name, trademark, or logo of
18 * Digital Equipment Corporation. Neither the "Digital Equipment
19 * Corporation" name nor any trademark or logo of Digital Equipment
20 * Corporation may be used to endorse or promote products derived
21 * from this software without the prior written permission of
22 * Digital Equipment Corporation.
23 *
24 * 3) This software is provided "AS-IS" and any express or implied
25 * warranties, including but not limited to, any implied warranties
26 * of merchantability, fitness for a particular purpose, or
27 * non-infringement are disclaimed. In no event shall DIGITAL be
28 * liable for any damages whatsoever, and in particular, DIGITAL
29 * shall not be liable for special, indirect, consequential, or
30 * incidental damages or damages for lost profits, loss of
31 * revenue or loss of use, whether such damages arise in contract,
32 * negligence, tort, under statute, in equity, at law or otherwise,
33 * even if advised of the possibility of such damage.
34 */
35
36 /*
37 * XXX open for writing (for user programs to mmap, and write contents)
38 */
39
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: ofrom.c,v 1.29 2021/01/27 03:10:21 thorpej Exp $");
42
43 #include <sys/param.h>
44 #include <sys/device.h>
45 #include <sys/systm.h>
46 #include <sys/conf.h>
47 #include <sys/fcntl.h>
48 #include <sys/bus.h>
49
50 #include <uvm/uvm_extern.h>
51
52 #include <dev/ofw/openfirm.h>
53
54 struct ofrom_softc {
55 int enabled;
56 paddr_t base;
57 paddr_t size;
58 };
59
60 int ofromprobe(device_t, cfdata_t, void *);
61 void ofromattach(device_t, device_t, void *);
62
63 CFATTACH_DECL_NEW(ofrom, sizeof(struct ofrom_softc),
64 ofromprobe, ofromattach, NULL, NULL);
65
66 extern struct cfdriver ofrom_cd;
67
68 dev_type_open(ofromopen);
69 dev_type_read(ofromrw);
70 dev_type_mmap(ofrommmap);
71
72 const struct cdevsw ofrom_cdevsw = {
73 .d_open = ofromopen,
74 .d_close = nullclose,
75 .d_read = ofromrw,
76 .d_write = ofromrw,
77 .d_ioctl = noioctl,
78 .d_stop = nostop,
79 .d_tty = notty,
80 .d_poll = nopoll,
81 .d_mmap = ofrommmap,
82 .d_kqfilter = nokqfilter,
83 .d_discard = nodiscard,
84 .d_flag = 0
85 };
86
87 static const struct device_compatible_entry compat_data[] = {
88 { .compat = "rom" },
89 DEVICE_COMPAT_EOL
90 };
91
92 int
ofromprobe(device_t parent,cfdata_t cf,void * aux)93 ofromprobe(device_t parent, cfdata_t cf, void *aux)
94 {
95 struct ofbus_attach_args *oba = aux;
96
97 return of_compatible_match(oba->oba_phandle, compat_data) * 5;
98 }
99
100
101 void
ofromattach(device_t parent,device_t self,void * aux)102 ofromattach(device_t parent, device_t self, void *aux)
103 {
104 struct ofrom_softc *sc = device_private(self);
105 struct ofbus_attach_args *oba = aux;
106 char regbuf[8];
107
108 if (OF_getproplen(oba->oba_phandle, "reg") != 8) {
109 printf(": invalid reg property\n");
110 return;
111 }
112 if (OF_getprop(oba->oba_phandle, "reg", regbuf, sizeof regbuf) != 8) {
113 printf(": couldn't read reg property\n");
114 return;
115 }
116 sc->base = of_decode_int(®buf[0]);
117 sc->size = of_decode_int(®buf[4]);
118 sc->enabled = 1;
119
120 printf(": %#lx-%#lx\n", sc->base, sc->base + sc->size - 1);
121 }
122
123 int
ofromopen(dev_t dev,int oflags,int devtype,struct lwp * l)124 ofromopen(dev_t dev, int oflags, int devtype, struct lwp *l)
125 {
126 struct ofrom_softc *sc;
127
128 sc = device_lookup_private(&ofrom_cd, minor(dev));
129 if (!sc || !sc->enabled)
130 return (ENXIO);
131
132 if (oflags & FWRITE)
133 return (EINVAL);
134
135 return (0);
136 }
137
138 int
ofromrw(dev_t dev,struct uio * uio,int flags)139 ofromrw(dev_t dev, struct uio *uio, int flags)
140 {
141 pmap_t kpm = pmap_kernel();
142 struct ofrom_softc *sc;
143 int c, error = 0;
144 struct iovec *iov;
145 paddr_t v;
146 psize_t o;
147 extern kmutex_t memlock;
148 extern char *memhook;
149
150 sc = device_lookup_private(&ofrom_cd, minor(dev));
151 if (!sc || !sc->enabled)
152 return (ENXIO); /* XXX PANIC */
153
154 mutex_enter(&memlock);
155 while (uio->uio_resid > 0 && error == 0) {
156 iov = uio->uio_iov;
157 if (iov->iov_len == 0) {
158 uio->uio_iov++;
159 uio->uio_iovcnt--;
160 if (uio->uio_iovcnt < 0)
161 panic("ofromrw");
162 continue;
163 }
164
165 /*
166 * Since everything is page aligned and no more
167 * than the rest of a page is done at once, we
168 * can just check that the offset isn't too big.
169 */
170 if (uio->uio_offset >= sc->size)
171 break;
172
173 v = sc->base + uio->uio_offset;
174 pmap_kenter_pa((vaddr_t)memhook, trunc_page(v),
175 uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE,
176 0);
177 pmap_update(kpm);
178 o = uio->uio_offset & PGOFSET;
179 c = uimin(uio->uio_resid, (int)(PAGE_SIZE - o));
180 error = uiomove((char *)memhook + o, c, uio);
181 pmap_kremove((vaddr_t)memhook, (vaddr_t)memhook + PAGE_SIZE);
182 pmap_update(kpm);
183 }
184 mutex_exit(&memlock);
185
186 return (error);
187 }
188
189 paddr_t
ofrommmap(dev_t dev,off_t off,int prot)190 ofrommmap(dev_t dev, off_t off, int prot)
191 {
192 struct ofrom_softc *sc;
193
194 sc = device_lookup_private(&ofrom_cd, minor(dev));
195 if (!sc || !sc->enabled)
196 return (-1); /* XXX PANIC */
197
198 if ((u_int)off >= sc->size)
199 return (-1);
200
201 return arm_btop(sc->base + off);
202 }
203