mirror of
https://github.com/ipxe/ipxe
synced 2025-12-18 10:30:23 +03:00
148 lines
3.7 KiB
C
148 lines
3.7 KiB
C
|
|
#include <etherboot.h>
|
|
#include <fs.h>
|
|
#include <lib.h>
|
|
|
|
#define DEBUG_THIS DEBUG_ELTORITO
|
|
#include <debug.h>
|
|
|
|
#define ELTORITO_PLATFORM_X86 0
|
|
#define ELTORITO_PLATFORM_PPC 1
|
|
#define ELTORITO_PLATFORM_MAC 2
|
|
#include <bits/eltorito.h>
|
|
|
|
#ifndef ELTORITO_PLATFORM
|
|
#error "ELTORITO_PLATFORM is not defined for this arch"
|
|
#endif
|
|
|
|
/* El Torito boot record at sector 0x11 of bootable CD */
|
|
struct boot_record {
|
|
uint8_t ind;
|
|
uint8_t iso_id[5];
|
|
uint8_t version;
|
|
uint8_t boot_id[32];
|
|
uint8_t reserved[32];
|
|
uint8_t catalog_offset[4];
|
|
};
|
|
|
|
/* First entry of the catalog */
|
|
struct validation_entry {
|
|
uint8_t header_id;
|
|
uint8_t platform;
|
|
uint8_t reserved[2];
|
|
uint8_t id[24];
|
|
uint8_t checksum[2];
|
|
uint8_t key55;
|
|
uint8_t keyAA;
|
|
};
|
|
|
|
/* Initial/Default catalog entry */
|
|
struct default_entry {
|
|
uint8_t boot_id;
|
|
uint8_t media_type;
|
|
#define MEDIA_MASK 0x0f
|
|
#define MEDIA_NOEMU 0
|
|
#define MEDIA_1200_FD 1
|
|
#define MEDIA_1440_FD 2
|
|
#define MEDIA_2880_FD 3
|
|
#define MEDIA_HD 4
|
|
uint8_t load_segment[2];
|
|
uint8_t system_type;
|
|
uint8_t reserved;
|
|
uint8_t sector_count[2];
|
|
uint8_t start_sector[4];
|
|
uint8_t reserved_too[20];
|
|
};
|
|
|
|
/* Find El-Torito boot disk image */
|
|
int open_eltorito_image(int part, unsigned long *offset_p,
|
|
unsigned long *length_p)
|
|
{
|
|
struct boot_record boot_record;
|
|
uint32_t cat_offset;
|
|
uint8_t catalog[2048];
|
|
struct validation_entry *ve;
|
|
int i, sum;
|
|
struct default_entry *de;
|
|
|
|
/* We always use 512-byte "soft sector", but
|
|
* El-Torito uses 2048-byte CD-ROM sector */
|
|
|
|
/* Boot Record is at sector 0x11 */
|
|
if (!devread(0x11<<2, 0, sizeof boot_record, &boot_record))
|
|
return 0;
|
|
|
|
if (boot_record.ind != 0
|
|
|| memcmp(boot_record.iso_id, "CD001", 5) != 0
|
|
|| memcmp(boot_record.boot_id, "EL TORITO SPECIFICATION", 23)
|
|
!= 0) {
|
|
debug("No El-Torito signature\n");
|
|
return PARTITION_UNKNOWN;
|
|
}
|
|
|
|
if (part != 0) {
|
|
printf("El-Torito entries other than Initial/Default is not supported\n");
|
|
return 0;
|
|
}
|
|
|
|
cat_offset = get_le32(boot_record.catalog_offset);
|
|
debug("El-Torito boot catalog at sector %u\n", cat_offset);
|
|
if (!devread(cat_offset<<2, 0, 2048, catalog))
|
|
return 0;
|
|
|
|
/* Validate the catalog */
|
|
ve = (void *) catalog;
|
|
//debug_hexdump(ve, sizeof *ve);
|
|
if (ve->header_id != 1 || ve->key55 != 0x55 || ve->keyAA != 0xAA) {
|
|
printf("Invalid El Torito boot catalog\n");
|
|
return 0;
|
|
}
|
|
/* All words must sum up to zero */
|
|
sum = 0;
|
|
for (i = 0; i < sizeof(*ve); i += 2)
|
|
sum += get_le16(&catalog[i]);
|
|
sum &= 0xffff;
|
|
if (sum != 0) {
|
|
printf("El Torito boot catalog verify failed\n");
|
|
return 0;
|
|
}
|
|
debug("id='%.*s'\n", sizeof ve->id, ve->id);
|
|
|
|
/* Platform check is warning only, because we won't directly execute
|
|
* the image. Just mounting it should be safe. */
|
|
if (ve->platform != ELTORITO_PLATFORM){
|
|
debugx("WARNING: Boot disk for different platform: %d\n", ve->platform);
|
|
}
|
|
|
|
/* Just support initial/default entry for now */
|
|
de = (void *) (ve + 1);
|
|
if (de->boot_id != 0x88) {
|
|
debugx("WARNING: Default boot entry is not bootable\n");
|
|
}
|
|
|
|
switch (de->media_type & MEDIA_MASK) {
|
|
case MEDIA_NOEMU:
|
|
printf("Disc doesn't use boot disk emulation\n");
|
|
return 0;
|
|
case MEDIA_1200_FD:
|
|
*length_p = 1200*1024/512;
|
|
break;
|
|
case MEDIA_1440_FD:
|
|
*length_p = 1440*1024/512;
|
|
break;
|
|
case MEDIA_2880_FD:
|
|
*length_p = 2880*1024/512;
|
|
break;
|
|
case MEDIA_HD:
|
|
/* FIXME: read partition table and return first partition.
|
|
* Spec states emulation HD has only one partition and it must
|
|
* be the first partition */
|
|
printf("Disc uses hard disk emulation - not supported\n");
|
|
return 0;
|
|
}
|
|
*offset_p = get_le32(de->start_sector) << 2;
|
|
debug("offset=%#lx length=%#lx\n", *offset_p, *length_p);
|
|
|
|
return 1;
|
|
}
|