1 /* $FreeBSD$ */ 2 /* $NetBSD: citrus_mapper_std.c,v 1.8 2006/09/11 13:06:33 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 return (ret); 179 ++rc->rc_src_rowcol_len, ++lz; 180 } 181 m = be32toh(rcx->rcx_src_col_begin); 182 n = be32toh(rcx->rcx_src_col_end); 183 184 return (set_linear_zone(lz, m, n)); 185 } 186 187 static __inline int 188 rowcol_parse_variable(struct _citrus_mapper_std_rowcol *rc, 189 struct _region *r) 190 { 191 const struct _citrus_mapper_std_rowcol_info_x *rcx; 192 struct _citrus_mapper_std_linear_zone *lz; 193 size_t i; 194 uint32_t m, n; 195 int ret; 196 197 rcx = _region_head(r); 198 199 rc->rc_dst_invalid = be32toh(rcx->rcx_dst_invalid); 200 rc->rc_dst_unit_bits = be32toh(rcx->rcx_dst_unit_bits); 201 202 m = be32toh(rcx->rcx_src_rowcol_bits); 203 n = 1 << (m - 1); 204 n |= n - 1; 205 rc->rc_src_rowcol_bits = m; 206 rc->rc_src_rowcol_mask = n; 207 208 rc->rc_src_rowcol_len = be32toh(rcx->rcx_src_rowcol_len); 209 if (rc->rc_src_rowcol_len > _CITRUS_MAPPER_STD_ROWCOL_MAX) 210 return (EFTYPE); 211 rc->rc_src_rowcol = malloc(rc->rc_src_rowcol_len * 212 sizeof(*rc->rc_src_rowcol)); 213 if (rc->rc_src_rowcol == NULL) 214 return (ENOMEM); 215 for (i = 0, lz = rc->rc_src_rowcol; 216 i < rc->rc_src_rowcol_len; ++i, ++lz) { 217 m = be32toh(rcx->rcx_src_rowcol[i].begin), 218 n = be32toh(rcx->rcx_src_rowcol[i].end); 219 ret = set_linear_zone(lz, m, n); 220 if (ret != 0) { 221 free(rc->rc_src_rowcol); 222 rc->rc_src_rowcol = NULL; 223 return (ret); 224 } 225 } 226 return (0); 227 } 228 229 static void 230 rowcol_uninit(struct _citrus_mapper_std *ms) 231 { 232 struct _citrus_mapper_std_rowcol *rc; 233 234 rc = &ms->ms_rowcol; 235 free(rc->rc_src_rowcol); 236 } 237 238 static int 239 rowcol_init(struct _citrus_mapper_std *ms) 240 { 241 struct _citrus_mapper_std_linear_zone *lz; 242 struct _citrus_mapper_std_rowcol *rc; 243 const struct _citrus_mapper_std_rowcol_ext_ilseq_info_x *eix; 244 struct _region r; 245 uint64_t table_size; 246 size_t i; 247 int ret; 248 249 ms->ms_convert = &rowcol_convert; 250 ms->ms_uninit = &rowcol_uninit; 251 rc = &ms->ms_rowcol; 252 253 /* get table region */ 254 ret = _db_lookup_by_s(ms->ms_db, _CITRUS_MAPPER_STD_SYM_TABLE, 255 &rc->rc_table, NULL); 256 if (ret) { 257 if (ret == ENOENT) 258 ret = EFTYPE; 259 return (ret); 260 } 261 262 /* get table information */ 263 ret = _db_lookup_by_s(ms->ms_db, _CITRUS_MAPPER_STD_SYM_INFO, &r, NULL); 264 if (ret) { 265 if (ret == ENOENT) 266 ret = EFTYPE; 267 return (ret); 268 } 269 switch (_region_size(&r)) { 270 case _CITRUS_MAPPER_STD_ROWCOL_INFO_COMPAT_SIZE: 271 ret = rowcol_parse_variable_compat(rc, &r); 272 break; 273 case _CITRUS_MAPPER_STD_ROWCOL_INFO_SIZE: 274 ret = rowcol_parse_variable(rc, &r); 275 break; 276 default: 277 return (EFTYPE); 278 } 279 if (ret != 0) 280 return (ret); 281 /* sanity check */ 282 switch (rc->rc_src_rowcol_bits) { 283 case 8: case 16: case 32: 284 if (rc->rc_src_rowcol_len <= 32 / rc->rc_src_rowcol_bits) 285 break; 286 /*FALLTHROUGH*/ 287 default: 288 return (EFTYPE); 289 } 290 291 /* ilseq extension */ 292 rc->rc_oob_mode = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL; 293 rc->rc_dst_ilseq = rc->rc_dst_invalid; 294 ret = _db_lookup_by_s(ms->ms_db, 295 _CITRUS_MAPPER_STD_SYM_ROWCOL_EXT_ILSEQ, &r, NULL); 296 if (ret && ret != ENOENT) 297 return (ret); 298 if (_region_size(&r) < sizeof(*eix)) 299 return (EFTYPE); 300 if (ret == 0) { 301 eix = _region_head(&r); 302 rc->rc_oob_mode = be32toh(eix->eix_oob_mode); 303 rc->rc_dst_ilseq = be32toh(eix->eix_dst_ilseq); 304 } 305 306 /* calcurate expected table size */ 307 i = rc->rc_src_rowcol_len; 308 lz = &rc->rc_src_rowcol[--i]; 309 table_size = lz->width; 310 while (i > 0) { 311 lz = &rc->rc_src_rowcol[--i]; 312 table_size *= lz->width; 313 } 314 table_size *= rc->rc_dst_unit_bits/8; 315 316 if (table_size > UINT32_MAX || 317 _region_size(&rc->rc_table) < table_size) 318 return (EFTYPE); 319 320 return (0); 321 } 322 323 typedef int (*initfunc_t)(struct _citrus_mapper_std *); 324 static const struct { 325 initfunc_t t_init; 326 const char *t_name; 327 } types[] = { 328 { &rowcol_init, _CITRUS_MAPPER_STD_TYPE_ROWCOL }, 329 }; 330 #define NUM_OF_TYPES ((int)(sizeof(types)/sizeof(types[0]))) 331 332 static int 333 /*ARGSUSED*/ 334 _citrus_mapper_std_mapper_init(struct _citrus_mapper_area *__restrict ma __unused, 335 struct _citrus_mapper * __restrict cm, const char * __restrict curdir, 336 const void * __restrict var, size_t lenvar, 337 struct _citrus_mapper_traits * __restrict mt, size_t lenmt) 338 { 339 struct _citrus_mapper_std *ms; 340 char path[PATH_MAX]; 341 const char *type; 342 int id, ret; 343 344 /* set traits */ 345 if (lenmt < sizeof(*mt)) { 346 ret = EINVAL; 347 goto err0; 348 } 349 mt->mt_src_max = mt->mt_dst_max = 1; /* 1:1 converter */ 350 mt->mt_state_size = 0; /* stateless */ 351 352 /* alloc mapper std structure */ 353 ms = malloc(sizeof(*ms)); 354 if (ms == NULL) { 355 ret = errno; 356 goto err0; 357 } 358 359 /* open mapper file */ 360 snprintf(path, sizeof(path), "%s/%.*s", curdir, (int)lenvar, 361 (const char *)var); 362 ret = _map_file(&ms->ms_file, path); 363 if (ret) 364 goto err1; 365 366 ret = _db_open(&ms->ms_db, &ms->ms_file, _CITRUS_MAPPER_STD_MAGIC, 367 &_db_hash_std, NULL); 368 if (ret) 369 goto err2; 370 371 /* get mapper type */ 372 ret = _db_lookupstr_by_s(ms->ms_db, _CITRUS_MAPPER_STD_SYM_TYPE, 373 &type, NULL); 374 if (ret) { 375 if (ret == ENOENT) 376 ret = EFTYPE; 377 goto err3; 378 } 379 for (id = 0; id < NUM_OF_TYPES; id++) 380 if (_bcs_strcasecmp(type, types[id].t_name) == 0) 381 break; 382 383 if (id == NUM_OF_TYPES) 384 goto err3; 385 386 /* init the per-type structure */ 387 ret = (*types[id].t_init)(ms); 388 if (ret) 389 goto err3; 390 391 cm->cm_closure = ms; 392 393 return (0); 394 395 err3: 396 _db_close(ms->ms_db); 397 err2: 398 _unmap_file(&ms->ms_file); 399 err1: 400 free(ms); 401 err0: 402 return (ret); 403 } 404 405 static void 406 /*ARGSUSED*/ 407 _citrus_mapper_std_mapper_uninit(struct _citrus_mapper *cm) 408 { 409 struct _citrus_mapper_std *ms; 410 411 ms = cm->cm_closure; 412 if (ms->ms_uninit) 413 (*ms->ms_uninit)(ms); 414 _db_close(ms->ms_db); 415 _unmap_file(&ms->ms_file); 416 free(ms); 417 } 418 419 static void 420 /*ARGSUSED*/ 421 _citrus_mapper_std_mapper_init_state(void) 422 { 423 424 } 425 426 static int 427 /*ARGSUSED*/ 428 _citrus_mapper_std_mapper_convert(struct _citrus_mapper * __restrict cm, 429 _index_t * __restrict dst, _index_t src, void * __restrict ps) 430 { 431 struct _citrus_mapper_std *ms; 432 433 ms = cm->cm_closure; 434 return ((*ms->ms_convert)(ms, dst, src, ps)); 435 } 436