]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c
MdeModulePkg/UsbMass: Fix USB key write failure
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbMassStorageDxe / UsbMassBoot.c
index b84bfd2d729034417dfe689f78119fdd5052ad36..69e2252134064b1a80574a0da73d80aa86664e87 100644 (file)
@@ -224,7 +224,7 @@ UsbBootExecCmd (
   If the device isn't ready, wait for it. If the device is ready\r
   and error occurs, retry the command again until it exceeds the\r
   limit of retrial times.\r
-  \r
+\r
   @param  UsbMass                The device to issue commands to\r
   @param  Cmd                    The command to execute\r
   @param  CmdLen                 The length of the command\r
@@ -412,7 +412,7 @@ UsbBootInquiry (
   @retval EFI_SUCCESS            The disk geometry is successfully retrieved.\r
   @retval EFI_NOT_READY          The returned block size is zero.\r
   @retval Other                  READ CAPACITY 16 bytes command execution failed.\r
\r
+\r
 **/\r
 EFI_STATUS\r
 UsbBootReadCapacity16 (\r
@@ -442,7 +442,7 @@ UsbBootReadCapacity16 (
   ZeroMem ((CapacityCmd + 2), 8);\r
 \r
   CapacityCmd[13] = sizeof (CapacityData);\r
-  \r
+\r
   Status = UsbBootExecCmdWithRetry (\r
              UsbMass,\r
              CapacityCmd,\r
@@ -464,13 +464,13 @@ UsbBootReadCapacity16 (
   Media->LastBlock    = SwapBytes64 (ReadUnaligned64 ((CONST UINT64 *) &(CapacityData.LastLba7)));\r
 \r
   BlockSize           = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) &(CapacityData.BlockSize3)));\r
-  \r
+\r
   Media->LowestAlignedLba = (CapacityData.LowestAlignLogic2 << 8) |\r
                              CapacityData.LowestAlignLogic1;\r
   Media->LogicalBlocksPerPhysicalBlock  = (1 << CapacityData.LogicPerPhysical);\r
   if (BlockSize == 0) {\r
     //\r
-    //  Get sense data  \r
+    //  Get sense data\r
     //\r
     return UsbBootRequestSense (UsbMass);\r
   } else {\r
@@ -494,7 +494,7 @@ UsbBootReadCapacity16 (
   @retval EFI_SUCCESS            The disk geometry is successfully retrieved.\r
   @retval EFI_NOT_READY          The returned block size is zero.\r
   @retval Other                  READ CAPACITY command execution failed.\r
\r
+\r
 **/\r
 EFI_STATUS\r
 UsbBootReadCapacity (\r
@@ -538,7 +538,7 @@ UsbBootReadCapacity (
   BlockSize           = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.BlockLen));\r
   if (BlockSize == 0) {\r
     //\r
-    //  Get sense data  \r
+    //  Get sense data\r
     //\r
     return UsbBootRequestSense (UsbMass);\r
   } else {\r
@@ -736,6 +736,13 @@ UsbBootDetectMedia (
     return Status;\r
   }\r
 \r
+  //\r
+  // Simply reject device whose block size is unacceptable small (==0) or large (>64K).\r
+  //\r
+  if ((Media->BlockSize == 0) || (Media->BlockSize > USB_BOOT_MAX_CARRY_SIZE)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
   //\r
   // Detect whether it is necessary to reinstall the Block I/O Protocol.\r
   //\r
@@ -792,33 +799,37 @@ UsbBootDetectMedia (
 \r
 \r
 /**\r
-  Read some blocks from the device.\r
+  Read or write some blocks from the device.\r
 \r
-  @param  UsbMass                The USB mass storage device to read from\r
+  @param  UsbMass                The USB mass storage device to access\r
+  @param  Write                  TRUE for write operation.\r
   @param  Lba                    The start block number\r
-  @param  TotalBlock             Total block number to read\r
-  @param  Buffer                 The buffer to read to\r
+  @param  TotalBlock             Total block number to read or write\r
+  @param  Buffer                 The buffer to read to or write from\r
 \r
-  @retval EFI_SUCCESS            Data are read into the buffer\r
-  @retval Others                 Failed to read all the data\r
+  @retval EFI_SUCCESS            Data are read into the buffer or writen into the device.\r
+  @retval Others                 Failed to read or write all the data\r
 \r
 **/\r
 EFI_STATUS\r
-UsbBootReadBlocks (\r
+UsbBootReadWriteBlocks (\r
   IN  USB_MASS_DEVICE       *UsbMass,\r
+  IN  BOOLEAN               Write,\r
   IN  UINT32                Lba,\r
   IN  UINTN                 TotalBlock,\r
-  OUT UINT8                 *Buffer\r
+  IN OUT UINT8              *Buffer\r
   )\r
 {\r
-  USB_BOOT_READ10_CMD       ReadCmd;\r
-  EFI_STATUS                Status;\r
-  UINT16                    Count;\r
-  UINT32                    BlockSize;\r
-  UINT32                    ByteSize;\r
-  UINT32                    Timeout;\r
+  USB_BOOT_READ_WRITE_10_CMD Cmd;\r
+  EFI_STATUS                 Status;\r
+  UINT32                     Count;\r
+  UINT32                     CountMax;\r
+  UINT32                     BlockSize;\r
+  UINT32                     ByteSize;\r
+  UINT32                     Timeout;\r
 \r
   BlockSize = UsbMass->BlockIoMedia.BlockSize;\r
+  CountMax  = USB_BOOT_MAX_CARRY_SIZE / BlockSize;\r
   Status    = EFI_SUCCESS;\r
 \r
   while (TotalBlock > 0) {\r
@@ -827,8 +838,9 @@ UsbBootReadBlocks (
     // on the device. We must split the total block because the READ10\r
     // command only has 16 bit transfer length (in the unit of block).\r
     //\r
-    Count     = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);\r
-    ByteSize  = (UINT32)Count * BlockSize;\r
+    Count    = (UINT32)MIN (TotalBlock, CountMax);\r
+    Count    = MIN (MAX_UINT16, Count);\r
+    ByteSize = Count * BlockSize;\r
 \r
     //\r
     // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]\r
@@ -838,18 +850,18 @@ UsbBootReadBlocks (
     //\r
     // Fill in the command then execute\r
     //\r
-    ZeroMem (&ReadCmd, sizeof (USB_BOOT_READ10_CMD));\r
+    ZeroMem (&Cmd, sizeof (USB_BOOT_READ_WRITE_10_CMD));\r
 \r
-    ReadCmd.OpCode  = USB_BOOT_READ10_OPCODE;\r
-    ReadCmd.Lun     = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));\r
-    WriteUnaligned32 ((UINT32 *) ReadCmd.Lba, SwapBytes32 (Lba));\r
-    WriteUnaligned16 ((UINT16 *) ReadCmd.TransferLen, SwapBytes16 (Count));\r
+    Cmd.OpCode  = Write ? USB_BOOT_WRITE10_OPCODE : USB_BOOT_READ10_OPCODE;\r
+    Cmd.Lun     = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));\r
+    WriteUnaligned32 ((UINT32 *) Cmd.Lba, SwapBytes32 (Lba));\r
+    WriteUnaligned16 ((UINT16 *) Cmd.TransferLen, SwapBytes16 ((UINT16)Count));\r
 \r
     Status = UsbBootExecCmdWithRetry (\r
                UsbMass,\r
-               &ReadCmd,\r
-               (UINT8) sizeof (USB_BOOT_READ10_CMD),\r
-               EfiUsbDataIn,\r
+               &Cmd,\r
+               (UINT8) sizeof (USB_BOOT_READ_WRITE_10_CMD),\r
+               Write ? EfiUsbDataOut : EfiUsbDataIn,\r
                Buffer,\r
                ByteSize,\r
                Timeout\r
@@ -857,128 +869,58 @@ UsbBootReadBlocks (
     if (EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
-    DEBUG ((EFI_D_BLKIO, "UsbBootReadBlocks: LBA (0x%x), Blk (0x%x)\n", Lba, Count));\r
+    DEBUG ((\r
+      DEBUG_BLKIO, "UsbBoot%sBlocks: LBA (0x%lx), Blk (0x%x)\n",\r
+      Write ? L"Write" : L"Read",\r
+      Lba, Count\r
+      ));\r
     Lba        += Count;\r
-    Buffer     += Count * BlockSize;\r
+    Buffer     += ByteSize;\r
     TotalBlock -= Count;\r
   }\r
 \r
   return Status;\r
 }\r
 \r
-\r
 /**\r
-  Write some blocks to the device.\r
+  Read or write some blocks from the device by SCSI 16 byte cmd.\r
 \r
-  @param  UsbMass                The USB mass storage device to write to\r
+  @param  UsbMass                The USB mass storage device to access\r
+  @param  Write                  TRUE for write operation.\r
   @param  Lba                    The start block number\r
-  @param  TotalBlock             Total block number to write\r
-  @param  Buffer                 Pointer to the source buffer for the data.\r
-\r
-  @retval EFI_SUCCESS            Data are written into the buffer\r
-  @retval Others                 Failed to write all the data\r
+  @param  TotalBlock             Total block number to read or write\r
+  @param  Buffer                 The buffer to read to or write from\r
 \r
+  @retval EFI_SUCCESS            Data are read into the buffer or writen into the device.\r
+  @retval Others                 Failed to read or write all the data\r
 **/\r
 EFI_STATUS\r
-UsbBootWriteBlocks (\r
-  IN  USB_MASS_DEVICE         *UsbMass,\r
-  IN  UINT32                  Lba,\r
-  IN  UINTN                   TotalBlock,\r
-  IN  UINT8                   *Buffer\r
-  )\r
-{\r
-  USB_BOOT_WRITE10_CMD  WriteCmd;\r
-  EFI_STATUS            Status;\r
-  UINT16                Count;\r
-  UINT32                BlockSize;\r
-  UINT32                ByteSize;\r
-  UINT32                Timeout;\r
-\r
-  BlockSize = UsbMass->BlockIoMedia.BlockSize;\r
-  Status    = EFI_SUCCESS;\r
-\r
-  while (TotalBlock > 0) {\r
-    //\r
-    // Split the total blocks into smaller pieces to ease the pressure\r
-    // on the device. We must split the total block because the WRITE10\r
-    // command only has 16 bit transfer length (in the unit of block).\r
-    //\r
-    Count     = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);\r
-    ByteSize  = (UINT32)Count * BlockSize;\r
-\r
-    //\r
-    // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]\r
-    //\r
-    Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;\r
-\r
-    //\r
-    // Fill in the write10 command block\r
-    //\r
-    ZeroMem (&WriteCmd, sizeof (USB_BOOT_WRITE10_CMD));\r
-\r
-    WriteCmd.OpCode = USB_BOOT_WRITE10_OPCODE;\r
-    WriteCmd.Lun    = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));\r
-    WriteUnaligned32 ((UINT32 *) WriteCmd.Lba, SwapBytes32 (Lba));\r
-    WriteUnaligned16 ((UINT16 *) WriteCmd.TransferLen, SwapBytes16 (Count));\r
-\r
-    Status = UsbBootExecCmdWithRetry (\r
-               UsbMass,\r
-               &WriteCmd,\r
-               (UINT8) sizeof (USB_BOOT_WRITE10_CMD),\r
-               EfiUsbDataOut,\r
-               Buffer,\r
-               ByteSize,\r
-               Timeout\r
-               );\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
-    DEBUG ((EFI_D_BLKIO, "UsbBootWriteBlocks: LBA (0x%x), Blk (0x%x)\n", Lba, Count));\r
-\r
-    Lba        += Count;\r
-    Buffer     += Count * BlockSize;\r
-    TotalBlock -= Count;\r
-  }\r
-\r
-  return Status;\r
-}\r
-\r
-/**\r
-  Read some blocks from the device by SCSI 16 byte cmd.\r
-\r
-  @param  UsbMass                The USB mass storage device to read from\r
-  @param  Lba                    The start block number\r
-  @param  TotalBlock             Total block number to read\r
-  @param  Buffer                 The buffer to read to\r
-\r
-  @retval EFI_SUCCESS            Data are read into the buffer\r
-  @retval Others                 Failed to read all the data\r
-\r
-**/\r
-EFI_STATUS\r
-UsbBootReadBlocks16 (\r
+UsbBootReadWriteBlocks16 (\r
   IN  USB_MASS_DEVICE       *UsbMass,\r
+  IN  BOOLEAN               Write,\r
   IN  UINT64                Lba,\r
   IN  UINTN                 TotalBlock,\r
-  OUT UINT8                 *Buffer\r
+  IN OUT UINT8              *Buffer\r
   )\r
 {\r
-  UINT8                     ReadCmd[16];\r
+  UINT8                     Cmd[16];\r
   EFI_STATUS                Status;\r
-  UINT16                    Count;\r
+  UINT32                    Count;\r
+  UINT32                    CountMax;\r
   UINT32                    BlockSize;\r
   UINT32                    ByteSize;\r
   UINT32                    Timeout;\r
 \r
   BlockSize = UsbMass->BlockIoMedia.BlockSize;\r
+  CountMax  = USB_BOOT_MAX_CARRY_SIZE / BlockSize;\r
   Status    = EFI_SUCCESS;\r
 \r
   while (TotalBlock > 0) {\r
     //\r
     // Split the total blocks into smaller pieces.\r
     //\r
-    Count     = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);\r
-    ByteSize  = (UINT32)Count * BlockSize;\r
+    Count    = (UINT32)MIN (TotalBlock, CountMax);\r
+    ByteSize Count * BlockSize;\r
 \r
     //\r
     // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]\r
@@ -988,92 +930,18 @@ UsbBootReadBlocks16 (
     //\r
     // Fill in the command then execute\r
     //\r
-    ZeroMem (ReadCmd, sizeof (ReadCmd));\r
-\r
-    ReadCmd[0]  = EFI_SCSI_OP_READ16;\r
-    ReadCmd[1]  = (UINT8) ((USB_BOOT_LUN (UsbMass->Lun) & 0xE0));\r
-    WriteUnaligned64 ((UINT64 *) &ReadCmd[2], SwapBytes64 (Lba));\r
-    WriteUnaligned32 ((UINT32 *) &ReadCmd[10], SwapBytes32 (Count));\r
-\r
-    Status = UsbBootExecCmdWithRetry (\r
-               UsbMass,\r
-               ReadCmd,\r
-               (UINT8) sizeof (ReadCmd),\r
-               EfiUsbDataIn,\r
-               Buffer,\r
-               ByteSize,\r
-               Timeout\r
-               );\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
-    DEBUG ((EFI_D_BLKIO, "UsbBootReadBlocks16: LBA (0x%lx), Blk (0x%x)\n", Lba, Count));\r
-    Lba        += Count;\r
-    Buffer     += Count * BlockSize;\r
-    TotalBlock -= Count;\r
-  }\r
-\r
-  return Status;\r
-}\r
-\r
-\r
-/**\r
-  Write some blocks to the device by SCSI 16 byte cmd.\r
-\r
-  @param  UsbMass                The USB mass storage device to write to\r
-  @param  Lba                    The start block number\r
-  @param  TotalBlock             Total block number to write\r
-  @param  Buffer                 Pointer to the source buffer for the data.\r
-\r
-  @retval EFI_SUCCESS            Data are written into the buffer\r
-  @retval Others                 Failed to write all the data\r
-\r
-**/\r
-EFI_STATUS\r
-UsbBootWriteBlocks16 (\r
-  IN  USB_MASS_DEVICE         *UsbMass,\r
-  IN  UINT64                  Lba,\r
-  IN  UINTN                   TotalBlock,\r
-  IN  UINT8                   *Buffer\r
-  )\r
-{\r
-  UINT8                 WriteCmd[16];\r
-  EFI_STATUS            Status;\r
-  UINT16                Count;\r
-  UINT32                BlockSize;\r
-  UINT32                ByteSize;\r
-  UINT32                Timeout;\r
-\r
-  BlockSize = UsbMass->BlockIoMedia.BlockSize;\r
-  Status    = EFI_SUCCESS;\r
-\r
-  while (TotalBlock > 0) {\r
-    //\r
-    // Split the total blocks into smaller pieces.\r
-    //\r
-    Count     = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);\r
-    ByteSize  = (UINT32)Count * BlockSize;\r
+    ZeroMem (Cmd, sizeof (Cmd));\r
 \r
-    //\r
-    // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]\r
-    //\r
-    Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;\r
-\r
-    //\r
-    // Fill in the write16 command block\r
-    //\r
-    ZeroMem (WriteCmd, sizeof (WriteCmd));\r
-\r
-    WriteCmd[0]  = EFI_SCSI_OP_WRITE16;\r
-    WriteCmd[1]  = (UINT8) ((USB_BOOT_LUN (UsbMass->Lun) & 0xE0));\r
-    WriteUnaligned64 ((UINT64 *) &WriteCmd[2], SwapBytes64 (Lba));\r
-    WriteUnaligned32 ((UINT32 *) &WriteCmd[10], SwapBytes32 (Count));\r
+    Cmd[0]  = Write ? EFI_SCSI_OP_WRITE16 : EFI_SCSI_OP_READ16;\r
+    Cmd[1]  = (UINT8) ((USB_BOOT_LUN (UsbMass->Lun) & 0xE0));\r
+    WriteUnaligned64 ((UINT64 *) &Cmd[2], SwapBytes64 (Lba));\r
+    WriteUnaligned32 ((UINT32 *) &Cmd[10], SwapBytes32 (Count));\r
 \r
     Status = UsbBootExecCmdWithRetry (\r
                UsbMass,\r
-               WriteCmd,\r
-               (UINT8) sizeof (WriteCmd),\r
-               EfiUsbDataOut,\r
+               Cmd,\r
+               (UINT8) sizeof (Cmd),\r
+               Write ? EfiUsbDataOut : EfiUsbDataIn,\r
                Buffer,\r
                ByteSize,\r
                Timeout\r
@@ -1081,9 +949,13 @@ UsbBootWriteBlocks16 (
     if (EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
-    DEBUG ((EFI_D_BLKIO, "UsbBootWriteBlocks: LBA (0x%lx), Blk (0x%x)\n", Lba, Count));\r
+    DEBUG ((\r
+      DEBUG_BLKIO, "UsbBoot%sBlocks16: LBA (0x%lx), Blk (0x%x)\n",\r
+      Write ? L"Write" : L"Read",\r
+      Lba, Count\r
+      ));\r
     Lba        += Count;\r
-    Buffer     += Count * BlockSize;\r
+    Buffer     += ByteSize;\r
     TotalBlock -= Count;\r
   }\r
 \r