glue.c revision 176481
1176348Smarcel/*-
2176348Smarcel * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com>
3176348Smarcel * All rights reserved.
4176348Smarcel *
5176348Smarcel * Redistribution and use in source and binary forms, with or without
6176348Smarcel * modification, are permitted provided that the following conditions
7176348Smarcel * are met:
8176348Smarcel * 1. Redistributions of source code must retain the above copyright
9176348Smarcel *    notice, this list of conditions and the following disclaimer.
10176348Smarcel * 2. Redistributions in binary form must reproduce the above copyright
11176348Smarcel *    notice, this list of conditions and the following disclaimer in the
12176348Smarcel *    documentation and/or other materials provided with the distribution.
13176348Smarcel *
14176348Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15176348Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16176348Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17176348Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18176348Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19176348Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20176348Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21176348Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22176348Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23176348Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24176348Smarcel * SUCH DAMAGE.
25176348Smarcel */
26176348Smarcel
27176348Smarcel#include <sys/cdefs.h>
28176348Smarcel__FBSDID("$FreeBSD: head/sys/boot/uboot/lib/glue.c 176481 2008-02-23 17:56:17Z marcel $");
29176348Smarcel
30176348Smarcel#include <stand.h>
31176348Smarcel#include "api_public.h"
32176481Smarcel#include "glue.h"
33176348Smarcel
34176481Smarcel#define DEBUG
35176348Smarcel#undef DEBUG
36176348Smarcel
37176348Smarcel#ifdef DEBUG
38176348Smarcel#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0)
39176348Smarcel#else
40176348Smarcel#define debugf(fmt, args...)
41176348Smarcel#endif
42176348Smarcel
43176481Smarcel/* Some random address used by U-Boot. */
44176481Smarcelextern long		uboot_address;
45176348Smarcel
46176348Smarcel/* crc32 stuff stolen from lib/libdisk/write_ia64_disk.c */
47176348Smarcelstatic uint32_t crc32_tab[] = {
48176348Smarcel	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
49176348Smarcel	0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
50176348Smarcel	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
51176348Smarcel	0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
52176348Smarcel	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
53176348Smarcel	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
54176348Smarcel	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
55176348Smarcel	0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
56176348Smarcel	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
57176348Smarcel	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
58176348Smarcel	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
59176348Smarcel	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
60176348Smarcel	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
61176348Smarcel	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
62176348Smarcel	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
63176348Smarcel	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
64176348Smarcel	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
65176348Smarcel	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
66176348Smarcel	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
67176348Smarcel	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
68176348Smarcel	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
69176348Smarcel	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
70176348Smarcel	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
71176348Smarcel	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
72176348Smarcel	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
73176348Smarcel	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
74176348Smarcel	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
75176348Smarcel	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
76176348Smarcel	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
77176348Smarcel	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
78176348Smarcel	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
79176348Smarcel	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
80176348Smarcel	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
81176348Smarcel	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
82176348Smarcel	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
83176348Smarcel	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
84176348Smarcel	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
85176348Smarcel	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
86176348Smarcel	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
87176348Smarcel	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
88176348Smarcel	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
89176348Smarcel	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
90176348Smarcel	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
91176348Smarcel};
92176348Smarcel
93176348Smarcelstatic uint32_t
94176348Smarcelcrc32(const void *buf, size_t size)
95176348Smarcel{
96176348Smarcel	const uint8_t *p;
97176348Smarcel	uint32_t crc;
98176348Smarcel
99176348Smarcel	p = buf;
100176348Smarcel	crc = ~0U;
101176348Smarcel
102176348Smarcel	while (size--)
103176348Smarcel		crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
104176348Smarcel
105176348Smarcel	return (crc ^ ~0U);
106176348Smarcel}
107176348Smarcel
108176348Smarcel
109176348Smarcelstatic int valid_sig(struct api_signature *sig)
110176348Smarcel{
111176348Smarcel	uint32_t checksum;
112176348Smarcel	struct api_signature s;
113176348Smarcel
114176348Smarcel	if (sig == NULL)
115176348Smarcel		return 0;
116176348Smarcel	/*
117176348Smarcel	 * Clear the checksum field (in the local copy) so as to calculate the
118176348Smarcel	 * CRC with the same initial contents as at the time when the sig was
119176348Smarcel	 * produced
120176348Smarcel	 */
121176348Smarcel	s = *sig;
122176348Smarcel	s.checksum = 0;
123176348Smarcel
124176348Smarcel	checksum = crc32((void *)&s, sizeof(struct api_signature));
125176348Smarcel
126176348Smarcel	if (checksum != sig->checksum)
127176348Smarcel		return 0;
128176348Smarcel
129176348Smarcel	return 1;
130176348Smarcel}
131176348Smarcel
132176348Smarcel/*
133176348Smarcel * Searches for the U-Boot API signature
134176348Smarcel *
135176348Smarcel * returns 1/0 depending on found/not found result
136176348Smarcel */
137176348Smarcelint api_search_sig(struct api_signature **sig) {
138176348Smarcel
139176481Smarcel	unsigned char *sp, *spend;
140176348Smarcel
141176348Smarcel	if (sig == NULL)
142176348Smarcel		return 0;
143176348Smarcel
144176481Smarcel	if (uboot_address == 0)
145176481Smarcel		uboot_address = 255 * 1024 * 1024;
146176348Smarcel
147176481Smarcel	sp = (void *)(uboot_address & ~0x000fffff);
148176481Smarcel	spend = sp + 0x00100000 - API_SIG_MAGLEN;
149176481Smarcel	while (sp < spend) {
150176348Smarcel		if (!bcmp(sp, API_SIG_MAGIC, API_SIG_MAGLEN)) {
151176348Smarcel			*sig = (struct api_signature *)sp;
152176348Smarcel			if (valid_sig(*sig))
153176348Smarcel				return 1;
154176348Smarcel		}
155176348Smarcel		sp += API_SIG_MAGLEN;
156176348Smarcel	}
157176348Smarcel
158176348Smarcel	*sig = NULL;
159176348Smarcel	return 0;
160176348Smarcel}
161176348Smarcel
162176348Smarcel/****************************************
163176348Smarcel *
164176348Smarcel * console
165176348Smarcel *
166176348Smarcel ****************************************/
167176348Smarcel
168176348Smarcelint ub_getc(void)
169176348Smarcel{
170176348Smarcel	int c;
171176348Smarcel
172176348Smarcel	if (!syscall(API_GETC, NULL, (uint32_t)&c))
173176348Smarcel		return -1;
174176348Smarcel
175176348Smarcel	return c;
176176348Smarcel}
177176348Smarcel
178176348Smarcelint ub_tstc(void)
179176348Smarcel{
180176348Smarcel	int t;
181176348Smarcel
182176348Smarcel	if (!syscall(API_TSTC, NULL, (uint32_t)&t))
183176348Smarcel		return -1;
184176348Smarcel
185176348Smarcel	return t;
186176348Smarcel}
187176348Smarcel
188176348Smarcelvoid ub_putc(char c)
189176348Smarcel{
190176348Smarcel	syscall(API_PUTC, NULL, (uint32_t)&c);
191176348Smarcel}
192176348Smarcel
193176348Smarcelvoid ub_puts(const char *s)
194176348Smarcel{
195176348Smarcel	syscall(API_PUTS, NULL, (uint32_t)s);
196176348Smarcel}
197176348Smarcel
198176348Smarcel/****************************************
199176348Smarcel *
200176348Smarcel * system
201176348Smarcel *
202176348Smarcel ****************************************/
203176348Smarcel
204176348Smarcelvoid ub_reset(void)
205176348Smarcel{
206176348Smarcel	syscall(API_RESET, NULL);
207176348Smarcel}
208176348Smarcel
209176348Smarcel
210176348Smarcel#define MR_MAX 5
211176348Smarcelstatic struct mem_region mr[MR_MAX];
212176348Smarcelstatic struct sys_info si;
213176348Smarcel
214176348Smarcelstruct sys_info * ub_get_sys_info(void)
215176348Smarcel{
216176348Smarcel	int err = 0;
217176348Smarcel
218176348Smarcel	memset(&si, 0, sizeof(struct sys_info));
219176348Smarcel	si.mr = mr;
220176348Smarcel	si.mr_no = MR_MAX;
221176348Smarcel	memset(&mr, 0, sizeof(mr));
222176348Smarcel
223176348Smarcel	if (!syscall(API_GET_SYS_INFO, &err, (u_int32_t)&si))
224176348Smarcel		return NULL;
225176348Smarcel
226176348Smarcel	return ((err) ? NULL : &si);
227176348Smarcel}
228176348Smarcel
229176348Smarcel
230176348Smarcel/****************************************
231176348Smarcel *
232176348Smarcel * timing
233176348Smarcel *
234176348Smarcel ****************************************/
235176348Smarcel
236176348Smarcelvoid ub_udelay(unsigned long usec)
237176348Smarcel{
238176348Smarcel	syscall(API_UDELAY, NULL, &usec);
239176348Smarcel}
240176348Smarcel
241176348Smarcelunsigned long ub_get_timer(unsigned long base)
242176348Smarcel{
243176348Smarcel	unsigned long cur;
244176348Smarcel
245176348Smarcel	if (!syscall(API_GET_TIMER, NULL, &cur, &base))
246176348Smarcel		return 0;
247176348Smarcel
248176348Smarcel	return cur;
249176348Smarcel}
250176348Smarcel
251176348Smarcel
252176348Smarcel/****************************************************************************
253176348Smarcel *
254176348Smarcel * devices
255176348Smarcel *
256176348Smarcel * Devices are identified by handles: numbers 0, 1, 2, ..., MAX_DEVS-1
257176348Smarcel *
258176348Smarcel ***************************************************************************/
259176348Smarcel
260176348Smarcel#define MAX_DEVS 6
261176348Smarcel
262176348Smarcelstatic struct device_info devices[MAX_DEVS];
263176348Smarcel
264176348Smarcelstruct device_info * ub_dev_get(int i)
265176348Smarcel{
266176348Smarcel	return ((i < 0 || i >= MAX_DEVS) ? NULL : &devices[i]);
267176348Smarcel}
268176348Smarcel
269176348Smarcel/*
270176348Smarcel * Enumerates the devices: fills out device_info elements in the devices[]
271176348Smarcel * array.
272176348Smarcel *
273176348Smarcel * returns:		number of devices found
274176348Smarcel */
275176348Smarcelint ub_dev_enum(void)
276176348Smarcel{
277176348Smarcel	struct device_info *di;
278176348Smarcel	int n = 0;
279176348Smarcel
280176348Smarcel	memset(&devices, 0, sizeof(struct device_info) * MAX_DEVS);
281176348Smarcel	di = &devices[0];
282176348Smarcel
283176348Smarcel	if (!syscall(API_DEV_ENUM, NULL, di))
284176348Smarcel		return 0;
285176348Smarcel
286176348Smarcel	while (di->cookie != NULL) {
287176348Smarcel
288176348Smarcel		if (++n >= MAX_DEVS)
289176348Smarcel			break;
290176348Smarcel
291176348Smarcel		/* take another device_info */
292176348Smarcel		di++;
293176348Smarcel
294176348Smarcel		/* pass on the previous cookie */
295176348Smarcel		di->cookie = devices[n - 1].cookie;
296176348Smarcel
297176348Smarcel		if (!syscall(API_DEV_ENUM, NULL, di))
298176348Smarcel			return 0;
299176348Smarcel	}
300176348Smarcel
301176348Smarcel	return n;
302176348Smarcel}
303176348Smarcel
304176348Smarcel
305176348Smarcel/*
306176348Smarcel * handle:	0-based id of the device
307176348Smarcel *
308176348Smarcel * returns:	0 when OK, err otherwise
309176348Smarcel */
310176348Smarcelint ub_dev_open(int handle)
311176348Smarcel{
312176348Smarcel	struct device_info *di;
313176348Smarcel	int err = 0;
314176348Smarcel
315176348Smarcel	if (handle < 0 || handle >= MAX_DEVS)
316176348Smarcel		return API_EINVAL;
317176348Smarcel
318176348Smarcel	di = &devices[handle];
319176348Smarcel	if (!syscall(API_DEV_OPEN, &err, di))
320176348Smarcel		return -1;
321176348Smarcel
322176348Smarcel	return err;
323176348Smarcel}
324176348Smarcel
325176348Smarcelint ub_dev_close(int handle)
326176348Smarcel{
327176348Smarcel	struct device_info *di;
328176348Smarcel
329176348Smarcel	if (handle < 0 || handle >= MAX_DEVS)
330176348Smarcel		return API_EINVAL;
331176348Smarcel
332176348Smarcel	di = &devices[handle];
333176348Smarcel	if (!syscall(API_DEV_CLOSE, NULL, di))
334176348Smarcel		return -1;
335176348Smarcel
336176348Smarcel	return 0;
337176348Smarcel}
338176348Smarcel
339176348Smarcel/*
340176348Smarcel * Validates device for read/write, it has to:
341176348Smarcel *
342176348Smarcel * - have sane handle
343176348Smarcel * - be opened
344176348Smarcel *
345176348Smarcel * returns:	0/1 accordingly
346176348Smarcel */
347176348Smarcelstatic int dev_valid(int handle)
348176348Smarcel{
349176348Smarcel	if (handle < 0 || handle >= MAX_DEVS)
350176348Smarcel		return 0;
351176348Smarcel
352176348Smarcel	if (devices[handle].state != DEV_STA_OPEN)
353176348Smarcel		return 0;
354176348Smarcel
355176348Smarcel	return 1;
356176348Smarcel}
357176348Smarcel
358176348Smarcelstatic int dev_stor_valid(int handle)
359176348Smarcel{
360176348Smarcel	if (!dev_valid(handle))
361176348Smarcel		return 0;
362176348Smarcel
363176348Smarcel	if (!(devices[handle].type & DEV_TYP_STOR))
364176348Smarcel		return 0;
365176348Smarcel
366176348Smarcel	return 1;
367176348Smarcel}
368176348Smarcel
369176348Smarcelint ub_dev_read(int handle, void *buf, lbasize_t len, lbastart_t start)
370176348Smarcel{
371176348Smarcel	struct device_info *di;
372176348Smarcel	lbasize_t act_len;
373176348Smarcel	int err = 0;
374176348Smarcel
375176348Smarcel	if (!dev_stor_valid(handle))
376176348Smarcel		return API_ENODEV;
377176348Smarcel
378176348Smarcel	di = &devices[handle];
379176348Smarcel	if (!syscall(API_DEV_READ, &err, di, buf, &len, &start, &act_len))
380176348Smarcel		return -1;
381176348Smarcel
382176348Smarcel	if (err)
383176348Smarcel		return err;
384176348Smarcel
385176348Smarcel	if (act_len != len)
386176348Smarcel		return API_EIO;
387176348Smarcel
388176348Smarcel	return 0;
389176348Smarcel}
390176348Smarcel
391176348Smarcelstatic int dev_net_valid(int handle)
392176348Smarcel{
393176348Smarcel	if (!dev_valid(handle))
394176348Smarcel		return 0;
395176348Smarcel
396176348Smarcel	if (devices[handle].type != DEV_TYP_NET)
397176348Smarcel		return 0;
398176348Smarcel
399176348Smarcel	return 1;
400176348Smarcel}
401176348Smarcel
402176348Smarcelint ub_dev_recv(int handle, void *buf, int len)
403176348Smarcel{
404176348Smarcel	struct device_info *di;
405176348Smarcel	int err = 0, act_len;
406176348Smarcel
407176348Smarcel	if (!dev_net_valid(handle))
408176348Smarcel		return API_ENODEV;
409176348Smarcel
410176348Smarcel	di = &devices[handle];
411176348Smarcel	if (!syscall(API_DEV_READ, &err, di, buf, &len, &act_len))
412176348Smarcel		return -1;
413176348Smarcel
414176348Smarcel	if (err)
415176348Smarcel		return -1;
416176348Smarcel
417176348Smarcel	return act_len;
418176348Smarcel}
419176348Smarcel
420176348Smarcelint ub_dev_send(int handle, void *buf, int len)
421176348Smarcel{
422176348Smarcel	struct device_info *di;
423176348Smarcel	int err = 0;
424176348Smarcel
425176348Smarcel	if (!dev_net_valid(handle))
426176348Smarcel		return API_ENODEV;
427176348Smarcel
428176348Smarcel	di = &devices[handle];
429176348Smarcel	if (!syscall(API_DEV_WRITE, &err, di, buf, &len))
430176348Smarcel		return -1;
431176348Smarcel
432176348Smarcel	return err;
433176348Smarcel}
434176348Smarcel
435176348Smarcel/****************************************
436176348Smarcel *
437176348Smarcel * env vars
438176348Smarcel *
439176348Smarcel ****************************************/
440176348Smarcel
441176348Smarcelchar * ub_env_get(const char *name)
442176348Smarcel{
443176348Smarcel	char *value;
444176348Smarcel
445176348Smarcel	if (!syscall(API_ENV_GET, NULL, (uint32_t)name, (uint32_t)&value))
446176348Smarcel		return NULL;
447176348Smarcel
448176348Smarcel	return value;
449176348Smarcel}
450176348Smarcel
451176348Smarcelvoid ub_env_set(const char *name, char *value)
452176348Smarcel{
453176348Smarcel	syscall(API_ENV_SET, NULL, (uint32_t)name, (uint32_t)value);
454176348Smarcel}
455176348Smarcel
456176348Smarcel
457176348Smarcelstatic char env_name[256];
458176348Smarcel
459176348Smarcelconst char * ub_env_enum(const char *last)
460176348Smarcel{
461176348Smarcel	const char *env, *str;
462176348Smarcel	int i;
463176348Smarcel
464176348Smarcel	env = NULL;
465176348Smarcel
466176348Smarcel	/*
467176348Smarcel	 * It's OK to pass only the name piece as last (and not the whole
468176348Smarcel	 * 'name=val' string), since the API_ENUM_ENV call uses envmatch()
469176348Smarcel	 * internally, which handles such case
470176348Smarcel	 */
471176348Smarcel	if (!syscall(API_ENV_ENUM, NULL, (uint32_t)last, (uint32_t)&env))
472176348Smarcel		return NULL;
473176348Smarcel
474176348Smarcel	if (!env)
475176348Smarcel		/* no more env. variables to enumerate */
476176348Smarcel		return NULL;
477176348Smarcel#if 0
478176348Smarcel	if (last && strncmp(env, last, strlen(last)) == 0);
479176348Smarcel		/* error, trying to enumerate non existing env. variable */
480176348Smarcel		return NULL;
481176348Smarcel#endif
482176348Smarcel
483176348Smarcel	/* next enumerated env var */
484176348Smarcel	memset(env_name, 0, 256);
485176348Smarcel	for (i = 0, str = env; *str != '=' && *str != '\0';)
486176348Smarcel		env_name[i++] = *str++;
487176348Smarcel
488176348Smarcel	env_name[i] = '\0';
489176348Smarcel
490176348Smarcel	return env_name;
491176348Smarcel}
492