4 Packages





A package is a the set of methods and properties that resides in a device node. A support package is a group of functions or methods that implements a specific interface. A package implements a library of functions that may then be called by FCode programs.

For many devices, this is not particularly useful, but it will be useful for FCode programs that:

A plug-in package is a package that is not permanently resident in the main OpenBoot PROM. Plug-in packages are written in FCode. Since FCode is represented with a machine-independent binary format, it lets the same plug- in packages be used on machines with different CPU instruction sets.

A package's references to OpenBoot PROM system functions are resolved and the functions defined by the package are made available to other parts of the OpenBoot during the linking process. This occurs at run-time, when OpenBoot interprets (probes) the package. Thus, plug-in packages do not need to be pre- linked with a particular OpenBoot implementation.

OpenBoot only needs the beginning address of the package in order to probe it. Once probed, the package becomes a working part of OpenBoot, until the system is reset or turned off. A package exports its interface to OpenBoot, and to other packages, as a vocabulary of Forth words.

Many packages implement a specific interface; a standard set of functions. Different packages may implement the same interface. For example, there may be two display device driver packages, each implementing the standard display device interface, but for two different display devices.

There may also be multiple instances of a single package. For example, a plug- in disk driver may have as many instances as there are disks of that type.

Package Instances

A package consists of:

The active package is the package whose methods are currently visible. dev and find-device can be used to change the active package. However, they only make a package's methods visible; they do not enable the execution of those methods.

Before a package's methods may be executed, create an instance of the package. Think of an instance as a working copy of the package. An instance contains a working copy of all of the package's private data.

An instance is created from a package by opening that package. The act of opening a package allocates memory for the instance's data and sets the contents of that memory to the initial values stored in the package. The instance exists until it is terminated by closing it. When it is closed, the memory used to hold that instance's private data is freed. Multiple instances may be created from the same package, and exist simultaneously.

The current instance is the instance whose private data and methods are available for direct use (i.e. directly by name without having to use $call-method).

When a package method accesses a data item, it refers to the copy of that data item associated with the current instance. The private data of the current instance is accessible; the private data of all other instances is inaccessible. Furthermore, to use the methods of a package, an instance of that package must be (at least temporarily) the current instance.

A package to be opened is described by a device path or device alias. The process of opening the package includes opening each of the nodes in the device path from the root to the specified device (i.e. from the top of the chain to the bottom). As each of these nodes is opened, an instance is created for the node and all of these instances are linked together in an instance chain as shown in Figure 4-1. When a method is accessed using the ihandle of the chain, each node in the chain is able to access the methods of its parent with $call-parent using the links provided by the instance chain

.

When the chain is no longer needed, the individual instances of the chain may be closed or the entire chain may be closed. When closing the entire chain, the chain is closed from bottom to top to enable a given node's close method to use parental methods.

The current instance is a dynamic entity. It is changed in several different ways under several different circumstances. Specifically:

    This causes any instance data/methods that are subsequently created (prior to the execution of finish-device) to be added to this node, and enables their later execution when an instance of this node is made current.

If a package is in the node /packages, $open-package can be used to create an instance of the package. Unlike packages opened with open-dev, packages opened with $open-package are opened without opening their ancestors. Each time a package instance is created by $open-package, that instance is attached to the one that called $open-package. Figure 4-2 shows the modified instance chain that results when the /iommu/sbus/ledma/le instance opens the obp-tftp support package using $open-package.

Notice that the only additional instance created is one for the obp-tftp package, and that this instance is linked to the /iommu/sbus/ledma/le instance. If another instance of obp-tftp were opened by an instance in another instance chain, the resulting instance of obp-tftp would have no association with the instance shown in Figure 4-2.

Package Data

Package data is named, read/write RAM storage used by package methods. Individual data items can be either initialized or zero-filled and either static or instance-specific.

