Index: branches/ErmaC/Enoch/i386/libsaio/Makefile =================================================================== --- branches/ErmaC/Enoch/i386/libsaio/Makefile (revision 2869) +++ branches/ErmaC/Enoch/i386/libsaio/Makefile (revision 2870) @@ -28,7 +28,7 @@ INC = -I. -I$(SRCROOT) -I$(SYMROOT) -I$(LIBSADIR) -I$(BOOT2DIR) -I${SRCROOT}/i386/include SAIO_OBJS = table.o asm.o bios.o biosfn.o \ - disk.o sys.o cache.o bootstruct.o \ + binaryPatcher.o disk.o sys.o cache.o bootstruct.o \ stringTable.o load.o pci.o allocate.o misc.o \ befs.o freebsd.o openbsd.o \ vbe.o nbp.o hfs.o hfs_compare.o \ Index: branches/ErmaC/Enoch/i386/libsaio/binaryPatcher.c =================================================================== --- branches/ErmaC/Enoch/i386/libsaio/binaryPatcher.c (revision 0) +++ branches/ErmaC/Enoch/i386/libsaio/binaryPatcher.c (revision 2870) @@ -0,0 +1,433 @@ +// +// binaryPatcher.c +// +// binary patcher of any kinds (kexts, kernel, ACPI tables etc..) +// +// + +#include "binaryPatcher.h" +#include "boot.h" /* to expose gDarwinBuildVerStr */ + +// Clover +// Searches Source for Search pattern of size SearchSize and return number of occurrences +// +unsigned int FindAndCount(void *sourceData, + UInt32 SourceSize, + UInt32 StartLocation, + UInt8 *Search, + unsigned int SearchSize) +{ + UInt8 *Source = ( UInt8 *)sourceData; + SourceSize += StartLocation; + unsigned int NumFounds = 0; + UInt8 *End = Source + SourceSize; + + while (Source < End) { + if (memcmp(Source, Search, SearchSize) == 0) { + NumFounds++; + Source += SearchSize; + } else { + Source++; + } + } + return NumFounds; +} + +// Clover +// +// Searches Source for Search pattern of size SearchSize +// and replaces it with Replace up to MaxReplaces times. +// If MaxReplaces <= 0, then there is no restriction on number of replaces. +// Replace should have the same size as Search. +// Returns number of replaces done. +// + +unsigned int FindAndReplace(void *sourceData, + UInt32 SourceSize, + UInt32 StartLocation, + UInt8 *Search, + unsigned int SearchSize, + UInt8 *Replace, + int MaxReplaces) +{ + UInt8 *Source = ( UInt8 *)sourceData; + Source += StartLocation; + unsigned int NumReplaces = 0; + bool NoReplacesRestriction = MaxReplaces <= 0; + UInt8 *End = Source + SourceSize; + if (!Source || !Search || !Replace || !SearchSize) { + return 0; + } + + while ((Source < End) && (NoReplacesRestriction || (MaxReplaces > 0))) { + if (memcmp(Source, Search, SearchSize) == 0) { + memcpy(Source, Replace, SearchSize); + NumReplaces++; + MaxReplaces--; + Source += SearchSize; + } else { + Source++; + } + } + return NumReplaces; +} + +bool IsPatchEnabled (char *MatchOSEntry, char *CurrOS) +{ + int i; + bool ret = false; + struct MatchOSes *mos; // = malloc(sizeof(struct MatchOSes)); + + if (!MatchOSEntry || !CurrOS) { + return true; //undefined matched corresponds to old behavior + } + + mos = GetStrArraySeparatedByChar(MatchOSEntry, ','); + if (!mos) { + return true; //memory fails -> anyway the patch enabled + } + + for (i = 0; i < mos->count; ++i) { + // dot represent MatchOS + if ( + ((strstr(mos->array[i], ".") != NULL) && IsOSValid(mos->array[i], CurrOS)) || // MatchOS + (strstr(mos->array[i], CurrOS) != NULL) // MatchBuild + ) { + ret = true; + break; + } + } + deallocMatchOSes(mos); + return ret; +} +// FIXME +// the following is an improved versione of what Clover have +// but malloc in Enoch fails to allocate memory (also using the same code in Clover ). +// For now we use a buffer and for this reason deallocMatchOSes() does nothing.. +struct MatchOSes *GetStrArraySeparatedByChar(char *str, char sep) +{ + char buffer[strlen(str) +1]; + struct MatchOSes *mo; + int len = 0, i = 0, inc = 1; + + char doubleSep[2]; + + mo = malloc(sizeof(struct MatchOSes)); + if (!mo) { + return NULL; + } + mo->count = countOccurrences( str, sep ) + 1; + len = (int)strlen(str); + doubleSep[0] = sep; doubleSep[1] = sep; + + if(strstr(str, doubleSep) || !len || str[0] == sep || str[len -1] == sep) { + mo->count = 0; + mo->array[0] = NULL; + return mo; + } + + if (mo->count > 1) { + int *indexes = (int *) malloc(mo->count + 1); + + for (i = 0; i < len; ++i) { + char c = str[i]; + if (c == sep) { + indexes[inc]=i; + inc++; + } + } + + indexes[0] = 0; // manually add first index + indexes[mo->count] = len; // manually add last index + + int startLocation = 0, endLocation = 0; + + for (i = 0; i < mo->count; ++i) { + unsigned int newLen = 0; + startLocation = i ? indexes[i] + 1 : indexes[0]; + endLocation = (i == mo->count - 1) ? len : indexes[i + 1]; + + newLen = (endLocation - startLocation); + + //char *lastStr = (char *) malloc(newLen+1); + //strncpy(lastStr, str + startLocation, newLen); + strncpy(buffer, str + startLocation, newLen); + buffer[newLen /*strlen(lastStr)*/] = '\0'; + mo->array[i] = buffer; + + //printf("%s [len = %lu]\n", mo->array[i], strlen(mo->array[i])); + if (endLocation == len) break; + } + + free(indexes); + } + else { + //char *lastStr = (char *) malloc(strlen(str)+1); + //strncpy(lastStr, str, strlen(str)); + strncpy(buffer, str, strlen(str)); + buffer[strlen(str)] = '\0'; + mo->array[0] = buffer; + //printf("%s [len = %lu]\n", mo->array[0], strlen(mo->array[0])); + } + //printf("------------\n"); + + return mo; +} + +void deallocMatchOSes(struct MatchOSes *s) +{ + /* + int i; + + if (!s) { + return; + } + + for (i = 0; i < s->count; i++) { + if (s->array[i]) { + free(s->array[i]); + } + } + free(s); + */ +} + +bool IsOSValid(char *MatchOS, char *CurrOS) +{ + /* example for valid matches are: + 10.7, only 10.7 (10.7.1 will be skipped) + 10.10.2 only 10.10.2 (10.10.1 or 10.10.5 will be skipped) + 10.10.x (or 10.10.X), in this case is valid for all minor version of 10.10 (10.10.(0-9)) + */ + + bool ret = false; + struct MatchOSes *osToc; + struct MatchOSes *currOStoc; + + if (!MatchOS || !CurrOS) { + return true; //undefined matched corresponds to old behavior + } + + osToc = GetStrArraySeparatedByChar(MatchOS, '.'); + currOStoc = GetStrArraySeparatedByChar(CurrOS, '.'); + + if (osToc->count == 2) { + if (strcmp(osToc->array[0], currOStoc->array[0]) == 0 + && strcmp(osToc->array[1], currOStoc->array[1]) == 0) { + ret = true; + } + } else if (osToc->count == 3) { + if (currOStoc->count == 3) { + if (strcmp(osToc->array[0], currOStoc->array[0]) == 0 + && strcmp(osToc->array[1], currOStoc->array[1]) == 0 + && strcmp(osToc->array[2], currOStoc->array[2]) == 0) { + ret = true; + } else if (strcmp(osToc->array[0], currOStoc->array[0]) == 0 + && strcmp(osToc->array[1], currOStoc->array[1]) == 0 + && (strcmp(osToc->array[2], "x") == 0 || strcmp(osToc->array[2], "X") == 0)) { + ret = true; + } + } else if (currOStoc->count == 2) { + if (strcmp(osToc->array[0], currOStoc->array[0]) == 0 + && strcmp(osToc->array[1], currOStoc->array[1]) == 0) { + ret = true; + } else if (strcmp(osToc->array[0], currOStoc->array[0]) == 0 + && strcmp(osToc->array[1], currOStoc->array[1]) == 0 + && (strcmp(osToc->array[2], "x") == 0 || strcmp(osToc->array[2], "X") == 0)) { + ret = true; + } + } + + } + + deallocMatchOSes(osToc); + deallocMatchOSes(currOStoc); + return ret; +} + +int countOccurrences( char *s, char c ) +{ + return *s == '\0' + ? 0 + : countOccurrences( s + 1, c ) + (*s == c); +} +// End of MatchOS + + +// +// Micky1979 +// +// Function to iterate the kernel.plist/kexts.plist (Acpi.plist?) and apply patches +// +void pach_binaryUsingDictionary(void *data, + UInt32 dataLen, + UInt32 StartLocation, + char *reason, + TagPtr config) +{ + bool canPatch = false; + UInt8 *bytes = (UInt8 *)data; + int numPatch, count; + numPatch = -1; + count = 0; + char * realReason; + TagPtr PatchTag = NULL; + + if (!config) return; + + /* coming soon.. + if (!strcmp(reason, "AcpiPatches")) { + // on all the acpi tables + realReason = "Acpi"; + } + else + if (!strcmp(reason, "DsdtPatches")) { + // only on dsdt + realReason = "Dsdt"; + } + else + */ + if (!strcmp(reason, "KernelPatches")) { + realReason = "kernel"; + } + else + { + realReason = reason; + } + + if ((PatchTag = XMLCastArray(XMLGetProperty(config, (const char *)reason)))) + { + count = XMLTagCount(PatchTag); + + /* for (i=0; i 0 ;) /* reversed iteration since xml.c add it reversed */ + { + numPatch ++; + if (!bytes) { + verbose("\t Skipping patch for %s because no bytes to patch..\n", realReason); + return; + } + + TagPtr index = XMLGetElement( PatchTag, i ); + if (index) + { + char *Comment = NULL; + char *MatchOS = NULL; + char *MatchBuild = NULL; + char *MatchUUID = NULL; + + int numPatches = 0; + + TagPtr FindPtr = XMLGetProperty(index, (const char*)"Find"); + TagPtr ReplacePtr = XMLGetProperty(index, (const char*)"Replace"); + + Comment = XMLCastString(XMLGetProperty(index, (const char*)"Comment")); + MatchOS = XMLCastString(XMLGetProperty(index, (const char*)"MatchOS")); + MatchBuild = XMLCastString(XMLGetProperty(index, (const char*)"MatchBuild")); + MatchUUID = XMLCastString(XMLGetProperty(index, (const char*)"MatchUUID")); + + Comment = (Comment != NULL && strlen(Comment) >0) ? Comment : "untitled"; + MatchOS = (MatchOS != NULL && strlen(MatchOS) >0) ? MatchOS : ""; // if lenght is 0 IsPatchEnabled() will not be called! + MatchBuild = (MatchBuild != NULL && strlen(MatchBuild) >0) ? MatchBuild : ""; + MatchUUID = (MatchUUID != NULL && strlen(MatchUUID) >0) ? MatchUUID : ""; + + canPatch = true; + // the order is important to skip patches + if (strlen(MatchUUID)) + { + // to be implemented + // check MatchUUID and disable this patch if does not match. Usefull to load or skip patches for certain volumes + // canPatch = IsPatchEnabled(MatchUUID, (char *)uuid_to_be_taken_somewhere); + } + else + { + MatchUUID = "not implemented"; + } + + if (strlen(MatchOS)) + { + // check MatchOS and disable this patch if does not match + canPatch = IsPatchEnabled(MatchOS, (char *)gMacOSVersion); + } + else + { + MatchOS = "not set"; + } + + if (strlen(MatchBuild)) + { + // check MatchBuild and disable this patch if does not match + canPatch = IsPatchEnabled(MatchBuild, (char *)gMacOSVersion); + } + else + { + MatchBuild = "not set"; + } + + char buf[1024]; + sprintf(buf, "\tPatching %s [Item %d] (%s) MatchOS[ %s ] MatchBuild[ %s ]: ", + realReason, numPatch, Comment, MatchOS, MatchBuild); + verbose("%s", buf); + + if (canPatch) + { + if (FindPtr && ReplacePtr) + { + if (!XMLIsData(FindPtr)) + { + verbose("\n\t\t\tUser Error, Find not in data tag, patch skipped\n"); + return; + } + + if (!XMLIsData(ReplacePtr)) + { + verbose("\n\t\t\tUser Error, Replace not in data tag, patch skipped\n"); + return; + } + + // don't allow patches with less than 2 bytes (it's ridiculous) + if (sizeof(FindPtr->data) <= 2) + { + verbose("\n\t\t\tUser Error, Find is less than 2 bytes (or less), patch skipped\n"); + return; + } + + if (sizeof(FindPtr->data) != sizeof(ReplacePtr->data)) + { + verbose("\n\t\t\tUser Error, Find and Replace does not have the same length, patch skipped\n"); + return; + } + + if (sizeof(FindPtr->data) > (dataLen - StartLocation)) + { + verbose("\n\t\t\tUser Error, Find is bigger than the hole data, patch skipped\n"); + return; + } + } + else + { + verbose("\n\t\t\tUser Error, Find or Replace (or both) are missing, patch skipped\n"); + return; + } + } + + + // patch it + if (canPatch) { + numPatches = FindAndReplace(data, + (UInt32)dataLen, + StartLocation, + FindPtr->data, + sizeof(FindPtr->data), + ReplacePtr->data, + 0); + verbose("%d substitutions made!\n", numPatches); + } + else + { + verbose("disabled!\n"); + } + } + } + } +} Index: branches/ErmaC/Enoch/i386/libsaio/binaryPatcher.h =================================================================== --- branches/ErmaC/Enoch/i386/libsaio/binaryPatcher.h (revision 0) +++ branches/ErmaC/Enoch/i386/libsaio/binaryPatcher.h (revision 2870) @@ -0,0 +1,76 @@ +// +// binaryPatcher.h +// +// binary patcher of any kinds (kexts, kernel, ACPI tables etc..) +// +// + +#ifndef binaryPatcher_h +#define binaryPatcher_h + +#include +#include +#include +#include "saio_types.h" +#include "libsaio.h" +#include "xml.h" + +#include "bootargs.h" +#include "saio_types.h" +#include "bios.h" +#include "device_tree.h" + +// Micky1979: Next five functions (+ needed struct) are to split a string like "10.10.5,10.7,10.11.6,10.8.x" +// in their components separated by comma (in this case) +struct MatchOSes { + int count; + char* array[100]; +}; + +/** Returns a boolean and then enable disable the patch if MachOSEntry have a match for the booted OS. */ +bool IsPatchEnabled(char *MatchOSEntry, char *CurrOS); + +/** return true if a given os contains '.' as separator, + and then match components of the current booted OS. Also allow 10.10.x format meaning all revisions + of the 10.10 OS */ +bool IsOSValid(char *MatchOS, char *CurrOS); + +/** return MatchOSes struct (count+array) with the components of str that contains the given char sep as separator. */ +struct MatchOSes *GetStrArraySeparatedByChar(char *str, char sep); + +/** free MatchOSes struct and its array. */ +void deallocMatchOSes(struct MatchOSes *s); + +/** count occurrences of a given char in a char* string. */ +int countOccurrences( char *s, char c ); + + +unsigned int FindAndReplace(void *sourceData, + UInt32 SourceSize, + UInt32 StartLocation, + UInt8 *Search, + unsigned int SearchSize, + UInt8 *Replace, + int MaxReplaces); + +unsigned int FindAndReplace(void *sourceData, + UInt32 SourceSize, + UInt32 StartLocation, + UInt8 *Search, + unsigned int SearchSize, + UInt8 *Replace, + int MaxReplaces); + +/* +unsigned int FindAndCount(void *sourceData, + UInt32 SourceSize, + UInt8 *Search, + unsigned int SearchSize); +*/ +void pach_binaryUsingDictionary(void *data, + UInt32 dataLen, + UInt32 StartLocation, + char *reason, + TagPtr config); + +#endif /* binaryPatcher_h */ Index: branches/ErmaC/Enoch/i386/boot2/boot.c =================================================================== --- branches/ErmaC/Enoch/i386/boot2/boot.c (revision 2869) +++ branches/ErmaC/Enoch/i386/boot2/boot.c (revision 2870) @@ -56,8 +56,8 @@ #include "platform.h" #include "modules.h" #include "device_tree.h" +#include "xml.h" - #if DEBUG_BOOT2 #define DBG(x...) printf(x) #else