Beispiel #1
0
bool MtkFormat::isValid(const unsigned char *data, std::size_t size)
{
    // We have to parse the boot image so we can search for the mtk headers

    // Find Android header
    std::size_t headerIndex;
    if (!findHeader(data, size, 512, &headerIndex)) {
        return false;
    }

    // Check for header size overflow
    if (size < headerIndex + sizeof(BootImageHeader)) {
        return false;
    }

    // Read the Android boot image header
    auto hdr = reinterpret_cast<const BootImageHeader *>(&data[headerIndex]);

    uint32_t pos = 0;

    // Skip header
    pos += headerIndex;
    pos += sizeof(BootImageHeader);
    pos += skipPadding(sizeof(BootImageHeader), hdr->page_size);

    // Check for kernel size overflow
    if (pos + hdr->kernel_size > size) {
        return false;
    }
    if (hdr->kernel_size >= sizeof(MtkHeader)) {
        auto mtkHdr = reinterpret_cast<const MtkHeader *>(&data[pos]);
        if (std::memcmp(mtkHdr->magic, MTK_MAGIC, MTK_MAGIC_SIZE) == 0) {
            return true;
        }
    }
    // Skip kernel image
    pos += hdr->kernel_size;
    pos += skipPadding(hdr->kernel_size, hdr->page_size);

    // Check for ramdisk size overflow
    if (pos + hdr->ramdisk_size > size) {
        return false;
    }
    if (hdr->ramdisk_size >= sizeof(MtkHeader)) {
        auto mtkHdr = reinterpret_cast<const MtkHeader *>(&data[pos]);
        if (std::memcmp(mtkHdr->magic, MTK_MAGIC, MTK_MAGIC_SIZE) == 0) {
            return true;
        }
    }
    // Skip ramdisk image
    pos += hdr->ramdisk_size;
    pos += skipPadding(hdr->ramdisk_size, hdr->page_size);

    // There's no need to check any other images since the mtk header should
    // only exist for the kernel and ramdisk
    return false;
}
Beispiel #2
0
/*
 * Skip the current member of the archive so that we are positioned
 * to tbe beginning of the next member's header (or end of file).
 * Returns TRUE on success.
 */
static BOOL
skipMember(const Archive * arch)
{
	if (lseek(arch->fd, arch->size, SEEK_CUR) == -1)
	{
		fprintf(stderr, "Can't skip past archive member: %s\n",
			strerror(errno));

		return FALSE;
	}

	return skipPadding(arch->fd, arch->pad);
}
Beispiel #3
0
/*
 * Copy all of the file data from the archive to the specified
 * open file.  Returns TRUE on success.
 */
