| | 390 | #if defined(VBOX) |
| | 391 | // |
| | 392 | // Extract INT32 from char array |
| | 393 | // |
| | 394 | #define UNPACK_INT32(a) (INT32)( (((UINT8 *) a)[0] << 0) | \ |
| | 395 | (((UINT8 *) a)[1] << 8) | \ |
| | 396 | (((UINT8 *) a)[2] << 16) | \ |
| | 397 | (((UINT8 *) a)[3] << 24) ) |
| | 398 | |
| | 399 | /** |
| | 400 | Test for presence of one or more El Torito EFI boot entries. |
| | 401 | |
| | 402 | @param[in] BlockIo BlockIo interface. |
| | 403 | @param[in] DiskIo DiskIo interface. |
| | 404 | |
| | 405 | @retval EFI_SUCCESS An El Torito EFI boot entry was found. |
| | 406 | @retval EFI_NOT_FOUND An El Torito EFI boot entry was not found. |
| | 407 | @retval other Failed to perform disk I/O. |
| | 408 | |
| | 409 | **/ |
| | 410 | EFI_STATUS |
| | 411 | FindElToritoBootEntry ( |
| | 412 | IN EFI_BLOCK_IO_PROTOCOL *BlockIo, |
| | 413 | IN EFI_DISK_IO_PROTOCOL *DiskIo |
| | 414 | ) |
| | 415 | { |
| | 416 | EFI_STATUS Status; |
| | 417 | EFI_BLOCK_IO_MEDIA *Media; |
| | 418 | CDROM_VOLUME_DESCRIPTOR *VolDescriptor; |
| | 419 | ELTORITO_CATALOG *Catalog; |
| | 420 | UINT64 VolDescriptorOffset; |
| | 421 | UINT32 Lba2KB; |
| | 422 | UINTN Check; |
| | 423 | UINT16 *CheckBuffer; |
| | 424 | UINTN Index; |
| | 425 | UINTN InEfiSection; |
| | 426 | UINTN MaxIndex; |
| | 427 | EFI_STATUS Found; |
| | 428 | |
| | 429 | Found = EFI_NOT_FOUND; |
| | 430 | Media = BlockIo->Media; |
| | 431 | |
| | 432 | // |
| | 433 | // CD_ROM has the fixed block size as 2048 bytes (SIZE_2KB) |
| | 434 | // |
| | 435 | |
| | 436 | // If the ISO image has been copied onto a different storage media |
| | 437 | // then the block size might be different (eg: USB). |
| | 438 | // Ensure 2048 (SIZE_2KB) is a multiple of block size |
| | 439 | if (((SIZE_2KB % Media->BlockSize) != 0) || (Media->BlockSize > SIZE_2KB)) { |
| | 440 | return EFI_NOT_FOUND; |
| | 441 | } |
| | 442 | |
| | 443 | VolDescriptor = AllocatePool ((UINTN)SIZE_2KB); |
| | 444 | |
| | 445 | if (VolDescriptor == NULL) { |
| | 446 | return EFI_NOT_FOUND; |
| | 447 | } |
| | 448 | |
| | 449 | Catalog = (ELTORITO_CATALOG *) VolDescriptor; |
| | 450 | |
| | 451 | // |
| | 452 | // Loop: handle one volume descriptor per time |
| | 453 | // The ISO-9660 volume descriptor starts at 32k on the media |
| | 454 | // |
| | 455 | for (VolDescriptorOffset = SIZE_32KB; |
| | 456 | VolDescriptorOffset <= MultU64x32 (Media->LastBlock, Media->BlockSize); |
| | 457 | VolDescriptorOffset += SIZE_2KB) { |
| | 458 | Status = DiskIo->ReadDisk ( |
| | 459 | DiskIo, |
| | 460 | Media->MediaId, |
| | 461 | VolDescriptorOffset, |
| | 462 | SIZE_2KB, |
| | 463 | VolDescriptor |
| | 464 | ); |
| | 465 | if (EFI_ERROR (Status)) { |
| | 466 | Found = Status; |
| | 467 | break; |
| | 468 | } |
| | 469 | // |
| | 470 | // Check for valid volume descriptor signature |
| | 471 | // |
| | 472 | if (VolDescriptor->Unknown.Type == CDVOL_TYPE_END || |
| | 473 | CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0 |
| | 474 | ) { |
| | 475 | // |
| | 476 | // end of Volume descriptor list |
| | 477 | // |
| | 478 | break; |
| | 479 | } |
| | 480 | // |
| | 481 | // Is it an El Torito volume descriptor? |
| | 482 | // |
| | 483 | if (CompareMem (VolDescriptor->BootRecordVolume.SystemId, CDVOL_ELTORITO_ID, sizeof (CDVOL_ELTORITO_ID) - 1) != 0) { |
| | 484 | continue; |
| | 485 | } |
| | 486 | // |
| | 487 | // Read in the boot El Torito boot catalog |
| | 488 | // The LBA unit used by El Torito boot catalog is 2KB unit |
| | 489 | // |
| | 490 | Lba2KB = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog); |
| | 491 | // Ensure the LBA (in 2KB unit) fits into our media |
| | 492 | if (Lba2KB * (SIZE_2KB / Media->BlockSize) > Media->LastBlock) { |
| | 493 | continue; |
| | 494 | } |
| | 495 | |
| | 496 | Status = DiskIo->ReadDisk ( |
| | 497 | DiskIo, |
| | 498 | Media->MediaId, |
| | 499 | MultU64x32 (Lba2KB, SIZE_2KB), |
| | 500 | SIZE_2KB, |
| | 501 | Catalog |
| | 502 | ); |
| | 503 | if (EFI_ERROR (Status)) { |
| | 504 | DEBUG ((EFI_D_ERROR, "EltCheckDevice: error reading catalog %r\n", Status)); |
| | 505 | continue; |
| | 506 | } |
| | 507 | // |
| | 508 | // We don't care too much about the Catalog header's contents, but we do want |
| | 509 | // to make sure it looks like a Catalog header |
| | 510 | // |
| | 511 | if (Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG || Catalog->Catalog.Id55AA != 0xAA55) { |
| | 512 | DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header IDs not correct\n")); |
| | 513 | continue; |
| | 514 | } |
| | 515 | |
| | 516 | Check = 0; |
| | 517 | CheckBuffer = (UINT16 *) Catalog; |
| | 518 | for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) { |
| | 519 | Check += CheckBuffer[Index]; |
| | 520 | } |
| | 521 | |
| | 522 | if ((Check & 0xFFFF) != 0) { |
| | 523 | DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n")); |
| | 524 | continue; |
| | 525 | } |
| | 526 | |
| | 527 | InEfiSection = 0; |
| | 528 | |
| | 529 | // |
| | 530 | // Here we limit the scan to a single media block. In theory |
| | 531 | // an El Torito catalog can extend beyond that; in practice |
| | 532 | // that's unlikely. |
| | 533 | // |
| | 534 | MaxIndex = Media->BlockSize / sizeof (ELTORITO_CATALOG); |
| | 535 | for (Index = 1; Index < MaxIndex; Index += 1) { |
| | 536 | // |
| | 537 | // Next entry |
| | 538 | // |
| | 539 | Catalog += 1; |
| | 540 | |
| | 541 | // |
| | 542 | // Check this entry |
| | 543 | // |
| | 544 | if (Catalog->Section.Indicator == ELTORITO_ID_SECTION_HEADER || |
| | 545 | Catalog->Section.Indicator == ELTORITO_ID_SECTION_HEADER_FINAL) { |
| | 546 | InEfiSection = Catalog->Section.PlatformId == 0xEF; |
| | 547 | continue; |
| | 548 | } |
| | 549 | if (InEfiSection && |
| | 550 | Catalog->Boot.Indicator == ELTORITO_ID_SECTION_BOOTABLE && |
| | 551 | Catalog->Boot.MediaType == ELTORITO_NO_EMULATION && |
| | 552 | Catalog->Boot.Lba != 0) { |
| | 553 | Found = EFI_SUCCESS; |
| | 554 | break; |
| | 555 | } |
| | 556 | } |
| | 557 | } |
| | 558 | |
| | 559 | FreePool (VolDescriptor); |
| | 560 | |
| | 561 | return Found; |
| | 562 | } |
| | 563 | #endif |
| | 564 | |