From bd4309372cd8a3b6731875437c59494309cb9228 Mon Sep 17 00:00:00 2001 From: John Floren Date: Mon, 23 May 2011 15:15:14 +0300 Subject: [PATCH] kvm tools: Add BIOS INT10 handler 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 [ turning code into patches and cleanup ] Signed-off-by: Sasha Levin Signed-off-by: Pekka Enberg --- tools/kvm/bios/bios-rom.S | 56 ++++++------- tools/kvm/bios/int10.c | 160 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 188 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 8a53dcd2ea01..5645cd27ae33 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 int10_handler + + 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 000000000000..02c1e03518bf --- /dev/null +++ b/tools/kvm/bios/int10.c @@ -0,0 +1,160 @@ +#include "kvm/segment.h" +#include "kvm/bios.h" +#include "kvm/util.h" +#include "kvm/vesa.h" +#include + +#define VESA_MAGIC ('V' + ('E' << 8) + ('S' << 16) + ('A' << 24)) + +struct int10_args { + 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 int10_putchar(struct int10_args *args) +{ + u8 al, ah; + + al = args->eax & 0xFF; + ah = (args->eax & 0xFF00) >> 8; + + outb(0x3f8, al); +} + +static void int10_vesa(struct int10_args *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 int10_handler(struct int10_args *args) +{ + u8 ah; + + ah = (args->eax & 0xff00) >> 8; + + switch (ah) { + case 0x0e: + int10_putchar(args); + break; + case 0x4f: + int10_vesa(args); + break; + } + +} -- 2.39.5