static BOOL
writeFile(const Archive * arch, int outfd)
{
	unsigned char	buf[BUF_SIZE];
	off_t		n;

	n = arch->size;

	while (n > 0)
	{
		ssize_t cc;

		cc = read((int)arch->fd, (void *)buf, (size_t)MIN(n,(int) sizeof(buf)));

		if (cc == -1)
		{
			fprintf(stderr, "Error reading archive member: %s\n",
				strerror(errno));

			return FALSE;
		}

		if (cc == 0)
		{
			fprintf(stderr, "Unexpected end of file\n");

			return FALSE;
		}

		if (fullWrite(outfd,(const char *)buf,(int) cc) < 0)
		{
			fprintf(stderr, "Write error: %s\n", strerror(errno));

			return FALSE;
		}

		n -= cc;
	}

	if (!skipPadding(arch->fd, arch->pad))
		return FALSE;

	return TRUE;
}
bool AndroidFormat::loadImage(const unsigned char *data, std::size_t size)
{
    std::size_t headerIndex;
    if (!findHeader(data, size, 512, &headerIndex)) {
        LOGE("Failed to find Android header in boot image");
        return false;
    }

    LOGD("Found Android boot image header at: %" PRIzu, headerIndex);

    if (!loadHeader(data, size, headerIndex)) {
        return false;
    }

    uint32_t pos = 0;

    // Save kernel image
    pos += headerIndex;
    pos += sizeof(BootImageHeader);
    pos += skipPadding(sizeof(BootImageHeader), mI10e->pageSize);
    if (pos + mI10e->hdrKernelSize > size) {
        LOGE("Kernel image exceeds boot image size by %" PRIzu " bytes",
             pos + mI10e->hdrKernelSize - size);
        return false;
    }

    mI10e->kernelImage.assign(data + pos, data + pos + mI10e->hdrKernelSize);

    // Save ramdisk image
    pos += mI10e->hdrKernelSize;
    pos += skipPadding(mI10e->hdrKernelSize, mI10e->pageSize);
    if (pos + mI10e->hdrRamdiskSize > size) {
        LOGE("Ramdisk image exceeds boot image size by %" PRIzu " bytes",
             pos + mI10e->hdrRamdiskSize - size);
        return false;
    }

    mI10e->ramdiskImage.assign(data + pos, data + pos + mI10e->hdrRamdiskSize);

    // Save second bootloader image
    pos += mI10e->hdrRamdiskSize;
    pos += skipPadding(mI10e->hdrRamdiskSize, mI10e->pageSize);
    if (pos + mI10e->hdrSecondSize > size) {
        LOGE("Second bootloader image exceeds boot image size by %" PRIzu " bytes",
             pos + mI10e->hdrSecondSize - size);
        return false;
    }

    // The second bootloader may not exist
    if (mI10e->hdrSecondSize > 0) {
        mI10e->secondImage.assign(data + pos, data + pos + mI10e->hdrSecondSize);
    } else {
        mI10e->secondImage.clear();
    }

    // Save device tree image
    pos += mI10e->hdrSecondSize;
    pos += skipPadding(mI10e->hdrSecondSize, mI10e->pageSize);
    if (pos + mI10e->hdrDtSize > size) {
        std::size_t diff = pos + mI10e->hdrDtSize - size;

        LOGE("WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING");
        LOGE("THIS BOOT IMAGE MAY NO LONGER BE BOOTABLE. YOU HAVE BEEN WARNED");
        LOGE("Device tree image exceeds boot image size by %" PRIzu
             " bytes and HAS BEEN TRUNCATED", diff);
        LOGE("WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING");

        mI10e->dtImage.assign(data + pos, data + pos + mI10e->hdrDtSize - diff);
    } else {
        mI10e->dtImage.assign(data + pos, data + pos + mI10e->hdrDtSize);
    }

    // The device tree image may not exist as well
    if (mI10e->hdrDtSize == 0) {
        mI10e->dtImage.clear();
    }

    pos += mI10e->hdrDtSize;
    pos += skipPadding(mI10e->hdrDtSize, mI10e->pageSize);

    return true;
}
bool AndroidFormat::createImage(std::vector<unsigned char> *dataOut)
{
    BootImageHeader hdr;
    std::vector<unsigned char> data;

    memset(&hdr, 0, sizeof(BootImageHeader));

    // Set header metadata fields
    memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
    hdr.kernel_size = mI10e->hdrKernelSize;
    hdr.kernel_addr = mI10e->kernelAddr;
    hdr.ramdisk_size = mI10e->hdrRamdiskSize;
    hdr.ramdisk_addr = mI10e->ramdiskAddr;
    hdr.second_size = mI10e->hdrSecondSize;
    hdr.second_addr = mI10e->secondAddr;
    hdr.tags_addr = mI10e->tagsAddr;
    hdr.page_size = mI10e->pageSize;
    hdr.dt_size = mI10e->hdrDtSize;
    hdr.unused = mI10e->hdrUnused;
    // -1 for null byte
    std::strcpy(reinterpret_cast<char *>(hdr.name),
                mI10e->boardName.substr(0, BOOT_NAME_SIZE - 1).c_str());
    std::strcpy(reinterpret_cast<char *>(hdr.cmdline),
                mI10e->cmdline.substr(0, BOOT_ARGS_SIZE - 1).c_str());

    // Update SHA1
    updateSha1Hash(&hdr, mI10e);

    switch (mI10e->pageSize) {
    case 2048:
    case 4096:
    case 8192:
    case 16384:
    case 32768:
    case 65536:
    case 131072:
        break;
    default:
        LOGE("Invalid page size: %u", mI10e->pageSize);
        return false;
    }

    // Header
    unsigned char *hdrBegin = reinterpret_cast<unsigned char *>(&hdr);
    data.insert(data.end(), hdrBegin, hdrBegin + sizeof(BootImageHeader));

    // Padding
    uint32_t paddingSize = skipPadding(sizeof(BootImageHeader), hdr.page_size);
    data.insert(data.end(), paddingSize, 0);

    // Kernel image
    data.insert(data.end(),
                mI10e->kernelImage.begin(),
                mI10e->kernelImage.end());

    // More padding
    paddingSize = skipPadding(mI10e->kernelImage.size(), hdr.page_size);
    data.insert(data.end(), paddingSize, 0);

    // Ramdisk image
    data.insert(data.end(),
                mI10e->ramdiskImage.begin(),
                mI10e->ramdiskImage.end());

    // Even more padding
    paddingSize = skipPadding(mI10e->ramdiskImage.size(), hdr.page_size);
    data.insert(data.end(), paddingSize, 0);

    // Second bootloader image
    if (!mI10e->secondImage.empty()) {
        data.insert(data.end(),
                    mI10e->secondImage.begin(),
                    mI10e->secondImage.end());

        // Enough padding already!
        paddingSize = skipPadding(mI10e->secondImage.size(), hdr.page_size);
        data.insert(data.end(), paddingSize, 0);
    }

    // Device tree image
    if (!mI10e->dtImage.empty()) {
        data.insert(data.end(),
                    mI10e->dtImage.begin(),
                    mI10e->dtImage.end());

        // Last bit of padding (I hope)
        paddingSize = skipPadding(mI10e->dtImage.size(), hdr.page_size);
        data.insert(data.end(), paddingSize, 0);
    }

    dataOut->swap(data);
    return true;
}
Beispiel #6
0
/*
 * Deserialize a HeapTuple's data from a byte-array.
 *
 * This code is based on the binary input handling functions in copy.c.
 */
