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, IOUserClient);
12
13 bool
start(IOService * provider)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
27 IOReturn
clientClose()28 TestIODeviceMemoryRosettaUserClient::clientClose()
29 {
30 if (!isInactive()) {
31 terminate();
32 }
33 return kIOReturnSuccess;
34 }
35
36 IOReturn
externalMethod(uint32_t selector,IOExternalMethodArguments * args,IOExternalMethodDispatch * dispatch,OSObject * target,void * reference)37 TestIODeviceMemoryRosettaUserClient::externalMethod(uint32_t selector, IOExternalMethodArguments * args,
38 IOExternalMethodDispatch * dispatch, OSObject * target, void * reference)
39 {
40 IOReturn ret = kIOReturnError;
41 IOMemoryMap * map = NULL;
42 IODeviceMemory * deviceMemory = NULL;
43 uint64_t * buf;
44
45 struct TestIODeviceMemoryRosettaUserClientArgs {
46 uint64_t size;
47 uint64_t offset;
48 uint64_t deviceMemoryOffset;
49 uint64_t length;
50 uint64_t xorkey;
51 };
52
53 struct TestIODeviceMemoryRosettaUserClientOutput {
54 mach_vm_address_t address;
55 mach_vm_size_t size;
56 };
57
58 if (args->structureInputSize != sizeof(TestIODeviceMemoryRosettaUserClientArgs)) {
59 return kIOReturnBadArgument;
60 }
61
62 if (args->structureOutputSize != sizeof(TestIODeviceMemoryRosettaUserClientOutput)) {
63 return kIOReturnBadArgument;
64 }
65
66 TestIODeviceMemoryRosettaUserClientArgs * userClientArgs = (TestIODeviceMemoryRosettaUserClientArgs *)args->structureInput;
67 TestIODeviceMemoryRosettaUserClientOutput * userClientOutput = (TestIODeviceMemoryRosettaUserClientOutput *)args->structureOutput;
68
69 if (userClientArgs->size % sizeof(uint64_t) != 0) {
70 return kIOReturnBadArgument;
71 }
72
73 if (userClientArgs->size + userClientArgs->deviceMemoryOffset > phys_carveout_size) {
74 return kIOReturnBadArgument;
75 }
76
77 // Create memory descriptor using the physical carveout
78 deviceMemory = IODeviceMemory::withRange(phys_carveout_pa + userClientArgs->deviceMemoryOffset, userClientArgs->size);
79 if (!deviceMemory) {
80 printf("Failed to allocate device memory\n");
81 goto finish;
82 }
83
84 // Fill carveout memory with known values, xored with the key
85 buf = (uint64_t *)phys_carveout;
86 for (uint64_t idx = 0; idx < (userClientArgs->deviceMemoryOffset + userClientArgs->size) / sizeof(uint64_t); idx++) {
87 buf[idx] = idx ^ userClientArgs->xorkey;
88 }
89
90 // Map the memory descriptor
91 map = deviceMemory->createMappingInTask(current_task(), 0, kIOMapAnywhere, userClientArgs->offset, userClientArgs->length);
92
93 if (map) {
94 // Release map when task exits
95 userClientOutput->address = map->getAddress();
96 userClientOutput->size = map->getSize();
97 mach_port_name_t name __unused = iokit_make_send_right(current_task(), map, IKOT_IOKIT_OBJECT);
98 ret = kIOReturnSuccess;
99 }
100
101 finish:
102 OSSafeReleaseNULL(map);
103 OSSafeReleaseNULL(deviceMemory);
104 return ret;
105 }
106
107 #endif /* (DEVELOPMENT || DEBUG) && XNU_TARGET_OS_OSX */
108