Annotation of qemu/roms/sgabios/sgabios.S, revision 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.