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