mirror of
https://github.com/ipxe/ipxe
synced 2025-12-19 02:50:25 +03:00
[comboot] Allow for tail recursion of COMBOOT images
Multi-level menus via COMBOOT rely on the COMBOOT program being able to exit and invoke a new COMBOOT program (the next menu). This works, but rapidly (within about five iterations) runs out of space in gPXE's internal stack, since each new image is executed in a new function context. Fix by allowing tail recursion between images; an image can now specify a replacement image for itself, and image_exec() will perform the necessary tail recursion.
This commit is contained in:
@@ -53,6 +53,7 @@ static void free_image ( struct refcnt *refcnt ) {
|
||||
|
||||
uri_put ( image->uri );
|
||||
ufree ( image->data );
|
||||
image_put ( image->replacement );
|
||||
free ( image );
|
||||
DBGC ( image, "IMAGE %p freed\n", image );
|
||||
}
|
||||
@@ -142,9 +143,9 @@ int register_image ( struct image *image ) {
|
||||
* @v image Executable/loadable image
|
||||
*/
|
||||
void unregister_image ( struct image *image ) {
|
||||
DBGC ( image, "IMAGE %p unregistered\n", image );
|
||||
list_del ( &image->list );
|
||||
image_put ( image );
|
||||
DBGC ( image, "IMAGE %p unregistered\n", image );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -237,6 +238,7 @@ int image_autoload ( struct image *image ) {
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int image_exec ( struct image *image ) {
|
||||
struct image *replacement;
|
||||
struct uri *old_cwuri;
|
||||
int rc;
|
||||
|
||||
@@ -257,18 +259,40 @@ int image_exec ( struct image *image ) {
|
||||
old_cwuri = uri_get ( cwuri );
|
||||
churi ( image->uri );
|
||||
|
||||
/* Take out a temporary reference to the image. This allows
|
||||
* the image to unregister itself if necessary, without
|
||||
* automatically freeing itself.
|
||||
*/
|
||||
image_get ( image );
|
||||
|
||||
/* 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;
|
||||
/* Do not return yet; we still have clean-up to do */
|
||||
}
|
||||
|
||||
done:
|
||||
/* Pick up replacement image before we drop the original
|
||||
* image's temporary reference.
|
||||
*/
|
||||
if ( ( replacement = image->replacement ) != NULL )
|
||||
image_get ( replacement );
|
||||
|
||||
/* Drop temporary reference to the original image */
|
||||
image_put ( image );
|
||||
|
||||
/* Reset current working directory */
|
||||
churi ( old_cwuri );
|
||||
uri_put ( old_cwuri );
|
||||
|
||||
/* Tail-recurse into replacement image, if one exists */
|
||||
if ( replacement ) {
|
||||
DBGC ( image, "IMAGE %p replacing self with IMAGE %p\n",
|
||||
image, replacement );
|
||||
if ( ( rc = image_exec ( replacement ) ) != 0 )
|
||||
return rc;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user