1219019Sgabor/* $FreeBSD$ */ 2219019Sgabor/* $NetBSD: citrus_mapper_zone.c,v 1.4 2003/07/12 15:39:21 tshiozak Exp $ */ 3219019Sgabor 4219019Sgabor/*- 5219019Sgabor * Copyright (c)2003 Citrus Project, 6219019Sgabor * All rights reserved. 7219019Sgabor * 8219019Sgabor * Redistribution and use in source and binary forms, with or without 9219019Sgabor * modification, are permitted provided that the following conditions 10219019Sgabor * are met: 11219019Sgabor * 1. Redistributions of source code must retain the above copyright 12219019Sgabor * notice, this list of conditions and the following disclaimer. 13219019Sgabor * 2. Redistributions in binary form must reproduce the above copyright 14219019Sgabor * notice, this list of conditions and the following disclaimer in the 15219019Sgabor * documentation and/or other materials provided with the distribution. 16219019Sgabor * 17219019Sgabor * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18219019Sgabor * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19219019Sgabor * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20219019Sgabor * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21219019Sgabor * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22219019Sgabor * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23219019Sgabor * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24219019Sgabor * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25219019Sgabor * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26219019Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27219019Sgabor * SUCH DAMAGE. 28219019Sgabor */ 29219019Sgabor 30219019Sgabor#include <sys/cdefs.h> 31219019Sgabor#include <sys/queue.h> 32219019Sgabor 33219019Sgabor#include <assert.h> 34219019Sgabor#include <errno.h> 35219019Sgabor#include <stdio.h> 36219019Sgabor#include <stdlib.h> 37219019Sgabor#include <string.h> 38219019Sgabor 39219019Sgabor#include "citrus_namespace.h" 40219019Sgabor#include "citrus_types.h" 41219019Sgabor#include "citrus_bcs.h" 42219019Sgabor#include "citrus_module.h" 43219019Sgabor#include "citrus_region.h" 44219019Sgabor#include "citrus_memstream.h" 45219019Sgabor#include "citrus_mmap.h" 46219019Sgabor#include "citrus_hash.h" 47219019Sgabor#include "citrus_mapper.h" 48219019Sgabor#include "citrus_mapper_zone.h" 49219019Sgabor 50219019Sgabor/* ---------------------------------------------------------------------- */ 51219019Sgabor 52219019Sgabor_CITRUS_MAPPER_DECLS(mapper_zone); 53219019Sgabor_CITRUS_MAPPER_DEF_OPS(mapper_zone); 54219019Sgabor 55219019Sgabor 56219019Sgabor/* ---------------------------------------------------------------------- */ 57219019Sgabor 58219019Sgaborstruct _zone { 59219019Sgabor uint32_t z_begin; 60219019Sgabor uint32_t z_end; 61219019Sgabor}; 62219019Sgabor 63219019Sgaborstruct _citrus_mapper_zone { 64219019Sgabor struct _zone mz_col; 65219019Sgabor struct _zone mz_row; 66219019Sgabor int32_t mz_col_offset; 67219019Sgabor int32_t mz_row_offset; 68219019Sgabor int mz_col_bits; 69219019Sgabor}; 70219019Sgabor 71219019Sgaborstruct _parse_state { 72219019Sgabor enum { S_BEGIN, S_OFFSET } ps_state; 73219019Sgabor union { 74219019Sgabor uint32_t u_imm; 75219019Sgabor int32_t s_imm; 76219019Sgabor struct _zone zone; 77219019Sgabor } u; 78219019Sgabor#define ps_u_imm u.u_imm 79219019Sgabor#define ps_s_imm u.s_imm 80219019Sgabor#define ps_zone u.zone 81219019Sgabor int ps_top; 82219019Sgabor}; 83219019Sgabor 84219019Sgaborint 85219019Sgabor_citrus_mapper_zone_mapper_getops(struct _citrus_mapper_ops *ops) 86219019Sgabor{ 87219019Sgabor 88219019Sgabor memcpy(ops, &_citrus_mapper_zone_mapper_ops, 89219019Sgabor sizeof(_citrus_mapper_zone_mapper_ops)); 90219019Sgabor 91219019Sgabor return (0); 92219019Sgabor} 93219019Sgabor 94219019Sgabor#define BUFSIZE 20 95219019Sgabor#define T_ERR 0x100 96219019Sgabor#define T_IMM 0x101 97219019Sgabor 98219019Sgaborstatic int 99219019Sgaborget_imm(struct _memstream *ms, struct _parse_state *ps) 100219019Sgabor{ 101219019Sgabor int c, i, sign = 0; 102219019Sgabor char buf[BUFSIZE + 1]; 103219019Sgabor char *p; 104219019Sgabor 105219019Sgabor for (i = 0; i < BUFSIZE; i++) { 106219019Sgaborretry: 107219019Sgabor c = _memstream_peek(ms); 108219019Sgabor if (i == 0) { 109219019Sgabor if (sign == 0 && (c == '+' || c == '-')) { 110219019Sgabor sign = c; 111219019Sgabor _memstream_getc(ms); 112219019Sgabor goto retry; 113219019Sgabor } else if (!_bcs_isdigit(c)) 114219019Sgabor break; 115219019Sgabor } else if (!_bcs_isxdigit(c)) 116219019Sgabor if (!(i == 1 && c == 'x')) 117219019Sgabor break; 118219019Sgabor buf[i] = _memstream_getc(ms); 119219019Sgabor } 120219019Sgabor buf[i] = '\0'; 121219019Sgabor ps->ps_u_imm = strtoul(buf, &p, 0); 122219019Sgabor if ((p - buf) != i) 123219019Sgabor return (T_ERR); 124219019Sgabor if (sign == '-') 125219019Sgabor ps->ps_u_imm = (unsigned long)-(long)ps->ps_u_imm; 126219019Sgabor return (T_IMM); 127219019Sgabor} 128219019Sgabor 129219019Sgaborstatic int 130219019Sgaborget_tok(struct _memstream *ms, struct _parse_state *ps) 131219019Sgabor{ 132219019Sgabor int c; 133219019Sgabor 134219019Sgaborloop: 135219019Sgabor c = _memstream_peek(ms); 136219019Sgabor if (c == 0x00) 137219019Sgabor return (EOF); 138219019Sgabor if (_bcs_isspace(c)) { 139219019Sgabor _memstream_getc(ms); 140219019Sgabor goto loop; 141219019Sgabor } 142219019Sgabor 143219019Sgabor switch (ps->ps_state) { 144219019Sgabor case S_BEGIN: 145219019Sgabor switch (c) { 146219019Sgabor case ':': 147219019Sgabor case '-': 148219019Sgabor case '/': 149219019Sgabor _memstream_getc(ms); 150219019Sgabor return (c); 151219019Sgabor case '0': 152219019Sgabor case '1': 153219019Sgabor case '2': 154219019Sgabor case '3': 155219019Sgabor case '4': 156219019Sgabor case '5': 157219019Sgabor case '6': 158219019Sgabor case '7': 159219019Sgabor case '8': 160219019Sgabor case '9': 161219019Sgabor return (get_imm(ms, ps)); 162219019Sgabor } 163219019Sgabor break; 164219019Sgabor case S_OFFSET: 165219019Sgabor switch (c) { 166219019Sgabor case '/': 167219019Sgabor _memstream_getc(ms); 168219019Sgabor return (c); 169219019Sgabor case '+': 170219019Sgabor case '-': 171219019Sgabor case '0': 172219019Sgabor case '1': 173219019Sgabor case '2': 174219019Sgabor case '3': 175219019Sgabor case '4': 176219019Sgabor case '5': 177219019Sgabor case '6': 178219019Sgabor case '7': 179219019Sgabor case '8': 180219019Sgabor case '9': 181219019Sgabor return (get_imm(ms, ps)); 182219019Sgabor } 183219019Sgabor break; 184219019Sgabor } 185219019Sgabor return (T_ERR); 186219019Sgabor} 187219019Sgabor 188219019Sgaborstatic int 189219019Sgaborparse_zone(struct _memstream *ms, struct _parse_state *ps, struct _zone *z) 190219019Sgabor{ 191219019Sgabor 192219019Sgabor if (get_tok(ms, ps) != T_IMM) 193219019Sgabor return (-1); 194219019Sgabor z->z_begin = ps->ps_u_imm; 195219019Sgabor if (get_tok(ms, ps) != '-') 196219019Sgabor return (-1); 197219019Sgabor if (get_tok(ms, ps) != T_IMM) 198219019Sgabor return (-1); 199219019Sgabor z->z_end = ps->ps_u_imm; 200219019Sgabor 201219019Sgabor if (z->z_begin > z->z_end) 202219019Sgabor return (-1); 203219019Sgabor 204219019Sgabor return (0); 205219019Sgabor} 206219019Sgabor 207219019Sgaborstatic int 208219019Sgaborcheck_rowcol(struct _zone *z, int32_t ofs, uint32_t maxval) 209219019Sgabor{ 210219019Sgabor uint32_t remain; 211219019Sgabor 212219019Sgabor if (maxval != 0 && z->z_end >= maxval) 213219019Sgabor return (-1); 214219019Sgabor 215219019Sgabor if (ofs > 0) { 216219019Sgabor if (maxval == 0) 217219019Sgabor /* this should 0x100000000 - z->z_end */ 218219019Sgabor remain = (z->z_end == 0) ? 0xFFFFFFFF : 219219019Sgabor 0xFFFFFFFF - z->z_end + 1; 220219019Sgabor else 221219019Sgabor remain = maxval - z->z_end; 222219019Sgabor if ((uint32_t)ofs > remain) 223219019Sgabor return (-1); 224219019Sgabor } else if (ofs < 0) { 225219019Sgabor if (z->z_begin < (uint32_t)-ofs) 226219019Sgabor return (-1); 227219019Sgabor } 228219019Sgabor 229219019Sgabor return (0); 230219019Sgabor} 231219019Sgabor 232219019Sgaborstatic int 233219019Sgaborparse_var(struct _citrus_mapper_zone *mz, struct _memstream *ms) 234219019Sgabor{ 235219019Sgabor struct _parse_state ps; 236219019Sgabor uint32_t colmax, rowmax; 237219019Sgabor int isrc, ret; 238219019Sgabor 239219019Sgabor ps.ps_state = S_BEGIN; 240219019Sgabor 241219019Sgabor if (parse_zone(ms, &ps, &mz->mz_col)) 242219019Sgabor return (-1); 243219019Sgabor 244219019Sgabor ret = get_tok(ms, &ps); 245219019Sgabor if (ret == '/') { 246219019Sgabor /* rowzone / colzone / bits */ 247219019Sgabor isrc = 1; 248219019Sgabor mz->mz_row = mz->mz_col; 249219019Sgabor 250219019Sgabor if (parse_zone(ms, &ps, &mz->mz_col)) 251219019Sgabor return (-1); 252219019Sgabor if (get_tok(ms, &ps) != '/') 253219019Sgabor return (-1); 254219019Sgabor if (get_tok(ms, &ps) != T_IMM) 255219019Sgabor return (-1); 256219019Sgabor mz->mz_col_bits = ps.ps_u_imm; 257219019Sgabor if (mz->mz_col_bits < 0 || mz->mz_col_bits > 32) 258219019Sgabor return (-1); 259219019Sgabor ret = get_tok(ms, &ps); 260219019Sgabor } else { 261219019Sgabor /* colzone */ 262219019Sgabor isrc = 0; 263219019Sgabor mz->mz_col_bits = 32; 264219019Sgabor mz->mz_row.z_begin = mz->mz_row.z_end = 0; 265219019Sgabor } 266219019Sgabor if (ret == ':') { 267219019Sgabor /* offset */ 268219019Sgabor ps.ps_state = S_OFFSET; 269219019Sgabor if (get_tok(ms, &ps) != T_IMM) 270219019Sgabor return (-1); 271219019Sgabor mz->mz_col_offset = ps.ps_s_imm; 272219019Sgabor if (isrc) { 273219019Sgabor /* row/col */ 274219019Sgabor mz->mz_row_offset = mz->mz_col_offset; 275219019Sgabor if (get_tok(ms, &ps) != '/') 276219019Sgabor return (-1); 277219019Sgabor if (get_tok(ms, &ps) != T_IMM) 278219019Sgabor return (-1); 279219019Sgabor mz->mz_col_offset = ps.ps_s_imm; 280219019Sgabor } else 281219019Sgabor mz->mz_row_offset = 0; 282219019Sgabor ret = get_tok(ms, &ps); 283219019Sgabor } 284219019Sgabor if (ret != EOF) 285219019Sgabor return (-1); 286219019Sgabor 287219019Sgabor /* sanity check */ 288219019Sgabor colmax = (mz->mz_col_bits == 32) ? 0 : 1 << mz->mz_col_bits; 289219019Sgabor rowmax = (mz->mz_col_bits == 0) ? 0 : 1 << (32-mz->mz_col_bits); 290219019Sgabor if (check_rowcol(&mz->mz_col, mz->mz_col_offset, colmax)) 291219019Sgabor return (-1); 292219019Sgabor if (check_rowcol(&mz->mz_row, mz->mz_row_offset, rowmax)) 293219019Sgabor return (-1); 294219019Sgabor 295219019Sgabor return (0); 296219019Sgabor} 297219019Sgabor 298219019Sgaborstatic int 299219019Sgabor/*ARGSUSED*/ 300219019Sgabor_citrus_mapper_zone_mapper_init(struct _citrus_mapper_area *__restrict ma __unused, 301219019Sgabor struct _citrus_mapper * __restrict cm, const char * __restrict dir __unused, 302219019Sgabor const void * __restrict var, size_t lenvar, 303219019Sgabor struct _citrus_mapper_traits * __restrict mt, size_t lenmt) 304219019Sgabor{ 305219019Sgabor struct _citrus_mapper_zone *mz; 306219019Sgabor struct _memstream ms; 307219019Sgabor struct _region r; 308219019Sgabor 309219019Sgabor if (lenmt < sizeof(*mt)) 310219019Sgabor return (EINVAL); 311219019Sgabor 312219019Sgabor mz = malloc(sizeof(*mz)); 313219019Sgabor if (mz == NULL) 314219019Sgabor return (errno); 315219019Sgabor 316219019Sgabor mz->mz_col.z_begin = mz->mz_col.z_end = 0; 317219019Sgabor mz->mz_row.z_begin = mz->mz_row.z_end = 0; 318219019Sgabor mz->mz_col_bits = 0; 319219019Sgabor mz->mz_row_offset = 0; 320219019Sgabor mz->mz_col_offset = 0; 321219019Sgabor 322219019Sgabor _region_init(&r, __DECONST(void *, var), lenvar); 323219019Sgabor _memstream_bind(&ms, &r); 324219019Sgabor if (parse_var(mz, &ms)) { 325219019Sgabor free(mz); 326219019Sgabor return (EINVAL); 327219019Sgabor } 328219019Sgabor cm->cm_closure = mz; 329219019Sgabor mt->mt_src_max = mt->mt_dst_max = 1; /* 1:1 converter */ 330219019Sgabor mt->mt_state_size = 0; /* stateless */ 331219019Sgabor 332219019Sgabor return (0); 333219019Sgabor} 334219019Sgabor 335219019Sgaborstatic void 336219019Sgabor/*ARGSUSED*/ 337219019Sgabor_citrus_mapper_zone_mapper_uninit(struct _citrus_mapper *cm __unused) 338219019Sgabor{ 339219019Sgabor 340219019Sgabor} 341219019Sgabor 342219019Sgaborstatic int 343219019Sgabor/*ARGSUSED*/ 344219019Sgabor_citrus_mapper_zone_mapper_convert(struct _citrus_mapper * __restrict cm, 345219019Sgabor _citrus_index_t * __restrict dst, _citrus_index_t src, 346219019Sgabor void * __restrict ps __unused) 347219019Sgabor{ 348219019Sgabor struct _citrus_mapper_zone *mz = cm->cm_closure; 349219019Sgabor uint32_t col, row; 350219019Sgabor 351219019Sgabor if (mz->mz_col_bits == 32) { 352219019Sgabor col = src; 353219019Sgabor row = 0; 354219019Sgabor if (col < mz->mz_col.z_begin || col > mz->mz_col.z_end) 355219019Sgabor return (_CITRUS_MAPPER_CONVERT_NONIDENTICAL); 356219019Sgabor if (mz->mz_col_offset > 0) 357219019Sgabor col += (uint32_t)mz->mz_col_offset; 358219019Sgabor else 359219019Sgabor col -= (uint32_t)-mz->mz_col_offset; 360219019Sgabor *dst = col; 361219019Sgabor } else { 362219019Sgabor col = src & (((uint32_t)1 << mz->mz_col_bits) - 1); 363219019Sgabor row = src >> mz->mz_col_bits; 364219019Sgabor if (row < mz->mz_row.z_begin || row > mz->mz_row.z_end || 365219019Sgabor col < mz->mz_col.z_begin || col > mz->mz_col.z_end) 366219019Sgabor return (_CITRUS_MAPPER_CONVERT_NONIDENTICAL); 367219019Sgabor if (mz->mz_col_offset > 0) 368219019Sgabor col += (uint32_t)mz->mz_col_offset; 369219019Sgabor else 370219019Sgabor col -= (uint32_t)-mz->mz_col_offset; 371219019Sgabor if (mz->mz_row_offset > 0) 372219019Sgabor row += (uint32_t)mz->mz_row_offset; 373219019Sgabor else 374219019Sgabor row -= (uint32_t)-mz->mz_row_offset; 375219019Sgabor *dst = col | (row << mz->mz_col_bits); 376219019Sgabor } 377219019Sgabor return (_CITRUS_MAPPER_CONVERT_SUCCESS); 378219019Sgabor} 379219019Sgabor 380219019Sgaborstatic void 381219019Sgabor/*ARGSUSED*/ 382219019Sgabor_citrus_mapper_zone_mapper_init_state(void) 383219019Sgabor{ 384219019Sgabor 385219019Sgabor} 386