LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* i486 emu in mainline?
@ 2004-05-22 23:40 Christoph Hellwig
  2004-05-23  0:20 ` Rene Rebe
                   ` (4 more replies)
  0 siblings, 5 replies; 29+ messages in thread
From: Christoph Hellwig @ 2004-05-22 23:40 UTC (permalink / raw)
  To: akpm, willy; +Cc: linux-kernel

These days gcc uses i486+ only instruction by default in libstdc++ so
most modern distros wouldn't work on i386 cpus anymore.  To make it work
again Debian merged Willy Tarreau's patch to trap those and emulate them
on real i386 cpus.  The patch is extremely non-invasive and would
certainly be usefull for mainline.  Any reason not to include it?


--- kernel-source-2.6.6/arch/i386/Kconfig	2004-05-10 19:47:45.000000000 +1000
+++ kernel-source-2.6.6-1/arch/i386/Kconfig	2004-05-10 22:21:08.000000000 +1000
@@ -330,6 +330,41 @@
 	  This is really intended for distributors who need more
 	  generic optimizations.
 
+config X86_EMU486
+       bool "486 emulation"
+       help
+          When used on a 386, Linux can emulate 3 instructions from the 486
+          set.  This allows user space programs compiled for 486 to run on a
+          386 without crashing with a SIGILL. As any emulation, performance
+          will be very low, but since these instruction are not often used,
+          this might not hurt.  The emulated instructions are:
+             - bswap (does the same as htonl())
+             - cmpxchg (used in multi-threading, mutex locking)
+             - xadd (rarely used)
+
+          Note that this can also allow Step-A 486's to correctly run
+          multi-thread applications since cmpxchg has a wrong opcode on this
+          early CPU.
+
+          Don't use this to enable multi-threading on an SMP machine, the lock
+          atomicity can't be guaranted!
+
+          Although it's highly preferable that you only execute programs
+          targetted for your CPU, it may happen that, consecutively to a
+          hardware replacement, or during rescue of a damaged system, you have
+          to execute such programs on an inadapted processor.  In this case,
+          this option will help you get your programs working, even if they
+          will be slower.
+
+          It is recommended that you say N here in any case, except for the
+          kernels that you will use on your rescue disks.
+ 
+          This option should not be left on by default, because it means that
+          you execute a program not targetted for your CPU.  You should
+          recompile your applications whenever possible.
+
+          If you are not sure, say N.
+
 endif
 
 #
@@ -438,6 +473,7 @@
 
 config SMP
 	bool "Symmetric multi-processing support"
+	depends on !X86_EMU486
 	---help---
 	  This enables support for systems with more than one CPU. If you have
 	  a system with only one CPU, like most personal computers, say N. If
--- kernel-source-2.6.6/arch/i386/kernel/Makefile	2004-05-10 19:47:45.000000000 +1000
+++ kernel-source-2.6.6-1/arch/i386/kernel/Makefile	2004-05-10 22:21:08.000000000 +1000
@@ -28,6 +28,7 @@
 obj-$(CONFIG_MODULES)		+= module.o
 obj-y				+= sysenter.o vsyscall.o
 obj-$(CONFIG_ACPI_SRAT) 	+= srat.o
+obj-$(CONFIG_X86_EMU486)	+= emu.o
 obj-$(CONFIG_HPET_TIMER) 	+= time_hpet.o
 obj-$(CONFIG_EFI) 		+= efi.o efi_stub.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
