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

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