随手记下的
系统入口:
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;
}