--- kernel-source-2.6.6/arch/i386/kernel/emu.c	1970-01-01 10:00:00.000000000 +1000
+++ kernel-source-2.6.6-1/arch/i386/kernel/emu.c	2003-08-01 20:21:31.000000000 +1000
@@ -0,0 +1,434 @@
+/*
+ *  linux/arch/i386/emu.c
+ *
+ *  Copyright (C) 2002  Willy Tarreau
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/linkage.h>
+#include <linux/preempt.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+
+#include <asm/uaccess.h>
+#include <asm/segment.h>
+
+asmlinkage void do_general_protection(struct pt_regs *regs, long error_code);
+asmlinkage void do_invalid_op(struct pt_regs *regs, long error_code);
+
+/* gives the address of any register member in a struct pt_regs */
+static const int reg_ofs[8] = {
+	(int)&((struct pt_regs *)0)->eax,
+	(int)&((struct pt_regs *)0)->ecx,
+	(int)&((struct pt_regs *)0)->edx,
+	(int)&((struct pt_regs *)0)->ebx,
+	(int)&((struct pt_regs *)0)->esp,
+	(int)&((struct pt_regs *)0)->ebp,
+	(int)&((struct pt_regs *)0)->esi,
+	(int)&((struct pt_regs *)0)->edi
+};
+
+#define REG_PTR(regs, reg) ((unsigned long *)(((void *)(regs)) + reg_ofs[reg]))
+
+/* This code can be used to allow old 386's to hopefully correctly execute some
+ * code which was originally compiled for a 486, and to allow CMOV-disabled
+ * processors to emulate CMOV instructions. In user space, only 3 instructions
+ * have been added between the 386 the 486 :
+ *    - BSWAP reg		performs exactly htonl())
+ *    - CMPXCHG reg/mem, reg	used for mutex locking
+ *    - XADD reg/mem, reg	not encountered yet.
+ *
+ * Warning: this will NEVER allow a kernel compiled for a 486 to boot on a 386,
+ * neither will it allow a CMOV-optimized kernel to run on a processor without
+ * CMOV ! It will only help to port programs, or save you on a rescue disk, but
+ * for performance's sake, it's far better to recompile.
+ *
+ * Tests patterns have been submitted to this code on a 386, and it now seems
+ * OK. If you think you've found a bug, please report it to
+ * Willy Tarreau <willy@meta-x.org>.
+ */
+
+/* [modrm_address] returns a pointer to a user-space location by decoding the
+ * mod/rm byte and the bytes at <from>, which point to the mod/reg/rm byte.
+ * This must only be called if modrm indicates memory and not register. The
+ * <from> parameter is updated when bytes are read.
+ * NOTE: this code has some ugly lines, which produce a better assembler output
+ * than the "cleaner" version.
+ */
+static void *modrm_address(struct pt_regs *regs, u8 **from,
+                           int bit32, int modrm)
+{
+	u32 offset = 0;
+	u8 sib, mod, rm;
+
+	/* better optimization to compute them here, even
+	 * if rm is not always used
+	 */
+	rm = modrm & 7;
+	mod = modrm & 0xC0;
+
+	if (bit32) {  /* 32-bits addressing mode (default) */
+		if (mod == 0 && rm == 5) /* 32 bits offset and nothing more */
+			return (void *)*((u32*)*from)++;
+		
+		if (rm == 4) {
+			/* SIB byte is present and must be used */
+			sib = *(*from)++; /* SS(7-6) IDX(5-3) BASE(2-0) */
+
+			/* index * scale */
+			if (((sib >> 3) & 7) != 4)
+				offset += *REG_PTR(regs, (sib >> 3) & 7) << (sib >> 6);
+
+			rm = (sib & 7); /* base replaces rm from now */
+			if (mod == 0 && rm == 5) /* base off32 + scaled index */
+				return (void *)offset + *((u32*)*from)++;
+		}
+
+		/* base register */
+		offset += *REG_PTR(regs, rm);
+	
+		if (mod) {
+			if (mod & 0x80) /* 32 bits unsigned offset */
+				offset += *((u32*)*from)++;
+			else  /* 0x40: 8 bits signed offset */
+				offset += *((s8*)*from)++;
+		}
+
+		return (void *)offset;
+
+	} else { /* 16-bits addressing mode */
+		/* handle special case now */
+		if (mod == 0 && rm == 6) /* 16 bits offset */
+			return (void *)(u32)*((u16*)*from)++;
+
+		if ((rm & 4) == 0)
+			offset += (rm & 2) ? regs->ebp : regs->ebx;
+		if (rm < 6)
+			offset += (rm & 1) ? regs->edi : regs->esi;
+		else if (rm == 6)  /* bp */
+			offset += regs->ebp;
+		else if (rm == 7)  /* bx */
+			offset += regs->ebx;
+
+		/* now, let's include 8/16 bits offset */
+		if (mod) {
+			if (mod & 0x80) /* 16 bits unsigned offset */
+				offset += *((u16*)*from)++;
+			else  /* 0x40: 8 bits signed offset */
+				offset += *((s8*)*from)++;
+		}
+		return (void *)(offset & 0xFFFF);
+	}
+}
+
+
+/*
+ * skip_modrm() computes the EIP value of next instruction from the
+ * pointer <from> which points to the first byte after the mod/rm byte.
+ * Its purpose is to implement a fast alternative to modrm_address()
+ * when offset value is not needed.
+ */
+static inline void *skip_modrm(u8 *from, int bit32, int modrm)
+{
+    	u8 mod,rm;
+
+	/* better optimization to compute them here, even
+	 * if rm is not always used
+	 */
+	rm = modrm & 7;
+	mod = modrm & 0xC0;
+
+	/* most common case first : registers */
+	if (mod == 0xC0)
+		return from;
+
+	if (bit32) { /* 32 bits addressing mode (default) */
+		if (rm == 4)	/* SIB byte : rm becomes base */
+			rm = (*from++ & 7);
+		if (mod == 0x00) {
+			if (rm == 5)  /* 32 bits offset and nothing more */
+				return from + 4;
+			else
+				return from;
+		}
+	}
+	else { /* 16 bits mode */
+		if (mod == 0x00) {
+			if (rm == 6)  /* 16 bits offset and nothing more */
+				return from + 2;
+			else
+				return from;
+		}
+	}
+
+	if (mod & 0x80)
+		return from + (2 * (bit32 + 1)); /* + 2 or 4 bytes */
+	else
+		return from + 1;
+}
+
+
+/* [reg_address] returns a pointer to a register in the regs struct, depending
+ * on <w> (byte/word) and reg. Since the caller knows about <w>, it's
+ * responsible for understanding the result as a byte, word or dword pointer.
+ * Only the 3 lower bits of <reg> are meaningful, higher ones are ignored.
+ */
+static inline void *reg_address(struct pt_regs *regs, char w, u8 reg)
+{
+	if (w)
+		/* 16/32 bits mode */
+		return REG_PTR(regs, reg & 7);
+	else
+		/* 8 bits mode : al,cl,dl,bl,ah,ch,dh,bh */
+		return ((reg & 4) >> 2) + (u8*)REG_PTR(regs, reg & 3);
+
+	/* this is set just to prevent the compiler from complaining */
+	return NULL;
+}
+
+/* [do_emu] is called by exception 6 after an invalid opcode has been
+ * encountered. It will decode the prefixes and the instruction code, to try
+ * to emulate it, and will send a SIGILL or SIGSEGV to the process if not
+ * possible.
+ * REP/REPN prefixes are not supported anymore because it didn't make sense
+ * to emulate instructions prefixed with such opcodes since no arch-specific
+ * instruction start by one of them. At most, they will be the start of newer
+ * arch-specific instructions (SSE ?).
+ */
+asmlinkage void do_emu(struct pt_regs *regs, long error_code)
+{
+	enum {
+		PREFIX_ES   = 1,
+		PREFIX_CS   = 2,
+		PREFIX_SS   = 4,
+		PREFIX_DS   = 8,
+		PREFIX_FS   = 16,
+		PREFIX_GS   = 32,
+		PREFIX_SEG  = 63,  /* any seg */
+		PREFIX_D32  = 64,
+		PREFIX_A32  = 128,
+		PREFIX_LOCK = 256,
+	} prefixes = 0;
+
+	u32 *src, *dst;
+	u8 *eip;
+
+	preempt_disable();
+	eip = (u8*)regs->eip;
+
+#ifdef BENCH_CPU_EXCEPTION_BUT_NOT_THE_CODE
+	regs->eip += 3;
+	goto out;
+#endif
+	/* we'll first read all known opcode prefixes, and discard obviously
+	   invalid combinations.*/
+	while (1) {
+		/* prefix for CMOV, BSWAP, CMPXCHG, XADD */
+		if (*eip == 0x0F) {
+			eip++;
+
+			/* we'll verify if this is a BSWAP opcode, main source of SIGILL on 386's */
+			if ((*eip & 0xF8) == 0xC8) {  /* BSWAP */
+				u8 reg;
+
+				reg = *eip++ & 0x07;
+				src = reg_address(regs, 1, reg);
+				
+				__asm__ __volatile__ (
+						      "xchgb %%al, %%ah\n\t"
+						      "roll $16, %%eax\n\t"
+						      "xchgb %%al, %%ah\n\t"
+						      : "=a" (*(u32*)src)
+						      : "a" (*(u32*)src));
+				regs->eip = (u32)eip;
+				goto out;
+			}
+
+
+			/* we'll also try to emulate the CMPXCHG instruction (used in mutex locks).
+			   This instruction is often locked, but it's not possible to put a lock
+			   here. Anyway, I don't believe that there are lots of multiprocessors
+			   386 out there ...
+			*/
+			if ((*eip & 0xFE) == 0xB0) {  /* CMPXCHG */
+				u8 w, reg, modrm;
+
+				w = *eip & 1;
+				modrm = *(eip + 1);
+				eip += 2; /* skips all the opcodes */
+
+				reg = (modrm >> 3) & 7;
+				
+				dst = reg_address(regs, w, reg);
+				if ((modrm & 0xC0) == 0xC0) /* register to register */
+					src = reg_address(regs, w, modrm);
+				else {
+					src = modrm_address(regs, &eip, !(prefixes & PREFIX_A32), modrm);
+					/* we must verify that src is valid for this task */
+					if ((prefixes & (PREFIX_FS | PREFIX_GS)) ||
+					    verify_area(VERIFY_WRITE, (void *)src, (w?((prefixes & PREFIX_D32)?2:4):1))) {
+						do_general_protection(regs, error_code);
+					    goto out;
+					}
+				}
+				
+				if (!w) { /* 8 bits operands */
+					if ((u8)regs->eax == *(u8*)src) {
+						*(u8*)src = *(u8*)dst;
+						regs->eflags |= X86_EFLAGS_ZF;  /* set Zero Flag */
+					}
+					else {
+						*(u8*)&(regs->eax) = *(u8*)src;
+						regs->eflags &= ~X86_EFLAGS_ZF;  /* clear Zero Flag */
+					}
+				}
+				else if (!(prefixes & PREFIX_D32)) { /* 32 bits operands */
+					if ((u32)regs->eax == *(u32*)src) {
+						*(u32*)src = *(u32*)dst;
+						regs->eflags |= X86_EFLAGS_ZF;  /* set Zero Flag */
+					}
+					else {
+						regs->eax = *(u32*)src;
+						regs->eflags &= ~X86_EFLAGS_ZF;  /* clear Zero Flag */
+					}
+				}
+				else { /* 16 bits operands */
+					if ((u16)regs->eax == *(u16*)src) {
+						*(u16*)src = *(u16*)dst;
+						regs->eflags |= X86_EFLAGS_ZF;  /* set Zero Flag */
+					}
+					else {
+						*(u16*)&regs->eax = *(u16*)src;
+						regs->eflags &= ~X86_EFLAGS_ZF;  /* clear Zero Flag */
+					}
+				}
+				regs->eip = (u32)eip;
+				goto out;
+			}
+
+			/* we'll also try to emulate the XADD instruction (not very common) */
+			if ((*eip & 0xFE) == 0xC0) {  /* XADD */
+				u8 w, reg, modrm;
+				u32 op1, op2;
+
+				w = *eip & 1;
+				modrm = *(eip + 1);
+				eip += 2; /* skips all the opcodes */
+
+				reg = (modrm >> 3) & 7;
+				
+				dst = reg_address(regs, w, reg);
+				if ((modrm & 0xC0) == 0xC0) /* register to register */
+					src = reg_address(regs, w, modrm);
+				else {
+					src = modrm_address(regs, &eip, !(prefixes & PREFIX_A32), modrm);
+					/* we must verify that src is valid for this task */
+					if ((prefixes & (PREFIX_FS | PREFIX_GS)) ||
+					    verify_area(VERIFY_WRITE, (void *)src, (w?((prefixes & PREFIX_D32)?2:4):1))) {
+						do_general_protection(regs, error_code);
+						goto out;
+					}
+				}
+				
+				if (!w) { /* 8 bits operands */
+					op1 = *(u8*)src;
+					op2 = *(u8*)dst;
+					*(u8*)src = op1 + op2;
+					*(u8*)dst = op1;
+				}
+				else if (!(prefixes & PREFIX_D32)) { /* 32 bits operands */
+					op1 = *(u32*)src;
+					op2 = *(u32*)dst;
+					*(u32*)src = op1 + op2;
+					*(u32*)dst = op1;
+				}
+				else { /* 16 bits operands */
+					op1 = *(u16*)src;
+					op2 = *(u16*)dst;
+					*(u16*)src = op1 + op2;
+					*(u16*)dst = op1;
+				}
+				regs->eip = (u32)eip;
+				goto out;
+			}
+		} /* if (*eip == 0x0F) */
+		else if ((*eip & 0xfc) == 0x64) {
+			switch (*eip) {
+			case 0x66: /* Operand switches 16/32 bits */
+				if (prefixes & PREFIX_D32)
+					goto invalid_opcode;
+				prefixes |= PREFIX_D32;
+				eip++;
+				continue;
+			case 0x67: /* Address switches 16/32 bits */
+				if (prefixes & PREFIX_A32)
+					goto invalid_opcode;
+				prefixes |= PREFIX_A32;
+				eip++;
+				continue;
+			case 0x64: /* FS: */
+				if (prefixes & PREFIX_SEG)
+					goto invalid_opcode;
+				prefixes |= PREFIX_FS;
+				eip++;
+				continue;
+			case 0x65: /* GS: */
+				if (prefixes & PREFIX_SEG)
+					goto invalid_opcode;
+				prefixes |= PREFIX_GS;
+				eip++;
+				continue;
+			}
+		}
+		else if (*eip == 0xf0) { /* lock */
+			if (prefixes & PREFIX_LOCK)
+				goto invalid_opcode;
+			prefixes |= PREFIX_LOCK;
+				eip++;
+				continue;
+		}
+		else if ((*eip & 0xe7) == 0x26) {
+			switch (*eip) {
+			case 0x26: /* ES: */
+				if (prefixes & PREFIX_SEG)
+					goto invalid_opcode;
+				prefixes |= PREFIX_ES;
+				eip++;
+				continue;
+			case 0x2E: /* CS: */
+				if (prefixes & PREFIX_SEG)
+					goto invalid_opcode;
+				prefixes |= PREFIX_CS;
+				eip++;
+				continue;
+			case 0x36: /* SS: */
+				if (prefixes & PREFIX_SEG)
+					goto invalid_opcode;
+				prefixes |= PREFIX_SS;
+				eip++;
+				continue;
+			case 0x3E: /* DS: */
+				if (prefixes & PREFIX_SEG)
+					goto invalid_opcode;
+				prefixes |= PREFIX_DS;
+				eip++;
+				continue;
+			}
+		}
+		/* if this opcode has not been processed, it's not a prefix. */
+		break;
+	}
+
+	/* it's a case we can't handle. Unknown opcode or too many prefixes. */
+invalid_opcode:
+	preempt_enable();
+#ifdef CONFIG_CPU_EMU486_DEBUG
+	printk(KERN_DEBUG "do_emu() : invalid opcode detected @%p : %02x %02x ...\n", eip, eip[0], eip[1]);
+#endif
+	do_invalid_op(regs, error_code);
+	return;
+
+out:
+	preempt_enable();
+}
--- kernel-source-2.6.6/arch/i386/kernel/entry.S	2004-05-10 19:47:45.000000000 +1000
+++ kernel-source-2.6.6-1/arch/i386/kernel/entry.S	2004-05-10 22:21:09.000000000 +1000
@@ -562,7 +562,11 @@
 
 ENTRY(invalid_op)
 	pushl $0
