diff mbox

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

Message ID 1306149553-26793-1-git-send-email-levinsasha928@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Sasha Levin May 23, 2011, 11:19 a.m. UTC
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

Comments

Ingo Molnar May 23, 2011, 11:29 a.m. UTC | #1
* 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
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

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