aboutsummaryrefslogtreecommitdiff
path: root/mubios/services/int10.c
diff options
context:
space:
mode:
Diffstat (limited to 'mubios/services/int10.c')
-rw-r--r--mubios/services/int10.c184
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;
+ }
}