summaryrefslogtreecommitdiffstats
path: root/ddcprobe
diff options
context:
space:
mode:
Diffstat (limited to 'ddcprobe')
-rw-r--r--ddcprobe/lrmi.c911
-rw-r--r--ddcprobe/lrmi.h85
-rw-r--r--ddcprobe/vbe.h311
-rw-r--r--ddcprobe/vesamode.h31
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 */