aboutsummaryrefslogtreecommitdiff
path: root/hw/test/phys-map-test.c
blob: 2aabdb826f23a5291b27e6e08336efb10c6de98e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
/*
 * Physical memory map test
 *
 * Copyright 2013-2017 IBM Corp.
 */

#include "../../core/test/stubs.c"
#include "../phys-map.c"

enum proc_gen proc_gen;

static inline void print_entry(const struct phys_map_entry *e)
{
	printf("type:%i index:%i addr:%016lx size:%016lx",
	       e->type, e->index, e->addr, e->size);
}

/* Check table directly for overlaps */
static void check_table_directly(void)
{
	const struct phys_map_entry *e, *prev;
	uint64_t start, end, pstart, pend;
	bool passed;

	/* Loop over table entries ...  */
	for (e = phys_map->table; !phys_map_entry_null(e); e++) {

		start = e->addr;
		end = e->addr + e->size;
		/* ... see if they overlap with previous entries */
		for (prev = phys_map->table; prev != e; prev++) {
			passed = true;
			/* Check for overlaping regions */
			pstart = prev->addr;
			pend = prev->addr + prev->size;
			if ((start > pstart) && (start < pend))
				passed = false;
			if ((end > pstart) && (end < pend))
				passed = false;

			/* Check for duplicate entries */
			if ((e->type == prev->type) &&
			    (e->index == prev->index))
				passed = false;

			if (passed)
				continue;

			printf("Phys map direct test FAILED: Entry overlaps\n");
			printf("First:  ");
			print_entry(prev);
			printf("\n");
			printf("Second: ");
			print_entry(e);
			printf("\n");
			assert(0);
		}
	}
}

struct map_call_entry {
	uint64_t start;
	uint64_t end;
};

static inline bool map_call_entry_null(const struct map_call_entry *t)
{
	if ((t->start == 0) &&
	    (t->end == 0))
		return true;
	return false;
}

/* Check calls to map to see if they overlap.
 * Creates a new table for each of the entries it gets to check against
 */

/* Pick a chip ID, any ID. */
#define FAKE_CHIP_ID 8

static void check_map_call(void)
{
	uint64_t start, size, end;
	const struct phys_map_entry *e;
	struct map_call_entry *tbl, *t, *tnext;
	int tbl_size = 0;
	bool passed;

	for (e = phys_map->table; !phys_map_entry_null(e); e++)
		tbl_size++;

	tbl_size++; /* allow for null entry at end */
	tbl_size *= sizeof(struct map_call_entry);
	tbl = malloc(tbl_size);
	assert(tbl != NULL);
	memset(tbl, 0, tbl_size);

	/* Loop over table entries ...  */
	for (e = phys_map->table; !phys_map_entry_null(e); e++) {
		phys_map_get(FAKE_CHIP_ID, e->type, e->index, &start, &size);

		/* Check for alignment */
		if ((e->type != SYSTEM_MEM) && (e->type != RESV)) {
			/* Size is power of 2? */
			assert(__builtin_popcountl(size) == 1);
			/* Start is aligned to size? */
			assert((start % size) == 0);
		}

		end = start + size;
		for (t = tbl; !map_call_entry_null(t); t++) {
			passed = true;

			/* Check for overlaping regions */
			if ((start > t->start) && (start < t->end))
				passed = false;
			if ((end > t->start) && (end < t->end))
				passed = false;

			if (passed)
				continue;

			printf("Phys map call test FAILED: Entry overlaps\n");
			printf("First:  addr:%016lx size:%016lx\n",
			       t->start, t->end - t->start);
			printf("Second: addr:%016lx size:%016lx\n  ",
			       start, size);
			print_entry(e);
			printf("\n");
			assert(0);
		}
		/* Insert entry at end of table */
		t->start = start;
		t->end = end;
	}

	for (t = tbl; !map_call_entry_null(t + 1); t++) {
		tnext = t + 1;
		/* Make sure the table is sorted */
		if (t->start > tnext->start) {
			printf("Phys map test FAILED: Entry not sorted\n");
			printf("First:  addr:%016lx size:%016lx\n",
			       t->start, t->end - t->start);
			printf("Second:  addr:%016lx size:%016lx\n",
			       tnext->start, tnext->end - tnext->start);
			assert(0);
		}

		/* Look for holes in the table in MMIO region */
		/* We assume over 1PB is MMIO. */
		if ((t->end != tnext->start) &&
		    (t->start > 0x0004000000000000)) {
			printf("Phys map test FAILED: Hole in map\n");
			printf("First:  addr:%016lx size:%016lx\n",
			       t->start, t->end - t->start);
			printf("Second:  addr:%016lx size:%016lx\n",
			       tnext->start, tnext->end - tnext->start);
			assert(0);
		}
	}

	free(tbl);
}

/* Fake PVR definitions. See include/processor.h */
unsigned long fake_pvr[] = {
	0x004e0200,	/* PVR_P9 */
	0x004f0100,	/* PVR_P9P */
};

int main(void)
{
	/* Fake we are POWER9 */
	proc_gen = proc_gen_p9;

	for (int i = 0; i < ARRAY_SIZE(fake_pvr); i++) {
		phys_map_init(fake_pvr[i]);

		/* Run tests */
		check_table_directly();
		check_map_call();
	}

	return(0);
}