aboutsummaryrefslogtreecommitdiffstats
path: root/vgasrc
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2014-10-17 22:15:42 -0400
committerKevin O'Connor <kevin@koconnor.net>2014-11-12 12:17:57 -0500
commitb4eb6fc5cc051e18d07f9483c093c9c32cece2f7 (patch)
tree0eb793ef2481b9b2dcaa8e501078708858146ec1 /vgasrc
parent6fed307251e2590e9a999af64cf29ff739b034f9 (diff)
downloadseabios-b4eb6fc5cc051e18d07f9483c093c9c32cece2f7.tar.gz
seabios-b4eb6fc5cc051e18d07f9483c093c9c32cece2f7.tar.xz
seabios-b4eb6fc5cc051e18d07f9483c093c9c32cece2f7.zip
vgabios: Add software cursor capability
Add mechanism for drawing a cursor to the framebuffer to implement a cursor in software. The timer interrupt is "hooked" so that the cursor can blink. This can be useful for "coreboot native vga". Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'vgasrc')
-rw-r--r--vgasrc/cbvga.c4
-rw-r--r--vgasrc/vgabios.c13
-rw-r--r--vgasrc/vgabios.h4
-rw-r--r--vgasrc/vgaentry.S30
-rw-r--r--vgasrc/vgafb.c63
-rw-r--r--vgasrc/vgainit.c34
6 files changed, 143 insertions, 5 deletions
diff --git a/vgasrc/cbvga.c b/vgasrc/cbvga.c
index 3acc839..1cfb9d3 100644
--- a/vgasrc/cbvga.c
+++ b/vgasrc/cbvga.c
@@ -95,8 +95,8 @@ cbvga_save_restore(int cmd, u16 seg, void *data)
int
cbvga_set_mode(struct vgamode_s *vmode_g, int flags)
{
- MASK_BDA_EXT(flags, BF_EMULATE_TEXT
- , (vmode_g == &CBemulinfo) ? BF_EMULATE_TEXT : 0);
+ u8 emul = vmode_g == &CBemulinfo || GET_GLOBAL(CBmode) == 0x03;
+ MASK_BDA_EXT(flags, BF_EMULATE_TEXT, emul ? BF_EMULATE_TEXT : 0);
if (!(flags & MF_NOCLEARMEM)) {
if (GET_GLOBAL(CBmodeinfo.memmodel) == MM_TEXT) {
memset16_far(SEG_CTEXT, (void*)0, 0x0720, 80*25*2);
diff --git a/vgasrc/vgabios.c b/vgasrc/vgabios.c
index 858f415..f5abda6 100644
--- a/vgasrc/vgabios.c
+++ b/vgasrc/vgabios.c
@@ -51,7 +51,7 @@ calc_page_size(u8 memmodel, u16 width, u16 height)
}
// Determine cursor shape (taking into account possible cursor scaling)
-static u16
+u16
get_cursor_shape(void)
{
u16 cursor_type = GET_BDA(cursor_type);
@@ -74,6 +74,7 @@ get_cursor_shape(void)
static void
set_cursor_shape(u16 cursor_type)
{
+ vgafb_set_swcursor(0);
SET_BDA(cursor_type, cursor_type);
if (CONFIG_VGA_STDVGA_PORTS)
stdvga_set_cursor_shape(get_cursor_shape());
@@ -88,6 +89,8 @@ set_cursor_pos(struct cursorpos cp)
if (page > 7)
return;
+ vgafb_set_swcursor(0);
+
// Bios cursor pos
SET_BDA(cursor_pos[page], (y << 8) | x);
@@ -103,7 +106,7 @@ set_cursor_pos(struct cursorpos cp)
stdvga_set_cursor_pos((int)text_address(cp));
}
-static struct cursorpos
+struct cursorpos
get_cursor_pos(u8 page)
{
if (page == 0xff)
@@ -129,6 +132,8 @@ set_active_page(u8 page)
if (!vmode_g)
return;
+ vgafb_set_swcursor(0);
+
// Calculate memory address of start of page
struct cursorpos cp = {0, 0, page};
int address = (int)text_address(cp);
@@ -282,6 +287,8 @@ vga_set_mode(int mode, int flags)
if (!vmode_g)
return VBE_RETURN_STATUS_FAILED;
+ vgafb_set_swcursor(0);
+
int ret = vgahw_set_mode(vmode_g, flags);
if (ret)
return ret;
@@ -305,7 +312,7 @@ vga_set_mode(int mode, int flags)
int cwidth = GET_GLOBAL(vmode_g->cwidth);
SET_BDA(video_cols, width / cwidth);
SET_BDA(video_rows, (height / cheight) - 1);
- SET_BDA(cursor_type, 0x0000);
+ SET_BDA(cursor_type, vga_emulate_text() ? 0x0607 : 0x0000);
}
SET_BDA(video_pagesize, calc_page_size(memmodel, width, height));
SET_BDA(crtc_address, CONFIG_VGA_STDVGA_PORTS ? stdvga_get_crtc() : 0);
diff --git a/vgasrc/vgabios.h b/vgasrc/vgabios.h
index 344b3d9..fd796f2 100644
--- a/vgasrc/vgabios.h
+++ b/vgasrc/vgabios.h
@@ -73,6 +73,7 @@ struct vga_bda_s {
#define BF_PM_MASK 0x0f
#define BF_EMULATE_TEXT 0x10
+#define BF_SWCURSOR 0x20
#define GET_BDA_EXT(var) \
GET_FARVAR(SEG_BDA, ((struct vga_bda_s *)VGA_CUSTOM_BDA)->var)
@@ -112,6 +113,8 @@ struct cursorpos {
};
int vga_bpp(struct vgamode_s *vmode_g);
u16 calc_page_size(u8 memmodel, u16 width, u16 height);
+u16 get_cursor_shape(void);
+struct cursorpos get_cursor_pos(u8 page);
int bda_save_restore(int cmd, u16 seg, void *data);
struct vgamode_s *get_current_mode(void);
int vga_set_mode(int mode, int flags);
@@ -129,6 +132,7 @@ void vgafb_write_char(struct cursorpos cp, struct carattr ca);
struct carattr vgafb_read_char(struct cursorpos cp);
void vgafb_write_pixel(u8 color, u16 x, u16 y);
u8 vgafb_read_pixel(u16 x, u16 y);
+void vgafb_set_swcursor(int enable);
// vbe.c
extern u32 VBE_total_memory;
diff --git a/vgasrc/vgaentry.S b/vgasrc/vgaentry.S
index 5d45380..c05502d 100644
--- a/vgasrc/vgaentry.S
+++ b/vgasrc/vgaentry.S
@@ -133,3 +133,33 @@ entry_10_extrastack:
pushl BREGS_code(%eax)
RESTOREBREGS_DSEAX
iretw
+
+ // Timer irq handling
+ DECLFUNC entry_timer_hook
+entry_timer_hook:
+ ENTRY handle_timer_hook
+ ljmpw *%cs:Timer_Hook_Resume
+
+ // Timer irq handling on extra stack
+ DECLFUNC entry_timer_hook_extrastack
+entry_timer_hook_extrastack:
+ cli
+ cld
+ pushw %ds // Set %ds:%eax to space on ExtraStack
+ pushl %eax
+ movw %cs:ExtraStackSeg, %ds
+ movl $(CONFIG_VGA_EXTRA_STACK_SIZE-BREGS_size-8), %eax
+ SAVEBREGS_POP_DSEAX
+ movl %esp, BREGS_size(%eax)
+ movw %ss, BREGS_size+4(%eax)
+
+ movw %ds, %dx // Setup %ss/%esp and call function
+ movw %dx, %ss
+ movl %eax, %esp
+ calll handle_timer_hook
+
+ movl %esp, %eax // Restore registers and return
+ movw BREGS_size+4(%eax), %ss
+ movl BREGS_size(%eax), %esp
+ RESTOREBREGS_DSEAX
+ ljmpw *%cs:Timer_Hook_Resume
diff --git a/vgasrc/vgafb.c b/vgasrc/vgafb.c
index e6a4a4c..59ddc56 100644
--- a/vgasrc/vgafb.c
+++ b/vgasrc/vgafb.c
@@ -454,6 +454,30 @@ gfx_write_char(struct vgamode_s *vmode_g
}
}
+// Draw/undraw a cursor on the framebuffer by xor'ing the cursor cell
+void
+gfx_set_swcursor(struct vgamode_s *vmode_g, int enable, struct cursorpos cp)
+{
+ u16 cursor_type = get_cursor_shape();
+ u8 start = cursor_type >> 8, end = cursor_type & 0xff;
+ struct gfx_op op;
+ init_gfx_op(&op, vmode_g);
+ op.x = cp.x * 8;
+ int cheight = GET_BDA(char_height);
+ op.y = cp.y * cheight + start;
+
+ int i;
+ for (i = start; i < cheight && i <= end; i++, op.y++) {
+ op.op = GO_READ8;
+ handle_gfx_op(&op);
+ int j;
+ for (j = 0; j < 8; j++)
+ op.pixels[j] ^= 0x07;
+ op.op = GO_WRITE8;
+ handle_gfx_op(&op);
+ }
+}
+
// Set the pixel at the given position.
void
vgafb_write_pixel(u8 color, u16 x, u16 y)
@@ -461,6 +485,7 @@ vgafb_write_pixel(u8 color, u16 x, u16 y)
struct vgamode_s *vmode_g = get_current_mode();
if (!vmode_g)
return;
+ vgafb_set_swcursor(0);
struct gfx_op op;
init_gfx_op(&op, vmode_g);
@@ -485,6 +510,7 @@ vgafb_read_pixel(u16 x, u16 y)
struct vgamode_s *vmode_g = get_current_mode();
if (!vmode_g)
return 0;
+ vgafb_set_swcursor(0);
struct gfx_op op;
init_gfx_op(&op, vmode_g);
@@ -518,6 +544,7 @@ vgafb_move_chars(struct cursorpos dest
struct vgamode_s *vmode_g = get_current_mode();
if (!vmode_g)
return;
+ vgafb_set_swcursor(0);
if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
gfx_move_chars(vmode_g, dest, src, movesize);
@@ -538,6 +565,7 @@ vgafb_clear_chars(struct cursorpos dest
struct vgamode_s *vmode_g = get_current_mode();
if (!vmode_g)
return;
+ vgafb_set_swcursor(0);
if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
gfx_clear_chars(vmode_g, dest, ca, clearsize);
@@ -557,6 +585,7 @@ vgafb_write_char(struct cursorpos cp, struct carattr ca)
struct vgamode_s *vmode_g = get_current_mode();
if (!vmode_g)
return;
+ vgafb_set_swcursor(0);
if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
gfx_write_char(vmode_g, cp, ca);
@@ -579,6 +608,7 @@ vgafb_read_char(struct cursorpos cp)
struct vgamode_s *vmode_g = get_current_mode();
if (!vmode_g)
goto fail;
+ vgafb_set_swcursor(0);
if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
// FIXME gfx mode
@@ -595,3 +625,36 @@ fail: ;
struct carattr ca2 = {0, 0, 0};
return ca2;
}
+
+// Draw/undraw a cursor on the screen
+void
+vgafb_set_swcursor(int enable)
+{
+ if (!vga_emulate_text())
+ return;
+ u8 flags = GET_BDA_EXT(flags);
+ if (!!(flags & BF_SWCURSOR) == enable)
+ // Already in requested mode.
+ return;
+ struct vgamode_s *vmode_g = get_current_mode();
+ if (!vmode_g)
+ return;
+ struct cursorpos cp = get_cursor_pos(0xff);
+ if (cp.x >= GET_BDA(video_cols) || cp.y > GET_BDA(video_rows)
+ || GET_BDA(cursor_type) >= 0x2000)
+ // Cursor not visible
+ return;
+
+ SET_BDA_EXT(flags, (flags & ~BF_SWCURSOR) | (enable ? BF_SWCURSOR : 0));
+
+ if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
+ gfx_set_swcursor(vmode_g, enable, cp);
+ return;
+ }
+
+ // In text mode, swap foreground and background attributes for cursor
+ void *dest_far = text_address(cp) + 1;
+ u8 attr = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)dest_far);
+ attr = (attr >> 4) | (attr << 4);
+ SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)dest_far, attr);
+}
diff --git a/vgasrc/vgainit.c b/vgasrc/vgainit.c
index 6ef19e1..8d12261 100644
--- a/vgasrc/vgainit.c
+++ b/vgasrc/vgainit.c
@@ -88,6 +88,38 @@ allocate_extra_stack(void)
/****************************************************************
+ * Timer hook
+ ****************************************************************/
+
+struct segoff_s Timer_Hook_Resume VAR16 VISIBLE16;
+
+void VISIBLE16
+handle_timer_hook(void)
+{
+ if (!vga_emulate_text())
+ return;
+ vgafb_set_swcursor(GET_BDA(timer_counter) % 18 < 9);
+}
+
+static void
+hook_timer_irq(void)
+{
+ if (!CONFIG_VGA_EMULATE_TEXT)
+ return;
+ extern void entry_timer_hook(void);
+ extern void entry_timer_hook_extrastack(void);
+ struct segoff_s oldirq = GET_IVT(0x08);
+ struct segoff_s newirq = SEGOFF(get_global_seg(), (u32)entry_timer_hook);
+ if (CONFIG_VGA_ALLOCATE_EXTRA_STACK && GET_GLOBAL(ExtraStackSeg))
+ newirq = SEGOFF(get_global_seg(), (u32)entry_timer_hook_extrastack);
+ dprintf(1, "Hooking hardware timer irq (old=%x new=%x)\n"
+ , oldirq.segoff, newirq.segoff);
+ SET_VGA(Timer_Hook_Resume, oldirq);
+ SET_IVT(0x08, newirq);
+}
+
+
+/****************************************************************
* VGA post
****************************************************************/
@@ -150,6 +182,8 @@ vga_post(struct bregs *regs)
allocate_extra_stack();
+ hook_timer_irq();
+
SET_VGA(HaveRunInit, 1);
// Fixup checksum