summaryrefslogtreecommitdiffstats
path: root/perl-install/standalone/draknfs
Commit message (Expand)AuthorAgeFilesLines
* typo fixThierry Vignaud2005-09-181-1/+1
* fix draknfs bannerAntoine Ginies2005-09-161-1/+1
* our policy is not do display version number in taskbarThierry Vignaud2005-09-121-1/+1
* use Combo instaed of ComboBoxEntry to fiw 2 rows heigh bugAntoine Ginies2005-08-301-14/+19
* put comboxentry in a VBox (to avoid 2 rows bug in comboboxentry)Antoine Ginies2005-08-301-1/+3
* remove icon on all buttonsAntoine Ginies2005-08-301-3/+3
* in case of all_squash use anongid=65534 and anongid=65534Antoine Ginies2005-08-301-4/+13
* create dir if it does not existAntoine Ginies2005-08-291-1/+1
* use new iconsAntoine Ginies2005-08-271-2/+2
* various perl_checker fixAntoine Ginies2005-08-271-19/+16
* remove unused codeAntoine Ginies2005-08-271-2/+0
* fix bug #17255 (modify empty /etc/exports file)Antoine Ginies2005-08-081-0/+1
* fix User ID help (#17321)Antoine Ginies2005-08-081-4/+4
* corrected small typoPablo Saratxaga2005-07-271-1/+1
* no_all_squash as defaultAntoine Ginies2005-07-261-2/+1
* improve User id mapping, keep 4 options (no_all_squash is the defaultAntoine Ginies2005-07-221-47/+20
* remove duplicate entry in access listAntoine Ginies2005-07-221-4/+6
* show only users/group ID > 500, fix secure label.Antoine Ginies2005-07-211-2/+2
* fix phrasingThierry Vignaud2005-07-191-1/+1
* remove ipnet/32 in access_listAntoine Ginies2005-07-191-1/+1
* advanced help:Thierry Vignaud2005-07-181-17/+16
* (help_b) fix displaying help the second timeThierry Vignaud2005-07-181-5/+5
* make sub dialogs modal and transcient to their main windowThierry Vignaud2005-07-181-2/+6
* don't translate the empty stringOlivier Blin2005-07-151-1/+1
* add an entry in menu to write_confAntoine Ginies2005-07-121-2/+3
* add a popup with users and groups when using anonuid and anongid (FACORAT Fab...Antoine Ginies2005-07-121-6/+50
* move menu above banner, use expander to show/hide advanced options,Antoine Ginies2005-07-121-26/+37
* typo fixAntoine Ginies2005-07-121-2/+2
* add exit on ok buttonAntoine Ginies2005-07-121-0/+1
* ensure nfs-utils is installedAntoine Ginies2005-07-121-0/+1
* always display ok_cancel buttonAntoine Ginies2005-07-081-1/+1
* add a checkbox to enable/disable advanced optionsAntoine Ginies2005-07-081-0/+12
* various adjustement in main windowsAntoine Ginies2005-07-081-31/+35
* add an apply buttonAntoine Ginies2005-07-071-2/+6
* use simple userid combolist, few other fixAntoine Ginies2005-07-071-23/+49
* fix test of directory and test of hosts access in alter modeAntoine Ginies2005-07-061-4/+4
* add editcell (disable by default) , add double clic supportAntoine Ginies2005-07-061-0/+37
* display wait message box while reloading/restarting nfs serverAntoine Ginies2005-07-061-15/+9
* fix undefined optionsAntoine Ginies2005-07-061-4/+3
* fix domain in hosts access comboboxAntoine Ginies2005-07-061-3/+3
* fix ip/8 in comboboxentryAntoine Ginies2005-07-061-2/+5
* button to close draknfsAntoine Ginies2005-07-061-96/+222
* (add_columns) reuse existing translationThierry Vignaud2005-07-051-1/+1
* fix layout somewhatThierry Vignaud2005-07-051-3/+6
* don't keep undefined optionsOlivier Blin2005-07-051-1/+1
* use join()Olivier Blin2005-07-051-4/+2
* perl_checker/translation fixesOlivier Blin2005-07-051-15/+13
* various other fix to be able to build drakxtoolsAntoine Ginies2005-07-051-8/+9
* various fix ("standalone/draknfs", line 140, character 38-48) thx tvAntoine Ginies2005-07-051-6/+6
* add help, remove unwanted useAntoine Ginies2005-07-051-3/+14
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 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;
#if 1
	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;
	}