Initialized data items are created by the FORTH defining words defer, value and variable. Uninitialized data items are created by buffer:. Preceding the defining word with the FORTH word instance causes the defining word to create an instance-specific item; otherwise it creates a static data item.

Static data items are used for information that applies equally to all instances of the associated package. For example, virtual addresses of shared hardware resources, reference counts and hardware dependent configuration data are often stored as static data.

Instance-specific data items are used for information that differs between instances of the same package. For example, a package that provides a driver for a SCSI host adapter might have several simultaneous instances on behalf of several different target devices; each instance might need to maintain individual state information (e.g. the negotiated synchronous transfer rate) for its target.

Static and Instance-specific Methods

There are several different kinds of package methods, depending on the environment in which they are called and their use of static and instance- specific data.

Static methods do not:

Static methods can be called when there is no open instance of their package. When there is no instance, there is also no parent instance (which is the reason for the prohibition about calling parent methods).

The most important example of static methods is the decode-unit method which is called by the system during the process of searching the device tree without opening all of the nodes that are encountered.

Instance-specific methods are permitted to:

There is no structural difference between static and instance-specific methods. The concept of static methods is just a terse way of saying that some methods have to obey the restrictions outlined above. Instance-specific methods are the usual case; the static methods restrictions apply only to a very small set of special-purpose methods.

Execution Tokens

