1 /* $NetBSD: citrus_mapper_zone.c,v 1.4 2003/07/12 15:39:21 tshiozak Exp $ */ 2 3 /*- 4 * Copyright (c)2003 Citrus Project, 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 #if defined(LIBC_SCCS) && !defined(lint) 31 __RCSID("$NetBSD: citrus_mapper_zone.c,v 1.4 2003/07/12 15:39:21 tshiozak Exp $"); 32 #endif /* LIBC_SCCS and not lint */ 33 34 #include <assert.h> 35 #include <errno.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <sys/queue.h> 40 41 #include "citrus_namespace.h" 42 #include "citrus_types.h" 43 #include "citrus_bcs.h" 44 #include "citrus_module.h" 45 #include "citrus_region.h" 46 #include "citrus_memstream.h" 47 #include "citrus_mmap.h" 48 #include "citrus_hash.h" 49 #include "citrus_mapper.h" 50 #include "citrus_mapper_zone.h" 51 52 /* ---------------------------------------------------------------------- */ 53 54 _CITRUS_MAPPER_DECLS(mapper_zone); 55 _CITRUS_MAPPER_DEF_OPS(mapper_zone); 56 57 58 /* ---------------------------------------------------------------------- */ 59 60 struct _zone { 61 u_int32_t z_begin; 62 u_int32_t z_end; 63 }; 64 65 struct _citrus_mapper_zone { 66 struct _zone mz_row; 67 struct _zone mz_col; 68 int mz_col_bits; 69 int32_t mz_row_offset; 70 int32_t mz_col_offset; 71 }; 72 73 struct _parse_state { 74 enum { S_BEGIN, S_OFFSET } ps_state; 75 union { 76 u_int32_t u_imm; 77 int32_t s_imm; 78 struct _zone zone; 79 } u; 80 #define ps_u_imm u.u_imm 81 #define ps_s_imm u.s_imm 82 #define ps_zone u.zone 83 int ps_top; 84 }; 85 86 int 87 _citrus_mapper_zone_mapper_getops(struct _citrus_mapper_ops *ops, 88 size_t lenops, uint32_t expected_version) 89 { 90 if (expected_version<_CITRUS_MAPPER_ABI_VERSION || lenops<sizeof(*ops)) 91 return EINVAL; 92 93 memcpy(ops, &_citrus_mapper_zone_mapper_ops, 94 sizeof(_citrus_mapper_zone_mapper_ops)); 95 96 return 0; 97 } 98 99 #define BUFSIZE 20 100 #define T_ERR 0x100 101 #define T_IMM 0x101 102 103 static int 104 get_imm(struct _memstream *ms, struct _parse_state *ps) 105 { 106 int sign = 0; 107 int c, i; 108 char buf[BUFSIZE+1], *p; 109 110 for (i=0; i<BUFSIZE; i++) { 111 retry: 112 c = _memstream_peek(ms); 113 if (i==0) { 114 if (sign == 0 && (c == '+' || c == '-')) { 115 sign = c; 116 _memstream_getc(ms); 117 goto retry; 118 } else if (!_bcs_isdigit(c)) 119 break; 120 } else if (!_bcs_isxdigit(c)) 121 if (!(i==1 && c == 'x')) 122 break; 123 buf[i] = _memstream_getc(ms); 124 } 125 buf[i] = '\0'; 126 ps->ps_u_imm = strtoul(buf, &p, 0); 127 if ((p-buf) != i) 128 return T_ERR; 129 if (sign == '-') 130 ps->ps_u_imm = (unsigned long)-(long)ps->ps_u_imm; 131 return T_IMM; 132 } 133 134 static int 135 get_tok(struct _memstream *ms, struct _parse_state *ps) 136 { 137 int c; 138 139 loop: 140 c = _memstream_peek(ms); 141 if (c==0x00) 142 return EOF; 143 if (_bcs_isspace(c)) { 144 _memstream_getc(ms); 145 goto loop; 146 } 147 148 switch (ps->ps_state) { 149 case S_BEGIN: 150 switch (c) { 151 case ':': 152 case '-': 153 case '/': 154 _memstream_getc(ms); 155 return c; 156 case '0': 157 case '1': 158 case '2': 159 case '3': 160 case '4': 161 case '5': 162 case '6': 163 case '7': 164 case '8': 165 case '9': 166 return get_imm(ms, ps); 167 } 168 break; 169 case S_OFFSET: 170 switch (c) { 171 case '/': 172 _memstream_getc(ms); 173 return c; 174 case '+': 175 case '-': 176 case '0': 177 case '1': 178 case '2': 179 case '3': 180 case '4': 181 case '5': 182 case '6': 183 case '7': 184 case '8': 185 case '9': 186 return get_imm(ms, ps); 187 } 188 break; 189 } 190 return T_ERR; 191 } 192 193 static int 194 parse_zone(struct _memstream *ms, struct _parse_state *ps, struct _zone *z) 195 { 196 if (get_tok(ms, ps) != T_IMM) 197 return -1; 198 z->z_begin = ps->ps_u_imm; 199 if (get_tok(ms, ps) != '-') 200 return -1; 201 if (get_tok(ms, ps) != T_IMM) 202 return -1; 203 z->z_end = ps->ps_u_imm; 204 205 if (z->z_begin > z->z_end) 206 return -1; 207 208 return 0; 209 } 210 211 static int 212 check_rowcol(struct _zone *z, int32_t ofs, uint32_t maxval) 213 { 214 u_int32_t remain; 215 216 if (maxval != 0 && z->z_end >= maxval) 217 return -1; 218 219 if (ofs > 0) { 220 if (maxval == 0) { 221 /* this should 0x100000000 - z->z_end */ 222 if (z->z_end == 0) { 223 remain = 0xFFFFFFFF; 224 } else { 225 remain = 0xFFFFFFFF - z->z_end + 1; 226 } 227 } else 228 remain = maxval - z->z_end; 229 if ((u_int32_t)ofs > remain) 230 return -1; 231 } else if (ofs < 0) { 232 if (z->z_begin < (u_int32_t)-ofs) 233 return -1; 234 } 235 236 return 0; 237 } 238 239 static int 240 parse_var(struct _citrus_mapper_zone *mz, struct _memstream *ms) 241 { 242 struct _parse_state ps; 243 int ret, isrc; 244 uint32_t rowmax, colmax; 245 246 ps.ps_state = S_BEGIN; 247 248 if (parse_zone(ms, &ps, &mz->mz_col)) 249 return -1; 250 251 ret = get_tok(ms, &ps); 252 if (ret == '/') { 253 /* rowzone / colzone / bits */ 254 isrc = 1; 255 mz->mz_row = mz->mz_col; 256 257 if (parse_zone(ms, &ps, &mz->mz_col)) 258 return -1; 259 if (get_tok(ms, &ps) != '/') 260 return -1; 261 if (get_tok(ms, &ps) != T_IMM) 262 return -1; 263 mz->mz_col_bits = ps.ps_u_imm; 264 if (mz->mz_col_bits<0 || mz->mz_col_bits>32) 265 return -1; 266 ret = get_tok(ms, &ps); 267 } else { 268 /* colzone */ 269 isrc = 0; 270 mz->mz_col_bits = 32; 271 mz->mz_row.z_begin = mz->mz_row.z_end = 0; 272 } 273 if (ret == ':') { 274 /* offset */ 275 ps.ps_state = S_OFFSET; 276 if (get_tok(ms, &ps) != T_IMM) 277 return -1; 278 mz->mz_col_offset = ps.ps_s_imm; 279 if (isrc) { 280 /* row/col */ 281 mz->mz_row_offset = mz->mz_col_offset; 282 if (get_tok(ms, &ps) != '/') 283 return -1; 284 if (get_tok(ms, &ps) != T_IMM) 285 return -1; 286 mz->mz_col_offset = ps.ps_s_imm; 287 } else 288 mz->mz_row_offset = 0; 289 ret = get_tok(ms, &ps); 290 } 291 if (ret != EOF) 292 return -1; 293 294 /* sanity check */ 295 if (mz->mz_col_bits==32) 296 colmax = 0; 297 else 298 colmax = 1 << mz->mz_col_bits; 299 if (mz->mz_col_bits==0) 300 rowmax = 0; 301 else 302 rowmax = 1 << (32-mz->mz_col_bits); 303 if (check_rowcol(&mz->mz_col, mz->mz_col_offset, colmax)) 304 return -1; 305 if (check_rowcol(&mz->mz_row, mz->mz_row_offset, rowmax)) 306 return -1; 307 308 return 0; 309 } 310 311 static int 312 /*ARGSUSED*/ 313 _citrus_mapper_zone_mapper_init(struct _citrus_mapper_area *__restrict ma, 314 struct _citrus_mapper * __restrict cm, 315 const char * __restrict dir, 316 const void * __restrict var, size_t lenvar, 317 struct _citrus_mapper_traits * __restrict mt, 318 size_t lenmt) 319 { 320 struct _citrus_mapper_zone *mz; 321 struct _memstream ms; 322 struct _region r; 323 324 _DIAGASSERT(cm && dir && mt); 325 326 if (lenmt<sizeof(*mt)) 327 return EINVAL; 328 329 mz = malloc(sizeof(*mz)); 330 if (mz == NULL) 331 return errno; 332 333 mz->mz_col.z_begin = mz->mz_col.z_end = 0; 334 mz->mz_row.z_begin = mz->mz_row.z_end = 0; 335 mz->mz_col_bits = 0; 336 mz->mz_row_offset = 0; 337 mz->mz_col_offset = 0; 338 339 _region_init(&r, (void *)var, lenvar); 340 _memstream_bind(&ms, &r); 341 if (parse_var(mz, &ms)) { 342 free(mz); 343 return EINVAL; 344 } 345 cm->cm_closure = mz; 346 mt->mt_src_max = mt->mt_dst_max = 1; /* 1:1 converter */ 347 mt->mt_state_size = 0; /* stateless */ 348 349 return 0; 350 } 351 352 static void 353 /*ARGSUSED*/ 354 _citrus_mapper_zone_mapper_uninit(struct _citrus_mapper *cm) 355 { 356 } 357 358 static int 359 /*ARGSUSED*/ 360 _citrus_mapper_zone_mapper_convert(struct _citrus_mapper * __restrict cm, 361 _citrus_index_t * __restrict dst, 362 _citrus_index_t src, void * __restrict ps) 363 { 364 u_int32_t row, col; 365 struct _citrus_mapper_zone *mz = cm->cm_closure; 366 367 if (mz->mz_col_bits == 32) { 368 col = src; 369 row = 0; 370 if (col < mz->mz_col.z_begin || col > mz->mz_col.z_end) 371 return _CITRUS_MAPPER_CONVERT_NONIDENTICAL; 372 if (mz->mz_col_offset>0) 373 col += (u_int32_t)mz->mz_col_offset; 374 else 375 col -= (u_int32_t)-mz->mz_col_offset; 376 *dst = col; 377 } else { 378 col = src & (((u_int32_t)1<<mz->mz_col_bits)-1); 379 row = src >> mz->mz_col_bits; 380 if (row < mz->mz_row.z_begin || row > mz->mz_row.z_end || 381 col < mz->mz_col.z_begin || col > mz->mz_col.z_end) 382 return _CITRUS_MAPPER_CONVERT_NONIDENTICAL; 383 if (mz->mz_col_offset>0) 384 col += (u_int32_t)mz->mz_col_offset; 385 else 386 col -= (u_int32_t)-mz->mz_col_offset; 387 if (mz->mz_row_offset>0) 388 row += (u_int32_t)mz->mz_row_offset; 389 else 390 row -= (u_int32_t)-mz->mz_row_offset; 391 *dst = col | (row << mz->mz_col_bits); 392 } 393 return _CITRUS_MAPPER_CONVERT_SUCCESS; 394 } 395 396 static void 397 /*ARGSUSED*/ 398 _citrus_mapper_zone_mapper_init_state(struct _citrus_mapper * __restrict cm, 399 void * __restrict ps) 400 { 401 } 402