<commit_before>/* Copyright 2013-2015 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <byteswap.h>
#include <stdint.h>
#include <stdbool.h>
#include <getopt.h>
#include <limits.h>
#include <arpa/inet.h>
#include <assert.h>
#include <inttypes.h>

#include <libflash/libflash.h>
#include <libflash/libffs.h>
#include <libflash/blocklevel.h>
#include <common/arch_flash.h>
#include "progress.h"

#define __aligned(x)			__attribute__((aligned(x)))

struct flash_details {
	struct blocklevel_device *bl;
	int need_relock;
	const char *name;
	uint64_t toc;
	uint64_t total_size;
	uint32_t erase_granule;
};

/* Full pflash version number (possibly includes gitid). */
extern const char version[];

const char *flashfilename = NULL;
static bool must_confirm = true;
static bool dummy_run;
static bool bmc_flash;

#define FILE_BUF_SIZE	0x10000
static uint8_t file_buf[FILE_BUF_SIZE] __aligned(0x1000);

static bool check_confirm(void)
{
	char yes[8], *p;

	if (!must_confirm)
		return true;

	printf("WARNING ! This will modify your %s flash chip content !\n",
	       bmc_flash ? "BMC" : "HOST");
	printf("Enter \"yes\" to confirm:");
	memset(yes, 0, sizeof(yes));
	if (!fgets(yes, 7, stdin))
		return false;
	p = strchr(yes, 10);
	if (p)
		*p = 0;
	p = strchr(yes, 13);
	if (p)
		*p = 0;
	if (strcmp(yes, "yes")) {
		printf("Operation cancelled !\n");
		return false;
	}
	must_confirm = false;
	return true;
}

static uint32_t print_ffs_info(struct ffs_handle *ffsh, uint32_t toc)
{
	struct ffs_entry *ent;
	uint32_t next_toc = toc;
	int rc;
	int i;

	printf("\n");
	printf("TOC@0x%08x Partitions:\n", toc);
	printf("-----------\n");

	for (i = 0;; i++) {
		uint32_t start, size, act, end;
		char *name = NULL, *flags;
		int l;

		rc = ffs_part_info(ffsh, i, &name, &start, &size, &act, NULL);
		if (rc == FFS_ERR_PART_NOT_FOUND)
			break;

		ent = ffs_entry_get(ffsh, i);
		if (rc || !ent) {
			fprintf(stderr, "Error %d scanning partitions\n",
					!ent ? FFS_ERR_PART_NOT_FOUND : rc);
		    goto out;
		}

		l = asprintf(&flags, "[%c%c%c%c%c]",
				has_ecc(ent) ? 'E' : '-',
				has_flag(ent, FFS_MISCFLAGS_PRESERVED) ? 'P' : '-',
				has_flag(ent, FFS_MISCFLAGS_READONLY) ? 'R' : '-',
				has_flag(ent, FFS_MISCFLAGS_BACKUP) ? 'B' : '-',
				has_flag(ent, FFS_MISCFLAGS_REPROVISION) ? 'F' : '-');
		if (l < 0)
			goto out;

		end = start + size;
		printf("ID=%02d %15s 0x%08x..0x%08x (actual=0x%08x) %s\n",
				i, name, start, end, act, flags);

		if (strcmp(name, "OTHER_SIDE") == 0)
			next_toc = start;

		free(flags);
out:
		free(name);
	}

	return next_toc;
}

static struct ffs_handle *open_ffs(struct flash_details *flash)
{
	struct ffs_handle *ffsh;
	int rc;

	rc = ffs_init(flash->toc, flash->total_size,
			flash->bl, &ffsh, 0);
	if (rc) {
		fprintf(stderr, "Error %d opening ffs !\n", rc);
		if (flash->toc) {
			fprintf(stderr, "You specified 0x%" PRIx64 " as the libffs TOC\n"
				   	"Looks like it doesn't exist\n", flash->toc);
			return NULL;
		}
	}

	return ffsh;
}

