diff -u --new-file --recursive v1.1.8/linux/CREDITS linux/CREDITS
--- v1.1.8/linux/CREDITS	Tue Apr 19 10:52:42 1994
+++ linux/CREDITS	Mon Apr 25 10:09:56 1994
@@ -614,9 +614,10 @@
 S: USA
 
 N: Eric Youngdale
+E: ericy@cais.com
 E: eric@tantalus.nrl.navy.mil
 D: General kernel hacker
-D: SCSI iso9660 and ELF
+D: SCSI, iso9660, ELF, ibcs2, clustering in buffer cache, generalized mmap.
 S: 17 Canterbury Square #101
 S: Alexandria, Virginia 22304
 S: USA
diff -u --new-file --recursive v1.1.8/linux/Makefile linux/Makefile
--- v1.1.8/linux/Makefile	Mon Apr 25 10:04:31 1994
+++ linux/Makefile	Mon Apr 25 10:10:18 1994
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 8
+SUBLEVEL = 9
 
 all:	Version zImage
 
diff -u --new-file --recursive v1.1.8/linux/drivers/block/sbpcd.c linux/drivers/block/sbpcd.c
--- v1.1.8/linux/drivers/block/sbpcd.c	Tue Apr 19 10:52:14 1994
+++ linux/drivers/block/sbpcd.c	Mon Apr 25 10:20:02 1994
@@ -5,7 +5,7 @@
  *            and for "no-sound" interfaces like Lasermate and the
  *            Panasonic CI-101P.
  *
- *  NOTE:     This is release 1.4.
+ *  NOTE:     This is release 1.5.
  *            It works with my SbPro & drive CR-521 V2.11 from 2/92
  *            and with the new CR-562-B V0.75 on a "naked" Panasonic
  *            CI-101P interface. And vice versa. 
@@ -72,6 +72,10 @@
  *       Added some debugging printout for the UPC/EAN code - but my drives 
  *       return only zeroes. Is there no UPC/EAN code written?
  *
+ *  1.5  Laborate with UPC/EAN code (not better yet).
+ *       Adapt to kernel 1.1.8 change (have to explicitely include
+ *       <linux/string.h> now).
+ *
  *     special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine
  *     elaborated speed-up experiments (and the fabulous results!), for
  *     the "push" towards load-free wait loops, and for the extensive mail
@@ -113,6 +117,7 @@
 #include <linux/cdrom.h>
 #include <linux/ioport.h>
 #include <linux/sbpcd.h>
+#include <linux/string.h>
 
 #if SBPCD_USE_IRQ
 #include <linux/signal.h>
@@ -129,7 +134,7 @@
 #define MAJOR_NR MATSUSHITA_CDROM_MAJOR
 #include "blk.h"
 
-#define VERSION "1.4 Eberhard Moenkeberg <emoenke@gwdg.de>"
+#define VERSION "1.5 Eberhard Moenkeberg <emoenke@gwdg.de>"
 
 #define SBPCD_DEBUG
 
@@ -149,6 +154,8 @@
 #undef XA_TEST1
 #define XA_TEST2
 
+#define TEST_UPC 0
+
 /*==========================================================================*/
 /*==========================================================================*/
 
@@ -238,6 +245,7 @@
  * (1<<DBG_UPC)  show UPC info
  * (1<<DBG_XA)   XA mode debugging
  * (1<<DBG_LCK)  door (un)lock info
+ * (1<<DBG_SQ)   dump SubQ frame
  * (1<<DBG_000)  unnecessary information
  */
 #if 1
@@ -249,6 +257,7 @@
                           (1<<DBG_IOC) |
                           (1<<DBG_XA)  |
                           (1<<DBG_LCK) |
+                          (1<<DBG_SQ)  |
                           (1<<DBG_IOX);
 #endif
 static int sbpcd_ioaddr = CDROM_PORT;	/* default I/O base address */
@@ -287,7 +296,8 @@
 static u_char cmd_type=0;
 static u_char drvcmd[7];
 static u_char infobuf[20];
-static u_char scratch_buf[CD_XA_TAIL];
+static u_char xa_head_buf[CD_XA_HEAD];
+static u_char xa_tail_buf[CD_XA_TAIL];
 
 static u_char timed_out=0;
 static u_int datarate= 1000000;
@@ -354,7 +364,6 @@
   u_char vol_ctrl3;
 #endif 000
   
-  u_char SubQ_audio;
   u_char SubQ_ctl_adr;
   u_char SubQ_trk;
   u_char SubQ_pnt_idx;
@@ -1153,33 +1162,38 @@
   int i,j;
 
   DS[d].diskstate_flags &= ~subq_bit;
