From owner-svn-src-stable-8@FreeBSD.ORG Tue Jun 1 21:19:58 2010 Return-Path: Delivered-To: svn-src-stable-8@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id BBC7D106566B; Tue, 1 Jun 2010 21:19:58 +0000 (UTC) (envelope-from attilio@FreeBSD.org) Received: from svn.freebsd.org (unknown [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id A5B398FC1B; Tue, 1 Jun 2010 21:19:58 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o51LJwAu048290; Tue, 1 Jun 2010 21:19:58 GMT (envelope-from attilio@svn.freebsd.org) Received: (from attilio@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o51LJw0d048280; Tue, 1 Jun 2010 21:19:58 GMT (envelope-from attilio@svn.freebsd.org) Message-Id: <201006012119.o51LJw0d048280@svn.freebsd.org> From: Attilio Rao Date: Tue, 1 Jun 2010 21:19:58 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r208723 - in stable/8: share/man/man4 sys/amd64/amd64 sys/amd64/include sys/dev/io sys/i386/i386 sys/i386/include sys/ia64/ia64 sys/ia64/include X-BeenThere: svn-src-stable-8@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for only the 8-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 01 Jun 2010 21:19:58 -0000 Author: attilio Date: Tue Jun 1 21:19:58 2010 New Revision: 208723 URL: http://svn.freebsd.org/changeset/base/208723 Log: MFC r207329, r208716: - Extract the IODEV_PIO interface from ia64 and make it MI. - On i386 and amd64 the old behaviour is kept but multithreaded processes must use the new interface in order to work well. - Support for the other architectures is greatly improved. Sponsored by: Sandvine Incorporated Approved by: re (kib, bz) Added: stable/8/sys/dev/io/iodev.h - copied unchanged from r207329, head/sys/dev/io/iodev.h Modified: stable/8/share/man/man4/io.4 stable/8/sys/amd64/amd64/io.c stable/8/sys/amd64/include/iodev.h stable/8/sys/dev/io/iodev.c stable/8/sys/i386/i386/io.c stable/8/sys/i386/include/iodev.h stable/8/sys/ia64/ia64/iodev_machdep.c stable/8/sys/ia64/include/iodev.h Directory Properties: stable/8/share/man/man4/ (props changed) stable/8/sys/ (props changed) stable/8/sys/amd64/include/xen/ (props changed) stable/8/sys/cddl/contrib/opensolaris/ (props changed) stable/8/sys/contrib/dev/acpica/ (props changed) stable/8/sys/contrib/pf/ (props changed) stable/8/sys/dev/xen/xenpci/ (props changed) stable/8/sys/geom/sched/ (props changed) Modified: stable/8/share/man/man4/io.4 ============================================================================== --- stable/8/share/man/man4/io.4 Tue Jun 1 21:15:05 2010 (r208722) +++ stable/8/share/man/man4/io.4 Tue Jun 1 21:19:58 2010 (r208723) @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 8, 2010 +.Dd June 01, 2010 .Dt IO 4 .Os .Sh NAME @@ -35,32 +35,89 @@ .Nd I/O privilege file .Sh SYNOPSIS .Cd "device io" +.Pp +.In sys/types.h +.In sys/ioctl.h +.In dev/io/iodev.h +.In machine/iodev.h +.Pp +.Bd -literal +struct iodev_pio_req { + u_int access; + u_int port; + u_int width; + u_int val; +}; .Sh DESCRIPTION The special file .Pa /dev/io is a controlled security hole that allows a process to gain I/O privileges (which are normally reserved for kernel-internal code). -Any process that holds a file descriptor on -.Pa /dev/io -open will get its -.Em IOPL -bits in the flag register set, thus allowing it to perform direct -I/O operations. This can be useful in order to write userland programs that handle some hardware directly. -Note that even read-only access will grant the full I/O privileges. +.Pp +The usual operations on the device are to open it via the +.Xr open 2 +interface and to send I/O requests to the file descriptor using the +.Xr ioctl 2 +syscall. +.Pp +The +.Xr ioctl 2 +requests available for +.Pa /dev/io +are mostly platform dependent, but there are also some in common between +all of them. +The +.Dv IODEV_PIO +is used by all the architectures in order to request that an I/O operation +be performed. It takes a 'struct iodev_pio_req' argument +that must be previously setup. +.Pp +The +.Fa access +member specifies the type of operation requested. It may be: +.Bl -tag -width IODEV_PIO_WRITE +.It Dv IODEV_PIO_READ +The operation is an "in" type. A value will be read from the specified port +(retrieved from the +.Fa port +member) and the result will be stored in the +.Fa val +member. +.It Dv IODEV_PIO_WRITE +The operation is a "out" type. The value will be fetched from the +.Fa val +member and will be written out to the specified port (defined as the +.Fa port +member). +.El +.Pp +Finally, the +.Fa width +member specifies the size of the operand to be read/written, expressed +in bytes. .Pp In addition to any file access permissions on .Pa /dev/io , the kernel enforces that only the super-user may open this device. -.Sh FILES -.Bl -tag -width Pa -compact -.It Pa /dev/io -.El +.Sh LEGACY +The +.Pa /dev/io +interface used to be very i386 specific and worked differently. The initial +implementation, in fact, simply raised the +.Em IOPL +of the current thread when +.Xr open 2 +was called on the file. This behaviour is retained in the current +implementation as legacy support for both i386 and amd64 architectures. .Sh SEE ALSO +.Xr close 2 , .Xr i386_get_ioperm 2 , .Xr i386_set_ioperm 2 , +.Xr ioctl 2 , +.Xr open 2 , .Xr mem 4 .Sh HISTORY The Modified: stable/8/sys/amd64/amd64/io.c ============================================================================== --- stable/8/sys/amd64/amd64/io.c Tue Jun 1 21:15:05 2010 (r208722) +++ stable/8/sys/amd64/amd64/io.c Tue Jun 1 21:19:58 2010 (r208723) @@ -28,60 +28,32 @@ __FBSDID("$FreeBSD$"); #include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include #include -#include -#include - -#include -#include - #include +#include -/* ARGSUSED */ int -ioopen(struct cdev *dev __unused, int flags __unused, int fmt __unused, - struct thread *td) +iodev_open(struct thread *td) { - int error; - - error = priv_check(td, PRIV_IO); - if (error != 0) - return (error); - error = securelevel_gt(td->td_ucred, 0); - if (error != 0) - return (error); td->td_frame->tf_rflags |= PSL_IOPL; - return (0); } -/* ARGSUSED */ int -ioclose(struct cdev *dev __unused, int flags __unused, int fmt __unused, - struct thread *td) +iodev_close(struct thread *td) { - td->td_frame->tf_rflags &= ~PSL_IOPL; + td->td_frame->tf_rflags &= ~PSL_IOPL; return (0); } /* ARGSUSED */ int -ioioctl(struct cdev *dev __unused, u_long cmd __unused, caddr_t data __unused, - int fflag __unused, struct thread *td __unused) +iodev_ioctl(u_long cmd __unused, caddr_t data __unused) { - return (ENXIO); + return (ENOIOCTL); } Modified: stable/8/sys/amd64/include/iodev.h ============================================================================== --- stable/8/sys/amd64/include/iodev.h Tue Jun 1 21:15:05 2010 (r208722) +++ stable/8/sys/amd64/include/iodev.h Tue Jun 1 21:19:58 2010 (r208723) @@ -25,7 +25,22 @@ * * $FreeBSD$ */ +#ifndef _MACHINE_IODEV_H_ +#define _MACHINE_IODEV_H_ -d_open_t ioopen; -d_close_t ioclose; -d_ioctl_t ioioctl; +#ifdef _KERNEL +#include + +#define iodev_read_1 inb +#define iodev_read_2 inw +#define iodev_read_4 inl +#define iodev_write_1 outb +#define iodev_write_2 outw +#define iodev_write_4 outl + +int iodev_open(struct thread *td); +int iodev_close(struct thread *td); +int iodev_ioctl(u_long cmd, caddr_t data); + +#endif /* _KERNEL */ +#endif /* _MACHINE_IODEV_H_ */ Modified: stable/8/sys/dev/io/iodev.c ============================================================================== --- stable/8/sys/dev/io/iodev.c Tue Jun 1 21:15:05 2010 (r208722) +++ stable/8/sys/dev/io/iodev.c Tue Jun 1 21:19:58 2010 (r208723) @@ -30,22 +30,27 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include -#include -#include +#include #include -#include +#include #include -#include #include -#include - -#include -#include #include +#include + +static int ioopen(struct cdev *dev, int flags, int fmt, + struct thread *td); +static int ioclose(struct cdev *dev, int flags, int fmt, + struct thread *td); +static int ioioctl(struct cdev *dev, u_long cmd, caddr_t data, + int fflag, struct thread *td); + +static int iopio_read(struct iodev_pio_req *req); +static int iopio_write(struct iodev_pio_req *req); + static struct cdev *iodev; static struct cdevsw io_cdevsw = { @@ -58,6 +63,129 @@ static struct cdevsw io_cdevsw = { /* ARGSUSED */ static int +ioopen(struct cdev *dev __unused, int flags __unused, int fmt __unused, + struct thread *td) +{ + int error; + + error = priv_check(td, PRIV_IO); + if (error != 0) + return (error); + error = securelevel_gt(td->td_ucred, 0); + if (error != 0) + return (error); + error = iodev_open(td); + + return (error); +} + +/* ARGSUSED */ +static int +ioclose(struct cdev *dev __unused, int flags __unused, int fmt __unused, + struct thread *td) +{ + + return (iodev_close(td)); +} + +/* ARGSUSED */ +static int +ioioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, + int fflag __unused, struct thread *td __unused) +{ + struct iodev_pio_req *pio_req; + int error; + + switch (cmd) { + case IODEV_PIO: + pio_req = (struct iodev_pio_req *)data; + switch (pio_req->access) { + case IODEV_PIO_READ: + error = iopio_read(pio_req); + break; + case IODEV_PIO_WRITE: + error = iopio_write(pio_req); + break; + default: + error = EINVAL; + break; + } + break; + default: + error = iodev_ioctl(cmd, data); + } + + return (error); +} + +static int +iopio_read(struct iodev_pio_req *req) +{ + + switch (req->width) { + case 1: + req->val = iodev_read_1(req->port); + break; + case 2: + if (req->port & 1) { + req->val = iodev_read_1(req->port); + req->val |= iodev_read_1(req->port + 1) << 8; + } else + req->val = iodev_read_2(req->port); + break; + case 4: + if (req->port & 1) { + req->val = iodev_read_1(req->port); + req->val |= iodev_read_2(req->port + 1) << 8; + req->val |= iodev_read_1(req->port + 3) << 24; + } else if (req->port & 2) { + req->val = iodev_read_2(req->port); + req->val |= iodev_read_2(req->port + 2) << 16; + } else + req->val = iodev_read_4(req->port); + break; + default: + return (EINVAL); + } + + return (0); +} + +static int +iopio_write(struct iodev_pio_req *req) +{ + + switch (req->width) { + case 1: + iodev_write_1(req->port, req->val); + break; + case 2: + if (req->port & 1) { + iodev_write_1(req->port, req->val); + iodev_write_1(req->port + 1, req->val >> 8); + } else + iodev_write_2(req->port, req->val); + break; + case 4: + if (req->port & 1) { + iodev_write_1(req->port, req->val); + iodev_write_2(req->port + 1, req->val >> 8); + iodev_write_1(req->port + 3, req->val >> 24); + } else if (req->port & 2) { + iodev_write_2(req->port, req->val); + iodev_write_2(req->port + 2, req->val >> 16); + } else + iodev_write_4(req->port, req->val); + break; + default: + return (EINVAL); + } + + return (0); +} + +/* ARGSUSED */ +static int io_modevent(module_t mod __unused, int type, void *data __unused) { switch(type) { Copied: stable/8/sys/dev/io/iodev.h (from r207329, head/sys/dev/io/iodev.h) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/8/sys/dev/io/iodev.h Tue Jun 1 21:19:58 2010 (r208723, copy of r207329, head/sys/dev/io/iodev.h) @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2010 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_IODEV_H_ +#define _DEV_IODEV_H_ + +#define IODEV_PIO_READ 0 +#define IODEV_PIO_WRITE 1 + +struct iodev_pio_req { + u_int access; + u_int port; + u_int width; + u_int val; +}; + +#define IODEV_PIO _IOWR('I', 0, struct iodev_pio_req) + +#endif /* _DEV_IODEV_H_ */ Modified: stable/8/sys/i386/i386/io.c ============================================================================== --- stable/8/sys/i386/i386/io.c Tue Jun 1 21:15:05 2010 (r208722) +++ stable/8/sys/i386/i386/io.c Tue Jun 1 21:19:58 2010 (r208723) @@ -28,60 +28,32 @@ __FBSDID("$FreeBSD$"); #include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include #include -#include -#include - -#include -#include - #include +#include -/* ARGSUSED */ int -ioopen(struct cdev *dev __unused, int flags __unused, int fmt __unused, - struct thread *td) +iodev_open(struct thread *td) { - int error; - - error = priv_check(td, PRIV_IO); - if (error != 0) - return (error); - error = securelevel_gt(td->td_ucred, 0); - if (error != 0) - return (error); td->td_frame->tf_eflags |= PSL_IOPL; - return (0); } -/* ARGSUSED */ int -ioclose(struct cdev *dev __unused, int flags __unused, int fmt __unused, - struct thread *td) +iodev_close(struct thread *td) { - td->td_frame->tf_eflags &= ~PSL_IOPL; + td->td_frame->tf_eflags &= ~PSL_IOPL; return (0); } /* ARGSUSED */ int -ioioctl(struct cdev *dev __unused, u_long cmd __unused, caddr_t data __unused, - int fflag __unused, struct thread *td __unused) +iodev_ioctl(u_long cmd __unused, caddr_t data __unused) { - return (ENXIO); + return (ENOIOCTL); } Modified: stable/8/sys/i386/include/iodev.h ============================================================================== --- stable/8/sys/i386/include/iodev.h Tue Jun 1 21:15:05 2010 (r208722) +++ stable/8/sys/i386/include/iodev.h Tue Jun 1 21:19:58 2010 (r208723) @@ -25,7 +25,22 @@ * * $FreeBSD$ */ +#ifndef _MACHINE_IODEV_H_ +#define _MACHINE_IODEV_H_ -d_open_t ioopen; -d_close_t ioclose; -d_ioctl_t ioioctl; +#ifdef _KERNEL +#include + +#define iodev_read_1 inb +#define iodev_read_2 inw +#define iodev_read_4 inl +#define iodev_write_1 outb +#define iodev_write_2 outw +#define iodev_write_4 outl + +int iodev_open(struct thread *td); +int iodev_close(struct thread *td); +int iodev_ioctl(u_long cmd, caddr_t data); + +#endif /* _KERNEL */ +#endif /* _MACHINE_IODEV_H_ */ Modified: stable/8/sys/ia64/ia64/iodev_machdep.c ============================================================================== --- stable/8/sys/ia64/ia64/iodev_machdep.c Tue Jun 1 21:15:05 2010 (r208722) +++ stable/8/sys/ia64/ia64/iodev_machdep.c Tue Jun 1 21:19:58 2010 (r208723) @@ -40,61 +40,33 @@ __FBSDID("$FreeBSD$"); #include #include -static int iodev_pio_read(struct iodev_pio_req *req); -static int iodev_pio_write(struct iodev_pio_req *req); - static int iodev_efivar_getvar(struct iodev_efivar_req *req); static int iodev_efivar_nextname(struct iodev_efivar_req *req); static int iodev_efivar_setvar(struct iodev_efivar_req *req); /* ARGSUSED */ int -ioopen(struct cdev *dev __unused, int flags __unused, int fmt __unused, - struct thread *td) +iodev_open(struct thread *td __unused) { - int error; - - error = priv_check(td, PRIV_IO); - if (error == 0) - error = securelevel_gt(td->td_ucred, 0); - return (error); + return (0); } /* ARGSUSED */ int -ioclose(struct cdev *dev __unused, int flags __unused, int fmt __unused, - struct thread *td __unused) +iodev_close(struct thread *td __unused) { return (0); } -/* ARGSUSED */ int -ioioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, - int fflag __unused, struct thread *td __unused) +iodev_ioctl(u_long cmd, caddr_t data) { struct iodev_efivar_req *efivar_req; - struct iodev_pio_req *pio_req; int error; - error = ENOIOCTL; switch (cmd) { - case IODEV_PIO: - pio_req = (struct iodev_pio_req *)data; - switch (pio_req->access) { - case IODEV_PIO_READ: - error = iodev_pio_read(pio_req); - break; - case IODEV_PIO_WRITE: - error = iodev_pio_write(pio_req); - break; - default: - error = EINVAL; - break; - } - break; case IODEV_EFIVAR: efivar_req = (struct iodev_efivar_req *)data; efivar_req->result = 0; /* So it's well-defined */ @@ -113,75 +85,11 @@ ioioctl(struct cdev *dev __unused, u_lon break; } break; - } - - return (error); -} - -static int -iodev_pio_read(struct iodev_pio_req *req) -{ - - switch (req->width) { - case 1: - req->val = bus_space_read_io_1(req->port); - break; - case 2: - if (req->port & 1) { - req->val = bus_space_read_io_1(req->port); - req->val |= bus_space_read_io_1(req->port + 1) << 8; - } else - req->val = bus_space_read_io_2(req->port); - break; - case 4: - if (req->port & 1) { - req->val = bus_space_read_io_1(req->port); - req->val |= bus_space_read_io_2(req->port + 1) << 8; - req->val |= bus_space_read_io_1(req->port + 3) << 24; - } else if (req->port & 2) { - req->val = bus_space_read_io_2(req->port); - req->val |= bus_space_read_io_2(req->port + 2) << 16; - } else - req->val = bus_space_read_io_4(req->port); - break; - default: - return (EINVAL); - } - - return (0); -} - -static int -iodev_pio_write(struct iodev_pio_req *req) -{ - - switch (req->width) { - case 1: - bus_space_write_io_1(req->port, req->val); - break; - case 2: - if (req->port & 1) { - bus_space_write_io_1(req->port, req->val); - bus_space_write_io_1(req->port + 1, req->val >> 8); - } else - bus_space_write_io_2(req->port, req->val); - break; - case 4: - if (req->port & 1) { - bus_space_write_io_1(req->port, req->val); - bus_space_write_io_2(req->port + 1, req->val >> 8); - bus_space_write_io_1(req->port + 3, req->val >> 24); - } else if (req->port & 2) { - bus_space_write_io_2(req->port, req->val); - bus_space_write_io_2(req->port + 2, req->val >> 16); - } else - bus_space_write_io_4(req->port, req->val); - break; default: - return (EINVAL); + error = ENOIOCTL; } - return (0); + return (error); } static int Modified: stable/8/sys/ia64/include/iodev.h ============================================================================== --- stable/8/sys/ia64/include/iodev.h Tue Jun 1 21:15:05 2010 (r208722) +++ stable/8/sys/ia64/include/iodev.h Tue Jun 1 21:19:58 2010 (r208723) @@ -31,22 +31,16 @@ #include -struct iodev_pio_req { - u_int access; -#define IODEV_PIO_READ 0 -#define IODEV_PIO_WRITE 1 - u_int port; - u_int width; - u_int val; -}; - -#define IODEV_PIO _IOWR('I', 0, struct iodev_pio_req) +#ifdef _KERNEL +#include +#endif -struct iodev_efivar_req { - u_int access; #define IODEV_EFIVAR_GETVAR 0 #define IODEV_EFIVAR_NEXTNAME 1 #define IODEV_EFIVAR_SETVAR 2 + +struct iodev_efivar_req { + u_int access; u_int result; /* errno value */ size_t namesize; u_short *name; /* UCS-2 */ @@ -59,11 +53,16 @@ struct iodev_efivar_req { #define IODEV_EFIVAR _IOWR('I', 1, struct iodev_efivar_req) #ifdef _KERNEL +#define iodev_read_1 bus_space_read_io_1 +#define iodev_read_2 bus_space_read_io_2 +#define iodev_read_4 bus_space_read_io_4 +#define iodev_write_1 bus_space_write_io_1 +#define iodev_write_2 bus_space_write_io_2 +#define iodev_write_4 bus_space_write_io_4 + +int iodev_open(struct thread *td); +int iodev_close(struct thread *td); +int iodev_ioctl(u_long, caddr_t data); -d_open_t ioopen; -d_close_t ioclose; -d_ioctl_t ioioctl; - -#endif - +#endif /* _KERNEL */ #endif /* _MACHINE_IODEV_H_ */