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