Message ID | 1306149553-26793-1-git-send-email-levinsasha928@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
* 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 --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; + } + +} +