mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-09-04 20:51:28 +00:00
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 <john@jfloren.net> [ turning code into patches and cleanup ] Signed-off-by: Sasha Levin <levinsasha928@gmail.com> Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
+26
-26
@@ -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
|
||||
|
||||
/*
|
||||
* put char in AL at current cursor and
|
||||
* increment cursor position
|
||||
*/
|
||||
putchar:
|
||||
stack_swap
|
||||
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
|
||||
|
||||
push %fs
|
||||
push %bx
|
||||
popl %eax
|
||||
popl %ebx
|
||||
popl %ecx
|
||||
popl %edx
|
||||
popl %esp
|
||||
popl %ebp
|
||||
popl %esi
|
||||
popl %edi
|
||||
popl %es
|
||||
popw %fs
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
#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 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;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user