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 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 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 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 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 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 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 177 lmapping_free_cb(lmapping_t *lm, void *arg) 178 { 179 free(lm); 180 return (0); 181 } 182 183 void 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 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