随手记下的

系统入口:
src\core\Main.c中的main函数,重点关注其中的autoboot()函数
autoboot函数中重点关注netboot()函数,改函数实现如下:


/**
 * Boot from a network device
 *
 * @v netdev  Network device
 * @ret rc  Return status code
 */
static int netboot ( struct net_device *netdev ) {
 char buf[256];
 struct in_addr next_server;
 int rc;

 /* Open device and display device status */
 if ( ( rc = ifopen ( netdev ) ) != 0 )
  return rc;
 ifstat ( netdev );

 /* Wait for link-up */
 printf ( "Waiting for link-up on %s...", netdev->name );
 if ( ( rc = iflinkwait ( netdev, LINK_WAIT_MS ) ) != 0 ) {
  printf ( " no link detected\n" );
  return rc;
 }
 printf ( " ok\n" );

 /* Configure device via DHCP */
 if ( ( rc = dhcp ( netdev ) ) != 0 )
  return rc;
 route();

 /* Try to boot an embedded image if we have one */
 rc = boot_embedded_image ();
 if ( rc != ENOENT )
  return rc;

 /* Try to download and boot whatever we are given as a filename */
 fetch_ipv4_setting ( NULL, &next_server_setting, &next_server );
 fetch_string_setting ( NULL, &filename_setting, buf, sizeof ( buf ) );
 if ( buf[0] ) {
  printf ( "Booting from filename \"%s\"\n", buf );
  return boot_next_server_and_filename ( next_server, buf );
 }
 
 /* No filename; try the root path */
 fetch_string_setting ( NULL, &root_path_setting, buf, sizeof ( buf ) );
 if ( buf[0] ) {
  printf ( "Booting from root path \"%s\"\n", buf );
  return boot_root_path ( buf );
 }

 printf ( "No filename or root path specified\n" );
 return -ENOENT;
}

关注其中的boot_next_server_and_filename()函数, 该函数实现如下:
/**
 * Boot using next-server and filename
 *
 * @v filename  Boot filename
 * @ret rc  Return status code
 */
static int boot_next_server_and_filename ( struct in_addr next_server,
        const char *filename ) {
 struct uri *uri;
 struct image *image;
 char buf[ 23 /* tftp://xxx.xxx.xxx.xxx/ */ + strlen(filename) + 1 ];
 int filename_is_absolute;
 int rc;

 /* Construct URI */
 uri = parse_uri ( filename );
 if ( ! uri ) {
  printf ( "Out of memory\n" );
  return -ENOMEM;
 }
 filename_is_absolute = uri_is_absolute ( uri );
 uri_put ( uri );
 if ( ! filename_is_absolute ) {
  /* Construct a tftp:// URI for the filename.  We can't
   * just rely on the current working URI, because the
   * relative URI resolution will remove the distinction
   * between filenames with and without initial slashes,
   * which is significant for TFTP.
   */
  snprintf ( buf, sizeof ( buf ), "tftp://%s/%s",
      inet_ntoa ( next_server ), filename );
  filename = buf;
 }

 image = alloc_image();
 if ( ! image ) {
  printf ( "Out of memory\n" );
  return -ENOMEM;
 }
 if ( ( rc = imgfetch ( image, filename,
          register_and_autoload_image ) ) != 0 ) {
  printf ( "Could not load %s: %s\n",
    filename, strerror ( rc ) );
  goto done;
 }
 if ( ( rc = imgexec ( image ) ) != 0 ) {
  printf ( "Could not boot %s: %s\n",
    filename, strerror ( rc ) );
  goto done;
 }

 done:
 image_put ( image );
 return rc;
}

其中imgfetch函数用于从服务器获取启动镜像,而imgexec 函数用于执行启动镜像,imgfetch函数实现如下:
/**
 * Fetch an image
 *
 * @v uri_string URI as a string (e.g. "http://www.nowhere.com/vmlinuz")
 * @v name  Name for image, or NULL
 * @v register_image Image registration routine
 * @ret rc  Return status code
 */
int imgfetch ( struct image *image, const char *uri_string,
        int ( * image_register ) ( struct image *image ) ) {
 struct uri *uri;
 int rc;

 if ( ! ( uri = parse_uri ( uri_string ) ) )
  return -ENOMEM;

 image_set_uri ( image, uri );

 if ( ( rc = create_downloader ( &monojob, image, image_register,
     LOCATION_URI, uri ) ) == 0 )
  rc = monojob_wait ( uri_string );

 uri_put ( uri );
 return rc;
}
其中create_downloader函数执行下载任务,改函数实现如下:
/**
 * Instantiate a downloader
 *
 * @v job  Job control interface
 * @v image  Image to fill with downloaded file
 * @v register_image Image registration routine
 * @v type  Location type to pass to xfer_open()
 * @v ...  Remaining arguments to pass to xfer_open()
 * @ret rc  Return status code
 *
 * Instantiates a downloader object to download the specified URI into
 * the specified image object.  If the download is successful, the
 * image registration routine @c register_image() will be called.
 */