-  clr_cmdbuf();
-  if (new_drive)
-    {
-      drvcmd[0]=0x87;
-      flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-      response_count=11;
-    }
-  else
-    {
-      drvcmd[0]=0x89;
-      drvcmd[1]=0x02;
-      flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-      response_count=13;
-    }
-  for (j=0;j<255;j++)
+  for (j=255;j>0;j--)
     {
+      clr_cmdbuf();
+      if (new_drive)
+	{
+	  drvcmd[0]=0x87;
+	  flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+	  response_count=11;
+	}
+      else
+	{
+	  drvcmd[0]=0x89;
+	  drvcmd[1]=0x02;
+	  flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
+	  response_count=13;
+	}
       i=cmd_out();
       if (i<0) return (i);
+      DPRINTF((DBG_SQ,"SBPCD: xx_ReadSubQ:"));
+      for (i=0;i<(new_drive?11:13);i++)
+	{
+	  DPRINTF((DBG_SQ," %02X", infobuf[i]));
+	}
+      DPRINTF((DBG_SQ,"\n"));
       if (infobuf[0]!=0) break;
-      if (!st_spinning)
+      if ((!st_spinning) || (j==1))
 	{
 	  DS[d].SubQ_ctl_adr=DS[d].SubQ_trk=DS[d].SubQ_pnt_idx=DS[d].SubQ_whatisthis=0;
 	  DS[d].SubQ_run_tot=DS[d].SubQ_run_trk=0;
 	  return (0);
 	}
     }
-  DS[d].SubQ_audio=infobuf[0];
   DS[d].SubQ_ctl_adr=swap_nibbles(infobuf[1]);
   DS[d].SubQ_trk=byt2bcd(infobuf[2]);
   DS[d].SubQ_pnt_idx=byt2bcd(infobuf[3]);
@@ -1479,37 +1493,62 @@
 static int xx_ReadUPC(void)
 {
   int i;
+#if TEST_UPC
+  int block, checksum;
+#endif TEST_UPC
 
   DS[d].diskstate_flags &= ~upc_bit;
-  clr_cmdbuf();
-  if (new_drive)
-    {
-      drvcmd[0]=0x88;
-      response_count=8;
-      flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-    }
-  else
-    {
-      drvcmd[0]=0x08;
-      response_count=0;
-      flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
-    }
-  i=cmd_out();
-  if (i<0) return (i);
-  if (!new_drive)
+#if TEST_UPC
+  for (block=CD_BLOCK_OFFSET+1;block<CD_BLOCK_OFFSET+200;block++)
     {
-      response_count=16;
-      i=xx_ReadPacket();
+#endif TEST_UPC
+      clr_cmdbuf();
+      if (new_drive)
+	{
+	  drvcmd[0]=0x88;
+#if TEST_UPC
+	  drvcmd[1]=(block>>16)&0xFF;
+	  drvcmd[2]=(block>>8)&0xFF;
+	  drvcmd[3]=block&0xFF;
+#endif TEST_UPC
+	  response_count=8;
+	  flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+	}
+      else
+	{
+	  drvcmd[0]=0x08;
+#if TEST_UPC
+	  drvcmd[2]=(block>>16)&0xFF;
+	  drvcmd[3]=(block>>8)&0xFF;
+	  drvcmd[4]=block&0xFF;
+#endif TEST_UPC
+	  response_count=0;
+	  flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
+	}
+      i=cmd_out();
       if (i<0) return (i);
-    }
-
-  DPRINTF((DBG_UPC,"SBPCD: UPC info: "));
-  for (i=0;i<(new_drive?8:16);i++)
-    {
-      DPRINTF((DBG_UPC,"%02X ", infobuf[i]));
+      if (!new_drive)
+	{
+	  response_count=16;
+	  i=xx_ReadPacket();
+	  if (i<0) return (i);
+	}
+#if TEST_UPC
+      checksum=0;
+#endif TEST_UPC
+      DPRINTF((DBG_UPC,"SBPCD: UPC info: "));
+      for (i=0;i<(new_drive?8:16);i++)
+	{
+#if TEST_UPC
+	  checksum |= infobuf[i];
+#endif TEST_UPC
+	  DPRINTF((DBG_UPC,"%02X ", infobuf[i]));
+	}
+      DPRINTF((DBG_UPC,"\n"));
+#if TEST_UPC
+      if ((checksum&0x7F)!=0) break;
     }
-  DPRINTF((DBG_UPC,"\n"));
-
+#endif TEST_UPC
   DS[d].UPC_ctl_adr=0;
   if (new_drive) i=0;
   else i=2;
@@ -1559,6 +1598,31 @@
   return (0);
 }
 /*==========================================================================*/
