Annotation of coherent/d/conf/tboot/cbootlib.c, revision 1.1.1.1

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(&current_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() */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.