[comp.unix.xenix] user doing direct I/O

usenet@carssdf.UUCP (John Watson) (07/26/90)

  Is there any way for a user to do direct (INP/OUTP) io to devices
similar to the printer port without writing a device driver?  These
instructions normally result in a protection violation.

John Watson    rutgers!carssdf!usenet

glenn@extro.ucc.su.OZ.AU (Glenn Geers) (07/27/90)

From article <251@carssdf.UUCP>, by usenet@carssdf.UUCP (John Watson):
> 
>   Is there any way for a user to do direct (INP/OUTP) io to devices
> similar to the printer port without writing a device driver?  These
> instructions normally result in a protection violation.

A lot of people would like to know how to do this. 
It turns out that it can be done on Xenix 2.2.2 and up using an ioctl. Only
root can perform the call and so programs which use it must be set uid 0.
The primary application is graphics - the ioctl is part of the graphics
stuff in Xenix. I don't think it will work under SCO UNIX for general 
(non-graphics) i/o.

Anyway, enough waffle. Here's how to do it:

/*
** I don't claim this code does anything useful.
** Do with it what you will
** I disclaim copyright
** G. Geers
*/

#include <stdio.h>
#include <sys/machdep.h>
main()
{
	int fd;

	fd = open("/dev/null", 2); /* open a useful file */
	ioctl(fd, IOPRIVL, 1); 
/*
** Guess what?
** You've just set the i/o privelege level of the current process
** to 3. You can write anywhere in the i/o address space!
** Be *careful*. Make 100% sure you have your i/o addresses correct
** otherwise you might trash your hard disk.
*/
	write_to_port();

	ioctl(fd, IOPRIVL, 0); /* reset to normal */
}

write_to_port() should be an assembler routine using ins/outs or whatever.
I use gcc so I like to embed my assembler inside C code using asm(). That
way stack frames and returns can be done easily. Also tests can be done in C
and it is possible to assign variables to specific 386 registers. If you are 
using masm you have to do this stuff yourself.

Whenever I write/port graphics applications I produce two (#ifdef'd) versions
one which doesn't write to hardware directly and one which does. For some
applications (e.g. dvivga) high speed writing of individual pixels is not
required but for others (e.g. ghostscript) it is. So I comprimise; 
security versus speed.

DISCLAIMER
Please nnote: I have *not* used this for anything except graphics so I don't
claim that it will work. And if you trash your hard disk or do anything
else nasty I'm not responsible.

			Enjoy,
				Glenn

p.s. If anyone does have courage enough to try non-graphics applications
I'd like to hear of the results

glenn@extro.ucc.su.oz.au
--
Glenn Geers                       | "So when it's over, we're back to people.
Department of Theoretical Physics |  Just to prove that human touch can have
The University of Sydney          |  no equal."
Sydney NSW 2006 Australia         |  - Basia Trzetrzelewska, 'Prime Time TV'

pgd@bbt.se (P.Garbha) (07/27/90)

In article <1990Jul26.232311.21450@metro.ucc.su.OZ.AU> glenn@extro.ucc.su.OZ.AU (Glenn Geers) writes:
>From article <251@carssdf.UUCP>, by usenet@carssdf.UUCP (John Watson):
>> 
>>   Is there any way for a user to do direct (INP/OUTP) io to devices
>> similar to the printer port without writing a device driver?  These
>> instructions normally result in a protection violation.
>
>A lot of people would like to know how to do this. 
>It turns out that it can be done on Xenix 2.2.2 and up using an ioctl. Only

I think there exist another possibility.
Create a dev file with major number 4 (same as mem), and minor numbers
according to the following list: 
3 -- for byte in/out to port
4 -- for word in/out to port
5 -- for lword in/out to port

These devices will go to i/o device space. So lseek to the address you
want to do input/output to, and read/write to one of these ports.

Now this is untested, and undocumented (at least I have not found the
documentation for it. Maybe it is there, somewhere). If someone (from SCO?)
could confirm if it is right, or wrong, it would be nice.
If this is not right, can someone tell what minor device number 3,4 &
5 actually are doing on the mem device?

jak@sactoh0.UUCP (Jay A. Konigsberg) (07/29/90)

From article <251@carssdf.UUCP>, by usenet@carssdf.UUCP (John Watson):
> 
>   Is there any way for a user to do direct (INP/OUTP) io to devices
> similar to the printer port without writing a device driver?  These
> instructions normally result in a protection violation.

A lot of people would like to know how to do this. 
It turns out that it can be done on Xenix 2.2.2 and up using an ioctl. Only

The following code works on Xenix 2.3.2 (386), Unix Sys V (3B2) and
several other Unix platforms.
	      ====

The code could use a little cleaning up, but it works as stated.
See termio(7) and ioctl(2) for further information.

--------------------------------------------------------------------------
#include <termio.h>

main()
{
struct	termio	ttyset;
unsigned short	holdvalue;
unsigned char	holdnext;

/* enter raw mode */
ioctl(0, TCGETA, &ttyset);
holdvalue=ttyset.c_lflag;
holdnext=ttyset.c_cc[4];
ttyset.c_cc[4] = (unsigned char)1;
ttyset.c_lflag &= ~ICANON;
ioctl(0, TCSETAW, &ttyset);

/* reset terminal charastics */
ttyset.c_lflag = holdvalue;
ttyset.c_cc[4] = holdnext;
ioctl(0, TCSETAW, &ttyset);
return(0);
}
-- 
-------------------------------------------------------------
Jay @ SAC-UNIX, Sacramento, Ca.   UUCP=...pacbell!sactoh0!jak
If something is worth doing, its worth doing correctly.

glenn@extro.ucc.su.OZ.AU (Glenn Geers) (07/30/90)

Yes, creating /dev/blah with major number 4 and minor number [3,4,5] works
as advertised. You lseek in to the device address and then use write or 
read as the case may be. However, you still don't get around the system
call overhead. This can only be achieved by issuing ioctl(fd, IOPRIVL, 1)
(1 system call, finished) and then banging away at i/o ports in assembler. For
*fast* graphics the latter technique is IMHO essential since even 1 system
call per pixel (you need at *least* 2 an lseek and a write or an ioctl) gives 
rise to a horrible slow down when writing coloured pixels (not a colour plane,
each pixel is a different colour).

				Glenn
--
Glenn Geers                       | "So when it's over, we're back to people.
Department of Theoretical Physics |  Just to prove that human touch can have
The University of Sydney          |  no equal."
Sydney NSW 2006 Australia         |  - Basia Trzetrzelewska, 'Prime Time TV'

chapman@sco.COM (Brian Chapman) (08/01/90)

glenn@extro.ucc.su.OZ.AU (Glenn Geers) writes:

>	<...>  However, you still don't get around the system
>call overhead. This can only be achieved by issuing ioctl(fd, IOPRIVL, 1)
>(1 system call, finished) and then banging away at i/o ports in assembler. For
>*fast* graphics <...>

Yes,  direct use of IN & OUT 386 instructions is possible from user
space after giving the [EV]GA_IOPRIVL command.  BUT...  this is
only for use with the video I/O ports.  You will find that Xenix
lets to access all I/O ports but SCO _Unix_ behaves in the more
restrictive manner.
	-- Chapman
-- 
Brian Chapman		uunet!sco!chapman
Pay no attention to the man behind the curtain!