Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16604 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			275 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			275 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Decode an El Torito formatted CD-ROM
 | |
| 
 | |
| Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
 | |
| This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions of the BSD License
 | |
| which accompanies this distribution.  The full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| 
 | |
| #include "Partition.h"
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Install child handles if the Handle supports El Torito format.
 | |
| 
 | |
|   @param[in]  This        Calling context.
 | |
|   @param[in]  Handle      Parent Handle.
 | |
|   @param[in]  DiskIo      Parent DiskIo interface.
 | |
|   @param[in]  DiskIo2     Parent DiskIo2 interface.
 | |
|   @param[in]  BlockIo     Parent BlockIo interface.
 | |
|   @param[in]  BlockIo2    Parent BlockIo2 interface.
 | |
|   @param[in]  DevicePath  Parent Device Path
 | |
| 
 | |
| 
 | |
|   @retval EFI_SUCCESS         Child handle(s) was added.
 | |
|   @retval EFI_MEDIA_CHANGED   Media changed Detected.
 | |
|   @retval other               no child handle was added.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PartitionInstallElToritoChildHandles (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
 | |
|   IN  EFI_HANDLE                   Handle,
 | |
|   IN  EFI_DISK_IO_PROTOCOL         *DiskIo,
 | |
|   IN  EFI_DISK_IO2_PROTOCOL        *DiskIo2,
 | |
|   IN  EFI_BLOCK_IO_PROTOCOL        *BlockIo,
 | |
|   IN  EFI_BLOCK_IO2_PROTOCOL       *BlockIo2,
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   UINT64                  VolDescriptorOffset;
 | |
|   UINT32                  Lba2KB;
 | |
|   EFI_BLOCK_IO_MEDIA      *Media;
 | |
|   CDROM_VOLUME_DESCRIPTOR *VolDescriptor;
 | |
|   ELTORITO_CATALOG        *Catalog;
 | |
|   UINTN                   Check;
 | |
|   UINTN                   Index;
 | |
|   UINTN                   BootEntry;
 | |
|   UINTN                   MaxIndex;
 | |
|   UINT16                  *CheckBuffer;
 | |
|   CDROM_DEVICE_PATH       CdDev;
 | |
|   UINT32                  SubBlockSize;
 | |
|   UINT32                  SectorCount;
 | |
|   EFI_STATUS              Found;
 | |
|   UINT32                  VolSpaceSize;
 | |
| 
 | |
|   Found         = EFI_NOT_FOUND;
 | |
|   Media         = BlockIo->Media;
 | |
| 
 | |
|   VolSpaceSize  = 0;
 | |
| 
 | |
|   //
 | |
|   // CD_ROM has the fixed block size as 2048 bytes (SIZE_2KB)
 | |
|   //
 | |
| 
 | |
|   // If the ISO image has been copied onto a different storage media
 | |
|   // then the block size might be different (eg: USB).
 | |
|   // Ensure 2048 (SIZE_2KB) is a multiple of block size
 | |
|   if (((SIZE_2KB % Media->BlockSize) != 0) || (Media->BlockSize > SIZE_2KB)) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   VolDescriptor = AllocatePool ((UINTN)SIZE_2KB);
 | |
| 
 | |
|   if (VolDescriptor == NULL) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   Catalog = (ELTORITO_CATALOG *) VolDescriptor;
 | |
| 
 | |
|   //
 | |
|   // Loop: handle one volume descriptor per time
 | |
|   //       The ISO-9660 volume descriptor starts at 32k on the media
 | |
|   //
 | |
|   for (VolDescriptorOffset = SIZE_32KB;
 | |
|        VolDescriptorOffset <= MultU64x32 (Media->LastBlock, Media->BlockSize);
 | |
|        VolDescriptorOffset += SIZE_2KB) {
 | |
|     Status = DiskIo->ReadDisk (
 | |
|                        DiskIo,
 | |
|                        Media->MediaId,
 | |
|                        VolDescriptorOffset,
 | |
|                        SIZE_2KB,
 | |
|                        VolDescriptor
 | |
|                        );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Found = Status;
 | |
|       break;
 | |
|     }
 | |
|     //
 | |
|     // Check for valid volume descriptor signature
 | |
|     //
 | |
|     if (VolDescriptor->Unknown.Type == CDVOL_TYPE_END ||
 | |
|         CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0
 | |
|         ) {
 | |
|       //
 | |
|       // end of Volume descriptor list
 | |
|       //
 | |
|       break;
 | |
|     }
 | |
|     //
 | |
|     // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte,
 | |
|     // the 32-bit numerical values is stored in Both-byte orders
 | |
|     //
 | |
|     if (VolDescriptor->PrimaryVolume.Type == CDVOL_TYPE_CODED) {
 | |
|       VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[0];
 | |
|     }
 | |
|     //
 | |
|     // Is it an El Torito volume descriptor?
 | |
|     //
 | |
|     if (CompareMem (VolDescriptor->BootRecordVolume.SystemId, CDVOL_ELTORITO_ID, sizeof (CDVOL_ELTORITO_ID) - 1) != 0) {
 | |
|       continue;
 | |
|     }
 | |
|     //
 | |
|     // Read in the boot El Torito boot catalog
 | |
|     // The LBA unit used by El Torito boot catalog is 2KB unit
 | |
|     //
 | |
|     Lba2KB = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog);
 | |
|     // Ensure the LBA (in 2KB unit) fits into our media
 | |
