Software portal on keep-cool.org

[ Home | Downloads | Software: [ animals | ckport | YIFF ] ]


YIFF Documentation

This document describes YIFF in general as seen by the user of libYIFF. libYIFFc has it's own documentation and is not subject of this document.

Overview -- How does YIFF work in general?

YIFF defines a standard structure for all kernel calls. libYIFF provides it as C structure (yiff_call_t). If the process want to call the kernel it fills this structure with the parameters for the call and calls the kernel by calling yiff_call() (or yiff_call_mapped()). libYIFF itself will call yiff_backend_call(). yiff_backend_call() is the CPU specific function doing entering the kernel.

Also there is a way for the kernel to call the process. In order to do this the application tells (as part of the startup process) the kernel the address of a function called masterast. This function is set using yiff_set_masterast(). This is normally done by the c runtime (for example libYIFFc).

This way of being called by the kernel works exactly the same as calling the kernel just othe other way: The kernel calls the masterast function in your process and passes you a full YIFF call structure.

This way the kernel can send signals to your process and similar stuff. As this interface is symmetric this can also be used to implement parts of the interface (some majors, see below) in the user land. Usages for this may be for example filesystems just like FUSE does on GNU/Linux.

The call structure

The call structure contains of diffrent members. Not all of them needs to be passed between userland and kernel all the time so the CPU depending YIFF backend can do some optimizing on how to pass data (for example using registers vs. memory (stack) passing).

The following table lists all members. "S" in the passing column stands for sender, "R" for receiver and tells if the member needs to be send by the sender or needs to be send by the hypervisor (kernel) to the receiver. This is important for providing a optimized backend function.

Member Type Passing (Call) Passing (Answer) Description
major major S: Yes, R: Yes S: No, R: No The major is the ID of the module a function is in while the minor is the ID for the function itself. for example the major may be (the numerical ID for) "io" and the minor (the numerical ID for) "read" for read(). major and minor have sizes so they can be passed using one register on most systems.
minor minor S: Yes, R: Yes S: No, R: No
requestor pid S: No, R: Yes S: No, R: No This is the process id of the sending process.
receiver pid S: if none zero, R: No S: No, R: Yes This is the process id of the receiving process. The value of 0 is used if the request should be handled by the process registered for the given major (normally the kernel).
flags flags S: backend depending, R: Yes S: backend depending, R: Yes Flags including information of the argument usage.
error sint_least16 S: No, R: No S: if non zero, R: Yes An error generated by the function. This is to set errno or similar.
arg0, arg1, arg2 arg S: depends on flags, R: depends on flags S: No, R: No The Arguments for the system call. arg is a union type. Which and how args are used is defined by the flags members settings.
ret arg S: No, R: No S: depends on flags, R: depends on flags The return value of the function.

In addition to the call structure there is the return value for the call function which needs to be passed. It is only passed on answer. libYIFF declares this as yiff_error_t. The type is signed and must be at least 16 bits big. The backend have to convert it to yiff_error_t.

The flags parameter

The flags parameter is 16 bits big and stores usage information on the return value and arguments as the following table shows:

Bit
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Reserved for future use, must be zero YIFFAsyncron YIFFError Type of arg2 Type of arg1 Type of arg0 Type of ret
YIFFAsyncron flag

The YIFFAsyncron flag is used to tell the backend a asyncronus operation should be started. If set the yiff call returns as soon as the call is queued by the hypervisor. The call object must say valid untill the call is complet. The completion of the call is signalized by setting this flag to zero by the backend.

YIFFError flag

The YIFFError flag is set if the call could not sucessfully be completed. This is the case if the return value of the YIFF call (not of the called function) is not YIFF_ERR_NONE (non zero). This bit can be used by the backend to optimized parameter passing. If not used by the backend libYIFF will set it in case of error.

Types of argument/return value usage
Type MSB LSB
Unused 0 0
Data 0 1
Address 1 0
Reserved 1 1

The error value

The error value is the error happeing within a function. Possible error values are defined in <YIFF/error.h>. This is not used to tell if a function or backend does not exist. For this the return value of the call itself is used. Setting this to YIFF_ERRNO_NOSYS (defined in <YIFF/error.h>) does only make sense if the function exists but some other function the function depends on does not exists. If a function does not exist the call itself should return YIFF_ERR_NOSYS (defined in <YIFF.h>).

Data type for arguments and return value

The type arg (libYIFF: yiff_arg_t) is a union type with contains the following members:

