Subject: Re: Wine & NetBSD?
To: None <tech-kern@netbsd.org>
From: Bang Jun-Young <bjy@mogua.org>
List: tech-kern
Date: 11/18/2001 02:59:09
--FCuugMFkClbJLl1L
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Fri, Nov 16, 2001 at 10:48:03AM +0900, Bang Jun-Young wrote:
> 1. Download Wine-20011108.tar.gz
> 2. Apply the following patch
> 3. configure & make & make install

gmake & gmake install indeed. Somebody broke BSD make compatibility
again. :(

> 4. Run wine sol.exe :)
> 
> Note: the patch was sent to wine-patches, but wasn't accepted.
> I have to prove it's not dangerous (or if it's really dangerous,
> find another way).

It's proven to be dangerous. This time I made a patch against the
kernel source, uvm_mmap.c (attached at the end of this mail).

> 
> Question: Does any MAP_FIXED mapping zap the previous mapping at
> that address? 

Yes. I wrote a small test program for that (attached).

Background: Unlike NetBSD/FreeBSD/Linux ELF binaries, most of Win32 PE
binaries are non-relocatable, and they are/should be loaded at fixed
address, 0x400000 in most cases. This is where the problem occurs:
Wine would fail if it was unable to mmap the executable image to the
specified address.

Back to NetBSD side, in normal operation NetBSD mmap(2) doesn't allow
the image to be mapped to address under the heap which starts roughly
at 0x48xxxxxx. So you have to give it MAP_FIXED to enforce mapping at
specified address. MAP_FIXED mapping, however, has a problem: it zaps
the previous mapping already established at the specified address.
It's clear that we shouldn't use MAP_FIXED in this case. That's why
my previous patch was rejected by Wine maintainers.

Linux/FreeBSD side: their manpages say the same as NetBSD one, but
implementation is different. Their mmap(2) return expected address
in most cases, so Wine doesn't have problem on them. 

Proposal: Here's a patch taken from FreeBSD. The mmap_test result is
as follows:

Before:
0x00400000
0x480f8000
0x00400000
0x480f9000

After:
0x00400000
0x00401000
0x00400000
0x00402000

Would somebody review and commit the patch? This is very important.
because Wine hardly would be able to run without it.

Jun-Young

-- 
Bang Jun-Young <bjy@mogua.org>


--FCuugMFkClbJLl1L
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="uvm_mmap.c.diff"

Index: uvm_mmap.c
===================================================================
RCS file: /cvsroot/syssrc/sys/uvm/uvm_mmap.c,v
retrieving revision 1.60
diff -u -r1.60 uvm_mmap.c
--- uvm_mmap.c	2001/11/10 07:37:00	1.60
+++ uvm_mmap.c	2001/11/16 18:39:22
@@ -347,16 +347,19 @@
 		if (addr > addr + size)
 			return (EINVAL);		/* no wrapping! */
 
-	} else {
-
-		/*
-		 * not fixed: make sure we skip over the largest possible heap.
-		 * we will refine our guess later (e.g. to account for VAC, etc)
-		 */
-
-		addr = MAX(addr, round_page((vaddr_t)p->p_vmspace->vm_daddr +
-					    MAXDSIZ));
 	}
+	/*
+	 * XXX for non-fixed mappings where no hint is provided or
+	 * the hint would fall in the potential heap space,
+	 * place it after the end of the largest possible heap.
+	 *
+	 * There should really be a pmap call to determine a reasonable
+	 * location.
+	 */
+	else if (addr == 0 ||
+	    (addr >= round_page((vaddr_t)p->p_vmspace->vm_taddr) &&
+	     addr < round_page((vaddr_t)p->p_vmspace->vm_daddr + MAXDSIZ)))
+		addr = round_page((vaddr_t)p->p_vmspace->vm_daddr + MAXDSIZ);
 
 	/*
 	 * check for file mappings (i.e. not anonymous) and verify file.

--FCuugMFkClbJLl1L
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="mmap_test.c"

#include <sys/mman.h>
#include <stdlib.h>
#include <fcntl.h>

void mmap_test(void *, int, int);

main()
{
	int fd;
		
	fd = open("/bin/ls", O_RDONLY);
	if (fd == -1)
		err(EXIT_FAILURE, NULL);
	
	mmap_test((void *)0x400000, MAP_PRIVATE | MAP_FIXED, fd);
	mmap_test((void *)0x400000, MAP_PRIVATE, fd);
	mmap_test((void *)0x400000, MAP_PRIVATE | MAP_FIXED, fd);
	mmap_test((void *)0x400000, MAP_PRIVATE, fd);
}

void
mmap_test(void *addr, int flags, int fd)
{
	addr = mmap(addr, 4096, PROT_READ, flags, fd, 0);
	if (addr == MAP_FAILED)
		err(EXIT_FAILURE, NULL);
	else
		printf("0x%08x\n", addr);
}

--FCuugMFkClbJLl1L--