int create_downloader ( struct job_interface *job, struct image *image,
   int ( * register_image ) ( struct image *image ),
   int type, ... ) {
 struct downloader *downloader;
 va_list args;
 int rc;

 /* Allocate and initialise structure */
 downloader = zalloc ( sizeof ( *downloader ) );
 if ( ! downloader )
  return -ENOMEM;
 downloader->refcnt.free = downloader_free;
 job_init ( &downloader->job, &downloader_job_operations,
     &downloader->refcnt );
 xfer_init ( &downloader->xfer, &downloader_xfer_operations,
      &downloader->refcnt );
 downloader->image = image_get ( image );
 downloader->register_image = register_image;
 va_start ( args, type );

 /* Instantiate child objects and attach to our interfaces */
 if ( ( rc = xfer_vopen ( &downloader->xfer, type, args ) ) != 0 )
  goto err;

 /* Attach parent interface, mortalise self, and return */
 job_plug_plug ( &downloader->job, job );
 ref_put ( &downloader->refcnt );
 va_end ( args );
 return 0;

 err:
 downloader_finished ( downloader, rc );
 ref_put ( &downloader->refcnt );
 va_end ( args );
 return rc;
}
注意到struct downloader,看看downloader的具体定义:

/** A downloader */
struct downloader {
 /** Reference count for this object */
 struct refcnt refcnt;

 /** Job control interface */
 struct job_interface job;
 /** Data transfer interface */
 struct xfer_interface xfer;

 /** Image to contain downloaded file */
 struct image *image;
 /** Current position within image buffer */
 size_t pos;
 /** Image registration routine */
 int ( * register_image ) ( struct image *image );
};
来看看其中的struct xfer_interface xfer的定义:

/** Data transfer interface operations */
struct xfer_interface_operations {
 /** Close interface
  *
  * @v xfer  Data transfer interface
  * @v rc  Reason for close
  */
 void ( * close ) ( struct xfer_interface *xfer, int rc );
 /** Redirect to new location
  *
  * @v xfer  Data transfer interface
  * @v type  New location type
  * @v args  Remaining arguments depend upon location type
  * @ret rc  Return status code
  */
 int ( * vredirect ) ( struct xfer_interface *xfer, int type,
         va_list args );
 /** Check flow control window
  *
  * @v xfer  Data transfer interface
  * @ret len  Length of window
  *
  * Flow control is regarded as advisory but not mandatory.
  * Users who have control over their own rate of data
  * generation should perform a flow control check before
  * generating new data.  Users who have no control (such as
  * NIC drivers or filter layers) are not obliged to check.
  *
  * Data transfer interfaces must be prepared to accept
  * datagrams even if they are advertising a window of zero
  * bytes.
  */
 size_t ( * window ) ( struct xfer_interface *xfer );
 /** Allocate I/O buffer
  *
  * @v xfer  Data transfer interface
  * @v len  I/O buffer payload length
  * @ret iobuf  I/O buffer
  */
 struct io_buffer * ( * alloc_iob ) ( struct xfer_interface *xfer,
          size_t len );
 /** Deliver datagram as I/O buffer with metadata
  *
  * @v xfer  Data transfer interface
  * @v iobuf  Datagram I/O buffer
  * @v meta  Data transfer metadata
  * @ret rc  Return status code
  *
  * A data transfer interface that wishes to support only raw
  * data delivery should set this method to
  * xfer_deliver_as_raw().
  */
 int ( * deliver_iob ) ( struct xfer_interface *xfer,
    struct io_buffer *iobuf,
    struct xfer_metadata *meta );
 /** Deliver datagram as raw data
  *
  * @v xfer  Data transfer interface
  * @v data  Data buffer
  * @v len  Length of data buffer
  * @ret rc  Return status code
  *
  * A data transfer interface that wishes to support only I/O
  * buffer delivery should set this method to
  * xfer_deliver_as_iob().
  */
 int ( * deliver_raw ) ( struct xfer_interface *xfer,
    const void *data, size_t len );
};

/** A data transfer interface */
struct xfer_interface {
 /** Generic object communication interface */
 struct interface intf;
 /** Operations for received messages */
 struct xfer_interface_operations *op;
};
其中struct xfer_interface_operations *op的初始化如下
哈哈,下载主要干事的家伙在这里,代码里面到处都是用c实现面向对象
/** Downloader data transfer interface operations */
static struct xfer_interface_operations downloader_xfer_operations = {
 .close  = downloader_xfer_close,
 .vredirect = xfer_vopen,
 .window  = unlimited_xfer_window,
 .alloc_iob = default_xfer_alloc_iob,
 .deliver_iob = downloader_xfer_deliver_iob,
 .deliver_raw = xfer_deliver_as_iob,
};
imgexec函数的实现如下:
/**
 * Execute loaded image
 *
 * @v image  Loaded image
 * @ret rc  Return status code
 */
int image_exec ( struct image *image ) {
 struct uri *old_cwuri;
 int rc;

 /* Image must be loaded first */
 if ( ! ( image->flags & IMAGE_LOADED ) ) {
  DBGC ( image, "IMAGE %p could not execute: not loaded\n",
         image );
  return -ENOTTY;
 }

 assert ( image->type != NULL );

 /* Check that image is actually executable */
 if ( ! image->type->exec )
  return -ENOEXEC;

 /* Switch current working directory to be that of the image itself */
 old_cwuri = uri_get ( cwuri );
 churi ( image->uri );

 /* Try executing the image 又见到工厂,插件式设计思想*/
 if ( ( rc = image->type->exec ( image ) ) != 0 ) {
  DBGC ( image, "IMAGE %p could not execute: %s\n",
         image, strerror ( rc ) );
  goto done;
 }

 done:
 /* Reset current working directory */
 churi ( old_cwuri );
 uri_put ( old_cwuri );

 return rc;
}