Subject: kern/5693: linux emulation: partial mremap(2) support (for Quake2)
To: None <gnats-bugs@gnats.netbsd.org>
From: Urban Boquist <boquist@cs.chalmers.se>
List: netbsd-bugs
Date: 07/02/1998 23:37:03
>Number:         5693
>Category:       kern
>Synopsis:       linux system call mremap is missing
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Jul  2 14:50:01 1998
>Last-Modified:
>Originator:     Urban Boquist
>Organization:
Dept. of CS, Chalmers, Sweden
>Release:        NetBSD-current June 1998
>Environment:
System: NetBSD dogbert.cs.chalmers.se 1.3E NetBSD 1.3E (DOGBERT) #0: Thu Mar 12 10:45:34 CET 1998 augustss@dogbert.cs.chalmers.se:/usr/src/sys/arch/i386/compile/DOGBERT i386

>Description:
The current linux emulation includes only a stub for the mremap system
call (it just returns ENOMEM). It is very easy to implement "half" of
mremap, the case when the mapped area is shrinking. The patch below
implements this. The other way around, a growing area, is harder.

With this patch I can successfully play linux Quake2. It works
perfectly, with sound, CD music, everything! ;-)

>How-To-Repeat:
Try linux Quake2 and watch it die.
>Fix:
--- src/sys/compat/linux/linux_misc.c	Tue Mar 24 13:19:43 1998
+++ src2/sys/compat/linux/linux_misc.c	Thu Jul  2 12:30:07 1998
@@ -519,16 +519,36 @@
 	void *v;
 	register_t *retval;
 {
-#ifdef notyet
 	struct linux_sys_mremap_args /* {
 		syscallarg(void *) old_address;
 		syscallarg(size_t) old_size;
 		syscallarg(size_t) new_size;
 		syscallarg(u_long) flags;
 	} */ *uap = v;
-#endif
+	struct sys_munmap_args mua;
+	int error;
 
-	return ENOMEM;
+	SCARG(uap, old_size) = round_page(SCARG(uap, old_size));
+	SCARG(uap, new_size) = round_page(SCARG(uap, new_size));
+
+	/*
+	 * XXX We handle only shrinking remaps (linux always allows this).
+	 */
+	if (SCARG(uap, new_size) > SCARG(uap, old_size)) {
+	    retval[0] = 0;
+	    return ENOMEM;
+	}
+
+	if (SCARG(uap, new_size) < SCARG(uap, old_size)) {
+	    SCARG(&mua, addr) = SCARG(uap, old_address) + SCARG(uap, new_size);
+	    SCARG(&mua, len) = SCARG(uap, old_size) - SCARG(uap, new_size);
+	    error = sys_munmap(p, &mua, retval);
+	    retval[0] = error ? 0 : (unsigned)SCARG(uap, old_address);
+	    return error;
+	}
+
+	retval[0] = (unsigned)SCARG(uap, old_address);
+	return 0;	
 }
 
 int
>Audit-Trail:
>Unformatted: