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 /**************************************************************************
28 RANDOM - compute a random number between 0 and 2147483647L or 2147483562?
29 **************************************************************************/
random(void)30 int32_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 /**************************************************************************
45 POLL INTERRUPTIONS
46 **************************************************************************/
poll_interruptions(void)47 void poll_interruptions(void)
48 {
49 	if (checkkey() != -1 && ASCII_CHAR(getkey()) == K_INTR) {
50 		user_abort++;
51 	}
52 }
53 
54 /**************************************************************************
55 SLEEP
56 **************************************************************************/
sleep(int secs)57 void 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 /**************************************************************************
67 INTERRUPTIBLE SLEEP
68 **************************************************************************/
interruptible_sleep(int secs)69 void interruptible_sleep(int secs)
70 {
71 	printf("<sleep>\n");
72 	return sleep(secs);
73 }
74 
75 /**************************************************************************
76 TWIDDLE
77 **************************************************************************/
twiddle(void)78 void 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 /**************************************************************************
109 PRINTF 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 **************************************************************************/
126 static int
etherboot_vsprintf(char * buf,const char * fmt,const int * dp)127 etherboot_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 
264 int
etherboot_sprintf(char * buf,const char * fmt,...)265 etherboot_sprintf (char *buf, const char *fmt, ...)
266 {
267   return etherboot_vsprintf (buf, fmt, ((const int *) &fmt) + 1);
268 }
269 
270 void
etherboot_printf(const char * fmt,...)271 etherboot_printf (const char *fmt, ...)
272 {
273   (void) etherboot_vsprintf (0, fmt, ((const int *) &fmt) + 1);
274 }
275 
276 int
inet_aton(char * p,in_addr * addr)277 inet_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 
301 int
getdec(char ** ptr)302 getdec (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