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 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <assert.h> 31 #include <stdlib.h> 32 #include "rcapd_mapping.h" 33 #include "utils.h" 34 35 /* 36 * lmapping_t is a list of non-overlapping mappings, ordered by address. These 37 * functions add, remove, and verify the existence of mappings in such a list. 38 * rcapd_scanner.c is a consumer. 39 */ 40 41 typedef struct lmapping_find_cb_arg { 42 uintptr_t lmfa_addr; 43 size_t lmfa_size; 44 lmapping_t *lmfa_prior; 45 lmapping_t *lmfa_ret; 46 } lmapping_find_cb_arg_t; 47 48 #ifdef DEBUG 49 /* 50 * Verify a sublist is properly ordered. 51 */ 52 static void 53 lmapping_verify(lmapping_t *lm) 54 { 55 while (lm != NULL) { 56 if (lm->lm_next != NULL) 57 ASSERT(lm->lm_next->lm_addr > lm->lm_addr); 58 lm = lm->lm_next; 59 } 60 } 61 #else /* !DEBUG */ 62 #define lmapping_verify(x) ((void)0) 63 #endif /* DEBUG */ 64 65 /* 66 * Determine the position of a mapping with the given address and size. Upon 67 * return, lmfa_ret will be set to the actual mapping, if it exists, and 68 * lmfa_prior will be set to the mapping which does or would precede one with 69 * the given characteristics. 70 */ 71 static int 72 lmapping_find_cb(lmapping_t *lm, void *arg) 73 { 74 lmapping_find_cb_arg_t *lmfa = arg; 75 76 if (lm->lm_addr >= lmfa->lmfa_addr) { 77 if (lmfa->lmfa_addr == lm->lm_addr && lmfa->lmfa_size == 78 lm->lm_size) 79 lmfa->lmfa_ret = lm; 80 return (1); 81 } else 82 lmfa->lmfa_prior = lm; 83 84 return (0); 85 } 86 87 static void 88 lmapping_walk(lmapping_t *lm, int(*lmapping_walk_cb)(lmapping_t *, void *), 89 void *arg) 90 { 91 lmapping_t *next; 92 93 while (lm != NULL) { 94 next = lm->lm_next; 95 lmapping_verify(lm); 96 if (lmapping_walk_cb(lm, arg) != 0) { 97 lmapping_verify(lm); 98 return; 99 } 100 lm = next; 101 } 102 } 103 104 int 105 lmapping_remove(lmapping_t **lm, uintptr_t addr, size_t size) 106 { 107 lmapping_find_cb_arg_t lmfa; 108 109 lmfa.lmfa_addr = addr; 110 lmfa.lmfa_size = size; 111 lmfa.lmfa_prior = lmfa.lmfa_ret = NULL; 112 113 lmapping_verify(*lm); 114 lmapping_walk(*lm, lmapping_find_cb, &lmfa); 115 if (lmfa.lmfa_ret == NULL) 116 return (-1); 117 118 if (lmfa.lmfa_prior != NULL) 119 lmfa.lmfa_prior->lm_next = lmfa.lmfa_ret->lm_next; 120 else if (*lm == lmfa.lmfa_ret) 121 *lm = lmfa.lmfa_ret->lm_next; 122 123 free(lmfa.lmfa_ret); 124 125 lmapping_verify(*lm); 126 127 return (0); 128 } 129 130 int 131 lmapping_insert(lmapping_t **lm, uintptr_t addr, size_t size) 132 { 133 lmapping_find_cb_arg_t lmfa; 134 lmapping_t *cur; 135 136 cur = malloc(sizeof (*cur)); 137 if (cur == NULL) 138 return (-1); 139 140 cur->lm_addr = addr; 141 cur->lm_size = size; 142 cur->lm_next = NULL; 143 144 lmfa.lmfa_addr = addr; 145 lmfa.lmfa_size = size; 146 lmfa.lmfa_prior = lmfa.lmfa_ret = NULL; 147 148 lmapping_verify(*lm); 149 lmapping_walk(*lm, lmapping_find_cb, &lmfa); 150 ASSERT(lmfa.lmfa_ret == NULL); 151 if (lmfa.lmfa_prior != NULL) { 152 cur->lm_next = lmfa.lmfa_prior->lm_next; 153 lmfa.lmfa_prior->lm_next = cur; 154 } else { 155 cur->lm_next = *lm; 156 *lm = cur; 157 } 158 159 lmapping_verify(*lm); 160 161 return (0); 162 } 163 164 int 165 lmapping_contains(lmapping_t *lm, uintptr_t addr, size_t size) 166 { 167 lmapping_find_cb_arg_t lmfa; 168 169 lmfa.lmfa_addr = addr; 170 lmfa.lmfa_size = size; 171 lmfa.lmfa_ret = NULL; 172 173 lmapping_walk(lm, lmapping_find_cb, &lmfa); 174 return (lmfa.lmfa_ret != NULL); 175 } 176 177 /*ARGSUSED*/ 178 static int 179 lmapping_free_cb(lmapping_t *lm, void *arg) 180 { 181 free(lm); 182 return (0); 183 } 184 185 void 186 lmapping_free(lmapping_t **lm) 187 { 188 lmapping_walk(*lm, lmapping_free_cb, NULL); 189 *lm = NULL; 190 } 191 192 #ifdef DEBUG 193 int 194 lmapping_dump_diff(lmapping_t *lm1, lmapping_t *lm2) 195 { 196 lmapping_t **lmv; 197 int res = 0; 198 int ch = 0; 199 int label_printed = 0; 200 201 #define OUTPUT_LABEL() \ 202 if (label_printed == 0) { \ 203 debug("changes in mappings:\n"); \ 204 label_printed++; \ 205 } 206 207 while (lm1 != NULL && lm2 != NULL) { 208 if ((lm1->lm_addr != lm2->lm_addr) || (lm1->lm_size != 209 lm2->lm_size)) { 210 res = -1; 211 212 if (lm1->lm_addr == lm2->lm_addr && lm1->lm_size < 213 lm2->lm_size || lm1->lm_addr < lm2->lm_addr) { 214 lmv = &lm1; 215 ch = '-'; 216 } else { 217 lmv = &lm2; 218 ch = '+'; 219 } 220 OUTPUT_LABEL(); 221 debug("%c%p+0x%llx\n", ch, (void *)(*lmv)->lm_addr, 222 (long long)(*lmv)->lm_size); 223 *lmv = (*lmv)->lm_next; 224 } else { 225 lm1 = lm1->lm_next; 226 lm2 = lm2->lm_next; 227 } 228 } 229 while (lm1 != NULL) { 230 OUTPUT_LABEL(); 231 debug("%c%p+0x%llx\n", '-', (void *)lm1->lm_addr, 232 (unsigned long long)lm1->lm_size); 233 lm1 = lm1->lm_next; 234 res = 1; 235 } 236 while (lm2 != NULL) { 237 OUTPUT_LABEL(); 238 debug("%c%p+0x%llx\n", '+', (void *)lm2->lm_addr, 239 (long long)lm2->lm_size); 240 lm2 = lm2->lm_next; 241 res = 1; 242 } 243 244 return (res); 245 #undef OUTPUT_LABEL 246 } 247 #endif /* DEBUG */ 248