1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/types.h>
28 #include <assert.h>
29 #include <stdlib.h>
30 #include "rcapd_mapping.h"
31 #include "utils.h"
32 
33 /*
34  * lmapping_t is a list of non-overlapping mappings, ordered by address.  These
35  * functions add, remove, and verify the existence of mappings in such a list.
36  * rcapd_scanner.c is a consumer.
37  */
38 
39 typedef struct lmapping_find_cb_arg {
40 	uintptr_t	lmfa_addr;
41 	size_t		lmfa_size;
42 	lmapping_t	*lmfa_prior;
43 	lmapping_t	*lmfa_ret;
44 } lmapping_find_cb_arg_t;
45 
46 #ifdef DEBUG
47 /*
48  * Verify a sublist is properly ordered.
49  */
50 static void
lmapping_verify(lmapping_t * lm)51 lmapping_verify(lmapping_t *lm)
52 {
53 	while (lm != NULL) {
54 		if (lm->lm_next != NULL)
55 			ASSERT(lm->lm_next->lm_addr > lm->lm_addr);
56 		lm = lm->lm_next;
57 	}
58 }
59 #else /* !DEBUG */
60 #define	lmapping_verify(x) ((void)0)
61 #endif /* DEBUG */
62 
63 /*
64  * Determine the position of a mapping with the given address and size.  Upon
65  * return, lmfa_ret will be set to the actual mapping, if it exists, and
66  * lmfa_prior will be set to the mapping which does or would precede one with
67  * the given characteristics.
68  */
69 static int
lmapping_find_cb(lmapping_t * lm,void * arg)70 lmapping_find_cb(lmapping_t *lm, void *arg)
71 {
72 	lmapping_find_cb_arg_t *lmfa = arg;
73 
74 	if (lm->lm_addr >= lmfa->lmfa_addr) {
75 		if (lmfa->lmfa_addr == lm->lm_addr && lmfa->lmfa_size ==
76 		    lm->lm_size)
77 			lmfa->lmfa_ret = lm;
78 		return (1);
79 	} else
80 		lmfa->lmfa_prior = lm;
81 
82 	return (0);
83 }
84 
85 static void
lmapping_walk(lmapping_t * lm,int (* lmapping_walk_cb)(lmapping_t *,void *),void * arg)86 lmapping_walk(lmapping_t *lm, int(*lmapping_walk_cb)(lmapping_t *, void *),
87     void *arg)
88 {
89 	lmapping_t *next;
90 
91 	while (lm != NULL) {
92 		next = lm->lm_next;
93 		lmapping_verify(lm);
94 		if (lmapping_walk_cb(lm, arg) != 0) {
95 			lmapping_verify(lm);
96 			return;
97 		}
98 		lm = next;
99 	}
100 }
101 
102 int
lmapping_remove(lmapping_t ** lm,uintptr_t addr,size_t size)103 lmapping_remove(lmapping_t **lm, uintptr_t addr, size_t size)
104 {
105 	lmapping_find_cb_arg_t lmfa;
106 
107 	lmfa.lmfa_addr = addr;
108 	lmfa.lmfa_size = size;
109 	lmfa.lmfa_prior = lmfa.lmfa_ret = NULL;
110 
111 	lmapping_verify(*lm);
112 	lmapping_walk(*lm, lmapping_find_cb, &lmfa);
113 	if (lmfa.lmfa_ret == NULL)
114 		return (-1);
115 
116 	if (lmfa.lmfa_prior != NULL)
117 		lmfa.lmfa_prior->lm_next = lmfa.lmfa_ret->lm_next;
118 	else if (*lm == lmfa.lmfa_ret)
119 		*lm = lmfa.lmfa_ret->lm_next;
120 
121 	free(lmfa.lmfa_ret);
122 
123 	lmapping_verify(*lm);
124 
125 	return (0);
126 }
127 
128 int
lmapping_insert(lmapping_t ** lm,uintptr_t addr,size_t size)129 lmapping_insert(lmapping_t **lm, uintptr_t addr, size_t size)
130 {
131 	lmapping_find_cb_arg_t lmfa;
132 	lmapping_t *cur;
133 
134 	cur = malloc(sizeof (*cur));
135 	if (cur == NULL)
136 		return (-1);
137 
138 	cur->lm_addr = addr;
139 	cur->lm_size = size;
140 	cur->lm_next = NULL;
141 
142 	lmfa.lmfa_addr = addr;
143 	lmfa.lmfa_size = size;
144 	lmfa.lmfa_prior = lmfa.lmfa_ret = NULL;
145 
146 	lmapping_verify(*lm);
147 	lmapping_walk(*lm, lmapping_find_cb, &lmfa);
148 	ASSERT(lmfa.lmfa_ret == NULL);
149 	if (lmfa.lmfa_prior != NULL) {
150 		cur->lm_next = lmfa.lmfa_prior->lm_next;
151 		lmfa.lmfa_prior->lm_next = cur;
152 	} else {
153 		cur->lm_next = *lm;
154 		*lm = cur;
155 	}
156 
157 	lmapping_verify(*lm);
158 
159 	return (0);
160 }
161 
162 int
lmapping_contains(lmapping_t * lm,uintptr_t addr,size_t size)163 lmapping_contains(lmapping_t *lm, uintptr_t addr, size_t size)
164 {
165 	lmapping_find_cb_arg_t lmfa;
166 
167 	lmfa.lmfa_addr = addr;
168 	lmfa.lmfa_size = size;
169 	lmfa.lmfa_ret = NULL;
170 
171 	lmapping_walk(lm, lmapping_find_cb, &lmfa);
172 	return (lmfa.lmfa_ret != NULL);
173 }
174 
175 /*ARGSUSED*/
176 static int
lmapping_free_cb(lmapping_t * lm,void * arg)177 lmapping_free_cb(lmapping_t *lm, void *arg)
178 {
179 	free(lm);
180 	return (0);
181 }
182 
183 void
lmapping_free(lmapping_t ** lm)184 lmapping_free(lmapping_t **lm)
185 {
186 	lmapping_walk(*lm, lmapping_free_cb, NULL);
187 	*lm = NULL;
188 }
189 
190 #ifdef DEBUG
191 int
lmapping_dump_diff(lmapping_t * lm1,lmapping_t * lm2)192 lmapping_dump_diff(lmapping_t *lm1, lmapping_t *lm2)
193 {
194 	lmapping_t **lmv;
195 	int res = 0;
196 	int ch = 0;
197 	int label_printed = 0;
198 
199 #define	OUTPUT_LABEL() \
200 	if (label_printed == 0) { \
201 		debug("changes in mappings:\n"); \
202 		label_printed++; \
203 	}
204 
205 	while (lm1 != NULL && lm2 != NULL) {
206 		if ((lm1->lm_addr != lm2->lm_addr) || (lm1->lm_size !=
207 		    lm2->lm_size)) {
208 			res = -1;
209 
210 			if (lm1->lm_addr == lm2->lm_addr && lm1->lm_size <
211 			    lm2->lm_size || lm1->lm_addr < lm2->lm_addr) {
212 				lmv = &lm1;
213 				ch = '-';
214 			} else {
215 				lmv = &lm2;
216 				ch = '+';
217 			}
218 			OUTPUT_LABEL();
219 			debug("%c%p+0x%llx\n", ch, (void *)(*lmv)->lm_addr,
220 			    (long long)(*lmv)->lm_size);
221 			*lmv = (*lmv)->lm_next;
222 		} else {
223 			lm1 = lm1->lm_next;
224 			lm2 = lm2->lm_next;
225 		}
226 	}
227 	while (lm1 != NULL) {
228 		OUTPUT_LABEL();
229 		debug("%c%p+0x%llx\n", '-', (void *)lm1->lm_addr,
230 		    (unsigned long long)lm1->lm_size);
231 		lm1 = lm1->lm_next;
232 		res = 1;
233 	}
234 	while (lm2 != NULL) {
235 		OUTPUT_LABEL();
236 		debug("%c%p+0x%llx\n", '+', (void *)lm2->lm_addr,
237 		    (long long)lm2->lm_size);
238 		lm2 = lm2->lm_next;
239 		res = 1;
240 	}
241 
242 	return (res);
243 #undef OUTPUT_LABEL
244 }
245 #endif /* DEBUG */
246