A Node object is responsible for bringing the system into operation and
also for shutting it down (i.e. to either halt, reboot, or suspend
it). Node is also a singleton3.1 used as a placeholder for
node-wide system properties (e.g. the portal for the authentication server
used to establish trust relationships among distributed kernels (auth),
and the portal for the external data translator used to translate foreign
kernel objects to the native architecture (xdt) are placed here.)
Being the outer-most starting point in the container hierarchy, its
id (obtained from the method get_id) is all the user needs to
know how to start looking for available system resources. Nodes have a
name, as any other resource do.
<Off node. >= (U->)
// An Off Node.
// Can be also handled as a resource: freeze, melt, etc.
class off_Node : public off_Resource {
private:
char *n_name; // Node name.
<Off private members for sequencing objects. >
<Other private members of off_Node. >
protected:
off_prtl_id_t n_xdt; // External data translator.
off_prtl_id_t n_auth; // Authenticator.
<Other protected members of off_Node. >
<Off protected methods for sequencing objects. >
<Other protected methods of off_Node. >
public:
<off_Node::valid public method. >
// Returns the node name.
const char *nameof(void) { assert(valid()); return n_name; }
// Returns or sets the authorization server and
// the external data translator portals.
off_prtl_id_t get_auth(void) {
off_prtl_id_t p;
assert(valid()); r_lock(); p=n_auth; r_unlock(); return p;
}
off_prtl_id_t get_xdt(void) {
off_prtl_id_t p;
assert(valid()); r_lock(); p=n_xdt; r_unlock(); return p;
}
void set_auth(const off_prtl_id_t &p) {
assert(valid()); if (!is_frozen()) { w_lock(); n_auth=p; w_unlock(); }
}
void set_xdt(const off_prtl_id_t &p) {
assert(valid()); if (!is_frozen()) { w_lock(); n_xdt=p; w_unlock(); }
}
// Halts, reboots, or suspends this node
void halt(const char *msg="System On. Now you can run Linux." );
void reboot( void );
err_t suspend( void );
<Other public methods of off_Node. >
};
Definesoff_Node(links are to index).
Note how we have used assert to ensure we are operating on a
valid node. Such check will be described below.
<Off node dependencies. >= (U->) [D->] #include <assert.h> // for assert #include <klib/ids.h> // for off_id_t et al. #include <klib/err.h> // for err_t and error numbers. #include <klib/Resource.h> // for off_Resource
The Node can be also considered to be a
façade3.2 (see
[#!gamma95:_patterns!#]) for node-wide system operations.
There is a single node instance which is made available system-wide.
<Off node exported variables. >= (U->) extern off_Node nd; // Node instance for this node.
Definesnd(links are to index).
<Off node global variables. >= (U->) off_Node nd; // Node instance for this node.
The node instance is staticly initialized with silly default values.
Its initialization will be actually done during main entry point
execution.
<Other public methods ofoff_Node. >= (<-U) [D->] // Creates an initial off_Node off_Node(void) : off_Resource(off_Protection(), OFF_PRTL_NULL,OFF_ID_NULL, OFF_MAGIC_NODE), <Initialize other aggregate members ofoff_Node. > { <Off initialization for sequencing objects. > n_name=NULL; n_xdt = n_auth = OFF_PRTL_NULL; <Initialize other private members ofoff_Node. > }
<Off node dependencies. >+= (U->) [<-D->] #include <klib/prot.h> // for off_Protection. #include <klib/Magic.h> // for off_magic_t and magic numbers.
Note how we have used the magic number for nodes. It is defined as follows.
<Off magic numbers. >= OFF_MAGIC_NODE, // Node magic nb.
We can now add another case to the implementation of
Magic::nameof.
<off_Magic::nameofcase form_numbers. >= case OFF_MAGIC_NODE: return "off_Node";
Node users can check their references to nodes with
<off_Node::valid public method. >= (<-U)
// Does this look like a node?
boolean_t valid(void) const { return get_magic() == OFF_MAGIC_NODE; }
We will be seeing the implementation of remaining methods of
off_Node through this chapter because they have to do with
different aspects of system operation.
To support efficient browsing of node components, the Node has a
set of methods that provide access to its components. Most of them
will be simply inlined. Node navigation is important because every
(outermost) resource container found in the local node will have an
instance aggregated to the Node. For example, for memory banks we
have:
<Other public methods of off_Node. >+= (<-U) [<-D->]
// Returns the number of specific containers found at this node
inline natural_t get_num_mbanks(void) const {
assert(valid()); return n_nmbanks; }
// Returns a pointer to a local memory bank.
inline off_MBank &get_mbank( natural_t id = 0 ) {
assert(valid()); return n_mbank[id];}
A local array of memory banks is kept.
<Other protected members of off_Node. >= (<-U) [D->]
natural_t n_nmbanks; // # of local mbanks.
off_MBank n_mbank[OFF_NMBANKS_MAX]; // Local memory banks.
<Initialize other aggregate members of off_Node. >= (<-U)
n_nmbanks(0)
The maximum number of memory banks OFF_NMBANKS_MAX is a system limit.
<Off limits. >= [D->] const int OFF_NMBANKS_MAX = 4; // Max. number of memory banks
DefinesOFF_NMBANKS_MAX(links are to index).
<Off node dependencies. >+= (U->) [<-D->] #include <klib/limits.h> // for OFF_NMBANKS_MAX et al. #include <flux/types.h> // for boolean_t natural_t et al. #include <hw/MBank.h> // for off_MBank
The same holds for remaining resource containers. Note how every resource container is kept inside the node instance but for the portal server, the shuttle server and the DMM, which are system servers on their own and provide their own global instances. Nevertheless, the node pretends that they are contained inside it for navigation purposes.
<Other public methods of off_Node. >+= (<-U) [<-D->]
// Return the number of specific containers found at this node
// Get a pointer to a hardware resource container
inline natural_t get_num_iobanks(void) const {
assert(valid()); return n_niobanks;
}
inline off_IOBank &get_iobank( natural_t id=0 ) {
assert(valid()); return n_iobank[id];
}
inline natural_t get_num_procs(void) const {
assert(valid()); return n_nprocs;
}
inline off_Processor &get_proc(natural_t id=0){
assert(valid()); return n_proc[id];
}
inline off_ShtlSrv &get_shtl( void ) {assert(valid()); return *n_shtl;}
#if 0 // XXX fix this.
inline natural_t get_num_dmas(void) const {
assert(valid()); return n_ndmas;
}
inline off_DMA &get_dma( natural_t id=0 ) {
assert(valid()); return n_dma[id];
}
inline off_PrtlSrv &get_prtl( void ) {assert(valid()); return *n_prtl;}
inline off_DMM &get_dmm( void ) {assert(valid()); return *n_dmm;}
#endif
<Other protected members of off_Node. >+= (<-U) [<-D->]
natural_t n_niobanks; // # of iobanks
off_IOBank n_iobank[OFF_NIOBANKS_MAX]; // IO banks
natural_t n_nprocs; // # of processors.
off_Processor n_proc[OFF_NPROC_MAX]; // Processors.
off_ShtlSrv *n_shtl; // Shuttle server.
#if 0 // XXXX fix this.
natural_t n_ndmas; // # of DMAs
off_DMA n_dma[OFF_NDMAS_MAX]; // DMAs
off_PrtlSrv *n_prtl; // Portal server
off_DMM *n_dmm; // DMM.
#endif
<Initialize other private members of off_Node. >= (<-U) [D->]
n_niobanks=0;
//n_ndmas=0;
//n_prtl=&prtl; XXX fix this
n_shtl=&shtl;
//n_dmm=&dmm;
The maximum number of IO banks, OFF_NMBANKS_MAX, and DMAs,
OFF_NDMAS_MAX, are system limits.
<Off limits. >+= [<-D->] const int OFF_NIOBANKS_MAX = 1; const int OFF_NDMAS_MAX = 1; // Max. number of DMAs const int OFF_NPROC_MAX = 1; // Max. number of Processors.
DefinesOFF_NDMAS_MAX,OFF_NIOBANKS_MAX,OFF_NPROC_MAX(links are to index).
<Off node dependencies. >+= (U->) [<-D->] #include <hw/IOBank.h> // for off_IOBank #include <hw/Processor.h> // for off_Processor #include <shtl/ShtlSrv.h> // for off_ShtlSrv //#include <hw/DMA.h> // for off_DMA fix this XXX //#include <hw/PrtlSrv.h> // for off_PrtlSrv //#include <hw/DMM.h> // for off_DMA
Besides, a generic navigator specialized for the Node will support
the common interface for navigation. That is primarily for system
users and not for the kernel itself.