Index: branches/meklort/i386/boot2/kernel_patcher.c =================================================================== --- branches/meklort/i386/boot2/kernel_patcher.c (revision 0) +++ branches/meklort/i386/boot2/kernel_patcher.c (revision 143) @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2009 Evan Lojewski. All rights reserved. + * + */ + +#include "libsaio.h" +#include "kernel_patcher.h" + +#define NUM_SYMBOLS 3 + +#define SYMBOL_CPUID_SET_INFO 0 +#define SYMBOL_PANIC 1 +#define SYMBOL_PMCPUEXITHALTTOOFF 2 + +#define SYMBOL_CPUID_SET_INFO_STRING "_cpuid_set_info" +#define SYMBOL_PANIC_STRING "_panic" +#define SYMBOL_PMCPUEXITHALTTOOFF_STRING "_pmCPUExitHaltToOff" + +char* kernelSymbols[NUM_SYMBOLS] = { + SYMBOL_CPUID_SET_INFO_STRING, + SYMBOL_PANIC_STRING, + SYMBOL_PMCPUEXITHALTTOOFF_STRING +}; + +UInt32 kernelSymbolAddresses[NUM_SYMBOLS] = { + 0, + 0, + 0 +}; + + +UInt32 textSection; +UInt32 textAddress; + + +extern unsigned long gBinaryAddress; + + +void patch_kernel() +{ + switch (locate_symbols((void*)gBinaryAddress)) { + case KERNEL_32: + patch_kernel_32((void*)gBinaryAddress); + break; + case KERNEL_64: + default: + patch_kernel_64((void*)gBinaryAddress); + break; + } +} + +// patches a 64bit kernel. +void patch_kernel_64(void* kernelData) +{ + // At the moment, the kernel patching code fails when used + // in 64bit mode, so we don't patch it. This is due to 32bit vs 64bit + // pointers as well as changes in structure sizes + verbose("Unable to patch 64bit kernel. Please use arch=i386.\n"); +} + +/** + ** 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). + **/ + +void patch_kernel_32(void* kernelData) +{ + patch_pmCPUExitHaltToOff(kernelData); + patch_cpuid_set_info(kernelData); + +} + +/** + ** This functions located the following in the mach_kernel symbol table + ** _panic + ** _cpuid_set_info + **/ +int locate_symbols(void* kernelData) +{ + UInt16 symbolIndexes[NUM_SYMBOLS]; + + struct load_command *loadCommand; + struct symtab_command *symtableData; + struct nlist *symbolEntry; + + char* symbolString; + + UInt32 kernelIndex = 0; + kernelIndex += sizeof(struct mach_header); + + if(((struct mach_header*)kernelData)->magic != MH_MAGIC) return KERNEL_64; + + //printf("%d load commands beginning at 0x%X\n", (unsigned int)header->ncmds, (unsigned int)kernelIndex); + //printf("Commands take up %d bytes\n", header->sizeofcmds); + + + int cmd = 0; + while(cmd < ((struct mach_header*)kernelData)->ncmds) // TODO: for loop instead + { + cmd++; + + loadCommand = kernelData + kernelIndex; + + UInt cmdSize = loadCommand->cmdsize; + + + // Locate start of _panic and _cpuid_set_info in the symbol tabe. + // Load commands should be anded with 0x7FFFFFFF to ignore the LC_REQ_DYLD flag + if((loadCommand->cmd & 0x7FFFFFFF) == LC_SYMTAB) // We only care about the symtab segment + { + //printf("Located symtable, length is 0x%X, 0x%X\n", (unsigned int)loadCommand->cmdsize, (unsigned int)sizeof(symtableData)); + + symtableData = kernelData + kernelIndex; + kernelIndex += sizeof(struct symtab_command); + + cmdSize -= sizeof(struct symtab_command); + + // Loop through symbol table untill all of the symbols have been found + + symbolString = kernelData + symtableData->stroff; + + + UInt16 symbolIndex = 0; + UInt8 numSymbolsFound = 0; + + while(symbolIndex < symtableData->nsyms && numSymbolsFound < NUM_SYMBOLS) // TODO: for loop + { + int i = 0; + while(i < NUM_SYMBOLS) + { + if(strcmp(symbolString, kernelSymbols[i]) == 0) + { + symbolIndexes[i] = symbolIndex; + numSymbolsFound++; + } + + } + symbolString += strlen(symbolString) + 1; + symbolIndex++; + } + + // loop again + symbolIndex = 0; + numSymbolsFound = 0; + while(symbolIndex < symtableData->nsyms && numSymbolsFound < NUM_SYMBOLS) // TODO: for loop + { + + symbolEntry = kernelData + symtableData->symoff + (symbolIndex * sizeof(struct nlist)); + + int i = 0; + while(i < NUM_SYMBOLS) + { + if(symbolIndex == (symbolIndexes[i] - 4)) + { + kernelSymbolAddresses[i] = (UInt32)symbolEntry->n_value; + numSymbolsFound++; + } + + } + + symbolIndex ++; + } + // Load commands should be anded with 0x7FFFFFFF to ignore the LC_REQ_DYLD flag + } else if((loadCommand->cmd & 0x7FFFFFFF) == LC_SEGMENT) // We only care about the __TEXT segment, any other load command can be ignored + { + + struct segment_command *segCommand; + + segCommand = kernelData + kernelIndex; + + //printf("Segment name is %s\n", segCommand->segname); + + if(strcmp("__TEXT", segCommand->segname) == 0) + { + UInt32 sectionIndex; + + sectionIndex = sizeof(struct segment_command); + + struct section *sect; + + while(sectionIndex < segCommand->cmdsize) + { + sect = kernelData + kernelIndex + sectionIndex; + + sectionIndex += sizeof(struct section); + + + if(strcmp("__text", sect->sectname) == 0) + { + // __TEXT,__text found, save the offset and address for when looking for the panic call. + textSection = sect->offset; + textAddress = sect->addr; + break; + } + } + } + + + kernelIndex += cmdSize; + } else { + kernelIndex += cmdSize; + } + } + + return KERNEL_32; +} + +/** + ** Locate the fisrt instance of _panic inside of _cpuid_set_info, and remove it + **/ +void patch_cpuid_set_info(void* kernelData) +{ + UInt8* bytes = (void*)kernelData; + UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_CPUID_SET_INFO] - textAddress + textSection); + UInt32 panidAddr = kernelSymbolAddresses[SYMBOL_PANIC] - textAddress; + + + //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] | + bytes[patchLocation + 1] << 8 | + bytes[patchLocation + 2] << 16 | + bytes[patchLocation + 3] << 24))) //&& + + // (patchLocation < maxLocation) // max location is not known... assuming there is a panic call somewhere after cpuid_set_info + ) + { + patchLocation++; + } + + // repace with nops + bytes[patchLocation - 1] = 0x90; + bytes[patchLocation ] = 0x90; + bytes[patchLocation + 1] = 0x90; + bytes[patchLocation + 2] = 0x90; + bytes[patchLocation + 3] = 0x90; + + // Patching finished +} + +/** + ** SleepEnabler.kext replacement (for those that need it) + ** Located the KERN_INVALID_ARGUMENT return and replace it with KERN_SUCCESS + **/ +void patch_pmCPUExitHaltToOff(void* kernelData) +{ + UInt8* bytes = (void*)kernelData; + UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_PMCPUEXITHALTTOOFF] - textAddress + textSection); + + while(bytes[patchLocation - 1] != 0xB8 || + bytes[patchLocation] != 0x04 || // KERN_INVALID_ARGUMENT (0x00000004) + bytes[patchLocation + 1] != 0x00 || // KERN_INVALID_ARGUMENT + bytes[patchLocation + 2] != 0x00 || // KERN_INVALID_ARGUMENT + bytes[patchLocation + 3] != 0x00) // KERN_INVALID_ARGUMENT + + { + patchLocation++; + } + bytes[patchLocation] = 0x00; // KERN_SUCCESS; + +} Index: branches/meklort/i386/boot2/kernel_patcher.h =================================================================== --- branches/meklort/i386/boot2/kernel_patcher.h (revision 0) +++ branches/meklort/i386/boot2/kernel_patcher.h (revision 143) @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2009 Evan Lojewski. All rights reserved. + * + */ + +#include +#include + +#ifndef __BOOT2_KERNEL_PATCHER_H +#define __BOOT2_KERNEL_PATCHER_H + +void patch_kernel(); + +#define KERNEL_64 1 +#define KERNEL_32 2 + +int locate_symbols(void* kernelData); + + +void patch_kernel_32(void* kernelData); +void patch_kernel_64(void* kernelData); + + + +void patch_cpuid_set_info(void* kernelData); +void patch_pmCPUExitHaltToOff(void* kernelData); + +#endif /* !__BOOT2_KERNEL_PATCHER_H */