static int get_dyn_reconf_crash_memory_ranges(void)
{
	uint64_t start, end;
	char fname[128], buf[32];
	FILE *file;
	unsigned int i;
	int n;
	uint32_t flags;

	strcpy(fname, "/proc/device-tree/");
	strcat(fname, "ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory");
	if ((file = fopen(fname, "r")) == NULL) {
		perror(fname);
		return -1;
	}

	fseek(file, 4, SEEK_SET);
	for (i = 0; i < num_of_lmbs; i++) {
		if ((n = fread(buf, 1, 24, file)) < 0) {
			perror(fname);
			fclose(file);
			return -1;
		}
		if (memory_ranges >= (max_memory_ranges + 1)) {
			/* No space to insert another element. */
				fprintf(stderr,
				"Error: Number of crash memory ranges"
				" excedeed the max limit\n");
			return -1;
		}

		start = be64_to_cpu(((uint64_t *)buf)[DRCONF_ADDR]);
		end = start + lmb_size;
		if (start == 0 && end >= (BACKUP_SRC_END + 1))
			start = BACKUP_SRC_END + 1;

		flags = be32_to_cpu((*((uint32_t *)&buf[DRCONF_FLAGS])));
		/* skip this block if the reserved bit is set in flags (0x80)
		   or if the block is not assigned to this partition (0x8) */
		if ((flags & 0x80) || !(flags & 0x8))
			continue;

		exclude_crash_region(start, end);
	}
	fclose(file);
	return 0;
}
/* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to
 * create Elf headers. Keeping it separate from get_memory_ranges() as
 * requirements are different in the case of normal kexec and crashdumps.
 *
 * Normal kexec needs to look at all of available physical memory irrespective
 * of the fact how much of it is being used by currently running kernel.
 * Crashdumps need to have access to memory regions actually being used by
 * running  kernel. Expecting a different file/data structure than /proc/iomem
 * to look into down the line. May be something like /proc/kernelmem or may
 * be zone data structures exported from kernel.
 */
