VbError_t nvstorage_write_disk(const uint8_t *buf)
{
	VbDiskInfo *internal_disk;
	uint8_t *block_buf;

	if (get_internal_disk(&internal_disk))
		return 1;

	if (get_nvcxt_block_of_disk(internal_disk, &block_buf))
		return 1;

	memcpy(block_buf, buf, VBNV_BLOCK_SIZE);

	if (VbExDiskWrite(internal_disk->handle,
				CHROMEOS_VBNVCONTEXT_LBA, 1, block_buf)) {
		VBDEBUG("Failed to write internal disk!\n");
		VbExFree(block_buf);
		return 1;
	}

	VbExFree(block_buf);

#ifdef CONFIG_EXYNOS5
	/*
	 * XXX(chrome-os-partner:10415): On Exynos, reliable write operations
	 * need write busy time; so add a delay here.  In the long run, we
	 * should avoid using eMMC as VbNvContext storage media.
	 */
	mdelay(1);
#endif

	return VBERROR_SUCCESS;
}
Example #2
0
/**
 * Write any changes for the GPT data back to the drive, then free the buffers.
 *
 * Returns 0 if successful, 1 if error.
 */
int WriteAndFreeGptData(VbExDiskHandle_t disk_handle, GptData *gptdata)
{
	int legacy = 0;
	GptHeader *header = (GptHeader *)gptdata->primary_header;
	uint64_t entries_bytes = header->number_of_entries
				* header->size_of_entry;
	uint64_t entries_sectors = entries_bytes / gptdata->sector_bytes;
	int ret = 1;

	/*
	 * TODO(namnguyen): Preserve padding between primary GPT header and
	 * its entries.
	 */
	uint64_t entries_lba = GPT_PMBR_SECTORS + GPT_HEADER_SECTORS;
	if (gptdata->primary_header) {
		GptHeader *h = (GptHeader *)(gptdata->primary_header);
		entries_lba = h->entries_lba;

		/*
		 * Avoid even looking at this data if we don't need to. We
		 * may in fact not have read it from disk if the read failed,
		 * and this avoids a valgrind complaint.
		 */
		if (gptdata->modified) {
			legacy = !Memcmp(h->signature, GPT_HEADER_SIGNATURE2,
					GPT_HEADER_SIGNATURE_SIZE);
		}
		if (gptdata->modified & GPT_MODIFIED_HEADER1) {
			if (legacy) {
				VBDEBUG(("Not updating GPT header 1: "
					 "legacy mode is enabled.\n"));
			} else {
				VBDEBUG(("Updating GPT header 1\n"));
				if (0 != VbExDiskWrite(disk_handle, 1, 1,
						       gptdata->primary_header))
					goto fail;
			}
		}
	}

	if (gptdata->primary_entries) {
		if (gptdata->modified & GPT_MODIFIED_ENTRIES1) {
			if (legacy) {
				VBDEBUG(("Not updating GPT entries 1: "
					 "legacy mode is enabled.\n"));
			} else {
				VBDEBUG(("Updating GPT entries 1\n"));
				if (0 != VbExDiskWrite(disk_handle, entries_lba,
						entries_sectors,
						gptdata->primary_entries))
					goto fail;
			}
		}
	}

	entries_lba = (gptdata->gpt_drive_sectors - entries_sectors -
		GPT_HEADER_SECTORS);
	if (gptdata->secondary_header) {
		GptHeader *h = (GptHeader *)(gptdata->secondary_header);
		entries_lba = h->entries_lba;
		if (gptdata->modified & GPT_MODIFIED_HEADER2) {
			VBDEBUG(("Updating GPT entries 2\n"));
			if (0 != VbExDiskWrite(disk_handle,
					       gptdata->gpt_drive_sectors - 1, 1,
					       gptdata->secondary_header))
				goto fail;
		}
	}

	if (gptdata->secondary_entries) {
		if (gptdata->modified & GPT_MODIFIED_ENTRIES2) {
			VBDEBUG(("Updating GPT header 2\n"));
			if (0 != VbExDiskWrite(disk_handle,
				entries_lba, entries_sectors,
				gptdata->secondary_entries))
				goto fail;
		}
	}

	ret = 0;

fail:
	/* Avoid leaking memory on disk write failure */
	if (gptdata->primary_header)
		VbExFree(gptdata->primary_header);
	if (gptdata->primary_entries)
		VbExFree(gptdata->primary_entries);
	if (gptdata->secondary_entries)
		VbExFree(gptdata->secondary_entries);
	if (gptdata->secondary_header)
		VbExFree(gptdata->secondary_header);

	/* Success */
	return ret;
}
static int do_vbexport_test_diskrw(cmd_tbl_t *cmdtp, int flag,
		int argc, char * const argv[])
{
	int ret = 0;
	VbDiskInfo *disk_info;
	VbExDiskHandle_t handle;
	uint32_t disk_count, test_lba_count, buf_byte_count, i;
	uint8_t *original_buf, *target_buf, *verify_buf;
	uint64_t t0, t1;

	switch (argc) {
	case 1:  /* if no argument given, use the default lba count */
		test_lba_count = DEFAULT_TEST_LBA_COUNT;
		break;
	case 2:  /* use argument */
		test_lba_count = simple_strtoul(argv[1], NULL, 10);
		if (!test_lba_count) {
			VbExDebug("The first argument is not a number!\n");
			return cmd_usage(cmdtp);
		}
		break;
	default:
		return cmd_usage(cmdtp);
	}

	/* We perform read/write operations on the first internal disk. */
	if (VbExDiskGetInfo(&disk_info, &disk_count, VB_DISK_FLAG_FIXED) ||
			disk_count == 0) {
		VbExDebug("No internal disk found!\n");
		return 1;
	}
	handle = disk_info[0].handle;
	buf_byte_count = disk_info[0].bytes_per_lba * test_lba_count;
	VbExDiskFreeInfo(disk_info, handle);

	/* Allocate the buffer and fill the target test pattern. */
	original_buf = VbExMalloc(buf_byte_count);
	target_buf = VbExMalloc(buf_byte_count);
	verify_buf = VbExMalloc(buf_byte_count);

	/* Fill the target test pattern. */
	for (i = 0; i < buf_byte_count; i++)
		target_buf[i] = i & 0xff;

	t0 = VbExGetTimer();
	if (VbExDiskRead(handle, TEST_LBA_START, test_lba_count,
			original_buf)) {
		VbExDebug("Failed to read disk.\n");
		goto out;
	}
	t1 = VbExGetTimer();
	VbExDebug("test_diskrw: disk_read, lba_count: %u, time: %llu\n",
			test_lba_count, t1 - t0);

	t0 = VbExGetTimer();
	ret = VbExDiskWrite(handle, TEST_LBA_START, test_lba_count, target_buf);
	t1 = VbExGetTimer();
	VbExDebug("test_diskrw: disk_write, lba_count: %u, time: %llu\n",
			test_lba_count, t1 - t0);

	if (ret) {
		VbExDebug("Failed to write disk.\n");
		ret = 1;
	} else {
		/* Read back and verify the data. */
		VbExDiskRead(handle, TEST_LBA_START, test_lba_count,
				verify_buf);
		if (memcmp(target_buf, verify_buf, buf_byte_count) != 0) {
			VbExDebug("Verify failed. The target data wrote "
					"wrong.\n");
			ret = 1;
		}
	}

	/* Write the original data back. */
	if (VbExDiskWrite(handle, TEST_LBA_START, test_lba_count,
			original_buf)) {
		VbExDebug("Failed to write the original data back. The disk "
				"may now be corrupt.\n");
	}

out:
	VbExDiskFreeInfo(disk_info, NULL);

	VbExFree(original_buf);
	VbExFree(target_buf);
	VbExFree(verify_buf);

	if (ret == 0)
		VbExDebug("Read and write disk test SUCCESS.\n");

	return ret;
}