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