| #include "kvm/bios.h" |
| #include "kvm/vesa.h" |
| |
| #include "asm/bios/memcpy.h" |
| |
| #include "asm/bios/vesa.h" |
| |
| static far_ptr gen_far_ptr(unsigned int pa) |
| { |
| far_ptr ptr; |
| |
| ptr.seg = (pa >> 4); |
| ptr.off = pa - (ptr.seg << 4); |
| |
| return ptr; |
| } |
| |
| 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 biosregs *args) |
| { |
| u8 al = args->eax & 0xFF; |
| |
| outb(0x3f8, al); |
| } |
| |
| static void vbe_get_mode(struct biosregs *args) |
| { |
| struct vesa_mode_info *info = (struct vesa_mode_info *) args->edi; |
| |
| *info = (struct vesa_mode_info) { |
| .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, |
| }; |
| } |
| |
| static void vbe_get_info(struct biosregs *args) |
| { |
| struct vesa_general_info *infop = (struct vesa_general_info *) args->edi; |
| struct vesa_general_info info; |
| |
| info = (struct vesa_general_info) { |
| .signature = VESA_MAGIC, |
| .version = 0x102, |
| .vendor_string = gen_far_ptr(VGA_ROM_BEGIN), |
| .capabilities = 0x10, |
| .video_mode_ptr = gen_far_ptr(VGA_ROM_MODES), |
| .total_memory = (4 * VESA_WIDTH * VESA_HEIGHT) / 0x10000, |
| }; |
| |
| memcpy16(args->es, infop, args->ds, &info, sizeof(info)); |
| } |
| |
| #define VBE_STATUS_OK 0x004F |
| |
| static void int10_vesa(struct biosregs *args) |
| { |
| u8 al; |
| |
| al = args->eax & 0xff; |
| |
| switch (al) { |
| case 0x00: |
| vbe_get_info(args); |
| break; |
| case 0x01: |
| vbe_get_mode(args); |
| break; |
| } |
| |
| args->eax = VBE_STATUS_OK; |
| } |
| |
| bioscall void int10_handler(struct biosregs *args) |
| { |
| u8 ah; |
| |
| ah = (args->eax & 0xff00) >> 8; |
| |
| switch (ah) { |
| case 0x0e: |
| int10_putchar(args); |
| break; |
| case 0x4f: |
| int10_vesa(args); |
| break; |
| } |
| |
| } |