/**

  funcs for checking decoded kernel in memory
  
  dmazar

**/

#include <Library/UefiLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>

#include "DecodedKernelCheck.h"
#include "AsmFuncs.h"
#include "BootArgs.h"

// monitoring AlocatePages
extern UINT32 gKernelEntry;

typedef struct {
	char			*segname;
	unsigned long	vmaddr;
	long			vmsize;
	long			filesize;
	unsigned long	adler32;
	unsigned char	ssample[8];
	unsigned char	esample[8];
} mySegData_t;
	
	 
//from Chameleon:
// i386:
mySegData_t mySegData[] = { // segment, vmaddr, vmsize, filesize, adler32
        {"__TEXT", 0x200000, 0x568000, 0x568000, 0x9cea7b0b,
            {0xce, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x00},
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
        },
        {"__DATA", 0x800000, 0x83000, 0x41000, 0x28829ec4,
            {0x28, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74},
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
        },
        {"__INITGDT", 0x106000, 0x1000, 0x1000, 0xfad20d6d,
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
        },
        {"__INITPT", 0x100000, 0x6000, 0x6000, 0xa58b95ca,
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
            {0x83, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00}
        },
        {"__DESC", 0x883000, 0x3000, 0x3000, 0x26fe0f95,
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
        },
        {"__VECTORS", 0x886000, 0x1000, 0x1000, 0xc6ae0a5c,
            {0x14, 0x3c, 0x2c, 0x00, 0x29, 0x3c, 0x2c, 0x00},
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
        },
        {"__HIB", 0x108000, 0x7000, 0x7000, 0x99a0f193,
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
        },
        {"__SLEEP", 0x107000, 0x1000, 0x1000, 0x10000001,
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
        },
        {"__KLD", 0x887000, 0x13000, 0x13000, 0xf6d84329,
            {0x55, 0x89, 0xe5, 0x56, 0x83, 0xec, 0x04, 0xb8},
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
        },
        {"__PRELINK_TEXT", 0x932000, 0x1564000, 0x1564000, 0x874e72cf,
            {0xce, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x00},
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
        },
        {"__PRELINK_INFO", 0x1e96000, 0x158000, 0x1575b8, 0x483406a5,
            {0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x3c, 0x6b},
            {0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x00}
        },
        {"__LINKEDIT", 0x89a000, 0x97428, 0x97428, 0x7802b8c4,
            {0x04, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x00, 0x00},
            {0x72, 0x65, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x00}
        },
};
int mySegDataNum = 12;
//unsigned long rentry = 0x2c3db0;
unsigned long rentryx64 = 0x2b8000;
unsigned long rentry = 0x2b8000;
unsigned char rentrySample[8] = {0x66, 0x8c, 0xdb, 0x8e, 0xc3, 0x89, 0xc5, 0x89};
// i386
// end from Chameleon

/*
 * Adler32 from Chameleon
*/

unsigned long OSSwapHostToBigInt32(unsigned long int32) {
	return int32;
}

#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);

unsigned long Adler32(unsigned char *buf, long len)
{
	unsigned long s1 = 1; // adler & 0xffff;
	unsigned long s2 = 0; // (adler >> 16) & 0xffff;
	unsigned long result;
	int k;
	
	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
	return OSSwapHostToBigInt32(result);
}




void PrintSample(unsigned char *sample, int size) {
	int i;
	for (i = 0; i < size; i++) {
		Print(L" %02x", *sample);
		sample++;
	}
}


EFI_STATUS
EFIAPI
CheckDecodedSegment (
	mySegData_t				*sData
	)
{
	EFI_STATUS				Status;
	//UINTN					i;
	unsigned char			*p;
	unsigned long			adler32;
	long					size;
	
	Status = EFI_SUCCESS;
	
	p = (UINT8 *)(UINTN) (sData->vmaddr + gRelocBase);
	size = sData->vmsize > sData->filesize ? sData->filesize : sData->vmsize;
	adler32 = Adler32(p, size);
	
	if (adler32 != sData->adler32) {
		Status = EFI_CRC_ERROR;
	}
	
	Print(L"Segment: %a, vmaddr=%lx, vmsize=%lx, filesize=%lx, adler32=%lx, our adler=%lx\n",
		sData->segname, sData->vmaddr, sData->vmsize, sData->filesize, sData->adler32, adler32);
	//Print(L"cham ssample:"); PrintSample(sData->ssample, 8); Print(L"\n");
	//Print(L"uefi ssample:"); PrintSample(p, 8); Print(L"\n");
	
	return Status;
}


EFI_STATUS
EFIAPI
CheckDecodedKernel (
		VOID
	)
{
	EFI_STATUS				Status;
	EFI_STATUS				segStatus;
	int						i;
	unsigned char			*p;
	
	Status = EFI_SUCCESS;
	
	for (i = 0; i < mySegDataNum; i++) {
		segStatus = CheckDecodedSegment(&mySegData[i]);
		if (EFI_ERROR (segStatus)) {
			Status = segStatus;
		}
	}
	
	Print(L"rentry %lx:\ncham sample:", rentry); PrintSample(rentrySample, 8); Print(L"\n");
	p = (UINT8 *)(UINTN) (rentry + gRelocBase);
	Print(L"uefi sample:"); PrintSample(p, 8); Print(L"\n");
	
	Print(L"CheckDecodedKernel Status=%r\n");
	return Status;
}



VOID
EFIAPI
DumpStack (
		UINT64				RSP
	)
{
	unsigned char			*p;
	
	Print(L"DumpStack RSP=%lx\n", RSP);
	
	p = (UINT8 *)(UINTN) RSP;
	PrintSample(p, 64);
	Print(L"\n");
	
	return;
}