Member Type
vp void *
reg register
ureg uregister
sreg sregister
major major
sint_least16 sint_least16
uint_least16 uint_least16
ssize ssize
usize usize
id identifier

Profiles

Profiles are variants of YIFF used so that the YIFF specification can match as close as possible the architecture's features and requirements. There are currently 4 diffrent profiles: tiny, small, large and huge. Large is the most used profile. It is targeted for desktop like and similar features systems. Huge is for mainframes, small for small but still powerfull devices like cell phones and tiny is for very small embedded systems.

Basically the rule of thumb is: tiny for 8 bit systems, small for 16 and small 32 bit systems, large for 32 and 64 bit systems and huge for strong 64 bit systems and 'better'. The following table shows the list of architectures for which this is already defined:

Architecture Register size in bits Profile
AMD64 strange Large
AVR 8 Tiny
Alpha 64 Large
ix86 strange Large

Data types

The following data types are defined in YIFF. Values in "()" are recommendations.

Type Attribues Size in bits on profile Description
Tiny Small Large Huge
sregister signed 8 >= 16 >= 32 >= 64 This is the type used for most numerical values. It should have the size of a architecture's general purpose register.
uregister unsigned 8 >= 16 >= 32 >= 64 The same as sregister just unsigned.
register Alias to uregister
sint_least16 signed >= 16 (16) >= 16 (16) >= 16 (32) >= 16 (32/64) This type is used like sregister just that it has a minimum size of 16 bits. The actual size should be chosen to match the register size and CPU's introduction set. (accessable with single introductions).
uint_least16 unsigned Unsigned version of sint_least16
major signed 8 8 16 16 Used to store YIFF major IDs.
minor signed 8 8 16 16 Used to store YIFF minor IDs.
ssize signed 16 32 64 128 This is used to store all kind of sizes which may also be negative. It is used by most IO and memory functions to store return values. Not that this size is defined as signed. Unlike POSIX (which does not define ssize_t as signed) this type is abled to store the full range of negative numbers, not only -1.
usize unsigned 16 32 64 128 Used to store sizes which can not be negative. This is used by most IO and memory functions to store the size of some object in arguements.
identifier signed 16 32 64 128 This is used for a system-global unique identifier.
pid Alias to identifier This is like identifier but only process IDs are allowed to store in here.
flags unsigned 16 16 16 16 Used to store flags of YIFF calls.
error signed >= 16 >= 16 >= 16 >= 16 Used as return type of YIFF calls.

Major IDs

Major IDs are used in YIFF to select a given module or interface. The Major IDs are unique at runtime. Each Major ID has a corresponding name which is unique, too. The numercal IDs are not defined by specification. They are assigned dynamically by the hypervisor. The only exception is Major ID 0 which is assigned to Major "core". This major is used to get the names for all other majors.

To make this simpler for the developer libYIFF provides a so called mapped mode in which it does the lookup transparently. This is used by yiff_mcall_t and yiff_call_mapped(). However this only works for common modules (see <YIFF.h> for the current list).

Here is a list of common majors with description. The column MM shows if this is available using the mapped interface of libYIFF (as of the time of writing this document).