static void print_flash_info(struct flash_details *flash)
{
	struct ffs_handle *ffsh;
	uint32_t next_toc;
	uint32_t toc;

	printf("Flash info:\n");
	printf("-----------\n");
	printf("Name          = %s\n", flash->name);
	printf("Total size    = %" PRIu64 "MB\t Flags E:ECC, P:PRESERVED, R:READONLY\n",
			flash->total_size >> 20);
	printf("Erase granule = %2d%-13sB:BACKUP, F:REPROVISION\n",
			flash->erase_granule >> 10, "KB");

	if (bmc_flash)
		return;

	toc = flash->toc;

	ffsh = open_ffs(flash);
	if (!ffsh)
		return;

	next_toc = print_ffs_info(ffsh, toc);
	ffs_close(ffsh);
	while(next_toc != toc) {
		struct ffs_handle *next_ffsh;

		flash->toc = next_toc;
		next_ffsh = open_ffs(flash);
		if (!next_ffsh)
			break;
		next_toc = print_ffs_info(next_ffsh, next_toc);
		ffs_close(next_ffsh);
	}
	flash->toc = toc;
}

static struct ffs_handle *open_partition(struct flash_details *flash,
		const char *name, uint32_t *index)
{
	struct ffs_handle *ffsh;
	int rc;

	ffsh = open_ffs(flash);
	if (!ffsh)
		return NULL;

	if (!name)
		/* Just open the FFS */
		return ffsh;

	/* Find partition */
	rc = ffs_lookup_part(ffsh, name, index);
	if (rc == FFS_ERR_PART_NOT_FOUND) {
		fprintf(stderr, "Partition '%s' not found !\n", name);
		goto out;
	}
	if (rc) {
		fprintf(stderr, "Error %d looking for partition '%s' !\n",
			rc, name);
		goto out;
	}
	return ffsh;
out:
	ffs_close(ffsh);
	return NULL;
}

static struct ffs_handle *lookup_partition_at_toc(struct flash_details *flash,
		const char *name, uint32_t *index)
{
	return open_partition(flash, name, index);
}

static struct ffs_handle *lookup_partition_at_side(struct flash_details *flash,
		int side, const char *name, uint32_t *index)
{
	uint32_t toc = 0;
	int rc;

	if (side == 1) {
		struct ffs_handle *ffsh;
		uint32_t side_index;

		ffsh = open_partition(flash, "OTHER_SIDE", &side_index);
		if (!ffsh)
			return NULL;

		/* Just need to know where it starts */
		rc = ffs_part_info(ffsh, side_index, NULL, &toc, NULL, NULL, NULL);
		ffs_close(ffsh);
		if (rc)
			return NULL;
	}

	flash->toc = toc;
	return lookup_partition_at_toc(flash, name, index);
}

static int erase_chip(struct flash_details *flash)
{
	bool confirm;
	int rc;
	uint64_t pos;

	printf("About to erase chip !\n");
	confirm = check_confirm();
	if (!confirm)
		return 1;

	printf("Erasing... (may take a while)\n");
	fflush(stdout);

	if (dummy_run) {
		printf("skipped (dummy)\n");
		return 1;
	}

	/*
	 * We could use arch_flash_erase_chip() here BUT everyone really
	 * likes the progress bars.
	 * Lets do an erase block at a time erase then...
	 */
	progress_init(flash->total_size);
	for (pos = 0; pos < flash->total_size; pos += flash->erase_granule) {
		rc = blocklevel_erase(flash->bl, pos, flash->erase_granule);
		if (rc)
			break;
		progress_tick(pos);
	}
	progress_end();
	if (rc) {
		fprintf(stderr, "Error %d erasing chip\n", rc);
		return rc;
	}

	printf("done !\n");
	return 0;
}

static int erase_range(struct flash_details *flash,
		uint32_t start, uint32_t size, bool will_program,
		struct ffs_handle *ffsh, int ffs_index)
{
	uint32_t done = 0, erase_mask = flash->erase_granule - 1;
	bool confirm;
	int rc;

	printf("About to erase 0x%08x..0x%08x !\n", start, start + size);
	confirm = check_confirm();
	if (!confirm)
		return 1;

	if (dummy_run) {
		printf("skipped (dummy)\n");
		return 1;
	}

