next up previous contents
Next: 3.2.2 OS modules startup Up: 3.2 System booting Previous: 3.2.0.1 Complete option listing

3.2.1 Starting system servers

The hard part of system bootstrap is done by the node singleton itself, in srvstart.

First, we initialize the memory bank for the node core to allow dynamic memory allocation inside the kernel and then we create the portal server so that other servers could create their portals. After doing so, we start the kernel virtual memory service and remaining hardware servers and system servers.

<off_Node::srvstart implementation. >= (U->)
// Creates an Off Node. 
void off_Node::srvstart(const off_Protection &prot)
{
  assert(valid());
  <Create memory banks for node core protected with prot. >
  <Create KVM. >
  <Start relocation table operation. >
  <Create the portal server protected with prot. >
  <Create hardware system servers protected with prot. >
  <Create abstract system servers protected with prot. >
  <Start non boot processors. >
}

To know how many memory banks must be created we use the machine dependent node information, n_mdep, which already knows about existing hardware. The machine dependent method get_mbank will return information about every memory banks. Besides we call to set_core to give memory banks a chance to do any static initialization which depends on the memory banks installed in the system.

<Create memory banks for node core protected with prot. >= (<-U)
off_MBank::set_core(n_mdep.get_minfo(0));
n_nmbanks=n_mdep.get_num_mbanks();
for (natural_t i=0; i<n_nmbanks; i++){
  n_mbank[i].protect(prot);
  n_mbank[i].start(n_mdep.get_minfo(i),get_server_id());
}

Identifiers for containers being created are obtained with get_server_id as we will see later. Depending on the exact number of system servers, portal identifiers for a given server may differ from node to node. This is not a problem because navigators and inspectors can be used to obtain their identifiers in a portable way.

To initialize the kernel virtual memory server we tell it whether support for DTLB is included and also the first available address after kernel memory.

<Create KVM. >= (<-U)
kvm.start(n_mbank[n_nmbanks-1].get_kend(),n_opts->usedmm());

<Off node implementation dependencies. >= (<-U) [D->]
#include <dmm/KVM.h>            // for kvm

When the KVM has been started, we can start relocation table operation. We simply need a region of kernel virtual memory to maintain relocation table entries.

<Start relocation table operation. >= (<-U)
off_RelocTbl::start(kvm.create_region());

We do the same with remaining hardware servers. Only processors are a little bit special. The boot processor has code to run, but others must wait until the shuttle server has been started to get their initial idle shuttles.

<Create hardware system servers protected with prot. >= (<-U)
n_niobanks=n_mdep.get_num_iobanks();
for (natural_t i=0; i<n_niobanks; i++){ 
  n_iobank[i].protect(prot);
  n_iobank[i].start(n_mdep.get_ioinfo(i),get_server_id());
}
n_nprocs=n_mdep.get_num_procs();
n_proc[0].protect(prot);
n_proc[0].start(n_mdep.get_procinfo(0),get_server_id());

#if 0               // XXX fix this
n_ndmas=n_mdep.get_num_dmas();
for (natural_t i=0; i<n_ndmas; i++){
  n_dma[i].protect(prot);
  n_dma[i].start(n_mdep.get_dmainfo(i),get_server_id());
}
#endif

<Start non boot processors. >= (<-U)
for (natural_t i=1; i<n_nprocs; i++){
  n_proc[i].protect(prot);
  n_proc[i].start(n_mdep.get_procinfo(i),get_server_id());
}

Starting (abstract) system servers is almost the same.

<Create the portal server protected with prot. >= (<-U)
//  n_prtl->protect(prot);               XXX fix this
//  n_prtl->start(get_server_id());

<Create abstract system servers protected with prot. >= (<-U)
#if 0                           // XXX fix this
  n_shtl->protect(prot);
  n_shtl->start();
  n_dmm->protect(prot);
  if (n_opts->usedmm()){
    n_dmm->start(get_server_id());
  }
#endif

We start the \dmm{} only when \dtlb{} support is required.

The srvstart implementation is also kept in node/Node.C.

<Implementation of other methods of off_Node. >+= (<-U) [<-D->]
<off_Node::srvstart implementation. > 

To assign identifiers for system servers, we used get_server_id.

<Other public methods of off_Node. >+= (<-U) [<-D->]
// Obtain the indentifier for a new system server. 
off_id_t get_server_id(void);

Its implementation uses the sequence number stored in the node instance to generate identifiers taking as a template the node identifier.

<off_Node::get_server_id implementation. >= (U->)
// Obtain the indentifier for a new system server. 
off_id_t off_Node::get_server_id(void)
{
  off_id_t id = get_id();
  assert(valid());
  id.i_seq    = get_seq();
  id.i_slot   = (off_slot_t)id.i_seq;
  return id;  
}

<Implementation of other methods of off_Node. >+= (<-U) [<-D->]
<off_Node::get_server_id implementation. >

We set the slot field with the same value of the seq field because portals will be created (to export system servers services) to match this identifiers. The portal server will assign slots in its internal allocator matching the seq field. Therefore, we avoid fake relocations by initializing the slot field.

Note also how locking is missing. When this method is used the node will be booting and it will be no longer used before any shuttle is ever created.


next up previous contents
Next: 3.2.2 OS modules startup Up: 3.2 System booting Previous: 3.2.0.1 Complete option listing
Francisco J. Ballesteros
1998-05-25