1 | ␉/*␊ |
2 | * Copyright (c) 2010 Evan Lojewski. All rights reserved.␊ |
3 | *␉␊ |
4 | *␉KextPather␊ |
5 | *␉This is an experimental module that I'm looking into implimenting.␊ |
6 | *␉The main purpose is to replace the need for programs such as ␊ |
7 | * NetbookInstaller's kext patching routines. THis way, Apple's kexts can be␊ |
8 | * patched whe loaded instead. (eg: GMA950 kext, Bluetooth + Wifi kexts)␊ |
9 | */␊ |
10 | ␊ |
11 | #include "libsaio.h"␊ |
12 | #include "zlib.h"␊ |
13 | #include "kext_patcher.h"␊ |
14 | #include "boot.h"␊ |
15 | #include "bootstruct.h"␊ |
16 | #include "pci.h"␊ |
17 | #include "drivers.h"␊ |
18 | #include "mkext.h"␊ |
19 | #include "modules.h"␊ |
20 | #include "hex_editor.h"␊ |
21 | ␊ |
22 | ␊ |
23 | #define kHDACodec␉␉␉␉"HDACodec"␊ |
24 | ␊ |
25 | ␊ |
26 | #ifndef DEBUG_KEXT_PATCHER␊ |
27 | #define DEBUG_KEXT_PATCHER 1␊ |
28 | #endif␊ |
29 | ␊ |
30 | #if DEBUG_KEXT_PATCHER␊ |
31 | #define DBG(x...)␉printf(x)␊ |
32 | #else␊ |
33 | #define DBG(x...)␊ |
34 | #endif␊ |
35 | ␊ |
36 | ␊ |
37 | bool patch_kext(TagPtr plist, char* plistbuffer, void* start);␊ |
38 | bool patch_hda_kext(TagPtr plist, char* plistbuffer, void* start);␊ |
39 | bool patch_hda_controller(TagPtr plist, char* plistbuffer, void* start);␊ |
40 | ␊ |
41 | ␊ |
42 | ␊ |
43 | static void * z_alloc(void *, u_int items, u_int size);␊ |
44 | static void z_free(void *, void *ptr);␊ |
45 | ␊ |
46 | #if UNUSED␊ |
47 | void KextPatcher_hook(void* current, void* arg2, void* arg3, void* arg4, void* arg5, void* arg6);␊ |
48 | bool patch_gma_kexts(TagPtr plist, char* plistbuffer, void* start);␊ |
49 | bool patch_bcm_kext(TagPtr plist, char* plistbuffer, void* start);␊ |
50 | int chartohex(char c);␊ |
51 | uint16_t patch_gma_deviceid = 0;␊ |
52 | uint16_t patch_bcm_deviceid = 0;␊ |
53 | // TODO: add detection code / a method for users to enter the id␊ |
54 | uint16_t patch_hda_codec = 0;␊ |
55 | ␊ |
56 | #define NEEDS_PATCHING␉␉(patch_bcm_deviceid || patch_gma_deviceid || patch_hda_codec)␊ |
57 | #endif␊ |
58 | ␊ |
59 | typedef struct z_mem {␊ |
60 | uint32_t alloc_size;␊ |
61 | uint8_t data[0];␊ |
62 | } z_mem;␊ |
63 | ␊ |
64 | /*␊ |
65 | * Space allocation and freeing routines for use by zlib routines.␊ |
66 | */␊ |
67 | void *␊ |
68 | z_alloc(void * notused __unused, u_int num_items, u_int size)␊ |
69 | {␊ |
70 | void * result = NULL;␊ |
71 | z_mem * zmem = NULL;␊ |
72 | uint32_t total = num_items * size;␊ |
73 | uint32_t allocSize = total + sizeof(zmem);␊ |
74 | ␊ |
75 | zmem = (z_mem *)malloc(allocSize);␊ |
76 | if (!zmem) {␊ |
77 | goto finish;␊ |
78 | }␊ |
79 | zmem->alloc_size = allocSize;␊ |
80 | result = (void *)&(zmem->data);␊ |
81 | finish:␊ |
82 | return result;␊ |
83 | }␊ |
84 | ␊ |
85 | void␊ |
86 | z_free(void * notused __unused, void * ptr)␊ |
87 | {␊ |
88 | uint32_t * skipper = (uint32_t *)ptr - 1;␊ |
89 | z_mem * zmem = (z_mem *)skipper;␊ |
90 | free((void *)zmem);␊ |
91 | return;␊ |
92 | }␊ |
93 | ␊ |
94 | ␊ |
95 | //unsigned long Mkext_Alder32( unsigned char * buffer, long length );␊ |
96 | static unsigned long␊ |
97 | Mkext_Alder32( unsigned char * buffer, long length )␊ |
98 | {␊ |
99 | long cnt;␊ |
100 | unsigned long result, lowHalf, highHalf;␊ |
101 | ␊ |
102 | lowHalf = 1;␊ |
103 | highHalf = 0;␊ |
104 | ␉␊ |
105 | ␉for ( cnt = 0; cnt < length; cnt++ )␊ |
106 | {␊ |
107 | if ((cnt % 5000) == 0)␊ |
108 | {␊ |
109 | lowHalf %= 65521L;␊ |
110 | highHalf %= 65521L;␊ |
111 | }␊ |
112 | ␉␉␊ |
113 | lowHalf += buffer[cnt];␊ |
114 | highHalf += lowHalf;␊ |
115 | }␊ |
116 | ␉␊ |
117 | ␉lowHalf %= 65521L;␊ |
118 | ␉highHalf %= 65521L;␊ |
119 | ␉␊ |
120 | ␉result = (highHalf << 16) | lowHalf;␊ |
121 | ␉␊ |
122 | ␉return result;␊ |
123 | }␊ |
124 | ␊ |
125 | /**␊ |
126 | ** KextPatcher_start -> module start␊ |
127 | **␉␉Notified the module system that this module will hook into the ␊ |
128 | **␉␉LoadMatchedModules and LoadDriverMKext functions␊ |
129 | **/␊ |
130 | void KextPatcher_start()␊ |
131 | {␉␉␊ |
132 | ␉// Hooks into the following:␊ |
133 | ␉//␉execute_hook("LoadDriverMKext", (void*)package, (void*) length, NULL, NULL, NULL, NULL);␊ |
134 | ␉// execute_hook("LoadMatchedModules", module, &length, executableAddr, NULL, NULL, NULL);␊ |
135 | #if UNUSED␊ |
136 | ␉register_hook_callback("PCIDevice", &KextPatcher_hook);␊ |
137 | #endif␊ |
138 | ␉//register_hook_callback("LoadMatchedModules", &kext_loaded); ␊ |
139 | ␉register_hook_callback("LoadDriverMKext", &mkext_loaded); ␊ |
140 | ␊ |
141 | }␊ |
142 | ␊ |
143 | /**␊ |
144 | ** kext_loaded -> Called whenever a kext is in read into memory␊ |
145 | **␉␉This function will be used to patch kexts ( eg AppleInteIntegratedFramebuffer)␊ |
146 | **␉␉and their plists when they are loaded into memmory␊ |
147 | **/␊ |
148 | void kext_loaded(void* moduletmp, void* lengthprt, void* executableAddr, void* arg4, void* arg5, void* arg6)␊ |
149 | {␊ |
150 | ␉␊ |
151 | ␉//ModulePtr module = moduletmp;␊ |
152 | ␉//long length = *(long*)lengthprt;␊ |
153 | ␉//long length2 = strlen(module->plistAddr);␊ |
154 | ␉// *(long*)lengthprt = length2 + 5 * 1024 * 1024;␊ |
155 | ␊ |
156 | ␉//printf("Loading %s, lenght is %d, executable is 0x%X\n", module->plistAddr, length, executableAddr);␊ |
157 | ␉//getc();␊ |
158 | }␊ |
159 | ␊ |
160 | /**␊ |
161 | ** mkext_loaded -> Called whenever an mkext is in read into memory␊ |
162 | **␉␉This function will be used to patch mkext. Matching kexts will be␊ |
163 | **␉␉Extracted, modified, and then compressed again. Note: I need to determine␊ |
164 | **␉␉what sort of slowdown this will cause and if it's worth implimenting.␊ |
165 | **/␊ |
166 | ␊ |
167 | void mkext_loaded(void* filespec, void* packagetmp, void* lengthtmp, void* arg4, void* arg5, void* arg6)␊ |
168 | {␊ |
169 | #if UNUSED␊ |
170 | ␉const char* hda_codec;␊ |
171 | ␉int len = 0;␊ |
172 | ␉␊ |
173 | ␉if (getValueForKey(kHDACodec, &hda_codec, &len, &bootInfo->bootConfig))␊ |
174 | ␉{␊ |
175 | ␉␉int index = 0;␊ |
176 | ␉␉while(len)␊ |
177 | ␉␉{␊ |
178 | ␉␉␉patch_hda_codec <<= 4;␊ |
179 | ␉␉␉patch_hda_codec |= chartohex(hda_codec[index]);␊ |
180 | ␉␉␉len--;␊ |
181 | ␉␉␉index++;␊ |
182 | ␉␉}␊ |
183 | ␉}␊ |
184 | ␉␉␊ |
185 | ␉if(!NEEDS_PATCHING) return;␉// No need to apply a patch, hardware doesn't need it␊ |
186 | #endif␉␊ |
187 | ␉int version = 0;␊ |
188 | ␉//int length = *((int*)lengthtmp);␊ |
189 | ␉mkext_basic_header* package = (mkext_basic_header*)packagetmp;␊ |
190 | ␊ |
191 | ␉// Verify the MKext.␊ |
192 | if (( MKEXT_GET_MAGIC(package)␉␉!= MKEXT_MAGIC ) ||␊ |
193 | ( MKEXT_GET_SIGNATURE(package)␉!= MKEXT_SIGN ) ||␊ |
194 | ( MKEXT_GET_LENGTH(package)␉␉> kLoadSize )␉ ||␊ |
195 | ( MKEXT_GET_CHECKSUM(package) !=␊ |
196 | ␉␉ Mkext_Alder32((unsigned char *)&package->version, MKEXT_GET_LENGTH(package) - 0x10) ) )␊ |
197 | {␊ |
198 | ␉␉return;␊ |
199 | ␉␉// Don't try to patch a b␊ |
200 | }␉␊ |
201 | ␉␉␊ |
202 | ␉/*␊ |
203 | ␉if(strcmp(filespec, "/System/Library/Caches/com.apple.kext.caches/Startup/Extensions.mkext") == 0)␊ |
204 | ␉{␊ |
205 | ␉␉printf("Invalidating mkext %s\n", filespec);␊ |
206 | ␉␉// 10.6 cache folder. Doesn't contain certain extensions we need, so invalidate it.␊ |
207 | ␉␉//package->adler32++;␊ |
208 | ␉␉// NOTE: double check that this is needed␊ |
209 | ␉␉package->magic = 0x00;␊ |
210 | ␉␉return;␊ |
211 | ␉}*/␊ |
212 | ␉␊ |
213 | ␉␊ |
214 | ␉version = MKEXT_GET_VERSION(package);␊ |
215 | ␉␊ |
216 | ␉if(version == 0x01008000) // mkext1␊ |
217 | ␉{␊ |
218 | ␉␉// mkext1 uses lzss␊ |
219 | ␉␉mkext1_header* package = (mkext1_header*)packagetmp;␊ |
220 | ␉␉int i;␊ |
221 | ␉␉for(i = 0; i < MKEXT_GET_COUNT(package); i++)␊ |
222 | ␉␉{␊ |
223 | ␉␉␉DBG("Parsing kext %d\n", i);␊ |
224 | ␉␉␉//mkext_kext* kext = MKEXT1_GET_KEXT(package, i);␊ |
225 | ␉␉␉// uses decompress_lzss␊ |
226 | ␉␉␉// TODO: handle kext␊ |
227 | ␊ |
228 | ␉␉}␊ |
229 | ␉}␊ |
230 | ␉else if((version & 0xFFFF0000) == 0x02000000) // mkext2␊ |
231 | ␉{␉␉␊ |
232 | ␉␉// mkext2 uses zlib␉␉␊ |
233 | ␉␉mkext2_header* package = (mkext2_header*)packagetmp;␊ |
234 | ␉␉z_stream zstream;␊ |
235 | ␉␉bool zstream_inited = false;␊ |
236 | ␉␉int zlib_result;␊ |
237 | ␉␉int plist_offset = MKEXT2_GET_PLIST(package);␊ |
238 | ␉␉␊ |
239 | ␉␉char* plist = malloc(MKEXT2_GET_PLIST_FULLSIZE(package));␊ |
240 | ␉␉␊ |
241 | ␉␉bzero(&zstream, sizeof(zstream));␉␉␊ |
242 | ␉␉zstream.next_in = (UInt8*)((char*)package + plist_offset);␊ |
243 | ␉␉zstream.avail_in = MKEXT2_GET_PLIST_COMPSIZE(package);␊ |
244 | ␉␉␊ |
245 | ␉␉zstream.next_out = (UInt8*)plist;␊ |
246 | ␉␉zstream.avail_out = MKEXT2_GET_PLIST_FULLSIZE(package);␊ |
247 | ␉␉␊ |
248 | ␉␉zstream.zalloc = z_alloc;␊ |
249 | ␉␉zstream.zfree = z_free;␊ |
250 | ␉␉␉␉␉␉␉␉␊ |
251 | ␉␉zlib_result = inflateInit(&zstream);␊ |
252 | ␉␉if (Z_OK != zlib_result)␊ |
253 | ␉␉{␊ |
254 | ␉␉␉printf("ZLIB Error: %s\n", zstream.msg);␊ |
255 | ␉␉␉getc();␊ |
256 | ␉␉}␊ |
257 | ␉␉else ␊ |
258 | ␉␉{␊ |
259 | ␉␉␉zstream_inited = true;␊ |
260 | ␉␉}␊ |
261 | ␊ |
262 | ␉␉␊ |
263 | ␉␉zlib_result = inflate(&zstream, Z_FINISH);␊ |
264 | ␉␉if (zstream_inited) inflateEnd(&zstream);␊ |
265 | ␊ |
266 | ␉␉DBG("Inflated result is %d, in: %d bytes, out: %d bytes\n", zlib_result, zstream.total_in, zstream.total_out);␊ |
267 | ␉␉␊ |
268 | ␉␉if (zlib_result == Z_STREAM_END || zlib_result == Z_OK)␊ |
269 | ␉␉{␉␉␉␊ |
270 | ␉␉␉config_file_t plistData;␊ |
271 | ␉␉␉config_file_t allDicts;␊ |
272 | ␉␉␉bzero(&plistData, sizeof(plistData));␊ |
273 | ␉␉␉bzero(&allDicts, sizeof(allDicts));␊ |
274 | ␉␉␉␊ |
275 | ␉␉␉XMLParseFile( plist, &plistData.dictionary );␊ |
276 | ␊ |
277 | ␉␉␉int count = 0;␊ |
278 | ␊ |
279 | ␉␉␉allDicts.dictionary = XMLGetProperty(plistData.dictionary, kMKEXTInfoDictionariesKey);␊ |
280 | ␉␉␉count = XMLTagCount(allDicts.dictionary);␊ |
281 | ␊ |
282 | ␉␉␉DBG("Plist contains %d kexts\n", count);␉␉␉␊ |
283 | ␉␉␉␉␉␉␊ |
284 | ␉␉␉bool patched = false;␊ |
285 | ␉␉␉␊ |
286 | ␉␉␉for(; count > 0 ;count-- )␊ |
287 | ␉␉␉{␊ |
288 | ␉␉␉␉TagPtr kextEntry = XMLGetElement(allDicts.dictionary, count);␊ |
289 | ␉␉␉␉patched |= patch_kext(kextEntry, plist, package);␊ |
290 | ␉␉␉}␊ |
291 | ␉␉␉␉␉␉␊ |
292 | ␉␉␉if(patched)␊ |
293 | ␉␉␉{␉␉␉␉␊ |
294 | ␉␉␉␉zstream_inited = false;␊ |
295 | ␉␉␉␉// Recompress the plist␊ |
296 | ␉␉␉␉bzero(&zstream, sizeof(zstream));␉␉␊ |
297 | ␉␉␉␉zstream.next_in = (UInt8*)plist;␊ |
298 | ␉␉␉␉zstream.next_out = (UInt8*)package + plist_offset;␊ |
299 | ␉␉␉␉zstream.avail_in = MKEXT2_GET_PLIST_FULLSIZE(package);␊ |
300 | ␉␉␉␉zstream.avail_out = MKEXT2_GET_PLIST_FULLSIZE(package)<<2;␉// Give us some extra free space, just in case␊ |
301 | ␉␉␉␉zstream.zalloc = Z_NULL;␊ |
302 | ␉␉␉␉zstream.zfree = Z_NULL;␊ |
303 | ␉␉␉␉zstream.opaque = Z_NULL;␊ |
304 | ␉␉␉␉␊ |
305 | ␉␉␉␉␊ |
306 | ␉␉␉␉zlib_result = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,15, 8 /* memLevel */, Z_DEFAULT_STRATEGY);␊ |
307 | ␉␉␉␉if (Z_OK != zlib_result) {␊ |
308 | ␉␉␉␉␉printf("ZLIB Deflate Error: %s\n", zstream.msg);␊ |
309 | ␉␉␉␉␉getc();␊ |
310 | ␉␉␉␉}␊ |
311 | ␉␉␉␉else ␊ |
312 | ␉␉␉␉{␊ |
313 | ␉␉␉␉␉zstream_inited = true;␊ |
314 | ␉␉␉␉}␊ |
315 | ␉␉␉␉␊ |
316 | ␉␉␉␉zlib_result = deflate(&zstream, Z_FINISH);␊ |
317 | ␉␉␉␉␊ |
318 | ␉␉␉␉if (zlib_result == Z_STREAM_END)␊ |
319 | ␉␉␉␉{␊ |
320 | ␉␉␉␉␉DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, MKEXT2_GET_PLIST_FULLSIZE(package));␊ |
321 | ␉␉␉␉␉␊ |
322 | ␉␉␉␉} ␊ |
323 | ␉␉␉␉else if (zlib_result == Z_OK)␊ |
324 | ␉␉␉␉{␊ |
325 | ␉␉␉␉␉/* deflate filled output buffer, meaning the data doesn't compress.␊ |
326 | ␉␉␉␉␉ */␊ |
327 | ␉␉␉␉␉DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, MKEXT2_GET_PLIST_FULLSIZE(package));␊ |
328 | ␉␉␉␉␉␊ |
329 | ␉␉␉␉} ␊ |
330 | ␉␉␉␉else if (zlib_result != Z_STREAM_ERROR)␊ |
331 | ␉␉␉␉{␊ |
332 | ␉␉␉␉␉printf("ZLIB Deflate Error: %s\n", zstream.msg);␊ |
333 | ␉␉␉␉␉getc();␊ |
334 | ␉␉␉␉}␊ |
335 | ␉␉␉␉␊ |
336 | ␉␉␉␉if(zstream.total_out != MKEXT2_GET_PLIST_COMPSIZE(package))␊ |
337 | ␉␉␉␉{␊ |
338 | ␉␉␉␉␉// Update the mkext length␊ |
339 | ␉␉␉␉␉MKEXT2_HDR_CAST(package)->length = MKEXT_SWAP(MKEXT_GET_LENGTH(package) - MKEXT2_GET_PLIST_COMPSIZE(package) + zstream.total_out);␊ |
340 | ␉␉␉␉␉MKEXT2_HDR_CAST(package)->plist_compressed_size = MKEXT_SWAP(zstream.total_out);␊ |
341 | ␉␉␉␉␉*((int*)lengthtmp) -= MKEXT2_GET_PLIST_COMPSIZE(package);␊ |
342 | ␉␉␉␉␉*((int*)lengthtmp) += zstream.total_out;␊ |
343 | ␉␉␉␉}␊ |
344 | ␉␉␉␉␉␉␉␉␊ |
345 | ␉␉␉␉if (zstream_inited) deflateEnd(&zstream);␊ |
346 | ␉␉␉␉␊ |
347 | ␉␉␉␉␊ |
348 | ␉␉␉␉␊ |
349 | ␉␉␉␉// re alder32 the new mkext2 package␊ |
350 | ␉␉␉␉MKEXT_HDR_CAST(package)->adler32 = ␊ |
351 | ␉␉␉␉␉MKEXT_SWAP(Mkext_Alder32((unsigned char *)&package->version,␊ |
352 | ␉␉␉␉␉␉␉␉␉␉␉ MKEXT_GET_LENGTH(package) - 0x10));␊ |
353 | ␉␉␉␉ ␊ |
354 | ␉␉␉}␊ |
355 | ␉␉}␊ |
356 | ␉␉else␊ |
357 | ␉␉{␊ |
358 | ␉␉␉printf("ZLIB Error: %s\n", zstream.msg);␊ |
359 | ␉␉␉getc();␊ |
360 | ␉␉}␉␉␊ |
361 | ␊ |
362 | ␉}␉␊ |
363 | ␉␊ |
364 | }␊ |
365 | ␊ |
366 | // FIXME: only handles mkext2 entries␊ |
367 | bool patch_kext(TagPtr plist, char* plistbuffer, void* start)␊ |
368 | {␊ |
369 | ␉␊ |
370 | ␉char* bundleID = XMLCastString(XMLGetProperty(plist, kPropCFBundleIdentifier));␊ |
371 | ␉␉␉␊ |
372 | ␉if(XMLGetProperty(plist, kMKEXTExecutableKey) == NULL) ␊ |
373 | ␉{␉␊ |
374 | ␉␉printf("Kext is plist only, aka legacykext\n");␉␉␊ |
375 | ␉␉return false;␉// Kext is a plist only kext, don't patch␊ |
376 | ␉}␉␊ |
377 | ␉␊ |
378 | #if UNUSED␊ |
379 | ␉if(/*patch_gma_deviceid &&*/␊ |
380 | ␉ (␊ |
381 | ␉␉␉(strcmp(bundleID, "com.apple.driver.AppleIntelGMA950") == 0) ||␊ |
382 | ␉␉␉(strcmp(bundleID, "com.apple.driver.AppleIntelIntegratedFramebuffer") == 0)␊ |
383 | ␉␉ )␊ |
384 | ␉ )␊ |
385 | ␉{␊ |
386 | ␉␉/*if(strcmp(bundleID, "com.apple.driver.AppleIntelIntegratedFramebuffer") == 0 || patch_gma_deviceid == 0x27ae)␊ |
387 | ␉␉{␊ |
388 | ␉␉␉return patch_gma_kexts(plist, plistbuffer, start);␊ |
389 | ␉␉}␊ |
390 | ␉␉else␊ |
391 | ␉␉{␊ |
392 | ␉␉␉␊ |
393 | ␉␉}*/␊ |
394 | ␉␉printf("%s found \n", bundleID);␊ |
395 | ␉␉␊ |
396 | ␉}␊ |
397 | ␉else if(/*patch_bcm_deviceid &&*/ (strcmp(bundleID, "com.apple.driver.AirPortBrcm43xx") == 0))␊ |
398 | ␉{␉␉␊ |
399 | ␉␉␊ |
400 | ␉␉//return patch_bcm_kext(plist, plistbuffer, start);␊ |
401 | ␊ |
402 | ␉}␊ |
403 | ␉else if(/*patch_bcm_deviceid &&*/ (strcmp(bundleID, "com.apple.iokit.IOAHCIBlockStorage") == 0))␊ |
404 | ␉{␉␉␊ |
405 | ␉␉␊ |
406 | ␉}␊ |
407 | ␉else ␊ |
408 | #endif␊ |
409 | ␉if(/*patch_hda_codec && */strcmp(bundleID, "com.apple.driver.AppleHDA") == 0)␊ |
410 | ␉{␊ |
411 | ␉␉//it seems that applehda.kext is not in extensions.mkext␊ |
412 | ␉␉return patch_hda_kext(plist, plistbuffer, start);␊ |
413 | ␊ |
414 | ␉}␉␉␊ |
415 | ␉else if(/*patch_hda_codec &&*/strcmp(bundleID, "com.apple.driver.AppleHDAController") == 0)␊ |
416 | ␉{␊ |
417 | ␉␉␊ |
418 | ␉␉//return patch_hda_controller(plist, plistbuffer, start);␊ |
419 | ␊ |
420 | ␉}␊ |
421 | ␉␊ |
422 | ␉return false;␊ |
423 | }␊ |
424 | ␊ |
425 | #if UNUSED␊ |
426 | void KextPatcher_hook(void* arg1, void* arg2, void* arg3, void* arg4, void* arg5, void* arg6)␊ |
427 | {␊ |
428 | ␉pci_dt_t* current = arg1;␊ |
429 | ␉if(current)␊ |
430 | ␉{␊ |
431 | ␉␉switch(current->class_id)␊ |
432 | ␉␉{␊ |
433 | ␉␉␉case PCI_CLASS_MULTIMEDIA_AUDIO:␊ |
434 | ␉␉␉␉break;␊ |
435 | ␉␉␉␉␊ |
436 | ␉␉␉case PCI_CLASS_DISPLAY_VGA:␊ |
437 | ␉␉␉␉if(current->vendor_id == 0x8086 && ␊ |
438 | ␉␉␉␉ (␊ |
439 | ␉␉␉␉␉current->device_id == 0x27AE ||␊ |
440 | ␉␉␉␉␉current->device_id == 0xA001 ||␊ |
441 | ␉␉␉␉␉current->device_id == 0xA002 ||␊ |
442 | ␉␉␉␉␉current->device_id == 0xA011 ||␊ |
443 | ␉␉␉␉␉current->device_id == 0xA012␊ |
444 | ␊ |
445 | ␉␉␉␉␉)␊ |
446 | ␉␉␉␉ )␊ |
447 | ␉␉␉␉{␊ |
448 | ␉␉␉␉␉patch_gma_deviceid = current->device_id;␊ |
449 | ␉␉␉␉}␊ |
450 | ␉␉␉␉break;␊ |
451 | ␉␉␉␉␊ |
452 | ␉␉␉case PCI_CLASS_NETWORK_OTHER:␊ |
453 | ␉␉␉␉␊ |
454 | ␉␉␉␉// Patch BCM43xx␊ |
455 | ␉␉␉␉if(current->vendor_id == 0x14E4 && ((current->device_id & 0xFF00) == 0x4300))␊ |
456 | ␉␉␉␉{␊ |
457 | ␉␉␉␉␉patch_bcm_deviceid = current->device_id;␊ |
458 | ␉␉␉␉}␊ |
459 | ␉␉␉␉break;␉␉␉␊ |
460 | ␉␉␉default:␊ |
461 | ␉␉␉␉break;␊ |
462 | ␉␉}␊ |
463 | ␉}␊ |
464 | }␊ |
465 | #endif␊ |
466 | ␊ |
467 | ␊ |
468 | bool patch_hda_controller(TagPtr plist, char* plistbuffer, void* start)␊ |
469 | {␊ |
470 | ␉return false;␊ |
471 | ␉// change the PCI class code to match to. Note: A LegacyHDA plist should do this on it's own␊ |
472 | ␉// As such, it's disabled␊ |
473 | ␊ |
474 | ␉// TODO: read class code␊ |
475 | ␉TagPtr personality;␊ |
476 | ␉personality =␉␉XMLCastDict(XMLGetProperty(plist, kPropIOKitPersonalities));␊ |
477 | ␉personality =␉␉XMLGetProperty(personality, (const char*)"BuiltInHDA");␉␊ |
478 | ␉TagPtr match_class =XMLCastArray(XMLGetProperty(personality, (const char*)"IOPCIClassMatch"));␊ |
479 | ␉␊ |
480 | ␉␊ |
481 | ␉char* new_str = malloc(strlen("0xXXXX000&0xFFFE0000")+1);␊ |
482 | ␉sprintf(new_str, "0x04030000&0xFFFE0000"); // todo, pass in actual class id␊ |
483 | ␉␊ |
484 | ␉␊ |
485 | ␉char* orig_string = "0x04020000&0xFFFE0000"; //XMLCastString(match_class);␊ |
486 | ␉␊ |
487 | ␉DBG("Attemting to replace '%s' with '%s'\n", orig_string, new_str);␊ |
488 | ␉␊ |
489 | ␉// TODO: verify string doesn't exist first.␊ |
490 | ␉␊ |
491 | ␉replace_string(orig_string, new_str, plistbuffer + XMLCastStringOffset(match_class), 10240);␊ |
492 | ␉␊ |
493 | ␉return true;␊ |
494 | ␉␊ |
495 | }␊ |
496 | ␊ |
497 | bool patch_hda_kext(TagPtr plist, char* plistbuffer, void* start)␊ |
498 | {␉␊ |
499 | ␉␊ |
500 | ␉␊ |
501 | ␉int full_size, compressed_size, executable_offset;␊ |
502 | ␉void* compressed_data;␊ |
503 | ␉mkext2_file_entry* kext;␊ |
504 | ␉int zlib_result;␊ |
505 | ␉z_stream zstream;␊ |
506 | ␉bool zstream_inited = false;␊ |
507 | #if UNUSED␊ |
508 | ␉uint16_t find_codec = 0;␊ |
509 | ␉switch(0xFF00 & patch_hda_codec)␊ |
510 | ␉{␊ |
511 | ␉␉case 0x0200:␊ |
512 | ␉␉␉find_codec = 0x0262;␊ |
513 | ␉␉␉break;␊ |
514 | ␊ |
515 | ␉␉case 0x0800:␊ |
516 | ␉␉␉find_codec = 0x0885;␊ |
517 | ␉␉␉break;␊ |
518 | ␉␉␉␊ |
519 | ␉␉case 0x0600:␉// specificaly the 662␊ |
520 | ␉␉␉find_codec = 0x0885;␊ |
521 | ␉␉␉break;␊ |
522 | ␉}␊ |
523 | ␉␊ |
524 | ␉if(!find_codec) return false;␉// notify caller that we aren't patching the kext␊ |
525 | #endif␊ |
526 | ␉␉␊ |
527 | ␉executable_offset = XMLCastInteger(XMLGetProperty(plist, kMKEXTExecutableKey));␊ |
528 | ␉kext = (void*)((char*)start + executable_offset);␊ |
529 | ␊ |
530 | ␉full_size = MKEXT2_GET_ENTRY_FULLSIZE(kext);␊ |
531 | ␉compressed_size = MKEXT2_GET_ENTRY_COMPSIZE(kext);␊ |
532 | ␉compressed_data = MKEXT2_GET_ENTRY_DATA(kext);␉␊ |
533 | ␉executable_offset = XMLCastInteger(XMLGetProperty(plist, kMKEXTExecutableKey));␊ |
534 | ␉␊ |
535 | ␉␊ |
536 | ␉char* executable = malloc(full_size);␊ |
537 | ␉␊ |
538 | ␉bzero(&zstream, sizeof(zstream));␉␉␊ |
539 | ␉zstream.next_in = (UInt8*)compressed_data;␊ |
540 | ␉zstream.avail_in = compressed_size;␊ |
541 | ␉␊ |
542 | ␉zstream.next_out = (UInt8*)executable;␊ |
543 | ␉zstream.avail_out = full_size;␊ |
544 | ␉␊ |
545 | ␉zstream.zalloc = z_alloc;␊ |
546 | ␉zstream.zfree = z_free;␊ |
547 | ␉␊ |
548 | ␉zlib_result = inflateInit(&zstream);␊ |
549 | ␉if (Z_OK != zlib_result)␊ |
550 | ␉{␊ |
551 | ␉␉printf("ZLIB Inflate Error: %s\n", zstream.msg);␊ |
552 | ␉␉getc();␊ |
553 | ␉}␊ |
554 | ␉else ␊ |
555 | ␉{␊ |
556 | ␉␉zstream_inited = true;␊ |
557 | ␉}␊ |
558 | ␉␊ |
559 | ␉␊ |
560 | ␉zlib_result = inflate(&zstream, Z_FINISH);␊ |
561 | ␉␊ |
562 | ␉DBG("Inflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);␊ |
563 | ␉␉␊ |
564 | #if UNUSED␊ |
565 | ␉replace_word(0x10EC | (find_codec << 16), 0x10EC | (patch_hda_codec << 16), executable, zstream.total_out);␊ |
566 | #else␊ |
567 | ␉if ((replace_word(0x10EC | (0x0885 << 16), 0x10EC | (0x0888 << 16), executable, zstream.total_out)) == 0)␊ |
568 | ␉{␊ |
569 | ␉␉if (zstream_inited) inflateEnd(&zstream);␊ |
570 | ␉␉free(executable);␊ |
571 | ␉␉return false;␊ |
572 | ␉}␊ |
573 | #endif␊ |
574 | ␉␊ |
575 | ␉if (zstream_inited) inflateEnd(&zstream);␊ |
576 | ␉␊ |
577 | ␉␊ |
578 | ␉zstream.next_in = (UInt8*)executable;␊ |
579 | ␉zstream.next_out = (UInt8*)compressed_data;␊ |
580 | ␉␊ |
581 | ␉zstream.avail_in = full_size;␊ |
582 | ␉zstream.avail_out = compressed_size;␊ |
583 | ␉zstream.zalloc = Z_NULL;␊ |
584 | ␉zstream.zfree = Z_NULL;␊ |
585 | ␉zstream.opaque = Z_NULL;␊ |
586 | ␉␊ |
587 | ␉␊ |
588 | ␉␊ |
589 | ␉// Recompress the eecutable␊ |
590 | ␉zlib_result = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,15, 8 /* memLevel */, Z_DEFAULT_STRATEGY);␊ |
591 | ␉if (Z_OK != zlib_result) {␊ |
592 | ␉␉printf("ZLIB Deflate Error: %s\n", zstream.msg);␊ |
593 | ␉␉getc();␊ |
594 | ␉}␊ |
595 | ␉else ␊ |
596 | ␉{␊ |
597 | ␉␉zstream_inited = true;␊ |
598 | ␉}␊ |
599 | ␉␊ |
600 | ␉zlib_result = deflate(&zstream, Z_FINISH);␊ |
601 | ␉␊ |
602 | ␉if (zlib_result == Z_STREAM_END)␊ |
603 | ␉{␊ |
604 | ␉␉DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);␊ |
605 | ␉␉getc();␊ |
606 | ␉} ␊ |
607 | ␉else if (zlib_result == Z_OK)␊ |
608 | ␉{␊ |
609 | ␉␉/* deflate filled output buffer, meaning the data doesn't compress.␊ |
610 | ␉␉ */␊ |
611 | ␉␉DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);␊ |
612 | ␉␉getc();␊ |
613 | ␉} ␊ |
614 | ␉else if (zlib_result != Z_STREAM_ERROR)␊ |
615 | ␉{␊ |
616 | ␉␉printf("ZLIB Deflate Error: %s\n", zstream.msg);␊ |
617 | ␉␉getc();␊ |
618 | ␉}␊ |
619 | ␉␊ |
620 | ␉if (zstream_inited) deflateEnd(&zstream);␊ |
621 | ␉␊ |
622 | ␉free(executable);␊ |
623 | ␉␊ |
624 | ␉return true;␉␊ |
625 | ␊ |
626 | }␊ |
627 | #if UNUSED␊ |
628 | bool patch_bcm_kext(TagPtr plist, char* plistbuffer, void* start)␊ |
629 | {␊ |
630 | ␉TagPtr personality;␊ |
631 | ␉personality =␉␉XMLCastDict(XMLGetProperty(plist, kPropIOKitPersonalities));␊ |
632 | ␉personality =␉␉XMLGetProperty(personality, (const char*)"Broadcom 802.11 PCI");␉␊ |
633 | ␉TagPtr match_names =XMLCastArray(XMLGetProperty(personality, (const char*)"IONameMatch"));␊ |
634 | ␊ |
635 | ␉␊ |
636 | ␉char* new_str = malloc(strlen("pci14e4,xxxx")+1);␊ |
637 | ␉sprintf(new_str, "pci14e4,%02x", patch_bcm_deviceid);␊ |
638 | ␊ |
639 | ␉// Check to see if we *really* need to modify the plist, if not, return false␊ |
640 | ␉// so that *if* this were going ot be the only modified kext, the repacking code␊ |
641 | ␉// won't need to be executed.␊ |
642 | ␉int count = XMLTagCount(match_names);␊ |
643 | ␉while(count)␊ |
644 | ␉{␊ |
645 | ␉␉count--;␊ |
646 | ␉␉TagPtr replace =␉XMLGetElement(match_names, count);␉// Modify the second entry␊ |
647 | ␉␉char* orig_string = XMLCastString(replace);␊ |
648 | ␉␉if(strcmp(orig_string, new_str) == 0) return false;␊ |
649 | ␉}␊ |
650 | ␊ |
651 | ␉␊ |
652 | ␉TagPtr replace =␉XMLGetElement(match_names, 1);␉// Modify the second entry␊ |
653 | ␉char* orig_string = XMLCastString(replace);␊ |
654 | ␉␊ |
655 | ␉␊ |
656 | ␉// TODO: verify string doesn't exist first.␊ |
657 | ␉␊ |
658 | ␉replace_string(orig_string, new_str, plistbuffer + XMLCastStringOffset(replace), 10240);␊ |
659 | ␊ |
660 | ␉return true;␊ |
661 | }␊ |
662 | ␊ |
663 | bool patch_gma_kexts(TagPtr plist, char* plistbuffer, void* start)␊ |
664 | {␊ |
665 | ␉// TODO: clean up this function / split into two / etc␊ |
666 | ␉int exeutable_offset, full_size, compressed_size;␊ |
667 | ␉TagPtr personality;␊ |
668 | ␉long offset;␊ |
669 | ␉int zlib_result;␊ |
670 | ␉z_stream zstream;␊ |
671 | ␉bool zstream_inited = false;␊ |
672 | ␉mkext2_file_entry* kext;␊ |
673 | ␉void* compressed_data;␊ |
674 | ␊ |
675 | ␉exeutable_offset = XMLCastInteger(XMLGetProperty(plist, kMKEXTExecutableKey));␊ |
676 | ␉kext = (void*)((char*)start + exeutable_offset);␊ |
677 | ␊ |
678 | ␉full_size = MKEXT2_GET_ENTRY_FULLSIZE(kext);␊ |
679 | ␉compressed_size = MKEXT2_GET_ENTRY_COMPSIZE(kext);␊ |
680 | ␉compressed_data = MKEXT2_GET_ENTRY_DATA(kext);␊ |
681 | ␉␊ |
682 | ␉personality =␉␉XMLCastDict(XMLGetProperty(plist, kPropIOKitPersonalities));␊ |
683 | ␉␊ |
684 | ␉␊ |
685 | ␉␊ |
686 | ␉char* executable = malloc(full_size);␊ |
687 | ␉␊ |
688 | ␉bzero(&zstream, sizeof(zstream));␉␉␊ |
689 | ␉zstream.next_in = (UInt8*)compressed_data;␊ |
690 | ␉zstream.avail_in = compressed_size;␊ |
691 | ␉␊ |
692 | ␉zstream.next_out = (UInt8*)executable;␊ |
693 | ␉zstream.avail_out = full_size;␊ |
694 | ␉␊ |
695 | ␉zstream.zalloc = z_alloc;␊ |
696 | ␉zstream.zfree = z_free;␊ |
697 | ␉␊ |
698 | ␉zlib_result = inflateInit(&zstream);␊ |
699 | ␉if (Z_OK != zlib_result)␊ |
700 | ␉{␊ |
701 | ␉␉printf("ZLIB Inflate Error: %s\n", zstream.msg);␊ |
702 | ␉␉getc();␊ |
703 | ␉}␊ |
704 | ␉else ␊ |
705 | ␉{␊ |
706 | ␉␉zstream_inited = true;␊ |
707 | ␉}␊ |
708 | ␉␊ |
709 | ␉␊ |
710 | ␉zlib_result = inflate(&zstream, Z_FINISH);␊ |
711 | ␉␊ |
712 | ␉DBG("Inflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);␊ |
713 | ␉␊ |
714 | ␉␊ |
715 | ␉␊ |
716 | ␉if(XMLGetProperty(personality, (const char*)"Intel915"))␊ |
717 | ␉{␊ |
718 | ␉␉personality =␉␉XMLGetProperty(personality, (const char*)"Intel915");␊ |
719 | ␉␉// IOAccelerator kext␊ |
720 | ␉}␊ |
721 | ␉else␊ |
722 | ␉{␊ |
723 | ␉␉personality =␉␉XMLGetProperty(personality, (const char*)"AppleIntelIntegratedFramebuffer");␊ |
724 | ␉␉// Framebuffer Kext␊ |
725 | ␉␉␊ |
726 | ␉␉if((patch_gma_deviceid & 0xFF00) == 0xA000)␉// GMA3150␊ |
727 | ␉␉{␊ |
728 | ␉␉␉// Cursor corruption fix.␊ |
729 | ␉␉␉// This patch changes the cursor address from␊ |
730 | ␉␉␉// a physical address (used in the gma950) to an offset (used in the gma3150).␊ |
731 | ␉␉␉␊ |
732 | ␉␉␉char find_bytes[] = {0x8b, 0x55, 0x08, 0x83, 0xba, 0xb0, 0x00, 0x00, 0x00, 0x01, 0x7e, 0x36, 0x89, 0x04, 0x24, 0xe8, 0x32, 0xbb, 0xff, 0xff};␉// getPhysicalAddress() and more␊ |
733 | ␉␉␉char new_bytes[] = {0xb8, 0x00, 0x00, 0x00, 0x02, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xEB, 0x04, 0x00, 0x00, 0x00, 0x00};␉// jump past getPhysicalAddress binding. NOTE: last six bytes are unusable␊ |
734 | ␉␉␉replace_bytes(find_bytes, sizeof(find_bytes), new_bytes, sizeof(new_bytes), executable, zstream.total_out);␊ |
735 | ␉␉}␊ |
736 | ␉␉␊ |
737 | ␉}␊ |
738 | ␉␊ |
739 | ␉␊ |
740 | #if DEBUG_KEXT_PATCHER␊ |
741 | ␉char* pcimatch =␉XMLCastString(XMLGetProperty(personality, (const char*)"IOPCIPrimaryMatch"));␊ |
742 | #endif␊ |
743 | ␉offset =␉␉XMLCastStringOffset(XMLGetProperty(personality, (const char*)"IOPCIPrimaryMatch"));␊ |
744 | ␉␊ |
745 | ␉char* newstring = malloc(strlen("0x00008086") + 1);␊ |
746 | ␉sprintf(newstring, "0x%04x", 0x8086 | (patch_gma_deviceid << 16));␊ |
747 | ␉␊ |
748 | ␉DBG("Replacing %s with %s\n", "0x00008086", newstring); ␊ |
749 | ␉replace_string("0x27A28086", newstring, plistbuffer + offset, 10240);␊ |
750 | ␉replace_word(0x27A28086, 0x8086 | (patch_gma_deviceid << 16), executable, zstream.total_out);␊ |
751 | ␊ |
752 | ␉␊ |
753 | ␉␊ |
754 | ␉if (zstream_inited) inflateEnd(&zstream);␊ |
755 | ␉␊ |
756 | ␉␊ |
757 | ␉zstream.next_in = (UInt8*)executable;␊ |
758 | ␉zstream.next_out = (UInt8*)compressed_data;␊ |
759 | ␉␊ |
760 | ␉zstream.avail_in = full_size;␊ |
761 | ␉zstream.avail_out = compressed_size;␊ |
762 | ␉zstream.zalloc = Z_NULL;␊ |
763 | ␉zstream.zfree = Z_NULL;␊ |
764 | ␉zstream.opaque = Z_NULL;␊ |
765 | ␉␊ |
766 | ␉␊ |
767 | ␉␊ |
768 | ␉// Recompress the eecutable␊ |
769 | ␉zlib_result = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,15, 8 /* memLevel */, Z_DEFAULT_STRATEGY);␊ |
770 | ␉if (Z_OK != zlib_result) {␊ |
771 | ␉␉printf("ZLIB Deflate Error: %s\n", zstream.msg);␊ |
772 | ␉␉getc();␊ |
773 | ␉}␊ |
774 | ␉else ␊ |
775 | ␉{␊ |
776 | ␉␉zstream_inited = true;␊ |
777 | ␉}␊ |
778 | ␉␊ |
779 | ␉zlib_result = deflate(&zstream, Z_FINISH);␊ |
780 | ␉␊ |
781 | ␉if (zlib_result == Z_STREAM_END)␊ |
782 | ␉{␊ |
783 | ␉␉DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);␊ |
784 | ␉} ␊ |
785 | ␉else if (zlib_result == Z_OK)␊ |
786 | ␉{␊ |
787 | ␉␉/* deflate filled output buffer, meaning the data doesn't compress.␊ |
788 | ␉␉ */␊ |
789 | ␉␉printf("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);␊ |
790 | ␉␉printf("ERROR: Unable to compress patched kext, not enough room.\n");␊ |
791 | ␉␉pause();␊ |
792 | ␉␉␊ |
793 | ␉} ␊ |
794 | ␉else if (zlib_result != Z_STREAM_ERROR)␊ |
795 | ␉{␊ |
796 | ␉␉printf("ZLIB Deflate Error: %s\n", zstream.msg);␊ |
797 | ␉␉getc();␊ |
798 | ␉}␊ |
799 | ␉//kext->compressed_size = MKEXT_SWAP(zstream.total_out);␊ |
800 | ␊ |
801 | ␉␊ |
802 | ␉␊ |
803 | ␉␊ |
804 | ␉if (zstream_inited) deflateEnd(&zstream);␊ |
805 | ␉␊ |
806 | ␉free(executable);␊ |
807 | ␉␊ |
808 | ␉return true;␉␊ |
809 | }␊ |
810 | #endif␊ |
811 | ␊ |
812 | int chartohex(char c)␊ |
813 | {␊ |
814 | ␉if(c <= '9' && c >= '0')␊ |
815 | ␉{␊ |
816 | ␉␉return c - '0';␉// c is between 0 and 9␊ |
817 | ␉}␊ |
818 | ␉else if(c <= 'F' && c >= 'A')␊ |
819 | ␉{␊ |
820 | ␉␉return c - 'A' + 10; // c = 10 - 15;␊ |
821 | ␉}␊ |
822 | ␉else if(c <= 'f' && c >= 'a')␊ |
823 | ␉{␊ |
824 | ␉␉return c - 'a' + 10; // c = 10 - 15;␊ |
825 | ␉}␊ |
826 | ␉return 0;␊ |
827 | } |