HeapTuple
DeserializeTuple(SerTupInfo * pSerInfo, StringInfo serialTup)
{
	MemoryContext oldCtxt;
	TupleDesc	tupdesc;
	HeapTuple	htup;
	int			natts;
	SerAttrInfo *attrInfo;
	uint32		attr_size;

	int			i;
	StringInfoData attr_data;
	bool		fHandled;

	AssertArg(pSerInfo != NULL);
	AssertArg(serialTup != NULL);

	tupdesc = pSerInfo->tupdesc;
	natts = tupdesc->natts;

	/*
	 * Flip to our tuple-serialization memory-context, to speed up memory
	 * reclamation operations.
	 */
	AssertState(s_tupSerMemCtxt != NULL);
	oldCtxt = MemoryContextSwitchTo(s_tupSerMemCtxt);

	/* Receive nulls character-array. */
	pq_copymsgbytes(serialTup, pSerInfo->nulls, natts);
	skipPadding(serialTup);

	/* Deserialize the non-NULL attributes of this tuple */
	initStringInfo(&attr_data);
	for (i = 0; i < natts; ++i)
	{
		attrInfo = pSerInfo->myinfo + i;

		if (pSerInfo->nulls[i])	/* NULL field. */
		{
			pSerInfo->values[i] = (Datum) 0;
			continue;
		}

		/*
		 * Assume that the data's output will be handled by the special IO
		 * code, and if not then we can handle it the slow way.
		 */
		fHandled = true;
		switch (attrInfo->atttypid)
		{
			case INT4OID:
				pSerInfo->values[i] = Int32GetDatum(stringInfoGetInt32(serialTup));
				break;

			case CHAROID:
				pSerInfo->values[i] = CharGetDatum(pq_getmsgbyte(serialTup));
				skipPadding(serialTup);
				break;

			case BPCHAROID:
			case VARCHAROID:
			case INT2VECTOROID: /* postgres serialization logic broken, use our own */
			case OIDVECTOROID: /* postgres serialization logic broken, use our own */
			case ANYARRAYOID:
			{
				text	   *pText;
				int			textSize;

				textSize = stringInfoGetInt32(serialTup);

#ifdef TUPSER_SCRATCH_SPACE
				if (textSize + VARHDRSZ <= attrInfo->varlen_scratch_size)
					pText = (text *) attrInfo->pv_varlen_scratch;
				else
					pText = (text *) palloc(textSize + VARHDRSZ);
#else
				pText = (text *) palloc(textSize + VARHDRSZ);
#endif

				SET_VARSIZE(pText, textSize + VARHDRSZ);
				pq_copymsgbytes(serialTup, VARDATA(pText), textSize);
				skipPadding(serialTup);
				pSerInfo->values[i] = PointerGetDatum(pText);
				break;
			}

			case DATEOID:
			{
				/*
				 * TODO:  I would LIKE to do something more efficient, but
				 * DateADT is not strictly limited to 4 bytes by its
				 * definition.
				 */
				DateADT date;

				pq_copymsgbytes(serialTup, (char *) &date, sizeof(DateADT));
				skipPadding(serialTup);
				pSerInfo->values[i] = DateADTGetDatum(date);
				break;
			}

			case NUMERICOID:
			{
				/*
				 * Treat the numeric as a varlena variable, and just push
				 * the whole shebang to the output-buffer.	We don't care
				 * about the guts of the numeric.
				 */
				Numeric		num;
				int			numSize;

				numSize = stringInfoGetInt32(serialTup);

#ifdef TUPSER_SCRATCH_SPACE
				if (numSize + VARHDRSZ <= attrInfo->varlen_scratch_size)
					num = (Numeric) attrInfo->pv_varlen_scratch;
				else
					num = (Numeric) palloc(numSize + VARHDRSZ);
#else
				num = (Numeric) palloc(numSize + VARHDRSZ);
#endif

				SET_VARSIZE(num, numSize + VARHDRSZ);
				pq_copymsgbytes(serialTup, VARDATA(num), numSize);
				skipPadding(serialTup);
				pSerInfo->values[i] = NumericGetDatum(num);
				break;
			}

			case ACLITEMOID:
			{
				int		aclSize, k, cnt;
				char		*inputstring, *starsfree;

				aclSize = stringInfoGetInt32(serialTup);
				inputstring = (char*) palloc(aclSize  + 1);
				starsfree = (char*) palloc(aclSize  + 1);
				cnt = 0;
	

				pq_copymsgbytes(serialTup, inputstring, aclSize);
				skipPadding(serialTup);
				inputstring[aclSize] = '\0';
				for(k=0; k<aclSize; k++)
				{					
					if( inputstring[k] != '*')
					{
						starsfree[cnt] = inputstring[k];
						cnt++;
					}
				}
				starsfree[cnt] = '\0';

				pSerInfo->values[i] = DirectFunctionCall1(aclitemin, CStringGetDatum(starsfree));
				pfree(inputstring);
				break;
			}

			case 210:
			{
				int 		strsize;
				char		*smgrstr;

				strsize = stringInfoGetInt32(serialTup);
				smgrstr = (char*) palloc(strsize + 1);
				pq_copymsgbytes(serialTup, smgrstr, strsize);
				skipPadding(serialTup);
				smgrstr[strsize] = '\0';

				pSerInfo->values[i] = DirectFunctionCall1(smgrin, CStringGetDatum(smgrstr));
				break;
			}
			default:
				fHandled = false;
		}

		if (fHandled)
			continue;

		attr_size = stringInfoGetInt32(serialTup);

		/* reset attr_data to empty, and load raw data into it */

		attr_data.len = 0;
		attr_data.data[0] = '\0';
		attr_data.cursor = 0;

		appendBinaryStringInfo(&attr_data,
							   pq_getmsgbytes(serialTup, attr_size), attr_size);
		skipPadding(serialTup);

		/* Call the attribute type's binary input converter. */
		if (attrInfo->recv_finfo.fn_nargs == 1)
			pSerInfo->values[i] = FunctionCall1(&attrInfo->recv_finfo,
												PointerGetDatum(&attr_data));
		else if (attrInfo->recv_finfo.fn_nargs == 2)
			pSerInfo->values[i] = FunctionCall2(&attrInfo->recv_finfo,
												PointerGetDatum(&attr_data),
												ObjectIdGetDatum(attrInfo->recv_typio_param));
		else if (attrInfo->recv_finfo.fn_nargs == 3)
			pSerInfo->values[i] = FunctionCall3(&attrInfo->recv_finfo,
												PointerGetDatum(&attr_data),
												ObjectIdGetDatum(attrInfo->recv_typio_param),
												Int32GetDatum(tupdesc->attrs[i]->atttypmod) );  
		else
		{
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
					 errmsg("Conversion function takes %d args",attrInfo->recv_finfo.fn_nargs)));
		}

		/* Trouble if it didn't eat the whole buffer */
		if (attr_data.cursor != attr_data.len)
		{
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
					 errmsg("incorrect binary data format")));
		}
	}

	/*
	 * Construct the tuple from the Datums and nulls values.  NOTE:  Switch
	 * out of our temporary context before we form the tuple!
	 */
	MemoryContextSwitchTo(oldCtxt);

	htup = heap_form_tuple(tupdesc, pSerInfo->values, pSerInfo->nulls);

	MemoryContextReset(s_tupSerMemCtxt);

	/* All done.  Return the result. */
	return htup;
}
Beispiel #7
0
/*
 * Read the first member of the archive file and check whether it
 * is a special one, and if so, handle it.  If the first member is
 * a normal archive member, then set up to rescan it for the next
 * readNormalMember call.  Returns TRUE on success.
 */
