diff options
Diffstat (limited to 'mubios/services/int10.c')
| -rw-r--r-- | mubios/services/int10.c | 184 |
1 files changed, 112 insertions, 72 deletions
diff --git a/mubios/services/int10.c b/mubios/services/int10.c index 4f6aef1..17959be 100644 --- a/mubios/services/int10.c +++ b/mubios/services/int10.c @@ -19,136 +19,176 @@ <http://www.gnu.org/licenses/>. */ -#include "bios.h" #include "regs.h" +#include "vbe.h" +#include "vga.h" -#define VGA_TEXT_BASE 0x000B8000u -#define BDA_CURSOR 0x00000450u -#define BDA_CURSOR_SHAPE 0x00000460u -#define VGA_PAGE_SIZE 0x00001000u - -static volatile u16 * +static u16 int10_cursor_for_page (u8 page) { - return (volatile u16 *)(BDA_CURSOR + ((u32)page * 2u)); + return *(volatile u16 *)(MUBIOS_BDA_BASE + BDA_CURSOR_BASE + page * 2u); } static volatile u16 * int10_video_for_page (u8 page) { - return (volatile u16 *)(VGA_TEXT_BASE + ((u32)page * VGA_PAGE_SIZE)); + return (volatile u16 *)(VGA_TEXT_BASE + (u32)page * VGA_PAGE_SIZE); } static void -int10_newline (volatile u16 *cursor) +int10_teletype (u8 character) { - u16 row; + volatile u8 *bda = (volatile u8 *)MUBIOS_BDA_BASE; + u8 page = bda[BDA_VIDEO_PAGE]; + volatile u16 *video = int10_video_for_page (page); + u16 cursor = int10_cursor_for_page (page); + u16 row = cursor >> 8; + u16 column = cursor & 0xFFu; + u16 position; + u16 cell; + u16 blank; + + /* AH=0Eh uses the active page, as in SeaVGABIOS. BEL has no text effect. */ + if (character == 0x07u) + return; + if (character == 0x0Du) + column = 0u; + else if (character == 0x0Au) + ++row; + else if (character == 0x08u) + { + /* A text-mode backspace moves left without erasing or crossing a row. */ + if (column != 0u) + --column; + } + else + { + position = (u16)(row * VGA_COLUMNS + column); + /* Mode 03h has 2000 visible cells per page. */ + if (position >= VGA_TEXT_CELLS) + return; + video[position] = (u16)((video[position] & 0xFF00u) | character); + ++column; + if (column >= VGA_COLUMNS) + { + column = 0u; + ++row; + } + } - row = (u16)(*cursor / 80u); - *cursor = (u16)((row + 1u) * 80u); + /* Passing the last row scrolls the active page, retaining text attributes. + */ + if (row >= VGA_ROWS) + { + blank = (u16)((video[(VGA_ROWS - 1u) * VGA_COLUMNS] & 0xFF00u) | 0x20u); + for (cell = 0; cell < (VGA_ROWS - 1u) * VGA_COLUMNS; ++cell) + video[cell] = video[cell + VGA_COLUMNS]; + for (; cell < VGA_TEXT_CELLS; ++cell) + video[cell] = blank; + row = VGA_ROWS - 1u; + } + vga_set_cursor_position (page, (u16)((row << 8) | column)); } void int10_service (struct bios_regs *regs) { - volatile u16 *cursor; + volatile u8 *bda = (volatile u8 *)MUBIOS_BDA_BASE; volatile u16 *video; - u8 function; - u8 page; - u8 character; - u8 attribute; + u8 function = (u8)(regs->eax >> 8); + u8 page = (u8)(regs->ebx >> 8); + u16 cursor; u16 position; u16 count; + u32 font_address; - function = (u8)(regs->eax >> 8); - page = (u8)(regs->ebx >> 8); + if (function == 0x4Fu) + { + vbe_service (regs); + return; + } if (function == 0x00u) { - if ((u8)regs->eax == 0x03u) - vga_text_mode_init (); + /* Bit 7 preserves video memory; the remaining bits select mode 03h. */ + if (((u8)regs->eax & 0x7Fu) == 0x03u) + vga_text_mode_set ((u8)regs->eax & 0x80u); return; } - if (function == 0x0Fu) + if (function == 0x01u) { - regs->eax = (regs->eax & 0xFFFF0000u) | 0x5003u; - regs->ebx &= 0xFFFF00FFu; + vga_set_cursor_shape ((u16)regs->ecx); return; } - if (function == 0x02u) + if (function == 0x05u) { - cursor = int10_cursor_for_page (page); - position = (u16)(((u8)(regs->edx >> 8) * 80u) + (u8)regs->edx); - *cursor = position; + vga_set_active_page ((u8)regs->eax); return; } - if (function == 0x03u) + if (function == 0x0Fu) { - cursor = int10_cursor_for_page (page); - position = *cursor; - regs->edx = (regs->edx & 0xFFFF0000u) | ((u32)(position / 80u) << 8) - | (u32)(position % 80u); - regs->ecx = (regs->ecx & 0xFFFF0000u) | 0x0607u; + regs->eax = (regs->eax & 0xFFFF0000u) + | ((u32)bda[BDA_VIDEO_COLUMNS] << 8) | bda[BDA_VIDEO_MODE] + | (bda[BDA_VIDEO_CTL] & 0x80u); + regs->ebx = (regs->ebx & 0xFFFF00FFu) | ((u32)bda[BDA_VIDEO_PAGE] << 8); return; } - if (function != 0x09u && function != 0x0Eu) - return; - - cursor = int10_cursor_for_page (page); - video = int10_video_for_page (page); - - character = (u8)regs->eax; - attribute = (u8)regs->ebx; - position = *cursor; - - if (function == 0x09u) + /* AH=11h/AL=30h reports the current font (BH=1) or ROM 8x16 font (BH=6). */ + if (function == 0x11u && (u8)regs->eax == 0x30u) { - count = (u16)regs->ecx; - - while (count != 0u) + if (page == 0x01u || page == 0x06u) { - if (position >= 2000u) - position = 0; - - video[position] = (u16)character | ((u16)attribute << 8); - position++; - count--; + font_address = (u32)vga_font_8x16; + regs->es = (u16)(font_address >> 4); + regs->ebp = (regs->ebp & 0xFFFF0000u) | (font_address & 0x0Fu); } - + regs->ecx = (regs->ecx & 0xFFFF0000u) + | *(volatile u16 *)(bda + BDA_VIDEO_HEIGHT); + regs->edx = (regs->edx & 0xFFFFFF00u) | bda[BDA_VIDEO_ROWS]; return; } - if (character == 0x0Du) + if (function == 0x0Eu) { - *cursor = (u16)((position / 80u) * 80u); + int10_teletype ((u8)regs->eax); return; } - if (character == 0x0Au) + /* The mode 03h INT 10h interface provides page numbers 0 through 7. */ + if (page >= VGA_PAGE_COUNT) + return; + + if (function == 0x02u) { - int10_newline (cursor); + vga_set_cursor_position (page, (u16)regs->edx); return; } - if (character == 0x08u) + if (function == 0x03u) { - if (position != 0u) - { - position--; - video[position] = (u16)(0x20u | ((u16)attribute << 8)); - *cursor = position; - } - + regs->edx = (regs->edx & 0xFFFF0000u) | int10_cursor_for_page (page); + regs->ecx = (regs->ecx & 0xFFFF0000u) + | *(volatile u16 *)(bda + BDA_CURSOR_SHAPE); return; } - if (position >= 2000u) - position = 0; + if (function != 0x09u) + return; - video[position] = (u16)character | ((u16)attribute << 8); - *cursor = (u16)(position + 1u); + cursor = int10_cursor_for_page (page); + position = (u16)((cursor >> 8) * VGA_COLUMNS + (cursor & 0xFFu)); + video = int10_video_for_page (page); + count = (u16)regs->ecx; + /* Repeated character/attribute output stays within the visible page and + does not change either the BDA or hardware cursor. */ + while (count != 0u && position < VGA_TEXT_CELLS) + { + video[position] = (u16)((u8)regs->eax | ((u16)(u8)regs->ebx << 8)); + ++position; + --count; + } } |
