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

Ingo Molnar
2011-05-23T11:29:29Z

* Sasha Levin <levinsasha928@gmail.com> wrote:

> 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;
> + }

Why are these functions prefixed in such a weird way? Why not int10_putchar(),
int10_vesa(), etc. like all other bits in tools/kvm/?

Thanks,

Ingo