xref: /freebsd/sys/x86/include/bus.h (revision e32fecd0c2c3ee37c47ee100f169e7eb0282a873)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause AND BSD-2-Clause-NetBSDE
3  *
4  * Copyright (c) KATO Takenori, 1999.
5  *
6  * All rights reserved.  Unpublished rights reserved under the copyright
7  * laws of Japan.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer as
15  *    the first lines of this file unmodified.
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. The name of the author 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 THE AUTHOR ``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 THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * $FreeBSD$
34  */
35 
36 /*	$NetBSD: bus.h,v 1.12 1997/10/01 08:25:15 fvdl Exp $	*/
37 
38 /*-
39  * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
40  * All rights reserved.
41  *
42  * This code is derived from software contributed to The NetBSD Foundation
43  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
44  * NASA Ames Research Center.
45  *
46  * Redistribution and use in source and binary forms, with or without
47  * modification, are permitted provided that the following conditions
48  * are met:
49  * 1. Redistributions of source code must retain the above copyright
50  *    notice, this list of conditions and the following disclaimer.
51  * 2. Redistributions in binary form must reproduce the above copyright
52  *    notice, this list of conditions and the following disclaimer in the
53  *    documentation and/or other materials provided with the distribution.
54  *
55  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
56  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
57  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
58  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
59  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
60  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
61  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
62  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
63  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
64  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
65  * POSSIBILITY OF SUCH DAMAGE.
66  */
67 
68 /*-
69  * Copyright (c) 1996 Charles M. Hannum.  All rights reserved.
70  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
71  *
72  * Redistribution and use in source and binary forms, with or without
73  * modification, are permitted provided that the following conditions
74  * are met:
75  * 1. Redistributions of source code must retain the above copyright
76  *    notice, this list of conditions and the following disclaimer.
77  * 2. Redistributions in binary form must reproduce the above copyright
78  *    notice, this list of conditions and the following disclaimer in the
79  *    documentation and/or other materials provided with the distribution.
80  * 3. All advertising materials mentioning features or use of this software
81  *    must display the following acknowledgement:
82  *      This product includes software developed by Christopher G. Demetriou
83  *	for the NetBSD Project.
84  * 4. The name of the author may not be used to endorse or promote products
85  *    derived from this software without specific prior written permission
86  *
87  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
88  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
89  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
90  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
91  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
92  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
93  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
94  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
95  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
96  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
97  */
98 
99 #ifndef _MACHINE_BUS_H_
100 #define _MACHINE_BUS_H_
101 
102 #include <machine/_bus.h>
103 #include <machine/cpufunc.h>
104 #include <machine/bus_dma.h>
105 
106 /*
107  * Values for the x86 bus space tag, not to be used directly by MI code.
108  */
109 #define	X86_BUS_SPACE_IO	0	/* space is i/o space */
110 #define	X86_BUS_SPACE_MEM	1	/* space is mem space */
111 
112 #define BUS_SPACE_MAXSIZE_24BIT	0xFFFFFF
113 #define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF
114 #if defined(__amd64__)
115 #define BUS_SPACE_MAXSIZE	0xFFFFFFFFFFFFFFFFULL
116 #else
117 #define BUS_SPACE_MAXSIZE	0xFFFFFFFF
118 #endif
119 #define BUS_SPACE_MAXADDR_24BIT	0xFFFFFF
120 #define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF
121 #if defined(__amd64__) || defined(PAE)
122 #define BUS_SPACE_MAXADDR_48BIT	0xFFFFFFFFFFFFULL
123 #define BUS_SPACE_MAXADDR	0xFFFFFFFFFFFFFFFFULL
124 #else
125 #define BUS_SPACE_MAXADDR	0xFFFFFFFF
126 #endif
127 
128 #define BUS_SPACE_INVALID_DATA	(~0)
129 #define BUS_SPACE_UNRESTRICTED	(~0)
130 
131 #define	BUS_SPACE_BARRIER_READ	0x01		/* force read barrier */
132 #define	BUS_SPACE_BARRIER_WRITE	0x02		/* force write barrier */
133 
134 #if defined(SAN_NEEDS_INTERCEPTORS) && !defined(SAN_RUNTIME)
135 #include <sys/bus_san.h>
136 #else
137 
138 /*
139  * Map a region of device bus space into CPU virtual address space.
140  */
141 
142 int bus_space_map(bus_space_tag_t tag, bus_addr_t addr, bus_size_t size,
143     int flags, bus_space_handle_t *bshp);
144 
145 /*
146  * Unmap a region of device bus space.
147  */
148 
149 void bus_space_unmap(bus_space_tag_t tag, bus_space_handle_t bsh,
150     bus_size_t size);
151 
152 /*
153  * Get a new handle for a subregion of an already-mapped area of bus space.
154  */
155 
156 static __inline int bus_space_subregion(bus_space_tag_t t,
157 					bus_space_handle_t bsh,
158 					bus_size_t offset, bus_size_t size,
159 					bus_space_handle_t *nbshp);
160 
161 static __inline int
162 bus_space_subregion(bus_space_tag_t t __unused, bus_space_handle_t bsh,
163 		    bus_size_t offset, bus_size_t size __unused,
164 		    bus_space_handle_t *nbshp)
165 {
166 
167 	*nbshp = bsh + offset;
168 	return (0);
169 }
170 
171 /*
172  * Allocate a region of memory that is accessible to devices in bus space.
173  */
174 
175 int	bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart,
176 			bus_addr_t rend, bus_size_t size, bus_size_t align,
177 			bus_size_t boundary, int flags, bus_addr_t *addrp,
178 			bus_space_handle_t *bshp);
179 
180 /*
181  * Free a region of bus space accessible memory.
182  */
183 
184 static __inline void bus_space_free(bus_space_tag_t t, bus_space_handle_t bsh,
185 				    bus_size_t size);
186 
187 static __inline void
188 bus_space_free(bus_space_tag_t t __unused, bus_space_handle_t bsh __unused,
189 	       bus_size_t size __unused)
190 {
191 }
192 
193 /*
194  * Read a 1, 2, 4, or 8 byte quantity from bus space
195  * described by tag/handle/offset.
196  */
197 static __inline u_int8_t bus_space_read_1(bus_space_tag_t tag,
198 					  bus_space_handle_t handle,
199 					  bus_size_t offset);
200 
201 static __inline u_int16_t bus_space_read_2(bus_space_tag_t tag,
202 					   bus_space_handle_t handle,
203 					   bus_size_t offset);
204 
205 static __inline u_int32_t bus_space_read_4(bus_space_tag_t tag,
206 					   bus_space_handle_t handle,
207 					   bus_size_t offset);
208 
209 #ifdef __amd64__
210 static __inline uint64_t bus_space_read_8(bus_space_tag_t tag,
211 					  bus_space_handle_t handle,
212 					  bus_size_t offset);
213 #endif
214 
215 static __inline u_int8_t
216 bus_space_read_1(bus_space_tag_t tag, bus_space_handle_t handle,
217 		 bus_size_t offset)
218 {
219 
220 	if (tag == X86_BUS_SPACE_IO)
221 		return (inb(handle + offset));
222 	return (*(volatile u_int8_t *)(handle + offset));
223 }
224 
225 static __inline u_int16_t
226 bus_space_read_2(bus_space_tag_t tag, bus_space_handle_t handle,
227 		 bus_size_t offset)
228 {
229 
230 	if (tag == X86_BUS_SPACE_IO)
231 		return (inw(handle + offset));
232 	return (*(volatile u_int16_t *)(handle + offset));
233 }
234 
235 static __inline u_int32_t
236 bus_space_read_4(bus_space_tag_t tag, bus_space_handle_t handle,
237 		 bus_size_t offset)
238 {
239 
240 	if (tag == X86_BUS_SPACE_IO)
241 		return (inl(handle + offset));
242 	return (*(volatile u_int32_t *)(handle + offset));
243 }
244 
245 #ifdef __amd64__
246 static __inline uint64_t
247 bus_space_read_8(bus_space_tag_t tag, bus_space_handle_t handle,
248 		 bus_size_t offset)
249 {
250 
251 	if (tag == X86_BUS_SPACE_IO) /* No 8 byte IO space access on x86 */
252 		return (BUS_SPACE_INVALID_DATA);
253 	return (*(volatile uint64_t *)(handle + offset));
254 }
255 #endif
256 
257 /*
258  * Read `count' 1, 2, 4, or 8 byte quantities from bus space
259  * described by tag/handle/offset and copy into buffer provided.
260  */
261 static __inline void bus_space_read_multi_1(bus_space_tag_t tag,
262 					    bus_space_handle_t bsh,
263 					    bus_size_t offset, u_int8_t *addr,
264 					    size_t count);
265 
266 static __inline void bus_space_read_multi_2(bus_space_tag_t tag,
267 					    bus_space_handle_t bsh,
268 					    bus_size_t offset, u_int16_t *addr,
269 					    size_t count);
270 
271 static __inline void bus_space_read_multi_4(bus_space_tag_t tag,
272 					    bus_space_handle_t bsh,
273 					    bus_size_t offset, u_int32_t *addr,
274 					    size_t count);
275 
276 static __inline void
277 bus_space_read_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh,
278 		       bus_size_t offset, u_int8_t *addr, size_t count)
279 {
280 
281 	if (tag == X86_BUS_SPACE_IO)
282 		insb(bsh + offset, addr, count);
283 	else {
284 		__asm __volatile("				\n\
285 		1:	movb (%2),%%al				\n\
286 			stosb					\n\
287 			loop 1b"				:
288 		    "=D" (addr), "=c" (count)			:
289 		    "r" (bsh + offset), "0" (addr), "1" (count)	:
290 		    "%eax", "memory");
291 	}
292 }
293 
294 static __inline void
295 bus_space_read_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh,
296 		       bus_size_t offset, u_int16_t *addr, size_t count)
297 {
298 
299 	if (tag == X86_BUS_SPACE_IO)
300 		insw(bsh + offset, addr, count);
301 	else {
302 		__asm __volatile("				\n\
303 		1:	movw (%2),%%ax				\n\
304 			stosw					\n\
305 			loop 1b"				:
306 		    "=D" (addr), "=c" (count)			:
307 		    "r" (bsh + offset), "0" (addr), "1" (count)	:
308 		    "%eax", "memory");
309 	}
310 }
311 
312 static __inline void
313 bus_space_read_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh,
314 		       bus_size_t offset, u_int32_t *addr, size_t count)
315 {
316 
317 	if (tag == X86_BUS_SPACE_IO)
318 		insl(bsh + offset, addr, count);
319 	else {
320 		__asm __volatile("				\n\
321 		1:	movl (%2),%%eax				\n\
322 			stosl					\n\
323 			loop 1b"				:
324 		    "=D" (addr), "=c" (count)			:
325 		    "r" (bsh + offset), "0" (addr), "1" (count)	:
326 		    "%eax", "memory");
327 	}
328 }
329 
330 #if 0	/* Cause a link error for bus_space_read_multi_8 */
331 #define	bus_space_read_multi_8	!!! bus_space_read_multi_8 unimplemented !!!
332 #endif
333 
334 /*
335  * Read `count' 1, 2, 4, or 8 byte quantities from bus space
336  * described by tag/handle and starting at `offset' and copy into
337  * buffer provided.
338  */
339 static __inline void bus_space_read_region_1(bus_space_tag_t tag,
340 					     bus_space_handle_t bsh,
341 					     bus_size_t offset, u_int8_t *addr,
342 					     size_t count);
343 
344 static __inline void bus_space_read_region_2(bus_space_tag_t tag,
345 					     bus_space_handle_t bsh,
346 					     bus_size_t offset, u_int16_t *addr,
347 					     size_t count);
348 
349 static __inline void bus_space_read_region_4(bus_space_tag_t tag,
350 					     bus_space_handle_t bsh,
351 					     bus_size_t offset, u_int32_t *addr,
352 					     size_t count);
353 
354 static __inline void
355 bus_space_read_region_1(bus_space_tag_t tag, bus_space_handle_t bsh,
356 			bus_size_t offset, u_int8_t *addr, size_t count)
357 {
358 
359 	if (tag == X86_BUS_SPACE_IO) {
360 		int _port_ = bsh + offset;
361 		__asm __volatile("				\n\
362 		1:	inb %w2,%%al				\n\
363 			stosb					\n\
364 			incl %2					\n\
365 			loop 1b"				:
366 		    "=D" (addr), "=c" (count), "=d" (_port_)	:
367 		    "0" (addr), "1" (count), "2" (_port_)	:
368 		    "%eax", "memory", "cc");
369 	} else {
370 		bus_space_handle_t _port_ = bsh + offset;
371 		__asm __volatile("				\n\
372 			repne					\n\
373 			movsb"					:
374 		    "=D" (addr), "=c" (count), "=S" (_port_)	:
375 		    "0" (addr), "1" (count), "2" (_port_)	:
376 		    "memory", "cc");
377 	}
378 }
379 
380 static __inline void
381 bus_space_read_region_2(bus_space_tag_t tag, bus_space_handle_t bsh,
382 			bus_size_t offset, u_int16_t *addr, size_t count)
383 {
384 
385 	if (tag == X86_BUS_SPACE_IO) {
386 		int _port_ = bsh + offset;
387 		__asm __volatile("				\n\
388 		1:	inw %w2,%%ax				\n\
389 			stosw					\n\
390 			addl $2,%2				\n\
391 			loop 1b"				:
392 		    "=D" (addr), "=c" (count), "=d" (_port_)	:
393 		    "0" (addr), "1" (count), "2" (_port_)	:
394 		    "%eax", "memory", "cc");
395 	} else {
396 		bus_space_handle_t _port_ = bsh + offset;
397 		__asm __volatile("				\n\
398 			repne					\n\
399 			movsw"					:
400 		    "=D" (addr), "=c" (count), "=S" (_port_)	:
401 		    "0" (addr), "1" (count), "2" (_port_)	:
402 		    "memory", "cc");
403 	}
404 }
405 
406 static __inline void
407 bus_space_read_region_4(bus_space_tag_t tag, bus_space_handle_t bsh,
408 			bus_size_t offset, u_int32_t *addr, size_t count)
409 {
410 
411 	if (tag == X86_BUS_SPACE_IO) {
412 		int _port_ = bsh + offset;
413 		__asm __volatile("				\n\
414 		1:	inl %w2,%%eax				\n\
415 			stosl					\n\
416 			addl $4,%2				\n\
417 			loop 1b"				:
418 		    "=D" (addr), "=c" (count), "=d" (_port_)	:
419 		    "0" (addr), "1" (count), "2" (_port_)	:
420 		    "%eax", "memory", "cc");
421 	} else {
422 		bus_space_handle_t _port_ = bsh + offset;
423 		__asm __volatile("				\n\
424 			repne					\n\
425 			movsl"					:
426 		    "=D" (addr), "=c" (count), "=S" (_port_)	:
427 		    "0" (addr), "1" (count), "2" (_port_)	:
428 		    "memory", "cc");
429 	}
430 }
431 
432 #if 0	/* Cause a link error for bus_space_read_region_8 */
433 #define	bus_space_read_region_8	!!! bus_space_read_region_8 unimplemented !!!
434 #endif
435 
436 /*
437  * Write the 1, 2, 4, or 8 byte value `value' to bus space
438  * described by tag/handle/offset.
439  */
440 
441 static __inline void bus_space_write_1(bus_space_tag_t tag,
442 				       bus_space_handle_t bsh,
443 				       bus_size_t offset, u_int8_t value);
444 
445 static __inline void bus_space_write_2(bus_space_tag_t tag,
446 				       bus_space_handle_t bsh,
447 				       bus_size_t offset, u_int16_t value);
448 
449 static __inline void bus_space_write_4(bus_space_tag_t tag,
450 				       bus_space_handle_t bsh,
451 				       bus_size_t offset, u_int32_t value);
452 
453 #ifdef __amd64__
454 static __inline void bus_space_write_8(bus_space_tag_t tag,
455 				       bus_space_handle_t bsh,
456 				       bus_size_t offset, uint64_t value);
457 #endif
458 
459 static __inline void
460 bus_space_write_1(bus_space_tag_t tag, bus_space_handle_t bsh,
461 		       bus_size_t offset, u_int8_t value)
462 {
463 
464 	if (tag == X86_BUS_SPACE_IO)
465 		outb(bsh + offset, value);
466 	else
467 		*(volatile u_int8_t *)(bsh + offset) = value;
468 }
469 
470 static __inline void
471 bus_space_write_2(bus_space_tag_t tag, bus_space_handle_t bsh,
472 		       bus_size_t offset, u_int16_t value)
473 {
474 
475 	if (tag == X86_BUS_SPACE_IO)
476 		outw(bsh + offset, value);
477 	else
478 		*(volatile u_int16_t *)(bsh + offset) = value;
479 }
480 
481 static __inline void
482 bus_space_write_4(bus_space_tag_t tag, bus_space_handle_t bsh,
483 		       bus_size_t offset, u_int32_t value)
484 {
485 
486 	if (tag == X86_BUS_SPACE_IO)
487 		outl(bsh + offset, value);
488 	else
489 		*(volatile u_int32_t *)(bsh + offset) = value;
490 }
491 
492 #ifdef __amd64__
493 static __inline void
494 bus_space_write_8(bus_space_tag_t tag, bus_space_handle_t bsh,
495 		  bus_size_t offset, uint64_t value)
496 {
497 
498 	if (tag == X86_BUS_SPACE_IO) /* No 8 byte IO space access on x86 */
499 		return;
500 	else
501 		*(volatile uint64_t *)(bsh + offset) = value;
502 }
503 #endif
504 
505 /*
506  * Write `count' 1, 2, 4, or 8 byte quantities from the buffer
507  * provided to bus space described by tag/handle/offset.
508  */
509 
510 static __inline void bus_space_write_multi_1(bus_space_tag_t tag,
511 					     bus_space_handle_t bsh,
512 					     bus_size_t offset,
513 					     const u_int8_t *addr,
514 					     size_t count);
515 static __inline void bus_space_write_multi_2(bus_space_tag_t tag,
516 					     bus_space_handle_t bsh,
517 					     bus_size_t offset,
518 					     const u_int16_t *addr,
519 					     size_t count);
520 
521 static __inline void bus_space_write_multi_4(bus_space_tag_t tag,
522 					     bus_space_handle_t bsh,
523 					     bus_size_t offset,
524 					     const u_int32_t *addr,
525 					     size_t count);
526 
527 static __inline void
528 bus_space_write_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh,
529 			bus_size_t offset, const u_int8_t *addr, size_t count)
530 {
531 
532 	if (tag == X86_BUS_SPACE_IO)
533 		outsb(bsh + offset, addr, count);
534 	else {
535 		__asm __volatile("				\n\
536 		1:	lodsb					\n\
537 			movb %%al,(%2)				\n\
538 			loop 1b"				:
539 		    "=S" (addr), "=c" (count)			:
540 		    "r" (bsh + offset), "0" (addr), "1" (count)	:
541 		    "%eax", "memory", "cc");
542 	}
543 }
544 
545 static __inline void
546 bus_space_write_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh,
547 			bus_size_t offset, const u_int16_t *addr, size_t count)
548 {
549 
550 	if (tag == X86_BUS_SPACE_IO)
551 		outsw(bsh + offset, addr, count);
552 	else {
553 		__asm __volatile("				\n\
554 		1:	lodsw					\n\
555 			movw %%ax,(%2)				\n\
556 			loop 1b"				:
557 		    "=S" (addr), "=c" (count)			:
558 		    "r" (bsh + offset), "0" (addr), "1" (count)	:
559 		    "%eax", "memory", "cc");
560 	}
561 }
562 
563 static __inline void
564 bus_space_write_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh,
565 			bus_size_t offset, const u_int32_t *addr, size_t count)
566 {
567 
568 	if (tag == X86_BUS_SPACE_IO)
569 		outsl(bsh + offset, addr, count);
570 	else {
571 		__asm __volatile("				\n\
572 		1:	lodsl					\n\
573 			movl %%eax,(%2)				\n\
574 			loop 1b"				:
575 		    "=S" (addr), "=c" (count)			:
576 		    "r" (bsh + offset), "0" (addr), "1" (count)	:
577 		    "%eax", "memory", "cc");
578 	}
579 }
580 
581 #if 0	/* Cause a link error for bus_space_write_multi_8 */
582 #define	bus_space_write_multi_8(t, h, o, a, c)				\
583 			!!! bus_space_write_multi_8 unimplemented !!!
584 #endif
585 
586 /*
587  * Write `count' 1, 2, 4, or 8 byte quantities from the buffer provided
588  * to bus space described by tag/handle starting at `offset'.
589  */
590 
591 static __inline void bus_space_write_region_1(bus_space_tag_t tag,
592 					      bus_space_handle_t bsh,
593 					      bus_size_t offset,
594 					      const u_int8_t *addr,
595 					      size_t count);
596 static __inline void bus_space_write_region_2(bus_space_tag_t tag,
597 					      bus_space_handle_t bsh,
598 					      bus_size_t offset,
599 					      const u_int16_t *addr,
600 					      size_t count);
601 static __inline void bus_space_write_region_4(bus_space_tag_t tag,
602 					      bus_space_handle_t bsh,
603 					      bus_size_t offset,
604 					      const u_int32_t *addr,
605 					      size_t count);
606 
607 static __inline void
608 bus_space_write_region_1(bus_space_tag_t tag, bus_space_handle_t bsh,
609 			 bus_size_t offset, const u_int8_t *addr, size_t count)
610 {
611 
612 	if (tag == X86_BUS_SPACE_IO) {
613 		int _port_ = bsh + offset;
614 		__asm __volatile("				\n\
615 		1:	lodsb					\n\
616 			outb %%al,%w0				\n\
617 			incl %0					\n\
618 			loop 1b"				:
619 		    "=d" (_port_), "=S" (addr), "=c" (count)	:
620 		    "0" (_port_), "1" (addr), "2" (count)	:
621 		    "%eax", "memory", "cc");
622 	} else {
623 		bus_space_handle_t _port_ = bsh + offset;
624 		__asm __volatile("				\n\
625 			repne					\n\
626 			movsb"					:
627 		    "=D" (_port_), "=S" (addr), "=c" (count)	:
628 		    "0" (_port_), "1" (addr), "2" (count)	:
629 		    "memory", "cc");
630 	}
631 }
632 
633 static __inline void
634 bus_space_write_region_2(bus_space_tag_t tag, bus_space_handle_t bsh,
635 			 bus_size_t offset, const u_int16_t *addr, size_t count)
636 {
637 
638 	if (tag == X86_BUS_SPACE_IO) {
639 		int _port_ = bsh + offset;
640 		__asm __volatile("				\n\
641 		1:	lodsw					\n\
642 			outw %%ax,%w0				\n\
643 			addl $2,%0				\n\
644 			loop 1b"				:
645 		    "=d" (_port_), "=S" (addr), "=c" (count)	:
646 		    "0" (_port_), "1" (addr), "2" (count)	:
647 		    "%eax", "memory", "cc");
648 	} else {
649 		bus_space_handle_t _port_ = bsh + offset;
650 		__asm __volatile("				\n\
651 			repne					\n\
652 			movsw"					:
653 		    "=D" (_port_), "=S" (addr), "=c" (count)	:
654 		    "0" (_port_), "1" (addr), "2" (count)	:
655 		    "memory", "cc");
656 	}
657 }
658 
659 static __inline void
660 bus_space_write_region_4(bus_space_tag_t tag, bus_space_handle_t bsh,
661 			 bus_size_t offset, const u_int32_t *addr, size_t count)
662 {
663 
664 	if (tag == X86_BUS_SPACE_IO) {
665 		int _port_ = bsh + offset;
666 		__asm __volatile("				\n\
667 		1:	lodsl					\n\
668 			outl %%eax,%w0				\n\
669 			addl $4,%0				\n\
670 			loop 1b"				:
671 		    "=d" (_port_), "=S" (addr), "=c" (count)	:
672 		    "0" (_port_), "1" (addr), "2" (count)	:
673 		    "%eax", "memory", "cc");
674 	} else {
675 		bus_space_handle_t _port_ = bsh + offset;
676 		__asm __volatile("				\n\
677 			repne					\n\
678 			movsl"					:
679 		    "=D" (_port_), "=S" (addr), "=c" (count)	:
680 		    "0" (_port_), "1" (addr), "2" (count)	:
681 		    "memory", "cc");
682 	}
683 }
684 
685 #if 0	/* Cause a link error for bus_space_write_region_8 */
686 #define	bus_space_write_region_8					\
687 			!!! bus_space_write_region_8 unimplemented !!!
688 #endif
689 
690 /*
691  * Write the 1, 2, 4, or 8 byte value `val' to bus space described
692  * by tag/handle/offset `count' times.
693  */
694 
695 static __inline void bus_space_set_multi_1(bus_space_tag_t tag,
696 					   bus_space_handle_t bsh,
697 					   bus_size_t offset,
698 					   u_int8_t value, size_t count);
699 static __inline void bus_space_set_multi_2(bus_space_tag_t tag,
700 					   bus_space_handle_t bsh,
701 					   bus_size_t offset,
702 					   u_int16_t value, size_t count);
703 static __inline void bus_space_set_multi_4(bus_space_tag_t tag,
704 					   bus_space_handle_t bsh,
705 					   bus_size_t offset,
706 					   u_int32_t value, size_t count);
707 
708 static __inline void
709 bus_space_set_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh,
710 		      bus_size_t offset, u_int8_t value, size_t count)
711 {
712 	bus_space_handle_t addr = bsh + offset;
713 
714 	if (tag == X86_BUS_SPACE_IO)
715 		while (count--)
716 			outb(addr, value);
717 	else
718 		while (count--)
719 			*(volatile u_int8_t *)(addr) = value;
720 }
721 
722 static __inline void
723 bus_space_set_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh,
724 		     bus_size_t offset, u_int16_t value, size_t count)
725 {
726 	bus_space_handle_t addr = bsh + offset;
727 
728 	if (tag == X86_BUS_SPACE_IO)
729 		while (count--)
730 			outw(addr, value);
731 	else
732 		while (count--)
733 			*(volatile u_int16_t *)(addr) = value;
734 }
735 
736 static __inline void
737 bus_space_set_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh,
738 		      bus_size_t offset, u_int32_t value, size_t count)
739 {
740 	bus_space_handle_t addr = bsh + offset;
741 
742 	if (tag == X86_BUS_SPACE_IO)
743 		while (count--)
744 			outl(addr, value);
745 	else
746 		while (count--)
747 			*(volatile u_int32_t *)(addr) = value;
748 }
749 
750 #if 0	/* Cause a link error for bus_space_set_multi_8 */
751 #define	bus_space_set_multi_8 !!! bus_space_set_multi_8 unimplemented !!!
752 #endif
753 
754 /*
755  * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described
756  * by tag/handle starting at `offset'.
757  */
758 
759 static __inline void bus_space_set_region_1(bus_space_tag_t tag,
760 					    bus_space_handle_t bsh,
761 					    bus_size_t offset, u_int8_t value,
762 					    size_t count);
763 static __inline void bus_space_set_region_2(bus_space_tag_t tag,
764 					    bus_space_handle_t bsh,
765 					    bus_size_t offset, u_int16_t value,
766 					    size_t count);
767 static __inline void bus_space_set_region_4(bus_space_tag_t tag,
768 					    bus_space_handle_t bsh,
769 					    bus_size_t offset, u_int32_t value,
770 					    size_t count);
771 
772 static __inline void
773 bus_space_set_region_1(bus_space_tag_t tag, bus_space_handle_t bsh,
774 		       bus_size_t offset, u_int8_t value, size_t count)
775 {
776 	bus_space_handle_t addr = bsh + offset;
777 
778 	if (tag == X86_BUS_SPACE_IO)
779 		for (; count != 0; count--, addr++)
780 			outb(addr, value);
781 	else
782 		for (; count != 0; count--, addr++)
783 			*(volatile u_int8_t *)(addr) = value;
784 }
785 
786 static __inline void
787 bus_space_set_region_2(bus_space_tag_t tag, bus_space_handle_t bsh,
788 		       bus_size_t offset, u_int16_t value, size_t count)
789 {
790 	bus_space_handle_t addr = bsh + offset;
791 
792 	if (tag == X86_BUS_SPACE_IO)
793 		for (; count != 0; count--, addr += 2)
794 			outw(addr, value);
795 	else
796 		for (; count != 0; count--, addr += 2)
797 			*(volatile u_int16_t *)(addr) = value;
798 }
799 
800 static __inline void
801 bus_space_set_region_4(bus_space_tag_t tag, bus_space_handle_t bsh,
802 		       bus_size_t offset, u_int32_t value, size_t count)
803 {
804 	bus_space_handle_t addr = bsh + offset;
805 
806 	if (tag == X86_BUS_SPACE_IO)
807 		for (; count != 0; count--, addr += 4)
808 			outl(addr, value);
809 	else
810 		for (; count != 0; count--, addr += 4)
811 			*(volatile u_int32_t *)(addr) = value;
812 }
813 
814 #if 0	/* Cause a link error for bus_space_set_region_8 */
815 #define	bus_space_set_region_8	!!! bus_space_set_region_8 unimplemented !!!
816 #endif
817 
818 /*
819  * Copy `count' 1, 2, 4, or 8 byte values from bus space starting
820  * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2.
821  */
822 
823 static __inline void bus_space_copy_region_1(bus_space_tag_t tag,
824 					     bus_space_handle_t bsh1,
825 					     bus_size_t off1,
826 					     bus_space_handle_t bsh2,
827 					     bus_size_t off2, size_t count);
828 
829 static __inline void bus_space_copy_region_2(bus_space_tag_t tag,
830 					     bus_space_handle_t bsh1,
831 					     bus_size_t off1,
832 					     bus_space_handle_t bsh2,
833 					     bus_size_t off2, size_t count);
834 
835 static __inline void bus_space_copy_region_4(bus_space_tag_t tag,
836 					     bus_space_handle_t bsh1,
837 					     bus_size_t off1,
838 					     bus_space_handle_t bsh2,
839 					     bus_size_t off2, size_t count);
840 
841 static __inline void
842 bus_space_copy_region_1(bus_space_tag_t tag, bus_space_handle_t bsh1,
843 			bus_size_t off1, bus_space_handle_t bsh2,
844 			bus_size_t off2, size_t count)
845 {
846 	bus_space_handle_t addr1 = bsh1 + off1;
847 	bus_space_handle_t addr2 = bsh2 + off2;
848 
849 	if (tag == X86_BUS_SPACE_IO) {
850 		if (addr1 >= addr2) {
851 			/* src after dest: copy forward */
852 			for (; count != 0; count--, addr1++, addr2++)
853 				outb(addr2, inb(addr1));
854 		} else {
855 			/* dest after src: copy backwards */
856 			for (addr1 += (count - 1), addr2 += (count - 1);
857 			    count != 0; count--, addr1--, addr2--)
858 				outb(addr2, inb(addr1));
859 		}
860 	} else {
861 		if (addr1 >= addr2) {
862 			/* src after dest: copy forward */
863 			for (; count != 0; count--, addr1++, addr2++)
864 				*(volatile u_int8_t *)(addr2) =
865 				    *(volatile u_int8_t *)(addr1);
866 		} else {
867 			/* dest after src: copy backwards */
868 			for (addr1 += (count - 1), addr2 += (count - 1);
869 			    count != 0; count--, addr1--, addr2--)
870 				*(volatile u_int8_t *)(addr2) =
871 				    *(volatile u_int8_t *)(addr1);
872 		}
873 	}
874 }
875 
876 static __inline void
877 bus_space_copy_region_2(bus_space_tag_t tag, bus_space_handle_t bsh1,
878 			bus_size_t off1, bus_space_handle_t bsh2,
879 			bus_size_t off2, size_t count)
880 {
881 	bus_space_handle_t addr1 = bsh1 + off1;
882 	bus_space_handle_t addr2 = bsh2 + off2;
883 
884 	if (tag == X86_BUS_SPACE_IO) {
885 		if (addr1 >= addr2) {
886 			/* src after dest: copy forward */
887 			for (; count != 0; count--, addr1 += 2, addr2 += 2)
888 				outw(addr2, inw(addr1));
889 		} else {
890 			/* dest after src: copy backwards */
891 			for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1);
892 			    count != 0; count--, addr1 -= 2, addr2 -= 2)
893 				outw(addr2, inw(addr1));
894 		}
895 	} else {
896 		if (addr1 >= addr2) {
897 			/* src after dest: copy forward */
898 			for (; count != 0; count--, addr1 += 2, addr2 += 2)
899 				*(volatile u_int16_t *)(addr2) =
900 				    *(volatile u_int16_t *)(addr1);
901 		} else {
902 			/* dest after src: copy backwards */
903 			for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1);
904 			    count != 0; count--, addr1 -= 2, addr2 -= 2)
905 				*(volatile u_int16_t *)(addr2) =
906 				    *(volatile u_int16_t *)(addr1);
907 		}
908 	}
909 }
910 
911 static __inline void
912 bus_space_copy_region_4(bus_space_tag_t tag, bus_space_handle_t bsh1,
913 			bus_size_t off1, bus_space_handle_t bsh2,
914 			bus_size_t off2, size_t count)
915 {
916 	bus_space_handle_t addr1 = bsh1 + off1;
917 	bus_space_handle_t addr2 = bsh2 + off2;
918 
919 	if (tag == X86_BUS_SPACE_IO) {
920 		if (addr1 >= addr2) {
921 			/* src after dest: copy forward */
922 			for (; count != 0; count--, addr1 += 4, addr2 += 4)
923 				outl(addr2, inl(addr1));
924 		} else {
925 			/* dest after src: copy backwards */
926 			for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1);
927 			    count != 0; count--, addr1 -= 4, addr2 -= 4)
928 				outl(addr2, inl(addr1));
929 		}
930 	} else {
931 		if (addr1 >= addr2) {
932 			/* src after dest: copy forward */
933 			for (; count != 0; count--, addr1 += 4, addr2 += 4)
934 				*(volatile u_int32_t *)(addr2) =
935 				    *(volatile u_int32_t *)(addr1);
936 		} else {
937 			/* dest after src: copy backwards */
938 			for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1);
939 			    count != 0; count--, addr1 -= 4, addr2 -= 4)
940 				*(volatile u_int32_t *)(addr2) =
941 				    *(volatile u_int32_t *)(addr1);
942 		}
943 	}
944 }
945 
946 #if 0	/* Cause a link error for bus_space_copy_8 */
947 #define	bus_space_copy_region_8	!!! bus_space_copy_region_8 unimplemented !!!
948 #endif
949 
950 /*
951  * Bus read/write barrier methods.
952  *
953  *	void bus_space_barrier(bus_space_tag_t tag, bus_space_handle_t bsh,
954  *			       bus_size_t offset, bus_size_t len, int flags);
955  *
956  *
957  * Note that BUS_SPACE_BARRIER_WRITE doesn't do anything other than
958  * prevent reordering by the compiler; all Intel x86 processors currently
959  * retire operations outside the CPU in program order.
960  */
961 static __inline void
962 bus_space_barrier(bus_space_tag_t tag __unused, bus_space_handle_t bsh __unused,
963 		  bus_size_t offset __unused, bus_size_t len __unused, int flags)
964 {
965 	if (flags & BUS_SPACE_BARRIER_READ)
966 #ifdef __amd64__
967 		__asm __volatile("lock; addl $0,0(%%rsp)" : : : "memory");
968 #else
969 		__asm __volatile("lock; addl $0,0(%%esp)" : : : "memory");
970 #endif
971 	else
972 		__compiler_membar();
973 }
974 
975 #ifdef BUS_SPACE_NO_LEGACY
976 #undef inb
977 #undef outb
978 #define inb(a) compiler_error
979 #define inw(a) compiler_error
980 #define inl(a) compiler_error
981 #define outb(a, b) compiler_error
982 #define outw(a, b) compiler_error
983 #define outl(a, b) compiler_error
984 #endif
985 
986 /*
987  * Stream accesses are the same as normal accesses on x86; there are no
988  * supported bus systems with an endianess different from the host one.
989  */
990 #define	bus_space_read_stream_1(t, h, o)	bus_space_read_1((t), (h), (o))
991 #define	bus_space_read_stream_2(t, h, o)	bus_space_read_2((t), (h), (o))
992 #define	bus_space_read_stream_4(t, h, o)	bus_space_read_4((t), (h), (o))
993 
994 #define	bus_space_read_multi_stream_1(t, h, o, a, c) \
995 	bus_space_read_multi_1((t), (h), (o), (a), (c))
996 #define	bus_space_read_multi_stream_2(t, h, o, a, c) \
997 	bus_space_read_multi_2((t), (h), (o), (a), (c))
998 #define	bus_space_read_multi_stream_4(t, h, o, a, c) \
999 	bus_space_read_multi_4((t), (h), (o), (a), (c))
1000 
1001 #define	bus_space_write_stream_1(t, h, o, v) \
1002 	bus_space_write_1((t), (h), (o), (v))
1003 #define	bus_space_write_stream_2(t, h, o, v) \
1004 	bus_space_write_2((t), (h), (o), (v))
1005 #define	bus_space_write_stream_4(t, h, o, v) \
1006 	bus_space_write_4((t), (h), (o), (v))
1007 
1008 #define	bus_space_write_multi_stream_1(t, h, o, a, c) \
1009 	bus_space_write_multi_1((t), (h), (o), (a), (c))
1010 #define	bus_space_write_multi_stream_2(t, h, o, a, c) \
1011 	bus_space_write_multi_2((t), (h), (o), (a), (c))
1012 #define	bus_space_write_multi_stream_4(t, h, o, a, c) \
1013 	bus_space_write_multi_4((t), (h), (o), (a), (c))
1014 
1015 #define	bus_space_set_multi_stream_1(t, h, o, v, c) \
1016 	bus_space_set_multi_1((t), (h), (o), (v), (c))
1017 #define	bus_space_set_multi_stream_2(t, h, o, v, c) \
1018 	bus_space_set_multi_2((t), (h), (o), (v), (c))
1019 #define	bus_space_set_multi_stream_4(t, h, o, v, c) \
1020 	bus_space_set_multi_4((t), (h), (o), (v), (c))
1021 
1022 #define	bus_space_read_region_stream_1(t, h, o, a, c) \
1023 	bus_space_read_region_1((t), (h), (o), (a), (c))
1024 #define	bus_space_read_region_stream_2(t, h, o, a, c) \
1025 	bus_space_read_region_2((t), (h), (o), (a), (c))
1026 #define	bus_space_read_region_stream_4(t, h, o, a, c) \
1027 	bus_space_read_region_4((t), (h), (o), (a), (c))
1028 
1029 #define	bus_space_write_region_stream_1(t, h, o, a, c) \
1030 	bus_space_write_region_1((t), (h), (o), (a), (c))
1031 #define	bus_space_write_region_stream_2(t, h, o, a, c) \
1032 	bus_space_write_region_2((t), (h), (o), (a), (c))
1033 #define	bus_space_write_region_stream_4(t, h, o, a, c) \
1034 	bus_space_write_region_4((t), (h), (o), (a), (c))
1035 
1036 #define	bus_space_set_region_stream_1(t, h, o, v, c) \
1037 	bus_space_set_region_1((t), (h), (o), (v), (c))
1038 #define	bus_space_set_region_stream_2(t, h, o, v, c) \
1039 	bus_space_set_region_2((t), (h), (o), (v), (c))
1040 #define	bus_space_set_region_stream_4(t, h, o, v, c) \
1041 	bus_space_set_region_4((t), (h), (o), (v), (c))
1042 
1043 #define	bus_space_copy_region_stream_1(t, h1, o1, h2, o2, c) \
1044 	bus_space_copy_region_1((t), (h1), (o1), (h2), (o2), (c))
1045 #define	bus_space_copy_region_stream_2(t, h1, o1, h2, o2, c) \
1046 	bus_space_copy_region_2((t), (h1), (o1), (h2), (o2), (c))
1047 #define	bus_space_copy_region_stream_4(t, h1, o1, h2, o2, c) \
1048 	bus_space_copy_region_4((t), (h1), (o1), (h2), (o2), (c))
1049 
1050 #define BUS_PEEK_FUNC(width, type)					\
1051 	static inline int						\
1052 	bus_space_peek_##width(bus_space_tag_t tag,			\
1053 	    bus_space_handle_t hnd, bus_size_t offset, type *value)	\
1054 	{								\
1055 		type tmp;						\
1056 		tmp = bus_space_read_##width(tag, hnd, offset);		\
1057 		*value = (type)tmp;					\
1058 		return (0);						\
1059 	}
1060 BUS_PEEK_FUNC(1, uint8_t)
1061 BUS_PEEK_FUNC(2, uint16_t)
1062 BUS_PEEK_FUNC(4, uint32_t)
1063 #ifdef __amd64__
1064 BUS_PEEK_FUNC(8, uint64_t)
1065 #endif
1066 
1067 #define BUS_POKE_FUNC(width, type)					\
1068 	static inline int						\
1069 	bus_space_poke_##width(bus_space_tag_t tag,			\
1070 	    bus_space_handle_t hnd, bus_size_t offset, type value)	\
1071 	{								\
1072 		bus_space_write_##width(tag, hnd, offset, value);	\
1073 		return (0); 						\
1074 	}
1075 BUS_POKE_FUNC(1, uint8_t)
1076 BUS_POKE_FUNC(2, uint16_t)
1077 BUS_POKE_FUNC(4, uint32_t)
1078 #ifdef __amd64__
1079 BUS_POKE_FUNC(8, uint64_t)
1080 #endif
1081 
1082 #endif /* !SAN_NEEDS_INTERCEPTORS && SAN_RUNTIME */
1083 
1084 #endif /* !_MACHINE_BUS_H_ */
1085