static BOOL
readSpecialMember(Archive * arch)
{
	struct ar_hdr	hdr;

	/*
	 * 1. Read a header H.  Fail if impossible.
	 */
	if (!readMember(arch, &hdr))
		return FALSE;

	/*
	 * 2. If H is a symbol table, ditch it.
	 * Fail if impossible.
	 */
	if ((strncmp(hdr.ar_name, "/ ", 2) == 0) ||
		(strncmp(hdr.ar_name, "__.SYMTAB       ",
			sizeof(hdr.ar_name)) == 0))
	{
		if (!canonicalize(arch, &hdr))
			return FALSE;

		return skipMember(arch);
	}

	/*
	 * 3. If H is a SysV longname table, read it into ARCH.
	 */
	if (strncmp(hdr.ar_name, "//", 2) == 0)
	{
		unsigned long	len;
		ssize_t		cc;

		if (!getNumber(hdr.ar_size, 10, sizeof(hdr.ar_size), &len))
		{
			fprintf(stderr, "Invalid name-table size\n");

			return FALSE;
		}

		arch->nameTable = malloc(len + 1);

		if (!arch->nameTable)
		{
			fprintf(stderr, "Out of memory\n");

			return FALSE;
		}

		cc = read(arch->fd, arch->nameTable, len);

		if (cc == -1)
		{
			fprintf(stderr, "Error reading name-table: %s\n",
				strerror(errno));

			return FALSE;
		}

		if (cc != (ssize_t) len)
		{
			fprintf(stderr,
				"Unexpected end of file in name-table\n");

			return FALSE;
		}

		arch->nameTable[len] = 0;

		return skipPadding(arch->fd, len % 2);
	}

	/*
	 * 4. We read a normal header.
	 * Canonicalize it, and mark it as needing rescanning.
	 */
	arch->rescan = TRUE;

	return canonicalize(arch, &hdr);
}
bool BumpFormat::isValid(const unsigned char *data, std::size_t size)
{
    // We have to parse the boot image to find the end so we can compare the
    // trailing bytes to the bump magic string

    std::size_t headerIndex;
    if (!findHeader(data, size, 512, &headerIndex)) {
        return false;
    }

    // Check for header size overflow
    if (size < headerIndex + sizeof(BootImageHeader)) {
        return false;
    }

    // Read the Android boot image header
    auto hdr = reinterpret_cast<const BootImageHeader *>(&data[headerIndex]);

    uint32_t pos = 0;

    // Skip header
    pos += headerIndex;
    pos += sizeof(BootImageHeader);
    pos += skipPadding(sizeof(BootImageHeader), hdr->page_size);

    // Check for kernel size overflow
    if (pos + hdr->kernel_size > size) {
        return false;
    }
    // Skip kernel image
    pos += hdr->kernel_size;
    pos += skipPadding(hdr->kernel_size, hdr->page_size);

    // Check for ramdisk size overflow
    if (pos + hdr->ramdisk_size > size) {
        return false;
    }
    // Skip ramdisk image
    pos += hdr->ramdisk_size;
    pos += skipPadding(hdr->ramdisk_size, hdr->page_size);

    // Check for second bootloader size overflow
    if (pos + hdr->second_size > size) {
        return false;
    }
    // Skip second bootloader image
    pos += hdr->second_size;
    pos += skipPadding(hdr->second_size, hdr->page_size);

    // Check for device tree image size overflow
    if (pos + hdr->dt_size > size) {
        return false;
    }
    // Skip device tree image
    pos += hdr->dt_size;
    pos += skipPadding(hdr->dt_size, hdr->page_size);

    // We are now at the end of the boot image, so check for the bump magic
    return (size >= pos + BUMP_MAGIC_SIZE)
            && std::memcmp(data + pos, BUMP_MAGIC, BUMP_MAGIC_SIZE) == 0;
}
Beispiel #9
0
/*
 * Deserialize a HeapTuple's data from a byte-array.
 *
 * This code is based on the binary input handling functions in copy.c.
 */