+#ifdef CONFIG_X86_EMU486
+	pushl $do_emu
+#else
 	pushl $do_invalid_op
+#endif
 	jmp error_code
 
 ENTRY(coprocessor_segment_overrun)

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-22 23:40 i486 emu in mainline? Christoph Hellwig
@ 2004-05-23  0:20 ` Rene Rebe
  2004-05-23  7:13 ` Arjan van de Ven
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 29+ messages in thread
From: Rene Rebe @ 2004-05-23  0:20 UTC (permalink / raw)
  To: hch; +Cc: akpm, willy, linux-kernel

Hi,

On: Sun, 23 May 2004 01:40:59 +0200,
    Christoph Hellwig <hch@lst.de> wrote:
> These days gcc uses i486+ only instruction by default in libstdc++ so
> most modern distros wouldn't work on i386 cpus anymore.  To make it work
> again Debian merged Willy Tarreau's patch to trap those and emulate them
> on real i386 cpus.  The patch is extremely non-invasive and would
> certainly be usefull for mainline.  Any reason not to include it?

Oh cool! Given the fact with libstdc++ and sparc32 kernel also always
contain code to emulatre the mul/div instructions missing in the v7
hardware (just foudn this SIGILL trap by accident recently ..) the
comment might be a bit too strict. Maybe something like written in the
MATH_EMULATION config:

"If you are not sure, say Y; apart from resulting in a 66 KB bigger
kernel, it won't hurt."

Sincerely yours,
  René Rebe
    - ROCK Linux stable release maintainer

--  
René Rebe - Europe/Germany/Berlin
  rene@rocklinux.org rene@rocklinux-consulting.de
http://www.rocklinux.org http://www.rocklinux-consulting.de


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-22 23:40 i486 emu in mainline? Christoph Hellwig
  2004-05-23  0:20 ` Rene Rebe
@ 2004-05-23  7:13 ` Arjan van de Ven
  2004-05-23  8:44   ` Willy Tarreau
  2004-05-23  8:29 ` Willy Tarreau
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 29+ messages in thread
From: Arjan van de Ven @ 2004-05-23  7:13 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: akpm, willy, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 526 bytes --]

On Sun, 2004-05-23 at 01:40, Christoph Hellwig wrote:
> These days gcc uses i486+ only instruction by default in libstdc++ so
> most modern distros wouldn't work on i386 cpus anymore.  To make it work
> again Debian merged Willy Tarreau's patch to trap those and emulate them
> on real i386 cpus.  The patch is extremely non-invasive and would
> certainly be usefull for mainline.  Any reason not to include it?
> 

on first look it seems to be missing a bunch of get_user() calls and
does direct access instead....

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-22 23:40 i486 emu in mainline? Christoph Hellwig
  2004-05-23  0:20 ` Rene Rebe
  2004-05-23  7:13 ` Arjan van de Ven