+#if FUTURE
+static int yy_SubChanInfo(int frame, int count, u_char *buffer)
+/* "frame" is a RED BOOK address */
+{
+  int i;
+
+  if (!new_drive) return (-3);
+#if 0
+  if (DS[d].audio_state!=audio_playing) return (-2);
+#endif
+  clr_cmdbuf();
+  drvcmd[0]=0x11;
+  drvcmd[1]=(frame>>16)&0xFF;
+  drvcmd[2]=(frame>>8)&0xFF;
+  drvcmd[3]=frame&0xFF;
+  drvcmd[5]=(count>>8)&0xFF;
+  drvcmd[6]=count&0xFF;
+  flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
+  cmd_type=READ_SC;
+  DS[d].frame_size=CD_FRAMESIZE_SUB;
+  i=cmd_out(); /* read directly into user's buffer */
+  return (i);
+}
+#endif FUTURE
+/*==========================================================================*/
 static void check_datarate(void)
 {
 #ifdef CDMKE
@@ -2290,9 +2354,6 @@
       st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl));
       if (st)	return (st);
       memcpy_fromfs(&SC, (void *) arg, sizeof(struct cdrom_subchnl));
-#if 0
-      if (DS[d].SubQ_audio==0x80) DS[d].SubQ_audio=CDROM_AUDIO_NO_STATUS;
-#endif
       switch (DS[d].audio_state)
 	{
 	case audio_playing:
@@ -2634,7 +2695,7 @@
   u_int data_waits = 0;
   u_int data_retrying = 0;
   int error_flag;
-
+  int xa_count;
   error_flag=0;
 
   for (frame=DS[d].sbp_current;frame<DS[d].sbp_read_frames&&!error_flag; frame++)
@@ -2687,12 +2748,18 @@
       p = DS[d].sbp_buf + frame *  CD_FRAMESIZE;
 
       if (sbpro_type) OUT(CDo_sel_d_i,0x01);
-      if (cmd_type==READ_M2) READ_DATA(CDi_data, scratch_buf, CD_XA_HEAD);
+      if (cmd_type==READ_M2) READ_DATA(CDi_data, xa_head_buf, CD_XA_HEAD);
       READ_DATA(CDi_data, p, CD_FRAMESIZE);
-      if (cmd_type==READ_M2) READ_DATA(CDi_data, scratch_buf, CD_XA_TAIL);
+      if (cmd_type==READ_M2) READ_DATA(CDi_data, xa_tail_buf, CD_XA_TAIL);
       if (sbpro_type) OUT(CDo_sel_d_i,0x00);
       DS[d].sbp_current++;
-
+      if (cmd_type==READ_M2)
+	{
+	  DPRINTF((DBG_XA,"SBPCD: xa_head:"));
+	  for (xa_count=0;xa_count<CD_XA_HEAD;xa_count++)
+	    DPRINTF((DBG_XA," %02X", xa_head_buf[xa_count]));
+	  DPRINTF((DBG_XA,"\n"));
+	}
       data_tries++;
       data_retrying = 0;
       if (data_tries >= 1000)
diff -u --new-file --recursive v1.1.8/linux/drivers/net/slhc.c linux/drivers/net/slhc.c
--- v1.1.8/linux/drivers/net/slhc.c	Tue Apr 19 10:53:45 1994
+++ linux/drivers/net/slhc.c	Mon Apr 25 11:00:35 1994
@@ -73,7 +73,7 @@
 
 int last_retran;
 
-static unsigned char *encode(unsigned char *cp,int n);
+static unsigned char *encode(unsigned char *cp, unsigned short n);
 static long decode(unsigned char **cpp);
 static unsigned char * put16(unsigned char *cp, unsigned short x);
 static unsigned short pull16(unsigned char **cpp);
@@ -160,7 +160,7 @@
 
 
 /* Put a short in host order into a char array in network order */
-static unsigned char *
+static inline unsigned char *
 put16(unsigned char *cp, unsigned short x)
 {
 	*cp++ = x >> 8;
@@ -172,7 +172,7 @@
 
 /* Encode a number */
 unsigned char *
-encode(unsigned char *cp, int n)
+encode(unsigned char *cp, unsigned short n)
 {
 	if(n >= 256 || n == 0){
 		*cp++ = 0;
diff -u --new-file --recursive v1.1.8/linux/fs/buffer.c linux/fs/buffer.c
--- v1.1.8/linux/fs/buffer.c	Mon Apr 25 10:04:33 1994
+++ linux/fs/buffer.c	Mon Apr 25 21:27:48 1994
@@ -15,11 +15,8 @@
  * disk change. This is where it fits best, I think, as it should
  * invalidate changed floppy-disk-caches.
  */
-
-#include <stdarg.h>
  
 #include <linux/config.h>
-#include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
@@ -195,7 +192,7 @@
 			 if (wait && bh->b_req && !bh->b_lock &&
 			     !bh->b_dirt && !bh->b_uptodate) {
 				  err = 1;
-				  printk("Weird - unlocked, clean and not uptodate buffer on list %d\n", nlist);
+				  printk("Weird - unlocked, clean and not uptodate buffer on list %d %x %lu\n", nlist, bh->b_dev, bh->b_blocknr);
 				  continue;
 			  }
 			 /* Don't write clean buffers.  Don't write ANY buffers
@@ -1867,7 +1864,7 @@
 		 repeat:
 			 bh = lru_list[nlist];
 			 if(bh) 
-				  for (i = nr_buffers_type[nlist]; --i > 0 && ndirty < bdf_prm.b_un.ndirty; 
+				  for (i = nr_buffers_type[nlist]; i-- > 0 && ndirty < bdf_prm.b_un.ndirty; 
 				       bh = next) {
 					  /* We may have stalled while waiting for I/O to complete. */
 					  if(bh->b_list != nlist) goto repeat;
@@ -1909,8 +1906,10 @@
 		
 		if(nr_buffers_type[BUF_DIRTY] < (nr_buffers - nr_buffers_type[BUF_SHARED]) * 
 		   bdf_prm.b_un.nfract/100) {
-		   	if (current->signal & (1 << (SIGKILL-1)))
+		   	if (current->signal & (1 << (SIGKILL-1))) {
+				bdflush_running--;
 		   		return 0;
+			}
 		   	current->signal = 0;
 			interruptible_sleep_on(&bdflush_wait);
 		}
diff -u --new-file --recursive v1.1.8/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v1.1.8/linux/fs/isofs/inode.c	Tue Apr 19 10:52:57 1994
+++ linux/fs/isofs/inode.c	Mon Apr 25 10:09:55 1994
@@ -477,6 +477,15 @@
 	brelse(bh);
 	
 	inode->i_op = NULL;
+
+	/* A volume number of 0 is nonsense.  Disable checking if we see
+	   this */
+	if (inode->i_sb->u.isofs_sb.s_cruft == 'n' && 
+	    isonum_723 (raw_inode->volume_sequence_number) == 0) {
+	  printk("Warning: defective cdrom.  Enabling \"cruft\" mount option.\n");
+	  inode->i_sb->u.isofs_sb.s_cruft = 'y';
+	}
+
 	if (inode->i_sb->u.isofs_sb.s_cruft != 'y' && 
 	    isonum_723 (raw_inode->volume_sequence_number) != 1) {
 		printk("Multi volume CD somehow got mounted.\n");
diff -u --new-file --recursive v1.1.8/linux/include/linux/sbpcd.h linux/include/linux/sbpcd.h
--- v1.1.8/linux/include/linux/sbpcd.h	Tue Apr 19 10:52:15 1994
+++ linux/include/linux/sbpcd.h	Mon Apr 25 10:19:26 1994
@@ -74,7 +74,8 @@
 #define DBG_UPC		21	/* show UPC information */
 #define DBG_XA 		22	/* XA mode debugging */
 #define DBG_LCK		23	/* door (un)lock info */
-#define DBG_000		24	/* unnecessary information */
+#define DBG_SQ 		24	/* dump SubQ frame */
+#define DBG_000		25	/* unnecessary information */
 
 /*==========================================================================*/
 /*==========================================================================*/
@@ -215,6 +216,7 @@
 #define CD_FRAMESIZE            2048  /* bytes per frame, data mode      */
 #define CD_FRAMESIZE_XA         2340  /* bytes per frame, "xa" mode      */
 #define CD_FRAMESIZE_RAW        2352  /* bytes per frame, "raw" mode     */
+#define CD_FRAMESIZE_SUB          96  /* subchannel data size            */
 #define CD_BLOCK_OFFSET          150  /* offset of first logical frame   */
 #define CD_XA_HEAD                12  /* header size of XA frame         */
 #define CD_XA_TAIL               280  /* tail size of XA frame           */
diff -u --new-file --recursive v1.1.8/linux/include/linux/sched.h linux/include/linux/sched.h
--- v1.1.8/linux/include/linux/sched.h	Mon Apr 25 10:04:35 1994
+++ linux/include/linux/sched.h	Mon Apr 25 11:26:58 1994
@@ -219,8 +219,10 @@
 	unsigned short used_math;
 	unsigned short rss;	/* number of resident pages */
 	char comm[16];
+/* virtual 86 mode stuff */
 	struct vm86_struct * vm86_info;
 	unsigned long screen_bitmap;
+	unsigned long v86flags, v86mask, v86mode;
 /* file system info */
 	int link_count;
 	int tty;		/* -1 if no tty, so it must be signed */
@@ -286,7 +288,7 @@
 /* math */	0, \
 /* rss */	2, \
 /* comm */	"swapper", \
-/* vm86_info */	NULL, 0, \
+/* vm86_info */	NULL, 0, 0, 0, 0, \
 /* fs info */	0,-1,0022,NULL,NULL,NULL,NULL, \
 /* ipc */	NULL, NULL, \
 /* filp */	{NULL,}, \
diff -u --new-file --recursive v1.1.8/linux/include/linux/vm86.h linux/include/linux/vm86.h
--- v1.1.8/linux/include/linux/vm86.h	Mon Apr 25 10:04:35 1994
+++ linux/include/linux/vm86.h	Mon Apr 25 21:27:48 1994
@@ -1,18 +1,46 @@
 #ifndef _LINUX_VM86_H
 #define _LINUX_VM86_H
 
+/*
+ * I'm guessing at the VIF/VIP flag usage, but hope that this is how
+ * the Pentium uses them. Linux will return from vm86 mode when both
+ * VIF and VIP is set.
+ *
+ * On a Pentium, we could probably optimize the virtual flags directly
+ * in the eflags register instead of doing it "by hand" in vflags...
+ *
+ * Linus
+ */
+
 #define TF_MASK		0x00000100
 #define IF_MASK		0x00000200
 #define IOPL_MASK	0x00003000
 #define NT_MASK		0x00004000
 #define VM_MASK		0x00020000
 #define AC_MASK		0x00040000
+#define VIF_MASK	0x00080000	/* virtual interrupt flag */
+#define VIP_MASK	0x00100000	/* virtual interrupt pending */
+#define ID_MASK		0x00200000
 
 #define BIOSSEG		0x0f000
 
+#define CPU_086		0
+#define CPU_186		1
 #define CPU_286		2
 #define CPU_386		3
 #define CPU_486		4
+#define CPU_586		5
+
+/*
+ * Return values for the 'vm86()' system call
+ */
+#define VM86_TYPE(retval)	((retval) & 0xff)
+#define VM86_ARG(retval)	((retval) >> 8)
+
+#define VM86_SIGNAL	0	/* return due to signal */
+#define VM86_UNKNOWN	1	/* unhandled GP fault - IO-instruction or similar */
+#define VM86_INTx	2	/* int3/int x instruction (ARG = x) */
+#define VM86_STI	3	/* sti/popfl instruction enabled virtual interrupts */
 
 /*
  * This is the stack-layout when we have done a "SAVE_ALL" from vm86
@@ -53,25 +81,35 @@
 	unsigned short gs, __gsh;
 };
 
+struct revectored_struct {
+	unsigned long __map[8];			/* 256 bits */
+};
+
 struct vm86_struct {
 	struct vm86_regs regs;
 	unsigned long flags;
 	unsigned long screen_bitmap;
-	unsigned long v_eflags;
 	unsigned long cpu_type;
-	unsigned long return_if_iflag;
-	unsigned char int_revectored[0x100];
-	unsigned char int21_revectored[0x100];
+	struct revectored_struct int_revectored;
+	struct revectored_struct int21_revectored;
 };
 
 /*
  * flags masks
  */
-#define VM86_SCREEN_BITMAP 1
+#define VM86_SCREEN_BITMAP	0x0001
 
 #ifdef __KERNEL__
 
 void handle_vm86_fault(struct vm86_regs *, long);
+
+extern inline int is_revectored(int nr, struct revectored_struct * bitmap)
+{
+	__asm__ __volatile__("btl %2,%%fs:%1\n\tsbbl %0,%0"
+		:"=r" (nr)
+		:"m" (*bitmap),"r" (nr));
+	return nr;
+}
 
 #endif
 
diff -u --new-file --recursive v1.1.8/linux/kernel/vm86.c linux/kernel/vm86.c
--- v1.1.8/linux/kernel/vm86.c	Mon Apr 25 10:04:37 1994
+++ linux/kernel/vm86.c	Mon Apr 25 21:27:48 1994
@@ -13,20 +13,37 @@
 #include <asm/segment.h>
 #include <asm/io.h>
 
+/*
+ * 16-bit register defines..
+ */
+#define IP(regs)	(*(unsigned short *)&((regs)->eip))
+#define SP(regs)	(*(unsigned short *)&((regs)->esp))
+
+/*
+ * virtual flags (16 and 32-bit versions)
+ */
+#define VFLAGS(regs)	(*(unsigned short *)&(current->v86flags))
+#define VEFLAGS(regs)	(current->v86flags)
+
+#define set_flags(X,new,mask) \
+((X) = ((X) & ~(mask)) | ((new) & (mask)))
+
+#define SAFE_MASK	(0xDD5)
+
 asmlinkage struct pt_regs * save_v86_state(struct vm86_regs * regs)
 {
-	unsigned long stack;
+	unsigned long tmp;
 
 	if (!current->vm86_info) {
 		printk("no vm86_info: BAD\n");
 		do_exit(SIGSEGV);
 	}
-	memcpy_tofs(&(current->vm86_info->regs),regs,sizeof(*regs));
-	put_fs_long(current->screen_bitmap,&(current->vm86_info->screen_bitmap));
-	stack = current->tss.esp0;
+	memcpy_tofs(&current->vm86_info->regs,regs,sizeof(*regs));
+	put_fs_long(current->screen_bitmap,&current->vm86_info->screen_bitmap);
+	tmp = current->tss.esp0;
 	current->tss.esp0 = current->saved_kernel_stack;
 	current->saved_kernel_stack = 0;
-	return (struct pt_regs *) stack;
+	return (struct pt_regs *) tmp;
 }
 
 static void mark_screen_rdonly(struct task_struct * tsk)
@@ -74,20 +91,41 @@
  * has set it up safely, so this makes sure interrupt etc flags are
  * inherited from protected mode.
  */
-	info.regs.eflags &= 0x00000dd5;
-	info.regs.eflags |= ~0x00000dd5 & pt_regs->eflags;
+ 	current->v86flags = info.regs.eflags;
+	info.regs.eflags &= SAFE_MASK;
+	info.regs.eflags |= ~SAFE_MASK & pt_regs->eflags;
 	info.regs.eflags |= VM_MASK;
+
+	switch (info.cpu_type) {
+		case CPU_286:
+			current->v86mask = 0;
+			break;
+		case CPU_386:
+			current->v86mask = NT_MASK | IOPL_MASK;
+			break;
+		case CPU_486:
+			current->v86mask = AC_MASK | NT_MASK | IOPL_MASK;
+			break;
+		default:
+			current->v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
+			break;
+	}
+
+/*
+ * Save old state, set default return value (%eax) to 0
+ */
+	pt_regs->eax = 0;
 	current->saved_kernel_stack = current->tss.esp0;
 	current->tss.esp0 = (unsigned long) pt_regs;
 	current->vm86_info = v86;
+
 	current->screen_bitmap = info.screen_bitmap;
 	if (info.flags & VM86_SCREEN_BITMAP)
 		mark_screen_rdonly(current);
 	__asm__ __volatile__("movl %0,%%esp\n\t"
-		"pushl $ret_from_sys_call\n\t"
-		"ret"
+		"jmp ret_from_sys_call"
 		: /* no outputs */
-		:"g" ((long) &(info.regs)),"a" (info.regs.eax));
+		:"r" (&info.regs));
 	return 0;
 }
 
@@ -97,131 +135,226 @@
 
 	regs32 = save_v86_state(regs16);
 	regs32->eax = retval;
-	__asm__("movl %0,%%esp\n\t"
+	__asm__ __volatile__("movl %0,%%esp\n\t"
 		"jmp ret_from_sys_call"
 		: : "r" (regs32));
 }
 
+static inline void set_IF(struct vm86_regs * regs)
+{
+	current->v86flags |= VIF_MASK;
+	if (current->v86flags & VIP_MASK)
+		return_to_32bit(regs, VM86_STI);
+}
+
+static inline void clear_IF(struct vm86_regs * regs)
+{
+	current->v86flags &= ~VIF_MASK;
+}
+
+static inline void clear_TF(struct vm86_regs * regs)
+{
+	regs->eflags &= ~TF_MASK;
+}
+
+static inline void set_vflags_long(unsigned long eflags, struct vm86_regs * regs)
+{
+	set_flags(VEFLAGS(regs), eflags, current->v86mask);
+	set_flags(regs->eflags, eflags, SAFE_MASK);
+	if (eflags & IF_MASK)
+		set_IF(regs);
+}
+
+static inline void set_vflags_short(unsigned short flags, struct vm86_regs * regs)
+{
+	set_flags(VFLAGS(regs), flags, current->v86mask);
+	set_flags(regs->eflags, flags, SAFE_MASK);
+	if (flags & IF_MASK)
+		set_IF(regs);
+}
+
+static inline unsigned long get_vflags(struct vm86_regs * regs)
+{
+	unsigned long flags = regs->eflags & SAFE_MASK;
+
+	if (current->v86flags & VIF_MASK)
+		flags |= IF_MASK;
+	return flags | (VEFLAGS(regs) & current->v86mask);
+}
+
+/*
+ * Boy are these ugly, but we need to do the correct 16-bit arithmetic.
+ * Gcc makes a mess of it, so we do it inline and use non-obvious calling
+ * conventions..
+ */
+#define pushb(base, ptr, val) \
+__asm__ __volatile__( \
+	"decw %w0\n\t" \
+	"movb %2,%%fs:0(%1,%0)" \
+	: "=r" (ptr) \
+	: "r" (base), "q" (val), "0" (ptr))
+
+#define pushw(base, ptr, val) \
+__asm__ __volatile__( \
+	"decw %w0\n\t" \
+	"movb %h2,%%fs:0(%1,%0)\n\t" \
+	"decw %w0\n\t" \
+	"movb %b2,%%fs:0(%1,%0)" \
+	: "=r" (ptr) \
+	: "r" (base), "q" (val), "0" (ptr))
+
+#define pushl(base, ptr, val) \
+__asm__ __volatile__( \
+	"decw %w0\n\t" \
+	"rorl $16,%2\n\t" \
+	"movb %h2,%%fs:0(%1,%0)\n\t" \
+	"decw %w0\n\t" \
+	"movb %b2,%%fs:0(%1,%0)\n\t" \
+	"decw %w0\n\t" \
+	"rorl $16,%2\n\t" \
+	"movb %h2,%%fs:0(%1,%0)\n\t" \
+	"decw %w0\n\t" \
+	"movb %b2,%%fs:0(%1,%0)" \
+	: "=r" (ptr) \
+	: "r" (base), "q" (val), "0" (ptr))
+
+#define popb(base, ptr) \
+({ unsigned long __res; \
+__asm__ __volatile__( \
+	"movb %%fs:0(%1,%0),%b2\n\t" \
+	"incw %w0" \
+	: "=r" (ptr), "=r" (base), "=r" (__res) \
+	: "0" (ptr), "1" (base), "2" (0)); \
+__res; })
+
+#define popw(base, ptr) \
+({ unsigned long __res; \
+__asm__ __volatile__( \
+	"movb %%fs:0(%1,%0),%b2\n\t" \
+	"incw %w0\n\t" \
+	"movb %%fs:0(%1,%0),%h2\n\t" \
+	"incw %w0" \
+	: "=r" (ptr), "=r" (base), "=r" (__res) \
+	: "0" (ptr), "1" (base), "2" (0)); \
+__res; })
+
+#define popl(base, ptr) \
+({ unsigned long __res; \
+__asm__ __volatile__( \
+	"movb %%fs:0(%1,%0),%b2\n\t" \
+	"incw %w0\n\t" \
+	"movb %%fs:0(%1,%0),%h2\n\t" \
+	"incw %w0\n\t" \
+	"rorl $16,%2\n\t" \
+	"movb %%fs:0(%1,%0),%b2\n\t" \
+	"incw %w0\n\t" \
+	"movb %%fs:0(%1,%0),%h2\n\t" \
+	"incw %w0\n\t" \
+	"rorl $16,%2" \
+	: "=r" (ptr), "=r" (base), "=r" (__res) \
+	: "0" (ptr), "1" (base)); \
+__res; })
+
+static void do_int(struct vm86_regs *regs, int i, unsigned char * ssp, unsigned long sp)
+{
+	unsigned short seg = get_fs_word((void *) ((i<<2)+2));
+
+	if (seg == BIOSSEG || regs->cs == BIOSSEG ||
+	    is_revectored(i, &current->vm86_info->int_revectored))
+		return_to_32bit(regs, VM86_INTx + (i << 8));
+	if (i==0x21 && is_revectored((regs->eax >> 4) & 0xff,&current->vm86_info->int21_revectored)) {
+		return_to_32bit(regs, VM86_INTx + (i << 8));
+	}
+	pushw(ssp, sp, get_vflags(regs));
+	pushw(ssp, sp, regs->cs);
+	pushw(ssp, sp, IP(regs));
+	regs->cs = seg;
+	SP(regs) -= 6;
+	IP(regs) = get_fs_word((void *) (i<<2));
+	clear_TF(regs);
+	clear_IF(regs);
+	return;
+}
+
+
 void handle_vm86_fault(struct vm86_regs * regs, long error_code)
 {
-	unsigned char *csp;
-	unsigned short *ssp;
-	unsigned short flags;
-	unsigned char i;
+	unsigned char *csp, *ssp;
+	unsigned long ip, sp;
 
-	csp = (unsigned char *) ((regs->cs << 4) + (regs->eip & 0xffff));
-	ssp = (unsigned short *) ((regs->ss << 4) + (regs->esp & 0xffff));
+	csp = (unsigned char *) (regs->cs << 4);
+	ssp = (unsigned char *) (regs->ss << 4);
+	sp = SP(regs);
+	ip = IP(regs);
 
-	switch (get_fs_byte(csp)) {
+	switch (popb(csp, ip)) {
 
 	/* operand size override */
 	case 0x66:
-		switch (get_fs_byte(++csp)) {
+		switch (popb(csp, ip)) {
 
 		/* pushfd */
 		case 0x9c:
-			regs->esp -= 4;
-			regs->eip += 2;
-			if (get_fs_long(&(current->vm86_info->cpu_type)) == CPU_386)
-			  put_fs_long(((regs->eflags) & ~(AC_MASK|NT_MASK|IOPL_MASK|IF_MASK)) |
-				(get_fs_long(&(current->vm86_info->v_eflags)) & (NT_MASK|IOPL_MASK|IF_MASK)), ssp-2);
-			else
-			  put_fs_long(((regs->eflags) & ~(AC_MASK|NT_MASK|IOPL_MASK|IF_MASK)) |
-				(get_fs_long(&(current->vm86_info->v_eflags)) & (AC_MASK|NT_MASK|IOPL_MASK|IF_MASK)), ssp-2);
+			SP(regs) -= 4;
+			IP(regs) += 2;
+			pushl(ssp, sp, get_vflags(regs));
 			return;
 
 		/* popfd */
 		case 0x9d:
-			regs->esp += 4;
-			regs->eip += 2;
-			flags = get_fs_word(ssp+1);
-			put_fs_word(flags, (unsigned short *) &(current->vm86_info->v_eflags) +1);
-			goto return_from_popf;
+			SP(regs) += 4;
+			IP(regs) += 2;
+			set_vflags_long(popl(ssp, sp), regs);
+			return;
 		}
 
 	/* pushf */
 	case 0x9c:
-		regs->esp -= 2;
-		regs->eip++;
-		if (get_fs_long(&(current->vm86_info->cpu_type)) == CPU_286)
-		  put_fs_word(((regs->eflags) & 0x0dd5) |
-			(get_fs_word(&(current->vm86_info->v_eflags)) & ~0xfdd5), --ssp);
-		else
-		  put_fs_word(((regs->eflags) & ~(NT_MASK|IOPL_MASK|IF_MASK)) |
-			(get_fs_word(&(current->vm86_info->v_eflags)) & (NT_MASK|IOPL_MASK|IF_MASK)), --ssp);
+		SP(regs) -= 2;
+		IP(regs)++;
+		pushw(ssp, sp, get_vflags(regs));
 		return;
 
 	/* popf */
 	case 0x9d:
-		regs->esp += 2;
-		regs->eip++;
-	return_from_popf:
-		flags = get_fs_word(ssp);
-		regs->eflags &= ~0x00000dd5;
-		regs->eflags |= flags & 0x00000dd5;
-		put_fs_word(flags, &(current->vm86_info->v_eflags));
-		goto do_dosemu_timer;
+		SP(regs) += 2;
+		IP(regs)++;
+		set_vflags_short(popw(ssp, sp), regs);
+		return;
 
 	/* int 3 */
 	case 0xcc:
-		if (get_fs_word((void *)14) == BIOSSEG || regs->cs == BIOSSEG
-			|| get_fs_byte(&(current->vm86_info->int_revectored[3])))
-			return_to_32bit(regs, SIGSEGV);
-		i = 3;
-		regs->eip++;
-		goto return_from_int_xx;
+		IP(regs)++;
+		do_int(regs, 3, ssp, sp);
+		return;
 
 	/* int xx */
 	case 0xcd:
-		i = get_fs_byte(++csp);
-		if (get_fs_word((void *)((i<<2)+2)) == BIOSSEG
-			|| regs->cs == BIOSSEG
-			|| get_fs_byte(&(current->vm86_info->int_revectored[i])))
-			return_to_32bit(regs, SIGSEGV);
-		if ((i==0x21) && get_fs_byte(&(current->vm86_info->int21_revectored[((regs->eax >> 4) & 0xff)])))
-			return_to_32bit(regs, SIGSEGV);
-		regs->eip+=2;
-		return_from_int_xx:
-		regs->esp -= 6;
-		if (get_fs_long(&(current->vm86_info->cpu_type)) == CPU_286)
-		  put_fs_word(((regs->eflags) & 0x0dd5) |
-			(get_fs_word(&(current->vm86_info->v_eflags)) & ~0xfdd5), --ssp);
-		else
-		  put_fs_word(((regs->eflags) & ~IF_MASK) |
-			(get_fs_word(&(current->vm86_info->v_eflags)) & IF_MASK), --ssp);
-		put_fs_word(regs->cs, --ssp);
-		put_fs_word((unsigned short)(regs->eip), --ssp);
-		regs->cs = get_fs_word((void *)((i<<2)+2));
-		regs->eip = (unsigned long) get_fs_word((void *)(i<<2));
-		regs->eflags &= ~TF_MASK;
-		and_fs_long(~IF_MASK, &(current->vm86_info->v_eflags));
+		IP(regs) += 2;
+		do_int(regs, popb(csp, ip), ssp, sp);
 		return;
 
 	/* iret */
 	case 0xcf:
-		regs->esp += 6;
-		regs->eip = get_fs_word(ssp++);
-		regs->cs = get_fs_word(ssp++);
-		goto return_from_popf;
+		SP(regs) += 6;
+		IP(regs) = popw(ssp, sp);
+		regs->cs = popw(ssp, sp);
+		set_vflags_short(popw(ssp, sp), regs);
+		return;
 
 	/* cli */
 	case 0xfa:
-		regs->eip++;
-		and_fs_long(~IF_MASK, &(current->vm86_info->v_eflags));
+		IP(regs)++;
+		clear_IF(regs);
 		return;
 
 	/* sti */
 	case 0xfb:
-		regs->eip++;
-		or_fs_long(IF_MASK, &(current->vm86_info->v_eflags));
-	do_dosemu_timer:
-		if ((get_fs_long(&(current->vm86_info->v_eflags)) & IF_MASK) &&
-		    get_fs_long(&(current->vm86_info->return_if_iflag)))
-			break;
+		IP(regs)++;
+		set_IF(regs);
 		return;
 
 	default:
-		return_to_32bit(regs, SIGSEGV);
+		return_to_32bit(regs, VM86_UNKNOWN);
 	}
-	return_to_32bit(regs, SIGALRM);
 }
