mirror of
https://github.com/ipxe/ipxe
synced 2025-12-28 18:42:53 +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:
@@ -70,20 +70,20 @@ static int com32_exec ( struct image *image ) {
|
||||
}
|
||||
|
||||
DBGC ( image, "COM32 %p: available memory top = 0x%x\n",
|
||||
image, (int)avail_mem_top );
|
||||
image, avail_mem_top );
|
||||
|
||||
assert ( avail_mem_top != 0 );
|
||||
|
||||
com32_external_esp = phys_to_virt ( avail_mem_top );
|
||||
|
||||
/* Hook COMBOOT API interrupts */
|
||||
hook_comboot_interrupts( );
|
||||
hook_comboot_interrupts();
|
||||
|
||||
/* Temporarily de-register image, so that a "boot" command
|
||||
* doesn't throw us into an execution loop. Hold a reference
|
||||
* to avoid the image's being freed.
|
||||
/* Unregister image, so that a "boot" command doesn't
|
||||
* throw us into an execution loop. We never
|
||||
* reregister ourselves; COMBOOT images expect to be
|
||||
* removed on exit.
|
||||
*/
|
||||
image_get ( image );
|
||||
unregister_image ( image );
|
||||
|
||||
__asm__ __volatile__ (
|
||||
@@ -111,25 +111,31 @@ static int com32_exec ( struct image *image ) {
|
||||
/* %6 */ "r" ( COM32_START_PHYS )
|
||||
:
|
||||
"memory" );
|
||||
DBGC ( image, "COM32 %p: returned\n", image );
|
||||
break;
|
||||
|
||||
case COMBOOT_RETURN_RUN_KERNEL:
|
||||
DBGC ( image, "COM32 %p: returned to run kernel...\n", image );
|
||||
comboot_run_kernel ( );
|
||||
case COMBOOT_EXIT:
|
||||
DBGC ( image, "COM32 %p: exited\n", image );
|
||||
break;
|
||||
|
||||
case COMBOOT_RETURN_EXIT:
|
||||
case COMBOOT_EXIT_RUN_KERNEL:
|
||||
DBGC ( image, "COM32 %p: exited to run kernel %p\n",
|
||||
image, comboot_replacement_image );
|
||||
image->replacement = comboot_replacement_image;
|
||||
image_autoload ( image->replacement );
|
||||
break;
|
||||
|
||||
case COMBOOT_EXIT_COMMAND:
|
||||
DBGC ( image, "COM32 %p: exited after executing command\n",
|
||||
image );
|
||||
break;
|
||||
|
||||
default:
|
||||
assert ( 0 );
|
||||
break;
|
||||
}
|
||||
|
||||
comboot_force_text_mode ( );
|
||||
|
||||
DBGC ( image, "COM32 %p returned\n", image );
|
||||
|
||||
/* Re-register image and return */
|
||||
register_image ( image );
|
||||
image_put ( image );
|
||||
comboot_force_text_mode();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -142,16 +142,16 @@ static int comboot_exec ( struct image *image ) {
|
||||
comboot_init_psp ( image, seg_userptr );
|
||||
|
||||
/* Hook COMBOOT API interrupts */
|
||||
hook_comboot_interrupts ( );
|
||||
hook_comboot_interrupts();
|
||||
|
||||
DBGC ( image, "executing 16-bit COMBOOT image at %4x:0100\n",
|
||||
COMBOOT_PSP_SEG );
|
||||
COMBOOT_PSP_SEG );
|
||||
|
||||
/* Temporarily de-register image, so that a "boot" command
|
||||
* doesn't throw us into an execution loop. Hold a reference
|
||||
* to avoid the image's being freed.
|
||||
/* Unregister image, so that a "boot" command doesn't
|
||||
* throw us into an execution loop. We never
|
||||
* reregister ourselves; COMBOOT images expect to be
|
||||
* removed on exit.
|
||||
*/
|
||||
image_get ( image );
|
||||
unregister_image ( image );
|
||||
|
||||
/* Store stack segment at 0x38 and stack pointer at 0x3A
|
||||
@@ -180,26 +180,32 @@ static int comboot_exec ( struct image *image ) {
|
||||
"xorw %%bp, %%bp\n\t"
|
||||
"lret\n\t" )
|
||||
: : "r" ( COMBOOT_PSP_SEG ) : "eax" );
|
||||
DBGC ( image, "COMBOOT %p: returned\n", image );
|
||||
break;
|
||||
|
||||
case COMBOOT_RETURN_RUN_KERNEL:
|
||||
DBGC ( image, "COMBOOT %p: returned to run kernel...\n", image );
|
||||
comboot_run_kernel ( );
|
||||
case COMBOOT_EXIT:
|
||||
DBGC ( image, "COMBOOT %p: exited\n", image );
|
||||
break;
|
||||
|
||||
case COMBOOT_RETURN_EXIT:
|
||||
case COMBOOT_EXIT_RUN_KERNEL:
|
||||
DBGC ( image, "COMBOOT %p: exited to run kernel %p\n",
|
||||
image, comboot_replacement_image );
|
||||
image->replacement = comboot_replacement_image;
|
||||
image_autoload ( image->replacement );
|
||||
break;
|
||||
|
||||
case COMBOOT_EXIT_COMMAND:
|
||||
DBGC ( image, "COMBOOT %p: exited after executing command\n",
|
||||
image );
|
||||
break;
|
||||
|
||||
default:
|
||||
assert ( 0 );
|
||||
break;
|
||||
}
|
||||
|
||||
comboot_force_text_mode ( );
|
||||
comboot_force_text_mode();
|
||||
|
||||
DBGC ( image, "COMBOOT %p returned\n", image );
|
||||
|
||||
/* Re-register image and return */
|
||||
register_image ( image );
|
||||
image_put ( image );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user