	printf("Erasing...\n");
	/*
	 * blocklevel_smart_erase() can do the entire thing in one call
	 * BUT everyone really likes progress bars so break stuff up
	 */
	progress_init(size);
	if (start & erase_mask) {
		/* Align to next erase block */
		rc = blocklevel_smart_erase(flash->bl, start,
				flash->erase_granule - (start & erase_mask));
		if (rc) {
			fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
			return 1;
		}
		start += flash->erase_granule - (start & erase_mask);
		size -= flash->erase_granule - (start & erase_mask);
		done = flash->erase_granule - (start & erase_mask);
	}
	progress_tick(done);
	while (size & ~(erase_mask)) {
		rc = blocklevel_smart_erase(flash->bl, start, flash->erase_granule);
		if (rc) {
			fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
			return 1;
		}
		start += flash->erase_granule;
		size -= flash->erase_granule;
		done += flash->erase_granule;
		progress_tick(done);
	}
	if (size) {
		rc = blocklevel_smart_erase(flash->bl, start, size);
		if (rc) {
			fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
			return 1;
		}
		done += size;
		progress_tick(done);
	}
	progress_end();
	/* If this is a flash partition, mark it empty if we aren't
	 * going to program over it as well
	 */
	if (ffsh && ffs_index >= 0 && !will_program) {
		printf("Updating actual size in partition header...\n");
		ffs_update_act_size(ffsh, ffs_index, 0);
	}
	return 0;
}

