|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.