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 **************************************************************************/ 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 **************************************************************************/ 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 **************************************************************************/ 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 **************************************************************************/ 69 void interruptible_sleep(int secs) 70 { 71 printf("<sleep>\n"); 72 return sleep(secs); 73 } 74 75 /************************************************************************** 76 TWIDDLE 77 **************************************************************************/ 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 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 265 etherboot_sprintf (char *buf, const char *fmt, ...) 266 { 267 return etherboot_vsprintf (buf, fmt, ((const int *) &fmt) + 1); 268 } 269 270 void 271 etherboot_printf (const char *fmt, ...) 272 { 273 (void) etherboot_vsprintf (0, fmt, ((const int *) &fmt) + 1); 274 } 275 276 int 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 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