|     if (Lba2KB * (SIZE_2KB / Media->BlockSize) > Media->LastBlock) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     Status = DiskIo->ReadDisk (
 | |
|                        DiskIo,
 | |
|                        Media->MediaId,
 | |
|                        MultU64x32 (Lba2KB, SIZE_2KB),
 | |
|                        SIZE_2KB,
 | |
|                        Catalog
 | |
|                        );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((EFI_D_ERROR, "EltCheckDevice: error reading catalog %r\n", Status));
 | |
|       continue;
 | |
|     }
 | |
|     //
 | |
|     // We don't care too much about the Catalog header's contents, but we do want
 | |
|     // to make sure it looks like a Catalog header
 | |
|     //
 | |
|     if (Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG || Catalog->Catalog.Id55AA != 0xAA55) {
 | |
|       DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header IDs not correct\n"));
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     Check       = 0;
 | |
|     CheckBuffer = (UINT16 *) Catalog;
 | |
|     for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) {
 | |
|       Check += CheckBuffer[Index];
 | |
|     }
 | |
| 
 | |
|     if ((Check & 0xFFFF) != 0) {
 | |
|       DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n"));
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     MaxIndex = Media->BlockSize / sizeof (ELTORITO_CATALOG);
 | |
|     for (Index = 1, BootEntry = 1; Index < MaxIndex; Index += 1) {
 | |
|       //
 | |
|       // Next entry
 | |
|       //
 | |
|       Catalog += 1;
 | |
| 
 | |
|       //
 | |
|       // Check this entry
 | |
|       //
 | |
|       if (Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE || Catalog->Boot.Lba == 0) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       SubBlockSize  = 512;
 | |
|       SectorCount   = Catalog->Boot.SectorCount * (SIZE_2KB / Media->BlockSize);
 | |
| 
 | |
|       switch (Catalog->Boot.MediaType) {
 | |
| 
 | |
|       case ELTORITO_NO_EMULATION:
 | |
|         SubBlockSize = Media->BlockSize;
 | |
|         break;
 | |
| 
 | |
|       case ELTORITO_HARD_DISK:
 | |
|         break;
 | |
| 
 | |
|       case ELTORITO_12_DISKETTE:
 | |
|         SectorCount = 0x50 * 0x02 * 0x0F;
 | |
|         break;
 | |
| 
 | |
|       case ELTORITO_14_DISKETTE:
 | |
|         SectorCount = 0x50 * 0x02 * 0x12;
 | |
|         break;
 | |
| 
 | |
|       case ELTORITO_28_DISKETTE:
 | |
|         SectorCount = 0x50 * 0x02 * 0x24;
 | |
|         break;
 | |
| 
 | |
|       default:
 | |
|         DEBUG ((EFI_D_INIT, "EltCheckDevice: unsupported El Torito boot media type %x\n", Catalog->Boot.MediaType));
 | |
|         SectorCount   = 0;
 | |
|         SubBlockSize  = Media->BlockSize;
 | |
|         break;
 | |
|       }
 | |
|       //
 | |
|       // Create child device handle
 | |
|       //
 | |
|       CdDev.Header.Type     = MEDIA_DEVICE_PATH;
 | |
|       CdDev.Header.SubType  = MEDIA_CDROM_DP;
 | |
|       SetDevicePathNodeLength (&CdDev.Header, sizeof (CdDev));
 | |
| 
 | |
|       if (Index == 1) {
 | |
|         //
 | |
|         // This is the initial/default entry
 | |
|         //
 | |
|         BootEntry = 0;
 | |
|       }
 | |
| 
 | |
|       CdDev.BootEntry = (UINT32) BootEntry;
 | |
|       BootEntry++;
 | |
|       CdDev.PartitionStart = Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize);
 | |
|       if (SectorCount < 2) {
 | |
|         //
 | |
|         // When the SectorCount < 2, set the Partition as the whole CD.
 | |
|         //
 | |
|         if (VolSpaceSize > (Media->LastBlock + 1)) {
 | |
|           CdDev.PartitionSize = (UINT32)(Media->LastBlock - Catalog->Boot.Lba + 1);
 | |
|         } else {
 | |
|           CdDev.PartitionSize = (UINT32)(VolSpaceSize - Catalog->Boot.Lba);
 | |
|         }
 | |
|       } else {
 | |
|         CdDev.PartitionSize = DivU64x32 (
 | |
|                                 MultU64x32 (
 | |
|                                   SectorCount,
 | |
|                                   SubBlockSize
 | |
|                                   ) + Media->BlockSize - 1,
 | |
|                                 Media->BlockSize
 | |
|                                 );
 | |
|       }
 | |
| 
 | |
|       Status = PartitionInstallChildHandle (
 | |
|                 This,
 | |
|                 Handle,
 | |
|                 DiskIo,
 | |
|                 DiskIo2,
 | |
|                 BlockIo,
 | |
|                 BlockIo2,
 | |
|                 DevicePath,
 | |
|                 (EFI_DEVICE_PATH_PROTOCOL *) &CdDev,
 | |
|                 Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize),
 | |
|                 MultU64x32 (Catalog->Boot.Lba + CdDev.PartitionSize - 1, SIZE_2KB / Media->BlockSize),
 | |
|                 SubBlockSize,
 | |
|                 FALSE
 | |
|                 );
 | |
|       if (!EFI_ERROR (Status)) {
 | |
|         Found = EFI_SUCCESS;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   FreePool (VolDescriptor);
 | |
| 
 | |
|   return Found;
 | |
| }
 |