]>
Commit | Line | Data |
---|---|---|
b0d623f7 | 1 | /* |
0a7de745 | 2 | * Copyright (c) 2000-2019 Apple Inc. All rights reserved. |
b0d623f7 A |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
0a7de745 | 5 | * |
b0d623f7 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
0a7de745 | 14 | * |
b0d623f7 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
0a7de745 | 17 | * |
b0d623f7 A |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
0a7de745 | 25 | * |
b0d623f7 A |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ | |
28 | /* | |
29 | * @OSF_COPYRIGHT@ | |
30 | */ | |
0a7de745 | 31 | /* |
b0d623f7 A |
32 | * Mach Operating System |
33 | * Copyright (c) 1991,1990,1989 Carnegie Mellon University | |
34 | * All Rights Reserved. | |
0a7de745 | 35 | * |
b0d623f7 A |
36 | * Permission to use, copy, modify and distribute this software and its |
37 | * documentation is hereby granted, provided that both the copyright | |
38 | * notice and this permission notice appear in all copies of the | |
39 | * software, derivative works or modified versions, and any portions | |
40 | * thereof, and that both notices appear in supporting documentation. | |
0a7de745 | 41 | * |
b0d623f7 A |
42 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" |
43 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |
44 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |
0a7de745 | 45 | * |
b0d623f7 | 46 | * Carnegie Mellon requests users of this software to return to |
0a7de745 | 47 | * |
b0d623f7 A |
48 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU |
49 | * School of Computer Science | |
50 | * Carnegie Mellon University | |
51 | * Pittsburgh PA 15213-3890 | |
0a7de745 | 52 | * |
b0d623f7 A |
53 | * any improvements or extensions that they make and grant Carnegie Mellon |
54 | * the rights to redistribute these changes. | |
55 | */ | |
56 | /* | |
57 | */ | |
58 | #include <mach_assert.h> | |
59 | ||
60 | #include <string.h> | |
61 | #include <mach/boolean.h> | |
62 | #include <mach/i386/vm_types.h> | |
63 | #include <mach/i386/vm_param.h> | |
64 | #include <kern/kern_types.h> | |
65 | #include <kern/misc_protos.h> | |
66 | #include <sys/errno.h> | |
67 | #include <i386/param.h> | |
68 | #include <i386/misc_protos.h> | |
69 | #include <i386/cpu_data.h> | |
70 | #include <i386/machine_routines.h> | |
71 | #include <i386/cpuid.h> | |
72 | #include <i386/vmx.h> | |
73 | #include <vm/pmap.h> | |
74 | #include <vm/vm_map.h> | |
75 | #include <vm/vm_kern.h> | |
76 | #include <vm/vm_fault.h> | |
77 | ||
78 | #include <libkern/OSAtomic.h> | |
0a7de745 | 79 | #include <libkern/OSDebug.h> |
b0d623f7 A |
80 | #include <sys/kdebug.h> |
81 | ||
39236c6e A |
82 | #if !MACH_KDP |
83 | #include <kdp/kdp_callout.h> | |
84 | #endif /* !MACH_KDP */ | |
85 | ||
0a7de745 A |
86 | #include <architecture/i386/pio.h> |
87 | ||
3e170ce0 A |
88 | #include <libkern/OSDebug.h> |
89 | #if CONFIG_DTRACE | |
90 | #include <mach/sdt.h> | |
91 | #endif | |
92 | ||
b0d623f7 A |
93 | #if 0 |
94 | ||
95 | #undef KERNEL_DEBUG | |
96 | #define KERNEL_DEBUG KERNEL_DEBUG_CONSTANT | |
97 | #define KDEBUG 1 | |
98 | ||
99 | #endif | |
100 | ||
5ba3f43e A |
101 | /* prevent infinite recursion when memmove calls bcopy; in string.h, bcopy is defined to call memmove */ |
102 | #undef bcopy | |
103 | ||
b0d623f7 | 104 | /* XXX - should be gone from here */ |
0a7de745 A |
105 | extern void invalidate_icache64(addr64_t addr, unsigned cnt, int phys); |
106 | extern void flush_dcache64(addr64_t addr, unsigned count, int phys); | |
107 | extern boolean_t phys_page_exists(ppnum_t); | |
108 | extern void bcopy_no_overwrite(const char *from, char *to, vm_size_t bytes); | |
109 | extern void pmap_set_reference(ppnum_t pn); | |
110 | extern void mapping_set_mod(ppnum_t pa); | |
111 | extern void mapping_set_ref(ppnum_t pn); | |
112 | ||
113 | extern void ovbcopy(const char *from, | |
114 | char *to, | |
115 | vm_size_t nbytes); | |
39236c6e | 116 | void machine_callstack(uintptr_t *buf, vm_size_t callstack_max); |
b0d623f7 A |
117 | |
118 | ||
119 | #define value_64bit(value) ((value) & 0xFFFFFFFF00000000ULL) | |
120 | #define low32(x) ((unsigned int)((x) & 0x00000000FFFFFFFFULL)) | |
121 | ||
0a7de745 | 122 | #define INT_SIZE (BYTE_SIZE * sizeof (int)) |
b0d623f7 A |
123 | |
124 | /* | |
125 | * Set indicated bit in bit string. | |
126 | */ | |
127 | void | |
128 | setbit(int bitno, int *s) | |
129 | { | |
130 | s[bitno / INT_SIZE] |= 1 << (bitno % INT_SIZE); | |
131 | } | |
132 | ||
133 | /* | |
134 | * Clear indicated bit in bit string. | |
135 | */ | |
136 | void | |
137 | clrbit(int bitno, int *s) | |
138 | { | |
139 | s[bitno / INT_SIZE] &= ~(1 << (bitno % INT_SIZE)); | |
140 | } | |
141 | ||
142 | /* | |
143 | * Test if indicated bit is set in bit string. | |
144 | */ | |
145 | int | |
146 | testbit(int bitno, int *s) | |
147 | { | |
148 | return s[bitno / INT_SIZE] & (1 << (bitno % INT_SIZE)); | |
149 | } | |
150 | ||
151 | /* | |
152 | * Find first bit set in bit string. | |
153 | */ | |
154 | int | |
155 | ffsbit(int *s) | |
156 | { | |
157 | int offset; | |
158 | ||
0a7de745 A |
159 | for (offset = 0; !*s; offset += (int)INT_SIZE, ++s) { |
160 | ; | |
161 | } | |
b0d623f7 A |
162 | return offset + __builtin_ctz(*s); |
163 | } | |
164 | ||
165 | int | |
166 | ffs(unsigned int mask) | |
167 | { | |
0a7de745 | 168 | if (mask == 0) { |
b0d623f7 | 169 | return 0; |
0a7de745 | 170 | } |
b0d623f7 A |
171 | |
172 | /* | |
173 | * NOTE: cannot use __builtin_ffs because it generates a call to | |
174 | * 'ffs' | |
175 | */ | |
176 | return 1 + __builtin_ctz(mask); | |
177 | } | |
178 | ||
5ba3f43e A |
179 | int |
180 | ffsll(unsigned long long mask) | |
181 | { | |
0a7de745 | 182 | if (mask == 0) { |
5ba3f43e | 183 | return 0; |
0a7de745 | 184 | } |
5ba3f43e A |
185 | |
186 | /* | |
187 | * NOTE: cannot use __builtin_ffsll because it generates a call to | |
188 | * 'ffsll' | |
189 | */ | |
190 | return 1 + __builtin_ctzll(mask); | |
191 | } | |
192 | ||
193 | /* | |
194 | * Find last bit set in bit string. | |
195 | */ | |
196 | int | |
197 | fls(unsigned int mask) | |
198 | { | |
0a7de745 | 199 | if (mask == 0) { |
5ba3f43e | 200 | return 0; |
0a7de745 | 201 | } |
5ba3f43e | 202 | |
0a7de745 | 203 | return (sizeof(mask) << 3) - __builtin_clz(mask); |
5ba3f43e A |
204 | } |
205 | ||
206 | int | |
207 | flsll(unsigned long long mask) | |
208 | { | |
0a7de745 | 209 | if (mask == 0) { |
5ba3f43e | 210 | return 0; |
0a7de745 | 211 | } |
5ba3f43e | 212 | |
0a7de745 | 213 | return (sizeof(mask) << 3) - __builtin_clzll(mask); |
5ba3f43e A |
214 | } |
215 | ||
b0d623f7 A |
216 | void |
217 | bzero_phys_nc( | |
0a7de745 A |
218 | addr64_t src64, |
219 | uint32_t bytes) | |
b0d623f7 | 220 | { |
0a7de745 | 221 | bzero_phys(src64, bytes); |
b0d623f7 A |
222 | } |
223 | ||
224 | void | |
225 | bzero_phys( | |
0a7de745 A |
226 | addr64_t src64, |
227 | uint32_t bytes) | |
b0d623f7 A |
228 | { |
229 | bzero(PHYSMAP_PTOV(src64), bytes); | |
230 | } | |
231 | ||
232 | ||
233 | /* | |
234 | * bcopy_phys - like bcopy but copies from/to physical addresses. | |
235 | */ | |
236 | ||
237 | void | |
238 | bcopy_phys( | |
0a7de745 A |
239 | addr64_t src64, |
240 | addr64_t dst64, | |
241 | vm_size_t bytes) | |
b0d623f7 A |
242 | { |
243 | /* Not necessary for K64 - but ensure we stay within a page */ | |
0a7de745 A |
244 | if (((((uint32_t)src64 & (NBPG - 1)) + bytes) > NBPG) || |
245 | ((((uint32_t)dst64 & (NBPG - 1)) + bytes) > NBPG)) { | |
246 | panic("bcopy_phys alignment"); | |
b0d623f7 A |
247 | } |
248 | bcopy(PHYSMAP_PTOV(src64), PHYSMAP_PTOV(dst64), bytes); | |
249 | } | |
250 | ||
6d2010ae A |
251 | /* |
252 | * allow a function to get a quick virtual mapping of a physical page | |
253 | */ | |
254 | ||
255 | int | |
256 | apply_func_phys( | |
0a7de745 A |
257 | addr64_t dst64, |
258 | vm_size_t bytes, | |
259 | int (*func)(void * buffer, vm_size_t bytes, void * arg), | |
260 | void * arg) | |
6d2010ae A |
261 | { |
262 | /* Not necessary for K64 - but ensure we stay within a page */ | |
0a7de745 A |
263 | if (((((uint32_t)dst64 & (NBPG - 1)) + bytes) > NBPG)) { |
264 | panic("apply_func_phys alignment"); | |
6d2010ae A |
265 | } |
266 | ||
267 | return func(PHYSMAP_PTOV(dst64), bytes, arg); | |
268 | } | |
269 | ||
0a7de745 A |
270 | /* |
271 | * ovbcopy - like bcopy, but recognizes overlapping ranges and handles | |
b0d623f7 A |
272 | * them correctly. |
273 | */ | |
274 | ||
275 | void | |
276 | ovbcopy( | |
0a7de745 A |
277 | const char *from, |
278 | char *to, | |
279 | vm_size_t bytes) /* num bytes to copy */ | |
b0d623f7 A |
280 | { |
281 | /* Assume that bcopy copies left-to-right (low addr first). */ | |
0a7de745 A |
282 | if (from + bytes <= to || to + bytes <= from || to == from) { |
283 | bcopy_no_overwrite(from, to, bytes); /* non-overlapping or no-op*/ | |
284 | } else if (from > to) { | |
285 | bcopy_no_overwrite(from, to, bytes); /* overlapping but OK */ | |
286 | } else { | |
b0d623f7 A |
287 | /* to > from: overlapping, and must copy right-to-left. */ |
288 | from += bytes - 1; | |
289 | to += bytes - 1; | |
0a7de745 | 290 | while (bytes-- > 0) { |
b0d623f7 | 291 | *to-- = *from--; |
0a7de745 | 292 | } |
b0d623f7 A |
293 | } |
294 | } | |
295 | ||
296 | ||
297 | /* | |
298 | * Read data from a physical address. Memory should not be cache inhibited. | |
299 | */ | |
300 | ||
3e170ce0 | 301 | uint64_t reportphyreaddelayabs; |
0a7de745 | 302 | uint64_t reportphywritedelayabs; |
3e170ce0 | 303 | uint32_t reportphyreadosbt; |
0a7de745 | 304 | uint32_t reportphywriteosbt; |
5ba3f43e | 305 | |
813fb2f6 A |
306 | #if DEVELOPMENT || DEBUG |
307 | uint32_t phyreadpanic = 1; | |
0a7de745 A |
308 | uint32_t phywritepanic = 1; |
309 | uint64_t tracephyreaddelayabs = 50 * NSEC_PER_USEC; | |
310 | uint64_t tracephywritedelayabs = 50 * NSEC_PER_USEC; | |
311 | uint64_t simulate_stretched_io = 0; | |
813fb2f6 A |
312 | #else |
313 | uint32_t phyreadpanic = 0; | |
0a7de745 A |
314 | uint32_t phywritepanic = 0; |
315 | uint64_t tracephyreaddelayabs = 0; | |
316 | uint64_t tracephywritedelayabs = 0; | |
813fb2f6 | 317 | #endif |
b0d623f7 | 318 | |
813fb2f6 | 319 | __private_extern__ uint64_t |
0a7de745 A |
320 | ml_phys_read_data(uint64_t paddr, int size) |
321 | { | |
813fb2f6 | 322 | uint64_t result = 0; |
fe8ab488 A |
323 | unsigned char s1; |
324 | unsigned short s2; | |
5ba3f43e A |
325 | boolean_t istate = TRUE, timeread = FALSE; |
326 | uint64_t sabs = 0, eabs; | |
b0d623f7 | 327 | |
0a7de745 | 328 | if (__improbable(!physmap_enclosed(paddr))) { |
7ddcb079 | 329 | panic("%s: 0x%llx out of bounds\n", __FUNCTION__, paddr); |
0a7de745 | 330 | } |
7ddcb079 | 331 | |
3e170ce0 A |
332 | if (__improbable(reportphyreaddelayabs != 0)) { |
333 | istate = ml_set_interrupts_enabled(FALSE); | |
334 | sabs = mach_absolute_time(); | |
813fb2f6 | 335 | timeread = TRUE; |
3e170ce0 | 336 | } |
0a7de745 A |
337 | #if DEVELOPMENT || DEBUG |
338 | if (__improbable(timeread && simulate_stretched_io)) { | |
339 | sabs -= simulate_stretched_io; | |
340 | } | |
341 | #endif /* x86_64 DEVELOPMENT || DEBUG */ | |
3e170ce0 | 342 | |
0a7de745 A |
343 | switch (size) { |
344 | case 1: | |
7ddcb079 A |
345 | s1 = *(volatile unsigned char *)PHYSMAP_PTOV(paddr); |
346 | result = s1; | |
347 | break; | |
0a7de745 | 348 | case 2: |
7ddcb079 A |
349 | s2 = *(volatile unsigned short *)PHYSMAP_PTOV(paddr); |
350 | result = s2; | |
351 | break; | |
0a7de745 | 352 | case 4: |
7ddcb079 A |
353 | result = *(volatile unsigned int *)PHYSMAP_PTOV(paddr); |
354 | break; | |
813fb2f6 A |
355 | case 8: |
356 | result = *(volatile unsigned long long *)PHYSMAP_PTOV(paddr); | |
357 | break; | |
7ddcb079 | 358 | default: |
0a7de745 | 359 | panic("Invalid size %d for ml_phys_read_data", size); |
7ddcb079 | 360 | break; |
0a7de745 | 361 | } |
3e170ce0 | 362 | |
813fb2f6 | 363 | if (__improbable(timeread == TRUE)) { |
3e170ce0 | 364 | eabs = mach_absolute_time(); |
0a7de745 A |
365 | |
366 | #if DEVELOPMENT || DEBUG | |
367 | iotrace(IOTRACE_PHYS_READ, 0, paddr, size, result, sabs, eabs - sabs); | |
368 | #endif | |
3e170ce0 | 369 | |
813fb2f6 | 370 | if (__improbable((eabs - sabs) > reportphyreaddelayabs)) { |
0a7de745 A |
371 | (void)ml_set_interrupts_enabled(istate); |
372 | ||
5ba3f43e | 373 | if (phyreadpanic && (machine_timeout_suspended() == FALSE)) { |
813fb2f6 | 374 | panic_io_port_read(); |
0a7de745 A |
375 | panic("Read from physical addr 0x%llx took %llu ns, " |
376 | "result: 0x%llx (start: %llu, end: %llu), ceiling: %llu", | |
377 | paddr, (eabs - sabs), result, sabs, eabs, | |
378 | reportphyreaddelayabs); | |
813fb2f6 A |
379 | } |
380 | ||
3e170ce0 | 381 | if (reportphyreadosbt) { |
0a7de745 A |
382 | OSReportWithBacktrace("ml_phys_read_data took %lluus", |
383 | (eabs - sabs) / NSEC_PER_USEC); | |
3e170ce0 A |
384 | } |
385 | #if CONFIG_DTRACE | |
0a7de745 A |
386 | DTRACE_PHYSLAT4(physread, uint64_t, (eabs - sabs), |
387 | uint64_t, paddr, uint32_t, size, uint64_t, result); | |
388 | #endif /* CONFIG_DTRACE */ | |
389 | } else if (__improbable(tracephyreaddelayabs > 0 && (eabs - sabs) > tracephyreaddelayabs)) { | |
390 | KDBG(MACHDBG_CODE(DBG_MACH_IO, DBC_MACH_IO_PHYS_READ), | |
391 | (eabs - sabs), sabs, paddr, result); | |
392 | ||
393 | (void)ml_set_interrupts_enabled(istate); | |
394 | } else { | |
395 | (void)ml_set_interrupts_enabled(istate); | |
3e170ce0 A |
396 | } |
397 | } | |
398 | ||
0a7de745 | 399 | return result; |
b0d623f7 A |
400 | } |
401 | ||
402 | static unsigned long long | |
0a7de745 A |
403 | ml_phys_read_long_long(uint64_t paddr) |
404 | { | |
813fb2f6 | 405 | return ml_phys_read_data(paddr, 8); |
b0d623f7 A |
406 | } |
407 | ||
0a7de745 A |
408 | unsigned int |
409 | ml_phys_read(vm_offset_t paddr) | |
b0d623f7 | 410 | { |
0a7de745 | 411 | return (unsigned int) ml_phys_read_data(paddr, 4); |
b0d623f7 A |
412 | } |
413 | ||
0a7de745 A |
414 | unsigned int |
415 | ml_phys_read_word(vm_offset_t paddr) | |
416 | { | |
417 | return (unsigned int) ml_phys_read_data(paddr, 4); | |
b0d623f7 A |
418 | } |
419 | ||
0a7de745 A |
420 | unsigned int |
421 | ml_phys_read_64(addr64_t paddr64) | |
b0d623f7 | 422 | { |
0a7de745 | 423 | return (unsigned int) ml_phys_read_data(paddr64, 4); |
b0d623f7 A |
424 | } |
425 | ||
0a7de745 A |
426 | unsigned int |
427 | ml_phys_read_word_64(addr64_t paddr64) | |
b0d623f7 | 428 | { |
0a7de745 | 429 | return (unsigned int) ml_phys_read_data(paddr64, 4); |
b0d623f7 A |
430 | } |
431 | ||
0a7de745 A |
432 | unsigned int |
433 | ml_phys_read_half(vm_offset_t paddr) | |
b0d623f7 | 434 | { |
0a7de745 | 435 | return (unsigned int) ml_phys_read_data(paddr, 2); |
b0d623f7 A |
436 | } |
437 | ||
0a7de745 A |
438 | unsigned int |
439 | ml_phys_read_half_64(addr64_t paddr64) | |
b0d623f7 | 440 | { |
0a7de745 | 441 | return (unsigned int) ml_phys_read_data(paddr64, 2); |
b0d623f7 A |
442 | } |
443 | ||
0a7de745 A |
444 | unsigned int |
445 | ml_phys_read_byte(vm_offset_t paddr) | |
b0d623f7 | 446 | { |
0a7de745 | 447 | return (unsigned int) ml_phys_read_data(paddr, 1); |
b0d623f7 A |
448 | } |
449 | ||
0a7de745 A |
450 | unsigned int |
451 | ml_phys_read_byte_64(addr64_t paddr64) | |
b0d623f7 | 452 | { |
0a7de745 | 453 | return (unsigned int) ml_phys_read_data(paddr64, 1); |
b0d623f7 A |
454 | } |
455 | ||
0a7de745 A |
456 | unsigned long long |
457 | ml_phys_read_double(vm_offset_t paddr) | |
b0d623f7 | 458 | { |
0a7de745 | 459 | return ml_phys_read_long_long(paddr); |
b0d623f7 A |
460 | } |
461 | ||
0a7de745 A |
462 | unsigned long long |
463 | ml_phys_read_double_64(addr64_t paddr64) | |
b0d623f7 | 464 | { |
0a7de745 | 465 | return ml_phys_read_long_long(paddr64); |
b0d623f7 A |
466 | } |
467 | ||
468 | ||
469 | ||
470 | /* | |
471 | * Write data to a physical address. Memory should not be cache inhibited. | |
472 | */ | |
473 | ||
0a7de745 A |
474 | __private_extern__ void |
475 | ml_phys_write_data(uint64_t paddr, unsigned long long data, int size) | |
b0d623f7 | 476 | { |
0a7de745 A |
477 | boolean_t istate = TRUE, timewrite = FALSE; |
478 | uint64_t sabs = 0, eabs; | |
479 | ||
480 | if (__improbable(!physmap_enclosed(paddr))) { | |
7ddcb079 | 481 | panic("%s: 0x%llx out of bounds\n", __FUNCTION__, paddr); |
0a7de745 | 482 | } |
7ddcb079 | 483 | |
0a7de745 A |
484 | if (__improbable(reportphywritedelayabs != 0)) { |
485 | istate = ml_set_interrupts_enabled(FALSE); | |
486 | sabs = mach_absolute_time(); | |
487 | timewrite = TRUE; | |
488 | } | |
489 | #if DEVELOPMENT || DEBUG | |
490 | if (__improbable(timewrite && simulate_stretched_io)) { | |
491 | sabs -= simulate_stretched_io; | |
492 | } | |
493 | #endif /* x86_64 DEVELOPMENT || DEBUG */ | |
494 | ||
495 | switch (size) { | |
496 | case 1: | |
497 | *(volatile unsigned char *)PHYSMAP_PTOV(paddr) = (unsigned char)data; | |
498 | break; | |
499 | case 2: | |
500 | *(volatile unsigned short *)PHYSMAP_PTOV(paddr) = (unsigned short)data; | |
501 | break; | |
502 | case 4: | |
503 | *(volatile unsigned int *)PHYSMAP_PTOV(paddr) = (unsigned int)data; | |
504 | break; | |
505 | case 8: | |
506 | *(volatile unsigned long *)PHYSMAP_PTOV(paddr) = data; | |
507 | break; | |
7ddcb079 | 508 | default: |
0a7de745 | 509 | panic("Invalid size %d for ml_phys_write_data", size); |
7ddcb079 | 510 | break; |
0a7de745 A |
511 | } |
512 | ||
513 | if (__improbable(timewrite == TRUE)) { | |
514 | eabs = mach_absolute_time(); | |
515 | ||
516 | #if DEVELOPMENT || DEBUG | |
517 | iotrace(IOTRACE_PHYS_WRITE, 0, paddr, size, data, sabs, eabs - sabs); | |
518 | #endif | |
519 | ||
520 | if (__improbable((eabs - sabs) > reportphywritedelayabs)) { | |
521 | (void)ml_set_interrupts_enabled(istate); | |
522 | ||
523 | if (phywritepanic && (machine_timeout_suspended() == FALSE)) { | |
524 | panic_io_port_read(); | |
525 | panic("Write to physical addr 0x%llx took %llu ns, " | |
526 | "data: 0x%llx (start: %llu, end: %llu), ceiling: %llu", | |
527 | paddr, (eabs - sabs), data, sabs, eabs, | |
528 | reportphywritedelayabs); | |
529 | } | |
530 | ||
531 | if (reportphywriteosbt) { | |
532 | OSReportWithBacktrace("ml_phys_write_data (%p, 0x%llx) " | |
533 | "took %lluus", | |
534 | paddr, data, (eabs - sabs) / NSEC_PER_USEC); | |
535 | } | |
536 | #if CONFIG_DTRACE | |
537 | DTRACE_PHYSLAT4(physwrite, uint64_t, (eabs - sabs), | |
538 | uint64_t, paddr, uint32_t, size, uint64_t, data); | |
539 | #endif /* CONFIG_DTRACE */ | |
540 | } else if (__improbable(tracephywritedelayabs > 0 && (eabs - sabs) > tracephywritedelayabs)) { | |
541 | KDBG(MACHDBG_CODE(DBG_MACH_IO, DBC_MACH_IO_PHYS_WRITE), | |
542 | (eabs - sabs), sabs, paddr, data); | |
543 | ||
544 | (void)ml_set_interrupts_enabled(istate); | |
545 | } else { | |
546 | (void)ml_set_interrupts_enabled(istate); | |
547 | } | |
548 | } | |
b0d623f7 A |
549 | } |
550 | ||
0a7de745 A |
551 | void |
552 | ml_phys_write_byte(vm_offset_t paddr, unsigned int data) | |
b0d623f7 | 553 | { |
0a7de745 A |
554 | ml_phys_write_data(paddr, data, 1); |
555 | } | |
556 | ||
557 | void | |
558 | ml_phys_write_byte_64(addr64_t paddr64, unsigned int data) | |
559 | { | |
560 | ml_phys_write_data(paddr64, data, 1); | |
561 | } | |
562 | ||
563 | void | |
564 | ml_phys_write_half(vm_offset_t paddr, unsigned int data) | |
565 | { | |
566 | ml_phys_write_data(paddr, data, 2); | |
567 | } | |
568 | ||
569 | void | |
570 | ml_phys_write_half_64(addr64_t paddr64, unsigned int data) | |
571 | { | |
572 | ml_phys_write_data(paddr64, data, 2); | |
573 | } | |
574 | ||
575 | void | |
576 | ml_phys_write(vm_offset_t paddr, unsigned int data) | |
577 | { | |
578 | ml_phys_write_data(paddr, data, 4); | |
579 | } | |
7ddcb079 | 580 | |
0a7de745 A |
581 | void |
582 | ml_phys_write_64(addr64_t paddr64, unsigned int data) | |
583 | { | |
584 | ml_phys_write_data(paddr64, data, 4); | |
b0d623f7 A |
585 | } |
586 | ||
0a7de745 A |
587 | void |
588 | ml_phys_write_word(vm_offset_t paddr, unsigned int data) | |
b0d623f7 | 589 | { |
0a7de745 | 590 | ml_phys_write_data(paddr, data, 4); |
b0d623f7 A |
591 | } |
592 | ||
0a7de745 A |
593 | void |
594 | ml_phys_write_word_64(addr64_t paddr64, unsigned int data) | |
595 | { | |
596 | ml_phys_write_data(paddr64, data, 4); | |
597 | } | |
598 | ||
599 | void | |
600 | ml_phys_write_double(vm_offset_t paddr, unsigned long long data) | |
b0d623f7 | 601 | { |
0a7de745 | 602 | ml_phys_write_data(paddr, data, 8); |
b0d623f7 A |
603 | } |
604 | ||
0a7de745 A |
605 | void |
606 | ml_phys_write_double_64(addr64_t paddr64, unsigned long long data) | |
b0d623f7 | 607 | { |
0a7de745 | 608 | ml_phys_write_data(paddr64, data, 8); |
b0d623f7 A |
609 | } |
610 | ||
0a7de745 A |
611 | uint32_t |
612 | ml_port_io_read(uint16_t ioport, int size) | |
b0d623f7 | 613 | { |
0a7de745 A |
614 | uint32_t result = 0; |
615 | ||
616 | uint64_t sabs, eabs; | |
617 | boolean_t istate, timeread = FALSE; | |
618 | ||
619 | if (__improbable(reportphyreaddelayabs != 0)) { | |
620 | istate = ml_set_interrupts_enabled(FALSE); | |
621 | sabs = mach_absolute_time(); | |
622 | timeread = TRUE; | |
623 | } | |
624 | ||
625 | #if DEVELOPMENT || DEBUG | |
626 | if (__improbable(timeread && simulate_stretched_io)) { | |
627 | sabs -= simulate_stretched_io; | |
628 | } | |
629 | #endif /* x86_64 DEVELOPMENT || DEBUG */ | |
630 | ||
631 | switch (size) { | |
632 | case 1: | |
633 | result = inb(ioport); | |
634 | break; | |
635 | case 2: | |
636 | result = inw(ioport); | |
637 | break; | |
638 | case 4: | |
639 | result = inl(ioport); | |
640 | break; | |
641 | default: | |
642 | panic("Invalid size %d for ml_port_io_read(0x%x)", size, (unsigned)ioport); | |
643 | break; | |
644 | } | |
645 | ||
646 | if (__improbable(timeread == TRUE)) { | |
647 | eabs = mach_absolute_time(); | |
648 | ||
649 | #if DEVELOPMENT || DEBUG | |
650 | iotrace(IOTRACE_PORTIO_READ, 0, ioport, size, result, sabs, eabs - sabs); | |
651 | #endif | |
652 | ||
653 | if (__improbable((eabs - sabs) > reportphyreaddelayabs)) { | |
654 | (void)ml_set_interrupts_enabled(istate); | |
655 | ||
656 | if (phyreadpanic && (machine_timeout_suspended() == FALSE)) { | |
657 | panic_io_port_read(); | |
658 | panic("Read from IO port 0x%x took %llu ns, " | |
659 | "result: 0x%x (start: %llu, end: %llu), ceiling: %llu", | |
660 | ioport, (eabs - sabs), result, sabs, eabs, | |
661 | reportphyreaddelayabs); | |
662 | } | |
663 | ||
664 | if (reportphyreadosbt) { | |
665 | OSReportWithBacktrace("ml_port_io_read(0x%x) took %lluus", | |
666 | ioport, (eabs - sabs) / NSEC_PER_USEC); | |
667 | } | |
668 | #if CONFIG_DTRACE | |
669 | DTRACE_PHYSLAT3(portioread, uint64_t, (eabs - sabs), | |
670 | uint16_t, ioport, uint32_t, size); | |
671 | #endif /* CONFIG_DTRACE */ | |
672 | } else if (__improbable(tracephyreaddelayabs > 0 && (eabs - sabs) > tracephyreaddelayabs)) { | |
673 | KDBG(MACHDBG_CODE(DBG_MACH_IO, DBC_MACH_IO_PORTIO_READ), | |
674 | (eabs - sabs), sabs, ioport, result); | |
675 | ||
676 | (void)ml_set_interrupts_enabled(istate); | |
677 | } else { | |
678 | (void)ml_set_interrupts_enabled(istate); | |
679 | } | |
680 | } | |
681 | ||
682 | return result; | |
b0d623f7 A |
683 | } |
684 | ||
0a7de745 A |
685 | void |
686 | ml_port_io_write(uint16_t ioport, uint32_t val, int size) | |
b0d623f7 | 687 | { |
0a7de745 A |
688 | uint64_t sabs, eabs; |
689 | boolean_t istate, timewrite = FALSE; | |
690 | ||
691 | if (__improbable(reportphywritedelayabs != 0)) { | |
692 | istate = ml_set_interrupts_enabled(FALSE); | |
693 | sabs = mach_absolute_time(); | |
694 | timewrite = TRUE; | |
695 | } | |
696 | #if DEVELOPMENT || DEBUG | |
697 | if (__improbable(timewrite && simulate_stretched_io)) { | |
698 | sabs -= simulate_stretched_io; | |
699 | } | |
700 | #endif /* x86_64 DEVELOPMENT || DEBUG */ | |
701 | ||
702 | switch (size) { | |
703 | case 1: | |
704 | outb(ioport, (uint8_t)val); | |
705 | break; | |
706 | case 2: | |
707 | outw(ioport, (uint16_t)val); | |
708 | break; | |
709 | case 4: | |
710 | outl(ioport, (uint32_t)val); | |
711 | break; | |
712 | default: | |
713 | panic("Invalid size %d for ml_port_io_write(0x%x)", size, (unsigned)ioport); | |
714 | break; | |
715 | } | |
716 | ||
717 | if (__improbable(timewrite == TRUE)) { | |
718 | eabs = mach_absolute_time(); | |
719 | ||
720 | #if DEVELOPMENT || DEBUG | |
721 | iotrace(IOTRACE_PORTIO_WRITE, 0, ioport, size, val, sabs, eabs - sabs); | |
722 | #endif | |
723 | ||
724 | if (__improbable((eabs - sabs) > reportphywritedelayabs)) { | |
725 | (void)ml_set_interrupts_enabled(istate); | |
726 | ||
727 | if (phywritepanic && (machine_timeout_suspended() == FALSE)) { | |
728 | panic_io_port_read(); | |
729 | panic("Write to IO port 0x%x took %llu ns, val: 0x%x" | |
730 | " (start: %llu, end: %llu), ceiling: %llu", | |
731 | ioport, (eabs - sabs), val, sabs, eabs, | |
732 | reportphywritedelayabs); | |
733 | } | |
734 | ||
735 | if (reportphywriteosbt) { | |
736 | OSReportWithBacktrace("ml_port_io_write(0x%x, %d, 0x%llx) " | |
737 | "took %lluus", | |
738 | ioport, size, val, (eabs - sabs) / NSEC_PER_USEC); | |
739 | } | |
740 | ||
741 | #if CONFIG_DTRACE | |
742 | DTRACE_PHYSLAT4(portiowrite, uint64_t, (eabs - sabs), | |
743 | uint16_t, ioport, uint32_t, size, uint64_t, val); | |
744 | #endif /* CONFIG_DTRACE */ | |
745 | } else if (__improbable(tracephywritedelayabs > 0 && (eabs - sabs) > tracephywritedelayabs)) { | |
746 | KDBG(MACHDBG_CODE(DBG_MACH_IO, DBC_MACH_IO_PORTIO_WRITE), | |
747 | (eabs - sabs), sabs, ioport, val); | |
748 | ||
749 | (void)ml_set_interrupts_enabled(istate); | |
750 | } else { | |
751 | (void)ml_set_interrupts_enabled(istate); | |
752 | } | |
753 | } | |
b0d623f7 A |
754 | } |
755 | ||
0a7de745 A |
756 | uint8_t |
757 | ml_port_io_read8(uint16_t ioport) | |
b0d623f7 | 758 | { |
0a7de745 | 759 | return ml_port_io_read(ioport, 1); |
b0d623f7 A |
760 | } |
761 | ||
0a7de745 A |
762 | uint16_t |
763 | ml_port_io_read16(uint16_t ioport) | |
b0d623f7 | 764 | { |
0a7de745 | 765 | return ml_port_io_read(ioport, 2); |
b0d623f7 A |
766 | } |
767 | ||
0a7de745 A |
768 | uint32_t |
769 | ml_port_io_read32(uint16_t ioport) | |
b0d623f7 | 770 | { |
0a7de745 | 771 | return ml_port_io_read(ioport, 4); |
b0d623f7 A |
772 | } |
773 | ||
0a7de745 A |
774 | void |
775 | ml_port_io_write8(uint16_t ioport, uint8_t val) | |
b0d623f7 | 776 | { |
0a7de745 | 777 | ml_port_io_write(ioport, val, 1); |
b0d623f7 A |
778 | } |
779 | ||
0a7de745 A |
780 | void |
781 | ml_port_io_write16(uint16_t ioport, uint16_t val) | |
b0d623f7 | 782 | { |
0a7de745 | 783 | ml_port_io_write(ioport, val, 2); |
b0d623f7 A |
784 | } |
785 | ||
0a7de745 A |
786 | void |
787 | ml_port_io_write32(uint16_t ioport, uint32_t val) | |
788 | { | |
789 | ml_port_io_write(ioport, val, 4); | |
790 | } | |
b0d623f7 A |
791 | |
792 | /* PCI config cycle probing | |
793 | * | |
794 | * | |
795 | * Read the memory location at physical address paddr. | |
7ddcb079 A |
796 | * *Does not* recover from machine checks, unlike the PowerPC implementation. |
797 | * Should probably be deprecated. | |
b0d623f7 A |
798 | */ |
799 | ||
800 | boolean_t | |
801 | ml_probe_read(vm_offset_t paddr, unsigned int *val) | |
802 | { | |
0a7de745 A |
803 | if ((PAGE_SIZE - (paddr & PAGE_MASK)) < 4) { |
804 | return FALSE; | |
805 | } | |
b0d623f7 | 806 | |
0a7de745 | 807 | *val = ml_phys_read(paddr); |
b0d623f7 | 808 | |
0a7de745 | 809 | return TRUE; |
b0d623f7 A |
810 | } |
811 | ||
812 | /* | |
813 | * Read the memory location at physical address paddr. | |
814 | * This is a part of a device probe, so there is a good chance we will | |
815 | * have a machine check here. So we have to be able to handle that. | |
816 | * We assume that machine checks are enabled both in MSR and HIDs | |
817 | */ | |
0a7de745 | 818 | boolean_t |
b0d623f7 A |
819 | ml_probe_read_64(addr64_t paddr64, unsigned int *val) |
820 | { | |
0a7de745 A |
821 | if ((PAGE_SIZE - (paddr64 & PAGE_MASK)) < 4) { |
822 | return FALSE; | |
823 | } | |
b0d623f7 | 824 | |
0a7de745 A |
825 | *val = ml_phys_read_64(paddr64); |
826 | return TRUE; | |
b0d623f7 A |
827 | } |
828 | ||
829 | ||
5ba3f43e | 830 | #undef bcmp |
0a7de745 A |
831 | int |
832 | bcmp( | |
833 | const void *pa, | |
834 | const void *pb, | |
835 | size_t len) | |
b0d623f7 A |
836 | { |
837 | const char *a = (const char *)pa; | |
838 | const char *b = (const char *)pb; | |
839 | ||
0a7de745 | 840 | if (len == 0) { |
b0d623f7 | 841 | return 0; |
0a7de745 | 842 | } |
b0d623f7 | 843 | |
0a7de745 A |
844 | do{ |
845 | if (*a++ != *b++) { | |
b0d623f7 | 846 | break; |
0a7de745 A |
847 | } |
848 | } while (--len); | |
b0d623f7 A |
849 | |
850 | return (int)len; | |
851 | } | |
852 | ||
5ba3f43e | 853 | #undef memcmp |
b0d623f7 A |
854 | int |
855 | memcmp(const void *s1, const void *s2, size_t n) | |
856 | { | |
857 | if (n != 0) { | |
858 | const unsigned char *p1 = s1, *p2 = s2; | |
859 | ||
860 | do { | |
0a7de745 A |
861 | if (*p1++ != *p2++) { |
862 | return *--p1 - *--p2; | |
863 | } | |
b0d623f7 A |
864 | } while (--n != 0); |
865 | } | |
0a7de745 | 866 | return 0; |
b0d623f7 A |
867 | } |
868 | ||
5ba3f43e | 869 | #undef memmove |
fe8ab488 A |
870 | void * |
871 | memmove(void *dst, const void *src, size_t ulen) | |
872 | { | |
873 | bcopy(src, dst, ulen); | |
874 | return dst; | |
875 | } | |
876 | ||
b0d623f7 A |
877 | /* |
878 | * Abstract: | |
879 | * strlen returns the number of characters in "string" preceeding | |
880 | * the terminating null character. | |
881 | */ | |
882 | ||
5ba3f43e | 883 | #undef strlen |
b0d623f7 A |
884 | size_t |
885 | strlen( | |
39037602 | 886 | const char *string) |
b0d623f7 | 887 | { |
39037602 | 888 | const char *ret = string; |
b0d623f7 | 889 | |
0a7de745 | 890 | while (*string++ != '\0') { |
b0d623f7 | 891 | continue; |
0a7de745 | 892 | } |
b0d623f7 A |
893 | return string - 1 - ret; |
894 | } | |
895 | ||
0a7de745 | 896 | #if MACH_ASSERT |
b0d623f7 A |
897 | |
898 | /* | |
899 | * Machine-dependent routine to fill in an array with up to callstack_max | |
900 | * levels of return pc information. | |
901 | */ | |
0a7de745 A |
902 | void |
903 | machine_callstack( | |
904 | __unused uintptr_t *buf, | |
905 | __unused vm_size_t callstack_max) | |
b0d623f7 A |
906 | { |
907 | } | |
908 | ||
0a7de745 | 909 | #endif /* MACH_ASSERT */ |
b0d623f7 | 910 | |
0a7de745 A |
911 | void |
912 | fillPage(ppnum_t pa, unsigned int fill) | |
b0d623f7 | 913 | { |
0a7de745 | 914 | uint64_t src; |
b0d623f7 | 915 | int cnt = PAGE_SIZE / sizeof(unsigned int); |
b0d623f7 A |
916 | |
917 | src = i386_ptob(pa); | |
cb323159 | 918 | memset_word((int *)PHYSMAP_PTOV(src), fill, cnt); |
b0d623f7 A |
919 | } |
920 | ||
0a7de745 A |
921 | static inline void |
922 | __clflush(void *ptr) | |
b0d623f7 | 923 | { |
0a7de745 | 924 | __asm__ volatile ("clflush (%0)" : : "r" (ptr)); |
b0d623f7 A |
925 | } |
926 | ||
0a7de745 A |
927 | void |
928 | dcache_incoherent_io_store64(addr64_t pa, unsigned int count) | |
b0d623f7 | 929 | { |
6d2010ae A |
930 | addr64_t linesize = cpuid_info()->cache_linesize; |
931 | addr64_t bound = (pa + count + linesize - 1) & ~(linesize - 1); | |
b0d623f7 | 932 | |
39236c6e | 933 | mfence(); |
b0d623f7 | 934 | |
6d2010ae A |
935 | while (pa < bound) { |
936 | __clflush(PHYSMAP_PTOV(pa)); | |
937 | pa += linesize; | |
938 | } | |
b0d623f7 | 939 | |
39236c6e | 940 | mfence(); |
b0d623f7 A |
941 | } |
942 | ||
0a7de745 A |
943 | void |
944 | dcache_incoherent_io_flush64(addr64_t pa, unsigned int count) | |
b0d623f7 | 945 | { |
0a7de745 | 946 | return dcache_incoherent_io_store64(pa, count); |
b0d623f7 A |
947 | } |
948 | ||
949 | void | |
6d2010ae | 950 | flush_dcache64(addr64_t addr, unsigned count, int phys) |
b0d623f7 | 951 | { |
6d2010ae A |
952 | if (phys) { |
953 | dcache_incoherent_io_flush64(addr, count); | |
0a7de745 | 954 | } else { |
316670eb | 955 | uint64_t linesize = cpuid_info()->cache_linesize; |
0a7de745 | 956 | addr64_t bound = (addr + count + linesize - 1) & ~(linesize - 1); |
39236c6e | 957 | mfence(); |
6d2010ae A |
958 | while (addr < bound) { |
959 | __clflush((void *) (uintptr_t) addr); | |
960 | addr += linesize; | |
961 | } | |
39236c6e | 962 | mfence(); |
6d2010ae | 963 | } |
b0d623f7 A |
964 | } |
965 | ||
966 | void | |
967 | invalidate_icache64(__unused addr64_t addr, | |
0a7de745 A |
968 | __unused unsigned count, |
969 | __unused int phys) | |
b0d623f7 A |
970 | { |
971 | } | |
972 | ||
973 | ||
974 | addr64_t vm_last_addr; | |
975 | ||
976 | void | |
977 | mapping_set_mod(ppnum_t pn) | |
978 | { | |
0a7de745 | 979 | pmap_set_modify(pn); |
b0d623f7 A |
980 | } |
981 | ||
982 | void | |
983 | mapping_set_ref(ppnum_t pn) | |
984 | { | |
0a7de745 | 985 | pmap_set_reference(pn); |
b0d623f7 A |
986 | } |
987 | ||
0a7de745 | 988 | extern i386_cpu_info_t cpuid_cpu_info; |
b0d623f7 A |
989 | void |
990 | cache_flush_page_phys(ppnum_t pa) | |
991 | { | |
0a7de745 A |
992 | boolean_t istate; |
993 | unsigned char *cacheline_addr; | |
994 | i386_cpu_info_t *cpuid_infop = cpuid_info(); | |
995 | int cacheline_size; | |
996 | int cachelines_to_flush; | |
39236c6e A |
997 | |
998 | cacheline_size = cpuid_infop->cache_linesize; | |
0a7de745 | 999 | if (cacheline_size == 0) { |
39236c6e | 1000 | panic("cacheline_size=0 cpuid_infop=%p\n", cpuid_infop); |
0a7de745 A |
1001 | } |
1002 | cachelines_to_flush = PAGE_SIZE / cacheline_size; | |
b0d623f7 | 1003 | |
39236c6e | 1004 | mfence(); |
b0d623f7 A |
1005 | |
1006 | istate = ml_set_interrupts_enabled(FALSE); | |
1007 | ||
1008 | for (cacheline_addr = (unsigned char *)PHYSMAP_PTOV(i386_ptob(pa)); | |
0a7de745 A |
1009 | cachelines_to_flush > 0; |
1010 | cachelines_to_flush--, cacheline_addr += cacheline_size) { | |
b0d623f7 A |
1011 | __clflush((void *) cacheline_addr); |
1012 | } | |
1013 | ||
1014 | (void) ml_set_interrupts_enabled(istate); | |
1015 | ||
39236c6e | 1016 | mfence(); |
b0d623f7 A |
1017 | } |
1018 | ||
1019 | ||
b0d623f7 A |
1020 | #if !MACH_KDP |
1021 | void | |
39236c6e | 1022 | kdp_register_callout(kdp_callout_fn_t fn, void *arg) |
b0d623f7 | 1023 | { |
39236c6e | 1024 | #pragma unused(fn,arg) |
b0d623f7 A |
1025 | } |
1026 | #endif | |
1027 | ||
1028 | #if !CONFIG_VMX | |
0a7de745 A |
1029 | int |
1030 | host_vmxon(boolean_t exclusive __unused) | |
b0d623f7 A |
1031 | { |
1032 | return VMX_UNSUPPORTED; | |
1033 | } | |
1034 | ||
0a7de745 A |
1035 | void |
1036 | host_vmxoff(void) | |
b0d623f7 A |
1037 | { |
1038 | return; | |
1039 | } | |
1040 | #endif |