1 | /* |
2 | * Copyright (c) 2014-2016 Apple Inc. All rights reserved. |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
5 | * |
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. |
14 | * |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. |
17 | * |
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. |
25 | * |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ |
28 | |
29 | #include <sys/cdefs.h> |
30 | |
31 | #include <IOKit/assert.h> |
32 | #include <IOKit/system.h> |
33 | #include <IOKit/IOLib.h> |
34 | #include <IOKit/IOMemoryDescriptor.h> |
35 | #include <IOKit/IOMapper.h> |
36 | #include <IOKit/IODMACommand.h> |
37 | #include <IOKit/IOKitKeysPrivate.h> |
38 | #include "Tests.h" |
39 | |
40 | #ifndef __LP64__ |
41 | #include <IOKit/IOSubMemoryDescriptor.h> |
42 | #endif /* !__LP64__ */ |
43 | #include <IOKit/IOSubMemoryDescriptor.h> |
44 | #include <IOKit/IOMultiMemoryDescriptor.h> |
45 | #include <IOKit/IOBufferMemoryDescriptor.h> |
46 | |
47 | #include <IOKit/IOKitDebug.h> |
48 | #include <libkern/OSDebug.h> |
49 | #include <sys/uio.h> |
50 | |
51 | __BEGIN_DECLS |
52 | #include <vm/pmap.h> |
53 | #include <vm/vm_pageout.h> |
54 | #include <mach/memory_object_types.h> |
55 | #include <device/device_port.h> |
56 | |
57 | #include <mach/vm_prot.h> |
58 | #include <mach/mach_vm.h> |
59 | #include <vm/vm_fault.h> |
60 | #include <vm/vm_protos.h> |
61 | __END_DECLS |
62 | |
63 | |
64 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
65 | |
66 | #if DEVELOPMENT || DEBUG |
67 | |
68 | extern SInt32 gIOMemoryReferenceCount; |
69 | |
70 | static int IOMultMemoryDescriptorTest(int newValue) |
71 | { |
72 | IOMemoryDescriptor * mds[3]; |
73 | IOMultiMemoryDescriptor * mmd; |
74 | IOMemoryMap * map; |
75 | void * addr; |
76 | uint8_t * data; |
77 | uint32_t i; |
78 | IOAddressRange ranges[2]; |
79 | |
80 | data = (typeof(data)) IOMallocAligned(ptoa(8), page_size); |
81 | for (i = 0; i < ptoa(8); i++) data[i] = atop(i) | 0xD0; |
82 | |
83 | ranges[0].address = (IOVirtualAddress)(data + ptoa(4)); |
84 | ranges[0].length = ptoa(4); |
85 | ranges[1].address = (IOVirtualAddress)(data + ptoa(0)); |
86 | ranges[1].length = ptoa(4); |
87 | |
88 | mds[0] = IOMemoryDescriptor::withAddressRanges(&ranges[0], 2, kIODirectionOutIn, kernel_task); |
89 | |
90 | mds[1] = IOSubMemoryDescriptor::withSubRange(mds[0], ptoa(3), ptoa(2), kIODirectionOutIn); |
91 | mds[2] = IOSubMemoryDescriptor::withSubRange(mds[0], ptoa(7), ptoa(1), kIODirectionOutIn); |
92 | |
93 | mmd = IOMultiMemoryDescriptor::withDescriptors(&mds[0], sizeof(mds)/sizeof(mds[0]), kIODirectionOutIn, false); |
94 | mds[2]->release(); |
95 | mds[1]->release(); |
96 | mds[0]->release(); |
97 | map = mmd->createMappingInTask(kernel_task, 0, kIOMapAnywhere, ptoa(7), mmd->getLength() - ptoa(7)); |
98 | mmd->release(); |
99 | assert(map); |
100 | |
101 | addr = (void *) map->getVirtualAddress(); |
102 | assert(ptoa(4) == map->getLength()); |
103 | assert(0xd3d3d3d3 == ((uint32_t *)addr)[ptoa(0) / sizeof(uint32_t)]); |
104 | assert(0xd7d7d7d7 == ((uint32_t *)addr)[ptoa(1) / sizeof(uint32_t)]); |
105 | assert(0xd0d0d0d0 == ((uint32_t *)addr)[ptoa(2) / sizeof(uint32_t)]); |
106 | assert(0xd3d3d3d3 == ((uint32_t *)addr)[ptoa(3) / sizeof(uint32_t)]); |
107 | map->release(); |
108 | IOFreeAligned(data, ptoa(8)); |
109 | |
110 | return (0); |
111 | } |
112 | |
113 | |
114 | |
115 | // <rdar://problem/30102458> |
116 | static int |
117 | IODMACommandForceDoubleBufferTest(int newValue) |
118 | { |
119 | IOReturn ret; |
120 | IOBufferMemoryDescriptor * bmd; |
121 | IODMACommand * dma; |
122 | uint32_t dir, data; |
123 | IODMACommand::SegmentOptions segOptions = |
124 | { |
125 | .fStructSize = sizeof(segOptions), |
126 | .fNumAddressBits = 64, |
127 | .fMaxSegmentSize = 0x2000, |
128 | .fMaxTransferSize = 128*1024, |
129 | .fAlignment = 1, |
130 | .fAlignmentLength = 1, |
131 | .fAlignmentInternalSegments = 1 |
132 | }; |
133 | IODMACommand::Segment64 segments[1]; |
134 | UInt32 numSegments; |
135 | UInt64 dmaOffset; |
136 | |
137 | |
138 | for (dir = kIODirectionIn; ; dir++) |
139 | { |
140 | bmd = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, |
141 | dir | kIOMemoryPageable, ptoa(8)); |
142 | assert(bmd); |
143 | |
144 | ((uint32_t*) bmd->getBytesNoCopy())[0] = 0x53535300 | dir; |
145 | |
146 | ret = bmd->prepare((IODirection) dir); |
147 | assert(kIOReturnSuccess == ret); |
148 | |
149 | dma = IODMACommand::withSpecification(kIODMACommandOutputHost64, &segOptions, |
150 | kIODMAMapOptionMapped, |
151 | NULL, NULL); |
152 | assert(dma); |
153 | ret = dma->setMemoryDescriptor(bmd, true); |
154 | assert(kIOReturnSuccess == ret); |
155 | |
156 | ret = dma->synchronize(IODMACommand::kForceDoubleBuffer | kIODirectionOut); |
157 | assert(kIOReturnSuccess == ret); |
158 | |
159 | dmaOffset = 0; |
160 | numSegments = 1; |
161 | ret = dma->gen64IOVMSegments(&dmaOffset, &segments[0], &numSegments); |
162 | assert(kIOReturnSuccess == ret); |
163 | assert(1 == numSegments); |
164 | |
165 | if (kIODirectionOut & dir) |
166 | { |
167 | data = ((uint32_t*) bmd->getBytesNoCopy())[0]; |
168 | assertf((0x53535300 | dir) == data, "mismatch 0x%x" , data); |
169 | } |
170 | if (kIODirectionIn & dir) |
171 | { |
172 | IOMappedWrite32(segments[0].fIOVMAddr, 0x11223300 | dir); |
173 | } |
174 | |
175 | ret = dma->clearMemoryDescriptor(true); |
176 | assert(kIOReturnSuccess == ret); |
177 | dma->release(); |
178 | |
179 | bmd->complete((IODirection) dir); |
180 | |
181 | if (kIODirectionIn & dir) |
182 | { |
183 | data = ((uint32_t*) bmd->getBytesNoCopy())[0]; |
184 | assertf((0x11223300 | dir) == data, "mismatch 0x%x" , data); |
185 | } |
186 | |
187 | bmd->release(); |
188 | |
189 | if (dir == kIODirectionInOut) break; |
190 | } |
191 | |
192 | return (0); |
193 | } |
194 | |
195 | // <rdar://problem/34322778> |
196 | static int __unused |
197 | IODMACommandLocalMappedNonContig(int newValue) |
198 | { |
199 | IOReturn kr; |
200 | IOMemoryDescriptor * md; |
201 | IODMACommand * dma; |
202 | OSDictionary * matching; |
203 | IOService * device; |
204 | IOMapper * mapper; |
205 | IODMACommand::SegmentOptions segOptions = |
206 | { |
207 | .fStructSize = sizeof(segOptions), |
208 | .fNumAddressBits = 64, |
209 | .fMaxSegmentSize = 128*1024, |
210 | .fMaxTransferSize = 128*1024, |
211 | .fAlignment = 1, |
212 | .fAlignmentLength = 1, |
213 | .fAlignmentInternalSegments = 1 |
214 | }; |
215 | IODMACommand::Segment64 segments[1]; |
216 | UInt32 numSegments; |
217 | UInt64 dmaOffset; |
218 | UInt64 segPhys; |
219 | vm_address_t buffer; |
220 | vm_size_t bufSize = ptoa(4); |
221 | |
222 | if (!IOMapper::gSystem) return (0); |
223 | |
224 | buffer = 0; |
225 | kr = vm_allocate_kernel(kernel_map, &buffer, bufSize, VM_FLAGS_ANYWHERE, VM_KERN_MEMORY_IOKIT); |
226 | assert(KERN_SUCCESS == kr); |
227 | |
228 | // fragment the vmentries |
229 | kr = vm_inherit(kernel_map, buffer + ptoa(1), ptoa(1), VM_INHERIT_NONE); |
230 | assert(KERN_SUCCESS == kr); |
231 | |
232 | md = IOMemoryDescriptor::withAddressRange( |
233 | buffer + 0xa00, 0x2000, kIODirectionOutIn, kernel_task); |
234 | assert(md); |
235 | kr = md->prepare(kIODirectionOutIn); |
236 | assert(kIOReturnSuccess == kr); |
237 | |
238 | segPhys = md->getPhysicalSegment(0, NULL, 0); |
239 | |
240 | matching = IOService::nameMatching("XHC1" ); |
241 | assert(matching); |
242 | device = IOService::copyMatchingService(matching); |
243 | matching->release(); |
244 | mapper = device ? IOMapper::copyMapperForDeviceWithIndex(device, 0) : NULL; |
245 | |
246 | dma = IODMACommand::withSpecification(kIODMACommandOutputHost64, &segOptions, |
247 | kIODMAMapOptionMapped, |
248 | mapper, NULL); |
249 | assert(dma); |
250 | kr = dma->setMemoryDescriptor(md, true); |
251 | assert(kIOReturnSuccess == kr); |
252 | |
253 | dmaOffset = 0; |
254 | numSegments = 1; |
255 | kr = dma->gen64IOVMSegments(&dmaOffset, &segments[0], &numSegments); |
256 | assert(kIOReturnSuccess == kr); |
257 | assert(1 == numSegments); |
258 | |
259 | if (mapper) assertf(segments[0].fIOVMAddr != segPhys, "phys !local 0x%qx, 0x%qx, %p" , segments[0].fIOVMAddr, segPhys, dma); |
260 | |
261 | kr = dma->clearMemoryDescriptor(true); |
262 | assert(kIOReturnSuccess == kr); |
263 | dma->release(); |
264 | |
265 | kr = md->complete(kIODirectionOutIn); |
266 | assert(kIOReturnSuccess == kr); |
267 | md->release(); |
268 | |
269 | kr = vm_deallocate(kernel_map, buffer, bufSize); |
270 | assert(KERN_SUCCESS == kr); |
271 | OSSafeReleaseNULL(mapper); |
272 | |
273 | return (0); |
274 | } |
275 | |
276 | // <rdar://problem/30102458> |
277 | static int |
278 | IOMemoryRemoteTest(int newValue) |
279 | { |
280 | IOReturn ret; |
281 | IOMemoryDescriptor * md; |
282 | IOByteCount offset, length; |
283 | addr64_t addr; |
284 | uint32_t idx; |
285 | |
286 | IODMACommand * dma; |
287 | IODMACommand::SegmentOptions segOptions = |
288 | { |
289 | .fStructSize = sizeof(segOptions), |
290 | .fNumAddressBits = 64, |
291 | .fMaxSegmentSize = 0x2000, |
292 | .fMaxTransferSize = 128*1024, |
293 | .fAlignment = 1, |
294 | .fAlignmentLength = 1, |
295 | .fAlignmentInternalSegments = 1 |
296 | }; |
297 | IODMACommand::Segment64 segments[1]; |
298 | UInt32 numSegments; |
299 | UInt64 dmaOffset; |
300 | |
301 | IOAddressRange ranges[2] = { |
302 | { 0x1234567890123456ULL, 0x1000 }, { 0x5432109876543210, 0x2000 }, |
303 | }; |
304 | |
305 | md = IOMemoryDescriptor::withAddressRanges(&ranges[0], 2, kIODirectionOutIn|kIOMemoryRemote, TASK_NULL); |
306 | assert(md); |
307 | |
308 | // md->map(); |
309 | // md->readBytes(0, &idx, sizeof(idx)); |
310 | |
311 | ret = md->prepare(kIODirectionOutIn); |
312 | assert(kIOReturnSuccess == ret); |
313 | |
314 | printf("remote md flags 0x%qx, r %d\n" , |
315 | md->getFlags(), (0 != (kIOMemoryRemote & md->getFlags()))); |
316 | |
317 | for (offset = 0, idx = 0; true; offset += length, idx++) |
318 | { |
319 | addr = md->getPhysicalSegment(offset, &length, 0); |
320 | if (!length) break; |
321 | assert(idx < 2); |
322 | assert(addr == ranges[idx].address); |
323 | assert(length == ranges[idx].length); |
324 | } |
325 | assert(offset == md->getLength()); |
326 | |
327 | dma = IODMACommand::withSpecification(kIODMACommandOutputHost64, &segOptions, |
328 | kIODMAMapOptionUnmapped | kIODMAMapOptionIterateOnly, |
329 | NULL, NULL); |
330 | assert(dma); |
331 | ret = dma->setMemoryDescriptor(md, true); |
332 | assert(kIOReturnSuccess == ret); |
333 | |
334 | for (dmaOffset = 0, idx = 0; dmaOffset < md->getLength(); idx++) |
335 | { |
336 | numSegments = 1; |
337 | ret = dma->gen64IOVMSegments(&dmaOffset, &segments[0], &numSegments); |
338 | assert(kIOReturnSuccess == ret); |
339 | assert(1 == numSegments); |
340 | assert(idx < 2); |
341 | assert(segments[0].fIOVMAddr == ranges[idx].address); |
342 | assert(segments[0].fLength == ranges[idx].length); |
343 | } |
344 | assert(dmaOffset == md->getLength()); |
345 | |
346 | ret = dma->clearMemoryDescriptor(true); |
347 | assert(kIOReturnSuccess == ret); |
348 | dma->release(); |
349 | md->complete(kIODirectionOutIn); |
350 | md->release(); |
351 | |
352 | return (0); |
353 | } |
354 | |
355 | static IOReturn |
356 | IOMemoryPrefaultTest(uint32_t options) |
357 | { |
358 | IOBufferMemoryDescriptor * bmd; |
359 | IOMemoryMap * map; |
360 | IOReturn kr; |
361 | uint32_t data; |
362 | uint32_t * p; |
363 | IOSimpleLock * lock; |
364 | |
365 | lock = IOSimpleLockAlloc(); |
366 | assert(lock); |
367 | |
368 | bmd = IOBufferMemoryDescriptor::inTaskWithOptions(current_task(), |
369 | kIODirectionOutIn | kIOMemoryPageable, ptoa(8)); |
370 | assert(bmd); |
371 | kr = bmd->prepare(); |
372 | assert(KERN_SUCCESS == kr); |
373 | |
374 | map = bmd->map(kIOMapPrefault); |
375 | assert(map); |
376 | |
377 | p = (typeof(p)) map->getVirtualAddress(); |
378 | IOSimpleLockLock(lock); |
379 | data = p[0]; |
380 | IOSimpleLockUnlock(lock); |
381 | |
382 | IOLog("IOMemoryPrefaultTest %d\n" , data); |
383 | |
384 | map->release(); |
385 | bmd->release(); |
386 | IOSimpleLockFree(lock); |
387 | |
388 | return (kIOReturnSuccess); |
389 | } |
390 | |
391 | |
392 | // <rdar://problem/26375234> |
393 | static IOReturn |
394 | ZeroLengthTest(int newValue) |
395 | { |
396 | IOMemoryDescriptor * md; |
397 | |
398 | md = IOMemoryDescriptor::withAddressRange( |
399 | 0, 0, kIODirectionNone, current_task()); |
400 | assert(md); |
401 | md->prepare(); |
402 | md->complete(); |
403 | md->release(); |
404 | return (0); |
405 | } |
406 | |
407 | // <rdar://problem/27002624> |
408 | static IOReturn |
409 | BadFixedAllocTest(int newValue) |
410 | { |
411 | IOBufferMemoryDescriptor * bmd; |
412 | IOMemoryMap * map; |
413 | |
414 | bmd = IOBufferMemoryDescriptor::inTaskWithOptions(NULL, |
415 | kIODirectionIn | kIOMemoryPageable, ptoa(1)); |
416 | assert(bmd); |
417 | map = bmd->createMappingInTask(kernel_task, 0x2000, 0); |
418 | assert(!map); |
419 | |
420 | bmd->release(); |
421 | return (0); |
422 | } |
423 | |
424 | // <rdar://problem/26466423> |
425 | static IOReturn |
426 | IODirectionPrepareNoZeroFillTest(int newValue) |
427 | { |
428 | IOBufferMemoryDescriptor * bmd; |
429 | |
430 | bmd = IOBufferMemoryDescriptor::inTaskWithOptions(NULL, |
431 | kIODirectionIn | kIOMemoryPageable, ptoa(24)); |
432 | assert(bmd); |
433 | bmd->prepare((IODirection)(kIODirectionIn | kIODirectionPrepareNoZeroFill)); |
434 | bmd->prepare(kIODirectionIn); |
435 | bmd->complete((IODirection)(kIODirectionIn | kIODirectionCompleteWithDataValid)); |
436 | bmd->complete(kIODirectionIn); |
437 | bmd->release(); |
438 | return (0); |
439 | } |
440 | |
441 | // <rdar://problem/28190483> |
442 | static IOReturn |
443 | IOMemoryMapTest(uint32_t options) |
444 | { |
445 | IOBufferMemoryDescriptor * bmd; |
446 | IOMemoryDescriptor * md; |
447 | IOMemoryMap * map; |
448 | uint32_t data; |
449 | user_addr_t p; |
450 | uint8_t * p2; |
451 | int r; |
452 | uint64_t time, nano; |
453 | |
454 | bmd = IOBufferMemoryDescriptor::inTaskWithOptions(current_task(), |
455 | kIODirectionOutIn | kIOMemoryPageable, 0x4018+0x800); |
456 | assert(bmd); |
457 | p = (typeof(p)) bmd->getBytesNoCopy(); |
458 | p += 0x800; |
459 | data = 0x11111111; |
460 | r = copyout(&data, p, sizeof(data)); |
461 | assert(r == 0); |
462 | data = 0x22222222; |
463 | r = copyout(&data, p + 0x1000, sizeof(data)); |
464 | assert(r == 0); |
465 | data = 0x33333333; |
466 | r = copyout(&data, p + 0x2000, sizeof(data)); |
467 | assert(r == 0); |
468 | data = 0x44444444; |
469 | r = copyout(&data, p + 0x3000, sizeof(data)); |
470 | assert(r == 0); |
471 | |
472 | md = IOMemoryDescriptor::withAddressRange(p, 0x4018, |
473 | kIODirectionOut | options, |
474 | current_task()); |
475 | assert(md); |
476 | time = mach_absolute_time(); |
477 | map = md->map(kIOMapReadOnly); |
478 | time = mach_absolute_time() - time; |
479 | assert(map); |
480 | absolutetime_to_nanoseconds(time, &nano); |
481 | |
482 | p2 = (typeof(p2)) map->getVirtualAddress(); |
483 | assert(0x11 == p2[0]); |
484 | assert(0x22 == p2[0x1000]); |
485 | assert(0x33 == p2[0x2000]); |
486 | assert(0x44 == p2[0x3000]); |
487 | |
488 | data = 0x99999999; |
489 | r = copyout(&data, p + 0x2000, sizeof(data)); |
490 | assert(r == 0); |
491 | |
492 | assert(0x11 == p2[0]); |
493 | assert(0x22 == p2[0x1000]); |
494 | assert(0x44 == p2[0x3000]); |
495 | if (kIOMemoryMapCopyOnWrite & options) assert(0x33 == p2[0x2000]); |
496 | else assert(0x99 == p2[0x2000]); |
497 | |
498 | IOLog("IOMemoryMapCopyOnWriteTest map(%s) %lld ns\n" , |
499 | kIOMemoryMapCopyOnWrite & options ? "kIOMemoryMapCopyOnWrite" : "" , |
500 | nano); |
501 | |
502 | map->release(); |
503 | md->release(); |
504 | bmd->release(); |
505 | |
506 | return (kIOReturnSuccess); |
507 | } |
508 | |
509 | static int |
510 | IOMemoryMapCopyOnWriteTest(int newValue) |
511 | { |
512 | IOMemoryMapTest(0); |
513 | IOMemoryMapTest(kIOMemoryMapCopyOnWrite); |
514 | return (0); |
515 | } |
516 | |
517 | static int |
518 | AllocationNameTest(int newValue) |
519 | { |
520 | IOMemoryDescriptor * bmd; |
521 | kern_allocation_name_t name, prior; |
522 | |
523 | name = kern_allocation_name_allocate("com.apple.iokit.test" , 0); |
524 | assert(name); |
525 | |
526 | prior = thread_set_allocation_name(name); |
527 | |
528 | bmd = IOBufferMemoryDescriptor::inTaskWithOptions(TASK_NULL, |
529 | kIODirectionOutIn | kIOMemoryPageable | kIOMemoryKernelUserShared, |
530 | ptoa(13)); |
531 | assert(bmd); |
532 | bmd->prepare(); |
533 | |
534 | thread_set_allocation_name(prior); |
535 | kern_allocation_name_release(name); |
536 | |
537 | if (newValue != 7) bmd->release(); |
538 | |
539 | return (0); |
540 | } |
541 | |
542 | int IOMemoryDescriptorTest(int newValue) |
543 | { |
544 | int result; |
545 | |
546 | IOLog("/IOMemoryDescriptorTest %d\n" , (int) gIOMemoryReferenceCount); |
547 | |
548 | #if 0 |
549 | if (6 == newValue) |
550 | { |
551 | IOMemoryDescriptor * sbmds[3]; |
552 | IOMultiMemoryDescriptor * smmd; |
553 | IOMemoryDescriptor * mds[2]; |
554 | IOMultiMemoryDescriptor * mmd; |
555 | IOMemoryMap * map; |
556 | |
557 | sbmds[0] = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, kIODirectionOutIn | kIOMemoryKernelUserShared, ptoa(1)); |
558 | sbmds[1] = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, kIODirectionOutIn | kIOMemoryKernelUserShared, ptoa(2)); |
559 | sbmds[2] = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, kIODirectionOutIn | kIOMemoryKernelUserShared, ptoa(3)); |
560 | smmd = IOMultiMemoryDescriptor::withDescriptors(&sbmds[0], sizeof(sbmds)/sizeof(sbmds[0]), kIODirectionOutIn, false); |
561 | |
562 | mds[0] = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, kIODirectionOutIn | kIOMemoryKernelUserShared, ptoa(1)); |
563 | mds[1] = smmd; |
564 | mmd = IOMultiMemoryDescriptor::withDescriptors(&mds[0], sizeof(mds)/sizeof(mds[0]), kIODirectionOutIn, false); |
565 | map = mmd->createMappingInTask(kernel_task, 0, kIOMapAnywhere); |
566 | assert(map); |
567 | map->release(); |
568 | mmd->release(); |
569 | mds[0]->release(); |
570 | mds[1]->release(); |
571 | sbmds[0]->release(); |
572 | sbmds[1]->release(); |
573 | sbmds[2]->release(); |
574 | |
575 | return (0); |
576 | } |
577 | else if (5 == newValue) |
578 | { |
579 | IOReturn ret; |
580 | IOMemoryDescriptor * md; |
581 | IODMACommand * dma; |
582 | IODMACommand::SegmentOptions segOptions = |
583 | { |
584 | .fStructSize = sizeof(segOptions), |
585 | .fNumAddressBits = 64, |
586 | .fMaxSegmentSize = 4096, |
587 | .fMaxTransferSize = 128*1024, |
588 | .fAlignment = 4, |
589 | .fAlignmentLength = 4, |
590 | .fAlignmentInternalSegments = 0x1000 |
591 | }; |
592 | |
593 | IOAddressRange ranges[3][2] = |
594 | { |
595 | { |
596 | { (uintptr_t) &IOMemoryDescriptorTest, 0x2ffc }, |
597 | { 0, 0 }, |
598 | }, |
599 | { |
600 | { ranges[0][0].address, 0x10 }, |
601 | { 0x3000 + ranges[0][0].address, 0xff0 }, |
602 | }, |
603 | { |
604 | { ranges[0][0].address, 0x2ffc }, |
605 | { trunc_page(ranges[0][0].address), 0x800 }, |
606 | }, |
607 | }; |
608 | static const uint32_t rangesCount[3] = { 1, 2, 2 }; |
609 | uint32_t test; |
610 | |
611 | for (test = 0; test < 3; test++) |
612 | { |
613 | kprintf("---[%d] address 0x%qx-0x%qx, 0x%qx-0x%qx\n" , test, |
614 | ranges[test][0].address, ranges[test][0].length, |
615 | ranges[test][1].address, ranges[test][1].length); |
616 | |
617 | md = IOMemoryDescriptor::withAddressRanges((IOAddressRange*)&ranges[test][0], rangesCount[test], kIODirectionOut, kernel_task); |
618 | assert(md); |
619 | ret = md->prepare(); |
620 | assert(kIOReturnSuccess == ret); |
621 | dma = IODMACommand::withSpecification(kIODMACommandOutputHost64, &segOptions, |
622 | IODMACommand::kMapped, NULL, NULL); |
623 | assert(dma); |
624 | ret = dma->setMemoryDescriptor(md, true); |
625 | if (kIOReturnSuccess == ret) |
626 | { |
627 | IODMACommand::Segment64 segments[1]; |
628 | UInt32 numSegments; |
629 | UInt64 offset; |
630 | |
631 | offset = 0; |
632 | do |
633 | { |
634 | numSegments = 1; |
635 | ret = dma->gen64IOVMSegments(&offset, &segments[0], &numSegments); |
636 | assert(kIOReturnSuccess == ret); |
637 | assert(1 == numSegments); |
638 | kprintf("seg 0x%qx, 0x%qx\n" , segments[0].fIOVMAddr, segments[0].fLength); |
639 | } |
640 | while (offset < md->getLength()); |
641 | |
642 | ret = dma->clearMemoryDescriptor(true); |
643 | assert(kIOReturnSuccess == ret); |
644 | dma->release(); |
645 | } |
646 | md->release(); |
647 | } |
648 | |
649 | return (kIOReturnSuccess); |
650 | } |
651 | else if (4 == newValue) |
652 | { |
653 | IOService * isp; |
654 | IOMapper * mapper; |
655 | IOBufferMemoryDescriptor * md1; |
656 | IODMACommand * dma; |
657 | IOReturn ret; |
658 | size_t bufSize = 8192 * 8192 * sizeof(uint32_t); |
659 | uint64_t start, time, nano; |
660 | |
661 | isp = IOService::copyMatchingService(IOService::nameMatching("isp" )); |
662 | assert(isp); |
663 | mapper = IOMapper::copyMapperForDeviceWithIndex(isp, 0); |
664 | assert(mapper); |
665 | |
666 | md1 = IOBufferMemoryDescriptor::inTaskWithOptions(TASK_NULL, |
667 | kIODirectionOutIn | kIOMemoryPersistent | kIOMemoryPageable, |
668 | bufSize, page_size); |
669 | |
670 | ret = md1->prepare(); |
671 | assert(kIOReturnSuccess == ret); |
672 | |
673 | IODMAMapSpecification mapSpec; |
674 | bzero(&mapSpec, sizeof(mapSpec)); |
675 | uint64_t mapped; |
676 | uint64_t mappedLength; |
677 | |
678 | start = mach_absolute_time(); |
679 | |
680 | ret = md1->dmaMap(mapper, NULL, &mapSpec, 0, bufSize, &mapped, &mappedLength); |
681 | assert(kIOReturnSuccess == ret); |
682 | |
683 | time = mach_absolute_time() - start; |
684 | |
685 | absolutetime_to_nanoseconds(time, &nano); |
686 | kprintf("time %lld us\n" , nano / 1000ULL); |
687 | kprintf("seg0 0x%qx, 0x%qx\n" , mapped, mappedLength); |
688 | |
689 | assert(md1); |
690 | |
691 | dma = IODMACommand::withSpecification(kIODMACommandOutputHost32, |
692 | 32, 0, IODMACommand::kMapped, 0, 1, mapper, NULL); |
693 | |
694 | assert(dma); |
695 | |
696 | start = mach_absolute_time(); |
697 | ret = dma->setMemoryDescriptor(md1, true); |
698 | assert(kIOReturnSuccess == ret); |
699 | time = mach_absolute_time() - start; |
700 | |
701 | absolutetime_to_nanoseconds(time, &nano); |
702 | kprintf("time %lld us\n" , nano / 1000ULL); |
703 | |
704 | |
705 | IODMACommand::Segment32 segments[1]; |
706 | UInt32 numSegments = 1; |
707 | UInt64 offset; |
708 | |
709 | offset = 0; |
710 | ret = dma->gen32IOVMSegments(&offset, &segments[0], &numSegments); |
711 | assert(kIOReturnSuccess == ret); |
712 | assert(1 == numSegments); |
713 | kprintf("seg0 0x%x, 0x%x\n" , (int)segments[0].fIOVMAddr, (int)segments[0].fLength); |
714 | |
715 | ret = dma->clearMemoryDescriptor(true); |
716 | assert(kIOReturnSuccess == ret); |
717 | |
718 | md1->release(); |
719 | |
720 | return (kIOReturnSuccess); |
721 | } |
722 | |
723 | if (3 == newValue) |
724 | { |
725 | IOBufferMemoryDescriptor * md1; |
726 | IOBufferMemoryDescriptor * md2; |
727 | IOMemoryMap * map1; |
728 | IOMemoryMap * map2; |
729 | uint32_t * buf1; |
730 | uint32_t * buf2; |
731 | IOReturn err; |
732 | |
733 | md1 = IOBufferMemoryDescriptor::inTaskWithOptions(TASK_NULL, |
734 | kIODirectionOutIn | kIOMemoryPersistent | kIOMemoryPageable, |
735 | 64*1024, page_size); |
736 | assert(md1); |
737 | map1 = md1->createMappingInTask(kernel_task, 0, kIOMapAnywhere | kIOMapUnique); |
738 | assert(map1); |
739 | buf1 = (uint32_t *) map1->getVirtualAddress(); |
740 | |
741 | md2 = IOBufferMemoryDescriptor::inTaskWithOptions(TASK_NULL, |
742 | kIODirectionOutIn | kIOMemoryPersistent | kIOMemoryPageable, |
743 | 64*1024, page_size); |
744 | assert(md2); |
745 | map2 = md2->createMappingInTask(kernel_task, 0, kIOMapAnywhere | kIOMapUnique); |
746 | assert(map2); |
747 | buf2 = (uint32_t *) map2->getVirtualAddress(); |
748 | |
749 | memset(buf1, 0x11, 64*1024L); |
750 | memset(buf2, 0x22, 64*1024L); |
751 | |
752 | kprintf("md1 %p, map1 %p, buf2 %p; md2 %p, map2 %p, buf2 %p\n" , md1, map1, buf1, md2, map2, buf2); |
753 | |
754 | kprintf("no redir 0x%08x, 0x%08x\n" , buf1[0], buf2[0]); |
755 | assert(0x11111111 == buf1[0]); |
756 | assert(0x22222222 == buf2[0]); |
757 | err = map1->redirect(md2, 0, 0ULL); |
758 | kprintf("redir md2(0x%x) 0x%08x, 0x%08x\n" , err, buf1[0], buf2[0]); |
759 | assert(0x11111111 == buf2[0]); |
760 | assert(0x22222222 == buf1[0]); |
761 | err = map1->redirect(md1, 0, 0ULL); |
762 | kprintf("redir md1(0x%x) 0x%08x, 0x%08x\n" , err, buf1[0], buf2[0]); |
763 | assert(0x11111111 == buf1[0]); |
764 | assert(0x22222222 == buf2[0]); |
765 | map1->release(); |
766 | map2->release(); |
767 | md1->release(); |
768 | md2->release(); |
769 | } |
770 | #endif |
771 | |
772 | // result = IODMACommandLocalMappedNonContig(newValue); |
773 | // if (result) return (result); |
774 | |
775 | result = IODMACommandForceDoubleBufferTest(newValue); |
776 | if (result) return (result); |
777 | |
778 | result = AllocationNameTest(newValue); |
779 | if (result) return (result); |
780 | |
781 | result = IOMemoryMapCopyOnWriteTest(newValue); |
782 | if (result) return (result); |
783 | |
784 | result = IOMultMemoryDescriptorTest(newValue); |
785 | if (result) return (result); |
786 | |
787 | result = ZeroLengthTest(newValue); |
788 | if (result) return (result); |
789 | |
790 | result = IODirectionPrepareNoZeroFillTest(newValue); |
791 | if (result) return (result); |
792 | |
793 | result = BadFixedAllocTest(newValue); |
794 | if (result) return (result); |
795 | |
796 | result = IOMemoryRemoteTest(newValue); |
797 | if (result) return (result); |
798 | |
799 | result = IOMemoryPrefaultTest(newValue); |
800 | if (result) return (result); |
801 | |
802 | IOGeneralMemoryDescriptor * md; |
803 | vm_offset_t data[2]; |
804 | vm_size_t bsize = 16*1024*1024; |
805 | vm_size_t srcsize, srcoffset, mapoffset, size; |
806 | kern_return_t kr; |
807 | |
808 | data[0] = data[1] = 0; |
809 | kr = vm_allocate_kernel(kernel_map, &data[0], bsize, VM_FLAGS_ANYWHERE, VM_KERN_MEMORY_IOKIT); |
810 | assert(KERN_SUCCESS == kr); |
811 | |
812 | vm_inherit(kernel_map, data[0] + ptoa(1), ptoa(1), VM_INHERIT_NONE); |
813 | vm_inherit(kernel_map, data[0] + ptoa(16), ptoa(4), VM_INHERIT_NONE); |
814 | |
815 | IOLog("data 0x%lx, 0x%lx\n" , (long)data[0], (long)data[1]); |
816 | |
817 | uint32_t idx, offidx; |
818 | for (idx = 0; idx < (bsize / sizeof(uint32_t)); idx++) |
819 | { |
820 | ((uint32_t*)data[0])[idx] = idx; |
821 | } |
822 | |
823 | for (srcoffset = 0; srcoffset < bsize; srcoffset = ((srcoffset << 2) + 0x40c)) |
824 | { |
825 | for (srcsize = 4; srcsize < (bsize - srcoffset - 1); srcsize = ((srcsize << 2) + 0x3fc)) |
826 | { |
827 | IOAddressRange ranges[3]; |
828 | uint32_t rangeCount = 1; |
829 | |
830 | bzero(&ranges[0], sizeof(ranges)); |
831 | ranges[0].address = data[0] + srcoffset; |
832 | ranges[0].length = srcsize; |
833 | ranges[1].address = ranges[2].address = data[0]; |
834 | |
835 | if (srcsize > ptoa(5)) |
836 | { |
837 | ranges[0].length = 7634; |
838 | ranges[1].length = 9870; |
839 | ranges[2].length = srcsize - ranges[0].length - ranges[1].length; |
840 | ranges[1].address = ranges[0].address + ranges[0].length; |
841 | ranges[2].address = ranges[1].address + ranges[1].length; |
842 | rangeCount = 3; |
843 | } |
844 | else if ((srcsize > ptoa(2)) && !(page_mask & srcoffset)) |
845 | { |
846 | ranges[0].length = ptoa(1); |
847 | ranges[1].length = ptoa(1); |
848 | ranges[2].length = srcsize - ranges[0].length - ranges[1].length; |
849 | ranges[0].address = data[0] + srcoffset + ptoa(1); |
850 | ranges[1].address = data[0] + srcoffset; |
851 | ranges[2].address = ranges[0].address + ranges[0].length; |
852 | rangeCount = 3; |
853 | } |
854 | |
855 | md = OSDynamicCast(IOGeneralMemoryDescriptor, |
856 | IOMemoryDescriptor::withAddressRanges(&ranges[0], rangeCount, kIODirectionInOut, kernel_task)); |
857 | assert(md); |
858 | |
859 | IOLog("IOMemoryDescriptor::withAddressRanges [0x%lx @ 0x%lx]\n[0x%llx, 0x%llx],\n[0x%llx, 0x%llx],\n[0x%llx, 0x%llx]\n" , |
860 | (long) srcsize, (long) srcoffset, |
861 | (long long) ranges[0].address - data[0], (long long) ranges[0].length, |
862 | (long long) ranges[1].address - data[0], (long long) ranges[1].length, |
863 | (long long) ranges[2].address - data[0], (long long) ranges[2].length); |
864 | |
865 | if (kIOReturnSuccess == kr) |
866 | { |
867 | for (mapoffset = 0; mapoffset < srcsize; mapoffset = ((mapoffset << 1) + 0xf00)) |
868 | { |
869 | for (size = 4; size < (srcsize - mapoffset - 1); size = ((size << 2) + 0x200)) |
870 | { |
871 | IOMemoryMap * map; |
872 | mach_vm_address_t addr = 0; |
873 | uint32_t data; |
874 | |
875 | // IOLog("<mapRef [0x%lx @ 0x%lx]\n", (long) size, (long) mapoffset); |
876 | |
877 | map = md->createMappingInTask(kernel_task, 0, kIOMapAnywhere, mapoffset, size); |
878 | if (map) addr = map->getAddress(); |
879 | else kr = kIOReturnError; |
880 | |
881 | // IOLog(">mapRef 0x%x %llx\n", kr, addr); |
882 | |
883 | if (kIOReturnSuccess != kr) break; |
884 | kr = md->prepare(); |
885 | if (kIOReturnSuccess != kr) |
886 | { |
887 | panic("prepare() fail 0x%x\n" , kr); |
888 | break; |
889 | } |
890 | for (idx = 0; idx < size; idx += sizeof(uint32_t)) |
891 | { |
892 | offidx = (idx + mapoffset + srcoffset); |
893 | if ((srcsize <= ptoa(5)) && (srcsize > ptoa(2)) && !(page_mask & srcoffset)) |
894 | { |
895 | if (offidx < ptoa(2)) offidx ^= ptoa(1); |
896 | } |
897 | offidx /= sizeof(uint32_t); |
898 | |
899 | if (offidx != ((uint32_t*)addr)[idx/sizeof(uint32_t)]) |
900 | { |
901 | panic("vm mismatch md %p map %p, @ 0x%x, 0x%lx, 0x%lx, \n" , md, map, idx, (long) srcoffset, (long) mapoffset); |
902 | kr = kIOReturnBadMedia; |
903 | } |
904 | else |
905 | { |
906 | if (sizeof(data) != md->readBytes(mapoffset + idx, &data, sizeof(data))) data = 0; |
907 | if (offidx != data) |
908 | { |
909 | panic("phys mismatch md %p map %p, @ 0x%x, 0x%lx, 0x%lx, \n" , md, map, idx, (long) srcoffset, (long) mapoffset); |
910 | kr = kIOReturnBadMedia; |
911 | } |
912 | } |
913 | } |
914 | md->complete(); |
915 | map->release(); |
916 | // IOLog("unmapRef %llx\n", addr); |
917 | } |
918 | if (kIOReturnSuccess != kr) break; |
919 | } |
920 | } |
921 | md->release(); |
922 | if (kIOReturnSuccess != kr) break; |
923 | } |
924 | if (kIOReturnSuccess != kr) break; |
925 | } |
926 | |
927 | if (kIOReturnSuccess != kr) IOLog("FAIL: src 0x%lx @ 0x%lx, map 0x%lx @ 0x%lx\n" , |
928 | (long) srcsize, (long) srcoffset, (long) size, (long) mapoffset); |
929 | |
930 | assert(kr == kIOReturnSuccess); |
931 | |
932 | vm_deallocate(kernel_map, data[0], bsize); |
933 | // vm_deallocate(kernel_map, data[1], size); |
934 | |
935 | IOLog("IOMemoryDescriptorTest/ %d\n" , (int) gIOMemoryReferenceCount); |
936 | |
937 | return (0); |
938 | } |
939 | |
940 | #endif /* DEVELOPMENT || DEBUG */ |
941 | |