@ 2004-05-23  8:29 ` Willy Tarreau
  2004-05-23 11:08   ` Alan Cox
                     ` (2 more replies)
  2004-05-24 12:28 ` Maciej W. Rozycki
  2004-05-25 17:21 ` Kronos
  4 siblings, 3 replies; 29+ messages in thread
From: Willy Tarreau @ 2004-05-23  8:29 UTC (permalink / raw)
  To: Christoph Hellwig, akpm, linux-kernel; +Cc: alan, vda

Hi Christoph,

On Sun, May 23, 2004 at 01:40:59AM +0200, Christoph Hellwig wrote:
> These days gcc uses i486+ only instruction by default in libstdc++ so
> most modern distros wouldn't work on i386 cpus anymore.  To make it work
> again Debian merged Willy Tarreau's patch to trap those and emulate them
> on real i386 cpus.  The patch is extremely non-invasive and would
> certainly be usefull for mainline.  Any reason not to include it?

Well, I have mixed feelings about this because :

  - I don't know which version they based their port on. The version
    I published 2 years ago included CMOV emulation, and Denis Vlasenko
    found several bugs in it which I then fixed. Since the Debian port
    doesn't include CMOV, I wonder whether it includes those bugs or not
    (I'll have to diff the patches).

  - The code is ugly in some areas, and someone will kill me if this goes
    into mainline.

  - There are people (like Alan) who think that this should not go into
    mainline because this is a distro problem and nothing else. He says
    that only i386 packages should be installed on an i386 machine. He's
    perfectly right about this. I found it interesting for people like
    me who boot kernels on random machines, try to recover hard disk
    contents or other things using lots of dirty tools, and sometimes
    get hit by the "illegal instruction" trap. It also allowed me to
    run a pppd compiled with i586 glibc on my i386 firewall, but obviously
    this is just the easy way and not the right way to go.

  - I couldn't emulate locks, so this will break on SMP systems, and so
    will it if you need to access some memory share with an external
    microcontroller or something like that.

  - I've always wondered if this feature would not be exploitable to
    access unauthorized information. Eg: code an invalid opcode
    which would get emulated and references a memory area outside the
    user space. I put some verify_area() where I thought appropriate,
    but I might have left some caveats... Morten Welinder once insisted
    on the fact that each byte should be read once and only once so as
    to ensure that the user doesn't change the instruction while it is
    being emulated. I think it's already the case. He also said that I
    didn't take care of the segment selectors (such as SS) which some
    programs use perfectly legally (eg Wine). I don't know how to do
    that.

  - Denis Vlasenko suggested that we print some messages on the console
    when a program triggers the code, so as not to let the user think that
    his machine is slow as hell. But for this we would need not to flood the
    console (eg: once for each prog) but we don't want either to store
    anything in the task structure about the message having been displayed,
    so for now there's nothing. In fact, the only message which is displayed
    (in the most recent version) is about a warning about a LOCK prefix on
    an SMP kernel. But I didn't find it right here, so I suspect this is
    based on ancient code.

  - why not include the CMOV emulation while we're at it ? There are so
    many people using VIA EDEN chips who think it's i686 compatible that
    they may get hit too. IIRC, the chip only executes CMOV on registers,
    but very slowly (a few tens of cycles), while register to memory
    accesses generate a trap.

Other than that, I'm happy that someone found it useful, and happy too that
someone did the 2.6 port :-)

Regards,
Willy


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-23  7:13 ` Arjan van de Ven
@ 2004-05-23  8:44   ` Willy Tarreau
  2004-05-23  9:13     ` Arjan van de Ven
                       ` (2 more replies)
  0 siblings, 3 replies; 29+ messages in thread
From: Willy Tarreau @ 2004-05-23  8:44 UTC (permalink / raw)
  To: Arjan van de Ven; +Cc: Christoph Hellwig, akpm, linux-kernel

Hi Arjan,

On Sun, May 23, 2004 at 09:13:20AM +0200, Arjan van de Ven wrote:
> on first look it seems to be missing a bunch of get_user() calls and
> does direct access instead....

It was intentional for speed purpose. The areas are checked once with
verify_area() when we need to access memory, then data is copied directly
from/to memory. I don't think there's any risk, but I can be wrong.

Regards,
Willy


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-23  8:44   ` Willy Tarreau
@ 2004-05-23  9:13     ` Arjan van de Ven
  2004-05-23  9:48       ` Willy Tarreau
  2004-05-23  9:20     ` Andrew Morton
  2004-05-23 17:11     ` Brian Gerst
  2 siblings, 1 reply; 29+ messages in thread
From: Arjan van de Ven @ 2004-05-23  9:13 UTC (permalink / raw)
  To: Willy Tarreau; +Cc: Christoph Hellwig, akpm, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 569 bytes --]

On Sun, May 23, 2004 at 10:44:15AM +0200, Willy Tarreau wrote:
> Hi Arjan,
> 
> On Sun, May 23, 2004 at 09:13:20AM +0200, Arjan van de Ven wrote:
> > on first look it seems to be missing a bunch of get_user() calls and
> > does direct access instead....
> 
> It was intentional for speed purpose. The areas are checked once with
> verify_area() when we need to access memory, then data is copied directly
> from/to memory. I don't think there's any risk, but I can be wrong.

it's an oopsable offence; nothing is making sure the memory is actually
present for example.

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-23  8:44   ` Willy Tarreau
  2004-05-23  9:13     ` Arjan van de Ven
@ 2004-05-23  9:20     ` Andrew Morton
  2004-05-23 17:11     ` Brian Gerst
  2 siblings, 0 replies; 29+ messages in thread
From: Andrew Morton @ 2004-05-23  9:20 UTC (permalink / raw)
  To: Willy Tarreau; +Cc: arjanv, hch, linux-kernel

Willy Tarreau <willy@w.ods.org> wrote:
>
>  On Sun, May 23, 2004 at 09:13:20AM +0200, Arjan van de Ven wrote:
>  > on first look it seems to be missing a bunch of get_user() calls and
>  > does direct access instead....
> 
>  It was intentional for speed purpose. The areas are checked once with
>  verify_area() when we need to access memory, then data is copied directly
>  from/to memory. I don't think there's any risk, but I can be wrong.

