Annotation of qemu/roms/sgabios/sgabios.S, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright 2010 Google Inc.
                      3:  *
                      4:  * Licensed under the Apache License, Version 2.0 (the "License");
                      5:  * you may not use this file except in compliance with the License.
                      6:  * You may obtain a copy of the License at
                      7:  *
                      8:  *     http://www.apache.org/licenses/LICENSE-2.0
                      9:  *
                     10:  * Unless required by applicable law or agreed to in writing, software
                     11:  * distributed under the License is distributed on an "AS IS" BASIS,
                     12:  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                     13:  * See the License for the specific language governing permissions and
                     14:  * limitations under the License.
                     15:  */
                     16: 
                     17: #include "sgabios.h"
                     18: #define BUILD_CL  "$Id$"
                     19: 
                     20: .code16
                     21: .text
                     22:   .section ".init","ax"
                     23:   .globl _start
                     24:   .type _start,@object
                     25: _start:
                     26:   /* option rom header */
                     27:   .byte 0x55
                     28:   .byte 0xaa
                     29:   .byte _rom_size_byte
                     30:   .size _start, .-_start
                     31: 
                     32:   .globl legacy_entry
                     33:   .type legacy_entry,@function
                     34: legacy_entry:
                     35:   jmp sga_init
                     36:   /* pnp entry here to avoid changing PnP table as code moves */
                     37: pnp_init:
                     38:   jmp pnp_sga_init
                     39: 
                     40: /*
                     41:  * do_old_int10h
                     42:  *
                     43:  * Patched at option rom init to be a far jump to old int 10h isr
                     44:  *
                     45:  */
                     46: do_old_int10h:
                     47:   .byte 0xea                           /* jmp absolute segment:offset */
                     48: old_int10h:                            /* store what was at offset 0x40 */
                     49:   .word 0xf065                         /* placeholder for chained ISR offset */
                     50:   /* if the chained segment is detected as 0xc000, use 80 cols only */
                     51:   /* since it's assumed that a vga card is attached and 80 cols max */
                     52: old_int10h_seg:
                     53:   .word 0xf000                         /* placeholder for chained ISR segment */
                     54: /*
                     55:  * do_old_int16h
                     56:  *
                     57:  * Patched at option rom init to be a far jump to old int 16h isr
                     58:  *
                     59:  */
                     60: do_old_int16h:
                     61:   .byte 0xea                           /* jmp absolute segment:offset */
                     62: old_int16h:                            /* store what was at offset 0x58 */
                     63:   .word 0xe82e                         /* placeholder for chained ISR offset */
                     64:   .word 0xf000                         /* placeholder for chained ISR segment */
                     65: .org 0x18
                     66:   .word 0                              /* offset to PCI data, 0 = none */
                     67:   .word pnp_table                      /* offset to PnP expansion header */
                     68: .org 0x20
                     69: pnp_table:
                     70:   /* FIXME: **** PnP header currently disabled by PoO **** */
                     71:   /* legacy entry only called once, PnP entry called multiple times */
                     72:   /* The code isn't yet written to deal with multiple inits properly */
                     73:   .ascii "$PoO"                        /* PnP expansion header signature */
                     74:   .byte 1                              /* structure revision */
                     75:   .byte 2                              /* length in 16-byte increments */
                     76:   .word 0                              /* offset of next header, 0 if none */
                     77:   .byte 0                              /* reserved */
                     78:   .byte 0x52                           /* checksum - update manually! FIXME */
                     79:   .long 0                              /* device identifier */
                     80:   .word mfg_string                     /* pointer to manufacturer string */
                     81:   .word prod_string                    /* pointer to product name string */
                     82:   .byte 3, 0x80, 0x80                  /* device type code = other display */
                     83:   .byte 0xe3                           /* device indicators, kbd/display dev */
                     84:   .word 0                              /* boot connection vector, 0 if none */
                     85:   .word 0                              /* disconnect vector, 0 if none */
                     86:   .word pnp_init                       /* bootstrap entry vector */
                     87:   .word 0                              /* reserved */
                     88:   .word 0                              /* static resource information vector */
                     89: 
                     90:   /* WARNING: changing mfg_string / prod_string locations will */
                     91:   /* affect pnp table above -- recalculate checksum manually! */
                     92: mfg_string:
                     93:   .asciz "Google, Inc."
                     94: prod_string:
                     95:   .ascii "Serial Graphics Adapter "
                     96: build_date:
                     97:   .asciz BUILD_SHORT_DATE
                     98: long_version:
                     99:   .ascii "SGABIOS "
                    100:   .ascii BUILD_CL
                    101:   .ascii " ("
                    102:   .ascii BUILD_USER
                    103:   .ascii "@"
                    104:   .ascii BUILD_HOST
                    105:   .ascii ") "
                    106:   .asciz BUILD_DATE
                    107: term_cols:
                    108:   .byte 80             /* overwritten at rom init with detected value */
                    109: term_rows:
                    110:   .byte 24             /* overwritten at rom init with detected value */
                    111: term_init_string:      /* terminal reply: \033[n;mR n=row, m=col */
                    112:   .asciz "\033[1;256r\033[256;256H\033[6n"
                    113:   /* reset the scroll, move to col 256, row 256, ask current position */
                    114:   /* bios cursor positions >255 rows or cols can't be used anyway */
                    115: term_info:
                    116:   .asciz "Term: "
                    117: ebda_info:
                    118:   .asciz "EBDA: "
                    119: 
                    120: /*
                    121:  * do_old_irq3 - exception 0x0b, int 0x0a
                    122:  *
                    123:  * Patched at option rom init to be a far jump to old irq 3 isr
                    124:  *
                    125:  */
                    126: do_old_irq3:
                    127:   .byte 0xea                           /* jmp absolute segment:offset */
                    128: old_irq3:          /* store what was at offset 0x28 */
                    129:   .word 0xeef3                         /* placeholder for chained ISR offset */
                    130:   .word 0xf000                         /* placeholder for chained ISR segment */
                    131: 
                    132: /*
                    133:  * do_old_irq4 - exception 0x0c, int 0x0b
                    134:  *
                    135:  * Patched at option rom init to be a far jump to old irq 4 isr
                    136:  *
                    137:  */
                    138: do_old_irq4:
                    139:   .byte 0xea                           /* jmp absolute segment:offset */
                    140: old_irq4:          /* store what was at offset 0x2c */
                    141:   .word 0xeef3                         /* placeholder for chained ISR offset */
                    142:   .word 0xf000                         /* placeholder for chained ISR segment */
                    143: 
                    144: /*
                    145:  * do_old_int14h
                    146:  *
                    147:  * Patched at option rom init to be a far jump to old int 14h isr
                    148:  *
                    149:  */
                    150: do_old_int14h:
                    151:   .byte 0xea                           /* jmp absolute segment:offset */
                    152: old_int14h:                            /* store what was at offset 0x50 */
                    153:   .word 0xe739                         /* placeholder for chained ISR offset */
                    154:   .word 0xf000                         /* placeholder for chained ISR segment */
                    155: 
                    156: .align 16, 0xff    /* aligning this table only makes hexdump prettier */
                    157: /* ascii -> scancode, bit 7=shifted, char < 32 = +ctrl */
                    158: /* except chars 8, 9, 13, 27 (bs, tab, enter, esc) */
                    159: /* most int16h consumers will probably never use */
                    160: ascii2scan:
                    161: /*00*/  .byte 0x00, 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22
                    162: /*08*/  .byte 0x0e, 0x17, 0x24, 0x25, 0x26, 0x1c, 0x31, 0x18
                    163: /*10*/  .byte 0x19, 0x0f, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11
                    164: /*18*/  .byte 0x2d, 0x15, 0x2c, 0x01, 0x2b, 0x1b, 0x87, 0x8c
                    165: /*20*/  .byte 0x39, 0x82, 0xa8, 0x84, 0x85, 0x86, 0x88, 0x28
                    166: /*28*/  .byte 0x8a, 0x8b, 0x89, 0x8d, 0x33, 0x0c, 0x34, 0x35
                    167: /*30*/  .byte 0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
                    168: /*38*/  .byte 0x09, 0x0a, 0xa7, 0x27, 0xb3, 0x0d, 0x34, 0xb5
                    169: /*40*/  .byte 0x83, 0x9e, 0xb0, 0xae, 0xa0, 0x92, 0xa1, 0xa2
                    170: /*48*/  .byte 0xa3, 0x97, 0xa4, 0xa5, 0xa6, 0xb2, 0xb1, 0x98
                    171: /*50*/  .byte 0x99, 0x90, 0x93, 0x9f, 0x94, 0x96, 0xaf, 0x91
                    172: /*58*/  .byte 0xad, 0x95, 0xac, 0x1a, 0x2b, 0x1b, 0x87, 0x8c
                    173: /*60*/  .byte 0x29, 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22
                    174: /*68*/  .byte 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18
                    175: /*70*/  .byte 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11
                    176: /*78*/  .byte 0x2d, 0x15, 0x2c, 0x9a, 0xab, 0x9b, 0xa9, 0x0e
                    177: 
                    178: /* TABLES FOR NON-ASCII VGA CHARACTERS (CP437) TO ASCII */
                    179: /* Unicode at: http://en.wikipedia.org/wiki/Code_page_437 */
                    180: 
                    181: ctrl2ascii:
                    182: /* translate vga (CP437) first 32 characters to ascii */
                    183: /* for char 0, update the cursor position, but output nothing */
                    184: /* lilo uses this "trick" for a background attribute update */
                    185:   .ascii "\0@@v***........*><|!PS-|^v><L-^v"
                    186: high2ascii:
                    187: /* translate vga (CP437) chars 0x80 to 0xff to ascii */
                    188: /* these characters are mostly to visually approximate */
                    189: /* line art characters will probably need tweaking */
                    190: /*80*/  .ascii "CueaaaaceeeiiiAAEaAooouuyOUcLYPf"
                    191: /*a0*/  .ascii "aiounNao?--24!<>###||||++||+++++"
                    192: /*c0*/  .ascii "+--|-+||++--|-+----++++++++#-||-"
                    193: /*e0*/  .ascii "abgpesut00osiye^=+><||-=...vn2* "
                    194: 
                    195: colortable:
                    196: /* vga text color is IRGB, ansi color is BGR */
                    197: /* this table is effectively a nibble bit-reverse */
                    198:   .byte 0, 4, 2, 6, 1, 5, 3, 7
                    199: 
                    200: serial_port_base_address:
                    201:   .word COM_BASE_ADDR
                    202: 
                    203: /* in-memory console log
                    204:  *
                    205:  * It's expected that the EBDA contains a magic signature
                    206:  * like 0xdeadbabe, followed by a byte of flags, followed
                    207:  * by a 32-bit buffer pointer, followed by a 16-bit start
                    208:  * index, followed by a 16-bit end index, followed by 16-
                    209:  * bit logged character count, followed by an 8-bit flag.
                    210:  */
                    211: 
                    212: #define MEMCONSOLE_BUFFER_SIZE  32768
                    213: #define MEMCONSOLE_SIGNATURE  0xdeadbabe
                    214: #define MEMCONSOLE_ENDINDEX_OFF  0x0b
                    215: #define SGABIOS_EBDA_SIGNATURE  0x00414753
                    216: 
                    217: memconsole_buffer_start:               /* pulled from ebda struct */
                    218:   .long  0x00000000                    /* 0 = not found/no logging */
                    219: memconsole_ebda_deadbabe_offset:       /* bytes from start of ebda */
                    220:   .word  0x0000                        /* 40:0e contains ebda seg */
                    221: sgabios_ebda_logbuf_offset:            /* bytes from start of ebda */
                    222:   .word  0x0000                        /* 40:0e contains ebda seg */
                    223: 
                    224: /*
                    225:  * setup_memconsole
                    226:  *
                    227:  * Initialize the option rom variables associated with logging
                    228:  * of the legacy console output
                    229:  *
                    230:  * If these variables are left at zero, no logging will occur
                    231:  *
                    232:  * There are no parameters
                    233:  * All registers except flags should be preserved
                    234:  */
                    235: 
                    236: setup_memconsole:
                    237:   pushaw
                    238:   pushw %ds
                    239:   pushw %es
                    240:   pushw $BDA_SEG
                    241:   popw %ds                             /* ds = 0x40 */
                    242:   pushw BDA_EBDA                       /* push word at 0x0e */
                    243:   popw %es                             /* es = EBDA_SEG */
                    244:   /* search for memconsole signature in ebda */
                    245:   movl $MEMCONSOLE_SIGNATURE, %eax
                    246:   xorw %di, %di                        /* start at zero */
                    247:   movzbw %es:(%di), %cx                /* cx = size of EBDA in KB */
                    248:   shlw $8, %cx                         /* cx = (cx * 1024) / 4 */
                    249:   cld
                    250:   repnz
                    251:   scasl                                /* search until sig found */
                    252:   subw $4, %di                         /* scasl always increments di, undo */
                    253:   cmpl %eax, %es:(%di)                 /* is signature here? */
                    254:   jnz setup_memconsole_end             /* bail if so */
                    255:   movw %di, %cs:memconsole_ebda_deadbabe_offset  /* save offset */
                    256:   movl %es:5(%di), %eax                /* get 32-bit buffer base address */
                    257:   movl %eax, %cs:memconsole_buffer_start
                    258: setup_memconsole_end:
                    259:   popw %es
                    260:   popw %ds
                    261:   popaw
                    262:   ret
                    263: 
                    264: /*
                    265:  * memconsole_log_char
                    266:  *
                    267:  * Log the character passed in %al to the next available memory
                    268:  * console log position, if any.
                    269:  *
                    270:  * If memconsole_buffer_start is zero, no logging will occur
                    271:  *
                    272:  * %al = character to be logged
                    273:  * All registers except flags should be preserved
                    274:  */
                    275: 
                    276: memconsole_log_char:
                    277:   pushaw
                    278:   pushw %ds
                    279:   pushw %es
                    280:   pushw %fs
                    281:   pushw $BDA_SEG
                    282:   popw %ds                             /* ds = 0x40 */
                    283:   pushw BDA_EBDA                       /* push word at 0x0e */
                    284:   popw %es                             /* es = EBDA_SEG */
                    285:   movw %ax, %si                        /* %si = %al = byte to write */
                    286:   movl %cs:memconsole_buffer_start, %ebp
                    287:   movw %cs:memconsole_ebda_deadbabe_offset, %di
                    288:   addw $MEMCONSOLE_ENDINDEX_OFF, %di   /* %di points to char pos */
                    289:   orl %ebp, %ebp
                    290:   jz memconsole_log_tail               /* bufptr==0, no logging */
                    291:   movw %es:(%di), %bx                  /* bx = current position in buffer */
                    292:   cmpw $MEMCONSOLE_BUFFER_SIZE, %bx    /* at end of buffer? */
                    293:   jnc memconsole_log_tail              /* don't log any more if so */
                    294:   cmpb $0xd, %al                       /* is the char CR? */
                    295:   jz memconsole_log_tail               /* if so, ignore it */
                    296:   cmpb $0x8, %al                       /* is the char backspace? */
                    297:   jnz memconsole_update_fsbase         /* if not, log char as usual... */
                    298:   orw %bx, %bx                         /* make sure ptr isn't already zero */
                    299:   jz memconsole_log_tail               /* if so, bail */
                    300:   decw %bx                             /* else point to previous character */
                    301:   jmp memconsole_update_end_ptr        /* and go directly to save it */
                    302: memconsole_update_fsbase:
                    303:   movl $0xc0000100, %ecx               /* ecx = IA32_FS_BASE (AMD64+) */
                    304:   rdmsr                                /* read what was there before */
                    305:   pushl %eax                           /* save away previous FS_BASE eax */
                    306:   pushl %edx                           /* save away previous FS_BASE edx */
                    307:   xorl %edx, %edx                      /* clear high 32 bits */
                    308:   movl %ebp, %eax                      /* eax = memconsole buffer start */
                    309:   wrmsr                                /* fs_base = memconsole buffer start */
                    310:   movw %si, %ax                        /* %ax = saved value on entry */
                    311:   movb %al, %fs:(%bx)                  /* log character */
                    312:   popl %edx                            /* restore previous FS_BASE edx */
                    313:   popl %eax                            /* restore previous FS_BASE eax */
                    314:   wrmsr                                /* write what was there before */
                    315:   incw %bx                             /* update character count */
                    316: memconsole_update_end_ptr:
                    317:   movw %bx, %es:(%di)                  /* save new end pointer */
                    318:   addw $2, %di                         /* numchars stored at next word */
                    319:   movw %bx, %es:(%di)                  /* save new numchar value */
                    320: memconsole_log_tail:
                    321:   popw %fs
                    322:   popw %es
                    323:   popw %ds
                    324:   popaw
                    325:   ret
                    326: 
                    327: /* sgabioslog_setup_ebda
                    328:  *
                    329:  * SGABIOS makes its own 1KB EBDA allocation to save non-
                    330:  * translated characters with associated cursor positions
                    331:  * for the last 256 characters output.  This is organized
                    332:  * with 256 bytes reserved for houskeeping, 256 bytes for
                    333:  * the raw character codes, and 512 bytes of 16bit cursor
                    334:  * positions to record the associated position for each.
                    335:  *
                    336:  * The first 4 bytes contain "SGA\0" followed by a 16-bit
                    337:  * size of the allocation in bytes,  followed by a 16-bit
                    338:  * index indicating the next spot to be overwritten.
                    339:  * 
                    340:  * There are no parameters
                    341:  * All registers should be preserved
                    342:  */
                    343: 
                    344: sgabioslog_setup_ebda:
                    345:   pushf
                    346:   pushaw
                    347:   pushw %ds
                    348:   pushw %es
                    349:   pushw $BDA_SEG
                    350:   popw %ds                             /* ds = 0x40 */
                    351:   movw BDA_EBDA, %ax                   /* ax = old ebda segment from 0x0e */
                    352:   subw $SGABIOS_EBDA_DELTA, %ax
                    353:   movw %ax, %es                        /* es = new EBDA segment start */
                    354:   cmpw $EBDA_MIN_SEG, %ax              /* is there room for the allocation? */
                    355:   jc sgabioslog_setup_ebda_tail        /* if not, don't change anything */
                    356:   cli                                  /* paranoid in case irq uses EBDA */
                    357:   movw %ax, BDA_EBDA                   /* save new EBDA segment start */
                    358:   subw $SGABIOS_EBDA_KB, BDA_MEM_SIZE  /* subtract extra allocation */
                    359:   movw %ax, %ds                        /* ds = new EBDA segment start */
                    360:   movw $SGABIOS_EBDA_BYTES, %si        /* si = offset of first byte to move */
                    361:   movzbw (%si), %cx                    /* cx = number of KB in EBDA */
                    362:   addb $SGABIOS_EBDA_KB, (%si)         /* update EBDA size in kb */
                    363:   shlw $10, %cx                        /* cx = KB * 1024 = bytes in EBDA */
                    364:   movw %cx, %cs:sgabios_ebda_logbuf_offset  /* new ebda space */
                    365:   xorw %di, %di                        /* di = new EBDA start */
                    366:   cld
                    367:   rep
                    368:   movsb                                /* move ebda by SGABIOS_EBDA_BYTES */
                    369:   movw %cs:sgabios_ebda_logbuf_offset, %bx  /* bx = new buffer */
                    370:   movl $SGABIOS_EBDA_SIGNATURE, (%bx)  /* setup signature */
                    371:   movw $SGABIOS_EBDA_BYTES, 4(%bx)     /* bytes in new ebda buffer */
                    372:   movw $0, 6(%bx)                      /* next log index, new ebda buffer */
                    373: sgabioslog_setup_ebda_tail:
                    374:   popw %es
                    375:   popw %ds
                    376:   popaw
                    377:   popf
                    378:   ret
                    379: 
                    380: /*
                    381:  * sgabioslog_save_char
                    382:  *
                    383:  * Like memconsole_log_char, except the original, untranslated
                    384:  * character is expected to be given in the %al register.
                    385:  *
                    386:  * The original character and its corresponding cursor position
                    387:  * are logged to the sgabios ebda memory allocation.
                    388:  *
                    389:  * %al = character to be logged
                    390:  * All registers except flags should be preserved
                    391:  */
                    392: 
                    393: sgabioslog_save_char:
                    394:   pushaw
                    395:   pushw %ds
                    396:   pushw %es
                    397:   pushw $BDA_SEG
                    398:   popw %ds                             /* ds = 0x40 */
                    399:   pushw BDA_EBDA                       /* push word at 0x0e */
                    400:   popw %es                             /* es = EBDA_SEG */
                    401:   movw %cs:sgabios_ebda_logbuf_offset, %di
                    402:   orw %di, %di                         /* is offset zero? */
                    403:   jz sgabioslog_save_tail              /* if so, bail */
                    404:   cmpl $SGABIOS_EBDA_SIGNATURE, %es:(%di)
                    405:   jnz sgabioslog_save_tail             /* bail if magic not found */
                    406:   movw %es:6(%di), %bx                 /* bx = index of next char output */
                    407:   movb %al, %es:SGABIOS_EBDA_LOG_START(%bx,%di)  /* store character */
                    408:   movzbw %bl, %ax                      /* %ax = next cursor buffer index */
                    409:   shlw $1, %ax                         /* %ax = offset to cursor storage */
                    410:   call get_current_cursor              /* %dh = row, %dl = column */
                    411:   addw $SGABIOS_EBDA_POS_START, %di    /* cursor storage */
                    412:   addw %ax, %di                        /* %di = next cursor storage offset */
                    413:   movw %dx, %es:(%di)                  /* save position for logged char */
                    414:   incw %bx                             /* point to next char to log */
                    415:   cmpw $SGABIOS_EBDA_LOG_SIZE, %bx
                    416:   jnz sgabioslog_save_index
                    417:   xorw %bx, %bx                        /* wrap around to start */
                    418: sgabioslog_save_index:
                    419:   movw %cs:sgabios_ebda_logbuf_offset, %di
                    420:   movw %bx, %es:6(%di)                 /* save new index */
                    421: sgabioslog_save_tail:
                    422:   popw %es
                    423:   popw %ds
                    424:   popaw
                    425:   ret
                    426: 
                    427: /*
                    428:  * sgabioslog_get_char
                    429:  *
                    430:  * Return the character at current cursor position, last recorded
                    431:  * to sgabios ebda allocation, if available.
                    432:  *
                    433:  * If the current cursor postition contains one of the last 256 characters
                    434:  * written to the ebda buffer, return that character, else return 0.
                    435:  *
                    436:  * If sgabios_ebdda_logbuf_offset is zero, %al will be 0 and zf set
                    437:  *
                    438:  * All registers except flags and %al should be preserved
                    439:  */
                    440: 
                    441: sgabioslog_get_char:
                    442:   pushaw
                    443:   movw %sp, %bp
                    444:   movb $0, 14(%bp)                     /* %al on stack = 0 */
                    445:   pushw %ds
                    446:   pushw %es
                    447:   pushw $BDA_SEG
                    448:   popw %ds                             /* ds = 0x40 */
                    449:   pushw BDA_EBDA                       /* push word at 0x0e */
                    450:   popw %es                             /* es = EBDA_SEG */
                    451:   movw %cs:sgabios_ebda_logbuf_offset, %di
                    452:   orw %di, %di
                    453:   jz sgabioslog_get_tail               /* offset==0, no logging */
                    454:   cmpl $SGABIOS_EBDA_SIGNATURE, %es:(%di)
                    455:   jnz sgabioslog_get_tail              /* bail if magic not found */
                    456:   call get_current_cursor              /* dh = row, dl = col */
                    457:   std                                  /* scan backwards in mem */
                    458:   movw %es:6(%di), %bx                 /* bx = index of next char output */
                    459:   decw %bx                             /* %bx = offset of last char in buf */
                    460:   jnc sgabioslog_got_pos
                    461:   addw $SGABIOS_EBDA_LOG_SIZE, %bx     /* bx position wrap around */
                    462: sgabioslog_got_pos:
                    463:   movw %bx, %ax                        /* %ax = last cursor pos written */
                    464:   shlw $1, %ax                         /* %ax = offset of last cursor pos */
                    465:   addw $SGABIOS_EBDA_POS_START, %di    /* %di = first cursor position */
                    466:   addw %ax, %di                        /* %di = offset in ebda */
                    467:   movw %dx, %ax                        /* %ax = cursor pos to compare */
                    468:   movw %bx, %cx                        /* %cx = positions before wrap */
                    469:   jcxz sgabioslog_cmp_wrap             /* if zero, try from end next */
                    470:   repnz
                    471:   scasw                                /* search until position match */
                    472:   addw $2, %di                         /* scasd always decrements di, undo */
                    473:   cmpw %ax, %es:(%di)                  /* did it really match? */
                    474:   jz sgabioslog_cursor_match           /* if so, do something */
                    475: sgabioslog_cmp_wrap:
                    476:   movw %cs:sgabios_ebda_logbuf_offset, %di
                    477:   addw $SGABIOS_EBDA_POS_LAST, %di     /* %di = last cursor storage */
                    478:   movw $SGABIOS_EBDA_LOG_SIZE, %cx     /* %cx = compare all positions */
                    479:   repnz
                    480:   scasw                                /* search until position match */
                    481:   addw $2, %di                         /* scasd always decrements di, undo */
                    482:   cmpw %ax, %es:(%di)                  /* did it really match? */
                    483:   jnz sgabioslog_get_tail              /* if not, bail */
                    484: sgabioslog_cursor_match:
                    485:   /* %di contains the EBDA offset of the matching position */
                    486:   /* convert this into a memconsole offset */
                    487:   subw $512, %di                       /* take off the storage offset */
                    488:   subw %cs:sgabios_ebda_logbuf_offset, %di  /* and ebda offset */
                    489:   shrw $1, %di                         /* %di = char position index */
                    490:   addw %cs:sgabios_ebda_logbuf_offset, %di  /* add back ebda offset */
                    491:   addw $SGABIOS_EBDA_LOG_START, %di    /* and add back log offset */
                    492:   movb %es:(%di), %al                  /* get related saved character */
                    493:   movb %al, 14(%bp)                    /* %al on stack = logged char */
                    494: sgabioslog_get_tail:
                    495:   popw %es
                    496:   popw %ds
                    497:   popaw
                    498:   ret
                    499: 
                    500: /*
                    501:  * multibyteinput
                    502:  *
                    503:  * When an escape key is detected, the input routines will attempt to
                    504:  * capture as many characters as arrive up until a timeout, or six,
                    505:  * whichever is less.
                    506:  *
                    507:  * This table is intended to decide what the characters after the
                    508:  * initial escape key translate to in terms of high and low bytes
                    509:  * that go into the keyboard buffer the high byte is the scancode,
                    510:  * the low byte is ascii, but for special keys this is usually 0xe0
                    511:  * or 0x00.
                    512:  *
                    513:  * This table is formatted so that the first word is a scancode +
                    514:  * ascii pair (as returned by int 16h, ah = 10h or 11h).  Immediately
                    515:  * following is a nul-terminated ascii string to match in order to
                    516:  * use the corresponding scancode+ascii word.
                    517:  *
                    518:  * The search through this table is terminated by a match or finding
                    519:  * a 0 scancode+ascii word.
                    520:  *
                    521:  * FIXME: all the low bytes are now zero, get rid of them?
                    522:  */
                    523: multibyteinput:
                    524:   .byte 0x3b                           /* F1 */
                    525:   .asciz "[[A"                         /* F1/screen */
                    526: 
                    527:   .byte 0x3b                           /* F1 */
                    528:   .asciz "OP"                          /* F1/xterm/ansi */
                    529: 
                    530:   .byte 0x3b                           /* F1 */
                    531:   .asciz "[11~"                        /* F1/vt400 */
                    532: 
                    533:   .byte 0x3c                           /* F2 */
                    534:   .asciz "[[B"                         /* F2/screen */
                    535: 
                    536:   .byte 0x3c                           /* F2 */
                    537:   .asciz "OQ"                          /* F2/xterm/ansi */
                    538: 
                    539:   .byte 0x3c                           /* F2 */
                    540:   .asciz "[12~"                        /* F2/vt400 */
                    541: 
                    542:   .byte 0x3d                           /* F3 */
                    543:   .asciz "[[C"                         /* F3/screen */
                    544: 
                    545:   .byte 0x3d                           /* F3 */
                    546:   .asciz "OR"                          /* F3/xterm/ansi */
                    547: 
                    548:   .byte 0x3d                           /* F3 */
                    549:   .asciz "[13~"                        /* F3/vt400 */
                    550: 
                    551:   .byte 0x3e                           /* F4 */
                    552:   .asciz "[[D"                         /* F4/screen */
                    553: 
                    554:   .byte 0x3e                           /* F4 */
                    555:   .asciz "OS"                          /* F4/xterm/ansi */
                    556: 
                    557:   .byte 0x3e                           /* F4 */
                    558:   .asciz "[14~"                        /* F4/vt400 */
                    559: 
                    560:   .byte 0x3f                           /* F5 */
                    561:   .asciz "[[E"                         /* F5/screen */
                    562: 
                    563:   .byte 0x3f                           /* F5 */
                    564:   .asciz "[15~"                        /* F5/xterm */
                    565: 
                    566:   .byte 0x3f                           /* F5 */
                    567:   .asciz "OT"                          /* F5/ansi */
                    568: 
                    569:   .byte 0x40                           /* F6 */
                    570:   .asciz "[17~"                        /* F6/screen/vt220/xterm/vt400 */
                    571: 
                    572:   .byte 0x40                           /* F6 */
                    573:   .asciz "OU"                          /* F6/ansi */
                    574: 
                    575:   .byte 0x41                           /* F7 */
                    576:   .asciz "[18~"                        /* F7/screen/vt220/xterm/vt400 */
                    577: 
                    578:   .byte 0x41                           /* F7 */
                    579:   .asciz "OV"                          /* F7/ansi */
                    580: 
                    581:   .byte 0x42                           /* F8 */
                    582:   .asciz "[19~"                        /* F8/screen/vt220/xterm/vt400 */
                    583: 
                    584:   .byte 0x42                           /* F8 */
                    585:   .asciz "OW"                          /* F8/ansi */
                    586: 
                    587:   .byte 0x43                           /* F9 */
                    588:   .asciz "[20~"                        /* F9/screen/vt220/xterm/vt400 */
                    589: 
                    590:   .byte 0x43                           /* F9 */
                    591:   .asciz "OX"                          /* F9/ansi */
                    592: 
                    593:   .byte 0x44                           /* F10 */
                    594:   .asciz "[21~"                        /* F10/screen/vt220/xterm/vt400 */
                    595: 
                    596:   .byte 0x44                           /* F10 */
                    597:   .asciz "OY"                          /* F10/ansi */
                    598: 
                    599:   .byte 0x85                           /* F11 */
                    600:   .asciz "[23~"                        /* F11/screen/xterm/vt400 */
                    601: 
                    602:   .byte 0x85                           /* F11 */
                    603:   .asciz "OZ"                          /* F11/ansi */
                    604: 
                    605:   .byte 0x86                           /* F12 */
                    606:   .asciz "[24~"                        /* F12/screen/xterm/vt400 */
                    607: 
                    608:   .byte 0x52                           /* Insert */
                    609:   .asciz "[2~"                         /* Insert/screen/vt102/xterm */
                    610: 
                    611:   .byte 0x53                           /* Delete */
                    612:   .asciz "[3~"                         /* Delete/screen/vt102/xterm */
                    613: 
                    614:   .byte 0x4b                           /* Left */
                    615:   .asciz "OD"                          /* Left/screen/vt102 */
                    616: 
                    617:   .byte 0x4b                           /* Left */
                    618:   .asciz "[D"                          /* Left/xterm */
                    619: 
                    620:   .byte 0x47                           /* Home */
                    621:   .asciz "[1~"                         /* Home/screen/vt102 */
                    622: 
                    623:   .byte 0x47                           /* Home */
                    624:   .asciz "[H"                          /* Home/xterm */
                    625: 
                    626:   .byte 0x4f                           /* End */
                    627:   .asciz "[4~"                         /* End/screen/vt102 */
                    628: 
                    629:   .byte 0x4f                           /* End */
                    630:   .asciz "[F"                          /* End/xterm */
                    631: 
                    632:   .byte 0x48                           /* Up */
                    633:   .asciz "OA"                          /* Up/screen/vt102 app */
                    634: 
                    635:   .byte 0x48                           /* Up */
                    636:   .asciz "[A"                          /* Up/xterm/vt102 ansi */
                    637: 
                    638:   .byte 0x50                           /* Down */
                    639:   .asciz "OB"                          /* Down/screen/vt102 app */
                    640: 
                    641:   .byte 0x50                           /* Down */
                    642:   .asciz "[B"                          /* Down/xterm/vt102 ansi */
                    643: 
                    644:   .byte 0x49                           /* PageUp */
                    645:   .asciz "[5~"                         /* PageUp/screen/vt102/xterm */
                    646: 
                    647:   .byte 0x51                           /* PageDown */
                    648:   .asciz "[6~"                         /* PageDown/screen/vt102/xterm */
                    649: 
                    650:   .byte 0x4d                           /* Right */
                    651:   .asciz "OC"                          /* Right/screen/vt102 app */
                    652: 
                    653:   .byte 0x4d                           /* Right */
                    654:   .asciz "[C"                          /* Right/xterm/vt102 ansi */
                    655: 
                    656:   .byte 0                              /* end of table marker */
                    657: 
                    658: /* init_serial_port
                    659:  *
                    660:  * Initialize serial port to 115200,8n1
                    661:  * Serial interrupts disabled
                    662:  *
                    663:  * All registers except flags preserved
                    664:  */
                    665: 
                    666: init_serial_port:
                    667:   pushw %ax
                    668:   pushw %dx
                    669:   pushw %bx
                    670:   movw %cs:serial_port_base_address, %dx
                    671:   addw $IER_OFFSET, %dx
                    672:   xorb %al, %al
                    673:   outb %al, %dx                        /* disable all serial interrupts */
                    674:   addw $(LCR_OFFSET - IER_OFFSET), %dx /* LCR */
                    675:   movb $(LCR_VALUE|LCR_DLAB), %al
                    676:   outb %al, %dx                        /* enable divisor access */
                    677:   movw %cs:serial_port_base_address, %dx
                    678:   movw $(PORT_DIVISOR/PORT_SPEED), %bx
                    679:   movb %bl, %al                        /* al = lsb of divisor */
                    680:   outb %al, %dx                        /* set divisor latch lsb */
                    681:   movb %bh, %al                        /* al = msb of divisor */
                    682:   incw %dx
                    683:   outb %al, %dx                        /* set divisor latch msb */
                    684:   movw %cs:serial_port_base_address, %dx
                    685:   addw $LCR_OFFSET, %dx
                    686:   movb $LCR_VALUE, %al
                    687:   outb %al, %dx                        /* disable divisor access */
                    688:   addw $(MCR_OFFSET - LCR_OFFSET), %dx /* MCR */
                    689:   movb $MCR_DTRRTS, %al
                    690:   outb %al, %dx                        /* enable DTR + RTS */
                    691:   movw %cs:serial_port_base_address, %dx
                    692:   addw $FCR_OFFSET, %dx
                    693:   movb $FCR_FIFO_ENABLE, %al
                    694:   outb %al, %dx                        /* enable FIFOs */
                    695:   popw %bx
                    696:   popw %dx
                    697:   popw %ax
                    698:   ret
                    699: 
                    700: 
                    701: /* get_serial_lsr
                    702:  *
                    703:  * return serial line status register in %al
                    704:  * return offset to serial port line status register io port in %dx
                    705:  * all other registers except flags unchanged
                    706:  *
                    707:  * if status == 0xff  return ZF=1, else return ZF=0
                    708:  */
                    709: 
                    710: get_serial_lsr:
                    711:   movw %cs:serial_port_base_address, %dx
                    712:   addw $LSR_OFFSET, %dx
                    713:   inb %dx, %al
                    714:   cmpb $0xff, %al
                    715:   ret
                    716:   
                    717: /*
                    718:  * get_byte
                    719:  *
                    720:  * get serial byte in %al, scancode in %ah [FIXME: EFI console input]
                    721:  *
                    722:  * all registers except %ax preserved
                    723:  *
                    724:  */
                    725: 
                    726: get_byte:
                    727:   pushw %dx
                    728:   pushw %bx
                    729: next_serial_char:
                    730:   call get_serial_lsr                  /* get serial lsr in %al */
                    731:   jz get_byte_tail                     /* no port present... */
                    732:   testb $1, %al                        /* bit 0 of LSR = 1 = data available */
                    733:   jz get_byte_tail                     /* no input waiting */
                    734:   /* new character found on serial port */
                    735:   /* convert it to a scancode */
                    736:   movw %cs:serial_port_base_address, %dx
                    737:   inb %dx, %al                         /* al = serial input char */
                    738:   testb $0x80, %al                     /* non-ascii char received? */
                    739:   jnz next_serial_char                 /* throw char away */
                    740:   movb %al, %dl                        /* dl = character read */
                    741:   pushw %ds
                    742:   pushw %cs
                    743:   popw %ds                             /* ds = cs */
                    744:   movw $ascii2scan, %bx                /* table to translate ascii->scan */
                    745:   xlatb                                /* translate char to scancode */
                    746:   popw %ds
                    747:   /* shift status is ignored at this point, may be used later */
                    748:   andb $0x7f, %al                      /* strip shift status from table */
                    749:   movb %al, %ah                        /* scancode goes in high byte */
                    750:   movb %dl, %al                        /* "translated" ascii in lower byte */
                    751:   cmpb $0x7f, %al                      /* Did the user transmit ascii DEL? */
                    752:   jnz get_byte_not_del                 /* if not, don't do anything to al */
                    753:   movb $0x08, %al                      /* else delete becomes backspace */
                    754: get_byte_not_del:
                    755:   testw %ax, %ax                       /* clear zero flag */
                    756: get_byte_tail:
                    757:   popw %bx
                    758:   popw %dx
                    759:   ret
                    760: 
                    761: /*
                    762:  * poll_byte
                    763:  *
                    764:  * get serial byte in %al, scancode in %ah [FIXME: EFI console input]
                    765:  * retry up to 65536 times for an expected input byte
                    766:  *
                    767:  * all registers except %ax preserved
                    768:  *
                    769:  */
                    770: 
                    771: poll_byte:
                    772:   pushw %cx
                    773:   xorw %cx, %cx
                    774: poll_byte_retry:
                    775:   inb $0xed, %al
                    776:   call get_byte
                    777:   loopz poll_byte_retry                /* repeat while zf set or cx != 0 */
                    778:   popw %cx
                    779:   ret
                    780: 
                    781: /*
                    782:  * get_multibyte
                    783:  *
                    784:  * after an escape character, poll for terminal keys that generate
                    785:  * an escape code plus multiple bytes (up to four).
                    786:  *
                    787:  * if no byte is waiting, all registers preserved except flags
                    788:  * if more bytes are waiting, all registers preserved except %ax and flags
                    789:  *
                    790:  */
                    791: get_multibyte:
                    792:   pushw %bp                            /* bp points to temp buffer on stack */
                    793:   pushw %bx                            /* bx points to multibyteinput table */
                    794:   pushw %cx                            /* cx will count chars */
                    795:   pushw %ax                            /* ax will receive chars */
                    796:   pushl $0                             /* make space on stack for 4 chars */
                    797:   xorw %cx, %cx                        /* cx = 0 */
                    798:   movw %sp, %bp                        /* point bp at temp data */
                    799:   call poll_byte                       /* is a character waiting? */
                    800:   jz get_multibyte_tail                /* if not, bail */
                    801: get_multibyte_store:
                    802:   movb %al, (%bp)                      /* store char received */
                    803:   incb %cl                             /* mark one char received */
                    804:   incw %bp                             /* point to next char */
                    805:   cmpb $4, %cl                         /* got enough chars? */
                    806:   jz got_multibyte                     /* no strings longer than 4 chars */
                    807:   call poll_byte                       /* is another char waiting? */
                    808:   jnz get_multibyte_store              /* store a new one if it's there */
                    809: got_multibyte:
                    810:   movw $multibyteinput, %bx            /* point to first scancode */
                    811: got_multibyte_findkey:
                    812:   movw %sp, %bp                        /* bp = start of buffer */
                    813:   movb %cs:(%bx), %ah                  /* ah = scancode */
                    814:   incw %bx                             /* bx = start of test string */
                    815:   orb %ah, %ah                         /* is it zero? */
                    816:   jz get_multibyte_tail                /* if so, bail, key not found */
                    817: got_multibyte_nextchar:
                    818:   movb %cs:(%bx), %ch                  /* ch = test char to compare */
                    819:   incw %bx                             /* point to next char */
                    820:   orb %ch, %ch                         /* is char to compare NUL? */
                    821:   jz got_multibyte_key                 /* matched to end of a string! */
                    822:   cmpb %ch, (%bp)                      /* input tmp buf equal to test char? */
                    823:   jnz got_multibyte_try_next_key
                    824:   /* note: expected that test string will be nul before input string */
                    825:   /* no attempt is made to ensure no more than 4 bytes stack read */
                    826:   incw %bp                             /* point to next input */
                    827:   jmp got_multibyte_nextchar
                    828: got_multibyte_try_next_key:  /* align to next scancode/ascii pair */
                    829:   movb %cs:(%bx), %ch                  /* ch = test char to compare */
                    830:   incw %bx                             /* point to next char */
                    831:   orb %ch, %ch                         /* is char to compare NUL? */
                    832:   jnz got_multibyte_try_next_key
                    833:   jmp got_multibyte_findkey
                    834: got_multibyte_key:
                    835:   xorb %al, %al                        /* ascii value = 0 for special keys */
                    836:   movw %sp, %bp
                    837:   movw %ax, 4(%bp)                     /* overwrite old %ax value with key */
                    838: get_multibyte_tail:
                    839:   addw $4, %sp                         /* pop temp space */
                    840:   popw %ax
                    841:   popw %cx
                    842:   popw %bx
                    843:   popw %bp
                    844:   ret
                    845: 
                    846: /*
                    847:  * send_byte
                    848:  *
                    849:  * send character in %al to serial port [FIXME: EFI console out]
                    850:  *
                    851:  * all registers preserved except flags
                    852:  *
                    853:  */
                    854: 
                    855: send_byte:
                    856:   pushw %ax
                    857:   pushw %dx
                    858:   pushw %cx
                    859:   testb $0x80, %al                     /* don't send non-ascii chars */
                    860:   jnz send_tail                        /* these should be translated earlier */
                    861:   movb %al, %ah                        /* save char to output in %ah */
                    862:   movw $0xFFF0, %cx                    /* only retry 65520 times */
                    863: serial_ready_test:
                    864:   call get_serial_lsr                  /* get serial lsr in %al */
                    865:   testb $TRANSMIT_READY_BIT, %al
                    866:   loopz serial_ready_test              /* if !tx ready, loop while cx!=0 */
                    867:   movb %ah, %al
                    868:   movw %cs:serial_port_base_address, %dx
                    869:   outb %al, %dx
                    870: send_tail:
                    871:   popw %cx
                    872:   popw %dx
                    873:   popw %ax
                    874:   ret
                    875: 
                    876: /*
                    877:  * translate_char
                    878:  *
                    879:  * translate vga character in %al to ascii
                    880:  *
                    881:  * returns:
                    882:  * al = translated character
                    883:  *
                    884:  * all registers except %al preserved
                    885:  *
                    886:  */
                    887: 
                    888: translate_char:
                    889:   pushw %bx
                    890:   pushw %ds
                    891:   pushw %cs
                    892:   popw %ds                             /* ds = cs */
                    893:   testb $0x80, %al
                    894:   jz translate_char_ctrl
                    895:   andb $0x7f, %al
                    896:   movw $high2ascii, %bx
                    897:   xlatb
                    898: translate_char_ctrl:
                    899:   cmpb $0x20, %al
                    900:   jnc translate_char_tail
                    901:   movw $ctrl2ascii, %bx
                    902:   xlatb
                    903: translate_char_tail:
                    904:   popw %ds
                    905:   popw %bx
                    906:   ret
                    907: 
                    908: /*
                    909:  * translate_char_tty
                    910:  *
                    911:  * translate vga character in %al to ascii
                    912:  * unless %al == 7, 8, 10, or 13 (bell, bs, lf, cr)
                    913:  *
                    914:  * returns:
                    915:  * al = translated character
                    916:  *
                    917:  * all registers except %al preserved
                    918:  *
                    919:  */
                    920: 
                    921: translate_char_tty:
                    922:   cmpb $0x07, %al                      /* bell */
                    923:   jz translate_char_tty_tail
                    924:   cmpb $0x08, %al                      /* backspace */
                    925:   jz translate_char_tty_tail
                    926:   cmpb $0x0a, %al                      /* LF */
                    927:   jz translate_char_tty_tail
                    928:   cmpb $0x0d, %al                      /* CR */
                    929:   jz translate_char_tty_tail
                    930:   call translate_char
                    931: translate_char_tty_tail:
                    932:   ret
                    933: 
                    934: /*
                    935:  * send_char
                    936:  *
                    937:  * send character 0 - 255 in %al out through serial port
                    938:  * increment cursor position without control processing
                    939:  *
                    940:  * send_byte is used for data that isn't tracked
                    941:  *
                    942:  * send_char is used for text that should be tracked
                    943:  * send_char outputs all characters as non-control chars
                    944:  *
                    945:  * returns:
                    946:  * al = translated character
                    947:  *
                    948:  * all registers except %al preserved
                    949:  *
                    950:  */
                    951: 
                    952: send_char:
                    953:   call sgabioslog_save_char            /* save original char+pos */
                    954:   call translate_char
                    955:   jmp send_char_tty_out
                    956:   /* after ctrl translation, same as send_char_tty */
                    957: 
                    958: /*
                    959:  * send_char_tty
                    960:  *
                    961:  * send character 0 - 255 in %al out through serial port
                    962:  * increment cursor position *with* control processing
                    963:  * for bell, linefeed, cr, and backspace (others all printable)
                    964:  *
                    965:  * send_byte is used for data that isn't tracked
                    966:  *
                    967:  * send_char_tty is used for text that should be tracked
                    968:  *
                    969:  * returns:
                    970:  * al = translated character
                    971:  *
                    972:  * all registers except %al preserved
                    973:  *
                    974:  */
                    975: 
                    976: 
                    977: /* send character 0 - 255 in %al out through serial port */
                    978: /* increment cursor position with CR/LF/Backspace processing */
                    979: send_char_tty:
                    980:   call sgabioslog_save_char            /* save original char+pos */
                    981:   call translate_char_tty
                    982: send_char_tty_out:
                    983:   pushw %dx
                    984:   call update_serial_cursor
                    985:   call get_current_cursor              /* vga cursor in %dx */
                    986:   cmpb $0x0d, %al                      /* CR */
                    987:   jnz send_char_tty_nul                /* if not CR, check for NUL */
                    988:   orb %dl, %dl                         /* already at col 0? */
                    989:   jz send_char_tty_tail                /* no need to re-send CR */
                    990: send_char_tty_nul:
                    991:   orb %al, %al                         /* %al == 0 ? (nul) */
                    992:   /* more than likely, we have NUL at this point because the caller */
                    993:   /* tried to read a char using int $0x10, %ah=8, and is trying */
                    994:   /* to re-output it with different attributes - for now send nothing */
                    995:   jz send_char_tty_tail
                    996: send_char_tty_write:
                    997:   call memconsole_log_char             /* log character sent */
                    998:   call send_byte
                    999:   cmpb $0x07, %al                      /* bell */
                   1000:   jz send_char_tty_tail                /* no cursor update for bell */
                   1001:   cmpb $0x08, %al                      /* backspace */
                   1002:   jz send_char_tty_backspace
                   1003:   cmpb $0x0a, %al                      /* LF */
                   1004:   jz send_char_tty_lf
                   1005:   cmpb $0x0d, %al                      /* CR */
                   1006:   jz send_char_tty_cr
                   1007:   incb %dl
                   1008:   jmp send_char_tty_tail
                   1009: send_char_tty_backspace:
                   1010:   orb %dl, %dl
                   1011:   jz send_char_tty_tail
                   1012:   decb %dl
                   1013:   jmp send_char_tty_tail
                   1014: send_char_tty_lf:
                   1015:   incb %dh
                   1016:   jmp send_char_tty_tail
                   1017: send_char_tty_cr:
                   1018:   xorb %dl, %dl
                   1019: send_char_tty_tail:
                   1020:   cmpb %cs:term_cols, %dl
                   1021:   jc send_char_tty_check_rows
                   1022:   movb %cs:term_cols, %dl
                   1023:   decb %dl                             /* dl = cols - 1 */
                   1024: send_char_tty_check_rows:
                   1025:   cmpb %cs:term_rows, %dh
                   1026:   jc send_char_tty_save_cursor
                   1027:   movb %cs:term_rows, %dh
                   1028:   decb %dh                             /* dh = rows - 1 */
                   1029: send_char_tty_save_cursor:
                   1030:   call set_current_cursor
                   1031:   pushw %ds
                   1032:   pushw $BDA_SEG
                   1033:   popw %ds
                   1034:   /* save current position as the serial terminal position */
                   1035:   /* since a character was just output at that position */
                   1036:   movw %dx, BDA_SERIAL_POS
                   1037:   popw %ds
                   1038:   popw %dx
                   1039:   ret
                   1040: 
                   1041: /*
                   1042:  * send_asciz_out
                   1043:  *
                   1044:  * send nul terminated string pointed to by %ds:%si
                   1045:  * to serial port without text tracking
                   1046:  *
                   1047:  * indended to be used for multi-byte send_byte
                   1048:  *
                   1049:  * all registers preserved except flags
                   1050:  */
                   1051: 
                   1052: send_asciz_out:
                   1053:   pushw %ax
                   1054:   pushw %si
                   1055:   cld
                   1056: send_asciz_loop:
                   1057:   lodsb
                   1058:   test %al,%al
                   1059:   jz send_asciz_end
                   1060:   call send_byte
                   1061:   jmp send_asciz_loop
                   1062: send_asciz_end:
                   1063:   popw %si
                   1064:   popw %ax
                   1065:   ret
                   1066: 
                   1067: /*
                   1068:  * send_string
                   1069:  *
                   1070:  * send cx chars in string pointed to by %ds:%si
                   1071:  * to serial port with tty tracking
                   1072:  * 
                   1073:  * indended to be used for multi-byte send_char_tty
                   1074:  *
                   1075:  * all registers preserved except flags
                   1076:  */
                   1077: 
                   1078: send_string:
                   1079:   pushw %ax
                   1080:   pushw %si
                   1081:   cld
                   1082: send_string_loop:
                   1083:   lodsb
                   1084:   call send_char_tty
                   1085:   loop send_string_loop
                   1086:   popw %si
                   1087:   popw %ax
                   1088:   ret
                   1089: 
                   1090: /*
                   1091:  * send_string
                   1092:  *
                   1093:  * send cx chars in string pointed to by %ds:%si
                   1094:  * with interleaved attribute data
                   1095:  * 
                   1096:  * indended to be used for multi-byte send_char_tty
                   1097:  * with interleaved vga attribute updates
                   1098:  *
                   1099:  * all registers preserved except flags
                   1100:  */
                   1101: 
                   1102: send_attr_string:
                   1103:   pushw %ax
                   1104:   pushw %bx
                   1105:   pushw %si
                   1106:   cld
                   1107: send_attr_string_loop:
                   1108:   lodsb
                   1109:   call send_char_tty
                   1110:   lodsb
                   1111:   movb %al, %bl
                   1112:   call send_attribute                  /* send attribute in %bl */
                   1113:   loop send_attr_string_loop
                   1114:   popw %si
                   1115:   popw %bx
                   1116:   popw %ax
                   1117:   ret
                   1118: 
                   1119: /*
                   1120:  * send_number
                   1121:  *
                   1122:  * send ascii version of number in %al to serial port
                   1123:  * 
                   1124:  * intended for ansi cursor positions and attributes,
                   1125:  * so cursor position is not tracked/updated
                   1126:  *
                   1127:  * all registers preserved except flags
                   1128:  */
                   1129: 
                   1130: send_number:
                   1131:   pushw %ax
                   1132:   pushw %bx
                   1133:   aam                                  /* ah = al/10, al = al mod 10 */
                   1134:   movw %ax, %bx                        /* bh = al/10, bl = al mod 10 */
                   1135:   movb %bh, %al
                   1136:   aam                                  /* ah = bh/10, al = bh mod 10 */
                   1137:   movb %al, %bh                        /* bh = 10s digit, bl = 1s digit */
                   1138:   movb %ah, %al                        /* ah = al = 100s digit */
                   1139:   testb %al, %al                       /* is there a 100s digit? */
                   1140:   jz send_tens                         /* move to tens if not */
                   1141:   orb $0x30, %al                       /* al = ascii value of digit */
                   1142:   call send_byte
                   1143: send_tens:
                   1144:   orb %bh, %ah                         /* bh = 10s, ah = 100s digits */
                   1145:   jz send_ones                         /* non-zero = must send tens */
                   1146:   movb %bh, %al                        /* al = bh = 10s digit */
                   1147:   orb $0x30, %al                       /* al = ascii value of digit */
                   1148:   call send_byte
                   1149: send_ones:
                   1150:   movb %bl, %al                        /* al = bl = 1s digit */
                   1151:   orb $0x30, %al                       /* al = ascii value of digit */
                   1152:   call send_byte
                   1153:   popw %bx
                   1154:   popw %ax
                   1155:   ret
                   1156: 
                   1157: /*
                   1158:  * send_crlf
                   1159:  *
                   1160:  * send CRLF to serial port
                   1161:  * 
                   1162:  * FIXME: used at vga init and for scrolling terminal
                   1163:  * so position is not tracked.  Callers of this routine
                   1164:  * predate the code that does smart tty/cursor output.
                   1165:  *
                   1166:  * Callers should probably be changed to use those
                   1167:  * routines or send_crlf changed to use them and
                   1168:  * terminal scrolling fixed to use linefeed only.
                   1169:  *
                   1170:  * all registers preserved except flags
                   1171:  */
                   1172: 
                   1173: send_crlf:
                   1174:   pushw %ax
                   1175:   movb $0x0d, %al
                   1176:   call send_byte
                   1177:   movb $0x0a, %al
                   1178:   call send_byte
                   1179:   popw %ax
                   1180:   ret
                   1181: /*
                   1182:  * send_ansi_csi
                   1183:  *
                   1184:  * send ESCAPE [ to serial port
                   1185:  * 
                   1186:  * output is not tracked since these are control sequences
                   1187:  *
                   1188:  * all registers preserved except flags
                   1189:  */
                   1190: 
                   1191: send_ansi_csi:      /* transmit ESC [ */
                   1192:   pushw %ax
                   1193:   movb $0x1b, %al                      /* escape */
                   1194:   call send_byte
                   1195:   movb $0x5b, %al                      /* [ */
                   1196:   call send_byte
                   1197:   popw %ax
                   1198:   ret
                   1199: /*
                   1200:  * send_ansi_csi_2num
                   1201:  *
                   1202:  * send ESC [ %dh ; %dl to serial port
                   1203:  * 
                   1204:  * since both position and attribute updates generally have
                   1205:  * two parameters, this function converts values in dx to
                   1206:  * two ascii numbers.  It's expected that the caller will
                   1207:  * output the final trailing H or m or whatever is required.
                   1208:  *
                   1209:  * output is not tracked since these are control sequences
                   1210:  *
                   1211:  * all registers preserved except flags
                   1212:  */
                   1213: 
                   1214: send_ansi_csi_2num:
                   1215: /* send ESC [ %dh ; %dl */
                   1216:   pushw %ax
                   1217:   call send_ansi_csi                   /* esc [ */
                   1218:   movb %dh, %al
                   1219:   call send_number
                   1220:   movb $0x3b, %al                      /* semicolon */
                   1221:   call send_byte
                   1222:   movb %dl, %al
                   1223:   call send_number
                   1224:   popw %ax
                   1225:   ret
                   1226: 
                   1227: /*
                   1228:  * send_ansi_cursor_pos
                   1229:  *
                   1230:  * send ESC [ %dh+1 ; %dl+1 to serial port to position
                   1231:  * cursor
                   1232:  * 
                   1233:  * since both position and attribute updates generally have
                   1234:  * two parameters, this function converts values in dx to
                   1235:  * two ascii numbers, after adding 1 to both dh and dl.
                   1236:  *
                   1237:  * output is not tracked since this is a control sequence
                   1238:  *
                   1239:  * all registers preserved except flags
                   1240:  */
                   1241: 
                   1242: send_ansi_cursor_pos:
                   1243:   pushw %ax
                   1244:   pushw %dx
                   1245:   addw $0x0101, %dx                    /* dh += 1, dl += 1 */
                   1246:   call send_ansi_csi_2num              /* send esc [ %dh+1;%dl+1 */
                   1247:   movb $0x48, %al                      /* H */
                   1248:   call send_byte
                   1249:   popw %dx
                   1250:   popw %ax
                   1251:   ret
                   1252: 
                   1253: /*
                   1254:  * send_attribute
                   1255:  *
                   1256:  * send ansi attribute change ESC [ 4x ; 3y ; (1|22)m
                   1257:  * if the attribute has changed since last sent (stored in bda)
                   1258:  * 
                   1259:  * output is not tracked since this is a control sequence
                   1260:  *
                   1261:  * all registers preserved except flags
                   1262:  */
                   1263: 
                   1264: send_attribute:
                   1265:   andb $0x7f, %bl                      /* ansi has no bright bg */
                   1266:   pushw %ds
                   1267:   pushw %es
                   1268:   pushw %ax
                   1269:   pushw %bx
                   1270:   pushw %dx
                   1271:   pushw $BDA_SEG
                   1272:   popw %es                             /* es = 0x40 */
                   1273:   pushw %cs
                   1274:   popw %ds                             /* ds = cs */
                   1275:   cmpb %es:BDA_COLOR_VAL, %bl
                   1276:   jz send_attribute_tail
                   1277:   cmpb $0x07, %bl                      /* is it white on black? */
                   1278:   jnz send_attribute_color
                   1279:   /* for white on black, send esc [ m */
                   1280:   call send_ansi_csi
                   1281:   jmp send_attribute_m                 /* send the m, return */
                   1282: send_attribute_color:
                   1283:   movb %bl, %ah                        /* ah = attribute */
                   1284:   movw $colortable, %bx
                   1285:   movb %ah, %al
                   1286:   andb $7, %al                         /* al = fg attr */
                   1287:   xlatb                                /* al = fg ansi num */
                   1288:   movb %al, %dl                        /* dl = fg ansi num */
                   1289:   movb %ah, %al
                   1290:   shrb $4, %al                         /* al = bg attr */
                   1291:   xlatb                                /* al = bg ansi num */
                   1292:   movb %al, %dh                        /* dh = bg ansi num */
                   1293:   addw $0x281e, %dx                    /* 3x=setfg, 4x=setbg */
                   1294:   call send_ansi_csi_2num
                   1295:   movb $0x3b, %al                      /* semicolon */
                   1296:   call send_byte
                   1297:   shlb $4, %ah                         /* bright text? */
                   1298:   sets %al                             /* if bit 7, al = 1 */
                   1299:   js send_attribute_intensity
                   1300:   movb $22, %al                        /* 22 = normal intensity */
                   1301: send_attribute_intensity:
                   1302:   call send_number                     /* either 22 or 1 */
                   1303: send_attribute_m:
                   1304:   movb $0x6d, %al                      /* m */
                   1305:   call send_byte
                   1306: send_attribute_tail:
                   1307:   popw %dx
                   1308:   popw %bx
                   1309:   /* mark attribute in %bl the current one */
                   1310:   movb %bl, %es:BDA_COLOR_VAL
                   1311:   popw %ax
                   1312:   popw %es
                   1313:   popw %ds
                   1314:   ret
                   1315: 
                   1316: /*
                   1317:  * serial_get_input
                   1318:  *
                   1319:  * common code for both interrupt-driven and non-interrupt
                   1320:  * driven serial input.   Called only when LSR bit 1 is set.
                   1321:  *
                   1322:  * No parameters, no return values
                   1323:  *
                   1324:  * Preserves all registers
                   1325:  */
                   1326: 
                   1327: serial_get_input:
                   1328:   pushf
                   1329:   /* be paranoid about int 9h happening during update */
                   1330:   cli
                   1331:   pushaw
                   1332:   pushw %ds
                   1333:   /* next char input buffer is at 0x40:0x1c */
                   1334:   pushw $BDA_SEG
                   1335:   popw %ds                             /* es = 0x40 */
                   1336:   call get_byte                        /* next scancode/byte in %ax */
                   1337:   cmpb $0x1b, %al                      /* look for escape */
                   1338:   jnz serial_gotkey                    /* not escape, don't look for more bytes */
                   1339:   call get_multibyte                   /* look for any chars after escape */
                   1340: serial_gotkey:
                   1341:   movw KBD_TAIL, %bx                   /* bx = keyboard tail pointer */
                   1342:   movw %ax, (%bx)                      /* store key in buffer */
                   1343:   addw $2, %bx                         /* point to next location */
                   1344:   cmpw $KBD_BUF_END, %bx               /* did the buffer wrap? */
                   1345:   jb kbd_buf_no_wrap
                   1346:   movw $KBD_BUF_START, %bx
                   1347: kbd_buf_no_wrap:
                   1348:   movw %bx, KBD_TAIL                   /* update tail pointer to show key */
                   1349:   popw %ds
                   1350:   popaw
                   1351:   popf
                   1352:   ret
                   1353: 
                   1354: /*
                   1355:  * irq3_isr
                   1356:  *
                   1357:  * entry point for irq 3 / int 0x0b / exception 11
                   1358:  *
                   1359:  * Called when COM2 or COM4 have characters pending
                   1360:  *
                   1361:  * The segment not present exception should never happen
                   1362:  * in real mode 16-bit code like this, but just to be safe,
                   1363:  * if this interrupt is invoked and no characters are
                   1364:  * pending on the port found in serial_port_base_address,
                   1365:  * this routine will chain to the original handler.
                   1366:  *
                   1367:  * If characters are found pending, they will be processed
                   1368:  * and control returned via iret.
                   1369:  */
                   1370: 
                   1371: irq3_isr:
                   1372: #if 0
                   1373:   pushw %ax
                   1374:   pushw %dx
                   1375:   /* placeholder, this shouldn't ever happen */
                   1376:   /* no interrupts are configured outside COM1 */
                   1377:   call get_serial_lsr                  /* get serial lsr in %al */
                   1378:   jz chain_irq3                        /* no port present... */
                   1379:   testb $1, %al                        /* bit 0 of LSR = 1 = data available */
                   1380:   jz chain_irq3                        /* no input waiting */
                   1381:   call serial_get_input                /* get input and stuff kbd buffer */
                   1382:   movb $0x20, %al
                   1383:   outb %al, $0x20                      /* send non-specific EOI */
                   1384:   popw %dx
                   1385:   popw %ax
                   1386:   iret
                   1387: chain_irq3:
                   1388:   popw %dx
                   1389:   popw %ax
                   1390: #endif
                   1391:   jmp do_old_irq3
                   1392: 
                   1393: /*
                   1394:  * irq4_isr
                   1395:  *
                   1396:  * entry point for irq 4 / int 0x0c / exception 12
                   1397:  *
                   1398:  * Called when COM1 or COM3 have characters pending
                   1399:  *
                   1400:  * The stack fault exception may occur if code attempts to
                   1401:  * read from sp:0xffff, so if this interrupt is invoked and
                   1402:  * no characters are pending on the port found in
                   1403:  * serial_port_base_address, this routine will chain to the
                   1404:  * original handler.
                   1405:  *
                   1406:  * If characters are found pending, they will be processed
                   1407:  * and control returned via iret.
                   1408:  */
                   1409: 
                   1410: irq4_isr:
                   1411: #if 0
                   1412:   pushw %ax
                   1413:   pushw %dx
                   1414:   call get_serial_lsr                  /* get serial lsr in %al */
                   1415:   jz chain_irq4                        /* no port present... */
                   1416:   testb $1, %al                        /* bit 0 of LSR = 1 = data available */
                   1417:   jz chain_irq4                        /* no input waiting */
                   1418:   call serial_get_input                /* get input and stuff kbd buffer */
                   1419:   movb $0x20, %al
                   1420:   outb %al, $0x20                      /* send non-specific EOI */
                   1421:   popw %dx
                   1422:   popw %ax
                   1423:   iret
                   1424: chain_irq4:
                   1425:   popw %dx
                   1426:   popw %ax
                   1427: #endif
                   1428:   jmp do_old_irq4
                   1429: 
                   1430: /*
                   1431:  * int14h_isr
                   1432:  *
                   1433:  * entry point for int 14h
                   1434:  *
                   1435:  */
                   1436: int14h_isr:
                   1437:   pushaw
                   1438:   movw %sp, %bp
                   1439:   addw $16, %bp                        /* bp points to return address */
                   1440:   orb %ah, %ah                         /* fn 0x00, initialize port */
                   1441:   jz int14h_init_port
                   1442:   cmpb $0x04, %ah                      /* fn 0x04, extended intialize */
                   1443:   jnz chain_isr14h
                   1444: int14h_init_port:
                   1445:   /* check for init port = current port */
                   1446:   pushw %ds
                   1447:   pushw $BDA_SEG
                   1448:   popw %ds                             /* ds = 0x40 */
                   1449:   movw %dx, %bx                        /* bx = port number */
                   1450:   shlw $1, %bx                         /* bx = port number * 2 */
                   1451:   andw $7, %bx                         /* bx = bda offset of serial io addr */
                   1452:   movw (%bx), %cx                      /* cx = io address of port to init */
                   1453:   popw %ds                             /* restore original ds */
                   1454:   cmpw %cx, %cs:serial_port_base_address
                   1455:   jnz chain_isr14h                     /* if different, don't get in the way */
                   1456:   /* init port == current port */
                   1457:   pushw %ds
                   1458:   /* LILO 22.6 HACK STARTS HERE */
                   1459:   movw (%bp), %bx                      /* return address for int 14h call */
                   1460:   movw 2(%bp), %ds                     /* return segment for int 14h call */
                   1461:   cmpl $0x4f4c494c, 0x06               /* does segment have lilo signature? */
                   1462:   jnz int14h_init_tail                 /* not lilo, bail on hack */
                   1463:   cmpw $0x0616, 0x0a                   /* does version match lilo 22.6? */
                   1464:   jnz int14h_init_tail                 /* unknown lilo release, bail on hack */
                   1465:   movb $0, 0x12                        /* set lilo com port = 0 */
                   1466:   movl $0x90c3585a, (%bx)              /* return code= pop dx;pop ax;ret;nop */
                   1467:   /* now lilo 22.6's own serial out is permanently disabled */
                   1468:   /* this prevents double-character output from int10h + serial */
                   1469:   /* this also prevents lilo from stealing serial input chars */
                   1470:   /* END LILO 22.6 HACK */
                   1471: int14h_init_tail:
                   1472:   popw %ds
                   1473:   popaw
                   1474:   pushw %dx                            /* get_serial_lsr trashes %dx */
                   1475:   call get_serial_lsr                  /* return serial status in %al */
                   1476:   xorb %ah, %ah                        /* return serial status in %ax */
                   1477:   popw %dx                             /* restore %dx */
                   1478:   iret
                   1479: chain_isr14h:
                   1480:   popaw
                   1481:   jmp do_old_int14h
                   1482: 
                   1483: /*
                   1484:  * int16h_isr
                   1485:  *
                   1486:  * entry point for int 16h
                   1487:  *
                   1488:  * keyboard characters are usually retrieved by calling
                   1489:  * int 16h, generally placed in the keyboard buffer by
                   1490:  * irq 1 (int 9h).  Poll serial port for new data before
                   1491:  * chaining to int 16h to fake irq 1 behavior
                   1492:  *
                   1493:  * all registers preserved except flags (later iret will restore)
                   1494:  * bda updated with a new keypress if available
                   1495:  *
                   1496:  * FIXME: handle multi-byte keypresses like cursor up/down
                   1497:  * to send proper scancodes for navigating lilo menus
                   1498:  */
                   1499: 
                   1500: int16h_isr:
                   1501:   pushw %ax
                   1502:   pushw %dx
                   1503:   /* each time int 16h is invoked, fake an int 9h */
                   1504:   /* except read the serial input buffer */
                   1505:   /* then chain to the original int 16h for processing */
                   1506:   call get_serial_lsr
                   1507:   jz chain_isr16h                      /* no port present... */
                   1508:   testb $1, %al                        /* bit 0 of LSR = 1 = data available */
                   1509:   jz chain_isr16h                      /* no input waiting */
                   1510:   call serial_get_input                /* get input and stuff kbd buffer */
                   1511:   /* for now, leave remaining chars pending in serial fifo */
                   1512:   /* int 16h callers only get one char at a time anyway */
                   1513: chain_isr16h:
                   1514:   popw %dx
                   1515:   popw %ax
                   1516:   jmp do_old_int16h
                   1517: 
                   1518: /*
                   1519:  * update serial_cursor
                   1520:  *
                   1521:  * figure out where the cursor was, and where it's going
                   1522:  * use the minimal amount of serial output to get it there
                   1523:  * input: vga cursor and serial cursor positions stored in BDA
                   1524:  *
                   1525:  * all registers preserved except flags
                   1526:  * bda updated with new position for serial console cursor
                   1527:  */
                   1528: update_serial_cursor:
                   1529:   pushw %ax
                   1530:   pushw %bx
                   1531:   pushw %dx
                   1532:   pushw %ds
                   1533:   pushw $BDA_SEG
                   1534:   popw %ds                             /* ds = 0x40 */
                   1535:   call get_current_cursor              /* dh = row, dl = col */
                   1536:   movw BDA_SERIAL_POS, %bx             /* bh = row, bl = col */
                   1537:   subb %dl, %bl                        /* -col update */
                   1538:   negb %bl                             /* col update */
                   1539:   subb %dh, %bh                        /* -row update */
                   1540:   negb %bh                             /* row update */
                   1541:   /* handle a few special movement cases */
                   1542:   /* cr, lf, bs, bs+bs, space, else send full ansi position */
                   1543:   orb %dl, %dl                         /* column zero? */
                   1544:   jnz update_serial_cursor_lf
                   1545:   movb $0x0d, %al                      /* CR */
                   1546:   call send_byte
                   1547:   xorb %bl, %bl                        /* mark no diff in col */
                   1548: update_serial_cursor_lf:
                   1549:   cmpb $1, %bh                         /* +1 row? */
                   1550:   jnz update_serial_cursor_bs
                   1551:   movb $0x0a, %al                      /* LF */
                   1552:   call send_byte
                   1553:   xorb %bh, %bh                        /* mark no diff in row */
                   1554: update_serial_cursor_bs:
                   1555:   cmpb $-1, %bl                        /* one char back */
                   1556:   jz update_serial_cursor_one_bs
                   1557:   cmpb $-2, %bl                        /* two chars back */
                   1558:   jnz update_serial_cursor_space       /* check for space */
                   1559:   movb $0x08, %al                      /* BS */
                   1560:   call send_byte
                   1561: update_serial_cursor_one_bs:
                   1562:   movb $0x08, %al                      /* BS */
                   1563:   call send_byte
                   1564:   xorb %bl, %bl                        /* mark no diff in col */
                   1565: update_serial_cursor_space:
                   1566:   cmpb $1, %bl                         /* one char forward */
                   1567:   jnz update_serial_cursor_up
                   1568:   movb $0x20, %al                      /* space */
                   1569:   call send_byte
                   1570:   xorb %bl, %bl                        /* mark no diff in col */
                   1571: update_serial_cursor_up:
                   1572:   cmpb $-1, %bh                        /* -1 row? */
                   1573:   jnz update_serial_cursor_full        /* do full ansi pos update */
                   1574:   call send_ansi_csi                   /* send ESC [ A (cursor up) */
                   1575:   movb $0x41, %al                      /* A */
                   1576:   call send_byte
                   1577:   xorb %bh, %bh                        /* mark no diff in row */
                   1578: update_serial_cursor_full:
                   1579:   orw %bx, %bx                         /* diff = 0? */
                   1580:   jz update_serial_cursor_done
                   1581:   call send_ansi_cursor_pos            /* set cursor pos from dh,dl */
                   1582: update_serial_cursor_done:
                   1583:   movw %dx, BDA_SERIAL_POS
                   1584:   popw %ds
                   1585:   popw %dx
                   1586:   popw %bx
                   1587:   popw %ax
                   1588:   ret
                   1589: 
                   1590: /*
                   1591:  * write_teletype
                   1592:  *
                   1593:  * handle int 10h, function 0eh
                   1594:  *
                   1595:  * ah = 0x0e write teletype character
                   1596:  * al = character ascii code
                   1597:  * bh = display page number
                   1598:  *
                   1599:  * all registers except %al preserved
                   1600:  * caller will restore all registers
                   1601:  */
                   1602: 
                   1603: write_teletype:
                   1604:   pushw %bx
                   1605:   movb $0x07, %bl                      /* black bg, white fg */
                   1606:   call send_attribute
                   1607:   popw %bx
                   1608:   call send_char_tty
                   1609:   ret
                   1610: 
                   1611: /*
                   1612:  * write_attr_char
                   1613:  *
                   1614:  * handle int 10h, function 09h
                   1615:  *
                   1616:  * ah = 0x09 write attribute/character at current cursor position
                   1617:  * al = character ascii code
                   1618:  * bh = display page number
                   1619:  * bl = character attribute
                   1620:  * cx = repetition count
                   1621:  *
                   1622:  * does not update cursor position
                   1623:  * all registers except %cx and %al preserved
                   1624:  * caller will restore all registers
                   1625:  */
                   1626: 
                   1627: write_attr_char:
                   1628:   call send_attribute                  /* send attribute in %bl */
                   1629:   jmp write_char_common
                   1630: 
                   1631: /*
                   1632:  * write_char
                   1633:  *
                   1634:  * handle int 10h, function 0ah
                   1635:  *
                   1636:  * ah = 0x0a write character at current cursor position
                   1637:  * al = character ascii code
                   1638:  * bh = display page number
                   1639:  * cx = repetition count
                   1640:  *
                   1641:  * does not update cursor position
                   1642:  * all registers except %cx and %al preserved
                   1643:  * caller will restore all registers
                   1644:  */
                   1645: 
                   1646: write_char:
                   1647:   pushw %bx
                   1648:   movb $0x07, %bl                      /* black bg, white fg */
                   1649:   call send_attribute
                   1650:   popw %bx
                   1651: write_char_common:
                   1652:   call get_current_cursor
                   1653:   call send_char
                   1654:   /* make cx=0 and cx=1 only output one char */
                   1655:   cmpw $1, %cx
                   1656:   jbe write_char_tail
                   1657:   decw %cx
                   1658:   jmp write_char
                   1659: write_char_tail:
                   1660:   /* put cursor back where it was on entry */
                   1661:   call set_current_cursor
                   1662:   ret
                   1663: 
                   1664: /*
                   1665:  * write_string
                   1666:  *
                   1667:  * handle int 10h, function 13h
                   1668:  *
                   1669:  * ah = 0x13 write character at current cursor position
                   1670:  * al = 0, data = char, ..., no cursor update
                   1671:  * al = 1, data = char, ..., cursor at end of string
                   1672:  * al = 2, data = char+attr, ..., no cursor update
                   1673:  * al = 3, data = char+attr, ..., cursor at end of string
                   1674:  * bh = display page number
                   1675:  * bl = character attribute for all chars (if al = 0 or 1)
                   1676:  * cx = characters in string (attributes don't count)
                   1677:  * dh = cursor row start
                   1678:  * dl = cursor column start
                   1679:  * es:bp = pointer to source text string in memory
                   1680:  *
                   1681:  * all registers preserved except flags
                   1682:  * caller will restore all registers
                   1683:  */
                   1684: write_string:
                   1685:   call set_cursor_position
                   1686:   pushw %ds
                   1687:   pushw %es
                   1688:   pushw %es
                   1689:   popw %ds                             /* ds = es */
                   1690:   movw %bp, %si                        /* si = bp */
                   1691:   testb $2, %al
                   1692:   jnz write_attr_string
                   1693:   call send_attribute                  /* send attribute in %bl */
                   1694:   test %cx, %cx
                   1695:   jz write_string_empty
                   1696:   call send_string                     /* plaintext out */
                   1697: write_string_empty:
                   1698:   jmp write_string_update_cursor
                   1699: write_attr_string:
                   1700:   call send_attr_string                /* text+attrib out */
                   1701: write_string_update_cursor:
                   1702:   testb $1, %al                        /* cursor update? */
                   1703:   jnz write_string_tail                /* yes?  already happened */
                   1704:   /* restore entry cursor position if no update */
                   1705:   call set_cursor_position
                   1706: write_string_tail:
                   1707:   popw %es
                   1708:   popw %ds
                   1709:   ret
                   1710: 
                   1711: /*
                   1712:  * set_cursor_position
                   1713:  *
                   1714:  * handle int 10h, function 02h
                   1715:  *
                   1716:  * ah = 0x02 set cursor position
                   1717:  * bh = display page number
                   1718:  * dh = cursor row
                   1719:  * dl = cursor column
                   1720:  *
                   1721:  * update bda cursor position with value in %dx
                   1722:  * serial console cursor only updated on text output
                   1723:  * this routine also called by set_current_cursor
                   1724:  * which won't bother setting ah = 2
                   1725:  *
                   1726:  * all registers preserved except flags
                   1727:  */
                   1728: 
                   1729: set_cursor_position:
                   1730:   pushw %ax
                   1731:   pushw %ds
                   1732:   pushw $BDA_SEG
                   1733:   popw %ds                             /* ds = 0x40 */
                   1734:   movzbw %bh, %ax                      /* ax = page number */
                   1735:   andb $0x07, %al                      /* prevent invalid page number */
                   1736:   shlb $1, %al                         /* calculate word offset */
                   1737:   addb $BDA_CURSOR_BUF, %al            /* ax = cursor save offset */
                   1738:   movw %ax, %bx                        /* bx = cursor save offset */
                   1739:   movw %dx, (%bx)                      /* save new cursor value */
                   1740:   popw %ds
                   1741:   popw %ax
                   1742:   ret
                   1743: 
                   1744: /*
                   1745:  * set_current_cursor
                   1746:  *
                   1747:  * get current display page number and call set_cursor_positon
                   1748:  * to store the row/column value in dx to the bda
                   1749:  *
                   1750:  * all registers preserved except flags
                   1751:  */
                   1752: 
                   1753: set_current_cursor:
                   1754:   pushw %ds
                   1755:   pushw %bx
                   1756:   pushw $BDA_SEG
                   1757:   popw %ds                             /* ds = 0x40 */
                   1758:   movb BDA_ACTIVE_PAGE, %bh
                   1759:   call set_cursor_position
                   1760:   popw %bx
                   1761:   popw %ds
                   1762:   ret
                   1763: 
                   1764: /*
                   1765:  * get_cursor_common
                   1766:  *
                   1767:  * read cursor position for page %bh from bda into %dx
                   1768:  *
                   1769:  * returns:
                   1770:  * dh = cursor row
                   1771:  * dl = cursor column
                   1772:  * ch = cursor start scanline
                   1773:  * cl = cursor end scanline
                   1774:  *
                   1775:  * all registers except %dx, %cx preserved
                   1776:  */
                   1777: get_cursor_common:
                   1778:   pushw %bx
                   1779:   pushw %ds
                   1780:   pushw $BDA_SEG
                   1781:   popw %ds                             /* ds = 0x40 */
                   1782:   movzbw %bh, %bx                      /* dx = current page */
                   1783:   andb $7, %bl
                   1784:   shlb $1, %bl
                   1785:   addb $BDA_CURSOR_BUF, %bl
                   1786:   movw (%bx), %dx                      /* get cursor pos */
                   1787:   movw BDA_CURSOR_SCAN, %cx
                   1788:   popw %ds
                   1789:   popw %bx
                   1790:   ret
                   1791: 
                   1792: /*
                   1793:  * get_current_cursor
                   1794:  *
                   1795:  * read cursor position for current page from bda into %dx
                   1796:  *
                   1797:  * returns:
                   1798:  * dh = cursor row
                   1799:  * dl = cursor column
                   1800:  *
                   1801:  * all registers except %dx preserved
                   1802:  */
                   1803: 
                   1804: get_current_cursor:
                   1805:   pushw %ds
                   1806:   pushw %bx
                   1807:   pushw %cx
                   1808:   pushw $BDA_SEG
                   1809:   popw %ds                             /* ds = 0x40 */
                   1810:   movb BDA_ACTIVE_PAGE, %bh
                   1811:   call get_cursor_common
                   1812:   popw %cx
                   1813:   popw %bx
                   1814:   popw %ds
                   1815:   ret
                   1816: 
                   1817: /*
                   1818:  * get_cursor_position
                   1819:  *
                   1820:  * handle int 10h, function 03h
                   1821:  *
                   1822:  * ah = 0x02 get cursor position
                   1823:  * bh = display page number
                   1824:  *
                   1825:  * returns:
                   1826:  * ax = 0
                   1827:  * ch = cursor start scanline
                   1828:  * ch = cursor end scanline
                   1829:  * dh = cursor row
                   1830:  * dl = cursor column
                   1831:  *
                   1832:  * all registers except %ax, %cx, %dx preserved
                   1833:  */
                   1834: 
                   1835: get_cursor_position:
                   1836:   call bail_if_vga_attached            /* does not return if vga attached */
                   1837:   popw %ax             /* not chaining, pop fake return address */
                   1838:   popw %dx             /* not chaining, pop saved cursor position */
                   1839:   popaw                /* not chaining to old int 10h, pop saved state */
                   1840:   call get_cursor_common
                   1841:   xorw %ax, %ax
                   1842:   iret
                   1843: 
                   1844: /*
                   1845:  * return_current_video_state
                   1846:  *
                   1847:  * handle int 10h, function 0fh
                   1848:  *
                   1849:  * ah = 0x0f return current video state
                   1850:  *
                   1851:  * returns:
                   1852:  * ah = number of columns on screen (from 40:4a)
                   1853:  * al = current video mode setting (from 40:49)
                   1854:  * bh = active display page number (from 40:62)
                   1855:  *
                   1856:  * all registers except %ax and %bh preserved
                   1857:  */
                   1858: 
                   1859: read_current_video_state:
                   1860:   call bail_if_vga_attached            /* does not return if vga attached */
                   1861:   popw %ax             /* not chaining, pop fake return address */
                   1862:   popw %dx             /* not chaining, pop saved cursor position */
                   1863:   popaw                /* not chaining to old int 10h, pop saved state */
                   1864:   pushw %ds
                   1865:   pushw $BDA_SEG
                   1866:   popw %ds                             /* ds = 0x40 */
                   1867:   movb BDA_COLS, %ah
                   1868:   movb BDA_MODE_NUM, %al
                   1869:   movb BDA_ACTIVE_PAGE, %bh
                   1870:   popw %ds
                   1871:   iret
                   1872: 
                   1873: /*
                   1874:  * read_attr_char
                   1875:  *
                   1876:  * handle int 10h, function 08h
                   1877:  *
                   1878:  * ah = 0x08 read character/attribute from screen
                   1879:  *
                   1880:  * returns:
                   1881:  * ah = attribute at current cursor position
                   1882:  * al = character read from current cursor position
                   1883:  *
                   1884:  * all registers preserved except %ax and flags
                   1885:  */
                   1886: 
                   1887: read_attr_char:
                   1888:   call bail_if_vga_attached            /* does not return if vga attached */
                   1889:   popw %ax             /* not chaining, pop fake return address */
                   1890:   popw %dx             /* not chaining, pop saved cursor position */
                   1891:   popaw                /* not chaining to old int 10h, pop saved state */
                   1892:   pushw %ds
                   1893:   pushw $BDA_SEG
                   1894:   popw %ds                             /* ds = 0x40 */
                   1895:   movb BDA_COLOR_VAL, %ah              /* return last color value */
                   1896:   call sgabioslog_get_char
                   1897:   popw %ds
                   1898:   iret
                   1899: 
                   1900: /*
                   1901:  * set_video_mode
                   1902:  *
                   1903:  * handle int 10h, function 00h
                   1904:  *
                   1905:  * ah = 0x00 set video mode
                   1906:  * al = video mode
                   1907:  *
                   1908:  * unless bit 7 of al = 1, setting mode clears screen
                   1909:  *
                   1910:  * all registers preserved except %bh, %dx, flags
                   1911:  */
                   1912: 
                   1913: set_video_mode:
                   1914:   testb $0x80, %al                     /* preserve screen flag? */
                   1915:   jnz set_video_mode_tail
                   1916:   call send_ansi_csi
                   1917:   movb $0x32, %al                      /* 2 */
                   1918:   call send_byte
                   1919:   movb $0x4a, %al                      /* J */
                   1920:   call send_byte
                   1921: set_video_mode_tail:
                   1922:   movb $0x07, %bl                      /* white on black text */
                   1923:   call send_attribute                  /* send attribute in %bl */
                   1924:   /* set cursor position to 0,0 */
                   1925:   xorb %bh, %bh                        /* page 0 */
                   1926:   xorw %dx, %dx
                   1927:   jmp set_cursor_position
                   1928: 
                   1929: /*
                   1930:  * scroll_page_up
                   1931:  *
                   1932:  * handle int 10h, function 06h
                   1933:  *
                   1934:  * ah = 0x06 scroll current page up
                   1935:  * al = scroll distance in character rows (0 blanks entire area)
                   1936:  * bh = attribute to used on blanked lines
                   1937:  * ch = top row (upper left corner) of window
                   1938:  * cl = left-most column (upper left corner) of window
                   1939:  * dh = bottom row (lower right corner) of window
                   1940:  * dl = right-most column (lower right corner) of window
                   1941:  *
                   1942:  * all registers preserved except flags
                   1943:  */
                   1944: 
                   1945: scroll_page_up:
                   1946:   pushw %si
                   1947:   pushw %dx
                   1948:   call get_current_cursor              /* save current cursor */
                   1949:   movw %dx, %si                        /* si = vga cursor pos */
                   1950:   popw %dx
                   1951:   cmpb $0, %al                         /* al = 0 = clear window */
                   1952:   jz scroll_common_clear
                   1953:   pushw %ax
                   1954:   call send_ansi_csi                   /* CSI [ %al S */
                   1955:   call send_number
                   1956:   movb $0x53, %al                      /* S */
                   1957:   call send_byte
                   1958:   popw %dx
                   1959:   popw %si
                   1960:   ret
                   1961: 
                   1962: /*
                   1963:  * scroll_common_clear
                   1964:  *
                   1965:  * common tail for up/down scrolls to clear window specified
                   1966:  * in %cx and %dx.
                   1967:  *
                   1968:  * stack should contain saved copy of si
                   1969:  * si = original vga cursor position on service entry
                   1970:  * 
                   1971:  * bh = attribute to used on blanked lines
                   1972:  * ch = top row (upper left corner) of window
                   1973:  * cl = left-most column (upper left corner) of window
                   1974:  * dh = bottom row (lower right corner) of window
                   1975:  * dl = right-most column (lower right corner) of window
                   1976:  */
                   1977: scroll_common_clear:
                   1978:   pushw %ax
                   1979:   xchgb %bl, %bh                       /* bl = attribute, bh = old bl */
                   1980:   call send_attribute                  /* send attribute in %bl */
                   1981:   xchgb %bl, %bh                       /* restore bx */
                   1982:   pushw %ds
                   1983:   pushw $BDA_SEG
                   1984:   popw %ds                             /* ds = 0x40 */
                   1985:   /* check to see if region is full screen, and attribute default */
                   1986:   orw %cx, %cx                         /* is top left 0,0? */
                   1987:   jnz scroll_common_window             /* no, handle window */
                   1988:   cmpb $0x07, %bh                      /* is attribute white on black? */
                   1989:   jnz scroll_common_window             /* no, must write spaces */
                   1990: #ifdef LILO_CLEAR_WORKAROUND_NOT_REQUIRED
                   1991:   cmpb %cs:term_cols, %dl              /* is right less than cols ? */
                   1992:   jc scroll_common_window              /* if so, handle window */
                   1993:   cmpb %cs:term_rows, %dh              /* is bottom less than rows ? */
                   1994:   jc scroll_common_window              /* if so, handle window */
                   1995: #endif
                   1996:   /* safe to send standard clear screen sequence */
                   1997:   call send_ansi_csi                   /* send ESC [ */
                   1998:   movb $0x32, %al                      /* 2 */
                   1999:   call send_byte
                   2000:   movb $0x4a, %al                      /* J */
                   2001:   call send_byte
                   2002:   jmp scroll_common_tail
                   2003: scroll_common_window:
                   2004:   pushw %dx
                   2005:   movw %cx, %dx                        /* dx = upper right */
                   2006:   call set_current_cursor
                   2007:   popw %dx
                   2008:   pushw %cx
                   2009:   /* setup cx with count of chars to clear per row */
                   2010:   xorb %ch, %ch
                   2011:   negb %cl
                   2012:   addb %dl, %cl                        /* cl = dl - cl */
                   2013:   incb %cl                             /* start = end col = clear 1 col */
                   2014:   cmpb %cs:term_cols, %cl              /* is count < cols? */
                   2015:   jc scroll_common_row_ok              /* if so then skip limit */
                   2016:   movb %cs:term_cols, %cl              /* limit count to cols */
                   2017: scroll_common_row_ok:
                   2018:   jz scroll_common_row_done            /* count == 0 ? */
                   2019:   movb $0x20, %al                      /* space */
                   2020: scroll_common_space_loop:
                   2021:   call send_char
                   2022:   loop scroll_common_space_loop        /* send cx spaces */
                   2023: scroll_common_row_done:
                   2024:   popw %cx
                   2025:   incb %ch                             /* top left now next row */
                   2026:   cmpb %dh, %ch
                   2027:   jbe scroll_common_window             /* do next row */
                   2028: scroll_common_tail:
                   2029:   popw %ds
                   2030:   popw %ax
                   2031:   pushw %dx
                   2032:   movw %si, %dx                        /* dx = saved vga cursor pos */
                   2033:   call set_current_cursor              /* restore saved cursor */
                   2034:   popw %dx
                   2035:   popw %si
                   2036:   ret
                   2037: 
                   2038: /*
                   2039:  * scroll_page_down
                   2040:  *
                   2041:  * handle int 10h, function 07h
                   2042:  *
                   2043:  * ah = 0x07 scroll current page down
                   2044:  * al = scroll distance in character rows (0 blanks entire area)
                   2045:  * bh = attribute to used on blanked lines
                   2046:  * ch = top row (upper left corner) of window
                   2047:  * cl = left-most column (upper left corner) of window
                   2048:  * dh = bottom row (lower right corner) of window
                   2049:  * dl = right-most column (lower right corner) of window
                   2050:  *
                   2051:  * FIXME: this routine doesn't handle windowing, it currently
                   2052:  * only handles one line screen scrolls and erasing entire screen
                   2053:  *
                   2054:  * all registers preserved except flags
                   2055:  */
                   2056: 
                   2057: scroll_page_down:
                   2058:   pushw %si
                   2059:   pushw %dx
                   2060:   call get_current_cursor              /* save current cursor */
                   2061:   movw %dx, %si                        /* si = vga cursor pos */
                   2062:   popw %dx
                   2063:   cmpb $0, %al                         /* al = 0 = clear window */
                   2064:   jz scroll_common_clear
                   2065:   pushw %ax
                   2066:   call send_ansi_csi                   /* CSI [ %al T */
                   2067:   call send_number
                   2068:   movb $0x54, %al                      /* T */
                   2069:   call send_byte
                   2070:   popw %dx
                   2071:   popw %si
                   2072:   ret
                   2073: 
                   2074: /*
                   2075:  * bail_if_vga_attached
                   2076:  *
                   2077:  * Check for vga installed, if not, return to caller.
                   2078:  * If so, pop return address, return to chain_isr_10h
                   2079:  *
                   2080:  * expected that routine calling this one has chain_isr_10h
                   2081:  * as the next item on the stack
                   2082:  *
                   2083:  * all registers except flags and sp preserved
                   2084:  */
                   2085: 
                   2086: bail_if_vga_attached:
                   2087:   cmpw $0xc000, %cs:old_int10h_seg     /* vga attached? */
                   2088:   jnz bail_tail                        /* if not, don't modify stack */
                   2089:   addw $2, %sp                         /* else drop first return address */
                   2090: bail_tail:
                   2091:   ret                                  /* return to caller or chain_isr_10h */
                   2092: 
                   2093: /*
                   2094:  * int10h_isr
                   2095:  *
                   2096:  * entry point for int 10h
                   2097:  *
                   2098:  * save all registers, force return to chain to previous int10h isr
                   2099:  * decide which function in ah needs to be dispatched
                   2100:  *
                   2101:  * ah = 0x00 set mode
                   2102:  * ah = 0x01 set cursor type
                   2103:  * ah = 0x02 set cursor position
                   2104:  * ah = 0x03 read cursor position
                   2105:  * ah = 0x04 read light pen position
                   2106:  * ah = 0x05 set active display page
                   2107:  * ah = 0x06 scroll active page up
                   2108:  * ah = 0x07 scroll active page down
                   2109:  * ah = 0x08 read attribute/character at cursor
                   2110:  * ah = 0x09 write attribute/character at cursor
                   2111:  * ah = 0x0a write character at cursor position
                   2112:  * ah = 0x0b set color palette
                   2113:  * ah = 0x0c write pixel
                   2114:  * ah = 0x0d read pixel
                   2115:  * ah = 0x0e write teletype
                   2116:  * ah = 0x0f read current video state
                   2117:  * ah = 0x10 set individual palette registers
                   2118:  * ah = 0x11 character generation (font control/info)
                   2119:  * ah = 0x12 alternate select (video control/info)
                   2120:  * ah = 0x13 write string
                   2121:  * ah = 0x1a read/write display combination code
                   2122:  * ah = 0x1b return functionality/state information
                   2123:  * ah = 0x1c save/restore video state
                   2124:  * ah = 0x4f vesa bios calls
                   2125:  * all registers preserved except flags (later iret will restore)
                   2126:  */
                   2127: 
                   2128: int10h_isr:
                   2129:   pushaw
                   2130:   call get_current_cursor
                   2131:   pushw %dx                            /* save current cursor */
                   2132:   pushw %bp                            /* need bp for indexing off stack */
                   2133:   movw %sp, %bp                        /* bp = sp */
                   2134:   movw 14(%bp), %dx                    /* restore dx from earlier pushaw */
                   2135:   popw %bp                             /* restore old bp */
                   2136:   pushw $chain_isr10h                  /* force return to chain_isr10h */
                   2137:   testb %ah, %ah
                   2138:   jnz int10h_02
                   2139:   jmp set_video_mode
                   2140: int10h_02:
                   2141:   cmpb $0x02, %ah
                   2142:   jnz int10h_03
                   2143:   jmp set_cursor_position
                   2144: int10h_03:
                   2145:   cmpb $0x03, %ah
                   2146:   jnz int10h_06
                   2147:   jmp get_cursor_position
                   2148: int10h_06:
                   2149:   cmpb $0x06, %ah
                   2150:   jnz int10h_07
                   2151:   jmp scroll_page_up
                   2152: int10h_07:
                   2153:   cmpb $0x07, %ah
                   2154:   jnz int10h_08
                   2155:   jmp scroll_page_down
                   2156: int10h_08:
                   2157:   cmpb $0x08, %ah
                   2158:   jnz int10h_09
                   2159:   jmp read_attr_char
                   2160: int10h_09:
                   2161:   cmpb $0x09, %ah
                   2162:   jnz int10h_0a
                   2163:   jmp write_attr_char
                   2164: int10h_0a:
                   2165:   cmpb $0x0a, %ah
                   2166:   jnz int10h_0e
                   2167:   jmp write_char
                   2168: int10h_0e:
                   2169:   cmpb $0x0e, %ah
                   2170:   jnz int10h_0f
                   2171:   jmp write_teletype
                   2172: int10h_0f:
                   2173:   cmpb $0x0f, %ah
                   2174:   jnz int10h_13
                   2175:   jmp read_current_video_state
                   2176: int10h_13:
                   2177:   cmpb $0x13, %ah
                   2178:   jnz int10h_default
                   2179:   jmp write_string
                   2180: int10h_default:
                   2181:   popw %ax                             /* pop chain_isr10h return address */
                   2182: chain_isr10h:
                   2183:   popw %dx                             /* pop saved cursor */
                   2184:   cmpw $0xc000, %cs:old_int10h_seg     /* vga attached? */
                   2185:   jnz chain_post_cursor                /* if not, don't restore the cursor */
                   2186:   call set_current_cursor              /* restore cursor if vga attached */
                   2187: chain_post_cursor:
                   2188:   popaw
                   2189:   jmp do_old_int10h
                   2190: 
                   2191: /*
                   2192:  * pnp_sga_init
                   2193:  *
                   2194:  * handle PnP initialization of option rom
                   2195:  *
                   2196:  * es:di = pointer to PnP structure
                   2197:  * ax = indication as to which vectors should be hooked
                   2198:  *      by specifying th type of boot device this has
                   2199:  *      been selected as
                   2200:  *      bit 7..3= reserved(0)
                   2201:  *      bit 2   = 1 = connect as IPL (int 13h)
                   2202:  *      bit 1   = 1 = connect as primary video (int 10h)
                   2203:  *      bit 0   = 1 = connect as primary input (int 9h)
                   2204:  * bx = card select number (probably 0xffff)
                   2205:  * dx = read data port address (probably 0xffff)
                   2206:  *
                   2207:  * return:
                   2208:  * ax = initialization status
                   2209:  * bit 8    = 1 = IPL device supports int 13h block dev format
                   2210:  * bit 7    = 1 = Output device supports int 10h char output
                   2211:  * bit 6    = 1 = Input device supports int 9h char input
                   2212:  * bit 5..4 = 00 = no IPL device attached
                   2213:  *            01 = unknown whether or not IPL device attached
                   2214:  *            10 = IPL device attached (RPL devices have connection)
                   2215:  *            11 = reserved
                   2216:  * bit 3..2 = 00 = no display device attached
                   2217:  *            01 = unknown whether or not display device attached
                   2218:  *            10 = display device attached
                   2219:  *            11 = reserved
                   2220:  * bit 1..0 = 00 = no input device attached
                   2221:  *            01 = unknown whether or not input device attached
                   2222:  *            10 = input device attached
                   2223:  *            11 = reserved
                   2224:  *
                   2225:  * all registers preserved except %ax
                   2226:  */
                   2227: 
                   2228: pnp_sga_init:
                   2229:   /* FIXME: this is *wrong* -- init only what bios says to init */
                   2230:   movw $0xca, %ax      /* 0xca = attached int 10h, 9h display, input */
                   2231: 
                   2232: /*
                   2233:  * sga_init
                   2234:  *
                   2235:  * legacy option rom entry point
                   2236:  *
                   2237:  * all registers preserved
                   2238:  */
                   2239: 
                   2240: sga_init:
                   2241:   /* this is probably paranoid about register preservation */
                   2242:   pushfw
                   2243:   cli                                  /* more paranoia */
                   2244:   pushaw
                   2245:   pushw %ds
                   2246:   pushw %es
                   2247:   pushw $0
                   2248:   popw %es                             /* es = 0 */
                   2249:   pushw %cs
                   2250:   popw %ds                             /* ds = cs */
                   2251:   /* get original ISR */
                   2252:   movl %es:0x28, %eax                  /* eax = old irq 3/int 0bh */
                   2253:   movl %eax, old_irq3                  /* save away old irq 4/int 0bh */
                   2254:   movl %es:0x2c, %eax                  /* eax = old irq 4/int 0ch */
                   2255:   movl %eax, old_irq4                  /* save away old irq 4/int 0ch */
                   2256:   movl %es:0x40, %eax                  /* eax = old int 10h */
                   2257:   movl %eax, old_int10h                /* save away old int 10h */
                   2258:   movl %es:0x50, %eax                  /* eax = old int 14h */
                   2259:   movl %eax, old_int14h                /* save away old int 14h */
                   2260:   movl %es:0x58, %eax                  /* eax = old int 16h */
                   2261:   movl %eax, old_int16h                /* save away old int 16h */
                   2262:   movw $irq3_isr, %es:0x28             /* new irq 3 offset */
                   2263:   movw %cs, %es:0x2a                   /* write new irq 3 seg */
                   2264:   movw $irq4_isr, %es:0x2c             /* new irq 4 offset */
                   2265:   movw %cs, %es:0x2e                   /* write new irq 4 seg */
                   2266:   movw $int10h_isr, %es:0x40           /* new int 10h offset */
                   2267:   movw %cs, %es:0x42                   /* write new int10h seg */
                   2268:   movw $int14h_isr, %es:0x50           /* new int 14h offset */
                   2269:   movw %cs, %es:0x52                   /* write new int14h seg */
                   2270:   movw $int16h_isr, %es:0x58           /* new int 16h offset */
                   2271:   movw %cs, %es:0x5a                   /* write new int16h seg */
                   2272:   /* empty input buffer to prepare for terminal sizing */
                   2273:   call init_serial_port
                   2274: input_clear_loop:
                   2275:   call get_byte
                   2276:   jnz input_clear_loop
                   2277:   movw $term_init_string, %si
                   2278:   call send_asciz_out
                   2279:   push $BDA_SEG
                   2280:   push $BDA_SEG
                   2281:   popw %ds                             /* ds = 0x40 */
                   2282:   popw %es                             /* es = 0x40 */
                   2283:   movw $BDA_CURSOR_BUF, %di
                   2284: input_timeout_loop:
                   2285:   /* get input from terminal until timeout found */
                   2286:   /* store input at 40:50 - 40:5e (cursor pos) */
                   2287:   call poll_byte
                   2288:   jz input_timeout
                   2289:   stosb                                /* es:di */
                   2290:   cmpw $0x5f, %di                      /* 14 characters max */
                   2291:   jnz input_timeout_loop               /* good for more data */
                   2292: input_timeout:
                   2293:   xorb %al, %al                        /* nul terminate input */
                   2294:   stosb
                   2295:   cmpw $0x58, %di                      /* less than 8 chars? */
                   2296:   jc resize_end                        /* too small to have valid data */
                   2297:   movw $BDA_CURSOR_BUF, %si            /* point to start */
                   2298:   lodsw                                /* ax = first 2 chars */
                   2299:   cmpw $0x5b1b, %ax                    /* was it "ESC[" ? */
                   2300:   jnz resize_end                       /* reply starts ESC[row;colR */
                   2301:   xorb %bl, %bl                        /* bl = ascii->int conversion */
                   2302: input_first_number:
                   2303:   lodsb                                /* al = next char */
                   2304:   cmpb $0x30, %al
                   2305:   jc resize_end                        /* char < 0x30 invalid */
                   2306:   cmpb $0x3a, %al                      /* is char < 0x3a */
                   2307:   jnc input_semicolon
                   2308:   andb $0x0f, %al                      /* al = 0 - 9 */
                   2309:   movb %bl, %ah                        /* ah = last conversion */
                   2310:   aad                                  /* ax = (al + ah * 10) & 0xff */
                   2311:   movb %al, %bl                        /* bl = row ascii->int conversion */
                   2312:   jmp input_first_number
                   2313: input_semicolon:
                   2314:   /* at this point bl should contain rows, al = ; */
                   2315:   /* sanity check, bail if invalid */
                   2316:   cmpb $0x3b, %al
                   2317:   jnz resize_end                       /* invalid input found */
                   2318:   cmpb $0x0a, %bl                      /* less than 10 rows? */
                   2319:   jc suspect_loopback                  /* consider input invalid */
                   2320:   xorb %bh, %bh                        /* bh = col ascii->int conversion */
                   2321: input_second_number:
                   2322:   lodsb                                /* al = next char */
                   2323:   cmpb $0x30, %al
                   2324:   jc resize_end                        /* char < 0x30 invalid */
                   2325:   cmpb $0x3a, %al                      /* is char < 0x3a */
                   2326:   jnc input_final_r
                   2327:   andb $0x0f, %al                      /* al = 0 - 9 */
                   2328:   movb %bh, %ah                        /* ah = last conversion */
                   2329:   aad                                  /* ax = (al + ah * 10) & 0xff */
                   2330:   movb %al, %bh                        /* bh = ascii->int conversion */
                   2331:   jmp input_second_number
                   2332: input_final_r:
                   2333:   cmpb $0x52, %al                      /* is al = 'R' ? */
                   2334:   jnz suspect_loopback                 /* invalid input found */
                   2335:   movb %bl, %cs:term_rows              /* save away bl rows value */
                   2336:   cmpw $0xc000, %cs:old_int10h_seg     /* vga attached? */
                   2337:   jz resize_end                        /* if so, leave term_cols at 80 */
                   2338:   movb %bh, %cs:term_cols              /* save away bh cols value */
                   2339:   jmp resize_end
                   2340: suspect_loopback:
                   2341:   /*
                   2342:    * characters were received that look like what we sent out
                   2343:    * at this point, assume that a loopback device was plugged in
                   2344:    * and disable any future serial port reads or writes, by pointing
                   2345:    * output to port 0x2e8 (COM4) instead of 0x3f8 -- it's expected
                   2346:    * that this is safe since a real port responds correctly and a
                   2347:    * missing port will respond with 0xff which will terminate the
                   2348:    * loop that waits for the "right" status on the port.
                   2349:    */
                   2350:   movw $0x2e8, %cs:serial_port_base_address
                   2351: resize_end:
                   2352:   /* clear (hopefully) overwritten cursor position buffer */
                   2353:   xorb %al, %al
                   2354:   movw $BDA_CURSOR_BUF, %di
                   2355:   movw $0x10, %cx
                   2356:   cld
                   2357:   rep
                   2358:   stosb                                /* fill 40:50 - 40:5f with 0 */
                   2359:   pushw %cs
                   2360:   popw %ds                             /* ds = cs */
                   2361:   call get_byte                        /* flush any remaining "wrong" input */
                   2362:   jnz resize_end
                   2363:   call send_crlf                       /* place cursor on start of last line */
                   2364:   movw $mfg_string, %si
                   2365:   call send_asciz_out
                   2366:   call send_crlf
                   2367:   movw $prod_string, %si
                   2368:   call send_asciz_out
                   2369:   call send_crlf
                   2370:   movw $long_version, %si
                   2371:   call send_asciz_out
                   2372:   call send_crlf
                   2373:   /* if vga attached, skip terminal message and bda setup... */
                   2374:   cmpw $0xc000, %cs:old_int10h_seg     /* vga attached? */
                   2375:   jz post_bda_init_tail                /* if so, don't modify BDA */
                   2376:   /* show detected terminal size, or default if none detected */
                   2377:   movw $term_info, %si
                   2378:   call send_asciz_out
                   2379:   pushw $BDA_SEG
                   2380:   popw %ds                             /* ds = 0x40 */
                   2381:   movb %cs:term_cols, %al
                   2382:   movb %al, BDA_COLS                   /* 40:4a = number of character cols */
                   2383:   movb $0, BDA_CURSOR_COL              /* 40:51 = cursor0 col */
                   2384:   call send_number
                   2385:   movb $0x78, %al                      /* x */
                   2386:   call send_byte
                   2387:   movb %cs:term_rows, %al
                   2388:   movb %al, %ah
                   2389:   decb %ah                             /* ah = rows-1 */
                   2390:   movb %ah, BDA_ROWS                   /* 40:84 = num character rows - 1 */
                   2391:   movb %ah, BDA_CURSOR_ROW             /* 40:50 = cursor0 row */
                   2392:   call send_number
                   2393:   call send_crlf
                   2394:   movb $3, BDA_MODE_NUM
                   2395:   movb $0x29, BDA_MODE_SEL
                   2396:   movw $VGA_IO_BASE, BDA_6845_ADDR
                   2397:   movw $0x4000, BDA_PAGE_SIZE          /* 16KB per video page */
                   2398:   /* to avoid ansi colors every character, store last attribute */
                   2399:   movb $0x07, BDA_COLOR_VAL            /* 07 = black bg, white fg */
                   2400:   movw %cs, %ax
                   2401:   movw $_start, BDA_ROM_OFF
                   2402:   movw %ax, BDA_ROM_SEG
                   2403: post_bda_init_tail:
                   2404:   /* copy BDA rows/cols to sgabios location... */
                   2405:   /* if vga card is installed, reuse those values... */
                   2406:   /* if no vga card is installed, this shouldn't change anything */
                   2407:   pushw $BDA_SEG
                   2408:   popw %ds                             /* ds = 0x40 */
                   2409:   movb BDA_ROWS, %al
                   2410:   incb %al                             /* bda holds rows-1 */
                   2411:   movb %al, %cs:term_rows              /* sgabios rows */
                   2412:   movb BDA_COLS, %ah
                   2413:   movb %ah, %cs:term_cols              /* sgabios cols */
                   2414:   /* setup in-memory logging of console if desired... */
                   2415:   call setup_memconsole
                   2416:   /* setup logging of last 256 characters output, if ebda has room */
                   2417:   call sgabioslog_setup_ebda
                   2418:   movw $ebda_info, %si
                   2419:   call send_asciz_out
                   2420:   movw %cs:sgabios_ebda_logbuf_offset, %ax
                   2421:   xchgb %ah, %al
                   2422:   call send_number
                   2423:   movb $0x20, %al
                   2424:   call send_byte
                   2425:   movb %ah, %al
                   2426:   call send_number
                   2427:   call send_crlf
                   2428:   popw %es
                   2429:   popw %ds
                   2430:   popaw
                   2431:   popf
                   2432:   lret
                   2433: 
                   2434: _end_sgabios:

unix.superglobalmegacorp.com

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