1 | #include "TestIODeviceMemoryRosetta.h" |
2 | #include <IOKit/IOService.h> |
3 | #include <IOKit/IOUserClient.h> |
4 | #include <IOKit/IOKitServer.h> |
5 | #include <kern/ipc_kobject.h> |
6 | |
7 | #if (DEVELOPMENT || DEBUG) && XNU_TARGET_OS_OSX |
8 | |
9 | OSDefineMetaClassAndStructors(TestIODeviceMemoryRosetta, IOService); |
10 | |
11 | OSDefineMetaClassAndStructors(TestIODeviceMemoryRosettaUserClient, IOUserClient2022); |
12 | |
13 | bool |
14 | TestIODeviceMemoryRosetta::start(IOService * provider) |
15 | { |
16 | OSString * str = OSString::withCStringNoCopy("TestIODeviceMemoryRosettaUserClient" ); |
17 | bool ret = IOService::start(provider); |
18 | if (ret && str != NULL) { |
19 | setProperty(gIOUserClientClassKey, str); |
20 | registerService(); |
21 | } |
22 | OSSafeReleaseNULL(str); |
23 | return ret; |
24 | } |
25 | |
26 | bool |
27 | TestIODeviceMemoryRosettaUserClient::start(IOService * provider) |
28 | { |
29 | if (!IOUserClient2022::start(provider)) { |
30 | return false; |
31 | } |
32 | setProperty(kIOUserClientDefaultLockingKey, kOSBooleanTrue); |
33 | setProperty(kIOUserClientDefaultLockingSetPropertiesKey, kOSBooleanTrue); |
34 | setProperty(kIOUserClientDefaultLockingSingleThreadExternalMethodKey, kOSBooleanTrue); |
35 | |
36 | setProperty(kIOUserClientEntitlementsKey, kOSBooleanFalse); |
37 | |
38 | return true; |
39 | } |
40 | |
41 | IOReturn |
42 | TestIODeviceMemoryRosettaUserClient::clientClose() |
43 | { |
44 | if (!isInactive()) { |
45 | terminate(); |
46 | } |
47 | return kIOReturnSuccess; |
48 | } |
49 | |
50 | struct TestIODeviceMemoryRosettaUserClientArgs { |
51 | uint64_t size; |
52 | uint64_t offset; |
53 | uint64_t deviceMemoryOffset; |
54 | uint64_t length; |
55 | uint64_t xorkey; |
56 | }; |
57 | |
58 | struct TestIODeviceMemoryRosettaUserClientOutput { |
59 | mach_vm_address_t address; |
60 | mach_vm_size_t size; |
61 | }; |
62 | |
63 | IOReturn |
64 | TestIODeviceMemoryRosettaUserClient::externalMethodDispatched(IOExternalMethodArguments * args) |
65 | { |
66 | IOReturn ret = kIOReturnError; |
67 | IOMemoryMap * map = NULL; |
68 | IODeviceMemory * deviceMemory = NULL; |
69 | uint64_t * buf; |
70 | |
71 | TestIODeviceMemoryRosettaUserClientArgs * userClientArgs = (TestIODeviceMemoryRosettaUserClientArgs *)args->structureInput; |
72 | TestIODeviceMemoryRosettaUserClientOutput * userClientOutput = (TestIODeviceMemoryRosettaUserClientOutput *)args->structureOutput; |
73 | |
74 | if (userClientArgs->size % sizeof(uint64_t) != 0) { |
75 | return kIOReturnBadArgument; |
76 | } |
77 | |
78 | if (userClientArgs->size + userClientArgs->deviceMemoryOffset > phys_carveout_size) { |
79 | return kIOReturnBadArgument; |
80 | } |
81 | |
82 | // Create memory descriptor using the physical carveout |
83 | deviceMemory = IODeviceMemory::withRange(phys_carveout_pa + userClientArgs->deviceMemoryOffset, userClientArgs->size); |
84 | if (!deviceMemory) { |
85 | printf("Failed to allocate device memory\n" ); |
86 | goto finish; |
87 | } |
88 | |
89 | // Fill carveout memory with known values, xored with the key |
90 | buf = (uint64_t *)phys_carveout; |
91 | for (uint64_t idx = 0; idx < (userClientArgs->deviceMemoryOffset + userClientArgs->size) / sizeof(uint64_t); idx++) { |
92 | buf[idx] = idx ^ userClientArgs->xorkey; |
93 | } |
94 | |
95 | // Map the memory descriptor |
96 | map = deviceMemory->createMappingInTask(current_task(), 0, kIOMapAnywhere, userClientArgs->offset, userClientArgs->length); |
97 | |
98 | if (map) { |
99 | // Release map when task exits |
100 | userClientOutput->address = map->getAddress(); |
101 | userClientOutput->size = map->getSize(); |
102 | mach_port_name_t name __unused = iokit_make_send_right(current_task(), map, IKOT_IOKIT_OBJECT); |
103 | ret = kIOReturnSuccess; |
104 | } |
105 | |
106 | finish: |
107 | OSSafeReleaseNULL(map); |
108 | OSSafeReleaseNULL(deviceMemory); |
109 | return ret; |
110 | } |
111 | |
112 | static IOReturn |
113 | TestIODeviceMemoryRosettaMethodDispatched(OSObject * target, void * reference, IOExternalMethodArguments * arguments) |
114 | { |
115 | TestIODeviceMemoryRosettaUserClient * |
116 | me = OSRequiredCast(TestIODeviceMemoryRosettaUserClient, target); |
117 | return me->externalMethodDispatched(arguments); |
118 | } |
119 | |
120 | IOReturn |
121 | TestIODeviceMemoryRosettaUserClient::externalMethod(uint32_t selector, IOExternalMethodArgumentsOpaque * args) |
122 | { |
123 | static const IOExternalMethodDispatch2022 dispatchArray[] = { |
124 | [0] { |
125 | .function = &TestIODeviceMemoryRosettaMethodDispatched, |
126 | .checkScalarInputCount = 0, |
127 | .checkStructureInputSize = sizeof(TestIODeviceMemoryRosettaUserClientArgs), |
128 | .checkScalarOutputCount = 0, |
129 | .checkStructureOutputSize = sizeof(TestIODeviceMemoryRosettaUserClientOutput), |
130 | .allowAsync = false, |
131 | .checkEntitlement = "com.apple.iokit.test-check-entitlement" , |
132 | }, |
133 | }; |
134 | |
135 | return dispatchExternalMethod(selector, args, dispatchArray, sizeof(dispatchArray) / sizeof(dispatchArray[0]), this, NULL); |
136 | } |
137 | |
138 | #endif /* (DEVELOPMENT || DEBUG) && XNU_TARGET_OS_OSX */ |
139 | |