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