A method is identified by its execution token, xt. For words in the package being defined, the FORTH word ['] returns an execution token. The execution token is returned by find-method for other packages. (See the following sections for more details.)

The execution token is used to execute a method in another package, and also to schedule a method for automatic, repeated execution by the system clock interrupt. See the alarm FCode.

Intra-package Calling Methods

A package can call its own methods directly simply by naming the target method in a FORTH colon definition. Such calls require neither a call-time name search nor a change of the current instance. The binding of name to execution behavior occurs at compile time so subsequent redefinitions of a name do not affect previously-compiled references to old versions of that named method.

Infrequently, it may be desirable to call a method in the same package so that the name search happens at run-time. To do so, use either $call-method or find-method/call-package with my-self as the ihandle argument. (See the next section for details.)

Accessing Other Packages

Packages often use methods of other previously-defined packages. There are two types of packages whose methods can be used directly:

Phandles and Ihandles

A package definition is identified by its phandle. find-package returns the phandle of a package in the /packages node. The phandle can then used to open that support package or to examine its properties. For example:

---------------------------
" deblocker" find-package ---------------------------

returns either false (package not found), or phandle true.

Opening a support package with open-package returns an ihandle. This ihandle is used primarily to call the methods of the support package, and to close the support package when it is no longer needed.

The ihandle of the current instance is stored in word my-self. An instance argument string must be supplied when opening any package (it may be null). The instance argument string can then be accessed from in the opened package with the my-args FCode (see below for details). For example (assume that phandle has already been found):

-------------------------------------------
" 5,3,0" phandle open-package ( ihandle ) -------------------------------------------

If the package cannot be opened, an ihandle of 0 is returned.

$open-package includes the functions of find-package and open- package. In most cases, it can be used in their place. The primitive functions find-package and open-package are rarely used directly, although find- package is sometimes used when it's necessary to examine a support package's properties without opening it.

The following FCode functions are used to find and open packages (in the /packages node):

    Table 4-1 Package Access FCodes

------------------------------------------------------------------------------------------------------------------
Name Stack Comment Description ------------------------------------------------------------------------------------------------------------------
                                                                           
find-package  ( name-str name-len -- false | phandle true )                Finds the package specified by 
                                                                           the string name-str name-len in 
                                                                           /packages. Returns the phandle 
                                                                           of the package, or false if not 
                                                                           found.
                                                                           
open-package  ( arg-str arg-len phandle -- ihandle | false )               Opens an instance of the 
                                                                           package phandle. Returns ihandle 
                                                                           for the opened package, or false 
                                                                           if unsuccessful. The package is 
                                                                           opened with an instance 
                                                                           argument string specified by 
                                                                           arg-str arg-len.
                                                                           
$open-        ( arg-str arg-len name-addr name-len -- ihandle | false )    Shortcut word to find and open 
package                                                                    the package named name-str 
                                                                           name-len in /packages in one 
                                                                           operation. Returns ihandle for the 
                                                                           opened package, or false if 
                                                                           unsuccessful.

------------------------------------------------------------------------------------------------------------------

Here is an example of using $open-package:

------------------------------------------------------
" 5,3,0" " deblocker" $open-package ( ihandle | 0 ) ------------------------------------------------------

    Table 4-2 Manipulating phandles and ihandles

------------------------------------------------------------------------------------------------------
Name Stack Comment Description ------------------------------------------------------------------------------------------------------
                                        
my-self         ( -- ihandle )          Return the instance handle of the currently-executing package 
                                        instance.
                                        
my-parent       ( -- ihandle )          Return the instance handle of the parent of the currently-
                                        executing package instance.
                                        
ihandlephandle  ( ihandle -- phandle )  Convert an instance handle to a package handle.
                                        
close-package   ( ihandle -- )          Close a package instance.

------------------------------------------------------------------------------------------------------

Don't confuse phandle with ihandle. Here's how to use them:

    1. Open the package with $open-package which returns an ihandle.
    2. Use the ihandle to call the methods of the package.
    3. When done calling the methods of the package, use the ihandle to close the instance of the package with close-package.

A package's phandle is primarily used to access the package's properties which are never instance-specific. Use ihandlephandle to find the phandle of an open package. my-self and my-parent return ihandles, which can be converted into phandles with ihandlephandle.

Inter-package Calling Methods

The following FCode functions enable the calling of methods of other packages :

    Table 4-3 FCode Functions Enabling Calling Other Packages' Methods

---------------------------------------------------------------------------------------------------------
Name Stack Comment Description ---------------------------------------------------------------------------------------------------------
                                                               
$call-method     ( ... method-str method-len ihandle -- ??? )  Shortcut word that finds and 
                                                               executes the method method-str 
                                                               method-len in the package instance 
                                                               ihandle.
                                                               
call-package     ( ... xt ihandle -- ??? )                     Executes the method xt in the 
                                                               instance ihandle.
                                                               
$call-parent     ( ... method-str method-len -- ??? )          Executes the method method-str 
                                                               method-len in the parent's package 
                                                               instance. Identical to calling 
                                                               my-parent $call-method.
                                                               
execute-device-  ( ... dev-str dev-len method-str method-len   Executes the method method-str 
method            -- ... false | ??? true )                    method-len in the package named 
                                                               dev-str dev-len. Returns false if the 
                                                               method could not be executed.
                                                               
find-method      ( method-str method-len phandle               Finds the method named method-
                  -- false | xt true )                         str method-len in the package 
                                                               phandle. Returns false if not found.

---------------------------------------------------------------------------------------------------------

$call-parent is used most-often, but is the least flexible of the above methods; it is exactly equivalent to the sequence "my-parent $call- method". Most inter-package method calling involves calling the methods of one's parent; $call-parent conveniently encapsulates the process of doing so.

$call-method can call methods of non-parent packages. It is most commonly used for calling methods of support packages. The ihandle argument of $call- method identifies the package instance whose method is to be called.

For example :

------------------------------
$call-parent $open-package $call-method ------------------------------

Both $call-parent and $call-method identify their target method by name. The method-str method-len arguments denote a text string that $call- parent or $call-method uses to search for a method of the same name in the target instance's list of methods. Obviously, this run-time name search is not as fast as directly executing a method whose address is already known. However:

    1. Most packages have a relatively small number of methods,
    2. Systems typically implement a reasonably-efficient name search mechanism, and
    3. Inter-package calls tend to occur relatively infrequently.

Consequently, the length of time spent searching is usually not a limiting factor.

A more complete example demonstrates the use of $open-package and $call-method:

--------------------------------------------------------------
: add-offset ( x.byte# -- x.byte#' ) my-args " disk-label" $open-package ( ihandle ) " offset" rot ( name-addr name-len ihandle ) $call-method ; --------------------------------------------------------------

When method name search time is a limiting factor, use find-method to perform the name search once. Then use call-package repetitively thereafter. find-method returns, and call-package expects, an execution token by which a method can be called quickly.

A more complex example that is somewhat faster if called repeatedly:

---------------------------------------------------------------------------
0 value label-ihandle \ place to save the other package's ihandle 0 value offset-method \ place to save found method's xt : init ( -- ) my-args " disk-label" $open-package ( ihandle ) to label-ihandle " offset" label-ihandle ihandlephandle ( name-addr name-len phandle ) find-method if ( xt ) to offset-method else ." Error: can't find method" then ; : add-offset ( d.byte# -- d.byte#' ) offset-method label-ihandle call-package ; ---------------------------------------------------------------------------

Because device access time often dominates I/O operations, the benefit of this extra code probably won't be noticed. It is only justified if the particular method will be called often.

Another use of find-method is to determine whether or not a package has a method with a particular name. This allows you to add new methods to an existing package interface definition without requiring version numbers to denote which new or optional methods a package implements.

With $call-method and $call-parent, the method name search is performed on every call. Consequently, if a new method (either one with a new name or with the same name as a previously-existing name) is created, any subsequent uses of $call-method or $call-parent naming that method will find the new one. On the other hand, find-method binds a name to an execution token and subsequent redefinitions of that name do not affect the previous execution token, so subsequent uses of $call-method continue to call the previous definition. In practice, this difference is rarely important, since it is quite unusual for new methods to be created when a package is already open. The one case where methods are routinely redefined under these circumstances is when a programmer does it explicitly during a debugging session; making such redefinitions is a powerful debugging technique.

All of the method calling functions described above change the current instance to the instance of the callee for the duration of the call, restoring it to the instance of the caller on return.

execute-device-method and apply

In addition to the inter- and intra-package method calling techniques just described, there is another way of calling methods that is rarely used by FCode Programs. execute-device-method and its variant apply allow a user to invoke a method of a particular package as a self-contained operation without explicitly opening and closing the package as separate operations. execute-device-method first opens all the package's parents, then calls the named method, and then closes all the parents.

apply performs the same functions as execute-device-method, but it takes its arguments from the command line instead of from the FORTH stack. It is consequently somewhat more convenient to use interactively.

execute-device-method and apply are most often used for methods like selftest. selftest methods are usually called with the test User Interface command which is usually implemented with execute-device-method.

Methods that are intended to be called with execute-device-method or its equivalent must not assume that the package's open method has been called, because execute-device-method does not call the open method of the package containing the target method although it opens all of the package's parents. Consequently, the target method must explicitly perform whatever initialization actions it requires, perhaps by calling the open method in the same package, or by executing some sub-sequence thereof. Before exiting, the target method must perform the corresponding close actions to undo its initialization actions.

execute-device-method was intentionally designed not to call the target's open and close methods automatically since the complete initialization sequence of open is not always appropriate for methods intended for use with execute-device-method. In particular, an open method usually puts its device in a fully operational state, while methods like selftest often need to perform a partial initialization of selected device functions.

execute-device-method is used with these methods:

Plug-in Device Drivers

Plug-in device drivers are plug-in packages implementing simple device drivers. The interfaces to these drivers are designed to provide basic I/O capability.

Plug-in drivers are used for such functions as booting the operating system from a device or displaying text on a device before the operating system has activated its own drivers. Plug-in drivers are added to the device tree during the probing phase of the OpenBoot PROM start-up sequence.

Plug-in drivers must be programmed to handle portability issues, such as hardware alignment restrictions and byte ordering of external devices. With care, you can write a driver so that it is portable to all of the systems in which the device could be used.

Plug-in drivers are usually stored in PROM located on the device itself, so that the act of installing the device automatically makes its plug-in driver available to the OpenBoot PROM.

For devices with no provision for such a plug-in driver PROM, the plug-in driver can be located elsewhere, perhaps in PROM located on a different device or in an otherwise unused portion of the main OpenBoot PROM. However, use of such a strategy limits such a device to certain systems and/or system configurations.

Common Package Methods

Different packages have different collections of methods depending on the job(s) that the packages have to do. The following four methods are found in many device drivers. None of them can be considered to be required, however, since the nature of a given driver governs the methods that the driver needs.

open and close are found in many drivers, but even they are not universally required. open and close are needed only if the device will be used with open-dev or another method that calls open-dev. Any device that has read and/or write methods needs open and close, as does any parent device whose children could possibly be opened.

Another way of looking at this is that open and close are needed for devices that are used to perform a series of related operations distributed over a period of time, relative to some other calling package. open initializes the device state that is maintained during the series of later operations, and close destroys that state after the series is complete.

To illustrate, a series of write calls generated by another package is such a series. Conversely, selftest is not such a series; selftest happens "atomically" as an indivisible self-contained operation.

Basic Methods

open ( -- ok? )
Prepares a package for subsequent use. open typically allocates resources, maps, initializes devices, and performs a brief sanity check (making no check at all may be acceptable). true is returned if successful, false if not. When open is called, the parent instance chain has already been opened, so this method may call its parent's methods.
close ( -- )
Restores a package to its "not in use" state. close typically turns off devices, unmaps, and de-allocates resources. close is executed before the package's parent is closed, so the parent's methods are available to close. It is an error to close a package which is not open.

Recommended Methods

The following methods are highly recommended.

reset
( -- )

Put the package into a "quiet" state. reset is primarily for packages that do not automatically assume a quiet state after a hardware reset, such as devices that turn on with interrupt requests asserted.

selftest
( -- error# )

Test the package. selftest is invoked by the OpenBoot test word. It returns 0 if no error found or a package-specific error number if a failure is noticed.

test does not open the package before executing selftest, so selftest is responsible for establishing any state necessary to perform its function prior to starting the tests, and for releasing any resources allocated after completing the tests. There should be no user interaction with selftest, as the word may be called from a program with no user present.

If the device was already open when selftest is called, a new instance will still be created and destroyed. A well-written selftest should handle this possibility correctly, if appropriate.

If the device is already open, but it is not possible to perform a complete selftest without destroying the state of the device, the integrity of the open device should take precedence, and the selftest process should test only those aspects of the device that can be tested without destroying device state. The inability to fully test the device should not be reported as an error result; an error result should occur only if selftest actually finds a device fault.

The "device already open" case happens most commonly for display devices, which are often used as the console output device, and thus remain open for long periods of time. When testing a display device that is already open, it is not necessary to preserve text that may already be on the screen, but the device state should be preserved to the extent that further text output can occur and be visible after selftest exits. Any error messages that are displayed by the selftest method will be sent to the console output device, so when testing an already-open display device, such error messages should be avoided during times when selftest has the device in a state where it is unable to display text.

selftest is not executed in an open/close pair. When selftest executes, a new instance is created (and destroyed). It will have its own set of variables, values, and so forth. These quantities are not normally shared with an instance opened with the normal open routine for the package.

Note - selftest should be written to do its own mapping and unmapping.

Package Data Definitions

The following examples show how to create static data items:

------------------------------------------------------
variable bar 5 value grinch defer stub create ival x , y , z , 7 buffer: foo ival foo 7 move \ One way to initialize a buffer ------------------------------------------------------

The data areas defined above are shared among all open instances of the package. If a value is changed, for instance, the new value will persist until it is changed again, independent of the creation and destruction of package instances.

Any open instance of a package can access and change the value of a static data item, which changes it for all other instances.

The following examples show how to create instance-specific data items, whose values are not shared among open instances:

--------------------------
instance variable bar 5 instance value grinch instance defer stub 7 instance buffer: foo --------------------------

Instance-specific data areas are re-initialized when a package instance is created (usually by opening the package), so each instance gets its own copy of the data area. For example, changes to bar in one instance will not affect the contents of it in another instance. (Note that create operates across all the instances, and cannot be made instance-specific.)

The total amount of data space needed for a package's instance-specific data items is remembered as part of the package definition when finish-device finishes the package definition. Also, the contents of all the variables, values, and defers at the time finish-device executes are stored as part of the package definition.

An instance of the package is created when that package is opened. Data space is allocated for that instance (the amount of which was remembered in the package definition). The portion of that data space created with variable, value, or defer is initialized from the values stored in the package definition. Data space created with buffer: is set to zero.

You can add new methods and new properties to a package definition at any time, even after finish-device has been executed for that package. To do so, select the package and create definitions or properties.

However, you cannot add new data items to a package definition after finish-device has been executed for that package. finish-device sets the size of the data space for that package, and subsequently the size is fixed.

Instance Arguments and Parameters

An instance argument (my-args) is a string that is passed to a package when it is opened. The string may contain parameters of any sort, based on the requirements of the package, or may simply be a null-string if no parameters are needed. A null string can be generated with either " " or 0 0.

The instance argument passed can be accessed from inside the package with the my-args FCode.

Note - A package is not required to inspect the passed arguments.

If the argument string contains several parameters separated by delimiter characters, you can extract the subsections from the package with left- parse-string. You can use any character as the delimiter; a comma is commonly used for this.

Note - Avoid using blanks or the / character, since these will confuse the parsing of pathnames.

A new value for my-args is passed when a package is opened. This can happen under a number of circumstances:

    1. The my-args string will be null when FCode on a SBus card is interpreted automatically by the OpenBoot system at power-on.
    2. The my-args string is set by a parameter to begin-package, which is used to set up the device tree when FORTH source code is downloaded and interpreted interactively.
    3. The my-args string can be set with set-args before a particular slot is probed, if SBus probing is being controlled from nvramrc.

The above three instances happen only once, when the package FCode is interpreted for the first time. If you want to preserve the initial value for my-args, the FCode program should copy it into a static buffer to preserve the information.

Whenever a package is re-opened, a new value for my-args is supplied. The method for supplying this new value depends on the method used to open the package, as described below.

    1. The instance argument (my-args) is supplied as a string parameter to the commands open-package or $open-package.
    2. User Interface commands, such as open-dev, execute-device-method and test, supply the entire pathname to the device being opened. This approach lets an instance argument be included in the pathname. For example, to open the SBus device "SUNW,bwtwo" with the argument string 5,3,0, enter:
-------------------------------------------
ok " /sbus/SUNW,bwtwo:5,3,0" open-dev ok -------------------------------------------

Here is a more complicated (and fictitious) example:

-------------------------------------------------------------------
ok " /sbus/SUNW,fremly:test/grumpin@7,32:print/SUNW,fht:1034,5" ok open-dev ok -------------------------------------------------------------------

Here the string test is passed to the SUNW,fremly package as it is opened, the string print is passed to the grumpin package as it is opened, and the string 1034,5 is passed to the SUNW,fht package as it is opened.

Package Addresses

A packages's address relative to its parent package is another piece of information available to a package. Again, there are two main ways to pass this address to the package:

As an example of the first method, suppose the following package is being opened:

-------------------------------------
ok "/sbus/esp/sd@3,0:b" open-dev -------------------------------------

Then the address of the /sd package relative to the /esp package is 3,0.

The package can find its relative address with my-unit, which returns the address as a pair of numbers. The first number (high) is the number before the comma in the example above, and the second number (low) is the number after the comma. Note that these are numbers, not strings.

As an example of the second method, suppose a test version of an FCode package is being interpreted:

-------------------------------------------
ok 0 0 " 3,0" " /sbus" begin-package -------------------------------------------

Here the my-args parameters for the new FCode are null, the initial address is 3,0 and it will be placed under the /sbus node.

The initial address can be obtained through my-address and my-space. Typically, you use my-space and my-address (plus an offset) to create the package's "reg" property, and also to map in needed regions of the device.

Package Mappings

Mappings set up by a package persist across instances unless they are explicitly unmapped. It is usually best for each new instance to do its own mappings, being sure to unmap resources as they are no longer needed.

However, if it is unlikely that a particular package will have several concurrent open instances, it is usually a good idea to maintain only one mapping for all the open instances, using a reference counter to count them. The variables that store the reference counter and the mapped address must be static, not instance-specific. When the last instance is closed, the resources should be unmapped.

nvramrc

Machines that support packages will generally also support the nvramrc facility. nvramrc is a special area in the NVRAM that can contain user interface commands to be executed by OpenBoot as the machine powers on. These commands can be used to specify behavior during start up or to define changes for later execution.

For example: assume a card in SBus slot #2 (named XYZ,me) needs custom attributes set by the user. nvramrc contents would include:

--------------------------------------------
probe-all dev /sbus/XYZ,me " type5" encode-string " xyzmode" property device-end install-console banner --------------------------------------------

After editing nvramrc, turn on the NVRAM parameter use-nvramrc? and reset the machine to activate the contents of nvramrc. See nvedit in Chapter 11, "FCode Dictionary" for more about editing nvramrc contents.

Modifying Package Properties

To modify the properties of a package, first probe the package to get it into memory, then create or modify properties by executing property or one of its short-hand forms. Normally, probing is done automatically after the nvramrc commands are executed.

See Chapter 5, "Properties", for more information about properties.

Standard Support Packages

The /packages node of the device tree is unique. It has children, but instead of describing a physical bus, /packages serves as a parent node for support packages. The children of /packages are general-purpose software packages not attached to any particular hardware device. The "physical address space" defined by /packages is a trivial one: there are no addresses. Its children are distinguished by name alone.

The children of /packages are used by other packages to perform commonly used functions. They may be opened with the FCodes open-package or $open-package, and closed with close-package. IEEE Standard 1275-1994 defines three support packages that are children of /packages.

Sun Disk-Label Support Package

Disk (block) devices are random-access, block-oriented storage devices with fixed-length blocks. Disks may be subdivided into several logical partitions, as defined by a disk label - a special disk block, usually the first one, containing information about the disk. The disk driver is responsible for appropriately interpreting a disk label. The driver may use the standard support package /disk-label if it does not implement a specialized label.

/disk-label interprets a standard Sun disk label, reading any partitioning information contained in it. It includes a first-stage disk boot protocol for the standard label. load is the most important method defined by this package.

This package uses the read and seek methods of its parent (in practice, the package which opens this one to use the support routines). /disk-label defines the following methods:

    Table 4-4 Sun Disk Label Package Methods

---------------------------------------------------------------------------------------------------------------------
Name Stack diagram Description ---------------------------------------------------------------------------------------------------------------------
                                                                                                             
open    (-- flag)        Reads and verifies the disk label accessed by the read and seek methods of          
                         its parent instance. Selects a disk partition based on the text string returned                
                         by my-args. For the standard Sun disk label format, the argument is                            
                         interpreted as follows:                                                                        
                                                                                                                        
                                                                                                                        
                                                                                                             
                         Argument                                                                            Partition
                                                                                                             
                         <none'>                                                                              0
                                                                                                             
                         a or A                                                                              0
                                                                                                             
                         b or B                                                                              1
                                                                                                             
                         ...                                                                                 ...
                                                                                                             
                         g or G                                                                              7
                                                                                                             
                         Returns -1 if the operation succeeds. As a special case, if the argument is the     
                         string "nolabel", open returns -1 (success) without attempting to read or                      
                         verify the label.                                                                              
                                                                                                             
close   (--)             Frees all resources that were allocated by open.                                    
                                                                                                             
load    (adr -- size)    Reads a stand-alone program from the standard disk boot block location for          
                         the partition specified when the package was opened. Puts the program at                       
                         memory address adr, returning its length size. For the standard Sun disk                       
                         format, the stand-alone program is 7.5K bytes beginning 512 bytes from the                     
                         start of the partition.                                                                        
                                                                                                             
offset  (x.rel-- x.abs)  Returns the 64-bit absolute byte offset x.abs corresponding to the 64-bit           
                         partition-relative byte offset x.rel. In other words, adds the byte location                   
                         of the beginning of the selected partition to the number on the stack.                         

---------------------------------------------------------------------------------------------------------------------

TFTP Booting Support Package

The /obp-tftp package implements the Internet Trivial File Transfer Protocol (TFTP) for use in network booting. It is typically used by a network device driver for its first stage network boot protocol. Again, load is the most important method defined by this package.

This package uses the read and write methods of its parent, and defines the following methods:

    Table 4-5 TFTP Package Methods

-----------------------------------------------------------------------------------------------------------
Name Stack diagram Description -----------------------------------------------------------------------------------------------------------
                      
open   (-- flag)      Prepares the package for subsequent use, returning -1 if the operation 
                      succeeds and 0 otherwise.
                      
close  (--)           Frees all resources that were allocated by open.
                      
load   (adr -- size)  Reads the default stand-alone program from the default TFTP server, 
                      putting the program at memory address adr and returning its length size. 
                      For the standard Sun TFTP booting protocol, RARP (Reverse Address 
                      Resolution Protocol) is used to acquire the IP address corresponding to the 
                      system's MAC address (equivalent to its Ethernet address). From the IP 
                      address, the default file name is constructed, of the form <Hex-IP-
                      Address>.<architecture> (for example, C0092E49.SUN4C). Then obp-tftp 
                      tries to TFTP read that file, first trying the server that responded to the RARP 
                      request, and if that fails, then broadcasting the TFTP read request.

-----------------------------------------------------------------------------------------------------------

Deblocker Support Package

The /deblocker package makes it easy to implement byte-oriented device methods, using the block-oriented or record-oriented methods defined by devices such as disks or tapes. It provides a layer of buffering between the high-level byte-oriented interface and the low-level block-oriented interface. /deblocker uses the max-transfer, block-size, read-blocks and write-blocks methods of its parent, and defines the following methods:

    Table 4-6 Deblocker Package Methods

---------------------------------------------------------------------------------------------------------------------
Name Stack diagram Description ---------------------------------------------------------------------------------------------------------------------
                             
open   (-- flag)             Prepares the package for subsequent use, allocating the buffers used by the 
                             deblocking process based on the values returned by the parent instance's max-
                             transfer and block-size methods. Returns -1 if the operation succeeds, 0 
                             otherwise.
                             
close  (--)                  Frees all resources that were allocated by open.
                             
read   (adr len -- actual)   Reads at most len bytes from the device into the memory buffer beginning at adr. 
                             Returns actual, the number of bytes actually read, or 0 if the read operation 
                             failed. Uses the parent's read-blocks method as necessary to satisfy the request, 
                             buffering any unused bytes for the next request.
                             
write  (adr len -- actual)   Writes at most len bytes from the device into the memory buffer beginning at adr. 
                             Returns actual, the number of bytes actually read, or 0 if the write operation 
                             failed. Uses the parent's write-blocks method as necessary to satisfy the request, 
                             buffering any unused bytes for the next request.
                             
seek   (x.position -- flag)  Sets the device position at which the next read or write will take place. The 
                             position is specified by the 64-bit number x.position. Returns 0 if the operation 
                             succeeds or -1 if it fails.

---------------------------------------------------------------------------------------------------------------------