diff options
Diffstat (limited to 'ddcprobe')
-rw-r--r-- | ddcprobe/lrmi.c | 911 | ||||
-rw-r--r-- | ddcprobe/lrmi.h | 85 | ||||
-rw-r--r-- | ddcprobe/vbe.h | 311 | ||||
-rw-r--r-- | ddcprobe/vesamode.h | 31 |
4 files changed, 1338 insertions, 0 deletions
diff --git a/ddcprobe/lrmi.c b/ddcprobe/lrmi.c new file mode 100644 index 000000000..ca8af0a1e --- /dev/null +++ b/ddcprobe/lrmi.c @@ -0,0 +1,911 @@ +/* +Linux Real Mode Interface - A library of DPMI-like functions for Linux. + +Copyright (C) 1998 by Josh Vanderhoof + +You are free to distribute and modify this file, as long as you +do not remove this copyright notice and clearly label modified +versions as being modified. + +This software has NO WARRANTY. Use it at your own risk. +*/ + +#include <stdio.h> +#include <string.h> +#include <sys/io.h> +#include <asm/vm86.h> + +#ifdef USE_LIBC_VM86 +#include <sys/vm86.h> +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <unistd.h> +#include <fcntl.h> + +#include "lrmi.h" + +#define REAL_MEM_BASE ((void *)0x10000) +#define REAL_MEM_SIZE 0x10000 +#define REAL_MEM_BLOCKS 0x100 + +struct mem_block + { + unsigned int size : 20; + unsigned int free : 1; + }; + +static struct + { + int ready; + int count; + struct mem_block blocks[REAL_MEM_BLOCKS]; + } mem_info = { 0 }; + +static int +real_mem_init(void) + { + void *m; + int fd_zero; + + if (mem_info.ready) + return 1; + + fd_zero = open("/dev/zero", O_RDONLY); + if (fd_zero == -1) + { + perror("open /dev/zero"); + return 0; + } + + m = mmap((void *)REAL_MEM_BASE, REAL_MEM_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, fd_zero, 0); + + if (m == (void *)-1) + { + perror("mmap /dev/zero"); + close(fd_zero); + return 0; + } + + mem_info.ready = 1; + mem_info.count = 1; + mem_info.blocks[0].size = REAL_MEM_SIZE; + mem_info.blocks[0].free = 1; + + return 1; + } + + +static void +insert_block(int i) + { + memmove( + mem_info.blocks + i + 1, + mem_info.blocks + i, + (mem_info.count - i) * sizeof(struct mem_block)); + + mem_info.count++; + } + +static void +delete_block(int i) + { + mem_info.count--; + + memmove( + mem_info.blocks + i, + mem_info.blocks + i + 1, + (mem_info.count - i) * sizeof(struct mem_block)); + } + +void * +LRMI_alloc_real(int size) + { + int i; + char *r = (char *)REAL_MEM_BASE; + + if (!mem_info.ready) + return NULL; + + if (mem_info.count == REAL_MEM_BLOCKS) + return NULL; + + size = (size + 15) & ~15; + + for (i = 0; i < mem_info.count; i++) + { + if (mem_info.blocks[i].free && size < mem_info.blocks[i].size) + { + insert_block(i); + + mem_info.blocks[i].size = size; + mem_info.blocks[i].free = 0; + mem_info.blocks[i + 1].size -= size; + + return (void *)r; + } + + r += mem_info.blocks[i].size; + } + + return NULL; + } + + +void +LRMI_free_real(void *m) + { + int i; + char *r = (char *)REAL_MEM_BASE; + + if (!mem_info.ready) + return; + + i = 0; + while (m != (void *)r) + { + r += mem_info.blocks[i].size; + i++; + if (i == mem_info.count) + return; + } + + mem_info.blocks[i].free = 1; + + if (i + 1 < mem_info.count && mem_info.blocks[i + 1].free) + { + mem_info.blocks[i].size += mem_info.blocks[i + 1].size; + delete_block(i + 1); + } + + if (i - 1 >= 0 && mem_info.blocks[i - 1].free) + { + mem_info.blocks[i - 1].size += mem_info.blocks[i].size; + delete_block(i); + } + } + + +#define DEFAULT_VM86_FLAGS (IF_MASK | IOPL_MASK) +#define DEFAULT_STACK_SIZE 0x1000 +#define RETURN_TO_32_INT 255 + +static struct + { + int ready; + unsigned short ret_seg, ret_off; + unsigned short stack_seg, stack_off; + struct vm86_struct vm; + } context = { 0 }; + + +static inline void +set_bit(unsigned int bit, void *array) + { + unsigned char *a = array; + + a[bit / 8] |= (1 << (bit % 8)); + } + + +static inline unsigned int +get_int_seg(int i) + { + return *(unsigned short *)(i * 4 + 2); + } + + +static inline unsigned int +get_int_off(int i) + { + return *(unsigned short *)(i * 4); + } + + +static inline void +pushw(unsigned short i) + { + struct vm86_regs *r = &context.vm.regs; + r->esp -= 2; + *(unsigned short *)(((unsigned int)r->ss << 4) + r->esp) = i; + } + + +int +LRMI_init(void) + { + void *m; + int fd_mem; + + if (context.ready) + return 1; + + if (!real_mem_init()) + return 0; + + /* + Map the Interrupt Vectors (0x0 - 0x400) + BIOS data (0x400 - 0x502) + and the ROM (0xa0000 - 0x100000) + */ + fd_mem = open("/dev/mem", O_RDWR); + + if (fd_mem == -1) + { + perror("open /dev/mem"); + return 0; + } + + m = mmap((void *)0, 0x502, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, fd_mem, 0); + + if (m == (void *)-1) + { + perror("mmap /dev/mem"); + return 0; + } + + m = mmap((void *)0xa0000, 0x100000 - 0xa0000, + PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_SHARED, fd_mem, 0xa0000); + + if (m == (void *)-1) + { + perror("mmap /dev/mem"); + return 0; + } + + + /* + Allocate a stack + */ + m = LRMI_alloc_real(DEFAULT_STACK_SIZE); + + context.stack_seg = (unsigned int)m >> 4; + context.stack_off = DEFAULT_STACK_SIZE; + + /* + Allocate the return to 32 bit routine + */ + m = LRMI_alloc_real(2); + + context.ret_seg = (unsigned int)m >> 4; + context.ret_off = (unsigned int)m & 0xf; + + ((unsigned char *)m)[0] = 0xcd; /* int opcode */ + ((unsigned char *)m)[1] = RETURN_TO_32_INT; + + memset(&context.vm, 0, sizeof(context.vm)); + + /* + Enable kernel emulation of all ints except RETURN_TO_32_INT + */ + memset(&context.vm.int_revectored, 0, sizeof(context.vm.int_revectored)); + set_bit(RETURN_TO_32_INT, &context.vm.int_revectored); + + context.ready = 1; + + return 1; + } + + +static void +set_regs(struct LRMI_regs *r) + { + context.vm.regs.edi = r->edi; + context.vm.regs.esi = r->esi; + context.vm.regs.ebp = r->ebp; + context.vm.regs.ebx = r->ebx; + context.vm.regs.edx = r->edx; + context.vm.regs.ecx = r->ecx; + context.vm.regs.eax = r->eax; + context.vm.regs.eflags = DEFAULT_VM86_FLAGS; + context.vm.regs.es = r->es; + context.vm.regs.ds = r->ds; + context.vm.regs.fs = r->fs; + context.vm.regs.gs = r->gs; + } + + +static void +get_regs(struct LRMI_regs *r) + { + r->edi = context.vm.regs.edi; + r->esi = context.vm.regs.esi; + r->ebp = context.vm.regs.ebp; + r->ebx = context.vm.regs.ebx; + r->edx = context.vm.regs.edx; + r->ecx = context.vm.regs.ecx; + r->eax = context.vm.regs.eax; + r->flags = context.vm.regs.eflags; + r->es = context.vm.regs.es; + r->ds = context.vm.regs.ds; + r->fs = context.vm.regs.fs; + r->gs = context.vm.regs.gs; + } + +#define DIRECTION_FLAG (1 << 10) + +static void +em_ins(int size) + { + unsigned int edx, edi; + + edx = context.vm.regs.edx & 0xffff; + edi = context.vm.regs.edi & 0xffff; + edi += (unsigned int)context.vm.regs.ds << 4; + + if (context.vm.regs.eflags & DIRECTION_FLAG) + { + if (size == 4) + asm volatile ("std; insl; cld" + : "=D" (edi) : "d" (edx), "0" (edi)); + else if (size == 2) + asm volatile ("std; insw; cld" + : "=D" (edi) : "d" (edx), "0" (edi)); + else + asm volatile ("std; insb; cld" + : "=D" (edi) : "d" (edx), "0" (edi)); + } + else + { + if (size == 4) + asm volatile ("cld; insl" + : "=D" (edi) : "d" (edx), "0" (edi)); + else if (size == 2) + asm volatile ("cld; insw" + : "=D" (edi) : "d" (edx), "0" (edi)); + else + asm volatile ("cld; insb" + : "=D" (edi) : "d" (edx), "0" (edi)); + } + + edi -= (unsigned int)context.vm.regs.ds << 4; + + context.vm.regs.edi &= 0xffff0000; + context.vm.regs.edi |= edi & 0xffff; + } + +static void +em_rep_ins(int size) + { + unsigned int ecx, edx, edi; + + ecx = context.vm.regs.ecx & 0xffff; + edx = context.vm.regs.edx & 0xffff; + edi = context.vm.regs.edi & 0xffff; + edi += (unsigned int)context.vm.regs.ds << 4; + + if (context.vm.regs.eflags & DIRECTION_FLAG) + { + if (size == 4) + asm volatile ("std; rep; insl; cld" + : "=D" (edi), "=c" (ecx) + : "d" (edx), "0" (edi), "1" (ecx)); + else if (size == 2) + asm volatile ("std; rep; insw; cld" + : "=D" (edi), "=c" (ecx) + : "d" (edx), "0" (edi), "1" (ecx)); + else + asm volatile ("std; rep; insb; cld" + : "=D" (edi), "=c" (ecx) + : "d" (edx), "0" (edi), "1" (ecx)); + } + else + { + if (size == 4) + asm volatile ("cld; rep; insl" + : "=D" (edi), "=c" (ecx) + : "d" (edx), "0" (edi), "1" (ecx)); + else if (size == 2) + asm volatile ("cld; rep; insw" + : "=D" (edi), "=c" (ecx) + : "d" (edx), "0" (edi), "1" (ecx)); + else + asm volatile ("cld; rep; insb" + : "=D" (edi), "=c" (ecx) + : "d" (edx), "0" (edi), "1" (ecx)); + } + + edi -= (unsigned int)context.vm.regs.ds << 4; + + context.vm.regs.edi &= 0xffff0000; + context.vm.regs.edi |= edi & 0xffff; + + context.vm.regs.ecx &= 0xffff0000; + context.vm.regs.ecx |= ecx & 0xffff; + } + +static void +em_outs(int size) + { + unsigned int edx, esi; + + edx = context.vm.regs.edx & 0xffff; + esi = context.vm.regs.esi & 0xffff; + esi += (unsigned int)context.vm.regs.ds << 4; + + if (context.vm.regs.eflags & DIRECTION_FLAG) + { + if (size == 4) + asm volatile ("std; outsl; cld" + : "=S" (esi) : "d" (edx), "0" (esi)); + else if (size == 2) + asm volatile ("std; outsw; cld" + : "=S" (esi) : "d" (edx), "0" (esi)); + else + asm volatile ("std; outsb; cld" + : "=S" (esi) : "d" (edx), "0" (esi)); + } + else + { + if (size == 4) + asm volatile ("cld; outsl" + : "=S" (esi) : "d" (edx), "0" (esi)); + else if (size == 2) + asm volatile ("cld; outsw" + : "=S" (esi) : "d" (edx), "0" (esi)); + else + asm volatile ("cld; outsb" + : "=S" (esi) : "d" (edx), "0" (esi)); + } + + esi -= (unsigned int)context.vm.regs.ds << 4; + + context.vm.regs.esi &= 0xffff0000; + context.vm.regs.esi |= esi & 0xffff; + } + +static void +em_rep_outs(int size) + { + unsigned int ecx, edx, esi; + + ecx = context.vm.regs.ecx & 0xffff; + edx = context.vm.regs.edx & 0xffff; + esi = context.vm.regs.esi & 0xffff; + esi += (unsigned int)context.vm.regs.ds << 4; + + if (context.vm.regs.eflags & DIRECTION_FLAG) + { + if (size == 4) + asm volatile ("std; rep; outsl; cld" + : "=S" (esi), "=c" (ecx) + : "d" (edx), "0" (esi), "1" (ecx)); + else if (size == 2) + asm volatile ("std; rep; outsw; cld" + : "=S" (esi), "=c" (ecx) + : "d" (edx), "0" (esi), "1" (ecx)); + else + asm volatile ("std; rep; outsb; cld" + : "=S" (esi), "=c" (ecx) + : "d" (edx), "0" (esi), "1" (ecx)); + } + else + { + if (size == 4) + asm volatile ("cld; rep; outsl" + : "=S" (esi), "=c" (ecx) + : "d" (edx), "0" (esi), "1" (ecx)); + else if (size == 2) + asm volatile ("cld; rep; outsw" + : "=S" (esi), "=c" (ecx) + : "d" (edx), "0" (esi), "1" (ecx)); + else + asm volatile ("cld; rep; outsb" + : "=S" (esi), "=c" (ecx) + : "d" (edx), "0" (esi), "1" (ecx)); + } + + esi -= (unsigned int)context.vm.regs.ds << 4; + + context.vm.regs.esi &= 0xffff0000; + context.vm.regs.esi |= esi & 0xffff; + + context.vm.regs.ecx &= 0xffff0000; + context.vm.regs.ecx |= ecx & 0xffff; + } + +static void +em_inbl(unsigned char literal) + { + context.vm.regs.eax = inb(literal) & 0xff; + } + +static void +em_inb(void) + { + asm volatile ("inb (%w1), %b0" + : "=a" (context.vm.regs.eax) + : "d" (context.vm.regs.edx), "0" (context.vm.regs.eax)); + } + +static void +em_inw(void) + { + asm volatile ("inw (%w1), %w0" + : "=a" (context.vm.regs.eax) + : "d" (context.vm.regs.edx), "0" (context.vm.regs.eax)); + } + +static void +em_inl(void) + { + asm volatile ("inl (%w1), %0" + : "=a" (context.vm.regs.eax) + : "d" (context.vm.regs.edx)); + } + +static void +em_outbl(unsigned char literal) + { + outb(context.vm.regs.eax & 0xff, literal); + } + +static void +em_outb(void) + { + asm volatile ("outb %b0, (%w1)" + : : "a" (context.vm.regs.eax), + "d" (context.vm.regs.edx)); + } + +static void +em_outw(void) + { + asm volatile ("outw %w0, (%w1)" + : : "a" (context.vm.regs.eax), + "d" (context.vm.regs.edx)); + } + +static void +em_outl(void) + { + asm volatile ("outl %0, (%w1)" + : : "a" (context.vm.regs.eax), + "d" (context.vm.regs.edx)); + } + +static int +emulate(void) + { + unsigned char *insn; + struct + { + unsigned int size : 1; + unsigned int rep : 1; + } prefix = { 0, 0 }; + int i = 0; + + insn = (unsigned char *)((unsigned int)context.vm.regs.cs << 4); + insn += context.vm.regs.eip; + + while (1) + { + if (insn[i] == 0x66) + { + prefix.size = 1 - prefix.size; + i++; + } + else if (insn[i] == 0xf3) + { + prefix.rep = 1; + i++; + } + else if (insn[i] == 0xf0 || insn[i] == 0xf2 + || insn[i] == 0x26 || insn[i] == 0x2e + || insn[i] == 0x36 || insn[i] == 0x3e + || insn[i] == 0x64 || insn[i] == 0x65 + || insn[i] == 0x67) + { + /* these prefixes are just ignored */ + i++; + } + else if (insn[i] == 0x6c) + { + if (prefix.rep) + em_rep_ins(1); + else + em_ins(1); + i++; + break; + } + else if (insn[i] == 0x6d) + { + if (prefix.rep) + { + if (prefix.size) + em_rep_ins(4); + else + em_rep_ins(2); + } + else + { + if (prefix.size) + em_ins(4); + else + em_ins(2); + } + i++; + break; + } + else if (insn[i] == 0x6e) + { + if (prefix.rep) + em_rep_outs(1); + else + em_outs(1); + i++; + break; + } + else if (insn[i] == 0x6f) + { + if (prefix.rep) + { + if (prefix.size) + em_rep_outs(4); + else + em_rep_outs(2); + } + else + { + if (prefix.size) + em_outs(4); + else + em_outs(2); + } + i++; + break; + } + else if (insn[i] == 0xe4) + { + em_inbl(insn[i + 1]); + i += 2; + break; + } + else if (insn[i] == 0xe6) + { + em_outbl(insn[i + 1]); + i += 2; + break; + } + else if (insn[i] == 0xec) + { + em_inb(); + i++; + break; + } + else if (insn[i] == 0xed) + { + if (prefix.size) + em_inl(); + else + em_inw(); + i++; + break; + } + else if (insn[i] == 0xee) + { + em_outb(); + i++; + break; + } + else if (insn[i] == 0xef) + { + if (prefix.size) + em_outl(); + else + em_outw(); + + i++; + break; + } + else + return 0; + } + + context.vm.regs.eip += i; + return 1; + } + + +/* + I don't know how to make sure I get the right vm86() from libc. + The one I want is syscall # 113 (vm86old() in libc 5, vm86() in glibc) + which should be declared as "int vm86(struct vm86_struct *);" in + <sys/vm86.h>. + + This just does syscall 113 with inline asm, which should work + for both libc's (I hope). +*/ +#if !defined(USE_LIBC_VM86) +static int +lrmi_vm86(struct vm86_struct *vm) + { + int r; +#ifdef __PIC__ + asm volatile ( + "pushl %%ebx\n\t" + "movl %2, %%ebx\n\t" + "int $0x80\n\t" + "popl %%ebx" + : "=a" (r) + : "0" (113), "r" (vm)); +#else + asm volatile ( + "int $0x80" + : "=a" (r) + : "0" (113), "b" (vm)); +#endif + return r; + } +#else +#define lrmi_vm86 vm86 +#endif + + +static void +debug_info(int vret) + { + int i; + unsigned char *p; + + fputs("vm86() failed\n", stderr); + fprintf(stderr, "return = 0x%x\n", vret); + fprintf(stderr, "eax = 0x%08lx\n", context.vm.regs.eax); + fprintf(stderr, "ebx = 0x%08lx\n", context.vm.regs.ebx); + fprintf(stderr, "ecx = 0x%08lx\n", context.vm.regs.ecx); + fprintf(stderr, "edx = 0x%08lx\n", context.vm.regs.edx); + fprintf(stderr, "esi = 0x%08lx\n", context.vm.regs.esi); + fprintf(stderr, "edi = 0x%08lx\n", context.vm.regs.edi); + fprintf(stderr, "ebp = 0x%08lx\n", context.vm.regs.ebp); + fprintf(stderr, "eip = 0x%08lx\n", context.vm.regs.eip); + fprintf(stderr, "cs = 0x%04x\n", context.vm.regs.cs); + fprintf(stderr, "esp = 0x%08lx\n", context.vm.regs.esp); + fprintf(stderr, "ss = 0x%04x\n", context.vm.regs.ss); + fprintf(stderr, "ds = 0x%04x\n", context.vm.regs.ds); + fprintf(stderr, "es = 0x%04x\n", context.vm.regs.es); + fprintf(stderr, "fs = 0x%04x\n", context.vm.regs.fs); + fprintf(stderr, "gs = 0x%04x\n", context.vm.regs.gs); + fprintf(stderr, "eflags = 0x%08lx\n", context.vm.regs.eflags); + + fputs("cs:ip = [ ", stderr); + + p = (unsigned char *)((context.vm.regs.cs << 4) + (context.vm.regs.eip & 0xffff)); + + for (i = 0; i < 16; ++i) + fprintf(stderr, "%02x ", (unsigned int)p[i]); + + fputs("]\n", stderr); + } + + +static int +run_vm86(void) + { + unsigned int vret; + + while (1) + { + vret = lrmi_vm86(&context.vm); + + if (VM86_TYPE(vret) == VM86_INTx) + { + unsigned int v = VM86_ARG(vret); + + if (v == RETURN_TO_32_INT) + return 1; + + pushw(context.vm.regs.eflags); + pushw(context.vm.regs.cs); + pushw(context.vm.regs.eip); + + context.vm.regs.cs = get_int_seg(v); + context.vm.regs.eip = get_int_off(v); + context.vm.regs.eflags &= ~(VIF_MASK | TF_MASK); + + continue; + } + + if (VM86_TYPE(vret) != VM86_UNKNOWN) + break; + + if (!emulate()) + break; + } + +#ifdef ORIGINAL_LRMI_CODE_THAT_GOT_IFDEFED_OUT + debug_info(vret); +#endif + return 0; + } + + +int +LRMI_call(struct LRMI_regs *r) + { + unsigned int vret; + + memset(&context.vm.regs, 0, sizeof(context.vm.regs)); + + set_regs(r); + + context.vm.regs.cs = r->cs; + context.vm.regs.eip = r->ip; + + if (r->ss == 0 && r->sp == 0) + { + context.vm.regs.ss = context.stack_seg; + context.vm.regs.esp = context.stack_off; + } + else + { + context.vm.regs.ss = r->ss; + context.vm.regs.esp = r->sp; + } + + pushw(context.ret_seg); + pushw(context.ret_off); + + vret = run_vm86(); + + get_regs(r); + + return vret; + } + + +int +LRMI_int(int i, struct LRMI_regs *r) + { + unsigned int vret; + unsigned int seg, off; + + seg = get_int_seg(i); + off = get_int_off(i); + + /* + If the interrupt is in regular memory, it's probably + still pointing at a dos TSR (which is now gone). + */ + if (seg < 0xa000 || (seg << 4) + off >= 0x100000) + { +#ifdef ORIGINAL_LRMI_CODE_THAT_GOT_IFDEFED_OUT + fprintf(stderr, "Int 0x%x is not in rom (%04x:%04x)\n", i, seg, off); +#endif + return 0; + } + + memset(&context.vm.regs, 0, sizeof(context.vm.regs)); + + set_regs(r); + + context.vm.regs.cs = seg; + context.vm.regs.eip = off; + + if (r->ss == 0 && r->sp == 0) + { + context.vm.regs.ss = context.stack_seg; + context.vm.regs.esp = context.stack_off; + } + else + { + context.vm.regs.ss = r->ss; + context.vm.regs.esp = r->sp; + } + + pushw(DEFAULT_VM86_FLAGS); + pushw(context.ret_seg); + pushw(context.ret_off); + + vret = run_vm86(); + + get_regs(r); + + return vret; + } + diff --git a/ddcprobe/lrmi.h b/ddcprobe/lrmi.h new file mode 100644 index 000000000..c9c186365 --- /dev/null +++ b/ddcprobe/lrmi.h @@ -0,0 +1,85 @@ +/* +Linux Real Mode Interface - A library of DPMI-like functions for Linux. + +Copyright (C) 1998 by Josh Vanderhoof + +You are free to distribute and modify this file, as long as you +do not remove this copyright notice and clearly label modified +versions as being modified. + +This software has NO WARRANTY. Use it at your own risk. +*/ + +#ifndef LRMI_H +#define LRMI_H + +struct LRMI_regs + { + unsigned int edi; + unsigned int esi; + unsigned int ebp; + unsigned int reserved; + unsigned int ebx; + unsigned int edx; + unsigned int ecx; + unsigned int eax; + unsigned short int flags; + unsigned short int es; + unsigned short int ds; + unsigned short int fs; + unsigned short int gs; + unsigned short int ip; + unsigned short int cs; + unsigned short int sp; + unsigned short int ss; + }; + + +#ifndef LRMI_PREFIX +#define LRMI_PREFIX LRMI_ +#endif + +#define LRMI_CONCAT2(a, b) a ## b +#define LRMI_CONCAT(a, b) LRMI_CONCAT2(a, b) +#define LRMI_MAKENAME(a) LRMI_CONCAT(LRMI_PREFIX, a) + +/* + Initialize + returns 1 if sucessful, 0 for failure +*/ +#define LRMI_init LRMI_MAKENAME(init) +int +LRMI_init(void); + +/* + Simulate a 16 bit far call + returns 1 if sucessful, 0 for failure +*/ +#define LRMI_call LRMI_MAKENAME(call) +int +LRMI_call(struct LRMI_regs *r); + +/* + Simulate a 16 bit interrupt + returns 1 if sucessful, 0 for failure +*/ +#define LRMI_int LRMI_MAKENAME(int) +int +LRMI_int(int interrupt, struct LRMI_regs *r); + +/* + Allocate real mode memory + The returned block is paragraph (16 byte) aligned +*/ +#define LRMI_alloc_real LRMI_MAKENAME(alloc_real) +void * +LRMI_alloc_real(int size); + +/* + Free real mode memory +*/ +#define LRMI_free_real LRMI_MAKENAME(free_real) +void +LRMI_free_real(void *m); + +#endif diff --git a/ddcprobe/vbe.h b/ddcprobe/vbe.h new file mode 100644 index 000000000..feae8498a --- /dev/null +++ b/ddcprobe/vbe.h @@ -0,0 +1,311 @@ +#ifndef vbe_h +#define vbe_h +#ident "$Id$" +#include <sys/types.h> + +/* Record returned by int 0x10, function 0x4f, subfunction 0x00. */ +struct vbe_info { + unsigned char signature[4]; + unsigned char version[2]; + union { + struct { + u_int16_t ofs; + u_int16_t seg; + } addr; + const char *string; + } oem_name; + u_int32_t capabilities; + union { + struct { + u_int16_t ofs; + u_int16_t seg; + } addr; + u_int16_t *list; + } mode_list; + u_int16_t memory_size; + /* VESA 3.0+ */ + u_int16_t vbe_revision; + union { + struct { + u_int16_t ofs; + u_int16_t seg; + } addr; + const char *string; + } vendor_name; + union { + struct { + u_int16_t ofs; + u_int16_t seg; + } addr; + const char *string; + } product_name; + union { + struct { + u_int16_t ofs; + u_int16_t seg; + } addr; + const char *string; + } product_revision; + char reserved1[222]; + char reserved2[256]; +} __attribute__ ((packed)); + +/* Stuff returned by int 0x10, function 0x4f, subfunction 0x01. */ +struct vbe_mode_info { + /* required for all VESA versions */ + struct { + /* VBE 1.0+ */ + u_int16_t supported: 1; + u_int16_t optional_info_available: 1; + u_int16_t bios_output_supported: 1; + u_int16_t color: 1; + u_int16_t graphics: 1; + /* VBE 2.0+ */ + u_int16_t not_vga_compatible: 1; + u_int16_t not_bank_switched: 1; + u_int16_t lfb: 1; + /* VBE 1.0+ */ + u_int16_t unknown: 1; + u_int16_t must_enable_directaccess_in_10: 1; + } mode_attributes; + struct { + unsigned char exists: 1; + unsigned char readable: 1; + unsigned char writeable: 1; + unsigned char reserved: 5; + } windowa_attributes, windowb_attributes; + u_int16_t window_granularity; + u_int16_t window_size; + u_int16_t windowa_start_segment, windowb_start_segment; + u_int16_t window_positioning_seg, window_positioning_ofs; + u_int16_t bytes_per_scanline; + /* optional for VESA 1.0/1.1, required for OEM modes */ + u_int16_t w, h; + unsigned char cell_width, cell_height; + unsigned char memory_planes; + unsigned char bpp; + unsigned char banks; + enum { + memory_model_text = 0, + memory_model_cga = 1, + memory_model_hgc = 2, + memory_model_ega16 = 3, + memory_model_packed_pixel = 4, + memory_model_sequ256 = 5, + memory_model_direct_color = 6, + memory_model_yuv = 7, + } memory_model: 8; + unsigned char bank_size; + unsigned char image_pages; + unsigned char reserved1; + /* required for VESA 1.2+ */ + unsigned char red_mask, red_field; + unsigned char green_mask, green_field; + unsigned char blue_mask, blue_field; + unsigned char reserved_mask, reserved_field; + unsigned char direct_color_mode_info; + /* VESA 2.0+ */ + u_int32_t linear_buffer_address; + u_int32_t offscreen_memory_address; + u_int16_t offscreen_memory_size; + unsigned char reserved2[206]; +} __attribute__ ((packed)); + +/* Modeline information used by XFree86. */ +struct vbe_modeline { + u_int16_t width, height; + unsigned char interlaced; + float refresh; + char *modeline; + float hfreq, vfreq, pixel_clock; +}; + +/* Aspect ratios used in EDID info. */ +enum vbe_edid_aspect { + aspect_unknown = 0, + aspect_75, + aspect_8, + aspect_5625, +}; + +/* Detailed timing information used in EDID v1.x */ +struct vbe_edid_detailed_timing { + u_int16_t pixel_clock; +#define VBE_EDID_DETAILED_TIMING_PIXEL_CLOCK(_x) \ + ((_x).pixel_clock * 10000) + unsigned char horizontal_active; + unsigned char horizontal_blanking; + unsigned char horizontal_active_hi: 4; + unsigned char horizontal_blanking_hi: 4; +#define VBE_EDID_DETAILED_TIMING_HORIZONTAL_ACTIVE(_x) \ + (((_x).horizontal_active_hi << 8) + (_x).horizontal_active) +#define VBE_EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(_x) \ + (((_x).horizontal_blanking_hi << 8) + (_x).horizontal_blanking) + unsigned char vertical_active; + unsigned char vertical_blanking; + unsigned char vertical_active_hi: 4; + unsigned char vertical_blanking_hi: 4; +#define VBE_EDID_DETAILED_TIMING_VERTICAL_ACTIVE(_x) \ + (((_x).vertical_active_hi << 8) + (_x).vertical_active) +#define VBE_EDID_DETAILED_TIMING_VERTICAL_BLANKING(_x) \ + (((_x).vertical_blanking_hi << 8) + (_x).vertical_blanking) + unsigned char hsync_offset; + unsigned char hsync_pulse_width; + unsigned char vsync_offset: 4; + unsigned char vsync_pulse_width: 4; + unsigned char hsync_offset_hi: 2; + unsigned char hsync_pulse_width_hi: 2; + unsigned char vsync_offset_hi: 2; + unsigned char vsync_pulse_width_hi: 2; +#define VBE_EDID_DETAILED_TIMING_HSYNC_OFFSET(_x) \ + (((_x).hsync_offset_hi << 8) + (_x).hsync_offset) +#define VBE_EDID_DETAILED_TIMING_HSYNC_PULSE_WIDTH(_x) \ + (((_x).hsync_pulse_width_hi << 8) + (_x).hsync_pulse_width) +#define VBE_EDID_DETAILED_TIMING_VSYNC_OFFSET(_x) \ + (((_x).vsync_offset_hi << 4) + (_x).vsync_offset) +#define VBE_EDID_DETAILED_TIMING_VSYNC_PULSE_WIDTH(_x) \ + (((_x).vsync_pulse_width_hi << 4) + (_x).vsync_pulse_width) + unsigned char himage_size; + unsigned char vimage_size; + unsigned char himage_size_hi: 4; + unsigned char vimage_size_hi: 4; +#define VBE_EDID_DETAILED_TIMING_HIMAGE_SIZE(_x) \ + (((_x).himage_size_hi << 8) + (_x).himage_size) +#define VBE_EDID_DETAILED_TIMING_VIMAGE_SIZE(_x) \ + (((_x).vimage_size_hi << 8) + (_x).vimage_size) + unsigned char hborder; + unsigned char vborder; + struct { + unsigned char interlaced: 1; + unsigned char stereo: 2; + unsigned char digital_composite: 2; + unsigned char variant: 2; + unsigned char zero: 1; + } flags __attribute__ ((packed)); +} __attribute__ ((packed)); + +enum { + vbe_edid_monitor_descriptor_serial = 0xff, + vbe_edid_monitor_descriptor_ascii = 0xfe, + vbe_edid_monitor_descriptor_range = 0xfd, + vbe_edid_monitor_descriptor_name = 0xfc, +} vbe_edid_monitor_descriptor_types; + +struct vbe_edid_monitor_descriptor { + u_int16_t zero_flag_1; + unsigned char zero_flag_2; + unsigned char type; + unsigned char zero_flag_3; + union { + char string[13]; + struct { + unsigned char vertical_min; + unsigned char vertical_max; + unsigned char horizontal_min; + unsigned char horizontal_max; + unsigned char pixel_clock_max; + unsigned char gtf_data[8]; + } range_data; + } data; +} __attribute__ ((packed)); + +struct vbe_edid1_info { + unsigned char header[8]; + struct { + u_int16_t char3: 5; + u_int16_t char2: 5; + u_int16_t char1: 5; + u_int16_t zero: 1; + } manufacturer_name __attribute__ ((packed)); + u_int16_t product_code; + u_int32_t serial_number; + unsigned char week; + unsigned char year; + unsigned char version; + unsigned char revision; + struct { + unsigned char separate_sync: 1; + unsigned char composite_sync: 1; + unsigned char sync_on_green: 1; + unsigned char unused: 2; + unsigned char voltage_level: 2; + unsigned char digital: 1; + } video_input_definition __attribute__ ((packed)); + unsigned char max_size_horizontal; + unsigned char max_size_vertical; + unsigned char gamma; + struct { + unsigned char unused1: 3; + unsigned char rgb: 1; + unsigned char unused2: 1; + unsigned char active_off: 1; + unsigned char suspend: 1; + unsigned char standby: 1; + } feature_support __attribute__ ((packed)); + unsigned char color_characteristics[10]; + struct { + unsigned char timing_720x400_70: 1; + unsigned char timing_720x400_88: 1; + unsigned char timing_640x480_60: 1; + unsigned char timing_640x480_67: 1; + unsigned char timing_640x480_72: 1; + unsigned char timing_640x480_75: 1; + unsigned char timing_800x600_56: 1; + unsigned char timing_800x600_60: 1; + unsigned char timing_800x600_72: 1; + unsigned char timing_800x600_75: 1; + unsigned char timing_832x624_75: 1; + unsigned char timing_1024x768_87i: 1; + unsigned char timing_1024x768_60: 1; + unsigned char timing_1024x768_70: 1; + unsigned char timing_1024x768_75: 1; + unsigned char timing_1280x1024_75: 1; + } established_timings __attribute__ ((packed)); + struct { + unsigned char timing_1152x870_75: 1; + unsigned char reserved: 7; + } manufacturer_timings __attribute__ ((packed)); + struct { + u_int16_t xresolution: 8; + u_int16_t vfreq: 6; + u_int16_t aspect: 2; + } standard_timing[8] __attribute__ ((packed)); + union { + struct vbe_edid_detailed_timing detailed_timing[4]; + struct vbe_edid_monitor_descriptor monitor_descriptor[4]; + } monitor_details __attribute__ ((packed)); + unsigned char extension_flag; + unsigned char checksum; + unsigned char padding[128]; +} __attribute__ ((packed)); + +#define VBE_LINEAR_FRAMEBUFFER 0x4000 + +/* Get VESA information. */ +struct vbe_info *vbe_get_vbe_info(); + +/* Get information about a particular video mode, bitwise or with + VBE_LINEAR_FRAMEBUFFER to check if LFB version is supported. */ +struct vbe_mode_info *vbe_get_mode_info(u_int16_t mode); + +/* Check if EDID reads are supported, and do them. */ +int vbe_get_edid_supported(); +struct vbe_edid1_info *vbe_get_edid_info(); + +/* Get the current video mode, -1 on error. */ +int32_t vbe_get_mode(); +/* Set a new video mode, bitwise or with VBE_LINEAR_FRAMEBUFFER. */ +void vbe_set_mode(u_int16_t mode); + +/* Save/restore the SVGA state. Call free() on the state record when done. */ +const void *vbe_save_svga_state(); +void vbe_restore_svga_state(const void *state); + +/* Get the ranges of values suitable for the attached monitor. */ +void vbe_get_edid_ranges(unsigned char *hmin, unsigned char *hmax, + unsigned char *vmin, unsigned char *vmax); + +/* Get a list of modelines that will work with this monitor. */ +struct vbe_modeline *vbe_get_edid_modelines(); + +#endif diff --git a/ddcprobe/vesamode.h b/ddcprobe/vesamode.h new file mode 100644 index 000000000..b7eef9283 --- /dev/null +++ b/ddcprobe/vesamode.h @@ -0,0 +1,31 @@ +#ifndef vesamode_h +#define vesamode_h +#include <sys/types.h> +#ident "$Id$" + +typedef enum { hsync_neg = 0, hsync_pos } hsync_t; +typedef enum { vsync_neg = 0, vsync_pos } vsync_t; + +struct vesa_mode_t { + u_int16_t number; + u_int16_t x, y; + u_int32_t colors; + const char *text; + const char *modeline; +}; + +struct vesa_timing_t { + u_int16_t x, y; + float refresh; + float dotclock; + u_int16_t timings[8]; + hsync_t hsync; + vsync_t vsync; + float hfreq; + float vfreq; +}; + +extern struct vesa_mode_t known_vesa_modes[]; +extern struct vesa_timing_t known_vesa_timings[]; + +#endif /* vesamode_h */ |