verify_area() simply checks that the address is a legal one for a userspace
access (it's not a chunk of kernel memory).  But the kernel can still take
a pagefault when accessing the address, so you need to use the uaccess
functions which will handle the fault appropriately.

That's put_user(), get_user(), copy_*_user(), etc.  Those functions
internally perform verify_area(), so if you've already done a verify_area()
you can use __put_user(), __get_user(), etc which skip the verify_area()
but which still know how to deal with user address faults.


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-23  9:13     ` Arjan van de Ven
@ 2004-05-23  9:48       ` Willy Tarreau
  2004-05-23  9:58         ` Arjan van de Ven
  2004-05-23 11:49         ` Helge Hafting
  0 siblings, 2 replies; 29+ messages in thread
From: Willy Tarreau @ 2004-05-23  9:48 UTC (permalink / raw)
  To: Arjan van de Ven; +Cc: Christoph Hellwig, akpm, linux-kernel

On Sun, May 23, 2004 at 11:13:56AM +0200, Arjan van de Ven wrote:
> On Sun, May 23, 2004 at 10:44:15AM +0200, Willy Tarreau wrote:
> > Hi Arjan,
> > 
> > On Sun, May 23, 2004 at 09:13:20AM +0200, Arjan van de Ven wrote:
> > > on first look it seems to be missing a bunch of get_user() calls and
> > > does direct access instead....
> > 
> > It was intentional for speed purpose. The areas are checked once with
> > verify_area() when we need to access memory, then data is copied directly
> > from/to memory. I don't think there's any risk, but I can be wrong.
> 
> it's an oopsable offence; nothing is making sure the memory is actually
> present for example.

You mean like when a user does a malloc() and the memory is not physically
allocated because not used yet ? or even in case memory has been swapped
out ? I believe I begin to understand, but the corner case is not really
clear to me. It yet seems strange to me that the user can reference memory
areas that the kernel cannot access. I'm certainly mistaken somewhere, but
I don't know where. In fact, if you could give me a simple example which
puts my original code at fault, it would really help me. Then I'll change
the code as suggested by Andrew but at least I would understand what I do.

Thanks in advance.
Willy


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-23  9:48       ` Willy Tarreau
@ 2004-05-23  9:58         ` Arjan van de Ven
  2004-05-23 11:49         ` Helge Hafting
  1 sibling, 0 replies; 29+ messages in thread
From: Arjan van de Ven @ 2004-05-23  9:58 UTC (permalink / raw)
  To: Willy Tarreau; +Cc: Christoph Hellwig, akpm, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1518 bytes --]


On Sun, May 23, 2004 at 11:48:53AM +0200, Willy Tarreau wrote:
> On Sun, May 23, 2004 at 11:13:56AM +0200, Arjan van de Ven wrote:
> > On Sun, May 23, 2004 at 10:44:15AM +0200, Willy Tarreau wrote:
> > > Hi Arjan,
> > > 
> > > On Sun, May 23, 2004 at 09:13:20AM +0200, Arjan van de Ven wrote:
> > > > on first look it seems to be missing a bunch of get_user() calls and
> > > > does direct access instead....
> > > 
> > > It was intentional for speed purpose. The areas are checked once with
> > > verify_area() when we need to access memory, then data is copied directly
> > > from/to memory. I don't think there's any risk, but I can be wrong.
> > 
> > it's an oopsable offence; nothing is making sure the memory is actually
> > present for example.
> 
> You mean like when a user does a malloc() and the memory is not physically
> allocated because not used yet ? or even in case memory has been swapped
> out ? 

Well both. Or even a stray invalid userspace pointer.

copy_from_user/get_user will catch the trap the cpu will cause in such a
case, and the VM will swap in the page, allocate a new page in case of the
malloc-but-never-used-yet or throw a segmentation fault if the userspace
pointer is broken.

If there is no protection (eg there is no exception handler defined) then
the kernel will throw an oops since it's an uncaught/unhandled kernel mode
exception. Obviously copy_from_user/get_user and co have such exception
handlers defined and will do the expected (right) thing. Direct access does
not.



[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-23  8:29 ` Willy Tarreau
@ 2004-05-23 11:08   ` Alan Cox
  2004-05-23 11:57     ` Willy Tarreau
       [not found]   ` <20040523105130.GA588@samarkand.rivenstone.net>
  2004-05-23 15:18   ` Jeff Garzik
  2 siblings, 1 reply; 29+ messages in thread
From: Alan Cox @ 2004-05-23 11:08 UTC (permalink / raw)
  To: Willy Tarreau; +Cc: Christoph Hellwig, akpm, linux-kernel, alan, vda

On Sun, May 23, 2004 at 10:29:12AM +0200, Willy Tarreau wrote:
>     being emulated. I think it's already the case. He also said that I
>     didn't take care of the segment selectors (such as SS) which some
>     programs use perfectly legally (eg Wine). I don't know how to do
>     that.

You have to parse all the valid header bytes (the opcode prefixes) that
change segment, cause repeats and change sizes. DOSemu has a worked example
of this particular set of horrors.

>   - why not include the CMOV emulation while we're at it ? There are so
>     many people using VIA EDEN chips who think it's i686 compatible that
>     they may get hit too. IIRC, the chip only executes CMOV on registers,
>     but very slowly (a few tens of cycles), while register to memory
>     accesses generate a trap.

gcc generates a lot of cmov on i686 so many that people I've talked with
on the compiler side also feel cmov emulation isnt useful. Newer Eden btw
has cmov.

> Other than that, I'm happy that someone found it useful, and happy too that
> someone did the 2.6 port :-)

Is there a reason btw it can't be done with LD_PRELOAD ?


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-23  9:48       ` Willy Tarreau
  2004-05-23  9:58         ` Arjan van de Ven
@ 2004-05-23 11:49         ` Helge Hafting
  1 sibling, 0 replies; 29+ messages in thread
From: Helge Hafting @ 2004-05-23 11:49 UTC (permalink / raw)
  To: Willy Tarreau; +Cc: Arjan van de Ven, Christoph Hellwig, akpm, linux-kernel

On Sun, May 23, 2004 at 11:48:53AM +0200, Willy Tarreau wrote:
> 
> You mean like when a user does a malloc() and the memory is not physically
> allocated because not used yet ? or even in case memory has been swapped
> out ? I believe I begin to understand, but the corner case is not really
> clear to me. It yet seems strange to me that the user can reference memory
> areas that the kernel cannot access. 

The user referencing non-present memory is not a problem, because:
1. It is always pssoible to block the user process and let it wait
   (a long time) for swapping to happen. That might not be an
   option for the kernel - it can't wait while holding a
   spinlock, for example.
2. It is always ok to kill the user process if it uses memory it
   doesn't have.  It is not ok to "kill" the kernel.  The indirect ways
   of using user memory from the kernel side ensures that the
   normal mechanisms (swap-wait or kill) applies to the process owning
   the memory.  Direct reference from kernel does not invoke normal page 
   fault mechanisms when memory goes wrong.

Helge Hafting 

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-23 11:08   ` Alan Cox
@ 2004-05-23 11:57     ` Willy Tarreau
  2004-05-23 13:15       ` Alan Cox
  0 siblings, 1 reply; 29+ messages in thread
From: Willy Tarreau @ 2004-05-23 11:57 UTC (permalink / raw)
  To: Alan Cox; +Cc: Christoph Hellwig, akpm, linux-kernel, vda

On Sun, May 23, 2004 at 07:08:36AM -0400, Alan Cox wrote:
> On Sun, May 23, 2004 at 10:29:12AM +0200, Willy Tarreau wrote:
> >     being emulated. I think it's already the case. He also said that I
> >     didn't take care of the segment selectors (such as SS) which some
> >     programs use perfectly legally (eg Wine). I don't know how to do
> >     that.
> 
> You have to parse all the valid header bytes (the opcode prefixes) that
> change segment, cause repeats and change sizes. DOSemu has a worked example
> of this particular set of horrors.

It's already what it does, but I don't use the segment base in the TSS nor
check the segment limit. It will take me quite some time to understand how
all this is implemented in the kernel and unfortunately I don't have such
time now.

> >   - why not include the CMOV emulation while we're at it ? There are so
> >     many people using VIA EDEN chips who think it's i686 compatible that
> >     they may get hit too. IIRC, the chip only executes CMOV on registers,
> >     but very slowly (a few tens of cycles), while register to memory
> >     accesses generate a trap.
> 
> gcc generates a lot of cmov on i686 so many that people I've talked with
> on the compiler side also feel cmov emulation isnt useful. Newer Eden btw
> has cmov.

agreed, but there are some programs which don't need speed at all, hence the
reason for my first implementation of cmov (which burnt about 400 cycles IIRC).

> > Other than that, I'm happy that someone found it useful, and happy too that
> > someone did the 2.6 port :-)
> 
> Is there a reason btw it can't be done with LD_PRELOAD ?

Well, this is an interesting question. I don't know how to do it this way
(how can a program know exactly where the trap occured, etc... I don't know
how to program this). Other than that, LD_PRELOAD will not work against setuid
binaries. But if it does for the rest, I think it can become an elegant
approach.