HeapTuple
DeserializeTuple(SerTupInfo * pSerInfo, StringInfo serialTup)
{
	MemoryContext oldCtxt;
	TupleDesc	tupdesc;
	HeapTuple	htup;
	int			natts;
	SerAttrInfo *attrInfo;
	int			i;

	AssertArg(pSerInfo != NULL);
	AssertArg(serialTup != NULL);

	tupdesc = pSerInfo->tupdesc;
	natts = tupdesc->natts;

	/*
	 * Flip to our tuple-serialization memory-context, to speed up memory
	 * reclamation operations.
	 */
	AssertState(s_tupSerMemCtxt != NULL);
	oldCtxt = MemoryContextSwitchTo(s_tupSerMemCtxt);

	/* Receive nulls character-array. */
	pq_copymsgbytes(serialTup, pSerInfo->nulls, natts);
	skipPadding(serialTup);

	/* Deserialize the non-NULL attributes of this tuple */
	for (i = 0; i < natts; ++i)
	{
		attrInfo = pSerInfo->myinfo + i;

		if (pSerInfo->nulls[i])	/* NULL field. */
		{
			pSerInfo->values[i] = (Datum) 0;
			continue;
		}

		if (attrInfo->typlen == -1)
		{
			int32		sz;
			struct varlena *p;

			/* Read length first */
			pq_copymsgbytes(serialTup, (char *) &sz, sizeof(int32));
			if (sz < 0)
				elog(ERROR, "invalid length received for a varlen Datum");

			p = palloc(sz + VARHDRSZ);

			pq_copymsgbytes(serialTup, VARDATA(p), sz);
			SET_VARSIZE(p, sz + VARHDRSZ);

			pSerInfo->values[i] = PointerGetDatum(p);
		}
		else if (attrInfo->typlen == -2)
		{
			int32		sz;
			char	   *p;

			/* CString, with terminating '\0' included */

			/* Read length first */
			pq_copymsgbytes(serialTup, (char *) &sz, sizeof(int32));
			if (sz < 0)
				elog(ERROR, "invalid length received for a CString");

			p = palloc(sz + VARHDRSZ);

			/* Then data */
			pq_copymsgbytes(serialTup, p, sz);

			pSerInfo->values[i] = CStringGetDatum(p);
		}
		else if (attrInfo->typbyval)
		{
			/* Read a whole Datum */

			pq_copymsgbytes(serialTup, (char *) &(pSerInfo->values[i]), sizeof(Datum));
		}
		else
		{
			/* fixed width, pass-by-ref */
			char	   *p = palloc(attrInfo->typlen);

			pq_copymsgbytes(serialTup, p, attrInfo->typlen);

			pSerInfo->values[i] = PointerGetDatum(p);
		}
	}

	/*
	 * Construct the tuple from the Datums and nulls values.  NOTE:  Switch
	 * out of our temporary context before we form the tuple!
	 */
	MemoryContextSwitchTo(oldCtxt);

	htup = heap_form_tuple(tupdesc, pSerInfo->values, pSerInfo->nulls);

	MemoryContextReset(s_tupSerMemCtxt);

	/* Trouble if it didn't eat the whole buffer */
	if (serialTup->cursor != serialTup->len)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
				 errmsg("incorrect binary data format")));

	/* All done.  Return the result. */
	return htup;
}
Beispiel #10
0
bool MtkFormat::createImage(std::vector<unsigned char> *dataOut)
{
    BootImageHeader hdr;
    std::vector<unsigned char> data;

    memset(&hdr, 0, sizeof(BootImageHeader));

    bool hasKernelHdr = !mI10e->mtkKernelHdr.empty();
    bool hasRamdiskHdr = !mI10e->mtkRamdiskHdr.empty();

    // Check header sizes
    if (hasKernelHdr && mI10e->mtkKernelHdr.size() != sizeof(MtkHeader)) {
        LOGE("Expected %" PRIzu " byte kernel MTK header, but have %" PRIzu " bytes",
             sizeof(MtkHeader), mI10e->mtkKernelHdr.size());
        return false;
    }
    if (hasRamdiskHdr && mI10e->mtkRamdiskHdr.size() != sizeof(MtkHeader)) {
        LOGE("Expected %" PRIzu " byte ramdisk MTK header, but have %" PRIzu " bytes",
             sizeof(MtkHeader), mI10e->mtkRamdiskHdr.size());
        return false;
    }

    std::size_t kernelSize =
            mI10e->kernelImage.size() + mI10e->mtkKernelHdr.size();
    std::size_t ramdiskSize =
            mI10e->ramdiskImage.size() + mI10e->mtkRamdiskHdr.size();

    MtkHeader mtkKernelHdr;
    MtkHeader mtkRamdiskHdr;
    if (hasKernelHdr) {
        std::memcpy(&mtkKernelHdr, mI10e->mtkKernelHdr.data(), sizeof(MtkHeader));
        mtkKernelHdr.size = mI10e->kernelImage.size();
    }
    if (hasRamdiskHdr) {
        std::memcpy(&mtkRamdiskHdr, mI10e->mtkRamdiskHdr.data(), sizeof(MtkHeader));
        mtkRamdiskHdr.size = mI10e->ramdiskImage.size();
    }

    // Set header metadata fields
    memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
    hdr.kernel_size = kernelSize;
    hdr.kernel_addr = mI10e->kernelAddr;
    hdr.ramdisk_size = ramdiskSize;
    hdr.ramdisk_addr = mI10e->ramdiskAddr;
    hdr.second_size = mI10e->hdrSecondSize;
    hdr.second_addr = mI10e->secondAddr;
    hdr.tags_addr = mI10e->tagsAddr;
    hdr.page_size = mI10e->pageSize;
    hdr.dt_size = mI10e->hdrDtSize;
    hdr.unused = mI10e->hdrUnused;
    // -1 for null byte
    std::strcpy(reinterpret_cast<char *>(hdr.name),
                mI10e->boardName.substr(0, BOOT_NAME_SIZE - 1).c_str());
    std::strcpy(reinterpret_cast<char *>(hdr.cmdline),
                mI10e->cmdline.substr(0, BOOT_ARGS_SIZE - 1).c_str());

    // Update SHA1
    updateSha1Hash(&hdr, mI10e,
                   hasKernelHdr ? &mtkKernelHdr : nullptr,
                   hasRamdiskHdr ? &mtkRamdiskHdr : nullptr,
                   kernelSize, ramdiskSize);

    switch (mI10e->pageSize) {
    case 2048:
    case 4096:
    case 8192:
    case 16384:
    case 32768:
    case 65536:
    case 131072:
        break;
    default:
        LOGE("Invalid page size: %u", mI10e->pageSize);
        return false;
    }

    // Header
    unsigned char *hdrBegin = reinterpret_cast<unsigned char *>(&hdr);
    data.insert(data.end(), hdrBegin, hdrBegin + sizeof(BootImageHeader));

    // Padding
    uint32_t paddingSize = skipPadding(sizeof(BootImageHeader), hdr.page_size);
    data.insert(data.end(), paddingSize, 0);

    // Kernel image
    if (hasKernelHdr) {
        data.insert(data.end(),
                    reinterpret_cast<const unsigned char *>(&mtkKernelHdr),
                    reinterpret_cast<const unsigned char *>(&mtkKernelHdr) + sizeof(MtkHeader));
    }
    data.insert(data.end(),
                mI10e->kernelImage.begin(),
                mI10e->kernelImage.end());

    // More padding
    paddingSize = skipPadding(kernelSize, hdr.page_size);
    data.insert(data.end(), paddingSize, 0);

    // Ramdisk image
    if (hasRamdiskHdr) {
        data.insert(data.end(),
                    reinterpret_cast<const unsigned char *>(&mtkRamdiskHdr),
                    reinterpret_cast<const unsigned char *>(&mtkRamdiskHdr) + sizeof(MtkHeader));
    }
    data.insert(data.end(),
                mI10e->ramdiskImage.begin(),
                mI10e->ramdiskImage.end());

    // Even more padding
    paddingSize = skipPadding(ramdiskSize, hdr.page_size);
    data.insert(data.end(), paddingSize, 0);

    // Second bootloader image
    if (!mI10e->secondImage.empty()) {
        data.insert(data.end(),
                    mI10e->secondImage.begin(),
                    mI10e->secondImage.end());

        // Enough padding already!
        paddingSize = skipPadding(mI10e->secondImage.size(), hdr.page_size);
        data.insert(data.end(), paddingSize, 0);
    }

    // Device tree image
    if (!mI10e->dtImage.empty()) {
        data.insert(data.end(),
                    mI10e->dtImage.begin(),
                    mI10e->dtImage.end());

        // Last bit of padding (I hope)
        paddingSize = skipPadding(mI10e->dtImage.size(), hdr.page_size);
        data.insert(data.end(), paddingSize, 0);
    }

    dataOut->swap(data);
    return true;
}