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