Thanks for your insights,
Willy


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
       [not found]   ` <20040523105130.GA588@samarkand.rivenstone.net>
@ 2004-05-23 11:59     ` Willy Tarreau
  2004-05-24  9:08       ` P
  0 siblings, 1 reply; 29+ messages in thread
From: Willy Tarreau @ 2004-05-23 11:59 UTC (permalink / raw)
  To: linux-kernel, Christoph Hellwig, akpm

On Sun, May 23, 2004 at 06:51:30AM -0400, Joseph Fannin wrote:
> On Sun, May 23, 2004 at 10:29:12AM +0200, Willy Tarreau wrote:
> 
> > On Sun, May 23, 2004 at 01:40:59AM +0200, Christoph Hellwig wrote:
> >> These days gcc uses i486+ only instruction by default in libstdc++ so
> >> most modern distros wouldn't work on i386 cpus anymore.  To make it work
> >> again Debian merged Willy Tarreau's patch to trap those and emulate them
> >> on real i386 cpus.  The patch is extremely non-invasive and would
> >> certainly be usefull for mainline.  Any reason not to include it?
> 
> 
> >   - I couldn't emulate locks, so this will break on SMP systems, and so
> >     will it if you need to access some memory share with an external
> >     microcontroller or something like that.
> 
>     Does this mean that programs that use the NPTL will work on
> non-SMP 386s?

I have no idea. Why would NPTL not work on i386 ?

Willy


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-23 11:57     ` Willy Tarreau
@ 2004-05-23 13:15       ` Alan Cox
  2004-05-24 15:17         ` Jan-Benedict Glaw
  0 siblings, 1 reply; 29+ messages in thread
From: Alan Cox @ 2004-05-23 13:15 UTC (permalink / raw)
  To: Willy Tarreau; +Cc: Alan Cox, Christoph Hellwig, akpm, linux-kernel, vda

> > Is there a reason btw it can't be done with LD_PRELOAD ?
> 
> Well, this is an interesting question. I don't know how to do it this way
> (how can a program know exactly where the trap occured, etc... I don't know
> how to program this). Other than that, LD_PRELOAD will not work against setuid
> binaries. But if it does for the rest, I think it can become an elegant
> approach.

setuid binaries can still use /etc/ld.preload or whatever the file is called
just not environment.

Someone actually did a libmmx long ago that used preload, hooked SIGILL
and the signal handlers and used that to provide mmx on an mmx free cpu


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-23  8:29 ` Willy Tarreau
  2004-05-23 11:08   ` Alan Cox
       [not found]   ` <20040523105130.GA588@samarkand.rivenstone.net>
@ 2004-05-23 15:18   ` Jeff Garzik
  2004-05-23 21:14     ` Alan Cox
  2 siblings, 1 reply; 29+ messages in thread
From: Jeff Garzik @ 2004-05-23 15:18 UTC (permalink / raw)
  To: Willy Tarreau; +Cc: Christoph Hellwig, akpm, linux-kernel, alan, vda

Willy Tarreau wrote:
>   - There are people (like Alan) who think that this should not go into
>     mainline because this is a distro problem and nothing else. He says
>     that only i386 packages should be installed on an i386 machine. He's
>     perfectly right about this. I found it interesting for people like


I disagree.

I want to add "old Alpha" emulation code, so that older Alphas can run 
binaries built on the newer alphas.

	Jeff



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-23  8:44   ` Willy Tarreau
  2004-05-23  9:13     ` Arjan van de Ven
  2004-05-23  9:20     ` Andrew Morton
@ 2004-05-23 17:11     ` Brian Gerst
  2004-05-24  2:47       ` Herbert Xu
  2 siblings, 1 reply; 29+ messages in thread
From: Brian Gerst @ 2004-05-23 17:11 UTC (permalink / raw)
  To: Willy Tarreau; +Cc: Arjan van de Ven, Christoph Hellwig, akpm, linux-kernel

Willy Tarreau wrote:
> Hi Arjan,
> 
> On Sun, May 23, 2004 at 09:13:20AM +0200, Arjan van de Ven wrote:
> 
>>on first look it seems to be missing a bunch of get_user() calls and
>>does direct access instead....
> 
> 
> It was intentional for speed purpose. The areas are checked once with
> verify_area() when we need to access memory, then data is copied directly
> from/to memory. I don't think there's any risk, but I can be wrong.

Which will break with 4G/4G.  You must use at least __get_user().

--
				Brian Gerst

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-23 15:18   ` Jeff Garzik
@ 2004-05-23 21:14     ` Alan Cox
  0 siblings, 0 replies; 29+ messages in thread
From: Alan Cox @ 2004-05-23 21:14 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: Willy Tarreau, Christoph Hellwig, akpm, linux-kernel, alan, vda

On Sun, May 23, 2004 at 11:18:31AM -0400, Jeff Garzik wrote:
> >  - There are people (like Alan) who think that this should not go into
> >    mainline because this is a distro problem and nothing else. He says
> >    that only i386 packages should be installed on an i386 machine. He's
> >    perfectly right about this. I found it interesting for people like
> 
> 
> I disagree.
> 
> I want to add "old Alpha" emulation code, so that older Alphas can run 
> binaries built on the newer alphas.

Well it always depends on the platform. cmov emulation isnt useful because
i686 gcc generates too many for it to be of value. For alpha it depends
on the commonness of the emulated instructions and the emulation cost.

Either way it is a user space problem in almost all situations. See
http://www-sop.inria.fr/geometrica/team/Sylvain.Pion/progs/mmx-emu/


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-23 17:11     ` Brian Gerst
@ 2004-05-24  2:47       ` Herbert Xu
  2004-05-27 21:03         ` Pavel Machek
  0 siblings, 1 reply; 29+ messages in thread
From: Herbert Xu @ 2004-05-24  2:47 UTC (permalink / raw)
  To: Brian Gerst; +Cc: willy, arjanv, hch, akpm, linux-kernel

Brian Gerst <bgerst@didntduck.org> wrote:
>
>> It was intentional for speed purpose. The areas are checked once with
>> verify_area() when we need to access memory, then data is copied directly
>> from/to memory. I don't think there's any risk, but I can be wrong.
> 
> Which will break with 4G/4G.  You must use at least __get_user().

A 386 with a 4G/4G split, I'd like to see that.
-- 
Visit Openswan at http://www.openswan.org/
Email:  Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-23 11:59     ` Willy Tarreau
@ 2004-05-24  9:08       ` P
  0 siblings, 0 replies; 29+ messages in thread
From: P @ 2004-05-24  9:08 UTC (permalink / raw)
  To: Willy Tarreau; +Cc: linux-kernel, Christoph Hellwig, akpm

Willy Tarreau wrote:
> On Sun, May 23, 2004 at 06:51:30AM -0400, Joseph Fannin wrote:
> 
>>On Sun, May 23, 2004 at 10:29:12AM +0200, Willy Tarreau wrote:
>>
>>>On Sun, May 23, 2004 at 01:40:59AM +0200, Christoph Hellwig wrote:
>>>
>>>>These days gcc uses i486+ only instruction by default in libstdc++ so
>>>>most modern distros wouldn't work on i386 cpus anymore.  To make it work
>>>>again Debian merged Willy Tarreau's patch to trap those and emulate them
>>>>on real i386 cpus.  The patch is extremely non-invasive and would
>>>>certainly be usefull for mainline.  Any reason not to include it?
>>
>>>  - I couldn't emulate locks, so this will break on SMP systems, and so
>>>    will it if you need to access some memory share with an external
>>>    microcontroller or something like that.
>>
>>    Does this mean that programs that use the NPTL will work on
>>non-SMP 386s?
> 
> I have no idea. Why would NPTL not work on i386 ?

i386 doesn't have the necessary instructions.
It's my understanding that the following is not being maintained:
http://sources.redhat.com/ml/libc-hacker/2004-05/msg00019.html

Pádraig.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-22 23:40 i486 emu in mainline? Christoph Hellwig
                   ` (2 preceding siblings ...)
  2004-05-23  8:29 ` Willy Tarreau
@ 2004-05-24 12:28 ` Maciej W. Rozycki
  2004-05-25 17:21 ` Kronos
  4 siblings, 0 replies; 29+ messages in thread
From: Maciej W. Rozycki @ 2004-05-24 12:28 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: akpm, willy, linux-kernel

On Sun, 23 May 2004, Christoph Hellwig wrote:

> +			/* we'll verify if this is a BSWAP opcode, main source of SIGILL on 386's */
> +			if ((*eip & 0xF8) == 0xC8) {  /* BSWAP */
> +				u8 reg;
> +
> +				reg = *eip++ & 0x07;
> +				src = reg_address(regs, 1, reg);
> +				
> +				__asm__ __volatile__ (
> +						      "xchgb %%al, %%ah\n\t"
> +						      "roll $16, %%eax\n\t"
> +						      "xchgb %%al, %%ah\n\t"
> +						      : "=a" (*(u32*)src)
> +						      : "a" (*(u32*)src));
> +				regs->eip = (u32)eip;
> +				goto out;
> +			}

 You've forgotten about the 16-bit variant here -- the emulation is wrong 
with PREFIX_D32.  This may not matter much in practice, though.

-- 
+  Maciej W. Rozycki, Technical University of Gdansk, Poland   +
+--------------------------------------------------------------+
+        e-mail: macro@ds2.pg.gda.pl, PGP key available        +

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-23 13:15       ` Alan Cox
@ 2004-05-24 15:17         ` Jan-Benedict Glaw
  2004-05-24 17:41           ` Alan Cox
  0 siblings, 1 reply; 29+ messages in thread
