1 /* Copyright 2013-2014 IBM Corp.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * 	http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12  * implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "../../core/test/stubs.c"
18 #include "../phys-map.c"
19 
20 enum proc_gen proc_gen;
21 
print_entry(const struct phys_map_entry * e)22 static inline void print_entry(const struct phys_map_entry *e)
23 {
24 	printf("type:%i index:%i addr:%016lx size:%016lx",
25 	       e->type, e->index, e->addr, e->size);
26 }
27 
28 /* Check table directly for overlaps */
check_table_directly(void)29 static void check_table_directly(void)
30 {
31 	const struct phys_map_entry *e, *prev;
32 	uint64_t start, end, pstart, pend;
33 	bool passed;
34 
35 	/* Loop over table entries ...  */
36 	for (e = phys_map->table; !phys_map_entry_null(e); e++) {
37 
38 		start = e->addr;
39 		end = e->addr + e->size;
40 		/* ... see if they overlap with previous entries */
41 		for (prev = phys_map->table; prev != e; prev++) {
42 			passed = true;
43 			/* Check for overlaping regions */
44 			pstart = prev->addr;
45 			pend = prev->addr + prev->size;
46 			if ((start > pstart) && (start < pend))
47 				passed = false;
48 			if ((end > pstart) && (end < pend))
49 				passed = false;
50 
51 			/* Check for duplicate entries */
52 			if ((e->type == prev->type) &&
53 			    (e->index == prev->index))
54 				passed = false;
55 
56 			if (passed)
57 				continue;
58 
59 			printf("Phys map direct test FAILED: Entry overlaps\n");
60 			printf("First:  ");
61 			print_entry(prev);
62 			printf("\n");
63 			printf("Second: ");
64 			print_entry(e);
65 			printf("\n");
66 			assert(0);
67 		}
68 	}
69 }
70 
71 struct map_call_entry {
72 	uint64_t start;
73 	uint64_t end;
74 };
75 
map_call_entry_null(const struct map_call_entry * t)76 static inline bool map_call_entry_null(const struct map_call_entry *t)
77 {
78 	if ((t->start == 0) &&
79 	    (t->end == 0))
80 		return true;
81 	return false;
82 }
83 
84 /* Check calls to map to see if they overlap.
85  * Creates a new table for each of the entries it gets to check against
86  */
87 
88 /* Pick a chip ID, any ID. */
89 #define FAKE_CHIP_ID 8
90 
check_map_call(void)91 static void check_map_call(void)
92 {
93 	uint64_t start, size, end;
94 	const struct phys_map_entry *e;
95 	struct map_call_entry *tbl, *t, *tnext;
96 	int tbl_size = 0;
97 	bool passed;
98 
99 	for (e = phys_map->table; !phys_map_entry_null(e); e++)
100 		tbl_size++;
101 
102 	tbl_size++; /* allow for null entry at end */
103 	tbl_size *= sizeof(struct map_call_entry);
104 	tbl = malloc(tbl_size);
105 	assert(tbl != NULL);
106 	memset(tbl, 0, tbl_size);
107 
108 	/* Loop over table entries ...  */
109 	for (e = phys_map->table; !phys_map_entry_null(e); e++) {
110 		phys_map_get(FAKE_CHIP_ID, e->type, e->index, &start, &size);
111 
112 		/* Check for alignment */
113 		if ((e->type != SYSTEM_MEM) && (e->type != RESV)) {
114 			/* Size is power of 2? */
115 			assert(__builtin_popcountl(size) == 1);
116 			/* Start is aligned to size? */
117 			assert((start % size) == 0);
118 		}
119 
120 		end = start + size;
121 		for (t = tbl; !map_call_entry_null(t); t++) {
122 			passed = true;
123 
124 			/* Check for overlaping regions */
125 			if ((start > t->start) && (start < t->end))
126 				passed = false;
127 			if ((end > t->start) && (end < t->end))
128 				passed = false;
129 
130 			if (passed)
131 				continue;
132 
133 			printf("Phys map call test FAILED: Entry overlaps\n");
134 			printf("First:  addr:%016lx size:%016lx\n",
135 			       t->start, t->end - t->start);
136 			printf("Second: addr:%016lx size:%016lx\n  ",
137 			       start, size);
138 			print_entry(e);
139 			printf("\n");
140 			assert(0);
141 		}
142 		/* Insert entry at end of table */
143 		t->start = start;
144 		t->end = end;
145 	}
146 
147 	for (t = tbl; !map_call_entry_null(t + 1); t++) {
148 		tnext = t + 1;
149 		/* Make sure the table is sorted */
150 		if (t->start > tnext->start) {
151 			printf("Phys map test FAILED: Entry not sorted\n");
152 			printf("First:  addr:%016lx size:%016lx\n",
153 			       t->start, t->end - t->start);
154 			printf("Second:  addr:%016lx size:%016lx\n",
155 			       tnext->start, tnext->end - tnext->start);
156 			assert(0);
157 		}
158 
159 		/* Look for holes in the table in MMIO region */
160 		/* We assume over 1PB is MMIO. */
161 		if ((t->end != tnext->start) &&
162 		    (t->start > 0x0004000000000000)) {
163 			printf("Phys map test FAILED: Hole in map\n");
164 			printf("First:  addr:%016lx size:%016lx\n",
165 			       t->start, t->end - t->start);
166 			printf("Second:  addr:%016lx size:%016lx\n",
167 			       tnext->start, tnext->end - tnext->start);
168 			assert(0);
169 		}
170 	}
171 
172 	free(tbl);
173 }
174 
main(void)175 int main(void)
176 {
177 	/* Fake we are POWER9 */
178 	proc_gen = proc_gen_p9;
179 	phys_map_init();
180 
181 	/* Run tests */
182 	check_table_directly();
183 	check_map_call();
184 
185 	return(0);
186 }
187