static int set_ecc(struct flash_details *flash, uint32_t start, uint32_t size)
{
	uint32_t i = start + 8;
	uint8_t ecc = 0;
	bool confirm;

	printf("About to erase and set ECC bits in region 0x%08x to 0x%08x\n", start, start + size);
	confirm = check_confirm();
	if (!confirm)
		return 1;

	erase_range(flash, start, size, true, NULL, 0);

	printf("Programming ECC bits...\n");
	progress_init(size);
	while (i < start + size) {
		blocklevel_write(flash->bl, i, &ecc, sizeof(ecc));<commit_msg>external/pflash: Fix not checking return values in set_ecc().<commit_after>/* Copyright 2013-2015 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <byteswap.h>
#include <stdint.h>
#include <stdbool.h>
#include <getopt.h>
#include <limits.h>
#include <arpa/inet.h>
#include <assert.h>
#include <inttypes.h>

#include <libflash/libflash.h>
#include <libflash/libffs.h>
#include <libflash/blocklevel.h>
#include <common/arch_flash.h>
#include "progress.h"

#define __aligned(x)			__attribute__((aligned(x)))

struct flash_details {
	struct blocklevel_device *bl;
	int need_relock;
	const char *name;
	uint64_t toc;
	uint64_t total_size;
	uint32_t erase_granule;
};

/* Full pflash version number (possibly includes gitid). */
extern const char version[];

const char *flashfilename = NULL;
static bool must_confirm = true;
static bool dummy_run;
static bool bmc_flash;

#define FILE_BUF_SIZE	0x10000
static uint8_t file_buf[FILE_BUF_SIZE] __aligned(0x1000);

static bool check_confirm(void)
{
	char yes[8], *p;

	if (!must_confirm)
		return true;

	printf("WARNING ! This will modify your %s flash chip content !\n",
	       bmc_flash ? "BMC" : "HOST");
	printf("Enter \"yes\" to confirm:");
	memset(yes, 0, sizeof(yes));
	if (!fgets(yes, 7, stdin))
		return false;
	p = strchr(yes, 10);
	if (p)
		*p = 0;
	p = strchr(yes, 13);
	if (p)
		*p = 0;
	if (strcmp(yes, "yes")) {
		printf("Operation cancelled !\n");
		return false;
	}
	must_confirm = false;
	return true;
}

static uint32_t print_ffs_info(struct ffs_handle *ffsh, uint32_t toc)
{
	struct ffs_entry *ent;
	uint32_t next_toc = toc;
	int rc;
	int i;

	printf("\n");
	printf("TOC@0x%08x Partitions:\n", toc);
	printf("-----------\n");

	for (i = 0;; i++) {
		uint32_t start, size, act, end;
		char *name = NULL, *flags;
		int l;

		rc = ffs_part_info(ffsh, i, &name, &start, &size, &act, NULL);
		if (rc == FFS_ERR_PART_NOT_FOUND)
			break;

		ent = ffs_entry_get(ffsh, i);
		if (rc || !ent) {
			fprintf(stderr, "Error %d scanning partitions\n",
					!ent ? FFS_ERR_PART_NOT_FOUND : rc);
		    goto out;
		}

		l = asprintf(&flags, "[%c%c%c%c%c]",
				has_ecc(ent) ? 'E' : '-',
				has_flag(ent, FFS_MISCFLAGS_PRESERVED) ? 'P' : '-',
				has_flag(ent, FFS_MISCFLAGS_READONLY) ? 'R' : '-',
				has_flag(ent, FFS_MISCFLAGS_BACKUP) ? 'B' : '-',
				has_flag(ent, FFS_MISCFLAGS_REPROVISION) ? 'F' : '-');
		if (l < 0)
			goto out;

		end = start + size;
		printf("ID=%02d %15s 0x%08x..0x%08x (actual=0x%08x) %s\n",
				i, name, start, end, act, flags);

		if (strcmp(name, "OTHER_SIDE") == 0)
			next_toc = start;

		free(flags);
out:
		free(name);
	}

	return next_toc;
}

static struct ffs_handle *open_ffs(struct flash_details *flash)
{
	struct ffs_handle *ffsh;
	int rc;

	rc = ffs_init(flash->toc, flash->total_size,
			flash->bl, &ffsh, 0);
	if (rc) {
		fprintf(stderr, "Error %d opening ffs !\n", rc);
		if (flash->toc) {
			fprintf(stderr, "You specified 0x%" PRIx64 " as the libffs TOC\n"
				   	"Looks like it doesn't exist\n", flash->toc);
			return NULL;
		}
	}

	return ffsh;
}

static void print_flash_info(struct flash_details *flash)
{
	struct ffs_handle *ffsh;
	uint32_t next_toc;
	uint32_t toc;

	printf("Flash info:\n");
	printf("-----------\n");
	printf("Name          = %s\n", flash->name);
	printf("Total size    = %" PRIu64 "MB\t Flags E:ECC, P:PRESERVED, R:READONLY\n",
			flash->total_size >> 20);
	printf("Erase granule = %2d%-13sB:BACKUP, F:REPROVISION\n",
			flash->erase_granule >> 10, "KB");

	if (bmc_flash)
		return;

	toc = flash->toc;

	ffsh = open_ffs(flash);
	if (!ffsh)
		return;

	next_toc = print_ffs_info(ffsh, toc);
	ffs_close(ffsh);
	while(next_toc != toc) {
		struct ffs_handle *next_ffsh;

		flash->toc = next_toc;
		next_ffsh = open_ffs(flash);
		if (!next_ffsh)
			break;
		next_toc = print_ffs_info(next_ffsh, next_toc);
		ffs_close(next_ffsh);
	}
	flash->toc = toc;
}

static struct ffs_handle *open_partition(struct flash_details *flash,
		const char *name, uint32_t *index)
{
	struct ffs_handle *ffsh;
	int rc;

	ffsh = open_ffs(flash);
	if (!ffsh)
		return NULL;

	if (!name)
		/* Just open the FFS */
		return ffsh;

	/* Find partition */
	rc = ffs_lookup_part(ffsh, name, index);
	if (rc == FFS_ERR_PART_NOT_FOUND) {
		fprintf(stderr, "Partition '%s' not found !\n", name);
		goto out;
	}
	if (rc) {
		fprintf(stderr, "Error %d looking for partition '%s' !\n",
			rc, name);
		goto out;
	}
	return ffsh;
out:
	ffs_close(ffsh);
	return NULL;
}

static struct ffs_handle *lookup_partition_at_toc(struct flash_details *flash,
		const char *name, uint32_t *index)
{
	return open_partition(flash, name, index);
}

static struct ffs_handle *lookup_partition_at_side(struct flash_details *flash,
		int side, const char *name, uint32_t *index)
{
	uint32_t toc = 0;
	int rc;

	if (side == 1) {
		struct ffs_handle *ffsh;
		uint32_t side_index;

		ffsh = open_partition(flash, "OTHER_SIDE", &side_index);
		if (!ffsh)
			return NULL;

		/* Just need to know where it starts */
		rc = ffs_part_info(ffsh, side_index, NULL, &toc, NULL, NULL, NULL);
		ffs_close(ffsh);
		if (rc)
			return NULL;
	}

	flash->toc = toc;
	return lookup_partition_at_toc(flash, name, index);
}

static int erase_chip(struct flash_details *flash)
{
	bool confirm;
	int rc;
	uint64_t pos;

	printf("About to erase chip !\n");
	confirm = check_confirm();
	if (!confirm)
		return 1;

	printf("Erasing... (may take a while)\n");
	fflush(stdout);

	if (dummy_run) {
		printf("skipped (dummy)\n");
		return 1;
	}

	/*
	 * We could use arch_flash_erase_chip() here BUT everyone really
	 * likes the progress bars.
	 * Lets do an erase block at a time erase then...
	 */
	progress_init(flash->total_size);
	for (pos = 0; pos < flash->total_size; pos += flash->erase_granule) {
		rc = blocklevel_erase(flash->bl, pos, flash->erase_granule);
		if (rc)
			break;
		progress_tick(pos);
	}
	progress_end();
	if (rc) {
		fprintf(stderr, "Error %d erasing chip\n", rc);
		return rc;
	}

	printf("done !\n");
	return 0;
}

static int erase_range(struct flash_details *flash,
		uint32_t start, uint32_t size, bool will_program,
		struct ffs_handle *ffsh, int ffs_index)
{
	uint32_t done = 0, erase_mask = flash->erase_granule - 1;
	bool confirm;
	int rc;

	printf("About to erase 0x%08x..0x%08x !\n", start, start + size);
	confirm = check_confirm();
	if (!confirm)
		return 1;

	if (dummy_run) {
		printf("skipped (dummy)\n");
		return 1;
	}

	printf("Erasing...\n");
	/*
	 * blocklevel_smart_erase() can do the entire thing in one call
	 * BUT everyone really likes progress bars so break stuff up
	 */
	progress_init(size);
	if (start & erase_mask) {
		/* Align to next erase block */
		rc = blocklevel_smart_erase(flash->bl, start,
				flash->erase_granule - (start & erase_mask));
		if (rc) {
			fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
			return 1;
		}
		start += flash->erase_granule - (start & erase_mask);
		size -= flash->erase_granule - (start & erase_mask);
		done = flash->erase_granule - (start & erase_mask);
	}
	progress_tick(done);
	while (size & ~(erase_mask)) {
		rc = blocklevel_smart_erase(flash->bl, start, flash->erase_granule);
		if (rc) {
			fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
			return 1;
		}
		start += flash->erase_granule;
		size -= flash->erase_granule;
		done += flash->erase_granule;
		progress_tick(done);
	}
	if (size) {
		rc = blocklevel_smart_erase(flash->bl, start, size);
		if (rc) {
			fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
			return 1;
		}
		done += size;
		progress_tick(done);
	}
	progress_end();
	/* If this is a flash partition, mark it empty if we aren't
	 * going to program over it as well
	 */
	if (ffsh && ffs_index >= 0 && !will_program) {
		printf("Updating actual size in partition header...\n");
		ffs_update_act_size(ffsh, ffs_index, 0);
	}
	return 0;
}

static int set_ecc(struct flash_details *flash, uint32_t start, uint32_t size)
{
	uint32_t i = start + 8;
	uint8_t ecc = 0;
	bool confirm;
	int rc;

	printf("About to erase and set ECC bits in region 0x%08x to 0x%08x\n", start, start + size);
	confirm = check_confirm();
	if (!confirm)
		return 1;

	rc = erase_range(flash, start, size, true, NULL, 0);
	if (rc) {
		fprintf(stderr, "Couldn't erase region to mark with ECC\n");
		return rc;
	}

	printf("Programming ECC bits...\n");
	progress_init(size);
	while (i < start + size) {
		rc = blocklevel_write(flash->bl, i, &ecc, sizeof(ecc));
		if (rc) {
			fprintf(stderr, "\nError setting ECC byte at 0x%08x\n", i);
			return rc;
		}
{'fraction_non_alphanumeric': 0.14771356508389077, 'fraction_numerical': 0.015517052308367146, 'mean_word_length': 3.8898123324396785, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 113, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4116786', 'n_tokens_mistral': 7734, 'n_tokens_neox': 7053, 'n_words': 1906}