static int get_crash_memory_ranges(struct memory_range **range, int *ranges)
{

	char device_tree[256] = "/proc/device-tree/";
	char fname[256];
	char buf[MAXBYTES];
	DIR *dir, *dmem;
	FILE *file;
	struct dirent *dentry, *mentry;
	int i, n, crash_rng_len = 0;
	unsigned long long start, end;
	int page_size;

	crash_max_memory_ranges = max_memory_ranges + 6;
	crash_rng_len = sizeof(struct memory_range) * crash_max_memory_ranges;

	crash_memory_range = (struct memory_range *) malloc(crash_rng_len);
	if (!crash_memory_range) {
		fprintf(stderr, "Allocation for crash memory range failed\n");
		return -1;
	}
	memset(crash_memory_range, 0, crash_rng_len);

	/* create a separate program header for the backup region */
	crash_memory_range[0].start = BACKUP_SRC_START;
	crash_memory_range[0].end = BACKUP_SRC_END + 1;
	crash_memory_range[0].type = RANGE_RAM;
	memory_ranges++;

	if ((dir = opendir(device_tree)) == NULL) {
		perror(device_tree);
		goto err;
	}

	cstart = crash_base;
	cend = crash_base + crash_size;

	while ((dentry = readdir(dir)) != NULL) {
		if (!strncmp(dentry->d_name,
				"ibm,dynamic-reconfiguration-memory", 35)){
			get_dyn_reconf_crash_memory_ranges();
			continue;
		}
		if (strncmp(dentry->d_name, "memory@", 7) &&
			strcmp(dentry->d_name, "memory"))
			continue;
		strcpy(fname, device_tree);
		strcat(fname, dentry->d_name);
		if ((dmem = opendir(fname)) == NULL) {
			perror(fname);
			closedir(dir);
			goto err;
		}
		while ((mentry = readdir(dmem)) != NULL) {
			if (strcmp(mentry->d_name, "reg"))
				continue;
			strcat(fname, "/reg");
			if ((file = fopen(fname, "r")) == NULL) {
				perror(fname);
				closedir(dmem);
				closedir(dir);
				goto err;
			}
			if ((n = fread(buf, 1, MAXBYTES, file)) < 0) {
				perror(fname);
				fclose(file);
				closedir(dmem);
				closedir(dir);
				goto err;
			}
			if (memory_ranges >= (max_memory_ranges + 1)) {
				/* No space to insert another element. */
				fprintf(stderr,
					"Error: Number of crash memory ranges"
					" excedeed the max limit\n");
				goto err;
			}

			start = ((unsigned long long *)buf)[0];
			end = start + ((unsigned long long *)buf)[1];
			if (start == 0 && end >= (BACKUP_SRC_END + 1))
				start = BACKUP_SRC_END + 1;

			exclude_crash_region(start, end);
			fclose(file);
		}
		closedir(dmem);
	}
	closedir(dir);

	/*
	 * If RTAS region is overlapped with crashkernel, need to create ELF
	 * Program header for the overlapped memory.
	 */
	if (crash_base < rtas_base + rtas_size &&
		rtas_base < crash_base + crash_size) {
		page_size = getpagesize();
		cstart = rtas_base;
		cend = rtas_base + rtas_size;
		if (cstart < crash_base)
			cstart = crash_base;
		if (cend > crash_base + crash_size)
			cend = crash_base + crash_size;
		/*
		 * The rtas section created here is formed by reading rtas-base
		 * and rtas-size from /proc/device-tree/rtas.  Unfortunately
		 * rtas-size is not required to be a multiple of PAGE_SIZE
		 * The remainder of the page it ends on is just garbage, and is
		 * safe to read, its just not accounted in rtas-size.  Since
		 * we're creating an elf section here though, lets round it up
		 * to the next page size boundary though, so makedumpfile can
		 * read it safely without going south on us.
		 */
		cend = (cend + page_size - 1) & (~(page_size - 1));

		crash_memory_range[memory_ranges].start = cstart;
		crash_memory_range[memory_ranges++].end = cend;
	}
	/*
	 * Can not trust the memory regions order that we read from
	 * device-tree. Hence, get the MAX end value.
	 */
	for (i = 0; i < memory_ranges; i++)
		if (saved_max_mem < crash_memory_range[i].end)
			saved_max_mem = crash_memory_range[i].end;

	*range = crash_memory_range;
	*ranges = memory_ranges;
#if DEBUG
	int j;
	printf("CRASH MEMORY RANGES\n");
	for(j = 0; j < *ranges; j++) {
		start = crash_memory_range[j].start;
		end = crash_memory_range[j].end;
		fprintf(stderr, "%016Lx-%016Lx\n", start, end);
	}
#endif
	return 0;

err:
	if (crash_memory_range)
		free(crash_memory_range);
	return -1;
}
Exemple #3
0
static int get_dyn_reconf_crash_memory_ranges(void)
{
	uint64_t start, end;
	uint64_t startrange, endrange;
	uint64_t size;
	char fname[128], buf[32];
	FILE *file;
	unsigned int i;
	int n;
	uint32_t flags;

	strcpy(fname, "/proc/device-tree/");
	strcat(fname, "ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory");
	if (is_dyn_mem_v2)
		strcat(fname, "-v2");
	if ((file = fopen(fname, "r")) == NULL) {
		perror(fname);
		return -1;
	}

	fseek(file, 4, SEEK_SET);
	startrange = endrange = 0;
	size = lmb_size;
	for (i = 0; i < num_of_lmb_sets; i++) {
		if ((n = fread(buf, 1, LMB_ENTRY_SIZE, file)) < 0) {
			perror(fname);
			fclose(file);
			return -1;
		}
		if (memory_ranges >= (max_memory_ranges + 1)) {
			/* No space to insert another element. */
				fprintf(stderr,
				"Error: Number of crash memory ranges"
				" excedeed the max limit\n");
			return -1;
		}

		/*
		 * If the property is ibm,dynamic-memory-v2, the first 4 bytes
		 * tell the number of sequential LMBs in this entry.
		 */
		if (is_dyn_mem_v2)
			size = be32_to_cpu(((unsigned int *)buf)[0]) * lmb_size;

		start = be64_to_cpu(*((uint64_t *)&buf[DRCONF_ADDR]));
		end = start + size;
		if (start == 0 && end >= (BACKUP_SRC_END + 1))
			start = BACKUP_SRC_END + 1;

		flags = be32_to_cpu((*((uint32_t *)&buf[DRCONF_FLAGS])));
		/* skip this block if the reserved bit is set in flags (0x80)
		   or if the block is not assigned to this partition (0x8) */
		if ((flags & 0x80) || !(flags & 0x8))
			continue;

		if (start != endrange) {
			if (startrange != endrange)
				exclude_crash_region(startrange, endrange);
			startrange = start;
		}
		endrange = end;
	}
	if (startrange != endrange)
		exclude_crash_region(startrange, endrange);

	fclose(file);
	return 0;
}