|
|
1.1 ! root 1: /* cbootlib.c -- C routines for use by boot programs. ! 2: * ! 3: * La Monte H. Yarroll <[email protected]>, September 1991 ! 4: */ ! 5: ! 6: #include <string.h> ! 7: #include <ctype.h> ! 8: #include "tboot.h" ! 9: ! 10: /* puts() -- put a NUL terminated string. ! 11: * Takes one argument--a pointer to a NUL terminated character string. ! 12: * Does no error checking. Calls the assembly language routine putc(). ! 13: */ ! 14: void ! 15: puts(s) ! 16: register char *s; ! 17: { ! 18: while (*s != '\0') { ! 19: putchar(*s++); ! 20: } ! 21: ! 22: } /* puts() */ ! 23: ! 24: ! 25: #define BS '\010' ! 26: #define DEL '\0' /* This is really what getchar() returns! */ ! 27: #define NAK '\025' ! 28: /* gets() -- Read string from keyboard. ! 29: * Takes one argument--a pointer to a buffer big enough for the ! 30: * expected response. ! 31: * It stops reading as soon as it detects a carriage return. The CR ! 32: * is replaced with a NUL. ! 33: */ ! 34: char * ! 35: gets(s) ! 36: char *s; ! 37: { ! 38: register char *t; ! 39: ! 40: t = s; ! 41: ! 42: while ('\r' != (*t = getchar())) { ! 43: if ((BS == *t) || (DEL == *t)) { ! 44: /* Process back space. */ ! 45: if (t > s) { ! 46: t--; ! 47: puts("\010 \010"); /* Erase the last character. */ ! 48: } ! 49: } else if (NAK == *t) { ! 50: /* Kill line. */ ! 51: while (--t >= s) { ! 52: puts("\010 \010"); /* Erase the last character. */ ! 53: } ! 54: t = s; ! 55: } else { ! 56: /* Echo the character; prepare for another. */ ! 57: putchar(*t); ! 58: t++; ! 59: } ! 60: } ! 61: *t = '\0'; ! 62: return(s); ! 63: } /* gets() */ ! 64: ! 65: ! 66: /* Reverse string s in place. ! 67: * Straight from K&R. ! 68: */ ! 69: void ! 70: reverse(s) ! 71: char s[]; ! 72: { ! 73: int c, i, j; ! 74: ! 75: for (i = 0, j = strlen(s)-1; i < j; i++, j--) { ! 76: c = s[i]; ! 77: s[i] = s[j]; ! 78: s[j] = c; ! 79: } ! 80: } /* reverse() */ ! 81: ! 82: #define BASE10 10 /* itoa() generates base 10 numbers. */ ! 83: ! 84: /* Convert n to decimal characters in s. ! 85: * Straight from K&R (with minor sylistic changes.) ! 86: */ ! 87: void ! 88: itoa(n, s) ! 89: char s[]; ! 90: int n; ! 91: { ! 92: int i, sign; ! 93: ! 94: if ((sign = n) < 0) { /* Record sign. */ ! 95: n = -n; /* Make n positive. */ ! 96: } ! 97: ! 98: i = 0; ! 99: do { /* Generate digits in reverse order. */ ! 100: s[i++] = n % BASE10 + '0'; /* Get next digit. */ ! 101: ! 102: } while ((n /= BASE10) > 0); /* Delete it. */ ! 103: ! 104: if (sign < 0) { ! 105: s[i++] = '-'; ! 106: } ! 107: s[i] = '\0'; ! 108: reverse(s); ! 109: } /* itoa() */ ! 110: ! 111: ! 112: #define BASE16 16 ! 113: /* Convert n to digits in s, base base. ! 114: * Works for any base from 2 to 36. ! 115: * Modified itoa() from K&R. ! 116: */ ! 117: void ! 118: itobase(n, s, base) ! 119: uint16 n; ! 120: char s[]; ! 121: int base; ! 122: { ! 123: uint16 i; ! 124: ! 125: i = 0; ! 126: do { /* Generate digits in reverse order. */ ! 127: s[i] = n % base + '0'; /* Get next digit. */ ! 128: /* Adjust for the gap between '9' and 'A'. */ ! 129: if (s[i] > '9') { ! 130: s[i] += ('A' - '9') - 1; ! 131: } ! 132: ++i; ! 133: } while ((n /= base) > 0); /* Delete it. */ ! 134: ! 135: s[i] = '\0'; ! 136: reverse(s); ! 137: } /* itobase() */ ! 138: ! 139: /* basetoi(char *s, int base) ! 140: * Convert a string base "base" to an integer. ! 141: * Good through base 36. ! 142: * Loosely based on K&R's atoi(). ! 143: */ ! 144: uint16 ! 145: basetoi(s, base) ! 146: char *s; ! 147: int base; ! 148: { ! 149: int i, n; ! 150: ! 151: static char convert[]="0123456789abcdefghijklmnopqrstuvwxyz"; ! 152: ! 153: /* Lowercase the entire string. */ ! 154: for(i = 0; '\0' != s[i]; ++i) { ! 155: if (isupper(s[i])) { ! 156: s[i] = tolower(s[i]); ! 157: } ! 158: } ! 159: ! 160: /* Actually do the conversion. */ ! 161: n = 0; ! 162: for (i = 0; '\0' != s[i] && NULL != strchr(convert, s[i]); ++i) { ! 163: n = (base * n) + (strchr(convert, s[i]) - convert); ! 164: } ! 165: return(n); ! 166: ! 167: } /* basetoi() */ ! 168: ! 169: ! 170: /* seginc(uint16 *offset, ! 171: * uint16 *segment, ! 172: * uint16 increment) ! 173: * Add an offset to a segment. We may adjust the segment base ! 174: * to make everything fit. ! 175: */ ! 176: #define MAXSEG (int32)0xffff /* Top address in a segment. */ ! 177: #define PPSIZE 16 /* Size of a paragraph-- ! 178: * segments are PP aligned. ! 179: */ ! 180: ! 181: void ! 182: seginc(offset, segment, increment) ! 183: uint16 *offset; ! 184: uint16 *segment; ! 185: uint16 increment; ! 186: { ! 187: /* If we won't spill over a segment boundary, just add increment ! 188: * to *offset. ! 189: */ ! 190: if ((int32) (*offset) + (int32) increment < MAXSEG) { ! 191: *offset += increment; ! 192: } else { ! 193: /* Otherwise, we have to adjust the segment. */ ! 194: *segment += (increment / PPSIZE); ! 195: ! 196: /* If offset is within PPSIZE of the end of a segment, ! 197: * we have to bump segment up to the next paragraph. ! 198: */ ! 199: if ((int32) (*offset) + (int32) (increment % PPSIZE) < MAXSEG) { ! 200: *offset += (increment % PPSIZE); ! 201: } else { ! 202: *segment += 1; ! 203: *offset = ! 204: (int) (((int32) (*offset) + ! 205: (int32) (increment % PPSIZE)) ! 206: - MAXSEG); ! 207: } ! 208: } ! 209: } /* seginc() */ ! 210: ! 211: ! 212: /* Pad a string s on the left with character c, to length n. ! 213: * The old contents of s are replaced by the padded version. ! 214: */ ! 215: char * ! 216: lpad(s, c, n) ! 217: char *s; ! 218: char c; ! 219: int n; ! 220: { ! 221: static char localbuf[LINESIZE]; ! 222: register int len_s; /* length of s. */ ! 223: register int i; ! 224: ! 225: len_s = strlen(s); ! 226: ! 227: /* We only have something to do if the string is too short. */ ! 228: if (len_s < n) { ! 229: /* Is n small enough to fit in locabuf? */ ! 230: if (n < (LINESIZE - 1)) { ! 231: /* Fill the padding into the local buffer. */ ! 232: for (i = 0; i < (n - len_s); ++i) { ! 233: localbuf[i] = c; ! 234: } ! 235: localbuf[i] = '\0'; ! 236: ! 237: /* Append the string to be padded. */ ! 238: strcat(localbuf, s); ! 239: /* Copy the padded string back where it came from. */ ! 240: strcpy(s, localbuf); ! 241: } else { ! 242: /* Too big! Do something more complicated. */ ! 243: strcpy(s, "lpad: n is too big!"); ! 244: } ! 245: } ! 246: ! 247: return(s); ! 248: } /* lpad() */ ! 249: ! 250: #define BITS_PER_INT16 16 /* Number of bits in an int16. */ ! 251: #define DIGITS_PER_INT16 4 /* Maximum hex digits in a 16 bit number. */ ! 252: #define DIGITS_PER_INT8 2 /* Maximum hex digits in an 8 bit number. */ ! 253: /* ! 254: * Print a 32 bit integer in hexadecimal. ! 255: */ ! 256: void ! 257: print32(my_int) ! 258: uint32 my_int; ! 259: { ! 260: uint16 half; ! 261: char buffer[sizeof("ffff")]; ! 262: ! 263: /* Convert and print the upper half. */ ! 264: half = (uint16) ((my_int) >> BITS_PER_INT16); ! 265: itobase(half, buffer, BASE16); ! 266: lpad(buffer, '0', DIGITS_PER_INT16); ! 267: puts(buffer); ! 268: ! 269: /* Convert and print the lower half. */ ! 270: half = (uint16) ((my_int << BITS_PER_INT16) >> BITS_PER_INT16); ! 271: itobase(half, buffer, BASE16); ! 272: lpad(buffer, '0', DIGITS_PER_INT16); ! 273: puts(buffer); ! 274: } ! 275: ! 276: /* ! 277: * Print a 16 bit integer in hexadecimal. ! 278: */ ! 279: void ! 280: print16(my_int) ! 281: uint16 my_int; ! 282: { ! 283: char buffer[sizeof("ffff")]; ! 284: ! 285: itobase(my_int, buffer, BASE16); ! 286: lpad(buffer, '0', DIGITS_PER_INT16); ! 287: puts(buffer); ! 288: } ! 289: ! 290: /* ! 291: * Print an 8 bit integer in hexadecimal. ! 292: */ ! 293: void ! 294: print8(my_int) ! 295: uint8 my_int; ! 296: { ! 297: char buffer[sizeof("ff")]; ! 298: ! 299: itobase((uint16) my_int, buffer, BASE16); ! 300: lpad(buffer, '0', DIGITS_PER_INT8); ! 301: puts(buffer); ! 302: } ! 303: ! 304: ! 305: /* ! 306: * Wrapper for far-far copy. Changes the segment so that the requested ! 307: * length does not wrap past the end of the segment. ! 308: * ! 309: * For Intel 8086 Real Mode. ! 310: */ ! 311: void ! 312: ffcopy(to_offset, to_seg, from_offset, from_seg, length) ! 313: uint16 to_offset; ! 314: uint16 to_seg; ! 315: uint16 from_offset; ! 316: uint16 from_seg; ! 317: uint16 length; ! 318: { ! 319: uint16 to_move; /* Amount to move at a time. */ ! 320: /* Algorithm: ! 321: * Align both segments so each offset is within a paragraph ! 322: * of the beginning of the segment. ! 323: * Move up to 1/2 a segment. ! 324: * Decrement length. ! 325: * Interate. ! 326: */ ! 327: ! 328: while (length != 0) { ! 329: /* Align both segments. */ ! 330: seg_align(&to_offset, &to_seg); ! 331: seg_align(&from_offset, &from_seg); ! 332: ! 333: /* Move up to 1/2 a segment. */ ! 334: to_move = LESSER(length, MAXUINT16/2); ! 335: ! 336: _ffcopy(from_offset, from_seg, to_offset, to_seg, to_move); ! 337: ! 338: /* Decrement length. */ ! 339: length -= to_move; ! 340: } ! 341: } /* ffcopy() */ ! 342: ! 343: /* ! 344: * Align a far address so that its offset is within a paragraph of ! 345: * the start of the segment. ! 346: * ! 347: * Note that we ignore overflow in the segment, since this is exactly ! 348: * what happens when you offset past the end of the highest segment. ! 349: * ! 350: * WARNING: This routine is destructive to its arguments. ! 351: * ! 352: * For Intel 8086 Real Mode. ! 353: */ ! 354: void ! 355: seg_align(offset, segment) ! 356: uint16 *offset; ! 357: uint16 *segment; ! 358: { ! 359: #define BYTE_PER_PP 16 /* Number of bytes in a paragraph. */ ! 360: uint16 new_offset, ! 361: new_segment; ! 362: ! 363: new_segment = *segment + (*offset/BYTE_PER_PP); ! 364: new_offset = *offset % BYTE_PER_PP; ! 365: ! 366: *segment = new_segment; ! 367: *offset = new_offset; ! 368: } /* seg_align() */ ! 369: /* ! 370: * wait_for_keystroke() -- wait for a specific keystroke. ! 371: */ ! 372: ! 373: /* Location of BIOS-run timer. */ ! 374: #define TIMER_SEG 0x0040 ! 375: #define TIMER_OFF 0x006c ! 376: ! 377: #define MIDNIGHT (((uint32) 24) << 16) ! 378: ! 379: /* ! 380: * Waits delay ticks for the requested keystroke. Returns TRUE if ! 381: * keystroke came, FALSE if delay runs out. ! 382: * If key == -1, accept ANY keystroke. ! 383: */ ! 384: int ! 385: wait_for_keystroke(delay, key) ! 386: int delay; ! 387: int key; ! 388: { ! 389: extern uint16 myds; /* My Data Segment, defined in Statup.s. */ ! 390: uint32 end_time; /* Return when time reaches this. */ ! 391: uint32 current_time; /* Current value of timer list. */ ! 392: int my_key_found; ! 393: ! 394: while (iskey()) { ! 395: getchar(); /* Eat all pending characters. */ ! 396: } ! 397: ! 398: /* Calculate the terminating time. */ ! 399: ffcopy(&end_time, myds, TIMER_OFF, TIMER_SEG, sizeof(int32)); ! 400: end_time += (int32) delay; ! 401: ! 402: /* Adjust for timer reset at midnight. */ ! 403: if (end_time > MIDNIGHT) { ! 404: /* These messages are meaningless. */ ! 405: puts("KABOOM!\r\n"); ! 406: puts("I'm tired. Please leave me alone.\r\n"); ! 407: end_time -= MIDNIGHT; ! 408: } ! 409: ! 410: /* Busy wait keystrokes and time delay. */ ! 411: ! 412: my_key_found = FALSE; ! 413: do { ! 414: ffcopy(¤t_time, myds, TIMER_OFF, TIMER_SEG,sizeof(int32)); ! 415: if (iskey()) { ! 416: /* The order of evaluation here is important. ! 417: * getchar() MUST be called to clean out the ! 418: * pending character. ! 419: */ ! 420: if (((int) getchar() == key) || (-1 == key)) { ! 421: my_key_found = TRUE; ! 422: } ! 423: } ! 424: } while (!my_key_found && (current_time < end_time)); ! 425: ! 426: return(my_key_found); ! 427: } /* wait_for_keystrok() */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.