comp.lang.ada
 help / color / mirror / Atom feed
From: ka@sorry.no.email (Kenneth Almquist)
Subject: Thoughts on the ADaOS user program interface
Date: 6 Sep 2001 14:18:04 -0400
Date: 2001-09-06T14:18:04-04:00	[thread overview]
Message-ID: <9n8eks$qsp$1@shell.monmouth.com> (raw)

I've been thinking about what the system call architecture for an
Ada OS might look like.  I would want the interface to be specified
in a collection of packages, all descendents of a package named
AdaOS or somthing similar.

The Intel x86 architecture supports procedure calls across protection
boundaries (so that user code can invoke procedures in the kernel),
but the design is not secure if you have multiple tasks because the
kernel mode procedure runs on the same stack as its caller, which
allows another task running concurrently to alter the stack frame of
the kernel mode procedure.  So calling a system procedure requires a
trap to allow us to switch to a kernel stack.  We could generate a
stub for each call which executes a trap instruction (that is what
Linux does), or we could tell the linker that the system procedures
are at addresses which are not actually mapped, and have the trap
handler invoke the actual kernel routine.

Some things are best modelled using tagged types; the obvious example
being the AdaOS analogue to UNIX file descriptors.  These will be
implemented as tagged types inside the kernel, but we also want them
to appear as tagged types to applications.  One idea is to have the
compiler implement

	pragma Separate_Tag(Tagged_Type);

which specifies that the named tagged type doesn't contain a tag
field.  Instead, pointers to Tagged_Type'Class are "fat pointers"
containing both the address of an object and its associated tag.
This allows user code to transparently use pointers to objects
which are not in the user's address space.  An alterative is to
create a "proxy" object in user space for each kernel object that
a program uses.  This complicates the interface to the kernel but
avoids compiler changes.

(Note: In addition to the use suggested here, pragma Separate_Tag
would improve the performance of types like Ada.Strings.Unbounded,
where a tagged type is required but the tag is rarely used.  When this
pragma is applied to a type, it is not possible to redispatch in the
primitive subprograms for that type, because that would require using
the tag in a context where there is no class-wide pointer to the
object.)

The UNIX ioctl system call bypasses the C type system.  Using tagged
types lets us provide similar functionality while staying within the
Ada type system.  Code that operates on tty devices might look like:

	if F in Tty_Devices then
	    Tty = Tty_Devices(F);
	    Get_Terminal_Modes(Tty, Modes);
	    ...
	end if;

Furthermore, users can implement their own data types which have the
same interface as system types, and use their types interchangably
with system types.  So you can write versions of the "file" data
type that do things like perform compression or read/write to
in-memory data structures rather than files, without involving
the operating system.  Contrast this to UNIX, where a file descriptor
can refer to a variety of entities, but extending this set requires
kernel modifications.

Error reporting should be done by throwing exceptions with a descriptive
error message attached.  My experience is that more often than not,
if a system call fails the program logic doesn't care why it fails.
Once the error is reported or logged, the recovery action is the same.
Therefore, I would suggest that exceptions be defined which relate to
the type of operation which failed, rather than the reason the operation
failed.  The exception message associated with the exception should
consist of an error code followed by descriptive text.  The error code
allows a program to take actions that depend on the precise reason
that an operation failed, when this is necessary.  It also simplifies
the task of converting error messages to a language other than English.

There should be a stub generator to create the linkage code to allow
kernel subroutines to be called from user mode.  The linkage code
needs to handle arguments as follows:

 *  Parameters passed by value (e.g. integers) need to be copied
    into kernel space.

 *  Parameters passed by reference do not need to be copied
    (assuming that the address mapping is set up appropriately
    so that user data can be read and written from kernel mode),
    but the address of the data has to be validated to ensure
    that it actually is used data and not kernel data.  Also,
    the bounds of an array or string need to be copied into
    kernel space so that they don't change after address validation
    is performed.

 *  Pointers to kernel data structures need to be validated to
    ensure that they actually point to an object of the appropriate
    type.  It is probably most efficient to make the pointer value
    used in user space actually be an index into a table of kernel
    objects.  The validation process would look up the actual kernel
    address in this table.

An initial implementation of these ideas could be done by adding
code to Linux or BSD.  This would allow an initial implementation
to be put together fairly quickly, allowing experience to be gained.
				Kenneth Almquist



             reply	other threads:[~2001-09-06 18:18 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2001-09-06 18:18 Kenneth Almquist [this message]
2001-09-07  8:24 ` Thoughts on the ADaOS user program interface Dmitry Kazakov
2001-09-07 16:48 ` Warren W. Gay VE3WWG
2001-09-07 19:35   ` David Starner
2001-09-08 11:42   ` Florian Weimer
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox