1 /* $FreeBSD$ */ 2 /* $NetBSD: citrus_mapper_std.c,v 1.10 2011/11/19 18:48:39 tnozaki Exp $ */ 3 4 /*- 5 * Copyright (c)2003, 2006 Citrus Project, 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 #include <sys/endian.h> 32 #include <sys/queue.h> 33 34 #include <assert.h> 35 #include <errno.h> 36 #include <limits.h> 37 #include <stdint.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 42 #include "citrus_namespace.h" 43 #include "citrus_types.h" 44 #include "citrus_bcs.h" 45 #include "citrus_region.h" 46 #include "citrus_mmap.h" 47 #include "citrus_module.h" 48 #include "citrus_hash.h" 49 #include "citrus_mapper.h" 50 #include "citrus_db.h" 51 #include "citrus_db_hash.h" 52 53 #include "citrus_mapper_std.h" 54 #include "citrus_mapper_std_file.h" 55 56 /* ---------------------------------------------------------------------- */ 57 58 _CITRUS_MAPPER_DECLS(mapper_std); 59 _CITRUS_MAPPER_DEF_OPS(mapper_std); 60 61 62 /* ---------------------------------------------------------------------- */ 63 64 int 65 _citrus_mapper_std_mapper_getops(struct _citrus_mapper_ops *ops) 66 { 67 68 memcpy(ops, &_citrus_mapper_std_mapper_ops, 69 sizeof(_citrus_mapper_std_mapper_ops)); 70 71 return (0); 72 } 73 74 /* ---------------------------------------------------------------------- */ 75 76 static int 77 /*ARGSUSED*/ 78 rowcol_convert(struct _citrus_mapper_std * __restrict ms, 79 _index_t * __restrict dst, _index_t src, void * __restrict ps __unused) 80 { 81 struct _citrus_mapper_std_linear_zone *lz; 82 struct _citrus_mapper_std_rowcol *rc; 83 _index_t idx = 0, n; 84 size_t i; 85 uint32_t conv; 86 87 /* ps may be unused */ 88 rc = &ms->ms_rowcol; 89 90 for (i = rc->rc_src_rowcol_len * rc->rc_src_rowcol_bits, 91 lz = &rc->rc_src_rowcol[0]; i > 0; ++lz) { 92 i -= rc->rc_src_rowcol_bits; 93 n = (src >> i) & rc->rc_src_rowcol_mask; 94 if (n < lz->begin || n > lz->end) { 95 switch (rc->rc_oob_mode) { 96 case _CITRUS_MAPPER_STD_OOB_NONIDENTICAL: 97 *dst = rc->rc_dst_invalid; 98 return (_MAPPER_CONVERT_NONIDENTICAL); 99 case _CITRUS_MAPPER_STD_OOB_ILSEQ: 100 return (_MAPPER_CONVERT_ILSEQ); 101 default: 102 return (_MAPPER_CONVERT_FATAL); 103 } 104 } 105 idx = idx * lz->width + n - lz->begin; 106 } 107 switch (rc->rc_dst_unit_bits) { 108 case 8: 109 conv = _region_peek8(&rc->rc_table, idx); 110 break; 111 case 16: 112 conv = be16toh(_region_peek16(&rc->rc_table, idx*2)); 113 break; 114 case 32: 115 conv = be32toh(_region_peek32(&rc->rc_table, idx*4)); 116 break; 117 default: 118 return (_MAPPER_CONVERT_FATAL); 119 } 120 121 if (conv == rc->rc_dst_invalid) { 122 *dst = rc->rc_dst_invalid; 123 return (_MAPPER_CONVERT_NONIDENTICAL); 124 } 125 if (conv == rc->rc_dst_ilseq) 126 return (_MAPPER_CONVERT_ILSEQ); 127 128 *dst = conv; 129 130 return (_MAPPER_CONVERT_SUCCESS); 131 } 132 133 static __inline int 134 set_linear_zone(struct _citrus_mapper_std_linear_zone *lz, 135 uint32_t begin, uint32_t end) 136 { 137 138 if (begin > end) 139 return (EFTYPE); 140 141 lz->begin = begin; 142 lz->end = end; 143 lz->width= end - begin + 1; 144 145 return (0); 146 } 147 148 static __inline int 149 rowcol_parse_variable_compat(struct _citrus_mapper_std_rowcol *rc, 150 struct _region *r) 151 { 152 const struct _citrus_mapper_std_rowcol_info_compat_x *rcx; 153 struct _citrus_mapper_std_linear_zone *lz; 154 uint32_t m, n; 155 int ret; 156 157 rcx = _region_head(r); 158 159 rc->rc_dst_invalid = be32toh(rcx->rcx_dst_invalid); 160 rc->rc_dst_unit_bits = be32toh(rcx->rcx_dst_unit_bits); 161 m = be32toh(rcx->rcx_src_col_bits); 162 n = 1 << (m - 1); 163 n |= n - 1; 164 rc->rc_src_rowcol_bits = m; 165 rc->rc_src_rowcol_mask = n; 166 167 rc->rc_src_rowcol = malloc(2 * 168 sizeof(*rc->rc_src_rowcol)); 169 if (rc->rc_src_rowcol == NULL) 170 return (ENOMEM); 171 lz = rc->rc_src_rowcol; 172 rc->rc_src_rowcol_len = 1; 173 m = be32toh(rcx->rcx_src_row_begin); 174 n = be32toh(rcx->rcx_src_row_end); 175 if (m + n > 0) { 176 ret = set_linear_zone(lz, m, n); 177 if (ret != 0) { 178 free(rc->rc_src_rowcol); 179 rc->rc_src_rowcol = NULL; 180 return (ret); 181 } 182 ++rc->rc_src_rowcol_len, ++lz; 183 } 184 m = be32toh(rcx->rcx_src_col_begin); 185 n = be32toh(rcx->rcx_src_col_end); 186 187 return (set_linear_zone(lz, m, n)); 188 } 189 190 static __inline int 191 rowcol_parse_variable(struct _citrus_mapper_std_rowcol *rc, 192 struct _region *r) 193 { 194 const struct _citrus_mapper_std_rowcol_info_x *rcx; 195 struct _citrus_mapper_std_linear_zone *lz; 196 size_t i; 197 uint32_t m, n; 198 int ret; 199 200 rcx = _region_head(r); 201 202 rc->rc_dst_invalid = be32toh(rcx->rcx_dst_invalid); 203 rc->rc_dst_unit_bits = be32toh(rcx->rcx_dst_unit_bits); 204 205 m = be32toh(rcx->rcx_src_rowcol_bits); 206 n = 1 << (m - 1); 207 n |= n - 1; 208 rc->rc_src_rowcol_bits = m; 209 rc->rc_src_rowcol_mask = n; 210 211 rc->rc_src_rowcol_len = be32toh(rcx->rcx_src_rowcol_len); 212 if (rc->rc_src_rowcol_len > _CITRUS_MAPPER_STD_ROWCOL_MAX) 213 return (EFTYPE); 214 rc->rc_src_rowcol = malloc(rc->rc_src_rowcol_len * 215 sizeof(*rc->rc_src_rowcol)); 216 if (rc->rc_src_rowcol == NULL) 217 return (ENOMEM); 218 for (i = 0, lz = rc->rc_src_rowcol; 219 i < rc->rc_src_rowcol_len; ++i, ++lz) { 220 m = be32toh(rcx->rcx_src_rowcol[i].begin), 221 n = be32toh(rcx->rcx_src_rowcol[i].end); 222 ret = set_linear_zone(lz, m, n); 223 if (ret != 0) { 224 free(rc->rc_src_rowcol); 225 rc->rc_src_rowcol = NULL; 226 return (ret); 227 } 228 } 229 return (0); 230 } 231 232 static void 233 rowcol_uninit(struct _citrus_mapper_std *ms) 234 { 235 struct _citrus_mapper_std_rowcol *rc; 236 237 rc = &ms->ms_rowcol; 238 free(rc->rc_src_rowcol); 239 } 240 241 static int 242 rowcol_init(struct _citrus_mapper_std *ms) 243 { 244 struct _citrus_mapper_std_linear_zone *lz; 245 struct _citrus_mapper_std_rowcol *rc; 246 const struct _citrus_mapper_std_rowcol_ext_ilseq_info_x *eix; 247 struct _region r; 248 uint64_t table_size; 249 size_t i; 250 int ret; 251 252 ms->ms_convert = &rowcol_convert; 253 ms->ms_uninit = &rowcol_uninit; 254 rc = &ms->ms_rowcol; 255 256 /* get table region */ 257 ret = _db_lookup_by_s(ms->ms_db, _CITRUS_MAPPER_STD_SYM_TABLE, 258 &rc->rc_table, NULL); 259 if (ret) { 260 if (ret == ENOENT) 261 ret = EFTYPE; 262 return (ret); 263 } 264 265 /* get table information */ 266 ret = _db_lookup_by_s(ms->ms_db, _CITRUS_MAPPER_STD_SYM_INFO, &r, NULL); 267 if (ret) { 268 if (ret == ENOENT) 269 ret = EFTYPE; 270 return (ret); 271 } 272 switch (_region_size(&r)) { 273 case _CITRUS_MAPPER_STD_ROWCOL_INFO_COMPAT_SIZE: 274 ret = rowcol_parse_variable_compat(rc, &r); 275 break; 276 case _CITRUS_MAPPER_STD_ROWCOL_INFO_SIZE: 277 ret = rowcol_parse_variable(rc, &r); 278 break; 279 default: 280 return (EFTYPE); 281 } 282 if (ret != 0) 283 return (ret); 284 /* sanity check */ 285 switch (rc->rc_src_rowcol_bits) { 286 case 8: case 16: case 32: 287 if (rc->rc_src_rowcol_len <= 32 / rc->rc_src_rowcol_bits) 288 break; 289 /*FALLTHROUGH*/ 290 default: 291 return (EFTYPE); 292 } 293 294 /* ilseq extension */ 295 rc->rc_oob_mode = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL; 296 rc->rc_dst_ilseq = rc->rc_dst_invalid; 297 ret = _db_lookup_by_s(ms->ms_db, 298 _CITRUS_MAPPER_STD_SYM_ROWCOL_EXT_ILSEQ, &r, NULL); 299 if (ret && ret != ENOENT) 300 return (ret); 301 if (_region_size(&r) < sizeof(*eix)) 302 return (EFTYPE); 303 if (ret == 0) { 304 eix = _region_head(&r); 305 rc->rc_oob_mode = be32toh(eix->eix_oob_mode); 306 rc->rc_dst_ilseq = be32toh(eix->eix_dst_ilseq); 307 } 308 309 /* calcurate expected table size */ 310 i = rc->rc_src_rowcol_len; 311 lz = &rc->rc_src_rowcol[--i]; 312 table_size = lz->width; 313 while (i > 0) { 314 lz = &rc->rc_src_rowcol[--i]; 315 table_size *= lz->width; 316 } 317 table_size *= rc->rc_dst_unit_bits/8; 318 319 if (table_size > UINT32_MAX || 320 _region_size(&rc->rc_table) < table_size) 321 return (EFTYPE); 322 323 return (0); 324 } 325 326 typedef int (*initfunc_t)(struct _citrus_mapper_std *); 327 static const struct { 328 initfunc_t t_init; 329 const char *t_name; 330 } types[] = { 331 { &rowcol_init, _CITRUS_MAPPER_STD_TYPE_ROWCOL }, 332 }; 333 #define NUM_OF_TYPES ((int)(sizeof(types)/sizeof(types[0]))) 334 335 static int 336 /*ARGSUSED*/ 337 _citrus_mapper_std_mapper_init(struct _citrus_mapper_area *__restrict ma __unused, 338 struct _citrus_mapper * __restrict cm, const char * __restrict curdir, 339 const void * __restrict var, size_t lenvar, 340 struct _citrus_mapper_traits * __restrict mt, size_t lenmt) 341 { 342 struct _citrus_mapper_std *ms; 343 char path[PATH_MAX]; 344 const char *type; 345 int id, ret; 346 347 /* set traits */ 348 if (lenmt < sizeof(*mt)) { 349 ret = EINVAL; 350 goto err0; 351 } 352 mt->mt_src_max = mt->mt_dst_max = 1; /* 1:1 converter */ 353 mt->mt_state_size = 0; /* stateless */ 354 355 /* alloc mapper std structure */ 356 ms = malloc(sizeof(*ms)); 357 if (ms == NULL) { 358 ret = errno; 359 goto err0; 360 } 361 362 /* open mapper file */ 363 snprintf(path, sizeof(path), "%s/%.*s", curdir, (int)lenvar, 364 (const char *)var); 365 ret = _map_file(&ms->ms_file, path); 366 if (ret) 367 goto err1; 368 369 ret = _db_open(&ms->ms_db, &ms->ms_file, _CITRUS_MAPPER_STD_MAGIC, 370 &_db_hash_std, NULL); 371 if (ret) 372 goto err2; 373 374 /* get mapper type */ 375 ret = _db_lookupstr_by_s(ms->ms_db, _CITRUS_MAPPER_STD_SYM_TYPE, 376 &type, NULL); 377 if (ret) { 378 if (ret == ENOENT) 379 ret = EFTYPE; 380 goto err3; 381 } 382 for (id = 0; id < NUM_OF_TYPES; id++) 383 if (_bcs_strcasecmp(type, types[id].t_name) == 0) 384 break; 385 386 if (id == NUM_OF_TYPES) 387 goto err3; 388 389 /* init the per-type structure */ 390 ret = (*types[id].t_init)(ms); 391 if (ret) 392 goto err3; 393 394 cm->cm_closure = ms; 395 396 return (0); 397 398 err3: 399 _db_close(ms->ms_db); 400 err2: 401 _unmap_file(&ms->ms_file); 402 err1: 403 free(ms); 404 err0: 405 return (ret); 406 } 407 408 static void 409 /*ARGSUSED*/ 410 _citrus_mapper_std_mapper_uninit(struct _citrus_mapper *cm) 411 { 412 struct _citrus_mapper_std *ms; 413 414 ms = cm->cm_closure; 415 if (ms->ms_uninit) 416 (*ms->ms_uninit)(ms); 417 _db_close(ms->ms_db); 418 _unmap_file(&ms->ms_file); 419 free(ms); 420 } 421 422 static void 423 /*ARGSUSED*/ 424 _citrus_mapper_std_mapper_init_state(void) 425 { 426 427 } 428 429 static int 430 /*ARGSUSED*/ 431 _citrus_mapper_std_mapper_convert(struct _citrus_mapper * __restrict cm, 432 _index_t * __restrict dst, _index_t src, void * __restrict ps) 433 { 434 struct _citrus_mapper_std *ms; 435 436 ms = cm->cm_closure; 437 return ((*ms->ms_convert)(ms, dst, src, ps)); 438 } 439