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