2020-09-07 00:19:48 +02:00
/*
*
*/
2020-08-17 21:40:52 +02:00
# include <Platform.h> // Only use angled for Platform, else, xcode project won't compile
2020-09-07 00:19:48 +02:00
extern " C " {
# include <Library/OcDeviceTreeLib.h>
}
2020-04-16 11:09:22 +02:00
# include "kext_inject.h"
2020-04-16 09:15:26 +02:00
# include "DataHubCpu.h"
2020-08-25 17:35:19 +02:00
# include "../Platform/plist/plist.h"
2020-08-17 21:40:52 +02:00
# include "../Platform/Settings.h"
2020-08-25 17:35:19 +02:00
# include "../Platform/guid.h"
2021-04-28 20:30:34 +02:00
# include "../Settings/SelfOem.h"
2021-02-06 18:16:46 +01:00
# include "../Platform/KextList.h"
2020-10-12 13:51:08 +02:00
# include "MemoryOperation.h"
2021-02-06 18:16:46 +01:00
# include "../include/OSTypes.h"
2020-03-26 13:59:20 +01:00
# ifndef DEBUG_ALL
2020-07-27 15:09:30 +02:00
# define KEXT_INJECT_DEBUG 1
2020-03-26 13:59:20 +01:00
# else
# define KEXT_INJECT_DEBUG DEBUG_ALL
# endif
2019-09-03 11:58:42 +02:00
# if KEXT_INJECT_DEBUG == 2
2020-07-20 10:52:36 +02:00
# define DBG(...) printf(__VA_ARGS__);
2019-09-03 11:58:42 +02:00
# elif KEXT_INJECT_DEBUG == 1
2020-07-20 10:52:36 +02:00
# define DBG(...) DebugLog(KEXT_INJECT_DEBUG, __VA_ARGS__)
2019-09-03 11:58:42 +02:00
# else
# define DBG(...)
# endif
// runtime debug
2020-05-01 18:26:28 +02:00
//
2020-05-02 05:38:38 +02:00
# define OLD_EXTRA_KEXT_PATCH 0
2019-09-03 11:58:42 +02:00
////////////////////
// globals
////////////////////
2021-02-06 18:16:46 +01:00
//LIST_ENTRY gKextList = INITIALIZE_LIST_HEAD_VARIABLE (gKextList);
XObjArray < KEXT_ENTRY > gKextList ;
2019-09-03 11:58:42 +02:00
////////////////////
// before booting
////////////////////
EFI_STATUS EFIAPI ThinFatFile ( IN OUT UINT8 * * binary , IN OUT UINTN * length , IN cpu_type_t archCpuType )
{
UINT32 nfat , swapped , size = 0 ;
FAT_HEADER * fhp = ( FAT_HEADER * ) * binary ;
FAT_ARCH * fap = ( FAT_ARCH * ) ( * binary + sizeof ( FAT_HEADER ) ) ;
cpu_type_t fapcputype ;
UINT32 fapoffset ;
UINT32 fapsize ;
swapped = 0 ;
if ( fhp - > magic = = FAT_MAGIC ) {
nfat = fhp - > nfat_arch ;
} else if ( fhp - > magic = = FAT_CIGAM ) {
nfat = SwapBytes32 ( fhp - > nfat_arch ) ;
swapped = 1 ;
//already thin
} else if ( fhp - > magic = = THIN_X64 ) {
if ( archCpuType = = CPU_TYPE_X86_64 ) {
return EFI_SUCCESS ;
}
return EFI_NOT_FOUND ;
} else if ( fhp - > magic = = THIN_IA32 ) {
if ( archCpuType = = CPU_TYPE_I386 ) {
return EFI_SUCCESS ;
}
return EFI_NOT_FOUND ;
} else {
MsgLog ( " Thinning fails \n " ) ;
return EFI_NOT_FOUND ;
}
for ( ; nfat > 0 ; nfat - - , fap + + ) {
if ( swapped ) {
fapcputype = SwapBytes32 ( fap - > cputype ) ;
fapoffset = SwapBytes32 ( fap - > offset ) ;
fapsize = SwapBytes32 ( fap - > size ) ;
} else {
fapcputype = fap - > cputype ;
fapoffset = fap - > offset ;
fapsize = fap - > size ;
}
if ( fapcputype = = archCpuType ) {
* binary = ( * binary + fapoffset ) ;
size = fapsize ;
break ;
}
}
if ( length ! = 0 ) * length = size ;
return EFI_SUCCESS ;
}
2020-08-15 15:47:56 +02:00
void toLowerStr ( CHAR8 * tstr , IN CONST CHAR8 * str ) {
2019-09-30 10:29:31 +02:00
UINT16 cnt = 0 ;
for ( cnt = 0 ; * str ! = ' \0 ' & & cnt < = 0xFF ; cnt + + , str + + , tstr + + ) {
if ( * str > = ' A ' & & * str < = ' Z ' )
* tstr = ' a ' + ( * str - ' A ' ) ;
else
* tstr = * str ;
}
* tstr = ' \0 ' ;
}
2021-09-28 10:28:45 +02:00
XBool LOADER_ENTRY : : checkOSBundleRequired ( const TagDict * dict )
2019-09-30 10:29:31 +02:00
{
2021-09-28 10:28:45 +02:00
XBool inject = true ;
2020-08-19 14:50:26 +02:00
const TagStruct * osBundleRequiredTag ;
2020-08-15 15:47:56 +02:00
XString8 osbundlerequired ;
2019-09-30 10:29:31 +02:00
2020-08-25 17:35:19 +02:00
osBundleRequiredTag = dict - > propertyForKey ( " OSBundleRequired " ) ;
2020-08-15 15:47:56 +02:00
if ( osBundleRequiredTag ) {
2020-08-25 17:35:19 +02:00
osbundlerequired = osBundleRequiredTag - > getString ( ) - > stringValue ( ) ;
2020-08-15 15:47:56 +02:00
osbundlerequired . lowerAscii ( ) ;
}
2019-09-30 10:29:31 +02:00
2020-10-14 18:08:32 +02:00
if ( OSTYPE_IS_OSX_RECOVERY ( LoaderType ) | |
OSTYPE_IS_OSX_INSTALLER ( LoaderType ) ) {
2020-08-15 15:47:56 +02:00
if ( osbundlerequired ! = " root " _XS8 & &
osbundlerequired ! = " local " _XS8 & &
osbundlerequired ! = " console " _XS8 & &
osbundlerequired ! = " network-root " _XS8 ) {
2021-09-28 10:28:45 +02:00
inject = false ;
2019-12-19 09:48:27 +01:00
}
}
2019-09-30 10:29:31 +02:00
return inject ;
}
2020-10-03 19:02:31 +02:00
//extern void KernelAndKextPatcherInit(IN LOADER_ENTRY *Entry);
//extern void AnyKextPatch(UINT8 *Driver, UINT32 DriverSize, CHAR8 *InfoPlist, UINT32 InfoPlistSize, INT32 N, LOADER_ENTRY *Entry);
2019-09-03 11:58:42 +02:00
2022-03-06 11:42:12 +01:00
//XStringW infoPlistPath = getKextPlist(&self.getCloverDir(), dir, KextEntry, &NoContents);
2022-03-08 17:48:52 +01:00
XStringW LOADER_ENTRY : : getKextPlist ( const EFI_FILE * Root , const XStringW & dirPath , const XStringW & FileName , XBool * NoContents )
2020-10-14 18:08:32 +02:00
{
XStringW TempName ;
2022-03-06 11:42:12 +01:00
XStringW FullName ;
if ( dirPath . isEmpty ( ) ) { //dirPath.isEmpty()
2022-03-09 20:34:49 +01:00
FullName = SWPrintf ( " \\ %ls " , FileName . wc_str ( ) ) ;
2022-03-06 11:42:12 +01:00
} else {
FullName = SWPrintf ( " %ls \\ %ls " , dirPath . wc_str ( ) , FileName . wc_str ( ) ) ;
}
2020-10-14 18:08:32 +02:00
2022-03-06 11:42:12 +01:00
TempName = SWPrintf ( " %ls \\ %ls " , FullName . wc_str ( ) , L " Contents \\ Info.plist " ) ;
2024-01-02 19:54:23 +01:00
2022-03-08 17:48:52 +01:00
if ( ! FileExists ( Root , TempName ) ) {
2020-10-14 18:08:32 +02:00
//try to find a planar kext, without Contents
2022-03-06 11:42:12 +01:00
TempName = SWPrintf ( " %ls \\ %ls " , FullName . wc_str ( ) , L " Info.plist " ) ;
2022-03-08 17:48:52 +01:00
if ( ! FileExists ( Root , TempName ) ) {
2022-03-09 20:34:49 +01:00
MsgLog ( " Failed to load file : %ls \n " , TempName . wc_str ( ) ) ;
2020-10-14 20:54:18 +02:00
return L " " _XSW ;
2020-10-14 18:08:32 +02:00
}
2021-09-28 10:28:45 +02:00
* NoContents = true ;
2020-10-14 18:08:32 +02:00
} else {
2021-09-28 10:28:45 +02:00
* NoContents = false ;
2020-10-14 18:08:32 +02:00
}
2020-10-14 20:54:18 +02:00
return TempName ;
2020-10-14 18:08:32 +02:00
}
2022-03-08 17:48:52 +01:00
//TagDict* dict = getInfoPlist(Root, infoPlistPath);
TagDict * LOADER_ENTRY : : getInfoPlist ( const EFI_FILE * Root , const XStringW & infoPlistPath )
2020-10-14 18:08:32 +02:00
{
EFI_STATUS Status ;
UINT8 * infoDictBuffer = NULL ;
UINTN infoDictBufferLength = 0 ;
TagDict * dict = NULL ;
2022-03-08 17:48:52 +01:00
Status = egLoadFile ( Root , infoPlistPath . wc_str ( ) , & infoDictBuffer , & infoDictBufferLength ) ;
2020-10-14 18:08:32 +02:00
if ( ! EFI_ERROR ( Status ) ) { //double check
2023-11-07 11:02:22 +01:00
if ( ParseXML ( infoDictBuffer , & dict , infoDictBufferLength ) ! = 0 ) {
2020-10-14 18:08:32 +02:00
MsgLog ( " Failed to parse Info.plist: %ls \n " , infoPlistPath . wc_str ( ) ) ;
dict = NULL ;
}
FreePool ( infoDictBuffer ) ;
return dict ;
}
return NULL ;
}
2022-03-06 11:42:12 +01:00
//XString8 execpath = getKextExecPath(dir, KextEntry.FileName, dict, NoContents);
2022-03-08 17:48:52 +01:00
XString8 LOADER_ENTRY : : getKextExecPath ( const EFI_FILE * Root , const XStringW & dirPath , const XStringW & FileName , TagDict * dict , XBool NoContents )
2020-10-14 18:08:32 +02:00
{
const TagStruct * prop = NULL ;
2020-10-14 20:54:18 +02:00
XString8 TempName ;
2020-10-14 18:08:32 +02:00
prop = dict - > propertyForKey ( " CFBundleExecutable " ) ;
if ( prop ! = NULL & & prop - > isString ( ) & & prop - > getString ( ) - > stringValue ( ) . notEmpty ( ) ) {
2020-10-14 20:54:18 +02:00
const XString8 & Executable = prop - > getString ( ) - > stringValue ( ) ;
2020-10-14 18:08:32 +02:00
if ( NoContents ) {
2020-10-14 20:54:18 +02:00
TempName = S8Printf ( " %s " , Executable . c_str ( ) ) ;
2020-10-14 18:08:32 +02:00
} else {
2020-10-14 20:54:18 +02:00
TempName = S8Printf ( " Contents \\ MacOS \\ %s " , Executable . c_str ( ) ) ;
2020-10-14 18:08:32 +02:00
}
2024-01-07 18:14:33 +01:00
XStringW fullPath = SWPrintf ( " %ls \\ %ls \\ %ls \\ %s " , selfOem . getKextsDirPathRelToSelfDir ( ) . wc_str ( ) , dirPath . wc_str ( ) , FileName . wc_str ( ) , TempName . c_str ( ) ) ;
2022-03-08 17:48:52 +01:00
if ( ! FileExists ( Root , fullPath ) ) {
2024-01-07 18:14:33 +01:00
// kext from OpenCoreLegacyPatcher renamed the executable without updating CFBundleExecutable
// let's see if there is an executable that has the same name as the kext.
XString8 TempName2 ;
XStringW FileNameWithoutExt ;
if ( FileName . indexOf ( ' . ' ) ! = MAX_XSIZE ) FileNameWithoutExt = FileName . subString ( 0 , FileName . indexOf ( ' . ' ) ) ;
else FileNameWithoutExt = FileName ;
if ( NoContents ) {
TempName2 = S8Printf ( " %ls " , FileNameWithoutExt . wc_str ( ) ) ;
} else {
TempName2 = S8Printf ( " Contents \\ MacOS \\ %ls " , FileNameWithoutExt . wc_str ( ) ) ;
}
fullPath = SWPrintf ( " %ls \\ %ls \\ %ls \\ %s " , selfOem . getKextsDirPathRelToSelfDir ( ) . wc_str ( ) , dirPath . wc_str ( ) , FileName . wc_str ( ) , TempName2 . c_str ( ) ) ;
if ( ! FileExists ( Root , fullPath ) ) {
MsgLog ( " Failed to load kext executable: %ls \n " , FileName . wc_str ( ) ) ;
return " " _XS8 ; //no executable
} else {
MsgLog ( " Warning : wrong value for CFBundleExecutable for kext %ls. It's %s and should be %ls \n " , FileName . wc_str ( ) , Executable . c_str ( ) , FileName . wc_str ( ) ) ;
return TempName2 ;
}
2020-10-14 18:08:32 +02:00
}
}
2020-10-14 20:54:18 +02:00
return TempName ;
2020-10-14 18:08:32 +02:00
}
//it seems no more used? Or???
2021-04-06 15:39:55 +02:00
// FileName is better as a XString8 instead of XStringW because _BooterKextFileInfo will need an utf8.
2022-03-06 07:42:49 +01:00
/*
2020-10-03 19:02:31 +02:00
EFI_STATUS LOADER_ENTRY : : LoadKext ( const EFI_FILE * RootDir , const XString8 & FileName , IN cpu_type_t archCpuType , IN OUT void * kext_v )
2019-09-03 11:58:42 +02:00
{
EFI_STATUS Status ;
UINT8 * infoDictBuffer = NULL ;
UINTN infoDictBufferLength = 0 ;
UINT8 * executableFatBuffer = NULL ;
UINT8 * executableBuffer = NULL ;
UINTN executableBufferLength = 0 ;
2020-09-14 15:01:30 +02:00
// CHAR8* bundlePathBuffer = NULL;
// UINTN bundlePathBufferLength = 0;
2021-09-28 15:54:31 +02:00
XStringW TempName ;
TagDict * dict = NULL ;
2020-08-19 14:50:26 +02:00
const TagStruct * prop = NULL ;
2021-09-28 15:54:31 +02:00
XBool NoContents = false ;
XBool inject = false ;
2019-09-03 11:58:42 +02:00
_BooterKextFileInfo * infoAddr = NULL ;
2020-05-01 18:26:28 +02:00
_DeviceTreeBuffer * kext = ( _DeviceTreeBuffer * ) kext_v ;
2019-09-03 11:58:42 +02:00
2020-09-14 15:01:30 +02:00
TempName = SWPrintf ( " %s \\ %ls " , FileName . c_str ( ) , L " Contents \\ Info.plist " ) ;
2020-08-09 17:55:30 +02:00
Status = egLoadFile ( RootDir , TempName . wc_str ( ) , & infoDictBuffer , & infoDictBufferLength ) ;
2019-09-03 11:58:42 +02:00
if ( EFI_ERROR ( Status ) ) {
//try to find a planar kext, without Contents
2020-09-14 15:01:30 +02:00
TempName = SWPrintf ( " %s \\ %ls " , FileName . c_str ( ) , L " Info.plist " ) ;
2020-07-21 11:17:02 +02:00
infoDictBufferLength = 0 ;
2020-08-09 17:55:30 +02:00
Status = egLoadFile ( RootDir , TempName . wc_str ( ) , & infoDictBuffer , & infoDictBufferLength ) ;
2019-09-03 11:58:42 +02:00
if ( EFI_ERROR ( Status ) ) {
2020-08-25 17:35:19 +02:00
MsgLog ( " Failed to load extra kext : %ls status=%s \n " , TempName . wc_str ( ) , efiStrError ( Status ) ) ;
2019-09-03 11:58:42 +02:00
return EFI_NOT_FOUND ;
}
2021-09-28 10:28:45 +02:00
NoContents = true ;
2019-09-03 11:58:42 +02:00
}
2020-08-25 17:35:19 +02:00
if ( ParseXML ( ( CHAR8 * ) infoDictBuffer , & dict , infoDictBufferLength ) ! = 0 ) {
2019-09-03 11:58:42 +02:00
FreePool ( infoDictBuffer ) ;
2020-09-14 15:01:30 +02:00
MsgLog ( " Failed to load extra kext (failed to parse Info.plist): %s \n " , FileName . c_str ( ) ) ;
2019-09-03 11:58:42 +02:00
return EFI_NOT_FOUND ;
}
2019-09-30 10:29:31 +02:00
2020-10-14 18:08:32 +02:00
inject = checkOSBundleRequired ( dict ) ;
2019-09-30 10:29:31 +02:00
if ( ! inject ) {
2020-09-14 15:01:30 +02:00
MsgLog ( " Skipping kext injection by OSBundleRequired : %s \n " , FileName . c_str ( ) ) ;
2019-09-30 10:29:31 +02:00
return EFI_UNSUPPORTED ;
}
2020-08-25 17:35:19 +02:00
prop = dict - > propertyForKey ( " CFBundleExecutable " ) ;
if ( prop ! = NULL & & prop - > isString ( ) & & prop - > getString ( ) - > stringValue ( ) . notEmpty ( ) ) {
2020-09-14 15:01:30 +02:00
XString8 Executable = prop - > getString ( ) - > stringValue ( ) ;
2019-09-03 11:58:42 +02:00
if ( NoContents ) {
2020-09-14 15:01:30 +02:00
TempName = SWPrintf ( " %s \\ %s " , FileName . c_str ( ) , Executable . c_str ( ) ) ;
2020-04-04 15:50:13 +02:00
// snwprintf(TempName, 512, "%s\\%s", FileName, Executable);
2019-09-03 11:58:42 +02:00
} else {
2020-09-14 15:01:30 +02:00
TempName = SWPrintf ( " %s \\ Contents \\ MacOS \\ %s " , FileName . c_str ( ) , Executable . c_str ( ) ) ;
2020-04-04 15:50:13 +02:00
// snwprintf(TempName, 512, L"%s\\%s\\%s", FileName, "Contents\\MacOS",Executable);
2019-09-03 11:58:42 +02:00
}
2020-08-09 17:55:30 +02:00
Status = egLoadFile ( RootDir , TempName . wc_str ( ) , & executableFatBuffer , & executableBufferLength ) ;
2019-09-03 11:58:42 +02:00
if ( EFI_ERROR ( Status ) ) {
FreePool ( infoDictBuffer ) ;
2020-09-14 15:01:30 +02:00
MsgLog ( " Failed to load extra kext (executable not found): %s \n " , FileName . c_str ( ) ) ;
2019-09-03 11:58:42 +02:00
return EFI_NOT_FOUND ;
}
executableBuffer = executableFatBuffer ;
if ( ThinFatFile ( & executableBuffer , & executableBufferLength , archCpuType ) ) {
FreePool ( infoDictBuffer ) ;
FreePool ( executableBuffer ) ;
2020-09-14 15:01:30 +02:00
MsgLog ( " Thinning failed: %s \n " , FileName . c_str ( ) ) ;
2019-09-03 11:58:42 +02:00
return EFI_NOT_FOUND ;
}
}
2020-09-14 15:01:30 +02:00
// bundlePathBufferLength = StrLen(FileName) + 1;
// bundlePathBuffer = (__typeof__(bundlePathBuffer))AllocateZeroPool(bundlePathBufferLength);
// UnicodeStrToAsciiStrS(FileName, bundlePathBuffer, bundlePathBufferLength);
2019-09-03 11:58:42 +02:00
2020-09-14 15:01:30 +02:00
kext - > length = ( UINT32 ) ( sizeof ( _BooterKextFileInfo ) + infoDictBufferLength + executableBufferLength + FileName . sizeInBytesIncludingTerminator ( ) ) ;
2019-09-03 11:58:42 +02:00
infoAddr = ( _BooterKextFileInfo * ) AllocatePool ( kext - > length ) ;
infoAddr - > infoDictPhysAddr = sizeof ( _BooterKextFileInfo ) ;
infoAddr - > infoDictLength = ( UINT32 ) infoDictBufferLength ;
infoAddr - > executablePhysAddr = ( UINT32 ) ( sizeof ( _BooterKextFileInfo ) + infoDictBufferLength ) ;
infoAddr - > executableLength = ( UINT32 ) executableBufferLength ;
infoAddr - > bundlePathPhysAddr = ( UINT32 ) ( sizeof ( _BooterKextFileInfo ) + infoDictBufferLength + executableBufferLength ) ;
2020-09-14 15:01:30 +02:00
infoAddr - > bundlePathLength = ( UINT32 ) FileName . sizeInBytesIncludingTerminator ( ) ;
2019-09-03 11:58:42 +02:00
kext - > paddr = ( UINT32 ) ( UINTN ) infoAddr ; // Note that we cannot free infoAddr because of this
CopyMem ( ( CHAR8 * ) infoAddr + sizeof ( _BooterKextFileInfo ) , infoDictBuffer , infoDictBufferLength ) ;
CopyMem ( ( CHAR8 * ) infoAddr + sizeof ( _BooterKextFileInfo ) + infoDictBufferLength , executableBuffer , executableBufferLength ) ;
2020-09-14 15:01:30 +02:00
CopyMem ( ( CHAR8 * ) infoAddr + sizeof ( _BooterKextFileInfo ) + infoDictBufferLength + executableBufferLength , FileName . c_str ( ) , FileName . sizeInBytesIncludingTerminator ( ) ) ;
2019-09-03 11:58:42 +02:00
FreePool ( infoDictBuffer ) ;
FreePool ( executableFatBuffer ) ;
2020-08-22 15:39:24 +02:00
dict - > FreeTag ( ) ;
2019-09-03 11:58:42 +02:00
return EFI_SUCCESS ;
}
2020-10-03 19:02:31 +02:00
EFI_STATUS LOADER_ENTRY : : AddKext ( const EFI_FILE * RootDir , const XString8 & FileName , IN cpu_type_t archCpuType )
2019-09-03 11:58:42 +02:00
{
EFI_STATUS Status ;
KEXT_ENTRY * KextEntry ;
2021-05-05 19:10:10 +02:00
KextEntry = new KEXT_ENTRY ;
2019-09-03 11:58:42 +02:00
KextEntry - > Signature = KEXT_SIGNATURE ;
2020-05-01 18:26:28 +02:00
Status = LoadKext ( RootDir , FileName , archCpuType , & KextEntry - > kext ) ;
2019-09-03 11:58:42 +02:00
if ( EFI_ERROR ( Status ) ) {
2021-02-06 18:16:46 +01:00
delete KextEntry ;
2019-09-03 11:58:42 +02:00
} else {
2021-02-06 18:16:46 +01:00
gKextList . AddReference ( KextEntry , true ) ;
2019-09-03 11:58:42 +02:00
}
return Status ;
}
2022-03-06 07:42:49 +01:00
*/
2019-09-03 11:58:42 +02:00
UINT32 GetListCount ( LIST_ENTRY const * List )
{
LIST_ENTRY * Link ;
UINT32 Count = 0 ;
if ( ! IsListEmpty ( List ) ) {
for ( Link = List - > ForwardLink ; Link ! = List ; Link = Link - > ForwardLink )
Count + + ;
}
return Count ;
}
2021-02-06 18:16:46 +01:00
//UINT32 GetKextsSize()
//{
// LIST_ENTRY *Link;
// KEXT_ENTRY *KextEntry;
// UINT32 kextsSize=0;
//
// if(!IsListEmpty(&gKextList)) {
// for (Link = gKextList.ForwardLink; Link != &gKextList; Link = Link->ForwardLink) {
// KextEntry = CR(Link, KEXT_ENTRY, Link, KEXT_SIGNATURE);
// kextsSize += RoundPage(KextEntry->kext.length);
// }
// }
// return kextsSize;
//}
2022-03-06 07:42:49 +01:00
/*
2021-09-28 10:28:45 +02:00
void LOADER_ENTRY : : LoadPlugInKexts ( const EFI_FILE * RootDir , const XString8 & DirName , IN cpu_type_t archCpuType , IN XBool Force )
2019-09-03 11:58:42 +02:00
{
REFIT_DIR_ITER PlugInIter ;
EFI_FILE_INFO * PlugInFile ;
2020-09-14 15:01:30 +02:00
XString8 FileName ;
if ( RootDir = = NULL | | DirName . isEmpty ( ) ) {
2019-09-03 11:58:42 +02:00
return ;
}
2020-09-14 15:01:30 +02:00
DirIterOpen ( RootDir , XStringW ( DirName ) . wc_str ( ) , & PlugInIter ) ;
2019-09-03 11:58:42 +02:00
while ( DirIterNext ( & PlugInIter , 1 , L " *.kext " , & PlugInFile ) ) {
2019-12-19 17:51:21 +01:00
if ( PlugInFile - > FileName [ 0 ] = = ' . ' | | StrStr ( PlugInFile - > FileName , L " .kext " ) = = NULL )
continue ; // skip this
2020-09-14 15:01:30 +02:00
FileName = SWPrintf ( " %s \\ %ls " , DirName . c_str ( ) , PlugInFile - > FileName ) ;
2020-04-04 15:50:13 +02:00
// snwprintf(FileName, 512, "%s\\%s", DirName, PlugInFile->FileName);
2020-09-14 15:01:30 +02:00
MsgLog ( " %ls PlugIn kext: %s \n " , Force ? L " Force " : L " Extra " , FileName . c_str ( ) ) ;
AddKext ( RootDir , FileName , archCpuType ) ;
2019-09-03 11:58:42 +02:00
}
DirIterClose ( & PlugInIter ) ;
}
2022-03-06 07:42:49 +01:00
*/
2020-10-03 19:02:31 +02:00
//void LOADER_ENTRY::AddKexts(const XStringW& SrcDir, const XStringW& Path, cpu_type_t archCpuType)
2020-09-14 15:01:30 +02:00
//{
// XStringW FileName;
// XStringW PlugInName;
// SIDELOAD_KEXT *CurrentKext;
// SIDELOAD_KEXT *CurrentPlugInKext;
// EFI_STATUS Status;
//
// MsgLog("Preparing kexts injection from %ls\n", SrcDir.wc_str());
// CurrentKext = InjectKextList;
// while (CurrentKext) {
//// DBG(" current kext name=%ls path=%ls, match against=%ls\n", CurrentKext->FileName, CurrentKext->KextDirNameUnderOEMPath, Path);
// if ( CurrentKext->KextDirNameUnderOEMPath == Path ) {
// FileName = SWPrintf("%ls\\%ls", SrcDir.wc_str(), CurrentKext->FileName.wc_str());
// // snwprintf(FileName, 512, "%s\\%s", SrcDir, CurrentKext->FileName);
// if (!(CurrentKext->MenuItem.BValue)) {
// // inject require
// MsgLog("->Extra kext: %ls (v.%ls)\n", FileName.wc_str(), CurrentKext->Version.wc_str());
// Status = AddKext(SelfVolume->RootDir, FileName.wc_str(), archCpuType);
// if(!EFI_ERROR(Status)) {
// // decide which plugins to inject
// CurrentPlugInKext = CurrentKext->PlugInList;
// while (CurrentPlugInKext) {
// PlugInName = SWPrintf("%ls\\%ls\\%ls", FileName.wc_str(), L"Contents\\PlugIns", CurrentPlugInKext->FileName.wc_str());
// // snwprintf(PlugInName, 512, L"%s\\%s\\%s", FileName, "Contents\\PlugIns", CurrentPlugInKext->FileName);
// if (!(CurrentPlugInKext->MenuItem.BValue)) {
// // inject PlugIn require
// MsgLog(" |-- PlugIn kext: %ls (v.%ls)\n", PlugInName.wc_str(), CurrentPlugInKext->Version.wc_str());
// AddKext(SelfVolume->RootDir, PlugInName.wc_str(), archCpuType);
// } else {
// MsgLog(" |-- Disabled plug-in kext: %ls (v.%ls)\n", PlugInName.wc_str(), CurrentPlugInKext->Version.wc_str());
// }
// CurrentPlugInKext = CurrentPlugInKext->Next;
// } // end of plug-in kext injection
// }
// } else {
// // disable current kext injection
// if ( SrcDir.containsIC(L"Off") ) {
// MsgLog("Disabled kext: %ls (v.%ls)\n", FileName.wc_str(), CurrentKext->Version.wc_str());
// }
// }
// }
// CurrentKext = CurrentKext->Next;
// } // end of kext injection
//
//}
2019-09-03 11:58:42 +02:00
2020-09-07 00:19:48 +02:00
// Jief : this should replace LOADER_ENTRY::AddKexts
2021-01-31 10:50:23 +01:00
void LOADER_ENTRY : : AddKextsFromDirInArray ( const XString8 & SrcDir , cpu_type_t archCpuType , XObjArray < SIDELOAD_KEXT > * kextArray )
2020-09-07 00:19:48 +02:00
{
XStringW FileName ;
XStringW PlugInName ;
2020-09-14 15:01:30 +02:00
MsgLog ( " AddKextsInArray from %s \n " , SrcDir . c_str ( ) ) ;
2020-09-16 01:01:53 +02:00
for ( size_t idx = 0 ; idx < InjectKextList . size ( ) ; idx + + ) {
SIDELOAD_KEXT & CurrentKext = InjectKextList [ idx ] ;
2020-09-16 19:50:16 +02:00
// DBG(" current kext name=%ls path=%ls, match against=%s\n", CurrentKext.FileName.wc_str(), CurrentKext.KextDirNameUnderOEMPath.wc_str(), Path.c_str());
2021-01-31 10:50:23 +01:00
if ( CurrentKext . KextDirNameUnderOEMPath = = SrcDir ) {
2020-09-16 01:01:53 +02:00
FileName = SWPrintf ( " %s \\ %ls " , SrcDir . c_str ( ) , CurrentKext . FileName . wc_str ( ) ) ;
if ( ! ( CurrentKext . MenuItem . BValue ) ) {
2020-09-07 00:19:48 +02:00
// inject require
2020-09-16 01:01:53 +02:00
MsgLog ( " ->Extra kext: %ls (v.%ls) \n " , FileName . wc_str ( ) , CurrentKext . Version . wc_str ( ) ) ;
2020-09-07 00:19:48 +02:00
// Status = AddKext(SelfVolume->RootDir, FileName.wc_str(), archCpuType);
2020-09-16 01:01:53 +02:00
kextArray - > AddReference ( & CurrentKext , false ) ; // do not free, CurrentKext belongs to an other object
2020-09-07 00:19:48 +02:00
// decide which plugins to inject
2020-09-16 01:01:53 +02:00
for ( size_t idxPlugin = 0 ; idxPlugin < CurrentKext . PlugInList . size ( ) ; idxPlugin + + ) {
SIDELOAD_KEXT & CurrentPlugInKext = CurrentKext . PlugInList [ idxPlugin ] ;
PlugInName = SWPrintf ( " %ls \\ Contents \\ PlugIns \\ %ls " , FileName . wc_str ( ) , CurrentPlugInKext . FileName . wc_str ( ) ) ;
// snwprintf(PlugInName, 512, L"%s\\%s\\%s", FileName, "Contents\\PlugIns", CurrentPlugInKext.FileName);
if ( ! ( CurrentPlugInKext . MenuItem . BValue ) ) {
2020-09-07 00:19:48 +02:00
// inject PlugIn require
2020-09-16 01:01:53 +02:00
MsgLog ( " |-- PlugIn kext: %ls (v.%ls) \n " , PlugInName . wc_str ( ) , CurrentPlugInKext . Version . wc_str ( ) ) ;
2020-09-07 00:19:48 +02:00
// AddKext(SelfVolume->RootDir, PlugInName.wc_str(), archCpuType);
2020-09-16 01:01:53 +02:00
kextArray - > AddReference ( & CurrentPlugInKext , false ) ; // do not free, CurrentKext belongs to an other object
2020-09-07 00:19:48 +02:00
} else {
2020-09-16 01:01:53 +02:00
MsgLog ( " |-- Disabled plug-in kext: %ls (v.%ls) \n " , PlugInName . wc_str ( ) , CurrentPlugInKext . Version . wc_str ( ) ) ;
2020-09-07 00:19:48 +02:00
}
} // end of plug-in kext injection
} else {
// disable current kext injection
if ( SrcDir . containsIC ( L " Off " ) ) {
2020-09-16 01:01:53 +02:00
MsgLog ( " Disabled kext: %ls (v.%ls) \n " , FileName . wc_str ( ) , CurrentKext . Version . wc_str ( ) ) ;
2020-09-07 00:19:48 +02:00
}
}
}
} // end of kext injection
}
2022-03-06 07:42:49 +01:00
2020-09-16 01:01:53 +02:00
void LOADER_ENTRY : : AddKextsInArray ( XObjArray < SIDELOAD_KEXT > * kextArray )
2019-09-03 11:58:42 +02:00
{
2020-08-09 17:55:30 +02:00
XStringW SrcDir ;
2022-03-06 07:42:49 +01:00
// REFIT_DIR_ITER PlugInIter;
// EFI_FILE_INFO *PlugInFile;
2021-04-06 15:39:55 +02:00
// XString8 FileName;
// XString8 PlugIns;
2020-05-02 21:57:41 +02:00
// CONST CHAR16 *Arch = NULL;
2020-04-05 14:25:39 +02:00
// CONST CHAR16 *Ptr = NULL;
2020-10-17 15:01:33 +02:00
if ( ! selfOem . isKextsDirFound ( ) ) return ;
2019-09-03 11:58:42 +02:00
# if defined(MDE_CPU_X64)
cpu_type_t archCpuType = CPU_TYPE_X86_64 ;
# else
cpu_type_t archCpuType = CPU_TYPE_I386 ;
# endif
// Make Arch point to the last appearance of "arch=" in LoadOptions (which is what boot.efi will use).
2020-05-02 21:57:41 +02:00
// if (LoadOptions.notEmpty()) {
2020-05-01 18:26:28 +02:00
// for (Ptr = StrStr(LoadOptions, L"arch="); Ptr != NULL; Arch = Ptr + StrLen(L"arch="), Ptr = StrStr(Arch, L"arch="));
2020-05-02 21:57:41 +02:00
// }
2019-09-03 11:58:42 +02:00
2020-05-02 21:57:41 +02:00
// if (Arch != NULL && StrnCmp(Arch,L"x86_64",StrLen(L"x86_64")) == 0) {
2020-08-06 20:53:01 +02:00
if ( LoadOptions . contains ( " arch=x86_64 " ) ) {
2019-09-03 11:58:42 +02:00
archCpuType = CPU_TYPE_X86_64 ;
2020-05-02 21:57:41 +02:00
// } else if (Arch != NULL && StrnCmp(Arch,L"i386",StrLen(L"i386")) == 0) {
2020-08-06 20:53:01 +02:00
} else if ( LoadOptions . contains ( " arch=i386 " ) ) {
2019-09-03 11:58:42 +02:00
archCpuType = CPU_TYPE_I386 ;
2021-01-31 10:50:23 +01:00
} else if ( macOSVersion . notEmpty ( ) ) {
// UINT64 os_version = AsciiOSVersionToUint64(macOSVersion);
if ( macOSVersion . isEmpty ( ) | | macOSVersion > = MacOsVersion ( " 10.8 " _XS8 ) ) {
archCpuType = CPU_TYPE_X86_64 ; // For macOSVersion >= 10.8, only x86_64 exists
} else if ( macOSVersion < MacOsVersion ( " 10.7 " _XS8 ) ) {
archCpuType = CPU_TYPE_I386 ; // For macOSVersion < 10.7, use default of i386
2019-09-03 11:58:42 +02:00
}
}
// Force kexts to load
2022-03-06 11:42:12 +01:00
2022-03-06 07:42:49 +01:00
/*
2021-03-25 15:32:56 +01:00
if ( KernelAndKextPatches . ForceKextsToLoad . notEmpty ( ) ) {
for ( size_t i = 0 ; i < KernelAndKextPatches . ForceKextsToLoad . size ( ) ; + + i ) {
MsgLog ( " Force kext: %ls \n " , KernelAndKextPatches . ForceKextsToLoad [ i ] . wc_str ( ) ) ;
2020-05-01 18:26:28 +02:00
if ( Volume & & Volume - > RootDir ) {
2019-09-03 11:58:42 +02:00
// Check if the entry is a directory
2021-04-06 15:39:55 +02:00
const wchar_t * p ;
if ( KernelAndKextPatches . ForceKextsToLoad [ i ] . startWith ( ' \\ ' ) ) p = KernelAndKextPatches . ForceKextsToLoad [ i ] . wc_str ( 1 ) ;
else p = KernelAndKextPatches . ForceKextsToLoad [ i ] . wc_str ( ) ;
if ( StrStr ( p , L " .kext " ) = = NULL ) {
DirIterOpen ( Volume - > RootDir , p , & PlugInIter ) ;
2019-09-03 11:58:42 +02:00
while ( DirIterNext ( & PlugInIter , 1 , L " *.kext " , & PlugInFile ) ) {
if ( PlugInFile - > FileName [ 0 ] = = ' . ' | | StrStr ( PlugInFile - > FileName , L " .kext " ) = = NULL )
continue ; // skip this
2021-04-06 15:39:55 +02:00
XString8 FileName = S8Printf ( " %ls \\ %ls " , p , PlugInFile - > FileName ) ;
2020-09-14 15:01:30 +02:00
MsgLog ( " Force kext: %s \n " , FileName . c_str ( ) ) ;
2022-03-06 07:42:49 +01:00
AddKext ( Volume - > RootDir , FileName , archCpuType , kextForceArray ) ;
2021-04-06 15:39:55 +02:00
XString8 PlugIns = S8Printf ( " %s \\ Contents \\ PlugIns " , FileName . c_str ( ) ) ;
2021-09-28 10:28:45 +02:00
LoadPlugInKexts ( Volume - > RootDir , PlugIns , archCpuType , true ) ;
2019-09-03 11:58:42 +02:00
}
DirIterClose ( & PlugInIter ) ;
} else {
2021-04-06 15:39:55 +02:00
XString8 Path = S8Printf ( " %ls " , p ) ;
2022-03-06 07:42:49 +01:00
AddKext ( Volume - > RootDir , Path , archCpuType , kextForceArray ) ;
2021-04-06 15:39:55 +02:00
XString8 PlugIns = S8Printf ( " %s \\ Contents \\ PlugIns " , Path . c_str ( ) ) ;
2021-09-28 10:28:45 +02:00
LoadPlugInKexts ( Volume - > RootDir , PlugIns , archCpuType , true ) ;
2019-09-03 11:58:42 +02:00
}
}
}
}
2022-03-06 07:42:49 +01:00
*/
2019-09-03 11:58:42 +02:00
2021-01-31 10:50:23 +01:00
// Clover/Kexts/Other is for general injection thus we need to scan both Other and macOSVersion folder
2021-09-28 10:28:45 +02:00
SrcDir = GetOtherKextsDir ( true ) ;
2020-08-09 17:55:30 +02:00
if ( SrcDir . notEmpty ( ) ) {
2021-01-31 10:50:23 +01:00
AddKextsFromDirInArray ( SrcDir , archCpuType , kextArray ) ;
2019-12-23 12:36:26 +01:00
} else {
2021-09-28 10:28:45 +02:00
DBG ( " GetOtherKextsDir(true) return NULL \n " ) ;
2019-09-03 11:58:42 +02:00
}
// slice: CLOVER/kexts/Off keep disabled kext which can be allowed
2021-09-28 10:28:45 +02:00
SrcDir = GetOtherKextsDir ( false ) ;
2020-08-09 17:55:30 +02:00
if ( SrcDir . notEmpty ( ) ) {
2021-01-31 10:50:23 +01:00
AddKextsFromDirInArray ( SrcDir , archCpuType , kextArray ) ;
2019-12-23 12:36:26 +01:00
} else {
2021-09-28 10:28:45 +02:00
DBG ( " GetOtherKextsDir(false) return NULL \n " ) ;
2019-09-03 11:58:42 +02:00
}
2021-01-31 10:50:23 +01:00
if ( macOSVersion . notEmpty ( ) )
2019-12-23 12:36:26 +01:00
{
2021-01-31 10:50:23 +01:00
XString8 OSVersionKextsDirName ; // declare here to avoid multiple allocation
2019-12-11 13:52:26 +01:00
2019-12-09 11:22:15 +01:00
2022-06-24 18:03:14 +02:00
// Add kexts from 10, 11, 12, 13...
2019-12-19 17:51:21 +01:00
2021-01-31 10:50:23 +01:00
OSVersionKextsDirName = macOSVersion . asString ( 1 ) ;
AddKextsFromDirInArray ( OSVersionKextsDirName , archCpuType , kextArray ) ;
OSVersionKextsDirName . S8Catf ( " _%s " , getSuffixForMacOsVersion ( LoaderType ) . c_str ( ) ) ;
AddKextsFromDirInArray ( OSVersionKextsDirName , archCpuType , kextArray ) ;
2019-12-11 13:52:26 +01:00
2021-01-31 10:50:23 +01:00
// Add kext from ${osMajorVersion}.{version}
OSVersionKextsDirName = macOSVersion . asString ( 2 ) ;
if ( macOSVersion . elementAt ( 1 ) = = - 1 ) OSVersionKextsDirName . S8Catf ( " .0 " ) ;
AddKextsFromDirInArray ( OSVersionKextsDirName , archCpuType , kextArray ) ;
OSVersionKextsDirName . S8Catf ( " _%s " , getSuffixForMacOsVersion ( LoaderType ) . c_str ( ) ) ;
AddKextsFromDirInArray ( OSVersionKextsDirName , archCpuType , kextArray ) ;
2019-12-09 11:22:15 +01:00
2019-12-19 17:51:21 +01:00
2019-12-23 12:36:26 +01:00
// Add kext from :
2020-09-07 00:19:48 +02:00
// ${osMajorVersion}.{version}.0 if NO minor version
// ${osMajorVersion}.{version}.{minor version} if minor version is > 0
2019-12-19 17:51:21 +01:00
2021-01-31 10:50:23 +01:00
OSVersionKextsDirName = macOSVersion . asString ( 3 ) ;
if ( macOSVersion . elementAt ( 1 ) = = - 1 ) OSVersionKextsDirName . S8Catf ( " .0 " ) ;
if ( macOSVersion . elementAt ( 2 ) = = - 1 ) OSVersionKextsDirName . S8Catf ( " .0 " ) ;
2019-12-11 13:52:26 +01:00
2021-01-31 10:50:23 +01:00
AddKextsFromDirInArray ( OSVersionKextsDirName , archCpuType , kextArray ) ;
OSVersionKextsDirName . S8Catf ( " _%s " , getSuffixForMacOsVersion ( LoaderType ) . c_str ( ) ) ;
AddKextsFromDirInArray ( OSVersionKextsDirName , archCpuType , kextArray ) ;
2020-09-08 13:00:17 +02:00
} else {
//MsgLog("No os version is detected\n");
2021-01-31 10:50:23 +01:00
AddKextsFromDirInArray ( " Unknown " _XS8 , archCpuType , kextArray ) ;
2019-12-23 12:36:26 +01:00
}
2019-12-09 11:22:15 +01:00
2020-09-14 15:01:30 +02:00
}
2020-11-12 22:25:56 +01:00
//EFI_STATUS LOADER_ENTRY::LoadKexts()
//{
// XObjArray<SIDELOAD_KEXT> kextArray;
// AddKextsInArray(&kextArray);
//
//
// #if defined(MDE_CPU_X64)
// cpu_type_t archCpuType=CPU_TYPE_X86_64;
// #else
// cpu_type_t archCpuType=CPU_TYPE_I386;
// #endif
// // Make Arch point to the last appearance of "arch=" in LoadOptions (which is what boot.efi will use).
// // if (LoadOptions.notEmpty()) {
// // for (Ptr = StrStr(LoadOptions, L"arch="); Ptr != NULL; Arch = Ptr + StrLen(L"arch="), Ptr = StrStr(Arch, L"arch="));
// // }
//
// // if (Arch != NULL && StrnCmp(Arch,L"x86_64",StrLen(L"x86_64")) == 0) {
// if (LoadOptions.contains("arch=x86_64")) {
// archCpuType = CPU_TYPE_X86_64;
// // } else if (Arch != NULL && StrnCmp(Arch,L"i386",StrLen(L"i386")) == 0) {
// } else if (LoadOptions.contains("arch=i386")) {
// archCpuType = CPU_TYPE_I386;
2021-01-31 10:50:23 +01:00
// } else if (macOSVersion.notEmpty()) {
//// UINT64 os_version = AsciiOSVersionToUint64(macOSVersion);
// if (macOSVersion.isEmpty() || macOSVersion >= MacOsVersion("10.8"_XS8)) {
// archCpuType = CPU_TYPE_X86_64; // For macOSVersion >= 10.8, only x86_64 exists
// } else if (macOSVersion < MacOsVersion("10.7"_XS8)) {
// archCpuType = CPU_TYPE_I386; // For macOSVersion < 10.7, use default of i386
2020-11-12 22:25:56 +01:00
// }
// }
//
// for (size_t idx = 0 ; idx < kextArray.size() ; idx++ ) {
// AddKext(SelfVolume->RootDir, S8Printf("%ls\\%ls", kextArray[idx].KextDirNameUnderOEMPath.wc_str(), kextArray[idx].FileName.wc_str()), archCpuType);
// }
//
// UINTN mm_extra_size;
// void *mm_extra;
// UINTN extra_size;
// void *extra;
//
// // reserve space in the device tree
// if (GetKextCount() > 0) {
// mm_extra_size = GetKextCount() * (sizeof(DTProperty) + sizeof(_DeviceTreeBuffer));
// mm_extra = (__typeof__(mm_extra))AllocateZeroPool(mm_extra_size - sizeof(DTProperty));
// /*Status = */LogDataHub(&gEfiMiscSubClassGuid, L"mm_extra", mm_extra, (UINT32)(mm_extra_size - sizeof(DTProperty)));
// extra_size = GetKextsSize();
// extra = (__typeof__(extra))AllocateZeroPool(extra_size - sizeof(DTProperty) + EFI_PAGE_SIZE);
// /*Status = */LogDataHub(&gEfiMiscSubClassGuid, L"extra", extra, (UINT32)(extra_size - sizeof(DTProperty) + EFI_PAGE_SIZE));
// // MsgLog("count: %d \n", GetKextCount());
// // MsgLog("mm_extra_size: %d \n", mm_extra_size);
// // MsgLog("extra_size: %d \n", extra_size);
// // MsgLog("offset: %d \n", extra_size - sizeof(DTProperty) + EFI_PAGE_SIZE);
// //no more needed
// FreePool(mm_extra);
// FreePool(extra);
// }
//
//// InjectKextList.setEmpty();
// return EFI_SUCCESS;
//}
2019-09-03 11:58:42 +02:00
2019-12-27 13:54:58 +01:00
/*
2020-07-20 10:52:36 +02:00
* Adler32 from Chameleon , not used
2019-12-27 13:54:58 +01:00
*/
# define BASE 65521L /* largest prime smaller than 65536 */
# define NMAX 5000
// NMAX (was 5521) the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
# define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
# define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
# define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
# define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
# define DO16(buf) DO8(buf,0); DO8(buf,8);
2020-07-20 10:52:36 +02:00
#if 0
2020-03-11 15:23:58 +01:00
static UINT32 Adler32 ( unsigned char * buf , long len )
2019-12-27 13:54:58 +01:00
{
unsigned long s1 = 1 ; // adler & 0xffff;
unsigned long s2 = 0 ; // (adler >> 16) & 0xffff;
unsigned long result ;
2020-03-11 15:23:58 +01:00
long k ;
2019-12-27 13:54:58 +01:00
while ( len > 0 ) {
k = len < NMAX ? len : NMAX ;
len - = k ;
while ( k > = 16 ) {
DO16 ( buf ) ;
buf + = 16 ;
k - = 16 ;
}
if ( k ! = 0 ) do {
s1 + = * buf + + ;
s2 + = s1 ;
} while ( - - k ) ;
s1 % = BASE ;
s2 % = BASE ;
}
result = ( s2 < < 16 ) | s1 ;
// result is in big endian
2020-03-11 15:23:58 +01:00
return ( UINT32 ) result ;
2019-12-27 13:54:58 +01:00
}
2019-12-27 17:01:27 +01:00
typedef struct {
UINT32 Magic ;
UINT32 Signature ;
UINT32 Length ;
UINT32 Adler32 ;
UINT32 Version ;
UINT32 NumKexts ;
UINT32 CpuType ;
UINT32 CpuSubtype ;
} MKextHeader ;
typedef struct {
UINT32 PlistOffset ;
UINT32 PlistCompressedSize ;
UINT32 PlistFullSize ;
UINT32 PlistModifiedSeconds ;
UINT32 BinaryOffset ;
UINT32 BinaryCompressedSize ;
UINT32 BinaryFullSize ;
UINT32 BinaryModifiedSeconds ;
} MKextFile ;
# define MKEXT_MAGIC 0x54584b4d
# define MKEXT_SIGNATURE 0x58534f4d
# define MKEXT_VERSION_1 0x00800001
2020-05-01 18:26:28 +02:00
int LOADER_ENTRY : : is_mkext_v1 ( UINT8 * drvPtr )
2019-12-31 18:44:47 +01:00
{
2020-09-07 00:19:48 +02:00
_DeviceTreeBuffer * dtb = ( _DeviceTreeBuffer * ) ( ( ( UINT8 * ) drvPtr ) + sizeof ( DTProperty ) ) ;
2019-12-27 17:01:27 +01:00
MKextHeader * mkext_ptr = ( MKextHeader * ) ( UINTN ) ( dtb - > paddr ) ;
2019-12-27 13:54:58 +01:00
2019-12-27 17:01:27 +01:00
if ( mkext_ptr - > Magic = = MKEXT_MAGIC
& & mkext_ptr - > Signature = = MKEXT_SIGNATURE
& & mkext_ptr - > Version = = MKEXT_VERSION_1 ) {
2020-05-01 18:26:28 +02:00
DBG_RT ( " MKext_v1 found at paddr=0x%08x, length=0x%08x \n " , dtb - > paddr , dtb - > length ) ;
2019-12-27 13:54:58 +01:00
return 1 ;
}
return 0 ;
}
2020-05-01 18:26:28 +02:00
void LOADER_ENTRY : : patch_mkext_v1 ( UINT8 * drvPtr )
2019-12-31 18:44:47 +01:00
{
2020-09-07 00:19:48 +02:00
_DeviceTreeBuffer * dtb = ( _DeviceTreeBuffer * ) ( ( ( UINT8 * ) drvPtr ) + sizeof ( DTProperty ) ) ;
2019-12-27 17:01:27 +01:00
MKextHeader * mkext_ptr = ( MKextHeader * ) ( UINTN ) dtb - > paddr ;
2019-12-27 13:54:58 +01:00
2019-12-27 17:01:27 +01:00
UINT32 mkext_len = SwapBytes32 ( mkext_ptr - > Length ) ;
UINT32 mkext_numKexts = SwapBytes32 ( mkext_ptr - > NumKexts ) ;
2019-12-27 13:54:58 +01:00
LIST_ENTRY * Link ;
KEXT_ENTRY * KextEntry ;
if ( ! IsListEmpty ( & gKextList ) ) {
for ( Link = gKextList . ForwardLink ; Link ! = & gKextList ; Link = Link - > ForwardLink ) {
KextEntry = CR ( Link , KEXT_ENTRY , Link , KEXT_SIGNATURE ) ;
2019-12-27 17:01:27 +01:00
MKextFile * mkext_insert = ( MKextFile * ) ( ( UINT8 * ) mkext_ptr + sizeof ( MKextHeader ) + mkext_numKexts * sizeof ( MKextFile ) ) ;
2019-12-27 13:54:58 +01:00
// free some space
2019-12-27 17:01:27 +01:00
CopyMem ( ( UINT8 * ) mkext_insert + sizeof ( MKextFile ) ,
( UINT8 * ) mkext_insert ,
mkext_len - ( sizeof ( MKextHeader ) + mkext_numKexts * sizeof ( MKextFile ) ) ) ;
mkext_len + = sizeof ( MKextFile ) ;
2019-12-27 13:54:58 +01:00
// update the offsets to reflect 0x20 bytes moved above
2019-12-27 17:01:27 +01:00
for ( UINT32 i = 0 ; i < mkext_numKexts ; i + + ) {
MKextFile * kext_base = ( MKextFile * ) ( ( UINT8 * ) mkext_ptr + sizeof ( MKextHeader ) + i * sizeof ( MKextFile ) ) ;
UINT32 plist_offset = SwapBytes32 ( kext_base - > PlistOffset ) + sizeof ( MKextFile ) ;
UINT32 binary_offset = SwapBytes32 ( kext_base - > BinaryOffset ) + sizeof ( MKextFile ) ;
kext_base - > PlistOffset = SwapBytes32 ( plist_offset ) ;
kext_base - > BinaryOffset = SwapBytes32 ( binary_offset ) ;
2019-12-27 13:54:58 +01:00
}
// copy kext data (plist+binary)
2019-12-27 17:01:27 +01:00
CopyMem ( ( UINT8 * ) mkext_ptr + mkext_len ,
( UINT8 * ) ( KextEntry - > kext . paddr + sizeof ( _BooterKextFileInfo ) ) ,
2019-12-27 13:54:58 +01:00
( UINT32 ) ( ( _BooterKextFileInfo * ) ( UINTN ) ( KextEntry - > kext . paddr ) ) - > infoDictLength
+ ( UINT32 ) ( ( _BooterKextFileInfo * ) ( UINTN ) ( KextEntry - > kext . paddr ) ) - > executableLength ) ;
// insert kext offsets
2019-12-27 17:01:27 +01:00
mkext_insert - > PlistOffset = SwapBytes32 ( mkext_len ) ;
2019-12-27 13:54:58 +01:00
mkext_len + = ( ( _BooterKextFileInfo * ) ( UINTN ) ( KextEntry - > kext . paddr ) ) - > infoDictLength ;
2019-12-27 17:01:27 +01:00
mkext_insert - > PlistCompressedSize = 0 ;
mkext_insert - > PlistFullSize = SwapBytes32 ( ( UINT32 ) ( ( _BooterKextFileInfo * ) ( UINTN ) ( KextEntry - > kext . paddr ) ) - > infoDictLength ) ;
mkext_insert - > PlistModifiedSeconds = 0 ;
mkext_insert - > BinaryOffset = SwapBytes32 ( mkext_len ) ;
2019-12-27 13:54:58 +01:00
mkext_len + = ( ( _BooterKextFileInfo * ) ( UINTN ) ( KextEntry - > kext . paddr ) ) - > executableLength ;
2019-12-27 17:01:27 +01:00
mkext_insert - > BinaryCompressedSize = 0 ;
mkext_insert - > BinaryFullSize = SwapBytes32 ( ( UINT32 ) ( ( _BooterKextFileInfo * ) ( UINTN ) ( KextEntry - > kext . paddr ) ) - > executableLength ) ;
mkext_insert - > BinaryModifiedSeconds = 0 ;
2019-12-27 13:54:58 +01:00
mkext_numKexts + + ;
// update the header
2019-12-27 17:01:27 +01:00
mkext_ptr - > Length = SwapBytes32 ( mkext_len ) ;
mkext_ptr - > NumKexts = SwapBytes32 ( mkext_numKexts ) ;
2019-12-27 13:54:58 +01:00
2019-12-27 17:01:27 +01:00
// update the checksum
mkext_ptr - > Adler32 = SwapBytes32 ( Adler32 ( ( UINT8 * ) mkext_ptr + 0x10 , mkext_len - 0x10 ) ) ;
2019-12-27 13:54:58 +01:00
2019-12-27 17:01:27 +01:00
// update the memory-map reference
2019-12-27 13:54:58 +01:00
dtb - > length = mkext_len ;
}
}
}
2020-07-20 10:52:36 +02:00
# endif
2019-12-27 13:54:58 +01:00
2019-09-03 11:58:42 +02:00
////////////////////
// OnExitBootServices
////////////////////
2022-03-06 07:42:49 +01:00
#if 0
2020-05-01 18:26:28 +02:00
EFI_STATUS LOADER_ENTRY : : InjectKexts ( IN UINT32 deviceTreeP , IN UINT32 * deviceTreeLength )
2019-09-03 11:58:42 +02:00
{
2019-12-18 19:41:07 +01:00
UINT8 * dtEntry = ( UINT8 * ) ( UINTN ) deviceTreeP ;
UINTN dtLen = ( UINTN ) * deviceTreeLength ;
2019-09-03 11:58:42 +02:00
2019-12-18 19:41:07 +01:00
DTEntry platformEntry ;
DTEntry memmapEntry ;
2019-09-03 11:58:42 +02:00
CHAR8 * ptr ;
2019-12-18 19:41:07 +01:00
OpaqueDTPropertyIterator OPropIter ;
2019-09-03 11:58:42 +02:00
DTPropertyIterator iter = & OPropIter ;
2020-09-07 00:19:48 +02:00
DTProperty * prop = NULL ;
2019-09-03 11:58:42 +02:00
2019-12-18 19:41:07 +01:00
UINT8 * infoPtr = 0 ;
UINT8 * extraPtr = 0 ;
UINT8 * drvPtr = 0 ;
UINTN offset = 0 ;
2019-09-03 11:58:42 +02:00
2019-12-18 19:41:07 +01:00
UINTN KextBase = 0 ;
_DeviceTreeBuffer * mm ;
_BooterKextFileInfo * drvinfo ;
2019-09-03 11:58:42 +02:00
2019-12-18 19:41:07 +01:00
UINTN Index ;
2019-09-03 11:58:42 +02:00
2020-05-01 18:26:28 +02:00
DBG_RT ( " \n InjectKexts: " ) ;
2020-07-20 10:52:36 +02:00
DBG ( " \n InjectKexts: " ) ;
2021-02-06 18:16:46 +01:00
if ( gKextList . size ( ) = = 0 ) {
2020-05-01 18:26:28 +02:00
DBG_RT ( " no kexts to inject. \n Pausing 5 secs ... \n " ) ;
2020-08-11 14:43:53 +02:00
if ( KernelAndKextPatches . KPDebug ) {
2019-09-03 11:58:42 +02:00
gBS - > Stall ( 5000000 ) ;
}
return EFI_NOT_FOUND ;
}
2021-02-06 18:16:46 +01:00
DBG_RT ( " %zu kexts ... \n " , gKextList . size ( ) ) ;
2019-09-03 11:58:42 +02:00
// kextsBase = Desc->PhysicalStart + (((UINTN) Desc->NumberOfPages) * EFI_PAGE_SIZE);
// kextsPages = EFI_SIZE_TO_PAGES(kext.length);
// Status = gBS->AllocatePages(AllocateAddress, EfiLoaderData, kextsPages, &kextsBase);
// if (EFI_ERROR(Status)) { MsgLog("Kext inject: could not allocate memory\n"); return Status; }
// Desc->NumberOfPages += kextsPages;
2020-10-03 19:02:31 +02:00
// CopyMem((void*)kextsBase, (void*)(UINTN)kext.paddr, kext.length);
2019-09-03 11:58:42 +02:00
// drvinfo = (_BooterKextFileInfo*) kextsBase;
// drvinfo->infoDictPhysAddr += (UINT32)kextsBase;
// drvinfo->executablePhysAddr += (UINT32)kextsBase;
// drvinfo->bundlePathPhysAddr += (UINT32)kextsBase;
2019-12-18 18:34:26 +01:00
DTInit ( dtEntry , deviceTreeLength ) ;
2019-12-18 19:41:07 +01:00
if ( ! EFI_ERROR ( DTLookupEntry ( NULL , " /chosen/memory-map " , & memmapEntry ) ) ) {
if ( ! EFI_ERROR ( DTCreatePropertyIterator ( memmapEntry , iter ) ) ) {
while ( ! EFI_ERROR ( DTIterateProperties ( iter , & ptr ) ) ) {
prop = iter - > CurrentProperty ;
2019-09-03 11:58:42 +02:00
drvPtr = ( UINT8 * ) prop ;
2020-05-16 21:30:29 +02:00
if ( strncmp ( prop - > Name , " Driver- " , 7 ) = = 0 | | strncmp ( prop - > Name , " DriversPackage- " , 15 ) = = 0 ) {
2019-09-03 11:58:42 +02:00
break ;
}
}
}
}
2019-12-18 19:41:07 +01:00
if ( ! EFI_ERROR ( DTLookupEntry ( NULL , " /efi/platform " , & platformEntry ) ) ) {
if ( ! EFI_ERROR ( DTCreatePropertyIterator ( platformEntry , iter ) ) ) {
while ( ! EFI_ERROR ( DTIterateProperties ( iter , & ptr ) ) ) {
prop = iter - > CurrentProperty ;
2020-05-16 21:30:29 +02:00
if ( strncmp ( prop - > Name , " mm_extra " , 8 ) = = 0 ) {
2019-12-18 19:41:07 +01:00
infoPtr = ( UINT8 * ) prop ;
2019-09-03 11:58:42 +02:00
}
2020-05-16 21:30:29 +02:00
if ( strncmp ( prop - > Name , " extra " , 5 ) = = 0 ) {
2019-12-18 19:41:07 +01:00
extraPtr = ( UINT8 * ) prop ;
2019-09-03 11:58:42 +02:00
}
}
}
}
if ( drvPtr = = 0 | | infoPtr = = 0 | | extraPtr = = 0 | | drvPtr > infoPtr | | drvPtr > extraPtr | | infoPtr > extraPtr ) {
2020-03-28 07:36:07 +01:00
printf ( " \n Invalid device tree for kext injection \n " ) ;
2019-09-03 11:58:42 +02:00
gBS - > Stall ( 5000000 ) ;
return EFI_INVALID_PARAMETER ;
}
// make space for memory map entries
2019-12-18 19:41:07 +01:00
platformEntry - > NumProperties - = 2 ;
2020-09-07 00:19:48 +02:00
offset = sizeof ( DTProperty ) + ( ( DTProperty * ) infoPtr ) - > Length ;
2019-09-03 11:58:42 +02:00
CopyMem ( drvPtr + offset , drvPtr , infoPtr - drvPtr ) ;
// make space behind device tree
// platformEntry->nProperties--;
2020-09-07 00:19:48 +02:00
offset = sizeof ( DTProperty ) + ( ( DTProperty * ) extraPtr ) - > Length ;
2019-12-18 18:34:26 +01:00
CopyMem ( extraPtr , extraPtr + offset , dtLen - ( UINTN ) ( extraPtr - dtEntry ) - offset ) ;
2019-09-03 11:58:42 +02:00
* deviceTreeLength - = ( UINT32 ) offset ;
KextBase = RoundPage ( dtEntry + * deviceTreeLength ) ;
2021-02-06 18:16:46 +01:00
if ( gKextList . notEmpty ( ) ) {
2019-09-03 11:58:42 +02:00
Index = 1 ;
2021-02-06 18:16:46 +01:00
for ( size_t gKextListIdx = 0 ; gKextListIdx < gKextList . size ( ) ; + + gKextListIdx ) {
KEXT_ENTRY * KextEntry = & gKextList [ gKextListIdx ] ;
2019-09-03 11:58:42 +02:00
2020-10-03 19:02:31 +02:00
CopyMem ( ( void * ) KextBase , ( void * ) ( UINTN ) KextEntry - > kext . paddr , KextEntry - > kext . length ) ;
2019-09-03 11:58:42 +02:00
drvinfo = ( _BooterKextFileInfo * ) KextBase ;
drvinfo - > infoDictPhysAddr + = ( UINT32 ) KextBase ;
drvinfo - > executablePhysAddr + = ( UINT32 ) KextBase ;
drvinfo - > bundlePathPhysAddr + = ( UINT32 ) KextBase ;
2019-12-18 19:41:07 +01:00
memmapEntry - > NumProperties + + ;
2020-09-07 00:19:48 +02:00
prop = ( ( DTProperty * ) drvPtr ) ;
2019-12-18 19:41:07 +01:00
prop - > Length = sizeof ( _DeviceTreeBuffer ) ;
2020-09-07 00:19:48 +02:00
mm = ( _DeviceTreeBuffer * ) ( ( ( UINT8 * ) prop ) + sizeof ( DTProperty ) ) ;
2019-09-03 11:58:42 +02:00
mm - > paddr = ( UINT32 ) KextBase ;
mm - > length = KextEntry - > kext . length ;
2020-04-10 15:52:49 +02:00
snprintf ( prop - > Name , 31 , " Driver-%X " , ( UINT32 ) KextBase ) ;
2019-09-03 11:58:42 +02:00
2020-09-07 00:19:48 +02:00
drvPtr + = sizeof ( DTProperty ) + sizeof ( _DeviceTreeBuffer ) ;
2019-09-03 11:58:42 +02:00
KextBase = RoundPage ( KextBase + KextEntry - > kext . length ) ;
2020-07-20 10:52:36 +02:00
DBG_RT ( " %llu - %s \n " , Index , ( CHAR8 * ) ( UINTN ) drvinfo - > bundlePathPhysAddr ) ;
DBG ( " %llu - %s \n " , Index , ( CHAR8 * ) ( UINTN ) drvinfo - > bundlePathPhysAddr ) ;
2021-04-03 16:42:49 +02:00
if ( GlobalConfig . KextPatchesAllowed ) {
2019-09-03 11:58:42 +02:00
CHAR8 SavedValue ;
CHAR8 * InfoPlist = ( CHAR8 * ) ( UINTN ) drvinfo - > infoDictPhysAddr ;
SavedValue = InfoPlist [ drvinfo - > infoDictLength ] ;
InfoPlist [ drvinfo - > infoDictLength ] = ' \0 ' ;
2020-07-20 10:52:36 +02:00
// KernelAndKextPatcherInit();
2020-08-12 17:15:47 +02:00
for ( size_t i = 0 ; i < KernelAndKextPatches . KextPatches . size ( ) ; i + + ) {
2021-04-06 15:39:55 +02:00
if ( ( KernelAndKextPatches . KextPatches [ i ] . Find . size ( ) > 0 ) & &
2020-08-12 17:15:47 +02:00
( AsciiStrStr ( InfoPlist , KernelAndKextPatches . KextPatches [ i ] . Name . c_str ( ) ) ! = NULL ) ) {
2019-09-03 11:58:42 +02:00
AnyKextPatch (
( UINT8 * ) ( UINTN ) drvinfo - > executablePhysAddr ,
drvinfo - > executableLength ,
InfoPlist ,
drvinfo - > infoDictLength ,
2020-05-01 18:26:28 +02:00
i
2019-09-03 11:58:42 +02:00
) ;
}
}
InfoPlist [ drvinfo - > infoDictLength ] = SavedValue ;
}
Index + + ;
}
}
2020-05-01 18:26:28 +02:00
DBG_RT ( " Done. \n " ) ;
Stall ( 5000000 ) ;
2019-09-03 11:58:42 +02:00
return EFI_SUCCESS ;
}
2022-03-06 07:42:49 +01:00
# endif
2019-09-03 11:58:42 +02:00
////////////////////////////////////
//
// KernelBooterExtensionsPatch to load extra kexts besides kernelcache
//
//
// Snow Leopard i386
2020-05-02 18:00:31 +02:00
const UINT8 KBESnowSearchEXT_i386 [ ] = { 0xE8 , 0xED , 0xF9 , 0xFF , 0xFF , 0xEB , 0x08 , 0x89 , 0x1C , 0x24 } ;
const UINT8 KBESnowReplaceEXT_i386 [ ] = { 0xE8 , 0xED , 0xF9 , 0xFF , 0xFF , 0x90 , 0x90 , 0x89 , 0x1C , 0x24 } ;
2019-09-03 11:58:42 +02:00
// Snow Leopard X64
2020-05-02 18:00:31 +02:00
const UINT8 KBESnowSearchEXT_X64 [ ] = { 0xE8 , 0x5A , 0xFB , 0xFF , 0xFF , 0xEB , 0x08 , 0x48 , 0x89 , 0xDF } ;
const UINT8 KBESnowReplaceEXT_X64 [ ] = { 0xE8 , 0x5A , 0xFB , 0xFF , 0xFF , 0x90 , 0x90 , 0x48 , 0x89 , 0xDF } ;
2019-09-03 11:58:42 +02:00
// Lion i386
2020-05-02 18:00:31 +02:00
const UINT8 KBELionSearchEXT_i386 [ ] = { 0xE8 , 0xAA , 0xFB , 0xFF , 0xFF , 0xEB , 0x08 , 0x89 , 0x34 , 0x24 } ;
const UINT8 KBELionReplaceEXT_i386 [ ] = { 0xE8 , 0xAA , 0xFB , 0xFF , 0xFF , 0x90 , 0x90 , 0x89 , 0x34 , 0x24 } ;
2019-09-03 11:58:42 +02:00
// Lion X64
2020-05-02 18:00:31 +02:00
const UINT8 KBELionSearchEXT_X64 [ ] = { 0xE8 , 0x0C , 0xFD , 0xFF , 0xFF , 0xEB , 0x08 , 0x48 , 0x89 , 0xDF } ;
const UINT8 KBELionReplaceEXT_X64 [ ] = { 0xE8 , 0x0C , 0xFD , 0xFF , 0xFF , 0x90 , 0x90 , 0x48 , 0x89 , 0xDF } ;
2019-09-03 11:58:42 +02:00
//
2021-01-31 10:50:23 +01:00
// We can not rely on macOSVersion global variable for OS version detection,
2019-09-03 11:58:42 +02:00
// since in some cases it is not correct (install of ML from Lion, for example).
// So, we'll use "brute-force" method - just try to patch.
// Actually, we'll at least check that if we can find only one instance of code that
// we are planning to patch.
//
// Fully reworked by Sherlocks. 2019.06.23
//
2020-04-29 22:09:59 +02:00
2020-10-03 19:02:31 +02:00
void EFIAPI LOADER_ENTRY : : KernelBooterExtensionsPatch ( )
2019-09-03 11:58:42 +02:00
{
2020-05-15 05:23:33 +02:00
// UINTN Num = 0;
2019-09-03 11:58:42 +02:00
UINTN NumSnow_i386_EXT = 0 ;
UINTN NumSnow_X64_EXT = 0 ;
UINTN NumLion_i386_EXT = 0 ;
UINTN NumLion_X64_EXT = 0 ;
2020-05-11 17:44:00 +02:00
UINTN patchLocation2 = 0 , patchLocation3 = 0 ;
2020-05-02 12:12:53 +02:00
2019-09-03 11:58:42 +02:00
2020-05-01 18:26:28 +02:00
DBG_RT ( " \n Patching kernel for injected kexts... \n " ) ;
2019-09-03 11:58:42 +02:00
if ( is64BitKernel ) {
2020-05-09 09:56:30 +02:00
NumSnow_X64_EXT = SearchAndCount ( KernelData , KERNEL_MAX_SIZE , KBESnowSearchEXT_X64 , sizeof ( KBESnowSearchEXT_X64 ) ) ;
NumLion_X64_EXT = SearchAndCount ( KernelData , KERNEL_MAX_SIZE , KBELionSearchEXT_X64 , sizeof ( KBELionSearchEXT_X64 ) ) ;
2019-09-03 11:58:42 +02:00
} else {
2020-05-09 09:56:30 +02:00
NumSnow_i386_EXT = SearchAndCount ( KernelData , KERNEL_MAX_SIZE , KBESnowSearchEXT_i386 , sizeof ( KBESnowSearchEXT_i386 ) ) ;
NumLion_i386_EXT = SearchAndCount ( KernelData , KERNEL_MAX_SIZE , KBELionSearchEXT_i386 , sizeof ( KBELionSearchEXT_i386 ) ) ;
2019-09-03 11:58:42 +02:00
}
if ( NumSnow_i386_EXT + NumSnow_X64_EXT + NumLion_i386_EXT + NumLion_X64_EXT > 1 ) {
// more then one pattern found - we do not know what to do with it
// and we'll skipp it
2020-05-02 12:12:53 +02:00
// DBG_RT("\nERROR patching kernel for injected kexts:\nmultiple patterns found (Snowi386: %llu, SnowX64: %llu, Lioni386: %llu, LionX64: %llu) - skipping patching!\n", NumSnow_i386_EXT, NumSnow_X64_EXT, NumLion_i386_EXT, NumLion_X64_EXT);
2020-05-15 05:23:33 +02:00
// Stall(10000000);
2019-09-03 11:58:42 +02:00
return ;
}
// X64
if ( is64BitKernel ) {
if ( NumSnow_X64_EXT = = 1 ) {
2020-05-15 05:23:33 +02:00
/*Num=*/ SearchAndReplace ( KernelData , KERNEL_MAX_SIZE , KBESnowSearchEXT_X64 , sizeof ( KBESnowSearchEXT_X64 ) , KBESnowReplaceEXT_X64 , 1 ) ;
2020-05-02 12:12:53 +02:00
// DBG_RT("==> kernel Snow Leopard X64: %llu replaces done.\n", Num);
2019-09-03 11:58:42 +02:00
} else if ( NumLion_X64_EXT = = 1 ) {
2020-05-15 05:23:33 +02:00
/*Num=*/ SearchAndReplace ( KernelData , KERNEL_MAX_SIZE , KBELionSearchEXT_X64 , sizeof ( KBELionSearchEXT_X64 ) , KBELionReplaceEXT_X64 , 1 ) ;
2020-05-02 12:12:53 +02:00
// DBG_RT("==> kernel Lion X64: %llu replaces done.\n", Num);
2019-09-03 11:58:42 +02:00
} else {
// EXT - load extra kexts besides kernelcache.
2020-04-29 10:06:44 +02:00
# if OLD_EXTRA_KEXT_PATCH
2020-04-29 22:09:59 +02:00
UINT32 patchLocation1 = 0 ;
2020-05-02 12:12:53 +02:00
for ( UINT32 i = 0 ; i < 0x1000000 ; i + + ) {
2019-09-03 11:58:42 +02:00
// 01 00 31 FF BE 14 00 05
if ( Kernel [ i + 0 ] = = 0x01 & & Kernel [ i + 1 ] = = 0x00 & & Kernel [ i + 2 ] = = 0x31 & &
Kernel [ i + 3 ] = = 0xFF & & Kernel [ i + 4 ] = = 0xBE & & Kernel [ i + 5 ] = = 0x14 & &
Kernel [ i + 6 ] = = 0x00 & & Kernel [ i + 7 ] = = 0x05 ) {
2020-05-01 18:26:28 +02:00
DBG_RT ( " ==> found EXT Base (10.8 - recent macOS) \n " ) ;
2020-05-02 12:12:53 +02:00
for ( UINT32 y = i ; y < 0x1000000 ; y + + ) {
2019-09-03 11:58:42 +02:00
// E8 XX 00 00 00 EB XX XX
if ( Kernel [ y + 0 ] = = 0xE8 & & Kernel [ y + 2 ] = = 0x00 & & Kernel [ y + 3 ] = = 0x00 & &
Kernel [ y + 4 ] = = 0x00 & & Kernel [ y + 5 ] = = 0xEB ) {
//(Kernel[y+7] == 0x48 || Kernel[y+7] == 0xE8)) { // 48:10.8-10.9/E8:10.10+
patchLocation1 = y ;
2020-05-01 18:26:28 +02:00
DBG_RT ( " ==> found EXT (10.8 - recent macOS) at 0x%08x \n " , patchLocation1 ) ;
2019-09-03 11:58:42 +02:00
break ;
}
}
break ;
}
}
if ( ! patchLocation1 ) {
2020-05-01 18:26:28 +02:00
DBG_RT ( " ==> can't find EXT (10.8 - recent macOS), kernel patch aborted. \n " ) ;
2019-09-03 11:58:42 +02:00
gBS - > Stall ( 3000000 ) ;
}
if ( patchLocation1 ) {
2020-05-01 18:26:28 +02:00
DBG_RT ( " ==> patched EXT (10.8 - recent macOS) location=%x \n " , patchLocation1 ) ;
2019-09-03 11:58:42 +02:00
for ( i = 5 ; i < 7 ; i + + ) {
// E8 XX 00 00 00 EB XX XX
// E8 XX 00 00 00 90 90 XX
Kernel [ patchLocation1 + i ] = 0x90 ;
}
}
2020-04-29 10:06:44 +02:00
# else
2020-05-02 05:38:38 +02:00
//Capitan
// procedure at 950950, len = fffffffffffff3f0
// proclen=256, end=256 startLen=0
// found start at 0x950950
// found pattern: 1
// address: 0095098b
// bytes:eb05
2020-07-17 05:28:17 +02:00
// BS
// E8 ?? 00 00 00 EB 05 E8 -->
// E8 ?? 00 00 00 90 90 E8.
2020-05-02 05:38:38 +02:00
2020-08-12 17:15:47 +02:00
UINTN procLocation = searchProc ( " readStartupExtensions " _XS8 ) ;
2020-05-02 05:38:38 +02:00
const UINT8 findJmp [ ] = { 0xEB , 0x05 } ;
const UINT8 patchJmp [ ] = { 0x90 , 0x90 } ;
2020-07-17 05:28:17 +02:00
DBG ( " ==> readStartupExtensions at %llx \n " , procLocation ) ;
2020-05-09 09:56:30 +02:00
if ( ! SearchAndReplace ( & KernelData [ procLocation ] , 0x100 , findJmp , 2 , patchJmp , 1 ) ) {
2020-07-17 05:28:17 +02:00
DBG ( " load kexts not patched \n " ) ;
for ( UINTN j = procLocation + 0x2b ; j < procLocation + 0x4b ; + + j ) {
DBG ( " %02x " , KernelData [ j ] ) ;
}
DBG ( " \n " ) ;
2020-05-02 15:30:33 +02:00
// Stall(10000000);
2020-06-24 06:20:45 +02:00
//second attempt brute force for 10.16
2020-07-20 10:52:36 +02:00
// const UINT8 findJmp2[] = {0xEB, 0x05, 0xE8, 0x7D, 0x03};
// const UINT8 patchJmp2[] = {0x90, 0x90, 0xE8, 0x7D, 0x03};
// if (!SearchAndReplace(&KernelData[0], KERNEL_MAX_SIZE, findJmp2, 5, patchJmp2, 1)) {
// DBG("load kexts 2 not patched\n");
// } else {
// DBG("load kexts 2 patched !!!\n");
// }
2020-05-01 18:26:28 +02:00
} else {
2020-07-20 10:52:36 +02:00
DBG ( " load kexts patched \n " ) ;
2020-05-02 12:12:53 +02:00
// for (UINTN j=procLocation+0x3b; j<procLocation+0x5b; ++j) {
// DBG_RT("%02x", Kernel[j]);
// }
2020-05-02 15:30:33 +02:00
// DBG_RT("\n");
2020-04-29 17:07:10 +02:00
}
2020-05-02 15:30:33 +02:00
Stall ( 12000000 ) ;
2020-04-29 10:06:44 +02:00
# endif
2019-09-03 11:58:42 +02:00
// SIP - bypass kext check by System Integrity Protection.
2020-05-01 18:26:28 +02:00
//the pattern found in __ZN6OSKext14loadExecutableEv: // OSKext::loadExecutable()
// iMac2017:Catalina sergey$ ./FindMask kernel -p loadExecutable -e 1000 -f 488500740048000048,FFFF00FF00FF0000FF
// descending
// procedure at 7a1ed0, len = ffffffffffff4b50
// proclen=4096, end=4096 startLen=0
// found start at 0x7a1ed0
// found pattern: 1
// address: 007a29b7
// bytes:4885c074224889c348
2020-07-17 05:28:17 +02:00
2020-05-01 18:26:28 +02:00
2020-05-02 05:38:38 +02:00
//Capitan
// ffffff800084897b 4885DB test rbx, rbx
// ffffff800084897e 7470 je 0xffffff80008489f0 -> patch to not jump
// 7412 jmp ffffff8000848992
// ; Basic Block Input Regs: rbx - Killed Regs: rax rdi
// ffffff8000848980 488B03 mov rax, qword [ds:rbx]
// ffffff8000848983 4889DF mov rdi, rbx
// ffffff8000848986 FF5028 call qword [ds:rax+0x28]
// ffffff8000848989 483B1DE04F2B00 cmp rbx, qword [ds:0xffffff8000afd970]
// ffffff8000848990 745E je 0xffffff80008489f0 -> patch to not jump
// ; Basic Block Input Regs: r13 - Killed Regs: rax rbx rdi
// ffffff8000848992 498B4500 mov rax, qword [ds:r13+0x0]
// procedure at 6487f0, len = 7250
// proclen=512, end=512 startLen=0
// found start at 0x6487f0
// found pattern: 1
// address: 0064897b
// bytes:4885db7470
# if OLD_EXTRA_KEXT_PATCH
2020-05-02 12:12:53 +02:00
for ( UINT32 i = 0 ; i < 0x1000000 ; i + + ) {
2019-09-03 11:58:42 +02:00
// 45 31 FF 41 XX 01 00 00 DC 48
if ( Kernel [ i + 0 ] = = 0x45 & & Kernel [ i + 1 ] = = 0x31 & & Kernel [ i + 3 ] = = 0x41 & &
//(Kernel[i+4] == 0xBF || Kernel[i+4] == 0xBE) && // BF:10.11/BE:10.12+
Kernel [ i + 5 ] = = 0x01 & & Kernel [ i + 6 ] = = 0x00 & & Kernel [ i + 7 ] = = 0x00 & &
Kernel [ i + 8 ] = = 0xDC & & Kernel [ i + 9 ] = = 0x48 ) {
2020-05-02 05:38:38 +02:00
DBG_RT ( " ==> found loadExecutable (10.11 - recent macOS) at %x \n " , i ) ;
2020-05-02 12:12:53 +02:00
for ( UINT32 y = i ; y < 0x100000 ; y + + ) {
2019-09-03 11:58:42 +02:00
// 48 85 XX 74 XX 48 XX XX 48
if ( Kernel [ y + 0 ] = = 0x48 & & Kernel [ y + 1 ] = = 0x85 & & Kernel [ y + 3 ] = = 0x74 & &
Kernel [ y + 5 ] = = 0x48 & & Kernel [ y + 8 ] = = 0x48 ) {
patchLocation2 = y ;
2020-05-01 18:26:28 +02:00
DBG_RT ( " ==> found SIP (10.11 - 10.14) at 0x%08x \n " , patchLocation2 ) ;
2019-09-03 11:58:42 +02:00
break ;
2020-05-01 18:26:28 +02:00
// 00 85 C0 0F 84 XX 00 00 00 49 //???? - not found in Catalina
2019-09-03 11:58:42 +02:00
} else if ( Kernel [ y + 0 ] = = 0x00 & & Kernel [ y + 1 ] = = 0x85 & & Kernel [ y + 2 ] = = 0xC0 & &
Kernel [ y + 3 ] = = 0x0F & & Kernel [ y + 4 ] = = 0x84 & & Kernel [ y + 9 ] = = 0x49 ) {
patchLocation2 = y ;
2020-05-01 18:26:28 +02:00
DBG_RT ( " ==> found SIP (10.15 - recent macOS) at 0x%08x \n " , patchLocation2 ) ;
2019-09-03 11:58:42 +02:00
break ;
}
}
break ;
}
}
2020-05-02 05:38:38 +02:00
# else
2020-07-17 05:28:17 +02:00
// BS
// E8 ?? ?? ?? 00 85 C0 0F 84 ?? 00 00 00 49 8B 45 -->
// E8 ?? ?? ?? 00 85 C0 90 90 90 90 90 90 49 8B 45.
2020-05-02 12:12:53 +02:00
const UINT8 find3 [ ] = { 0x48 , 0x85 , 00 , 0x74 , 00 , 0x48 , 00 , 00 , 0x48 } ;
const UINT8 mask3 [ ] = { 0xFF , 0xFF , 00 , 0xFF , 00 , 0xFF , 00 , 00 , 0xFF } ;
2020-05-02 05:38:38 +02:00
# endif
2020-05-02 12:12:53 +02:00
2020-05-03 06:10:02 +02:00
//ffffff80009a2267 488D35970D2400 lea rsi, qword [ds:0xffffff8000be3005] ; "com.apple.private.security.kext-management"
//ffffff80009a226e E89D780D00 call _IOTaskHasEntitlement
//ffffff80009a2273 85C0 test eax, eax =>change to eb06 -> jmp .+6
//ffffff80009a2275 0F843C010000 je 0xffffff80009a23b7
//ffffff80009a227b
2020-08-12 17:15:47 +02:00
UINTN taskLocation = searchProc ( " IOTaskHasEntitlement " _XS8 ) ;
procLocation = searchProc ( " loadExecutable " _XS8 ) ;
2020-07-06 06:04:01 +02:00
patchLocation2 = FindMemMask ( & KernelData [ procLocation ] , 0x500 , find3 , sizeof ( find3 ) , mask3 , sizeof ( mask3 ) ) ;
2020-07-18 20:06:10 +02:00
DBG ( " IOTaskHasEntitlement at 0x%llx, loadExecutable at 0x%llx \n " , taskLocation , procLocation ) ;
DBG ( " find3 at 0x%llx \n " , patchLocation2 ) ;
2020-10-12 13:51:08 +02:00
if ( patchLocation2 ! = MAX_UINTN ) {
2020-05-03 06:10:02 +02:00
DBG_RT ( " => patch SIP applied \n " ) ;
patchLocation2 + = procLocation ;
2020-05-09 09:56:30 +02:00
KernelData [ patchLocation2 + 3 ] = 0xEB ;
if ( KernelData [ patchLocation2 + 4 ] = = 0x6C ) {
KernelData [ patchLocation2 + 4 ] = 0x15 ;
2020-05-03 06:10:02 +02:00
} else {
2020-05-09 09:56:30 +02:00
KernelData [ patchLocation2 + 4 ] = 0x12 ;
2020-05-03 06:10:02 +02:00
}
} else {
2020-07-17 05:28:17 +02:00
patchLocation2 = FindRelative32 ( KernelData , procLocation , 0x700 , taskLocation ) ;
2020-07-18 20:06:10 +02:00
DBG ( " else search relative at 0x%llx \n " , patchLocation2 ) ;
2020-05-03 06:10:02 +02:00
if ( patchLocation2 ! = 0 ) {
DBG_RT ( " => patch2 SIP applied \n " ) ;
2020-05-09 09:56:30 +02:00
KernelData [ patchLocation2 ] = 0xEB ;
KernelData [ patchLocation2 + 1 ] = 0x06 ;
2020-06-24 06:20:45 +02:00
} else {
DBG_RT ( " => patch2 SIP not applied \n " ) ;
2020-07-17 05:28:17 +02:00
const UINT8 find7 [ ] = { 0xE8 , 0x00 , 0x00 , 0x00 , 0x00 , 0x85 , 0xC0 , 0x0F , 0x84 , 0xFF , 0x00 , 0x00 , 0x00 , 0x49 , 0x8B , 0x45 } ;
const UINT8 mask7 [ ] = { 0xFF , 0x00 , 0x00 , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ;
patchLocation2 = FindMemMask ( & KernelData [ 0 ] , KERNEL_MAX_SIZE , find7 , sizeof ( find7 ) , mask7 , sizeof ( mask7 ) ) ;
2020-07-18 20:06:10 +02:00
DBG ( " found call to TE at 0x%llx \n " , patchLocation2 ) ;
2020-07-17 05:28:17 +02:00
KernelData [ 0 + patchLocation2 + 7 ] = 0xEB ;
KernelData [ 0 + patchLocation2 + 8 ] = 0x04 ;
2020-05-02 12:12:53 +02:00
}
2019-09-03 11:58:42 +02:00
}
2020-05-03 06:10:02 +02:00
Stall ( 10000000 ) ;
2020-05-02 12:12:53 +02:00
/*
2020-05-02 05:38:38 +02:00
//Capitan: 48 85 db 74 70 48 8b 03 48
2019-09-03 11:58:42 +02:00
if ( patchLocation2 ) {
2020-05-02 12:12:53 +02:00
if ( taskFound ) {
UINT8 jmp = Kernel [ patchLocation2 + 4 ] ;
const UINT8 repl4 [ ] = { 0xB8 , 0x01 , 0x00 , 0x00 , 0x00 , 0xEB } ;
CopyMem ( & Kernel [ patchLocation2 ] , repl4 , sizeof ( repl4 ) ) ;
Kernel [ patchLocation2 + 6 ] = jmp ;
DBG_RT ( " => mojave SIP applyed \n " ) ;
} else
2019-09-03 11:58:42 +02:00
if ( Kernel [ patchLocation2 + 0 ] = = 0x48 & & Kernel [ patchLocation2 + 1 ] = = 0x85 ) {
2020-05-02 05:38:38 +02:00
Kernel [ patchLocation2 + 3 ] = 0xEB ;
2020-05-01 18:26:28 +02:00
DBG_RT ( " ==> patched SIP (10.11 - 10.14) \n " ) ;
2019-09-03 11:58:42 +02:00
if ( Kernel [ patchLocation2 + 4 ] = = 0x6C ) {
// 48 85 XX 74 6C 48 XX XX 48
// 48 85 XX EB 15 48 XX XX 48
Kernel [ patchLocation2 + 4 ] = 0x15 ; // 10.14.4-10.14.6
} else {
// 48 85 XX 74 XX 48 XX XX 48
// 48 85 XX EB 12 48 XX XX 48
Kernel [ patchLocation2 + 4 ] = 0x12 ; // 10.11-10.14.3
}
// PMheart
} else if ( Kernel [ patchLocation2 + 0 ] = = 0x00 & & Kernel [ patchLocation2 + 1 ] = = 0x85 ) {
2020-05-01 18:26:28 +02:00
DBG_RT ( " ==> patched SIP (10.15 - recent macOS) \n " ) ;
2019-09-03 11:58:42 +02:00
for ( i = 3 ; i < 9 ; i + + ) {
// 00 85 C0 0F 84 XX 00 00 00 49
// 00 85 C0 90 90 90 90 90 90 49
Kernel [ patchLocation2 + i ] = 0x90 ;
}
}
}
2020-05-01 18:26:28 +02:00
Stall ( 9000000 ) ;
2020-05-02 12:12:53 +02:00
*/
//Slice - hope this patch useful for some system that I have no.
2019-09-03 11:58:42 +02:00
// KxldUnmap by vit9696
// Avoid race condition in OSKext::removeKextBootstrap when using booter kexts without keepsyms=1.
2020-08-12 17:15:47 +02:00
procLocation = searchProc ( " removeKextBootstrap " _XS8 ) ;
2020-05-02 12:12:53 +02:00
const UINT8 find5 [ ] = { 0x00 , 0x0F , 0x85 , 00 , 00 , 0x00 , 0x00 , 0x48 } ;
const UINT8 mask5 [ ] = { 0xFF , 0xFF , 0xFF , 00 , 00 , 0xFF , 0xFF , 0xFF } ;
2020-07-20 10:52:36 +02:00
patchLocation3 = FindMemMask ( & KernelData [ procLocation ] , 0x300 , find5 , sizeof ( find5 ) , mask5 , sizeof ( mask5 ) ) ;
2020-07-07 08:19:59 +02:00
DBG ( " removeKextBootstrap at 0x%llx \n " , patchLocation3 ) ;
2020-05-02 12:12:53 +02:00
/*
for ( UINT32 i = 0 ; i < 0x1000000 ; i + + ) {
2019-09-03 11:58:42 +02:00
// 55 48 89 E5 41 57 41 56 41 54 53 //10
// 48 83 EC 30 48 C7 45 B8 XX XX XX //21
// XX XX XX XX XX XX XX XX XX XX XX //32
// XX XX XX XX XX XX XX XX XX XX XX //43
2020-03-23 14:31:04 +01:00
// XX XX XX XX XX XX XX XX XX FF XX //54
// XX XX XX XX XX XX XX XX XX FF FF //65
2019-09-03 11:58:42 +02:00
if ( Kernel [ i + 0 ] = = 0x55 & & Kernel [ i + 1 ] = = 0x48 & & Kernel [ i + 2 ] = = 0x89 & &
Kernel [ i + 3 ] = = 0xE5 & & Kernel [ i + 4 ] = = 0x41 & & Kernel [ i + 5 ] = = 0x57 & &
Kernel [ i + 6 ] = = 0x41 & & Kernel [ i + 7 ] = = 0x56 & & Kernel [ i + 8 ] = = 0x41 & &
Kernel [ i + 9 ] = = 0x54 & & Kernel [ i + 10 ] = = 0x53 & & Kernel [ i + 11 ] = = 0x48 & &
Kernel [ i + 12 ] = = 0x83 & & Kernel [ i + 13 ] = = 0xEC & & Kernel [ i + 14 ] = = 0x30 & &
Kernel [ i + 15 ] = = 0x48 & & Kernel [ i + 16 ] = = 0xC7 & & Kernel [ i + 17 ] = = 0x45 & &
2020-03-23 14:31:04 +01:00
Kernel [ i + 18 ] = = 0xB8 & & Kernel [ i + 53 ] = = 0xFF & & Kernel [ i + 64 ] = = 0xFF & & Kernel [ i + 65 ] = = 0xFF ) {
2020-05-01 18:26:28 +02:00
DBG_RT ( " ==> found KxldUnmap Base (10.14 - recent macOS) \n " ) ;
2020-05-02 12:12:53 +02:00
for ( UINT32 y = i ; y < 0x1000000 ; y + + ) {
2019-09-03 11:58:42 +02:00
// 00 0F 85 XX XX 00 00 48
if ( Kernel [ y + 0 ] = = 0x00 & & Kernel [ y + 1 ] = = 0x0F & & Kernel [ y + 2 ] = = 0x85 & &
Kernel [ y + 5 ] = = 0x00 & & Kernel [ y + 6 ] = = 0x00 & & Kernel [ y + 7 ] = = 0x48 ) {
patchLocation3 = y ;
2020-05-01 18:26:28 +02:00
DBG_RT ( " ==> found KxldUnmap (10.14 - recent macOS) at 0x%08x \n " , patchLocation3 ) ;
2019-09-03 11:58:42 +02:00
break ;
}
}
break ;
}
}
2020-05-02 12:12:53 +02:00
*/
2020-07-17 05:28:17 +02:00
//BS
//FF 80 3D ?? ?? ?? 00 00 0F 85 ?? 01 00 00 41 -->
//FF 80 3D ?? ?? ?? 00 00 90 E9 ?? 01 00 00 41.
2020-07-20 10:52:36 +02:00
/*
2020-05-02 12:12:53 +02:00
if ( patchLocation3 = = KERNEL_MAX_SIZE ) {
2020-07-17 05:28:17 +02:00
DBG_RT ( " ==> can't find KxldUnmap (10.14 - 10.15) \n " ) ;
2020-05-01 18:26:28 +02:00
Stall ( 3000000 ) ;
2020-07-17 05:28:17 +02:00
const UINT8 find6 [ ] = { 0xFF , 0x80 , 0x3D , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x0F , 0x85 , 0x00 , 0x01 , 0x00 , 0x00 , 0x41 } ;
const UINT8 mask6 [ ] = { 0xFF , 0xFF , 0xFF , 0x00 , 0x00 , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF } ;
patchLocation3 = FindMemMask ( & KernelData [ 0 ] , KERNEL_MAX_SIZE , find6 , sizeof ( find6 ) , mask6 , sizeof ( mask6 ) ) ;
2020-07-18 20:06:10 +02:00
DBG ( " find mask 6 at 0x%llx \n " , patchLocation3 ) ;
2020-07-17 05:28:17 +02:00
if ( patchLocation3 ! = KERNEL_MAX_SIZE ) {
KernelData [ 0 + patchLocation3 + 8 ] = 0x90 ;
KernelData [ 0 + patchLocation3 + 9 ] = 0xE9 ;
}
2020-05-02 12:12:53 +02:00
} else {
2020-07-20 10:52:36 +02:00
*/
//The patch is not needed for bigsur
2020-10-12 13:51:08 +02:00
if ( patchLocation3 ! = MAX_UINTN ) {
2020-07-20 10:52:36 +02:00
DBG ( " ==> patched KxldUnmap (10.14 - 10.15) \n " ) ;
2019-09-03 11:58:42 +02:00
// 00 0F 85 XX XX 00 00 48
// 00 90 E9 XX XX 00 00 48
2020-05-09 09:56:30 +02:00
KernelData [ procLocation + patchLocation3 + 1 ] = 0x90 ;
KernelData [ procLocation + patchLocation3 + 2 ] = 0xE9 ;
2019-09-03 11:58:42 +02:00
}
}
} else {
// i386
if ( NumSnow_i386_EXT = = 1 ) {
2020-05-15 05:23:33 +02:00
/*Num=*/ SearchAndReplace ( KernelData , KERNEL_MAX_SIZE , KBESnowSearchEXT_i386 , sizeof ( KBESnowSearchEXT_i386 ) , KBESnowReplaceEXT_i386 , 1 ) ;
2020-05-02 12:12:53 +02:00
// DBG_RT("==> kernel Snow Leopard i386: %llu replaces done.\n", Num);
2019-09-03 11:58:42 +02:00
} else if ( NumLion_i386_EXT = = 1 ) {
2020-05-15 05:23:33 +02:00
/*Num=*/ SearchAndReplace ( KernelData , KERNEL_MAX_SIZE , KBELionSearchEXT_i386 , sizeof ( KBELionSearchEXT_i386 ) , KBELionReplaceEXT_i386 , 1 ) ;
2020-05-02 12:12:53 +02:00
// DBG_RT("==> kernel Lion i386: %llu replaces done.\n", Num);
2019-09-03 11:58:42 +02:00
} else {
2020-05-01 18:26:28 +02:00
DBG_RT ( " ==> ERROR: NOT patched - unknown kernel. \n " ) ;
2019-09-03 11:58:42 +02:00
}
}
2020-05-09 09:56:30 +02:00
DBG_RT ( " Pausing 5 secs ... \n " ) ;
Stall ( 5000000 ) ;
2019-09-03 11:58:42 +02:00
}