You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

efi_image.c 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /*
  2. * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. FILE_LICENCE ( GPL2_OR_LATER );
  19. #include <errno.h>
  20. #include <stdlib.h>
  21. #include <ipxe/efi/efi.h>
  22. #include <ipxe/image.h>
  23. #include <ipxe/init.h>
  24. #include <ipxe/features.h>
  25. #include <ipxe/uri.h>
  26. FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
  27. /** EFI loaded image protocol GUID */
  28. static EFI_GUID efi_loaded_image_protocol_guid =
  29. EFI_LOADED_IMAGE_PROTOCOL_GUID;
  30. /**
  31. * Create a Unicode command line for the image
  32. *
  33. * @v image EFI image
  34. * @v devpath_out Device path to pass to image (output)
  35. * @v cmdline_out Unicode command line (output)
  36. * @v cmdline_len_out Length of command line in bytes (output)
  37. * @ret rc Return status code
  38. */
  39. static int efi_image_make_cmdline ( struct image *image,
  40. EFI_DEVICE_PATH **devpath_out,
  41. VOID **cmdline_out,
  42. UINT32 *cmdline_len_out ) {
  43. char *uri;
  44. size_t uri_len;
  45. FILEPATH_DEVICE_PATH *devpath;
  46. EFI_DEVICE_PATH *endpath;
  47. size_t devpath_len;
  48. CHAR16 *cmdline;
  49. UINT32 cmdline_len;
  50. size_t args_len = 0;
  51. UINT32 i;
  52. /* Get the URI string of the image */
  53. uri_len = unparse_uri ( NULL, 0, image->uri, URI_ALL ) + 1;
  54. /* Compute final command line length */
  55. if ( image->cmdline ) {
  56. args_len = strlen ( image->cmdline ) + 1;
  57. }
  58. cmdline_len = args_len + uri_len;
  59. /* Allocate space for the uri, final command line and device path */
  60. cmdline = malloc ( cmdline_len * sizeof ( CHAR16 ) + uri_len
  61. + SIZE_OF_FILEPATH_DEVICE_PATH
  62. + uri_len * sizeof ( CHAR16 )
  63. + sizeof ( EFI_DEVICE_PATH ) );
  64. if ( ! cmdline )
  65. return -ENOMEM;
  66. uri = (char *) ( cmdline + cmdline_len );
  67. devpath = (FILEPATH_DEVICE_PATH *) ( uri + uri_len );
  68. endpath = (EFI_DEVICE_PATH *) ( (char *) devpath
  69. + SIZE_OF_FILEPATH_DEVICE_PATH
  70. + uri_len * sizeof ( CHAR16 ) );
  71. /* Build the iPXE device path */
  72. devpath->Header.Type = MEDIA_DEVICE_PATH;
  73. devpath->Header.SubType = MEDIA_FILEPATH_DP;
  74. devpath_len = SIZE_OF_FILEPATH_DEVICE_PATH
  75. + uri_len * sizeof ( CHAR16 );
  76. devpath->Header.Length[0] = devpath_len & 0xFF;
  77. devpath->Header.Length[1] = devpath_len >> 8;
  78. endpath->Type = END_DEVICE_PATH_TYPE;
  79. endpath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
  80. endpath->Length[0] = 4;
  81. endpath->Length[1] = 0;
  82. unparse_uri ( uri, uri_len, image->uri, URI_ALL );
  83. /* Convert to Unicode */
  84. for ( i = 0 ; i < uri_len ; i++ ) {
  85. cmdline[i] = uri[i];
  86. devpath->PathName[i] = uri[i];
  87. }
  88. if ( image->cmdline ) {
  89. cmdline[uri_len - 1] = ' ';
  90. }
  91. for ( i = 0 ; i < args_len ; i++ ) {
  92. cmdline[i + uri_len] = image->cmdline[i];
  93. }
  94. *devpath_out = &devpath->Header;
  95. *cmdline_out = cmdline;
  96. *cmdline_len_out = cmdline_len * sizeof ( CHAR16 );
  97. return 0;
  98. }
  99. /**
  100. * Execute EFI image
  101. *
  102. * @v image EFI image
  103. * @ret rc Return status code
  104. */
  105. static int efi_image_exec ( struct image *image ) {
  106. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  107. union {
  108. EFI_LOADED_IMAGE_PROTOCOL *image;
  109. void *interface;
  110. } loaded;
  111. EFI_HANDLE handle;
  112. EFI_HANDLE device_handle = NULL;
  113. UINTN exit_data_size;
  114. CHAR16 *exit_data;
  115. EFI_STATUS efirc;
  116. int rc;
  117. /* Attempt loading image */
  118. if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL,
  119. user_to_virt ( image->data, 0 ),
  120. image->len, &handle ) ) != 0 ) {
  121. /* Not an EFI image */
  122. DBGC ( image, "EFIIMAGE %p could not load: %s\n",
  123. image, efi_strerror ( efirc ) );
  124. rc = -ENOEXEC;
  125. goto err_load_image;
  126. }
  127. /* Get the loaded image protocol for the newly loaded image */
  128. efirc = bs->OpenProtocol ( handle, &efi_loaded_image_protocol_guid,
  129. &loaded.interface, efi_image_handle,
  130. NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL );
  131. if ( efirc ) {
  132. /* Should never happen */
  133. rc = EFIRC_TO_RC ( efirc );
  134. goto err_open_protocol;
  135. }
  136. /* Pass an iPXE download protocol to the image */
  137. if ( ( rc = efi_download_install ( &device_handle ) ) != 0 ) {
  138. DBGC ( image, "EFIIMAGE %p could not install iPXE download "
  139. "protocol: %s\n", image, strerror ( rc ) );
  140. goto err_download_install;
  141. }
  142. loaded.image->DeviceHandle = device_handle;
  143. loaded.image->ParentHandle = efi_loaded_image;
  144. if ( ( rc = efi_image_make_cmdline ( image, &loaded.image->FilePath,
  145. &loaded.image->LoadOptions,
  146. &loaded.image->LoadOptionsSize ) ) != 0 )
  147. goto err_make_cmdline;
  148. /* Start the image */
  149. if ( ( efirc = bs->StartImage ( handle, &exit_data_size,
  150. &exit_data ) ) != 0 ) {
  151. DBGC ( image, "EFIIMAGE %p returned with status %s\n",
  152. image, efi_strerror ( efirc ) );
  153. rc = EFIRC_TO_RC ( efirc );
  154. goto err_start_image;
  155. }
  156. /* Success */
  157. rc = 0;
  158. err_start_image:
  159. free ( loaded.image->LoadOptions );
  160. err_make_cmdline:
  161. efi_download_uninstall ( device_handle );
  162. err_download_install:
  163. err_open_protocol:
  164. /* Unload the image. We can't leave it loaded, because we
  165. * have no "unload" operation.
  166. */
  167. bs->UnloadImage ( handle );
  168. err_load_image:
  169. return rc;
  170. }
  171. /**
  172. * Probe EFI image
  173. *
  174. * @v image EFI file
  175. * @ret rc Return status code
  176. */
  177. static int efi_image_probe ( struct image *image ) {
  178. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  179. EFI_HANDLE handle;
  180. EFI_STATUS efirc;
  181. /* Attempt loading image */
  182. if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL,
  183. user_to_virt ( image->data, 0 ),
  184. image->len, &handle ) ) != 0 ) {
  185. /* Not an EFI image */
  186. DBGC ( image, "EFIIMAGE %p could not load: %s\n",
  187. image, efi_strerror ( efirc ) );
  188. return -ENOEXEC;
  189. }
  190. /* Unload the image. We can't leave it loaded, because we
  191. * have no "unload" operation.
  192. */
  193. bs->UnloadImage ( handle );
  194. return 0;
  195. }
  196. /** EFI image type */
  197. struct image_type efi_image_type __image_type ( PROBE_NORMAL ) = {
  198. .name = "EFI",
  199. .probe = efi_image_probe,
  200. .exec = efi_image_exec,
  201. };