uefi-rs icon indicating copy to clipboard operation
uefi-rs copied to clipboard

Implementing pass-through protocols

Open ethindp opened this issue 3 years ago • 6 comments

Right now I'm trying to implement the EFI ATA, NVMe, and SD MMC pass-through protocols. These are defined in SECs. 13.13 (pg. 582), 13.15 (pg. 605), and 13.16 (pg. 615) of UEFI 2.9. I'm starting off with EFI_ATA_PASS_THRU_PROTOCOL. I'm currently stuck on the EFI_ATA_PASS_THRU_PROTOCOL.PassThru() function. Its signature is:

           typedef
           EFI_STATUS
           (EFIAPI *EFI_ATA_PASS_THRU_PASSTHRU) (
            IN   EFI_ATA_PASS_THRU_PROTOCOL          *This,
            IN   UINT16                               Port,
            IN   UINT16                               PortMultiplierPort,
            IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet,
            IN   EFI_EVENT            Event OPTIONAL
            );

This isn't what I'm stuck on; I'm stuck on the related definitions that this function requires:

          typedef struct {
           EFI_ATA_STATUS_BLOCK           *Asb;
           EFI_ATA_COMMAND_BLOCK          *Acb;
           UINT64                         Timeout;
           VOID                           *InDataBuffer;
           VOID                           *OutDataBuffer;
           UINT32                         InTransferLength;
           UINT32                         OutTransferLength;
           EFI_ATA_PASS_THRU_CMD_PROTOCOL Protocol;
           EFI_ATA_PASS_THRU_LENGTH       Length;
          } EFI_ATA_PASS_THRU_COMMAND_PACKET;

           typedef struct _EFI_ATA_COMMAND_BLOCK {
            UINT8 Reserved1[2];
            UINT8 AtaCommand;
            UINT8 AtaFeatures;
            UINT8 AtaSectorNumber;
            UINT8 AtaCylinderLow;
            UINT8 AtaCylinderHigh;
            UINT8 AtaDeviceHead;
            UINT8 AtaSectorNumberExp;
            UINT8 AtaCylinderLowExp;
            UINT8 AtaCylinderHighExp;
            UINT8 AtaFeaturesExp;
            UINT8 AtaSectorCount;
            UINT8 AtaSectorCountExp;
            UINT8 Reserved2[6];
           } EFI_ATA_COMMAND_BLOCK;

           typedef struct _EFI_ATA_STATUS_BLOCK {
            UINT8 Reserved1[2];
            UINT8 AtaStatus;
            UINT8 AtaError;
            UINT8 AtaSectorNumber;
            UINT8 AtaCylinderLow;
            UINT8 AtaCylinderHigh;
            UINT8 AtaDeviceHead;
            UINT8 AtaSectorNumberExp;
            UINT8 AtaCylinderLowExp;
            UINT8 AtaCylinderHighExp;
            UINT8 Reserved2;
            UINT8 AtaSectorCount;
            UINT8 AtaSectorCountExp;
            UINT8 Reserved3[6];
           } EFI_ATA_STATUS_BLOCK;

           typedef UINT8 EFI_ATA_PASS_THRU_CMD_PROTOCOL;

           #define   EFI_ATA_PASS_THRU_PROTOCOL_ATA_HARDWARE_RESET   0x00
           #define   EFI_ATA_PASS_THRU_PROTOCOL_ATA_SOFTWARE_RESET   0x01
           #define   EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA         0x02
           #define   EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN          0x04
           #define   EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT         0x05
           #define   EFI_ATA_PASS_THRU_PROTOCOL_DMA                  0x06
           #define   EFI_ATA_PASS_THRU_PROTOCOL_DMA_QUEUED           0x07
           #define   EFI_ATA_PASS_THRU_PROTOCOL_DEVICE_DIAGNOSTIC    0x08
           #define   EFI_ATA_PASS_THRU_PROTOCOL_DEVICE_RESET         0x09
           #define   EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN                  0x0A
           #define   EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT                 0x0B
           #define   EFI_ATA_PASS_THRU_PROTOCOL_FPDMA                         0x0C
           #define   EFI_ATA_PASS_THRU_PROTOCOL_RETURN_RESPONSE               0xFF

           typedef UINT8 EFI_ATA_PASS_THRU_LENGTH;

           #define EFI_ATA_PASS_THRU_LENGTH_BYTES                             0x80
           #define   EFI_ATA_PASS_THRU_LENGTH_MASK                            0x70
           #define   EFI_ATA_PASS_THRU_LENGTH_NO_DATA_TRANSFER                0x00
           #define   EFI_ATA_PASS_THRU_LENGTH_FEATURES                        0x10
           #define   EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT                    0x20
           #define   EFI_ATA_PASS_THRU_LENGTH_TPSIU                           0x30
           #define EFI_ATA_PASS_THRU_LENGTH_COUNT                             0x0F

Most of these definitions are trivial. What I'm confused about is the void pointers. (This isn't the only EFI protocol that has this, but this is one of them.) What type would I use for this in this environment since I (can't -- I don't think) use c_void?

ethindp avatar Jun 26 '21 04:06 ethindp

Hi! Usually, we represent such buffers as *mut u8, mutable arrays of bytes. If they have any alignment requirements (e.g. the spec says they should be 64-byte aligned), we also add asserts in the calling code to validate the alignment. See this function for an example.

GabrielMajeri avatar Jun 26 '21 12:06 GabrielMajeri

Hello, any progress on this? I've had NVMe passthrough implemented reasonably well for a while in my uefi project, and I am considering making a PR for this.

Although I am unsure about how to non-manually test it, since it requires passing an ssd to qemu with vfio, or, well, actually running it.

And also I'll need ATA later, so I am asking if I have to do it for myself or is there something you will make a PR with at some point.

necauqua avatar Nov 04 '21 20:11 necauqua

@necauqua since the original issue author didn't reply, I'm going to guess they're not actively working on this feature anymore?

Although I am unsure about how to non-manually test it, since it requires passing an ssd to qemu with vfio, or, well, actually running it. Indeed, we'll probably not be able to properly test this protocol in CI. At the most we can statically check the code keeps compiling, but the logic behind it will suffer from some code rot.

That being said, if you've already defined the corresponding protocols and wouldn't mind sharing them with the uefi-rs crate users, we'd welcome the contribution 😄

GabrielMajeri avatar Nov 27 '21 13:11 GabrielMajeri

Sure, I'd push the ones I have in my project, I need to add docs/missing impls and also yeah most of them are kind of untestable without dedicated hw or smth.

Also ATA passthrough mysteriously does not work for me: at least ATA Identify (just times out) but it's used by PI DiskInfo protocol (which I have also implemented without docs/tests seeking alternatives, as well as StorageSecurityCommand (13.14) and DevicePathToText (10.6.2)) and from it I do get identify data, so it seems like my impl/usage somehow differs from the C ones

necauqua avatar Dec 04 '21 20:12 necauqua