[comboot] Allow for tail recursion of COMBOOT images
[people/lynusvaz/gpxe.git] / src / core / image.c
index 440a68c..741b054 100644 (file)
@@ -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;
 }