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