[PATCH 1/5 V2] kvm tools: Add BIOS INT10 handler

Sasha Levin
2011-05-23T11:19:33Z

INT10 handler is a basic implementation of BIOS video services.

The handler implements a VESA interface which is initialized at
the very beginning of loading the kernel.

Signed-off-by: John Floren <john@jfloren.net>
[ turning code into patches and cleanup ]
Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
---
tools/kvm/bios/bios-rom.S | 56 ++++++++--------
tools/kvm/bios/int10.c | 161 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 189 insertions(+), 28 deletions(-)
create mode 100644 tools/kvm/bios/int10.c

diff --git a/tools/kvm/bios/bios-rom.S b/tools/kvm/bios/bios-rom.S
index 8a53dcd..b636cb8 100644
--- a/tools/kvm/bios/bios-rom.S
+++ b/tools/kvm/bios/bios-rom.S
@@ -27,36 +27,36 @@ ENTRY_END(bios_intfake)
* We ignore bx settings
*/
ENTRY(bios_int10)
- test $0x0e, %ah
- jne 1f
+ pushw %fs
+ pushl %es
+ pushl %edi
+ pushl %esi
+ pushl %ebp
+ pushl %esp
+ pushl %edx
+ pushl %ecx
+ pushl %ebx
+ pushl %eax
+
+ movl %esp, %eax
+ /* this is way easier than doing it in assembly */
+ /* just push all the regs and jump to a C handler */
+ call int10handler
+
+ popl %eax
+ popl %ebx
+ popl %ecx
+ popl %edx
+ popl %esp
+ popl %ebp
+ popl %esi
+ popl %edi
+ popl %es
+ popw %fs

-/*
- * put char in AL at current cursor and
- * increment cursor position
- */
-putchar:
- stack_swap
-
- push %fs
- push %bx
-
- mov $VGA_RAM_SEG, %bx
- mov %bx, %fs
- mov %cs:(cursor), %bx
- mov %al, %fs:(%bx)
- inc %bx
- test $VGA_PAGE_SIZE, %bx
- jb putchar_new
- xor %bx, %bx
-putchar_new:
- mov %bx, %fs:(cursor)
-
- pop %bx
- pop %fs
-
- stack_restore
-1:
IRET
+
+
/*
* private IRQ data
*/
diff --git a/tools/kvm/bios/int10.c b/tools/kvm/bios/int10.c
new file mode 100644
index 0000000..98205c3
--- /dev/null
+++ b/tools/kvm/bios/int10.c
@@ -0,0 +1,161 @@
+#include "kvm/segment.h"
+#include "kvm/bios.h"
+#include "kvm/util.h"
+#include "kvm/vesa.h"
+#include <stdint.h>
+
+#define VESA_MAGIC ('V' + ('E' << 8) + ('S' << 16) + ('A' << 24))
+
+struct int10args {
+ u32 eax;
+ u32 ebx;
+ u32 ecx;
+ u32 edx;
+ u32 esp;
+ u32 ebp;
+ u32 esi;
+ u32 edi;
+ u32 es;
+};
+
+/* VESA General Information table */
+struct vesa_general_info {
+ u32 signature; /* 0 Magic number = "VESA" */
+ u16 version; /* 4 */
+ void *vendor_string; /* 6 */
+ u32 capabilities; /* 10 */
+ void *video_mode_ptr; /* 14 */
+ u16 total_memory; /* 18 */
+
+ u8 reserved[236]; /* 20 */
+} __attribute__ ((packed));
+
+
+struct vminfo {
+ u16 mode_attr; /* 0 */
+ u8 win_attr[2]; /* 2 */
+ u16 win_grain; /* 4 */
+ u16 win_size; /* 6 */
+ u16 win_seg[2]; /* 8 */
+ u32 win_scheme; /* 12 */
+ u16 logical_scan; /* 16 */
+
+ u16 h_res; /* 18 */
+ u16 v_res; /* 20 */
+ u8 char_width; /* 22 */
+ u8 char_height; /* 23 */
+ u8 memory_planes; /* 24 */
+ u8 bpp; /* 25 */
+ u8 banks; /* 26 */
+ u8 memory_layout; /* 27 */
+ u8 bank_size; /* 28 */
+ u8 image_planes; /* 29 */
+ u8 page_function; /* 30 */
+
+ u8 rmask; /* 31 */
+ u8 rpos; /* 32 */
+ u8 gmask; /* 33 */
+ u8 gpos; /* 34 */
+ u8 bmask; /* 35 */
+ u8 bpos; /* 36 */
+ u8 resv_mask; /* 37 */
+ u8 resv_pos; /* 38 */
+ u8 dcm_info; /* 39 */
+
+ u32 lfb_ptr; /* 40 Linear frame buffer address */
+ u32 offscreen_ptr; /* 44 Offscreen memory address */
+ u16 offscreen_size; /* 48 */
+
+ u8 reserved[206]; /* 50 */
+};
+
+char oemstring[11] = "KVM VESA";
+u16 modes[2] = { 0x0112, 0xffff };
+
+static inline void outb(unsigned short port, unsigned char val)
+{
+ asm volatile("outb %0, %1" : : "a"(val), "Nd"(port));
+}
+
+/*
+ * It's probably much more useful to make this print to the serial
+ * line rather than print to a non-displayed VGA memory
+ */
+static inline void int10putchar(struct int10args *args)
+{
+ u8 al, ah;
+
+ al = args->eax & 0xFF;
+ ah = (args->eax & 0xFF00) >> 8;
+
+ outb(0x3f8, al);
+}
+
+static void int10vesa(struct int10args *args)
+{
+ u8 al, ah;
+ struct vesa_general_info *destination;
+ struct vminfo *vi;
+
+ al = args->eax;
+ ah = args->eax >> 8;
+
+ switch (al) {
+ case 0:
+ /* Set controller info */
+
+ destination = (struct vesa_general_info *)args->edi;
+ *destination = (struct vesa_general_info) {
+ .signature = VESA_MAGIC,
+ .version = 0x102,
+ .vendor_string = oemstring,
+ .capabilities = 0x10,
+ .video_mode_ptr = modes,
+ .total_memory = (4*VESA_WIDTH * VESA_HEIGHT) / 0x10000,
+ };
+
+ break;
+ case 1:
+ vi = (struct vminfo *)args->edi;
+ *vi = (struct vminfo) {
+ .mode_attr = 0xd9, /* 11011011 */
+ .logical_scan = VESA_WIDTH*4,
+ .h_res = VESA_WIDTH,
+ .v_res = VESA_HEIGHT,
+ .bpp = VESA_BPP,
+ .memory_layout = 6,
+ .memory_planes = 1,
+ .lfb_ptr = VESA_MEM_ADDR,
+ .rmask = 8,
+ .gmask = 8,
+ .bmask = 8,
+ .resv_mask = 8,
+ .resv_pos = 24,
+ .bpos = 16,
+ .gpos = 8,
+ };
+
+ break;
+ }
+
+ args->eax = 0x004f; /* return success every time */
+
+}
+
+bioscall void int10handler(struct int10args *args)
+{
+ u8 ah;
+
+ ah = (args->eax & 0xff00) >> 8;
+
+ switch (ah) {
+ case 0x0e:
+ int10putchar(args);
+ break;
+ case 0x4f:
+ int10vesa(args);
+ break;
+ }
+
+}
+
--
1.7.5.rc3