From owner-freebsd-ppc Thu Jul 18 1: 8:45 2002 Delivered-To: freebsd-ppc@freebsd.org Received: from mx1.FreeBSD.org (mx1.FreeBSD.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 4EDB837B400 for ; Thu, 18 Jul 2002 01:08:42 -0700 (PDT) Received: from gt3.OntheNet.com.au (nt.com.au [203.13.70.61]) by mx1.FreeBSD.org (Postfix) with ESMTP id 5576243E65 for ; Thu, 18 Jul 2002 01:08:40 -0700 (PDT) (envelope-from peterg@ptree32.com.au) Received: from ptree32.com.au (CPE-203-45-246-228.qld.bigpond.net.au [203.45.246.228]) by gt3.OntheNet.com.au (8.11.4/8.11.4) with ESMTP id g6I8ATb42480 for ; Thu, 18 Jul 2002 18:10:29 +1000 (EST) Message-ID: <3D367B81.511172C@ptree32.com.au> Date: Thu, 18 Jul 2002 18:25:37 +1000 From: Peter Grehan Organization: Ptree32 Pty Ltd X-Mailer: Mozilla 4.79 [en] (X11; U; Linux 2.2.14-12 i686) X-Accept-Language: en MIME-Version: 1.0 To: freebsd-ppc@freebsd.org Subject: Long-winded 32-bit syscalls, 64-bit retval explanation Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Sender: owner-freebsd-ppc@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG Given that FreeBSD runs on 32 and 64-bit little-endian, and 64-bit big-endian systems, I had thought that most endian and word-size related issues would have been discovered. But, I found a problem that is peculiar to 32-bit big-endian systems. There are a number of pseudo-syscalls that actually use __syscall(), since they have 64-bit parameters. mmap, lseek, ftruncate - basically, any call that has an off_t parameter. The issue is that __syscall() is defined as returning a 64-bit value. Most of the pseudo-syscalls are declared as 32-bit retvals, and either cast the __syscall return value or implicitly chop it. e.g. for mmap(), return((void *)(long)__syscall((quad_t)SYS_mmap, addr, len, prot, flags, fd, 0, offset)); In the kernel, 32-bit return values are placed into td->td_retval[0]. For 32-bit syscalls on ppc, the value is placed into r3 in the trapframe and everything works fine. However, for a 64-bit return, the ppc calling convention uses r3 for the high word, and r4 for the low word. For the __syscall() clients, this results in the return value coming back with incorrect word order, with the 32-bit actual result being discarded by the cast. Note that on i386, this problem doesn't show up, since the 32-bit value and the low word of the 64-bit value are in the same location. A true 64-bit return, such as lseek(), actually works correctly, since it's code treats &td->td_retval[0] as a pointer to where the result should be written, and the word order turns out correct. *(off_t *)(td->td_retval) = fp->f_offset; syscall() could fudge the registers, but it doesn't have enough information to determine if it's calling a 32- or 64-bit retval. I added the following ugly code which has hard-coded knowledge of __syscall users: switch (error) { case 0: if ((frame->fixreg[0] == SYS___syscall) && (code != SYS_lseek)) { /* * 64-bit return, 32-bit syscall. Fixup byte order */ frame->fixreg[FIRSTARG] = 0; frame->fixreg[FIRSTARG + 1] = td->td_retval[0]; } else { frame->fixreg[FIRSTARG] = td->td_retval[0]; frame->fixreg[FIRSTARG + 1] = td->td_retval[1]; } There are two ways to do a cleaner fix for this: either use a constant to index into the retval array e.g. td->td_retval[LOWORD], or to add a parameter to syscalls.master to indicate the size of the return value. Any other opinions ? Note that for error returns, this isn't an issue, since the libc .cerror routine can always use r3 to hold the E* value. later, Peter. To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-ppc" in the body of the message