Chameleon

Chameleon Commit Details

Date:2010-05-15 19:50:05 (13 years 11 months ago)
Author:Evan Lojewski
Commit:154
Parents: 153
Message:Added a pacth_lapic_init routine. determines if a patch is required based on cpu model. Todo: make cpuid patch configurable
Changes:
M/branches/meklort/i386/boot2/kernel_patcher.c
M/branches/meklort/i386/boot2/kernel_patcher.h

File differences

branches/meklort/i386/boot2/kernel_patcher.c
55
66
77
8
89
9
10
1011
12
1113
1214
1315
16
17
1418
1519
1620
1721
22
1823
1924
2025
2126
22
27
28
2329
2430
2531
2632
2733
34
2835
2936
3037
......
3340
3441
3542
36
37
38
3943
4044
4145
......
6266
6367
6468
65
66
67
69
70
71
72
6873
6974
7075
7176
72
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
73109
110
111
112
113
114
115
116
74117
75118
76119
77120
78
79
80
121
122
81123
82124
83125
......
214256
215257
216258
217
259
260
218261
219
262
220263
221264
222265
223266
224
267
225268
226269
227270
......
237280
238281
239282
240
283
241284
242285
243286
......
247290
248291
249292
250
251
252
253
254
255
256
257
258
259
260293
261
262
294
263295
264296
265
297
266298
267299
268300
269301
270302
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
303
304
305
306
307
308
309
310
311
312
313
293314
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
315367
316368
317369
......
341393
342394
343395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
#include "libsaio.h"
#include "kernel_patcher.h"
#include "platform.h"
#define NUM_SYMBOLS3
extern PlatformInfo_t Platform;
#define SYMBOL_CPUID_SET_INFO0
#define SYMBOL_PANIC1
#define SYMBOL_PMCPUEXITHALTTOOFF2
#define SYMBOL_LAPIC_INIT3
#define NUM_SYMBOLS4
#define SYMBOL_CPUID_SET_INFO_STRING"_cpuid_set_info"
#define SYMBOL_PANIC_STRING"_panic"
#define SYMBOL_PMCPUEXITHALTTOOFF_STRING"_pmCPUExitHaltToOff"
#define SYMBOL_LAPIC_INIT_STRING"_lapic_init"
char* kernelSymbols[NUM_SYMBOLS] = {
SYMBOL_CPUID_SET_INFO_STRING,
SYMBOL_PANIC_STRING,
SYMBOL_PMCPUEXITHALTTOOFF_STRING
SYMBOL_PMCPUEXITHALTTOOFF_STRING,
SYMBOL_LAPIC_INIT_STRING
};
UInt32 kernelSymbolAddresses[NUM_SYMBOLS] = {
0,
0,
0,
0
};
UInt32 textAddress = 0;
extern unsigned long gBinaryAddress;
void patch_kernel(void* kernelData)
{
switch (locate_symbols((void*)kernelData)) {
/**
** patch_kernel_32
**Due to the way the _cpuid_set_info function is writtin, the first instance of _panic is called
**when an unsupported (read: non apple used cpu) is found. This routine locates that first _panic call
**and replaces the jump call (0xe8) with no ops (0x90).
**patches kernel based on cpu info determined earlier in the boot process.
**It the machine is vmware, remove the artificial lapic panic
**If the CPU is not supported, remove the cpuid_set_info panic
**If the CPU is and Intel Atom, inject the penryn cpuid info.
**/
void patch_kernel_32(void* kernelData)
{
//patch_pmCPUExitHaltToOff(kernelData);// Not working as intended, disabled for now
patch_cpuid_set_info(kernelData);
//if(vmware_detected)
{
patch_lapic_init(kernelData);
}
switch( Platform.CPU.Vendor )
{
case 0x06:
switch(Platform.CPU.Model)
{
// Known good CPU's, no reason to patch kernel
case 13:
case CPUID_MODEL_YONAH:
case CPUID_MODEL_MEROM:
case CPUID_MODEL_PENRYN:
case CPUID_MODEL_NEHALEM:
case CPUID_MODEL_FIELDS:
case CPUID_MODEL_DALES:
case CPUID_MODEL_NEHALEM_EX:
break;
// Known unsuported CPU's
case CPUID_MODEL_ATOM:
// TODO: Impersonate CPU based on user selection
patch_cpuid_set_info(kernelData, CPUFAMILY_INTEL_PENRYN, CPUID_MODEL_PENRYN);// Impersonate Penryn CPU
break;
// Unknown CPU's
default:
// TODO: Impersonate CPU based on user selection
patch_cpuid_set_info(kernelData, 0, 0);// Remove Panic Call
break;
}
break;
default:
break;
}
}
/**
**This functions located the following in the mach_kernel symbol table
**_panic
**_cpuid_set_info
**This functions located the kernelSymbols[i] symbols in the macho header.
**as well as determines the start of the __TEXT segment and __TEXT,__text sections
**/
int locate_symbols(void* kernelData)
{
/**
** Locate the fisrt instance of _panic inside of _cpuid_set_info, and remove it
** Locate the fisrt instance of _panic inside of _cpuid_set_info, and either remove it
** Or replace it so that the cpuid is set to a valid value.
**/
void patch_cpuid_set_info(void* kernelData)
void patch_cpuid_set_info(void* kernelData, UInt32 impersonateFamily, UInt8 inpersonateModel)
{
UInt8* bytes = (UInt8*)kernelData;
UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_CPUID_SET_INFO] - textAddress + textSection);
UInt32 jumpLocation = 0;
UInt32 panidAddr = kernelSymbolAddresses[SYMBOL_PANIC] - textAddress;
UInt32 panicAddr = kernelSymbolAddresses[SYMBOL_PANIC] - textAddress;
if(kernelSymbolAddresses[SYMBOL_CPUID_SET_INFO] == 0)
{
printf("Unable to locate _cpuid_set_info\n");
//TODO: don't assume it'll always work (Look for *next* function address in symtab and fail once it's been reached)
while(
(bytes[patchLocation -1] != 0xE8) ||
( ( (UInt32)(panidAddr - patchLocation - 4) + textSection ) != (UInt32)((bytes[patchLocation + 0] << 0 |
( ( (UInt32)(panicAddr - patchLocation - 4) + textSection ) != (UInt32)((bytes[patchLocation + 0] << 0 |
bytes[patchLocation + 1] << 8 |
bytes[patchLocation + 2] << 16 |
bytes[patchLocation + 3] << 24)))
}
patchLocation--;
/*
// repace with nops to disable the panic call
Old patch, nolonger used. This is a safer patch than before, however
the new patch allows the native pm kext to load without any extra kexts
bytes[patchLocation] = 0x90;
bytes[patchLocation + 1] = 0x90;
bytes[patchLocation + 2] = 0x90;
bytes[patchLocation + 3] = 0x90;
bytes[patchLocation + 4] = 0x90;
*/
// Locate a JMP to patchLocation - sizeof(mov) + 2 (aka 8)
// ... NOTE: can *ONLY* be up to 0xFF - 8 bytes aways
// Locate the jump call, so that 10 bytes can be reclamed.
jumpLocation = patchLocation - 15;
while((bytes[jumpLocation - 1] != 0x77 ||
bytes[jumpLocation] != (patchLocation - jumpLocation - -8)) &&
bytes[jumpLocation] != (patchLocation - jumpLocation - -8)) &&
(patchLocation - jumpLocation) < 0xEF)
{
jumpLocation--;
}
// If found... (not the end of the world if it isn't found, the panic is removed either way.
// But if it isn't found, then IntelCPUPM.kext might panic if an unknown cpu (atom)
// Jump to patchLocation - 17
if((patchLocation - jumpLocation) < 0xEF) bytes[jumpLocation] -= 10; // sizeof(movl$0x6b5a4cd2,0x00872eb4)
// bytes[patchLocation - 17] = 0xC7;// already here... not needed to be done
// bytes[patchLocation - 16] = 0x05;// see above
UInt32 cpuid_cpufamily_addr =bytes[patchLocation - 15] << 0 |
bytes[patchLocation - 14] << 8 |
bytes[patchLocation - 13] << 16 |
bytes[patchLocation - 12] << 24;
// NOTE: may change, determined based on cpuid_info struct
UInt32 cpuid_model_addr = cpuid_cpufamily_addr - 299;
// cpufamily = CPUFAMILY_INTEL_PENRYN
bytes[patchLocation - 11] = (CPUFAMILY_INTEL_PENRYN & 0x000000FF) >> 0;
bytes[patchLocation - 10] = (CPUFAMILY_INTEL_PENRYN & 0x0000FF00) >> 8;
bytes[patchLocation - 9] = (CPUFAMILY_INTEL_PENRYN & 0x00FF0000) >> 16;
bytes[patchLocation - 8] = (CPUFAMILY_INTEL_PENRYN & 0xFF000000) >> 24;
// If found... AND we want to impersonate a specific cpumodel / family...
if(impersonateFamily &&
inpersonateModel &&
((patchLocation - jumpLocation) < 0xEF))
{
bytes[jumpLocation] -= 10;// sizeof(movl$0x6b5a4cd2,0x00872eb4) = 10bytes
/*
* Inpersonate the specified CPU FAMILY and CPU Model
*/
// NOPS, just in case if the jmp call wasn't patched, we'll jump to a
// nop and continue with the rest of the patch
// Yay two free bytes :), 10 more can be reclamed if needed, as well as a few
// from the above code (only cpuid_model needs to be set.
bytes[patchLocation - 7] = 0x90;
bytes[patchLocation - 6] = 0x90;
bytes[patchLocation - 5] = 0xC7;
bytes[patchLocation - 4] = 0x05;
bytes[patchLocation - 3] = (cpuid_model_addr & 0x000000FF) >> 0;
bytes[patchLocation - 2] = (cpuid_model_addr & 0x0000FF00) >> 8;
bytes[patchLocation - 1] = (cpuid_model_addr & 0x00FF0000) >> 16;
bytes[patchLocation - 0] = (cpuid_model_addr & 0xFF000000) >> 24;
// Note: I could have just copied the 8bit cpuid_model in and saved about 4 bytes
// so if this function need a different patch it's still possible. Also, about ten bytes previous can be freed.
bytes[patchLocation + 1] = 0x17;// cpuid_model
bytes[patchLocation + 2] = 0x01;// cpuid_extmodel
bytes[patchLocation + 3] = 0x00;// cpuid_extfamily
bytes[patchLocation + 4] = 0x02;// cpuid_stepping
// bytes[patchLocation - 17] = 0xC7;// already here... not needed to be done
// bytes[patchLocation - 16] = 0x05;// see above
UInt32 cpuid_cpufamily_addr =bytes[patchLocation - 15] << 0 |
bytes[patchLocation - 14] << 8 |
bytes[patchLocation - 13] << 16 |
bytes[patchLocation - 12] << 24;
// NOTE: may change, determined based on cpuid_info struct
UInt32 cpuid_model_addr = cpuid_cpufamily_addr - 299;
// cpufamily = CPUFAMILY_INTEL_PENRYN
bytes[patchLocation - 11] = (impersonateFamily & 0x000000FF) >> 0;
bytes[patchLocation - 10] = (impersonateFamily & 0x0000FF00) >> 8;
bytes[patchLocation - 9] = (impersonateFamily & 0x00FF0000) >> 16;
bytes[patchLocation - 8] = (impersonateFamily & 0xFF000000) >> 24;
// NOPS, just in case if the jmp call wasn't patched, we'll jump to a
// nop and continue with the rest of the patch
// Yay two free bytes :), 10 more can be reclamed if needed, as well as a few
// from the above code (only cpuid_model needs to be set.
bytes[patchLocation - 7] = 0x90;
bytes[patchLocation - 6] = 0x90;
bytes[patchLocation - 5] = 0xC7;
bytes[patchLocation - 4] = 0x05;
bytes[patchLocation - 3] = (cpuid_model_addr & 0x000000FF) >> 0;
bytes[patchLocation - 2] = (cpuid_model_addr & 0x0000FF00) >> 8;
bytes[patchLocation - 1] = (cpuid_model_addr & 0x00FF0000) >> 16;
bytes[patchLocation - 0] = (cpuid_model_addr & 0xFF000000) >> 24;
// Note: I could have just copied the 8bit cpuid_model in and saved about 4 bytes
// so if this function need a different patch it's still possible. Also, about ten bytes previous can be freed.
bytes[patchLocation + 1] = inpersonateModel;// cpuid_model
bytes[patchLocation + 2] = 0x01;// cpuid_extmodel
bytes[patchLocation + 3] = 0x00;// cpuid_extfamily
bytes[patchLocation + 4] = 0x02;// cpuid_stepping
}
else
{
// Either We were unable to change the jump call due to the funciton's sctructure
// changing, or the user did not request a patch. As such, resort to just
// removing the panic call. Note that the IntelCPUPM kext may still panic
// due to the cpu's Model ID not being patched
bytes[patchLocation + 0] = 0x90;
bytes[patchLocation + 1] = 0x90;
bytes[patchLocation + 2] = 0x90;
bytes[patchLocation + 3] = 0x90;
bytes[patchLocation + 4] = 0x90;
}
}
}
bytes[patchLocation] = 0x00;// KERN_SUCCESS;
}
void patch_lapic_init(void* kernelData)
{
UInt8 panicIndex = 0;
UInt8* bytes = (UInt8*)kernelData;
UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_LAPIC_INIT] - textAddress + textSection);
UInt32 panicAddr = kernelSymbolAddresses[SYMBOL_PANIC] - textAddress;
if(kernelSymbolAddresses[SYMBOL_LAPIC_INIT] == 0)
{
printf("Unable to locate _cpuid_set_info\n");
return;
}
if(kernelSymbolAddresses[SYMBOL_PANIC] == 0)
{
printf("Unable to locate _panic\n");
return;
}
// Locate the (panicIndex + 1) panic call
while(panicIndex < 3)// Find the third panic call
{
while(
(bytes[patchLocation -1] != 0xE8) ||
( ( (UInt32)(panicAddr - patchLocation - 4) + textSection ) != (UInt32)((bytes[patchLocation + 0] << 0 |
bytes[patchLocation + 1] << 8 |
bytes[patchLocation + 2] << 16 |
bytes[patchLocation + 3] << 24)))
)
{
patchLocation++;
}
patchLocation++;
panicIndex++;
}
bytes[--patchLocation] = 0x90;
bytes[++patchLocation] = 0x90;
bytes[++patchLocation] = 0x90;
bytes[++patchLocation] = 0x90;
bytes[++patchLocation] = 0x90;
}
branches/meklort/i386/boot2/kernel_patcher.h
99
1010
1111
12
13
14
15
16
17
18
19
20
21
22
1223
1324
1425
......
2132
2233
2334
24
35
2536
37
2638
2739
#ifndef __BOOT2_KERNEL_PATCHER_H
#define __BOOT2_KERNEL_PATCHER_H
#define CPUID_MODEL_YONAH14
#define CPUID_MODEL_MEROM15
#define CPUID_MODEL_PENRYN23
#define CPUID_MODEL_NEHALEM26
#define CPUID_MODEL_ATOM28
#define CPUID_MODEL_FIELDS30/* Lynnfield, Clarksfield, Jasper */
#define CPUID_MODEL_DALES31/* Havendale, Auburndale */
#define CPUID_MODEL_NEHALEM_EX46
void patch_kernel(void* kernelData);
#define KERNEL_641
void patch_cpuid_set_info(void* kernelData);
void patch_cpuid_set_info(void* kernelData, UInt32 impersonateFamily, UInt8 inpersonateModel);
void patch_pmCPUExitHaltToOff(void* kernelData);
void patch_lapic_init(void* kernelData);
#endif /* !__BOOT2_KERNEL_PATCHER_H */

Archive Download the corresponding diff file

Revision: 154