1/*
2 *  GRUB  --  GRand Unified Bootloader
3 *  Copyright (C) 2000,2001,2002  Free Software Foundation, Inc.
4 *
5 *  This program is free software; you can redistribute it and/or modify
6 *  it under the terms of the GNU General Public License as published by
7 *  the Free Software Foundation; either version 2 of the License, or
8 *  (at your option) any later version.
9 *
10 *  This program is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *  GNU General Public License for more details.
14 *
15 *  You should have received a copy of the GNU General Public License
16 *  along with this program; if not, write to the Free Software
17 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20/* Based on "src/misc.c" in etherboot-5.0.5.  */
21
22#include "grub.h"
23#include "timer.h"
24
25#include "nic.h"
26
27/**************************************************************************
28RANDOM - compute a random number between 0 and 2147483647L or 2147483562?
29**************************************************************************/
30int32_t random(void)
31{
32	static int32_t seed = 0;
33	int32_t q;
34	if (!seed) /* Initialize linear congruential generator */
35		seed = currticks() + *(int32_t *)&arptable[ARP_CLIENT].node
36		       + ((int16_t *)arptable[ARP_CLIENT].node)[2];
37	/* simplified version of the LCG given in Bruce Schneier's
38	   "Applied Cryptography" */
39	q = seed/53668;
40	if ((seed = 40014*(seed-53668*q) - 12211*q) < 0) seed += 2147483563L;
41	return seed;
42}
43
44/**************************************************************************
45POLL INTERRUPTIONS
46**************************************************************************/
47void poll_interruptions(void)
48{
49	if (checkkey() != -1 && ASCII_CHAR(getkey()) == K_INTR) {
50		user_abort++;
51	}
52}
53
54/**************************************************************************
55SLEEP
56**************************************************************************/
57void sleep(int secs)
58{
59	unsigned long tmo;
60
61	for (tmo = currticks()+secs*TICKS_PER_SEC; currticks() < tmo; ) {
62		poll_interruptions();
63	}
64}
65
66/**************************************************************************
67INTERRUPTIBLE SLEEP
68**************************************************************************/
69void interruptible_sleep(int secs)
70{
71	printf("<sleep>\n");
72	return sleep(secs);
73}
74
75/**************************************************************************
76TWIDDLE
77**************************************************************************/
78void twiddle(void)
79{
80#ifdef BAR_PROGRESS
81	static int count=0;
82	static const char tiddles[]="-\\|/";
83	static unsigned long lastticks = 0;
84	unsigned long ticks;
85#endif
86#ifdef FREEBSD_PXEEMU
87	extern char pxeemu_nbp_active;
88	if(pxeemu_nbp_active != 0)
89		return;
90#endif
91#ifdef	BAR_PROGRESS
92	/* Limit the maximum rate at which characters are printed */
93	ticks = currticks();
94	if ((lastticks + (TICKS_PER_SEC/18)) > ticks)
95		return;
96	lastticks = ticks;
97
98	putchar(tiddles[(count++)&3]);
99	putchar('\b');
100#else
101	//putchar('.');
102#endif	/* BAR_PROGRESS */
103}
104
105
106/* Because Etherboot uses its own formats for the printf family,
107   define separate definitions from GRUB.  */
108/**************************************************************************
109PRINTF and friends
110
111	Formats:
112		%[#]x	- 4 bytes long (8 hex digits, lower case)
113		%[#]X	- 4 bytes long (8 hex digits, upper case)
114		%[#]hx	- 2 bytes int (4 hex digits, lower case)
115		%[#]hX	- 2 bytes int (4 hex digits, upper case)
116		%[#]hhx	- 1 byte int (2 hex digits, lower case)
117		%[#]hhX	- 1 byte int (2 hex digits, upper case)
118			- optional # prefixes 0x or 0X
119		%d	- decimal int
120		%c	- char
121		%s	- string
122		%@	- Internet address in ddd.ddd.ddd.ddd notation
123		%!	- Ethernet address in xx:xx:xx:xx:xx:xx notation
124	Note: width specification not supported
125**************************************************************************/
126static int
127etherboot_vsprintf (char *buf, const char *fmt, const int *dp)
128{
129  char *p, *s;
130
131  s = buf;
132  for ( ; *fmt != '\0'; ++fmt)
133    {
134      if (*fmt != '%')
135	{
136	  buf ? *s++ = *fmt : grub_putchar (*fmt);
137	  continue;
138	}
139
140      if (*++fmt == 's')
141	{
142	  for (p = (char *) *dp++; *p != '\0'; p++)
143	    buf ? *s++ = *p : grub_putchar (*p);
144	}
145      else
146	{
147	  /* Length of item is bounded */
148	  char tmp[20], *q = tmp;
149	  int alt = 0;
150	  int shift = 28;
151
152	  if (*fmt == '#')
153	    {
154	      alt = 1;
155	      fmt++;
156	    }
157
158	  if (*fmt == 'h')
159	    {
160	      shift = 12;
161	      fmt++;
162	    }
163
164	  if (*fmt == 'h')
165	    {
166	      shift = 4;
167	      fmt++;
168	    }
169
170	  /*
171	   * Before each format q points to tmp buffer
172	   * After each format q points past end of item
173	   */
174	  if ((*fmt | 0x20) == 'x')
175	    {
176	      /* With x86 gcc, sizeof(long) == sizeof(int) */
177	      const long *lp = (const long *) dp;
178	      long h = *lp++;
179	      int ncase = (*fmt & 0x20);
180
181	      dp = (const int *) lp;
182	      if (alt)
183		{
184		  *q++ = '0';
185		  *q++ = 'X' | ncase;
186		}
187	      for (; shift >= 0; shift -= 4)
188		*q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase;
189	    }
190	  else if (*fmt == 'd')
191	    {
192	      int i = *dp++;
193	      char *r;
194
195	      if (i < 0)
196		{
197		  *q++ = '-';
198		  i = -i;
199		}
200
201	      p = q;		/* save beginning of digits */
202	      do
203		{
204		  *q++ = '0' + (i % 10);
205		  i /= 10;
206		}
207	      while (i);
208
209	      /* reverse digits, stop in middle */
210	      r = q;		/* don't alter q */
211	      while (--r > p)
212		{
213		  i = *r;
214		  *r = *p;
215		  *p++ = i;
216		}
217	    }
218	  else if (*fmt == '@')
219	    {
220	      unsigned char *r;
221	      union
222	      {
223		long		l;
224		unsigned char	c[4];
225	      }
226	      u;
227	      const long *lp = (const long *) dp;
228
229	      u.l = *lp++;
230	      dp = (const int *) lp;
231
232	      for (r = &u.c[0]; r < &u.c[4]; ++r)
233		q += etherboot_sprintf (q, "%d.", *r);
234
235	      --q;
236	    }
237	  else if (*fmt == '!')
238	    {
239	      char *r;
240	      p = (char *) *dp++;
241
242	      for (r = p + ETH_ALEN; p < r; ++p)
243		q += etherboot_sprintf (q, "%hhX:", *p);
244
245	      --q;
246	    }
247	  else if (*fmt == 'c')
248	    *q++ = *dp++;
249	  else
250	    *q++ = *fmt;
251
252	  /* now output the saved string */
253	  for (p = tmp; p < q; ++p)
254	    buf ? *s++ = *p : grub_putchar (*p);
255	}
256    }
257
258  if (buf)
259    *s = '\0';
260
261  return (s - buf);
262}
263
264int
265etherboot_sprintf (char *buf, const char *fmt, ...)
266{
267  return etherboot_vsprintf (buf, fmt, ((const int *) &fmt) + 1);
268}
269
270void
271etherboot_printf (const char *fmt, ...)
272{
273  (void) etherboot_vsprintf (0, fmt, ((const int *) &fmt) + 1);
274}
275
276int
277inet_aton (char *p, in_addr *addr)
278{
279  unsigned long ip = 0;
280  int val;
281  int i;
282
283  for (i = 0; i < 4; i++)
284    {
285      val = getdec (&p);
286
287      if (val < 0 || val > 255)
288	return 0;
289
290      if (i != 3 && *p++ != '.')
291	return 0;
292
293      ip = (ip << 8) | val;
294    }
295
296  addr->s_addr = htonl (ip);
297
298  return 1;
299}
300
301int
302getdec (char **ptr)
303{
304  char *p = *ptr;
305  int ret = 0;
306
307  if (*p < '0' || *p > '9')
308    return -1;
309
310  while (*p >= '0' && *p <= '9')
311    {
312      ret = ret * 10 + (*p - '0');
313      p++;
314    }
315
316  *ptr = p;
317
318  return ret;
319}
320
321
322