1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2003 Matthew N. Dodd <[email protected]>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/malloc.h>
34
35 #include <sys/module.h>
36 #include <sys/bus.h>
37 #include <sys/conf.h>
38
39 #include <machine/bus.h>
40 #include <machine/resource.h>
41 #include <sys/rman.h>
42
43 /* And all this for BIOS_PADDRTOVADDR() */
44 #include <vm/vm.h>
45 #include <vm/vm_param.h>
46 #include <vm/pmap.h>
47 #include <machine/md_var.h>
48 #include <machine/pc/bios.h>
49
50 #include <machine/smapi.h>
51
52 #define SMAPI_START 0xf0000
53 #define SMAPI_STEP 0x10
54 #define SMAPI_OFF 0
55 #define SMAPI_LEN 4
56 #define SMAPI_SIG "$SMB"
57
58 #define RES2HDR(res) ((struct smapi_bios_header *)rman_get_virtual(res))
59 #define ADDR2HDR(addr) ((struct smapi_bios_header *)BIOS_PADDRTOVADDR(addr))
60
61 struct smapi_softc {
62 struct cdev * cdev;
63 device_t dev;
64 struct resource * res;
65 int rid;
66
67 u_int32_t smapi32_entry;
68
69 struct smapi_bios_header *header;
70 };
71
72 extern u_long smapi32_offset;
73 extern u_short smapi32_segment;
74
75 static d_ioctl_t smapi_ioctl;
76
77 static struct cdevsw smapi_cdevsw = {
78 .d_version = D_VERSION,
79 .d_ioctl = smapi_ioctl,
80 .d_name = "smapi",
81 .d_flags = D_NEEDGIANT,
82 };
83
84 static void smapi_identify(driver_t *, device_t);
85 static int smapi_probe(device_t);
86 static int smapi_attach(device_t);
87 static int smapi_detach(device_t);
88 static int smapi_modevent(module_t, int, void *);
89
90 static int smapi_header_cksum(struct smapi_bios_header *);
91
92 extern int smapi32(struct smapi_bios_parameter *,
93 struct smapi_bios_parameter *);
94 extern int smapi32_new(u_long, u_short,
95 struct smapi_bios_parameter *,
96 struct smapi_bios_parameter *);
97
98 static int
smapi_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int fflag,struct thread * td)99 smapi_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
100 {
101 struct smapi_softc *sc = dev->si_drv1;
102 int error;
103
104 switch (cmd) {
105 case SMAPIOGHEADER:
106 bcopy((caddr_t)sc->header, data,
107 sizeof(struct smapi_bios_header));
108 error = 0;
109 break;
110 case SMAPIOCGFUNCTION:
111 smapi32_offset = sc->smapi32_entry;
112 error = smapi32((struct smapi_bios_parameter *)data,
113 (struct smapi_bios_parameter *)data);
114 break;
115 default:
116 error = ENOTTY;
117 }
118
119 return (error);
120 }
121
122 static int
smapi_header_cksum(struct smapi_bios_header * header)123 smapi_header_cksum (struct smapi_bios_header *header)
124 {
125 u_int8_t *ptr;
126 u_int8_t cksum;
127 int i;
128
129 ptr = (u_int8_t *)header;
130 cksum = 0;
131 for (i = 0; i < header->length; i++) {
132 cksum += ptr[i];
133 }
134
135 return (cksum);
136 }
137
138 static void
smapi_identify(driver_t * driver,device_t parent)139 smapi_identify (driver_t *driver, device_t parent)
140 {
141 device_t child;
142 u_int32_t addr;
143 int length;
144 int rid;
145
146 if (!device_is_alive(parent))
147 return;
148
149 addr = bios_sigsearch(SMAPI_START, SMAPI_SIG, SMAPI_LEN,
150 SMAPI_STEP, SMAPI_OFF);
151 if (addr != 0) {
152 rid = 0;
153 length = ADDR2HDR(addr)->length;
154
155 child = BUS_ADD_CHILD(parent, 5, "smapi", -1);
156 device_set_driver(child, driver);
157 bus_set_resource(child, SYS_RES_MEMORY, rid, addr, length);
158 device_set_desc(child, "SMAPI BIOS");
159 }
160
161 return;
162 }
163
164 static int
smapi_probe(device_t dev)165 smapi_probe (device_t dev)
166 {
167 struct resource *res;
168 int rid;
169 int error;
170
171 error = 0;
172 rid = 0;
173 res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
174 if (res == NULL) {
175 device_printf(dev, "Unable to allocate memory resource.\n");
176 error = ENOMEM;
177 goto bad;
178 }
179
180 if (smapi_header_cksum(RES2HDR(res))) {
181 device_printf(dev, "SMAPI header checksum failed.\n");
182 error = ENXIO;
183 goto bad;
184 }
185
186 bad:
187 if (res)
188 bus_release_resource(dev, SYS_RES_MEMORY, rid, res);
189 return (error);
190 }
191
192 static int
smapi_attach(device_t dev)193 smapi_attach (device_t dev)
194 {
195 struct make_dev_args args;
196 struct smapi_softc *sc;
197 int error;
198
199 sc = device_get_softc(dev);
200 error = 0;
201
202 sc->dev = dev;
203 sc->rid = 0;
204 sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid,
205 RF_ACTIVE);
206 if (sc->res == NULL) {
207 device_printf(dev, "Unable to allocate memory resource.\n");
208 error = ENOMEM;
209 goto bad;
210 }
211 sc->header = (struct smapi_bios_header *)rman_get_virtual(sc->res);
212 sc->smapi32_entry = (u_int32_t)BIOS_PADDRTOVADDR(
213 sc->header->prot32_segment +
214 sc->header->prot32_offset);
215
216 make_dev_args_init(&args);
217 args.mda_devsw = &smapi_cdevsw;
218 args.mda_uid = UID_ROOT;
219 args.mda_gid = GID_WHEEL;
220 args.mda_mode = 0600;
221 args.mda_si_drv1 = sc;
222 error = make_dev_s(&args, &sc->cdev, "%s%d",
223 smapi_cdevsw.d_name,
224 device_get_unit(sc->dev));
225 if (error != 0)
226 goto bad;
227
228 device_printf(dev, "Version: %d.%02d, Length: %d, Checksum: 0x%02x\n",
229 bcd2bin(sc->header->version_major),
230 bcd2bin(sc->header->version_minor),
231 sc->header->length,
232 sc->header->checksum);
233 device_printf(dev, "Information=0x%b\n",
234 sc->header->information,
235 "\020"
236 "\001REAL_VM86"
237 "\002PROTECTED_16"
238 "\003PROTECTED_32");
239
240 if (bootverbose) {
241 if (sc->header->information & SMAPI_REAL_VM86)
242 device_printf(dev, "Real/VM86 mode: Segment 0x%04x, Offset 0x%04x\n",
243 sc->header->real16_segment,
244 sc->header->real16_offset);
245 if (sc->header->information & SMAPI_PROT_16BIT)
246 device_printf(dev, "16-bit Protected mode: Segment 0x%08x, Offset 0x%04x\n",
247 sc->header->prot16_segment,
248 sc->header->prot16_offset);
249 if (sc->header->information & SMAPI_PROT_32BIT)
250 device_printf(dev, "32-bit Protected mode: Segment 0x%08x, Offset 0x%08x\n",
251 sc->header->prot32_segment,
252 sc->header->prot32_offset);
253 }
254
255 return (0);
256 bad:
257 if (sc->res)
258 bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res);
259 return (error);
260 }
261
262 static int
smapi_detach(device_t dev)263 smapi_detach (device_t dev)
264 {
265 struct smapi_softc *sc;
266
267 sc = device_get_softc(dev);
268
269 destroy_dev(sc->cdev);
270
271 if (sc->res)
272 bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res);
273
274 return (0);
275 }
276
277 static device_method_t smapi_methods[] = {
278 /* Device interface */
279 DEVMETHOD(device_identify, smapi_identify),
280 DEVMETHOD(device_probe, smapi_probe),
281 DEVMETHOD(device_attach, smapi_attach),
282 DEVMETHOD(device_detach, smapi_detach),
283 { 0, 0 }
284 };
285
286 static driver_t smapi_driver = {
287 "smapi",
288 smapi_methods,
289 sizeof(struct smapi_softc),
290 };
291
292 static int
smapi_modevent(module_t mod,int what,void * arg)293 smapi_modevent (module_t mod, int what, void *arg)
294 {
295 device_t * devs;
296 int count;
297 int i;
298
299 switch (what) {
300 case MOD_LOAD:
301 break;
302 case MOD_UNLOAD:
303 devclass_get_devices(devclass_find(smapi_driver.name), &devs,
304 &count);
305 for (i = 0; i < count; i++) {
306 device_delete_child(device_get_parent(devs[i]), devs[i]);
307 }
308 free(devs, M_TEMP);
309 break;
310 default:
311 break;
312 }
313
314 return (0);
315 }
316
317 DRIVER_MODULE(smapi, nexus, smapi_driver, smapi_modevent, NULL);
318 MODULE_VERSION(smapi, 1);
319