From: Jan-Benedict Glaw @ 2004-05-24 15:17 UTC (permalink / raw)
  To: Alan Cox; +Cc: Willy Tarreau, Christoph Hellwig, akpm, linux-kernel, vda

[-- Attachment #1: Type: text/plain, Size: 1625 bytes --]

On Sun, 2004-05-23 09:15:12 -0400, Alan Cox <alan@redhat.com>
wrote in message <20040523131512.GA25185@devserv.devel.redhat.com>:
> > > Is there a reason btw it can't be done with LD_PRELOAD ?
> > 
> > Well, this is an interesting question. I don't know how to do it this way
> > (how can a program know exactly where the trap occured, etc... I don't know
> > how to program this). Other than that, LD_PRELOAD will not work against setuid
> > binaries. But if it does for the rest, I think it can become an elegant
> > approach.
> 
> setuid binaries can still use /etc/ld.preload or whatever the file is called
> just not environment.

Being an old hardware user and tester (I still have a i386 and i486SLC
where I do testing on!), I strongly support the inclusion of the
emulator. I think that it should even be extended/fixed to catch the
remaining opcode(s).

> Someone actually did a libmmx long ago that used preload, hooked SIGILL
> and the signal handlers and used that to provide mmx on an mmx free cpu

There are some application that register signal handling functions IIRC
for SIGILL, SIGSEGV and the like to do internal error trapping on their
own (not only OOo comes to mind). These would probably be f*cked up if they
didn't call the LD_PRELOADed signal handler...

MfG, JBG

-- 
   Jan-Benedict Glaw       jbglaw@lug-owl.de    . +49-172-7608481
   "Eine Freie Meinung in  einem Freien Kopf    | Gegen Zensur | Gegen Krieg
    fuer einen Freien Staat voll Freier Bürger" | im Internet! |   im Irak!
   ret = do_actions((curr | FREE_SPEECH) & ~(NEW_COPYRIGHT_LAW | DRM | TCPA));

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-24 15:17         ` Jan-Benedict Glaw
@ 2004-05-24 17:41           ` Alan Cox
  2004-05-25  9:36             ` Jan-Benedict Glaw
  0 siblings, 1 reply; 29+ messages in thread
From: Alan Cox @ 2004-05-24 17:41 UTC (permalink / raw)
  To: Alan Cox, Willy Tarreau, Christoph Hellwig, akpm, linux-kernel, vda

On Mon, May 24, 2004 at 05:17:15PM +0200, Jan-Benedict Glaw wrote:
> There are some application that register signal handling functions IIRC
> for SIGILL, SIGSEGV and the like to do internal error trapping on their
> own (not only OOo comes to mind). These would probably be f*cked up if they
> didn't call the LD_PRELOADed signal handler...

No. The LD_PRELOAD also hooks the signal setting functions. This really is
not rocket science at all. 


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-24 17:41           ` Alan Cox
@ 2004-05-25  9:36             ` Jan-Benedict Glaw
  2004-05-25 13:48               ` Alan Cox
  0 siblings, 1 reply; 29+ messages in thread
From: Jan-Benedict Glaw @ 2004-05-25  9:36 UTC (permalink / raw)
  To: Alan Cox; +Cc: Willy Tarreau, Christoph Hellwig, akpm, linux-kernel, vda

[-- Attachment #1: Type: text/plain, Size: 1043 bytes --]

On Mon, 2004-05-24 13:41:56 -0400, Alan Cox <alan@redhat.com>
wrote in message <20040524174156.GG19161@devserv.devel.redhat.com>:
> On Mon, May 24, 2004 at 05:17:15PM +0200, Jan-Benedict Glaw wrote:
> > There are some application that register signal handling functions IIRC
> > for SIGILL, SIGSEGV and the like to do internal error trapping on their
> > own (not only OOo comes to mind). These would probably be f*cked up if they
> > didn't call the LD_PRELOADed signal handler...
> 
> No. The LD_PRELOAD also hooks the signal setting functions. This really is
> not rocket science at all. 

But works only on dynamically linkes executables, and only on those that
don't do system calls on their own, right?

MfG, JBG

-- 
   Jan-Benedict Glaw       jbglaw@lug-owl.de    . +49-172-7608481
   "Eine Freie Meinung in  einem Freien Kopf    | Gegen Zensur | Gegen Krieg
    fuer einen Freien Staat voll Freier Bürger" | im Internet! |   im Irak!
   ret = do_actions((curr | FREE_SPEECH) & ~(NEW_COPYRIGHT_LAW | DRM | TCPA));

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-25  9:36             ` Jan-Benedict Glaw
@ 2004-05-25 13:48               ` Alan Cox
  0 siblings, 0 replies; 29+ messages in thread
From: Alan Cox @ 2004-05-25 13:48 UTC (permalink / raw)
  To: Alan Cox, Willy Tarreau, Christoph Hellwig, akpm, linux-kernel, vda

On Tue, May 25, 2004 at 11:36:52AM +0200, Jan-Benedict Glaw wrote:
> > No. The LD_PRELOAD also hooks the signal setting functions. This really is
> > not rocket science at all. 
> 
> But works only on dynamically linkes executables, and only on those that
> don't do system calls on their own, right?

If it is static linked to glibc or libc5 then you have the source or the
bits to relink it. 

You can build an app to deliberately break software emulation, but that goes
for kernel mode too and isn't the problem you *actually* want to solve


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-22 23:40 i486 emu in mainline? Christoph Hellwig
                   ` (3 preceding siblings ...)
  2004-05-24 12:28 ` Maciej W. Rozycki
@ 2004-05-25 17:21 ` Kronos
  4 siblings, 0 replies; 29+ messages in thread
From: Kronos @ 2004-05-25 17:21 UTC (permalink / raw)
  To: linux-kernel; +Cc: Christoph Hellwig, willy

Christoph Hellwig <hch@lst.de> ha scritto:
> --- kernel-source-2.6.6/arch/i386/Kconfig     2004-05-10 19:47:45.000000000 +1000
> +++ kernel-source-2.6.6-1/arch/i386/Kconfig   2004-05-10 22:21:08.000000000 +1000
> @@ -330,6 +330,41 @@
>         This is really intended for distributors who need more
>         generic optimizations.
>
> +config X86_EMU486
> +       bool "486 emulation"
> +       help

Hi,
what about adding an explicit dependancy from M386/M486? A kernel
compiled for 486 or higher won't boot on 386 anyway so the emulation
code would be useless.

diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig
--- a/arch/i386/Kconfig	2004-05-25 19:07:16.000000000 +0200
+++ b/arch/i386/Kconfig	2004-05-25 19:10:59.000000000 +0200
@@ -332,6 +332,7 @@
 
 config X86_EMU486
        bool "486 emulation"
+       depends on M386 || M486
        help
           When used on a 386, Linux can emulate 3 instructions from the 486
           set.  This allows user space programs compiled for 486 to run on a


Signed-off-by: Luca Tettamanti <kronos@kronoz.cjb.net>
(just in case ;) )

Luca
-- 
Home: http://kronoz.cjb.net
Windows /win'dohz/ n. : thirty-two  bit extension and graphical shell to
a sixteen  bit patch to an  eight bit operating system  originally coded
for a  four bit microprocessor  which was  written by a  two-bit company
that can't stand a bit of competition.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-24  2:47       ` Herbert Xu
@ 2004-05-27 21:03         ` Pavel Machek
  0 siblings, 0 replies; 29+ messages in thread
From: Pavel Machek @ 2004-05-27 21:03 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Brian Gerst, willy, arjanv, hch, akpm, linux-kernel

Hi!

> >> It was intentional for speed purpose. The areas are checked once with
> >> verify_area() when we need to access memory, then data is copied directly
> >> from/to memory. I don't think there's any risk, but I can be wrong.
> > 
> > Which will break with 4G/4G.  You must use at least __get_user().
> 
> A 386 with a 4G/4G split, I'd like to see that.

I believe you could...

1) some 586 class machines do not know 486 opcodes

2) this is for rescue kernel. If you want to be able to rescue 64GB machine *and* rescue 486 too,
this+4G/4G is right choice ;-)

-- 
64 bytes from 195.113.31.123: icmp_seq=28 ttl=51 time=448769.1 ms         


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
@ 2004-10-10 20:33 Nathanael Nerode
  0 siblings, 0 replies; 29+ messages in thread
From: Nathanael Nerode @ 2004-10-10 20:33 UTC (permalink / raw)
  To: linux-kernel

Some thread necromancy...

On Sun, 23 May 2004 02:20:58 +0000, Andrew Morton wrote:
>Willy Tarreau <willy <at> w.ods.org> wrote:
>>
>>  On Sun, May 23, 2004 at 09:13:20AM +0200, Arjan van de Ven wrote:
>>  > on first look it seems to be missing a bunch of get_user() calls and
>>  > does direct access instead....
>> 
>>  It was intentional for speed purpose. The areas are checked once with
>>  verify_area() when we need to access memory, then data is copied directly
>>  from/to memory. I don't think there's any risk, but I can be wrong.
>
>verify_area() simply checks that the address is a legal one for a userspace
>access (it's not a chunk of kernel memory).  But the kernel can still take
>a pagefault when accessing the address, so you need to use the uaccess
>functions which will handle the fault appropriately.
>
>That's put_user(), get_user(), copy_*_user(), etc.  Those functions
>internally perform verify_area(), so if you've already done a verify_area()
>you can use __put_user(), __get_user(), etc which skip the verify_area()
>but which still know how to deal with user address faults.

After reviewing the thread, this seems to be the most important reason
why this patch can't be included.  So I thought, "Hey, I'll fix that."

But put_user, get_user, etc. may sleep (of course).
They're also "user context only".

This is a hardware trap handler.  What sort of context is that?  Is
it really "user context"?  Worse, we're attempting to emulate an
*atomic* instruction (CMPXCHG).

So how do I guarantee:
(1) the original process doesn't get resumed during the sleep
(perhaps this is guaranteed by other things?)
(2) nobody else messes with the data we're messing with, so that this is
actually atomic.  (Note that we're assuming there's no SMP, because this
is an i386 and there are no known i386 SMP machines supported by Linux.
So the only problem is stuff woken during sleep.)  Basically, this means
no other process which might share the memory can be woken up during the
sleep either.  :-P

Is this possible, or hopelessly difficult?

-- 
This space intentionally left blank.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
  2004-05-25 17:03 Albert Cahalan
@ 2004-05-25 22:43 ` Alan Cox
  0 siblings, 0 replies; 29+ messages in thread
From: Alan Cox @ 2004-05-25 22:43 UTC (permalink / raw)
  To: Albert Cahalan; +Cc: linux-kernel mailing list, alan, willy, hch, macro

On Tue, May 25, 2004 at 01:03:04PM -0400, Albert Cahalan wrote:
> The important thing is to correctly handle whatever is
> generated by gcc, icc, glibc, uclibc, dietlibc, klibc,
> and newlib. Thus you can assume that you're dealing with
> a 32-bit app that doesn't play LDT games. Segment selectors
> are limited to the pthreads assembly code.

The LDT stuff isnt that hard to deal with, you can probably ignore the
16bit code segment funky stuff, but you'd need to parse things like size
prefixes.


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: i486 emu in mainline?
@ 2004-05-25 17:03 Albert Cahalan
  2004-05-25 22:43 ` Alan Cox
  0 siblings, 1 reply; 29+ messages in thread
From: Albert Cahalan @ 2004-05-25 17:03 UTC (permalink / raw)
  To: linux-kernel mailing list; +Cc: alan, willy, hch, macro

Alan Cox writes:
> On Sun, May 23, 2004 at 10:29:12AM +0200, Willy Tarreau wrote:

>> being emulated. I think it's already the case. He also
>> said that I didn't take care of the segment selectors
>> (such as SS) which some programs use perfectly legally
>> (eg Wine). I don't know how to do that.
>
> You have to parse all the valid header bytes (the opcode
> prefixes) that change segment, cause repeats and change
> sizes. DOSemu has a worked example of this particular
> set of horrors.

You don't need that in a fully general way. You might want
to detect unhandled cases and generate SIGILL.

The important thing is to correctly handle whatever is
generated by gcc, icc, glibc, uclibc, dietlibc, klibc,
and newlib. Thus you can assume that you're dealing with
a 32-bit app that doesn't play LDT games. Segment selectors
are limited to the pthreads assembly code.

Wine and DOSEMU can take care of themselves.



^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2004-10-10 20:33 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-05-22 23:40 i486 emu in mainline? Christoph Hellwig
2004-05-23  0:20 ` Rene Rebe
2004-05-23  7:13 ` Arjan van de Ven
2004-05-23  8:44   ` Willy Tarreau
2004-05-23  9:13     ` Arjan van de Ven
2004-05-23  9:48       ` Willy Tarreau
2004-05-23  9:58         ` Arjan van de Ven
2004-05-23 11:49         ` Helge Hafting
2004-05-23  9:20     ` Andrew Morton
2004-05-23 17:11     ` Brian Gerst
2004-05-24  2:47       ` Herbert Xu
2004-05-27 21:03         ` Pavel Machek
2004-05-23  8:29 ` Willy Tarreau
2004-05-23 11:08   ` Alan Cox
2004-05-23 11:57     ` Willy Tarreau
2004-05-23 13:15       ` Alan Cox
2004-05-24 15:17         ` Jan-Benedict Glaw
2004-05-24 17:41           ` Alan Cox
2004-05-25  9:36             ` Jan-Benedict Glaw
2004-05-25 13:48               ` Alan Cox
     [not found]   ` <20040523105130.GA588@samarkand.rivenstone.net>
2004-05-23 11:59     ` Willy Tarreau
2004-05-24  9:08       ` P
2004-05-23 15:18   ` Jeff Garzik
2004-05-23 21:14     ` Alan Cox
2004-05-24 12:28 ` Maciej W. Rozycki
2004-05-25 17:21 ` Kronos
2004-05-25 17:03 Albert Cahalan
2004-05-25 22:43 ` Alan Cox
2004-10-10 20:33 Nathanael Nerode

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).