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.

eltorito.c 8.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /*
  2. * Copyright (C) 2007 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. /**
  20. * @file
  21. *
  22. * El Torito bootable ISO image format
  23. *
  24. */
  25. #include <stdint.h>
  26. #include <errno.h>
  27. #include <assert.h>
  28. #include <realmode.h>
  29. #include <bootsector.h>
  30. #include <int13.h>
  31. #include <ipxe/uaccess.h>
  32. #include <ipxe/image.h>
  33. #include <ipxe/segment.h>
  34. #include <ipxe/ramdisk.h>
  35. #include <ipxe/init.h>
  36. #define ISO9660_BLKSIZE 2048
  37. #define ELTORITO_VOL_DESC_OFFSET ( 17 * ISO9660_BLKSIZE )
  38. /** An El Torito Boot Record Volume Descriptor */
  39. struct eltorito_vol_desc {
  40. /** Boot record indicator; must be 0 */
  41. uint8_t record_indicator;
  42. /** ISO-9660 identifier; must be "CD001" */
  43. uint8_t iso9660_id[5];
  44. /** Version, must be 1 */
  45. uint8_t version;
  46. /** Boot system indicator; must be "EL TORITO SPECIFICATION" */
  47. uint8_t system_indicator[32];
  48. /** Unused */
  49. uint8_t unused[32];
  50. /** Boot catalog sector */
  51. uint32_t sector;
  52. } __attribute__ (( packed ));
  53. /** An El Torito Boot Catalog Validation Entry */
  54. struct eltorito_validation_entry {
  55. /** Header ID; must be 1 */
  56. uint8_t header_id;
  57. /** Platform ID
  58. *
  59. * 0 = 80x86
  60. * 1 = PowerPC
  61. * 2 = Mac
  62. */
  63. uint8_t platform_id;
  64. /** Reserved */
  65. uint16_t reserved;
  66. /** ID string */
  67. uint8_t id_string[24];
  68. /** Checksum word */
  69. uint16_t checksum;
  70. /** Signature; must be 0xaa55 */
  71. uint16_t signature;
  72. } __attribute__ (( packed ));
  73. /** A bootable entry in the El Torito Boot Catalog */
  74. struct eltorito_boot_entry {
  75. /** Boot indicator
  76. *
  77. * Must be @c ELTORITO_BOOTABLE for a bootable ISO image
  78. */
  79. uint8_t indicator;
  80. /** Media type
  81. *
  82. */
  83. uint8_t media_type;
  84. /** Load segment */
  85. uint16_t load_segment;
  86. /** System type */
  87. uint8_t filesystem;
  88. /** Unused */
  89. uint8_t reserved_a;
  90. /** Sector count */
  91. uint16_t length;
  92. /** Starting sector */
  93. uint32_t start;
  94. /** Unused */
  95. uint8_t reserved_b[20];
  96. } __attribute__ (( packed ));
  97. /** Boot indicator for a bootable ISO image */
  98. #define ELTORITO_BOOTABLE 0x88
  99. /** El Torito media types */
  100. enum eltorito_media_type {
  101. /** No emulation */
  102. ELTORITO_NO_EMULATION = 0,
  103. };
  104. struct image_type eltorito_image_type __image_type ( PROBE_NORMAL );
  105. /**
  106. * Calculate 16-bit word checksum
  107. *
  108. * @v data Data to checksum
  109. * @v len Length (in bytes, must be even)
  110. * @ret sum Checksum
  111. */
  112. static unsigned int word_checksum ( void *data, size_t len ) {
  113. uint16_t *words;
  114. uint16_t sum = 0;
  115. for ( words = data ; len ; words++, len -= 2 ) {
  116. sum += *words;
  117. }
  118. return sum;
  119. }
  120. /**
  121. * Execute El Torito image
  122. *
  123. * @v image El Torito image
  124. * @ret rc Return status code
  125. */
  126. static int eltorito_exec ( struct image *image ) {
  127. struct ramdisk ramdisk;
  128. struct int13_drive int13_drive;
  129. unsigned int load_segment = image->priv.ul;
  130. unsigned int load_offset = ( load_segment ? 0 : 0x7c00 );
  131. int rc;
  132. memset ( &ramdisk, 0, sizeof ( ramdisk ) );
  133. init_ramdisk ( &ramdisk, image->data, image->len, ISO9660_BLKSIZE );
  134. memset ( &int13_drive, 0, sizeof ( int13_drive ) );
  135. int13_drive.blockdev = &ramdisk.blockdev;
  136. register_int13_drive ( &int13_drive );
  137. if ( ( rc = call_bootsector ( load_segment, load_offset,
  138. int13_drive.drive ) ) != 0 ) {
  139. DBGC ( image, "ElTorito %p boot failed: %s\n",
  140. image, strerror ( rc ) );
  141. goto err;
  142. }
  143. rc = -ECANCELED; /* -EIMPOSSIBLE */
  144. err:
  145. unregister_int13_drive ( &int13_drive );
  146. return rc;
  147. }
  148. /**
  149. * Read and verify El Torito Boot Record Volume Descriptor
  150. *
  151. * @v image El Torito file
  152. * @ret catalog_offset Offset of Boot Catalog
  153. * @ret rc Return status code
  154. */
  155. static int eltorito_read_voldesc ( struct image *image,
  156. unsigned long *catalog_offset ) {
  157. static const struct eltorito_vol_desc vol_desc_signature = {
  158. .record_indicator = 0,
  159. .iso9660_id = "CD001",
  160. .version = 1,
  161. .system_indicator = "EL TORITO SPECIFICATION",
  162. };
  163. struct eltorito_vol_desc vol_desc;
  164. /* Sanity check */
  165. if ( image->len < ( ELTORITO_VOL_DESC_OFFSET + ISO9660_BLKSIZE ) ) {
  166. DBGC ( image, "ElTorito %p too short\n", image );
  167. return -ENOEXEC;
  168. }
  169. /* Read and verify Boot Record Volume Descriptor */
  170. copy_from_user ( &vol_desc, image->data, ELTORITO_VOL_DESC_OFFSET,
  171. sizeof ( vol_desc ) );
  172. if ( memcmp ( &vol_desc, &vol_desc_signature,
  173. offsetof ( typeof ( vol_desc ), sector ) ) != 0 ) {
  174. DBGC ( image, "ElTorito %p invalid Boot Record Volume "
  175. "Descriptor\n", image );
  176. return -ENOEXEC;
  177. }
  178. *catalog_offset = ( vol_desc.sector * ISO9660_BLKSIZE );
  179. DBGC ( image, "ElTorito %p boot catalog at offset %#lx\n",
  180. image, *catalog_offset );
  181. return 0;
  182. }
  183. /**
  184. * Read and verify El Torito Boot Catalog
  185. *
  186. * @v image El Torito file
  187. * @v catalog_offset Offset of Boot Catalog
  188. * @ret boot_entry El Torito boot entry
  189. * @ret rc Return status code
  190. */
  191. static int eltorito_read_catalog ( struct image *image,
  192. unsigned long catalog_offset,
  193. struct eltorito_boot_entry *boot_entry ) {
  194. struct eltorito_validation_entry validation_entry;
  195. /* Sanity check */
  196. if ( image->len < ( catalog_offset + ISO9660_BLKSIZE ) ) {
  197. DBGC ( image, "ElTorito %p bad boot catalog offset %#lx\n",
  198. image, catalog_offset );
  199. return -ENOEXEC;
  200. }
  201. /* Read and verify the Validation Entry of the Boot Catalog */
  202. copy_from_user ( &validation_entry, image->data, catalog_offset,
  203. sizeof ( validation_entry ) );
  204. if ( word_checksum ( &validation_entry,
  205. sizeof ( validation_entry ) ) != 0 ) {
  206. DBGC ( image, "ElTorito %p bad Validation Entry checksum\n",
  207. image );
  208. return -ENOEXEC;
  209. }
  210. /* Read and verify the Initial/Default entry */
  211. copy_from_user ( boot_entry, image->data,
  212. ( catalog_offset + sizeof ( validation_entry ) ),
  213. sizeof ( *boot_entry ) );
  214. if ( boot_entry->indicator != ELTORITO_BOOTABLE ) {
  215. DBGC ( image, "ElTorito %p not bootable\n", image );
  216. return -ENOEXEC;
  217. }
  218. if ( boot_entry->media_type != ELTORITO_NO_EMULATION ) {
  219. DBGC ( image, "ElTorito %p cannot support media type %d\n",
  220. image, boot_entry->media_type );
  221. return -ENOTSUP;
  222. }
  223. DBGC ( image, "ElTorito %p media type %d segment %04x\n",
  224. image, boot_entry->media_type, boot_entry->load_segment );
  225. return 0;
  226. }
  227. /**
  228. * Load El Torito virtual disk image into memory
  229. *
  230. * @v image El Torito file
  231. * @v boot_entry El Torito boot entry
  232. * @ret rc Return status code
  233. */
  234. static int eltorito_load_disk ( struct image *image,
  235. struct eltorito_boot_entry *boot_entry ) {
  236. unsigned long start = ( boot_entry->start * ISO9660_BLKSIZE );
  237. unsigned long length = ( boot_entry->length * ISO9660_BLKSIZE );
  238. unsigned int load_segment;
  239. userptr_t buffer;
  240. int rc;
  241. /* Sanity check */
  242. if ( image->len < ( start + length ) ) {
  243. DBGC ( image, "ElTorito %p virtual disk lies outside image\n",
  244. image );
  245. return -ENOEXEC;
  246. }
  247. DBGC ( image, "ElTorito %p virtual disk at %#lx+%#lx\n",
  248. image, start, length );
  249. /* Calculate load address */
  250. load_segment = boot_entry->load_segment;
  251. buffer = real_to_user ( load_segment, ( load_segment ? 0 : 0x7c00 ) );
  252. /* Verify and prepare segment */
  253. if ( ( rc = prep_segment ( buffer, length, length ) ) != 0 ) {
  254. DBGC ( image, "ElTorito %p could not prepare segment: %s\n",
  255. image, strerror ( rc ) );
  256. return rc;
  257. }
  258. /* Copy image to segment */
  259. memcpy_user ( buffer, 0, image->data, start, length );
  260. return 0;
  261. }
  262. /**
  263. * Load El Torito image into memory
  264. *
  265. * @v image El Torito file
  266. * @ret rc Return status code
  267. */
  268. static int eltorito_load ( struct image *image ) {
  269. struct eltorito_boot_entry boot_entry;
  270. unsigned long bootcat_offset;
  271. int rc;
  272. /* Read Boot Record Volume Descriptor, if present */
  273. if ( ( rc = eltorito_read_voldesc ( image, &bootcat_offset ) ) != 0 )
  274. return rc;
  275. /* This is an El Torito image, valid or otherwise */
  276. if ( ! image->type )
  277. image->type = &eltorito_image_type;
  278. /* Read Boot Catalog */
  279. if ( ( rc = eltorito_read_catalog ( image, bootcat_offset,
  280. &boot_entry ) ) != 0 )
  281. return rc;
  282. /* Load Virtual Disk image */
  283. if ( ( rc = eltorito_load_disk ( image, &boot_entry ) ) != 0 )
  284. return rc;
  285. /* Record load segment in image private data field */
  286. image->priv.ul = boot_entry.load_segment;
  287. return 0;
  288. }
  289. /** El Torito image type */
  290. struct image_type eltorito_image_type __image_type ( PROBE_NORMAL ) = {
  291. .name = "El Torito",
  292. .load = eltorito_load,
  293. .exec = eltorito_exec,
  294. };