1 /* $NetBSD: citrus_mapper_zone.c,v 1.1 2003/06/25 09:51:48 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.1 2003/06/25 09:51:48 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 40 #include "citrus_namespace.h" 41 #include "citrus_types.h" 42 #include "citrus_bcs.h" 43 #include "citrus_module.h" 44 #include "citrus_region.h" 45 #include "citrus_memstream.h" 46 #include "citrus_mmap.h" 47 #include "citrus_hash.h" 48 #include "citrus_mapper.h" 49 #include "citrus_mapper_zone.h" 50 51 /* ---------------------------------------------------------------------- */ 52 53 _CITRUS_MAPPER_DECLS(mapper_zone); 54 _CITRUS_MAPPER_DEF_OPS(mapper_zone); 55 56 57 /* ---------------------------------------------------------------------- */ 58 59 struct _zone { 60 u_int32_t z_begin; 61 u_int32_t z_end; 62 }; 63 64 struct _citrus_mapper_zone { 65 struct _zone mz_row; 66 struct _zone mz_col; 67 int mz_col_bits; 68 int32_t mz_row_offset; 69 int32_t mz_col_offset; 70 }; 71 72 struct _parse_state { 73 enum { S_BEGIN, S_OFFSET } ps_state; 74 union { 75 u_int32_t u_imm; 76 int32_t s_imm; 77 struct _zone zone; 78 } u; 79 #define ps_u_imm u.u_imm 80 #define ps_s_imm u.s_imm 81 #define ps_zone u.zone 82 int ps_top; 83 }; 84 85 int 86 _citrus_mapper_zone_mapper_getops(struct _citrus_mapper_ops *ops, 87 size_t lenops, uint32_t expected_version) 88 { 89 if (expected_version<_CITRUS_MAPPER_ABI_VERSION || lenops<sizeof(*ops)) 90 return EINVAL; 91 92 memcpy(ops, &_citrus_mapper_zone_mapper_ops, 93 sizeof(_citrus_mapper_zone_mapper_ops)); 94 95 return 0; 96 } 97 98 #define BUFSIZE 20 99 #define T_ERR 0x100 100 #define T_IMM 0x101 101 102 static int 103 get_imm(struct _memstream *ms, struct _parse_state *ps) 104 { 105 int sign = 0; 106 int c, i; 107 char buf[BUFSIZE+1], *p; 108 109 for (i=0; i<BUFSIZE; i++) { 110 retry: 111 c = _memstream_peek(ms); 112 if (i==0) { 113 if (sign == 0 && (c == '+' || c == '-')) { 114 sign = c; 115 _memstream_getc(ms); 116 goto retry; 117 } else if (!_bcs_isdigit(c)) 118 break; 119 } else if (!_bcs_isxdigit(c)) 120 if (!(i==1 && c == 'x')) 121 break; 122 buf[i] = _memstream_getc(ms); 123 } 124 buf[i] = '\0'; 125 ps->ps_u_imm = strtoul(buf, &p, 0); 126 if ((p-buf) != i) 127 return T_ERR; 128 if (sign == '-') 129 ps->ps_u_imm = (unsigned long)-(long)ps->ps_u_imm; 130 return T_IMM; 131 } 132 133 static int 134 get_tok(struct _memstream *ms, struct _parse_state *ps) 135 { 136 int c; 137 138 loop: 139 c = _memstream_peek(ms); 140 if (c==0x00) 141 return EOF; 142 if (_bcs_isspace(c)) { 143 _memstream_getc(ms); 144 goto loop; 145 } 146 147 switch (ps->ps_state) { 148 case S_BEGIN: 149 switch (c) { 150 case ':': 151 case '-': 152 case '/': 153 _memstream_getc(ms); 154 return c; 155 case '0': 156 case '1': 157 case '2': 158 case '3': 159 case '4': 160 case '5': 161 case '6': 162 case '7': 163 case '8': 164 case '9': 165 return get_imm(ms, ps); 166 } 167 break; 168 case S_OFFSET: 169 switch (c) { 170 case '/': 171 _memstream_getc(ms); 172 return c; 173 case '+': 174 case '-': 175 case '0': 176 case '1': 177 case '2': 178 case '3': 179 case '4': 180 case '5': 181 case '6': 182 case '7': 183 case '8': 184 case '9': 185 return get_imm(ms, ps); 186 } 187 break; 188 } 189 return T_ERR; 190 } 191 192 static int 193 parse_zone(struct _memstream *ms, struct _parse_state *ps, struct _zone *z) 194 { 195 if (get_tok(ms, ps) != T_IMM) 196 return -1; 197 z->z_begin = ps->ps_u_imm; 198 if (get_tok(ms, ps) != '-') 199 return -1; 200 if (get_tok(ms, ps) != T_IMM) 201 return -1; 202 z->z_end = ps->ps_u_imm; 203 204 if (z->z_begin > z->z_end) 205 return -1; 206 207 return 0; 208 } 209 210 static int 211 check_rowcol(struct _zone *z, int32_t ofs, uint32_t maxval) 212 { 213 u_int32_t remain; 214 215 if (maxval != 0 && z->z_end >= maxval) 216 return -1; 217 218 if (ofs > 0) { 219 if (maxval == 0) { 220 /* this should 0x100000000 - z->z_end */ 221 if (z->z_end == 0) { 222 remain = 0xFFFFFFFF; 223 } else { 224 remain = 0xFFFFFFFF - z->z_end + 1; 225 } 226 } else 227 remain = maxval - z->z_end; 228 if ((u_int32_t)ofs > remain) 229 return -1; 230 } else if (ofs < 0) { 231 if (z->z_begin < (u_int32_t)-ofs) 232 return -1; 233 } 234 235 return 0; 236 } 237 238 static int 239 parse_var(struct _citrus_mapper_zone *mz, struct _memstream *ms) 240 { 241 struct _parse_state ps; 242 int ret, isrc; 243 uint32_t rowmax, colmax; 244 245 ps.ps_state = S_BEGIN; 246 247 if (parse_zone(ms, &ps, &mz->mz_col)) 248 return -1; 249 250 ret = get_tok(ms, &ps); 251 if (ret == '/') { 252 /* rowzone / colzone / bits */ 253 isrc = 1; 254 mz->mz_row = mz->mz_col; 255 256 if (parse_zone(ms, &ps, &mz->mz_col)) 257 return -1; 258 if (get_tok(ms, &ps) != '/') 259 return -1; 260 if (get_tok(ms, &ps) != T_IMM) 261 return -1; 262 mz->mz_col_bits = ps.ps_u_imm; 263 if (mz->mz_col_bits<0 || mz->mz_col_bits>32) 264 return -1; 265 ret = get_tok(ms, &ps); 266 } else { 267 /* colzone */ 268 isrc = 0; 269 mz->mz_col_bits = 32; 270 mz->mz_row.z_begin = mz->mz_row.z_end = 0; 271 } 272 if (ret == ':') { 273 /* offset */ 274 ps.ps_state = S_OFFSET; 275 if (get_tok(ms, &ps) != T_IMM) 276 return -1; 277 mz->mz_col_offset = ps.ps_s_imm; 278 if (isrc) { 279 /* row/col */ 280 mz->mz_row_offset = mz->mz_col_offset; 281 if (get_tok(ms, &ps) != '/') 282 return -1; 283 if (get_tok(ms, &ps) != T_IMM) 284 return -1; 285 mz->mz_col_offset = ps.ps_s_imm; 286 } else 287 mz->mz_row_offset = 0; 288 ret = get_tok(ms, &ps); 289 } 290 if (ret != EOF) 291 return -1; 292 293 /* sanity check */ 294 if (mz->mz_col_bits==32) 295 colmax = 0; 296 else 297 colmax = 1 << mz->mz_col_bits; 298 if (mz->mz_col_bits==0) 299 rowmax = 0; 300 else 301 rowmax = 1 << (32-mz->mz_col_bits); 302 if (check_rowcol(&mz->mz_col, mz->mz_col_offset, colmax)) 303 return -1; 304 if (check_rowcol(&mz->mz_row, mz->mz_row_offset, rowmax)) 305 return -1; 306 307 return 0; 308 } 309 310 static int 311 /*ARGSUSED*/ 312 _citrus_mapper_zone_mapper_init(struct _citrus_mapper_area *__restrict ma, 313 struct _citrus_mapper * __restrict cm, 314 const char * __restrict dir, 315 const void * __restrict var, size_t lenvar, 316 struct _citrus_mapper_traits * __restrict mt, 317 size_t lenmt) 318 { 319 struct _citrus_mapper_zone *mz; 320 struct _memstream ms; 321 struct _region r; 322 323 _DIAGASSERT(cm && dir && mt); 324 325 if (lenmt<sizeof(*mt)) 326 return EINVAL; 327 328 mz = malloc(sizeof(*mz)); 329 if (mz == NULL) 330 return errno; 331 332 _region_init(&r, (void *)var, lenvar); 333 _memstream_bind(&ms, &r); 334 if (parse_var(mz, &ms)) { 335 free(mz); 336 return EINVAL; 337 } 338 cm->cm_closure = mz; 339 mt->mt_src_max = mt->mt_dst_max = 1; /* 1:1 converter */ 340 mt->mt_state_size = 0; /* stateless */ 341 342 return 0; 343 } 344 345 static void 346 /*ARGSUSED*/ 347 _citrus_mapper_zone_mapper_uninit(struct _citrus_mapper *cm) 348 { 349 } 350 351 static int 352 /*ARGSUSED*/ 353 _citrus_mapper_zone_mapper_convert(struct _citrus_mapper * __restrict cm, 354 _citrus_index_t * __restrict dst, 355 _citrus_index_t src, void * __restrict ps) 356 { 357 u_int32_t row, col; 358 struct _citrus_mapper_zone *mz = cm->cm_closure; 359 360 if (mz->mz_col_bits == 32) { 361 col = src; 362 row = 0; 363 if (col < mz->mz_col.z_begin || col > mz->mz_col.z_end) 364 return _CITRUS_MAPPER_CONVERT_INVAL; 365 if (mz->mz_col_offset>0) 366 col += (u_int32_t)mz->mz_col_offset; 367 else 368 col -= (u_int32_t)-mz->mz_col_offset; 369 *dst = col; 370 } else { 371 col = src & (((u_int32_t)1<<mz->mz_col_bits)-1); 372 row = src >> mz->mz_col_bits; 373 if (row < mz->mz_row.z_begin || row > mz->mz_row.z_end || 374 col < mz->mz_col.z_begin || col > mz->mz_col.z_end) 375 return _CITRUS_MAPPER_CONVERT_INVAL; 376 if (mz->mz_col_offset>0) 377 col += (u_int32_t)mz->mz_col_offset; 378 else 379 col -= (u_int32_t)-mz->mz_col_offset; 380 if (mz->mz_row_offset>0) 381 row += (u_int32_t)mz->mz_row_offset; 382 else 383 row -= (u_int32_t)-mz->mz_row_offset; 384 *dst = col | (row << mz->mz_col_bits); 385 } 386 return _CITRUS_MAPPER_CONVERT_SUCCESS; 387 } 388 389 static void 390 /*ARGSUSED*/ 391 _citrus_mapper_zone_mapper_init_state(struct _citrus_mapper * __restrict cm, 392 void * __restrict ps) 393 { 394 } 395