lrmi-0.10/0000775000076400007640000000000010344700507012337 5ustar joshjosh00000000000000lrmi-0.10/Makefile0000664000076400007640000000245210344676345014016 0ustar joshjosh00000000000000LIBDIR ?= /usr/local/lib INCDIR ?= /usr/local/include CFLAGS = -g -Wall sources = lrmi.c objects = lrmi.o pic_objects = lrmi.lo all = liblrmi.a liblrmi.so vbetest MAJOR = 0 MINOR = 10 VERSION = $(MAJOR).$(MINOR) LIBNAME = liblrmi %.o: %.c $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< %.lo: %.c $(CC) -c $(CPPFLAGS) $(CFLAGS) -fPIC -o $@ $< all: $(all) liblrmi.a: $(objects) $(AR) -rs $@ $^ liblrmi.so: $(pic_objects) # $(CC) $(CPPFLAGS) $(CFLAGS) -fPIC -shared -o $@ $^ $(CC) $(CPPFLAGS) $(CFLAGS) -Wl,-soname,$(LIBNAME).so.$(MAJOR) -fPIC -shared -o $(LIBNAME).so.$(VERSION) $^ ln -sf $(LIBNAME).so.$(VERSION) $(LIBNAME).so.$(MAJOR) ln -sf $(LIBNAME).so.$(MAJOR) $(LIBNAME).so vbetest: vbetest.c liblrmi.a $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $^ install: mkdir -p $(LIBDIR) install -m 755 -s -p $(LIBNAME).so.$(VERSION) $(LIBDIR)/$(LIBNAME).so.$(VERSION) rm -f $(LIBDIR)/$(LIBNAME).so ln -sf $(LIBNAME).so.$(VERSION) $(LIBDIR)/$(LIBNAME).so.$(MAJOR) ln -sf $(LIBNAME).so.$(MAJOR) $(LIBDIR)/$(LIBNAME).so install -m 644 -s -p lrmi.h $(INCDIR)/lrmi.h ldconfig .PHONY: clean clean: rm -f $(objects) $(pic_objects) $(all) core rm -f liblrmi.so liblrmi.so.$(MAJOR) liblrmi.so.$(VERSION) .PHONY: distclean distclean: clean rm -f .depend .PHONY: depend depend: $(sources) -$(CC) -M $(CPPFLAGS) $^ >.depend lrmi-0.10/Makefile.bsd0000664000076400007640000000132307660332564014560 0ustar joshjosh00000000000000CFLAGS = -g -Wall RANLIB = ranlib OS != uname -s sources = lrmi.c lrmi.h objects = lrmi.o pic_objects = lrmi.lo all = liblrmi.a liblrmi.so vbetest .if ${OS}=="NetBSD" || ${OS}=="OpenBSD" libs= -li386 .endif all: $(all) .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) -o ${.TARGET} ${.IMPSRC} .SUFFIXES: .lo .c.lo: $(CC) -c $(CPPFLAGS) $(CFLAGS) -fPIC -o ${.TARGET} ${.IMPSRC} liblrmi.a: $(objects) $(AR) -r ${.TARGET} ${.ALLSRC} $(RANLIB) ${.TARGET} liblrmi.so: $(pic_objects) $(CC) $(CPPFLAGS) $(CFLAGS) -fPIC -shared -o ${.TARGET} ${.ALLSRC} ${libs} vbetest: vbetest.o liblrmi.a $(CC) $(CPPFLAGS) $(CFLAGS) -o ${.TARGET} ${.ALLSRC} ${libs} .PHONY: clean clean: rm -f $(objects) $(pic_objects) vbetest.o $(all) *.core lrmi-0.10/README0000664000076400007640000000120710277116305013221 0ustar joshjosh00000000000000Linux Real Mode Interface ========================= 1, Goal This library provides a DPMI like interface under Linux and *BSD systems using vm86. There is also some VBE (VESA Bios Extension) interface utility called vbetest. 2, Supported systems Only under x86: * Linux 2.2 and above * FreeBSD * NetBSD * OpenBSD 3, License Look into the individual source files. 4, Authors Josh Vanderhoof * original author Dmitry Frolov * FreeBSD/NetBSD support Alex Beregszaszi * merged MPlayer, MPlayerXP, svgalib and LRMI versions * OpenBSD support Oleg I. Vdovikin * pthread fixes Peter Kosinar * pthread fixes lrmi-0.10/lrmi.c0000664000076400007640000005355210344677554013477 0ustar joshjosh00000000000000/* Linux Real Mode Interface - A library of DPMI-like functions for Linux. Copyright (C) 1998 by Josh Vanderhoof Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL JOSH VANDERHOOF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #if defined(__i386__) && (defined(__linux__) || defined(__NetBSD__) \ || defined(__FreeBSD__) || defined(__OpenBSD__)) #include #include #if defined(__linux__) #include #include #ifdef USE_LIBC_VM86 #include #endif #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) #include #include #include #include #include #include #endif /* __NetBSD__ || __FreeBSD__ || __OpenBSD__ */ #if defined(__FreeBSD__) #include #endif #include #include #include #include #include #include "lrmi.h" #define REAL_MEM_BASE ((void *)0x10000) #define REAL_MEM_SIZE 0x40000 #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 read_file(char *name, void *p, size_t n) { int fd; fd = open(name, O_RDONLY); if (fd == -1) { perror("open"); return 0; } if (read(fd, p, n) != n) { perror("read"); close(fd); return 0; } close(fd); return 1; } static int map_file(void *start, size_t length, int prot, int flags, char *name, long offset) { void *m; int fd; fd = open(name, (flags & MAP_SHARED) ? O_RDWR : O_RDONLY); if (fd == -1) { perror("open"); return 0; } m = mmap(start, length, prot, flags, fd, offset); if (m == (void *)-1) { perror("mmap"); close(fd); return 0; } close(fd); return 1; } static int real_mem_init(void) { if (mem_info.ready) return 1; if (!map_file((void *)REAL_MEM_BASE, REAL_MEM_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, "/dev/zero", 0)) 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 real_mem_deinit(void) { if (mem_info.ready) { munmap((void *)REAL_MEM_BASE, REAL_MEM_SIZE); mem_info.ready = 0; } } 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); } } #if defined(__linux__) #define DEFAULT_VM86_FLAGS (IF_MASK | IOPL_MASK) #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) #define DEFAULT_VM86_FLAGS (PSL_I | PSL_IOPL) #define TF_MASK PSL_T #define VIF_MASK PSL_VIF #endif #define DEFAULT_STACK_SIZE 0x1000 #define RETURN_TO_32_INT 255 #if defined(__linux__) #define CONTEXT_REGS context.vm.regs #define REG(x) x #elif defined(__NetBSD__) || defined(__OpenBSD__) #define CONTEXT_REGS context.vm.substr.regs #define REG(x) vmsc.sc_ ## x #elif defined(__FreeBSD__) #define CONTEXT_REGS context.vm.uc #define REG(x) uc_mcontext.mc_ ## x #endif static struct { int ready; unsigned short ret_seg, ret_off; unsigned short stack_seg, stack_off; #if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) struct vm86_struct vm; #elif defined(__FreeBSD__) struct { struct vm86_init_args init; ucontext_t uc; } vm; #endif #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) int success; jmp_buf env; void *old_sighandler; int vret; #endif } 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) { CONTEXT_REGS.REG(esp) -= 2; *(unsigned short *)(((unsigned int)CONTEXT_REGS.REG(ss) << 4) + CONTEXT_REGS.REG(esp)) = i; } int LRMI_init(void) { void *m; 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) */ if (!map_file((void *)0, 0x502, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, "/dev/zero", 0)) { real_mem_deinit(); return 0; } if (!read_file("/dev/mem", (void *)0, 0x502)) { munmap((void *)0, 0x502); real_mem_deinit(); return 0; } if (!map_file((void *)0xa0000, 0x100000 - 0xa0000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, "/dev/mem", 0xa0000)) { munmap((void *)0, 0x502); real_mem_deinit(); 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 */ #if defined(__linux__) memset(&context.vm.int_revectored, 0, sizeof(context.vm.int_revectored)); set_bit(RETURN_TO_32_INT, &context.vm.int_revectored); #elif defined(__NetBSD__) || defined(__OpenBSD__) set_bit(RETURN_TO_32_INT, &context.vm.int_byuser); #elif defined(__FreeBSD__) set_bit(RETURN_TO_32_INT, &context.vm.init.int_map); #endif context.ready = 1; return 1; } static void set_regs(struct LRMI_regs *r) { CONTEXT_REGS.REG(edi) = r->edi; CONTEXT_REGS.REG(esi) = r->esi; CONTEXT_REGS.REG(ebp) = r->ebp; CONTEXT_REGS.REG(ebx) = r->ebx; CONTEXT_REGS.REG(edx) = r->edx; CONTEXT_REGS.REG(ecx) = r->ecx; CONTEXT_REGS.REG(eax) = r->eax; CONTEXT_REGS.REG(eflags) = DEFAULT_VM86_FLAGS; CONTEXT_REGS.REG(es) = r->es; CONTEXT_REGS.REG(ds) = r->ds; CONTEXT_REGS.REG(fs) = r->fs; CONTEXT_REGS.REG(gs) = r->gs; } static void get_regs(struct LRMI_regs *r) { r->edi = CONTEXT_REGS.REG(edi); r->esi = CONTEXT_REGS.REG(esi); r->ebp = CONTEXT_REGS.REG(ebp); r->ebx = CONTEXT_REGS.REG(ebx); r->edx = CONTEXT_REGS.REG(edx); r->ecx = CONTEXT_REGS.REG(ecx); r->eax = CONTEXT_REGS.REG(eax); r->flags = CONTEXT_REGS.REG(eflags); r->es = CONTEXT_REGS.REG(es); r->ds = CONTEXT_REGS.REG(ds); r->fs = CONTEXT_REGS.REG(fs); r->gs = CONTEXT_REGS.REG(gs); } #define DIRECTION_FLAG (1 << 10) enum { CSEG = 0x2e, SSEG = 0x36, DSEG = 0x3e, ESEG = 0x26, FSEG = 0x64, GSEG = 0x65, }; static void em_ins(int size) { unsigned int edx, edi; edx = CONTEXT_REGS.REG(edx) & 0xffff; edi = CONTEXT_REGS.REG(edi) & 0xffff; edi += (unsigned int)CONTEXT_REGS.REG(es) << 4; if (CONTEXT_REGS.REG(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_REGS.REG(es) << 4; CONTEXT_REGS.REG(edi) &= 0xffff0000; CONTEXT_REGS.REG(edi) |= edi & 0xffff; } static void em_rep_ins(int size) { unsigned int cx; cx = CONTEXT_REGS.REG(ecx) & 0xffff; while (cx--) em_ins(size); CONTEXT_REGS.REG(ecx) &= 0xffff0000; } static void em_outs(int size, int seg) { unsigned int edx, esi, base; edx = CONTEXT_REGS.REG(edx) & 0xffff; esi = CONTEXT_REGS.REG(esi) & 0xffff; switch (seg) { case CSEG: base = CONTEXT_REGS.REG(cs); break; case SSEG: base = CONTEXT_REGS.REG(ss); break; case ESEG: base = CONTEXT_REGS.REG(es); break; case FSEG: base = CONTEXT_REGS.REG(fs); break; case GSEG: base = CONTEXT_REGS.REG(gs); break; default: case DSEG: base = CONTEXT_REGS.REG(ds); break; } esi += base << 4; if (CONTEXT_REGS.REG(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 -= base << 4; CONTEXT_REGS.REG(esi) &= 0xffff0000; CONTEXT_REGS.REG(esi) |= esi & 0xffff; } static void em_rep_outs(int size, int seg) { unsigned int cx; cx = CONTEXT_REGS.REG(ecx) & 0xffff; while (cx--) em_outs(size, seg); CONTEXT_REGS.REG(ecx) &= 0xffff0000; } static void em_inbl(unsigned char literal) { asm volatile ("inb %w1, %b0" : "=a" (CONTEXT_REGS.REG(eax)) : "d" (literal), "0" (CONTEXT_REGS.REG(eax))); } static void em_inb(void) { asm volatile ("inb %w1, %b0" : "=a" (CONTEXT_REGS.REG(eax)) : "d" (CONTEXT_REGS.REG(edx)), "0" (CONTEXT_REGS.REG(eax))); } static void em_inw(void) { asm volatile ("inw %w1, %w0" : "=a" (CONTEXT_REGS.REG(eax)) : "d" (CONTEXT_REGS.REG(edx)), "0" (CONTEXT_REGS.REG(eax))); } static void em_inl(void) { asm volatile ("inl %w1, %0" : "=a" (CONTEXT_REGS.REG(eax)) : "d" (CONTEXT_REGS.REG(edx))); } static void em_outbl(unsigned char literal) { asm volatile ("outb %b0, %w1" : : "a" (CONTEXT_REGS.REG(eax)), "d" (literal)); } static void em_outb(void) { asm volatile ("outb %b0, %w1" : : "a" (CONTEXT_REGS.REG(eax)), "d" (CONTEXT_REGS.REG(edx))); } static void em_outw(void) { asm volatile ("outw %w0, %w1" : : "a" (CONTEXT_REGS.REG(eax)), "d" (CONTEXT_REGS.REG(edx))); } static void em_outl(void) { asm volatile ("outl %0, %w1" : : "a" (CONTEXT_REGS.REG(eax)), "d" (CONTEXT_REGS.REG(edx))); } static int emulate(void) { unsigned char *insn; struct { unsigned char seg; unsigned int size : 1; unsigned int rep : 1; } prefix = { DSEG, 0, 0 }; int i = 0; insn = (unsigned char *)((unsigned int)CONTEXT_REGS.REG(cs) << 4); insn += CONTEXT_REGS.REG(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] == CSEG || insn[i] == SSEG || insn[i] == DSEG || insn[i] == ESEG || insn[i] == FSEG || insn[i] == GSEG) { prefix.seg = insn[i]; i++; } else if (insn[i] == 0xf0 || insn[i] == 0xf2 || 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, prefix.seg); else em_outs(1, prefix.seg); i++; break; } else if (insn[i] == 0x6f) { if (prefix.rep) { if (prefix.size) em_rep_outs(4, prefix.seg); else em_rep_outs(2, prefix.seg); } else { if (prefix.size) em_outs(4, prefix.seg); else em_outs(2, prefix.seg); } i++; break; } else if (insn[i] == 0xe4) { em_inbl(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] == 0xe6) { em_outbl(insn[i + 1]); i += 2; 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_REGS.REG(eip) += i; return 1; } #if defined(__linux__) /* 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 . 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 #endif /* __linux__ */ static void debug_info(int vret) { #ifdef LRMI_DEBUG int i; unsigned char *p; fputs("vm86() failed\n", stderr); fprintf(stderr, "return = 0x%x\n", vret); fprintf(stderr, "eax = 0x%08x\n", CONTEXT_REGS.REG(eax)); fprintf(stderr, "ebx = 0x%08x\n", CONTEXT_REGS.REG(ebx)); fprintf(stderr, "ecx = 0x%08x\n", CONTEXT_REGS.REG(ecx)); fprintf(stderr, "edx = 0x%08x\n", CONTEXT_REGS.REG(edx)); fprintf(stderr, "esi = 0x%08x\n", CONTEXT_REGS.REG(esi)); fprintf(stderr, "edi = 0x%08x\n", CONTEXT_REGS.REG(edi)); fprintf(stderr, "ebp = 0x%08x\n", CONTEXT_REGS.REG(ebp)); fprintf(stderr, "eip = 0x%08x\n", CONTEXT_REGS.REG(eip)); fprintf(stderr, "cs = 0x%04x\n", CONTEXT_REGS.REG(cs)); fprintf(stderr, "esp = 0x%08x\n", CONTEXT_REGS.REG(esp)); fprintf(stderr, "ss = 0x%04x\n", CONTEXT_REGS.REG(ss)); fprintf(stderr, "ds = 0x%04x\n", CONTEXT_REGS.REG(ds)); fprintf(stderr, "es = 0x%04x\n", CONTEXT_REGS.REG(es)); fprintf(stderr, "fs = 0x%04x\n", CONTEXT_REGS.REG(fs)); fprintf(stderr, "gs = 0x%04x\n", CONTEXT_REGS.REG(gs)); fprintf(stderr, "eflags = 0x%08x\n", CONTEXT_REGS.REG(eflags)); fputs("cs:ip = [ ", stderr); p = (unsigned char *)((CONTEXT_REGS.REG(cs) << 4) + (CONTEXT_REGS.REG(eip) & 0xffff)); for (i = 0; i < 16; ++i) fprintf(stderr, "%02x ", (unsigned int)p[i]); fputs("]\n", stderr); #endif } #if defined(__linux__) static int run_vm86(void) { unsigned int vret; sigset_t all_sigs, old_sigs; unsigned long old_gs, old_fs; while (1) { // FIXME: may apply this to BSD equivalents? sigfillset(&all_sigs); sigprocmask(SIG_SETMASK, &all_sigs, &old_sigs); asm volatile ("mov %%gs, %0" : "=rm" (old_gs)); asm volatile ("mov %%fs, %0" : "=rm" (old_fs)); vret = lrmi_vm86(&context.vm); asm volatile ("mov %0, %%gs" :: "rm" (old_gs)); asm volatile ("mov %0, %%fs" :: "rm" (old_fs)); sigprocmask(SIG_SETMASK, &old_sigs, NULL); if (VM86_TYPE(vret) == VM86_INTx) { unsigned int v = VM86_ARG(vret); if (v == RETURN_TO_32_INT) return 1; pushw(CONTEXT_REGS.REG(eflags)); pushw(CONTEXT_REGS.REG(cs)); pushw(CONTEXT_REGS.REG(eip)); CONTEXT_REGS.REG(cs) = get_int_seg(v); CONTEXT_REGS.REG(eip) = get_int_off(v); CONTEXT_REGS.REG(eflags) &= ~(VIF_MASK | TF_MASK); continue; } if (VM86_TYPE(vret) != VM86_UNKNOWN) break; if (!emulate()) break; } debug_info(vret); return 0; } #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) #if defined(__NetBSD__) || defined(__OpenBSD__) static void vm86_callback(int sig, int code, struct sigcontext *sc) { /* Sync our context with what the kernel develivered to us. */ memcpy(&CONTEXT_REGS, sc, sizeof(*sc)); switch (VM86_TYPE(code)) { case VM86_INTx: { unsigned int v = VM86_ARG(code); if (v == RETURN_TO_32_INT) { context.success = 1; longjmp(context.env, 1); } pushw(CONTEXT_REGS.REG(eflags)); pushw(CONTEXT_REGS.REG(cs)); pushw(CONTEXT_REGS.REG(eip)); CONTEXT_REGS.REG(cs) = get_int_seg(v); CONTEXT_REGS.REG(eip) = get_int_off(v); CONTEXT_REGS.REG(eflags) &= ~(VIF_MASK | TF_MASK); break; } case VM86_UNKNOWN: if (emulate() == 0) { context.success = 0; context.vret = code; longjmp(context.env, 1); } break; default: context.success = 0; context.vret = code; longjmp(context.env, 1); return; } /* ...and sync our context back to the kernel. */ memcpy(sc, &CONTEXT_REGS, sizeof(*sc)); } #elif defined(__FreeBSD__) static void vm86_callback(int sig, int code, struct sigcontext *sc) { unsigned char *addr; /* Sync our context with what the kernel develivered to us. */ memcpy(&CONTEXT_REGS, sc, sizeof(*sc)); if (code) { /* XXX probably need to call original signal handler here */ context.success = 0; context.vret = code; longjmp(context.env, 1); } addr = (unsigned char *)((CONTEXT_REGS.REG(cs) << 4) + CONTEXT_REGS.REG(eip)); if (addr[0] == 0xcd) { /* int opcode */ if (addr[1] == RETURN_TO_32_INT) { context.success = 1; longjmp(context.env, 1); } pushw(CONTEXT_REGS.REG(eflags)); pushw(CONTEXT_REGS.REG(cs)); pushw(CONTEXT_REGS.REG(eip)); CONTEXT_REGS.REG(cs) = get_int_seg(addr[1]); CONTEXT_REGS.REG(eip) = get_int_off(addr[1]); CONTEXT_REGS.REG(eflags) &= ~(VIF_MASK | TF_MASK); } else { if (emulate() == 0) { context.success = 0; longjmp(context.env, 1); } } /* ...and sync our context back to the kernel. */ memcpy(sc, &CONTEXT_REGS, sizeof(*sc)); } #endif /* __FreeBSD__ */ static int run_vm86(void) { if (context.old_sighandler) { #ifdef LRMI_DEBUG fprintf(stderr, "run_vm86: callback already installed\n"); #endif return (0); } #if defined(__NetBSD__) || defined(__OpenBSD__) context.old_sighandler = signal(SIGURG, (void (*)(int))vm86_callback); #elif defined(__FreeBSD__) context.old_sighandler = signal(SIGBUS, (void (*)(int))vm86_callback); #endif if (context.old_sighandler == (void *)-1) { context.old_sighandler = NULL; #ifdef LRMI_DEBUG fprintf(stderr, "run_vm86: cannot install callback\n"); #endif return (0); } if (setjmp(context.env)) { #if defined(__NetBSD__) || defined(__OpenBSD__) (void) signal(SIGURG, context.old_sighandler); #elif defined(__FreeBSD__) (void) signal(SIGBUS, context.old_sighandler); #endif context.old_sighandler = NULL; if (context.success) return (1); debug_info(context.vret); return (0); } #if defined(__NetBSD__) || defined(__OpenBSD__) if (i386_vm86(&context.vm) == -1) return (0); #elif defined(__FreeBSD__) if (i386_vm86(VM86_INIT, &context.vm.init)) return 0; CONTEXT_REGS.REG(eflags) |= PSL_VM | PSL_VIF; sigreturn(&context.vm.uc); #endif /* __FreeBSD__ */ /* NOTREACHED */ return (0); } #endif /* __NetBSD__ || __FreeBSD__ || __OpenBSD__ */ int LRMI_call(struct LRMI_regs *r) { unsigned int vret; memset(&CONTEXT_REGS, 0, sizeof(CONTEXT_REGS)); set_regs(r); CONTEXT_REGS.REG(cs) = r->cs; CONTEXT_REGS.REG(eip) = r->ip; if (r->ss == 0 && r->sp == 0) { CONTEXT_REGS.REG(ss) = context.stack_seg; CONTEXT_REGS.REG(esp) = context.stack_off; } else { CONTEXT_REGS.REG(ss) = r->ss; CONTEXT_REGS.REG(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 LRMI_DEBUG fprintf(stderr, "Int 0x%x is not in rom (%04x:%04x)\n", i, seg, off); #endif return 0; } memset(&CONTEXT_REGS, 0, sizeof(CONTEXT_REGS)); set_regs(r); CONTEXT_REGS.REG(cs) = seg; CONTEXT_REGS.REG(eip) = off; if (r->ss == 0 && r->sp == 0) { CONTEXT_REGS.REG(ss) = context.stack_seg; CONTEXT_REGS.REG(esp) = context.stack_off; } else { CONTEXT_REGS.REG(ss) = r->ss; CONTEXT_REGS.REG(esp) = r->sp; } pushw(DEFAULT_VM86_FLAGS); pushw(context.ret_seg); pushw(context.ret_off); vret = run_vm86(); get_regs(r); return vret; } #else /* (__linux__ || __NetBSD__ || __FreeBSD__ || __OpenBSD__) && __i386__ */ #warning "LRMI is not supported on your system!" #endif lrmi-0.10/lrmi.h0000664000076400007640000000535610277116305013466 0ustar joshjosh00000000000000/* Linux Real Mode Interface - A library of DPMI-like functions for Linux. Copyright (C) 1998 by Josh Vanderhoof Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL JOSH VANDERHOOF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef LRMI_H #define LRMI_H #if defined(__i386__) && (defined(__linux__) || defined(__NetBSD__) \ || defined(__FreeBSD__) || defined(__OpenBSD__)) 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) /* Package version (high 16bit = major, low 16bit minor) */ #define LRMI_version 0x0009 /* 0.9 */ /* 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); #else /* (__linux__ || __NetBSD__ || __FreeBSD__) && __i386__ */ #warning "LRMI is not supported on your system!" #endif #endif lrmi-0.10/vbe.h0000664000076400007640000000474607161017564013306 0ustar joshjosh00000000000000/* This file is in the public domain. */ #ifndef _VBE_H #define _VBE_H /* structures for vbe 2.0 */ struct vbe_info_block { char vbe_signature[4]; short vbe_version; unsigned short oem_string_off; unsigned short oem_string_seg; int capabilities; unsigned short video_mode_list_off; unsigned short video_mode_list_seg; short total_memory; short oem_software_rev; unsigned short oem_vendor_name_off; unsigned short oem_vendor_name_seg; unsigned short oem_product_name_off; unsigned short oem_product_name_seg; unsigned short oem_product_rev_off; unsigned short oem_product_rev_seg; char reserved[222]; char oem_data[256]; } __attribute__ ((packed)); #define VBE_ATTR_MODE_SUPPORTED (1 << 0) #define VBE_ATTR_TTY (1 << 2) #define VBE_ATTR_COLOR (1 << 3) #define VBE_ATTR_GRAPHICS (1 << 4) #define VBE_ATTR_NOT_VGA (1 << 5) #define VBE_ATTR_NOT_WINDOWED (1 << 6) #define VBE_ATTR_LINEAR (1 << 7) #define VBE_WIN_RELOCATABLE (1 << 0) #define VBE_WIN_READABLE (1 << 1) #define VBE_WIN_WRITEABLE (1 << 2) #define VBE_MODEL_TEXT 0 #define VBE_MODEL_CGA 1 #define VBE_MODEL_HERCULES 2 #define VBE_MODEL_PLANAR 3 #define VBE_MODEL_PACKED 4 #define VBE_MODEL_256 5 #define VBE_MODEL_RGB 6 #define VBE_MODEL_YUV 7 struct vbe_mode_info_block { unsigned short mode_attributes; unsigned char win_a_attributes; unsigned char win_b_attributes; unsigned short win_granularity; unsigned short win_size; unsigned short win_a_segment; unsigned short win_b_segment; unsigned short win_func_ptr_off; unsigned short win_func_ptr_seg; unsigned short bytes_per_scanline; unsigned short x_resolution; unsigned short y_resolution; unsigned char x_char_size; unsigned char y_char_size; unsigned char number_of_planes; unsigned char bits_per_pixel; unsigned char number_of_banks; unsigned char memory_model; unsigned char bank_size; unsigned char number_of_image_pages; unsigned char res1; unsigned char red_mask_size; unsigned char red_field_position; unsigned char green_mask_size; unsigned char green_field_position; unsigned char blue_mask_size; unsigned char blue_field_position; unsigned char rsvd_mask_size; unsigned char rsvd_field_position; unsigned char direct_color_mode_info; unsigned int phys_base_ptr; unsigned int offscreen_mem_offset; unsigned short offscreen_mem_size; unsigned char res2[206]; } __attribute__ ((packed)); struct vbe_palette_entry { unsigned char blue; unsigned char green; unsigned char red; unsigned char align; } __attribute__ ((packed)); #endif lrmi-0.10/vbetest.c0000644000076400007640000002171210344677554014177 0ustar joshjosh00000000000000/* List the available VESA graphics modes. This program is in the public domain. */ #include #include #include #include #include #if defined(__linux__) #include #include #include #elif defined(__NetBSD__) || defined(__OpenBSD__) #include #include #include #elif defined(__FreeBSD__) #include #include #endif #include "lrmi.h" #include "vbe.h" struct { struct vbe_info_block *info; struct vbe_mode_info_block *mode; char *win; /* this doesn't point directly at the window, see update_window() */ int win_low, win_high; } vbe; static char *run_command = NULL; void * save_state(void) { struct LRMI_regs r; void *buffer; memset(&r, 0, sizeof(r)); r.eax = 0x4f04; r.ecx = 0xf; /* all states */ r.edx = 0; /* get buffer size */ if (!LRMI_int(0x10, &r)) { fprintf(stderr, "Can't get video state buffer size (vm86 failure)\n"); return NULL; } if ((r.eax & 0xffff) != 0x4f) { fprintf(stderr, "Get video state buffer size failed\n"); return NULL; } buffer = LRMI_alloc_real((r.ebx & 0xffff) * 64); if (buffer == NULL) { fprintf(stderr, "Can't allocate video state buffer\n"); return NULL; } memset(&r, 0, sizeof(r)); r.eax = 0x4f04; r.ecx = 0xf; /* all states */ r.edx = 1; /* save state */ r.es = (unsigned int)buffer >> 4; r.ebx = (unsigned int)buffer & 0xf; if (!LRMI_int(0x10, &r)) { fprintf(stderr, "Can't save video state (vm86 failure)\n"); return NULL; } if ((r.eax & 0xffff) != 0x4f) { fprintf(stderr, "Save video state failed\n"); return NULL; } return buffer; } void restore_state(void *buffer) { struct LRMI_regs r; memset(&r, 0, sizeof(r)); r.eax = 0x4f04; r.ecx = 0xf; /* all states */ r.edx = 2; /* restore state */ r.es = (unsigned int)buffer >> 4; r.ebx = (unsigned int)buffer & 0xf; if (!LRMI_int(0x10, &r)) { fprintf(stderr, "Can't restore video state (vm86 failure)\n"); } else if ((r.eax & 0xffff) != 0x4f) { fprintf(stderr, "Restore video state failed\n"); } LRMI_free_real(buffer); } void text_mode(void) { struct LRMI_regs r; memset(&r, 0, sizeof(r)); r.eax = 3; if (!LRMI_int(0x10, &r)) { fprintf(stderr, "Can't set text mode (vm86 failure)\n"); } } int update_window(int address) { struct LRMI_regs r; int w, g; if (address >= vbe.win_low && address < vbe.win_high) return 0; g = vbe.mode->win_granularity * 1024; w = address / g; memset(&r, 0, sizeof(r)); r.eax = 0x4f05; r.ebx = 0; r.edx = w; LRMI_int(0x10, &r); vbe.win_low = w * g; vbe.win_high = vbe.win_low + vbe.mode->win_size * 1024; vbe.win = (char *)(vbe.mode->win_a_segment << 4); vbe.win -= vbe.win_low; return 1; } void set_pixel(int x, int y, int r, int g, int b) { int x_res = vbe.mode->x_resolution; int y_res = vbe.mode->y_resolution; int shift_r = vbe.mode->red_field_position; int shift_g = vbe.mode->green_field_position; int shift_b = vbe.mode->blue_field_position; int pixel_size = (vbe.mode->bits_per_pixel + 7) / 8; int bpl = vbe.mode->bytes_per_scanline; int c, addr; if (x < 0 || x >= x_res || y < 0 || y >= y_res) return; r >>= 8 - vbe.mode->red_mask_size; g >>= 8 - vbe.mode->green_mask_size; b >>= 8 - vbe.mode->blue_mask_size; c = (r << shift_r) | (g << shift_g) | (b << shift_b); addr = y * bpl + (x * pixel_size); update_window(addr); memcpy(vbe.win + addr, &c, pixel_size); } void set_mode(int n) { struct LRMI_regs r; memset(&r, 0, sizeof(r)); r.eax = 0x4f02; r.ebx = n; if (!LRMI_int(0x10, &r)) { fprintf(stderr, "Can't set video mode (vm86 failure)\n"); } else if ((r.eax & 0xffff) != 0x4f) { fprintf(stderr, "Set video mode failed\n"); } memset(&r, 0, sizeof(r)); r.eax = 0x4f01; r.ecx = n; r.es = (unsigned int)vbe.mode >> 4; r.edi = (unsigned int)vbe.mode & 0xf; if (!LRMI_int(0x10, &r)) { fprintf(stderr, "Can't get mode info (vm86 failure)\n"); return; } if ((r.eax & 0xffff) != 0x4f) { fprintf(stderr, "Get mode info failed\n"); return; } vbe.win_low = vbe.win_high = -1; /* Draw a colorful checkerboard */ if (vbe.mode->memory_model == VBE_MODEL_RGB) { int x_res = vbe.mode->x_resolution; int y_res = vbe.mode->y_resolution; int x, y; for (y = 0; y < y_res; ++y) { for (x = 0; x < x_res; ++x) { int r, g, b; if ((x & 16) ^ (y & 16)) { r = x * 255 / x_res; g = y * 255 / y_res; b = 255 - x * 255 / x_res; } else { r = 255 - x * 255 / x_res; g = y * 255 / y_res; b = 255 - y * 255 / y_res; } set_pixel(x, y, r, g, b); } } } } void interactive_set_mode(int n) { void *state; #if defined(__linux__) struct stat stat; #elif defined(__NetBSD__) || defined(__OpenBSD__) struct wsdisplay_fbinfo wsi; #elif defined(__FreeBSD__) struct vid_info vi; #endif if (n == -1) { printf("Type a mode number, or 'q' to quit - "); if (scanf("%d", &n) != 1) return; } #if defined(__linux__) if (fstat(0, &stat) != 0) { fprintf(stderr, "Can't stat() stdin\n"); return; } if ((stat.st_rdev & 0xff00) != 0x400 || (stat.st_rdev & 0xff) > 63) #elif defined(__NetBSD__) || defined(__OpenBSD__) if (ioctl(0, WSDISPLAYIO_GINFO, &wsi) == -1) #elif defined(__FreeBSD__) memset(&vi, 0, sizeof(vi)); vi.size = sizeof(vi); if (ioctl(0, CONS_GETINFO, &vi) == -1) #endif { fprintf(stderr, "To switch video modes, " "this program must be run from the console\n"); return; } printf("setting mode %d\n", n); #if defined(__linux__) || defined(__FreeBSD__) ioctl(0, KDSETMODE, KD_GRAPHICS); #elif defined(__NetBSD__) || defined(__OpenBSD__) ioctl(0, WSDISPLAYIO_SMODE, WSDISPLAYIO_MODE_MAPPED); #endif state = save_state(); if (state == NULL) return; set_mode(n); system(run_command); sleep(5); text_mode(); restore_state(state); #if defined(__linux__) || defined(__FreeBSD__) ioctl(0, KDSETMODE, KD_TEXT); #elif defined(__NetBSD__) || defined(__OpenBSD__) ioctl(0, WSDISPLAYIO_SMODE, WSDISPLAYIO_MODE_EMUL); #endif } void usage_and_quit(int error) { fputs("Usage: vbetest [-m mode] [-c command]\n", error ? stderr : stdout); exit(error); } int main(int argc, char *argv[]) { struct LRMI_regs r; short int *mode_list; int i, mode = -1; #if defined(__NetBSD__) || defined(__OpenBSD__) unsigned long iomap[32]; #endif for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-c") == 0) { i++; if (i == argc) usage_and_quit(1); run_command = argv[i]; } else if (strcmp(argv[i], "-m") == 0) { char *e; i++; if (i == argc) usage_and_quit(1); mode = strtol(argv[i], &e, 10); if (e == argv[i]) usage_and_quit(1); } else usage_and_quit(1); } if (!LRMI_init()) return 1; vbe.info = LRMI_alloc_real(sizeof(struct vbe_info_block) + sizeof(struct vbe_mode_info_block)); if (vbe.info == NULL) { fprintf(stderr, "Can't alloc real mode memory\n"); return 1; } vbe.mode = (struct vbe_mode_info_block *)(vbe.info + 1); #if 0 /* Allow read/write to video IO ports */ ioperm(0x2b0, 0x2df - 0x2b0, 1); ioperm(0x3b0, 0x3df - 0x3b0, 1); #else /* Allow read/write to ALL io ports */ #if defined(__linux__) ioperm(0, 1024, 1); iopl(3); #elif defined(__NetBSD__) || defined(__OpenBSD__) memset(&iomap[0], 0xff, sizeof(iomap)); i386_set_ioperm(iomap); i386_iopl(3); #elif defined(__FreeBSD__) i386_set_ioperm(0, 0x10000, 1); #endif #endif memset(&r, 0, sizeof(r)); r.eax = 0x4f00; r.es = (unsigned int)vbe.info >> 4; r.edi = 0; memcpy(vbe.info->vbe_signature, "VBE2", 4); if (!LRMI_int(0x10, &r)) { fprintf(stderr, "Can't get VESA info (vm86 failure)\n"); return 1; } if ((r.eax & 0xffff) != 0x4f || strncmp(vbe.info->vbe_signature, "VESA", 4) != 0) { fprintf(stderr, "No VESA bios\n"); return 1; } printf("VBE Version %x.%x\n", (int)(vbe.info->vbe_version >> 8) & 0xff, (int)vbe.info->vbe_version & 0xff); printf("%s\n", (char *)(vbe.info->oem_string_seg * 16 + vbe.info->oem_string_off)); mode_list = (short int *)(vbe.info->video_mode_list_seg * 16 + vbe.info->video_mode_list_off); while (*mode_list != -1) { memset(&r, 0, sizeof(r)); r.eax = 0x4f01; r.ecx = *mode_list; r.es = (unsigned int)vbe.mode >> 4; r.edi = (unsigned int)vbe.mode & 0xf; if (!LRMI_int(0x10, &r)) { fprintf(stderr, "Can't get mode info (vm86 failure)\n"); return 1; } if (vbe.mode->memory_model == VBE_MODEL_RGB) printf("[%3d] %dx%d (%d:%d:%d)\n", *mode_list, vbe.mode->x_resolution, vbe.mode->y_resolution, vbe.mode->red_mask_size, vbe.mode->green_mask_size, vbe.mode->blue_mask_size); else if (vbe.mode->memory_model == VBE_MODEL_256) printf("[%3d] %dx%d (256 color palette)\n", *mode_list, vbe.mode->x_resolution, vbe.mode->y_resolution); else if (vbe.mode->memory_model == VBE_MODEL_PACKED) printf("[%3d] %dx%d (%d color palette)\n", *mode_list, vbe.mode->x_resolution, vbe.mode->y_resolution, 1 << vbe.mode->bits_per_pixel); mode_list++; } LRMI_free_real(vbe.info); interactive_set_mode(mode); return 0; }