Major name MM Description
core Yes Basic YIFF functions (mainly needed to lookup other majors and to set masterast).
memory Yes Memory management (allocating, deallocating, locking, ...).
proc Yes Process management (getpid(), kill(), exit(), ...).
time Yes Time functions (time(), alarm(), gettimeofday(), ...).
io Yes General IO functions (read(), write(), close(), ...).
fs Yes Filesystem functions (open(), access(), chown(), ...).
block Yes Block mangement layer (not to be confused with block device raw access which is done using the io major. This is more like Linux' LVM).
math Yes Mathematical support functions. This is for stuff not direct accessable by the CPU like external support devices.
crypt Yes Crypto support functions. Just like major math but for cryptography.
net Yes Network functions (socket(), bind(), connect(), listen(), accept()).
audio Yes Audio Interface.
scheduler Yes Scheduler interface.
acl Yes Permission management.
identifier Yes Allocating and deallocating system global unique idenifiers.
hypervisor Yes Hypervisor interface (registering and unregistering majors, ...).
sysconf Yes System configuration (sysconf(), getnodename(), gethostid(), ...).
self No Loopback to current process. Used for testing.
sensoractor Yes Used to interact with sensors and actors.
radio Yes All kind of Radio devices.

Not all majors from this list must exist on a given system (the only one that needs to exist is major core (ID=0)). Also there can be any number of additional majors. For example on an embedded system there may be the io major as the devices knows about a serial console and other io resourced but no fs major as it does not have a file system. Such a device also may implement more majors to access device specific resources.

Minors

The use of minor IDs are completly depending on the major. However there are some minor IDs wich should be used the same on all majors. If a given major does not impelement what the minor is for it should just not use it. The next table shows the list of those "common minors". Types variate depending on major (but should not).

Name ID Argument usage (Type) Description
return value arg0 arg1 arg2
NOOP 0 (none) (none) (none) (none) No Operation.
SET_MASTERAST 1 (sregister) status (void *) masterast function (none) (none) Set masterast function (only on major=core)
GETMAJORBYNAME / GETOBJECTBYNAME 2 (major/identifier) major id or identifier (void *) major or object name (none) (none) Get major ID or object identifier for major or object by name. (on core: major, else identifier)
GETMAJORBYID / GETOBJECTBYID 3 (sregister) status (void *) info structure (major/identifier) major ID or identifier (none) Get information about a major or object by ID (on core: major, else object)
GETMAJORLIST / GETOBJECTLIST 4 (ssize) length of list (void *) list of majors or identifers (usize) size of list in arg0 (none) Get list of all majors or known objects (on core: major, else objects)
GETMINORBYNAME 5 (???) minor (void *) name of minor (none (none Get a minor by name (only useful on non-standard majors)
GETMINORBYID 6 (sregister) status (void *) info struct (???) minor (none) Get information about a minor
GETMINORLIST 7 (ssize) length of list (void *) list of minors (usize) size of list in arg0 (none) Get list of all minors in the major
(none) 8-14         Reserved
SUBREGISTER 15 (identifier) new subobject (identifier) parent object Parameters: size, subtype, name,... Register/Create a new subobject used with this major.
REGISTER 16 (identifier) new object Parameters: size, subtype, name,... Register/Create a new object used with this major.
ALIAS 17 (idenifier) alias (identfier) source id (none) (none) Creates an alias to an object (think of dup())
REF 18 (sregister) status (identfier) object (none) (none) Increment refrence counter
UNREF 19 (sregister) status (identfier) object (none) (none) decrement refrence counter
STAT 20 (sregister) status (identifer) object (void *) info structure (none) Get information about an object (fstat(), ...)
STATEX 21 (sregister) status (identifer) object     Like STAT but get's more extended stats (this call may take (much) more time than STAT)
FIX 22 (void *) address of object (identifer) object (void *) requested address (or NULL) (none) Map object into address space
UNFIX 23 (sregister) status (identifer) object (void *) address (none) Unmap object from address space
LOCK 24 (sregister) status ? ? ? Lock object in memory (can not be swapped out or similar)
UNLOCK 25 (sregister) status ? ? ? Unlock object in memory
* 26-127 Depends on major/minor Usage of those IDs are up to the major
* 128-32767 Depends on major/minor Usage of those IDs are up to the major but are not available/valid on some profiles

Appendix A: Examples

Pseudo-ASM example implementation of yiff_backend_call()

The architecture in this example has 5 64 bit general purpose registers we can use (r0, ..., r4) and uses syscall to enter the kernel. The call struct is in call.

 ld r2, &call.arg0
 ld r3, &call.arg1
 ld r4, &call.arg2
 ld r0, &call.major
 lshift r0, 16
 ld r1, &call.minor
 or r0, r1
 lshift r0, 16
 ld r1, &call.flags
 or r0, r1
 lshift r0, 32
 ld r1, &call.receiver

 syscall

 st &call.receiver, r1
 st &call.ret, r2
 mov r1, r0
 and r1, 0x000000000000FFFF
 rshift r0, 16
 mov r2, r0
 and r2, 0x0000000000000100 ; YIFFError bit
 brnz r1, on_error          ; BRanch on Not Zero
 st &call.error, r1
 mov r1, r0
 and r1, 0x000000000000FFFF
 st &call.flags, r1
 mov returnvaluereg, 0
 ret

 on_error:
 mov returnvaluereg, r1
 ret

ioctl() based example implementation of yiff_backend_call()

yiff_error_t yiff_backend_call(yiff_call_t * call) {
 static int backend = -1;
 if ( backend != -1 ) {
  backend = open("/dev/yiff", O_RDONLY);
 }

 if ( backend == -1 )
  return YIFF_ERR_NOBKEND;

 return ioctl(backend, YIFFCALL, call);
}

 

 


Powered by Fellig.org, Vim and Freedom.