xref: /netbsd-src/sys/arch/powerpc/powerpc/openfirm.c (revision 845bb89288536502a0ee02181ef1fd8d61eda8ea)
1 /*	$NetBSD: openfirm.c,v 1.33 2021/02/13 01:48:33 thorpej Exp $	*/
2 
3 /*
4  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5  * Copyright (C) 1995, 1996 TooLs GmbH.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by TooLs GmbH.
19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: openfirm.c,v 1.33 2021/02/13 01:48:33 thorpej Exp $");
36 
37 #ifdef _KERNEL_OPT
38 #include "opt_multiprocessor.h"
39 #endif
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 
44 #include <uvm/uvm_extern.h>
45 
46 #include <machine/psl.h>
47 #include <machine/autoconf.h>
48 
49 #include <dev/ofw/openfirm.h>
50 
51 char *OF_buf;
52 
53 static void ofbcopy(const void *, void *, size_t);
54 
55 #ifdef MULTIPROCESSOR
56 void OF_start_cpu(int, u_int, int);
57 
58 
59 static __cpu_simple_lock_t ofw_mutex = __SIMPLELOCK_UNLOCKED;
60 #endif /* MULTIPROCESSOR */
61 
62 static inline register_t
ofw_lock(void)63 ofw_lock(void)
64 {
65 	const register_t s = mfmsr();
66 
67 	mtmsr(s & ~(PSL_EE|PSL_RI));	/* disable interrupts */
68 
69 #ifdef MULTIPROCESSOR
70 	__cpu_simple_lock(&ofw_mutex);
71 #endif /* MULTIPROCESSOR */
72 
73 	return s;
74 }
75 
76 static inline void
ofw_unlock(register_t s)77 ofw_unlock(register_t s)
78 {
79 #ifdef MULTIPROCESSOR
80 	__cpu_simple_unlock(&ofw_mutex);
81 #endif /* MULTIPROCESSOR */
82 	mtmsr(s);
83 }
84 
85 int
OF_peer(int phandle)86 OF_peer(int phandle)
87 {
88 	static struct {
89 		const char *name;
90 		int nargs;
91 		int nreturns;
92 		int phandle;
93 		int sibling;
94 	} args = {
95 		"peer",
96 		1,
97 		1,
98 	};
99 
100 	const register_t s = ofw_lock();
101 	int rv;
102 
103 	args.phandle = phandle;
104 	if (openfirmware(&args) == -1)
105 		rv = 0;
106 	else
107 		rv = args.sibling;
108 
109 	ofw_unlock(s);
110 	return rv;
111 }
112 
113 int
OF_child(int phandle)114 OF_child(int phandle)
115 {
116 	static struct {
117 		const char *name;
118 		int nargs;
119 		int nreturns;
120 		int phandle;
121 		int child;
122 	} args = {
123 		"child",
124 		1,
125 		1,
126 	};
127 
128 	const register_t s = ofw_lock();
129 	int rv;
130 
131 	args.phandle = phandle;
132 	if (openfirmware(&args) == -1)
133 		rv = 0;
134 	else
135 		rv = args.child;
136 
137 	ofw_unlock(s);
138 	return rv;
139 }
140 
141 int
OF_parent(int phandle)142 OF_parent(int phandle)
143 {
144 	static struct {
145 		const char *name;
146 		int nargs;
147 		int nreturns;
148 		int phandle;
149 		int parent;
150 	} args = {
151 		"parent",
152 		1,
153 		1,
154 	};
155 
156 	const register_t s = ofw_lock();
157 	int rv;
158 
159 	args.phandle = phandle;
160 	if (openfirmware(&args) == -1)
161 		rv = 0;
162 	else
163 		rv = args.parent;
164 
165 	ofw_unlock(s);
166 	return rv;
167 }
168 
169 int
OF_instance_to_package(int ihandle)170 OF_instance_to_package(int ihandle)
171 {
172 	static struct {
173 		const char *name;
174 		int nargs;
175 		int nreturns;
176 		int ihandle;
177 		int phandle;
178 	} args = {
179 		"instance-to-package",
180 		1,
181 		1,
182 	};
183 
184 	const register_t s = ofw_lock();
185 	int rv;
186 
187 	args.ihandle = ihandle;
188 	if (openfirmware(&args) == -1)
189 		rv = -1;
190 	else
191 		rv = args.phandle;
192 
193 	ofw_unlock(s);
194 	return rv;
195 }
196 
197 int
OF_getproplen(int handle,const char * prop)198 OF_getproplen(int handle, const char *prop)
199 {
200 	static struct {
201 		const char *name;
202 		int nargs;
203 		int nreturns;
204 		int phandle;
205 		const char *prop;
206 		int proplen;
207 	} args = {
208 		"getproplen",
209 		2,
210 		1,
211 	};
212 
213 	const register_t s = ofw_lock();
214 	int rv;
215 
216 	strncpy(OF_buf, prop, 32);
217 	args.phandle = handle;
218 	args.prop = OF_buf;
219 	if (openfirmware(&args) == -1)
220 		rv = -1;
221 	else
222 		rv = args.proplen;
223 
224 	ofw_unlock(s);
225 	return rv;
226 }
227 
228 int
OF_getprop(int handle,const char * prop,void * buf,int buflen)229 OF_getprop(int handle, const char *prop, void *buf, int buflen)
230 {
231 	static struct {
232 		const char *name;
233 		int nargs;
234 		int nreturns;
235 		int phandle;
236 		const char *prop;
237 		void *buf;
238 		int buflen;
239 		int size;
240 	} args = {
241 		"getprop",
242 		4,
243 		1,
244 	};
245 
246 	if (buflen > PAGE_SIZE)
247 		return -1;
248 
249 	const register_t s = ofw_lock();
250 	int rv;
251 
252 	strncpy(OF_buf, prop, 32);
253 	args.phandle = handle;
254 	args.prop = OF_buf;
255 	args.buf = &OF_buf[33];
256 	args.buflen = buflen;
257 	if (openfirmware(&args) == -1)
258 		rv = -1;
259 	else {
260 		if (args.size > buflen)
261 			args.size = buflen;
262 		if (args.size > 0)
263 			ofbcopy(&OF_buf[33], buf, args.size);
264 		rv = args.size;
265 	}
266 
267 	ofw_unlock(s);
268 	return rv;
269 }
270 
271 int
OF_setprop(int handle,const char * prop,const void * buf,int buflen)272 OF_setprop(int handle, const char *prop, const void *buf, int buflen)
273 {
274 	struct {
275 		const char *name;
276 		int nargs;
277 		int nreturns;
278 		int phandle;
279 		const char *prop;
280 		const void *buf;
281 		int buflen;
282 		int size;
283 	} args = {
284 		"setprop",
285 		4,
286 		1
287 	};
288 
289 	if (buflen > PAGE_SIZE)
290 		return -1;
291 
292 	const register_t s = ofw_lock();
293 	int rv;
294 
295 	ofbcopy(buf, OF_buf, buflen);
296 	args.phandle = handle;
297 	args.prop = prop;
298 	args.buf = OF_buf;
299 	args.buflen = buflen;
300 	if (openfirmware(&args) == -1)
301 		rv = -1;
302 	else
303 		rv = args.size;
304 
305 	ofw_unlock(s);
306 	return rv;
307 }
308 
309 int
OF_nextprop(int handle,const char * prop,void * nextprop)310 OF_nextprop(int handle, const char *prop, void *nextprop)
311 {
312 	static struct {
313 		const char *name;
314 		int nargs;
315 		int nreturns;
316 		int phandle;
317 		const char *prop;
318 		char *buf;
319 		int flag;
320 	} args = {
321 		"nextprop",
322 		3,
323 		1,
324 	};
325 
326 	const register_t s = ofw_lock();
327 	int rv;
328 
329 	strncpy(OF_buf, prop, 32);
330 	args.phandle = handle;
331 	args.prop = OF_buf;
332 	args.buf = &OF_buf[33];
333 	if (openfirmware(&args) == -1)
334 		rv = -1;
335 	else {
336 		strncpy(nextprop, &OF_buf[33], 32);
337 		rv = args.flag;
338 	}
339 
340 	ofw_unlock(s);
341 	return rv;
342 }
343 
344 int
OF_finddevice(const char * name)345 OF_finddevice(const char *name)
346 {
347 	static struct {
348 		const char *name;
349 		int nargs;
350 		int nreturns;
351 		const char *device;
352 		int phandle;
353 	} args = {
354 		"finddevice",
355 		1,
356 		1,
357 	};
358 
359 	const register_t s = ofw_lock();
360 	int rv;
361 
362 	strncpy(OF_buf, name, NBPG);
363 	args.device = OF_buf;
364 	if (openfirmware(&args) == -1)
365 		rv = -1;
366 	else
367 		rv = args.phandle;
368 
369 	ofw_unlock(s);
370 	return rv;
371 }
372 
373 int
OF_instance_to_path(int ihandle,char * buf,int buflen)374 OF_instance_to_path(int ihandle, char *buf, int buflen)
375 {
376 	static struct {
377 		const char *name;
378 		int nargs;
379 		int nreturns;
380 		int ihandle;
381 		char *buf;
382 		int buflen;
383 		int length;
384 	} args = {
385 		"instance-to-path",
386 		3,
387 		1,
388 	};
389 
390 	if (buflen > PAGE_SIZE)
391 		return -1;
392 
393 	const register_t s = ofw_lock();
394 	int rv;
395 
396 	args.ihandle = ihandle;
397 	args.buf = OF_buf;
398 	args.buflen = buflen;
399 	if (openfirmware(&args) < 0)
400 		rv = -1;
401 	else {
402 		if (args.length > buflen)
403 			args.length = buflen;
404 		if (args.length > 0)
405 			ofbcopy(OF_buf, buf, args.length);
406 		rv = args.length;
407 	}
408 
409 	ofw_unlock(s);
410 	return rv;
411 }
412 
413 int
OF_package_to_path(int phandle,char * buf,int buflen)414 OF_package_to_path(int phandle, char *buf, int buflen)
415 {
416 	static struct {
417 		const char *name;
418 		int nargs;
419 		int nreturns;
420 		int phandle;
421 		char *buf;
422 		int buflen;
423 		int length;
424 	} args = {
425 		"package-to-path",
426 		3,
427 		1,
428 	};
429 
430 	if (buflen > PAGE_SIZE)
431 		return -1;
432 
433 	const register_t s = ofw_lock();
434 	int rv;
435 
436 	args.phandle = phandle;
437 	args.buf = OF_buf;
438 	args.buflen = buflen;
439 	if (openfirmware(&args) < 0)
440 		rv = -1;
441 	else {
442 		if (args.length > buflen)
443 			args.length = buflen;
444 		if (args.length > 0)
445 			ofbcopy(OF_buf, buf, args.length);
446 		rv = args.length;
447 	}
448 
449 	ofw_unlock(s);
450 	return rv;
451 }
452 
453 int
OF_call_method(const char * method,int ihandle,int nargs,int nreturns,...)454 OF_call_method(const char *method, int ihandle, int nargs, int nreturns, ...)
455 {
456 	static struct {
457 		const char *name;
458 		int nargs;
459 		int nreturns;
460 		const char *method;
461 		int ihandle;
462 		int args_n_results[12];
463 	} args = {
464 		"call-method",
465 		2,
466 		1,
467 	};
468 
469 	if (nargs > 6)
470 		return -1;
471 
472 	va_list ap;
473 	int *ip, n;
474 	int rv;
475 
476 	const register_t s = ofw_lock();
477 
478 	args.nargs = nargs + 2;
479 	args.nreturns = nreturns + 1;
480 	args.method = method;
481 	args.ihandle = ihandle;
482 
483 	va_start(ap, nreturns);
484 
485 	for (ip = args.args_n_results + (n = nargs); --n >= 0;) {
486 		*--ip = va_arg(ap, int);
487 	}
488 
489 	if (openfirmware(&args) == -1) {
490 		rv = -1;
491 	} else if (args.args_n_results[nargs]) {
492 		rv = args.args_n_results[nargs];
493 	} else {
494 		for (ip = args.args_n_results + nargs + (n = args.nreturns);
495 		     --n > 0;) {
496 			*va_arg(ap, int *) = *--ip;
497 		}
498 		rv = 0;
499 	}
500 
501 	va_end(ap);
502 
503 	ofw_unlock(s);
504 	return rv;
505 }
506 
507 int
OF_call_method_1(const char * method,int ihandle,int nargs,...)508 OF_call_method_1(const char *method, int ihandle, int nargs, ...)
509 {
510 	static struct {
511 		const char *name;
512 		int nargs;
513 		int nreturns;
514 		const char *method;
515 		int ihandle;
516 		int args_n_results[8];
517 	} args = {
518 		"call-method",
519 		2,
520 		2,
521 	};
522 
523 	if (nargs > 6)
524 		return -1;
525 
526 	va_list ap;
527 	int *ip, n;
528 	int rv;
529 
530 	const register_t s = ofw_lock();
531 
532 	args.nargs = nargs + 2;
533 	args.method = method;
534 	args.ihandle = ihandle;
535 
536 	va_start(ap, nargs);
537 	for (ip = args.args_n_results + (n = nargs); --n >= 0;) {
538 		*--ip = va_arg(ap, int);
539 	}
540 	va_end(ap);
541 
542 	if (openfirmware(&args) == -1)
543 		rv = -1;
544 	else if (args.args_n_results[nargs])
545 		rv = -1;
546 	else
547 		rv = args.args_n_results[nargs + 1];
548 
549 	ofw_unlock(s);
550 	return rv;
551 }
552 
553 int
OF_open(const char * dname)554 OF_open(const char *dname)
555 {
556 	static struct {
557 		const char *name;
558 		int nargs;
559 		int nreturns;
560 		const char *dname;
561 		int handle;
562 	} args = {
563 		"open",
564 		1,
565 		1,
566 	};
567 	int l;
568 
569 	if ((l = strlen(dname)) >= PAGE_SIZE)
570 		return -1;
571 
572 	const register_t s = ofw_lock();
573 	int rv;
574 
575 	ofbcopy(dname, OF_buf, l + 1);
576 	args.dname = OF_buf;
577 	if (openfirmware(&args) == -1)
578 		rv = -1;
579 	else
580 		rv = args.handle;
581 
582 	ofw_unlock(s);
583 	return rv;
584 }
585 
586 void
OF_close(int handle)587 OF_close(int handle)
588 {
589 	static struct {
590 		const char *name;
591 		int nargs;
592 		int nreturns;
593 		int handle;
594 	} args = {
595 		"close",
596 		1,
597 		0,
598 	};
599 
600 	const register_t s = ofw_lock();
601 
602 	args.handle = handle;
603 	openfirmware(&args);
604 
605 	ofw_unlock(s);
606 }
607 
608 /*
609  * This assumes that character devices don't read in multiples of PAGE_SIZE.
610  */
611 int
OF_read(int handle,void * addr,int len)612 OF_read(int handle, void *addr, int len)
613 {
614 	static struct {
615 		const char *name;
616 		int nargs;
617 		int nreturns;
618 		int ihandle;
619 		void *addr;
620 		int len;
621 		int actual;
622 	} args = {
623 		"read",
624 		3,
625 		1,
626 	};
627 	int l, act = 0;
628 	char *p = addr;
629 
630 	const register_t s = ofw_lock();
631 
632 	args.ihandle = handle;
633 	args.addr = OF_buf;
634 	for (; len > 0; len -= l, p += l) {
635 		l = uimin(PAGE_SIZE, len);
636 		args.len = l;
637 		if (openfirmware(&args) == -1) {
638 			act = -1;
639 			goto out;
640 		}
641 		if (args.actual > 0) {
642 			ofbcopy(OF_buf, p, args.actual);
643 			act += args.actual;
644 		}
645 		if (args.actual < l) {
646 			if (act == 0) {
647 				act = args.actual;
648 			}
649 			goto out;
650 		}
651 	}
652 
653  out:
654 	ofw_unlock(s);
655 	return act;
656 }
657 
658 int
OF_write(int handle,const void * addr,int len)659 OF_write(int handle, const void *addr, int len)
660 {
661 	static struct {
662 		const char *name;
663 		int nargs;
664 		int nreturns;
665 		int ihandle;
666 		void *addr;
667 		int len;
668 		int actual;
669 	} args = {
670 		"write",
671 		3,
672 		1,
673 	};
674 	int l, act = 0;
675 	const char *p = addr;
676 
677 	const register_t s = ofw_lock();
678 
679 	args.ihandle = handle;
680 	args.addr = OF_buf;
681 	for (; len > 0; len -= l, p += l) {
682 		l = uimin(PAGE_SIZE, len);
683 		ofbcopy(p, OF_buf, l);
684 		args.len = l;
685 		args.actual = l;	/* work around a PIBS bug */
686 		if (openfirmware(&args) == -1) {
687 			act = -1;
688 			goto out;
689 		}
690 		l = args.actual;
691 		act += l;
692 	}
693 
694  out:
695 	ofw_unlock(s);
696 	return act;
697 }
698 
699 int
OF_seek(int handle,u_quad_t pos)700 OF_seek(int handle, u_quad_t pos)
701 {
702 	static struct {
703 		const char *name;
704 		int nargs;
705 		int nreturns;
706 		int handle;
707 		int poshi;
708 		int poslo;
709 		int status;
710 	} args = {
711 		"seek",
712 		3,
713 		1,
714 	};
715 
716 	const register_t s = ofw_lock();
717 	int rv;
718 
719 	args.handle = handle;
720 	args.poshi = (int)(pos >> 32);
721 	args.poslo = (int)pos;
722 	if (openfirmware(&args) == -1)
723 		rv = -1;
724 	else
725 		rv = args.status;
726 
727 	ofw_unlock(s);
728 	return rv;
729 }
730 
731 #ifdef MULTIPROCESSOR
732 void
OF_start_cpu(int phandle,u_int pc,int arg)733 OF_start_cpu(int phandle, u_int pc, int arg)
734 {
735 	static struct {
736 		const char *name;
737 		int nargs;
738 		int nreturns;
739 		int phandle;
740 		u_int pc;
741 		int arg;
742 	} args = {
743 		"start-cpu",
744 		3,
745 		0,
746 	};
747 
748 	const register_t s = ofw_lock();
749 	bool failed = false;
750 
751 	args.phandle = phandle;
752 	args.pc = pc;
753 	args.arg = arg;
754 	if (openfirmware(&args) == -1)
755 		failed = true;
756 
757 	ofw_unlock(s);
758 	if (failed) {
759 		panic("WTF?");
760 	}
761 }
762 #endif
763 
764 void
OF_boot(const char * bstr)765 OF_boot(const char *bstr)
766 {
767 	static struct {
768 		const char *name;
769 		int nargs;
770 		int nreturns;
771 		char *bootspec;
772 	} args = {
773 		"boot",
774 		1,
775 		0,
776 	};
777 	int l;
778 
779 	if ((l = strlen(bstr)) >= PAGE_SIZE)
780 		panic("OF_boot");
781 
782 	const register_t s = ofw_lock();
783 
784 	ofbcopy(bstr, OF_buf, l + 1);
785 	args.bootspec = OF_buf;
786 	openfirmware(&args);
787 
788 	ofw_unlock(s);
789 	panic("OF_boot didn't");
790 }
791 
792 void
OF_enter(void)793 OF_enter(void)
794 {
795 	static struct {
796 		const char *name;
797 		int nargs;
798 		int nreturns;
799 	} args = {
800 		"enter",
801 		0,
802 		0,
803 	};
804 
805 	const register_t s = ofw_lock();
806 
807 	openfirmware(&args);
808 
809 	ofw_unlock(s);
810 }
811 
812 void
OF_exit(void)813 OF_exit(void)
814 {
815 	static struct {
816 		const char *name;
817 		int nargs;
818 		int nreturns;
819 	} args = {
820 		"exit",
821 		0,
822 		0,
823 	};
824 
825 	const register_t s = ofw_lock();
826 
827 	openfirmware(&args);
828 
829 	ofw_unlock(s);
830 	while (1);			/* just in case */
831 }
832 
833 void
OF_set_callback(void (* newfunc)(void *))834 (*OF_set_callback (void (*newfunc)(void *))) (void *)
835 {
836 	static struct {
837 		const char *name;
838 		int nargs;
839 		int nreturns;
840 		void (*newfunc)(void *);
841 		void (*oldfunc)(void *);
842 	} args = {
843 		"set-callback",
844 		1,
845 		1,
846 	};
847 
848 	const register_t s = ofw_lock();
849 	void (*rv)(void *);
850 
851 	args.newfunc = newfunc;
852 	if (openfirmware(&args) == -1)
853 		rv = NULL;
854 	else
855 		rv = args.oldfunc;
856 
857 	ofw_unlock(s);
858 	return rv;
859 }
860 
861 int
OF_interpret(const char * cmd,int nargs,int nreturns,...)862 OF_interpret(const char *cmd, int nargs, int nreturns, ...)
863 {
864 	static struct {
865 		const char *name;
866 		uint32_t nargs;
867 		uint32_t nreturns;
868 		uint32_t slots[16];
869 	} args = {
870 		"interpret",
871 		1,
872 		2,
873 	};
874 
875 	va_list ap;
876 	int i, len;
877 	int rv;
878 
879 	if (nreturns > 8)
880 		return -1;
881 	if ((len = strlen(cmd)) >= PAGE_SIZE)
882 		return -1;
883 
884 	const register_t s = ofw_lock();
885 
886 	ofbcopy(cmd, OF_buf, len + 1);
887 	i = 0;
888 	args.slots[i] = (uintptr_t)OF_buf;
889 	args.nargs = nargs + 1;
890 	args.nreturns = nreturns + 1;
891 	va_start(ap, nreturns);
892 	i++;
893 	while (i < args.nargs) {
894 		args.slots[i] = (uintptr_t)va_arg(ap, uint32_t *);
895 		i++;
896 	}
897 
898 	if (openfirmware(&args) == -1)
899 		rv = -1;
900 	else {
901 		rv = args.slots[i];
902 		i++;
903 
904 		while (i < args.nargs + args.nreturns) {
905 			*va_arg(ap, uint32_t *) = args.slots[i];
906 			i++;
907 		}
908 	}
909 	va_end(ap);
910 
911 	ofw_unlock(s);
912 	return rv;
913 }
914 
915 void
OF_quiesce(void)916 OF_quiesce(void)
917 {
918 	static struct {
919 		const char *name;
920 		int nargs;
921 		int nreturns;
922 	} args = {
923 		"quiesce",
924 		0,
925 		0,
926 	};
927 
928 	const register_t s = ofw_lock();
929 
930 	openfirmware(&args);
931 
932 	ofw_unlock(s);
933 }
934 
935 /*
936  * This version of bcopy doesn't work for overlapping regions!
937  */
938 static void
ofbcopy(const void * src,void * dst,size_t len)939 ofbcopy(const void *src, void *dst, size_t len)
940 {
941 	const char *sp = src;
942 	char *dp = dst;
943 
944 	if (src == dst)
945 		return;
946 
947 	while (len-- > 0)
948 		*dp++ = *sp++;
949 }
950