Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e4d95b77 authored by Wenhao Wang's avatar Wenhao Wang Committed by Gerrit Code Review
Browse files

Merge "Add storageproxyd UFS support"

parents 58211256 ce2f1a47
Loading
Loading
Loading
Loading
+129 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#include <errno.h>
#include <fcntl.h>
#include <scsi/sg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -51,6 +52,50 @@

#define MMC_BLOCK_SIZE 512

/*
 * There should be no timeout for security protocol ioctl call, so we choose a
 * large number for timeout.
 * 20000 millisecs == 20 seconds
 */
#define TIMEOUT 20000

/*
 * The sg device driver that supports new interface has a major version number of "3".
 * SG_GET_VERSION_NUM ioctl() will yield a number greater than or 30000.
 */
#define RPMB_MIN_SG_VERSION_NUM 30000

/*
 * CDB format of SECURITY PROTOCOL IN/OUT commands
 * (JEDEC Standard No. 220D, Page 264)
 */
struct sec_proto_cdb {
    /*
     * OPERATION CODE = A2h for SECURITY PROTOCOL IN command,
     * OPERATION CODE = B5h for SECURITY PROTOCOL OUT command.
     */
    uint8_t opcode;
    /* SECURITY PROTOCOL = ECh (JEDEC Universal Flash Storage) */
    uint8_t sec_proto;
    /*
     * The SECURITY PROTOCOL SPECIFIC field specifies the RPMB Protocol ID.
     * CDB Byte 2 = 00h and CDB Byte 3 = 01h for RPMB Region 0.
     */
    uint8_t cdb_byte_2;
    uint8_t cdb_byte_3;
    /*
     * Byte 4 and 5 are reserved.
     */
    uint8_t cdb_byte_4;
    uint8_t cdb_byte_5;
    /* ALLOCATION/TRANSFER LENGTH in big-endian */
    uint32_t length;
    /* Byte 9 is reserved. */
    uint8_t cdb_byte_10;
    /* CONTROL = 00h. */
    uint8_t ctrl;
} __packed;

static int rpmb_fd = -1;
static uint8_t read_buf[4096];
static enum dev_type dev_type = UNKNOWN_RPMB;
@@ -71,6 +116,21 @@ static void print_buf(const char* prefix, const uint8_t* buf, size_t size) {

#endif

static void set_sg_io_hdr(sg_io_hdr_t* io_hdrp, int dxfer_direction, unsigned char cmd_len,
                          unsigned char mx_sb_len, unsigned int dxfer_len, void* dxferp,
                          unsigned char* cmdp, void* sbp) {
    memset(io_hdrp, 0, sizeof(sg_io_hdr_t));
    io_hdrp->interface_id = 'S';
    io_hdrp->dxfer_direction = dxfer_direction;
    io_hdrp->cmd_len = cmd_len;
    io_hdrp->mx_sb_len = mx_sb_len;
    io_hdrp->dxfer_len = dxfer_len;
    io_hdrp->dxferp = dxferp;
    io_hdrp->cmdp = cmdp;
    io_hdrp->sbp = sbp;
    io_hdrp->timeout = TIMEOUT;
}

static int send_mmc_rpmb_req(int mmc_fd, const struct storage_rpmb_send_req* req) {
    struct {
        struct mmc_ioc_multi_cmd multi;
@@ -132,6 +192,57 @@ static int send_mmc_rpmb_req(int mmc_fd, const struct storage_rpmb_send_req* req
    return rc;
}

static int send_ufs_rpmb_req(int sg_fd, const struct storage_rpmb_send_req* req) {
    int rc;
    const uint8_t* write_buf = req->payload;
    /*
     * Meaning of member values are stated on the definition of struct sec_proto_cdb.
     */
    struct sec_proto_cdb in_cdb = {0xA2, 0xEC, 0x00, 0x01, 0x00, 0x00, 0, 0x00, 0x00};
    struct sec_proto_cdb out_cdb = {0xB5, 0xEC, 0x00, 0x01, 0x00, 0x00, 0, 0x00, 0x00};
    unsigned char sense_buffer[32];

    if (req->reliable_write_size) {
        /* Prepare SECURITY PROTOCOL OUT command. */
        out_cdb.length = __builtin_bswap32(req->reliable_write_size);
        sg_io_hdr_t io_hdr;
        set_sg_io_hdr(&io_hdr, SG_DXFER_TO_DEV, sizeof(out_cdb), sizeof(sense_buffer),
                      req->reliable_write_size, (void*)write_buf, (unsigned char*)&out_cdb,
                      sense_buffer);
        rc = ioctl(sg_fd, SG_IO, &io_hdr);
        if (rc < 0) {
            ALOGE("%s: ufs ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
        }
        write_buf += req->reliable_write_size;
    }

    if (req->write_size) {
        /* Prepare SECURITY PROTOCOL OUT command. */
        out_cdb.length = __builtin_bswap32(req->write_size);
        sg_io_hdr_t io_hdr;
        set_sg_io_hdr(&io_hdr, SG_DXFER_TO_DEV, sizeof(out_cdb), sizeof(sense_buffer),
                      req->write_size, (void*)write_buf, (unsigned char*)&out_cdb, sense_buffer);
        rc = ioctl(sg_fd, SG_IO, &io_hdr);
        if (rc < 0) {
            ALOGE("%s: ufs ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
        }
        write_buf += req->write_size;
    }

    if (req->read_size) {
        /* Prepare SECURITY PROTOCOL IN command. */
        out_cdb.length = __builtin_bswap32(req->read_size);
        sg_io_hdr_t io_hdr;
        set_sg_io_hdr(&io_hdr, SG_DXFER_FROM_DEV, sizeof(in_cdb), sizeof(sense_buffer),
                      req->read_size, read_buf, (unsigned char*)&in_cdb, sense_buffer);
        rc = ioctl(sg_fd, SG_IO, &io_hdr);
        if (rc < 0) {
            ALOGE("%s: ufs ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
        }
    }
    return rc;
}

static int send_virt_rpmb_req(int rpmb_fd, void* read_buf, size_t read_size, const void* payload,
                              size_t payload_size) {
    int rc;
@@ -194,6 +305,13 @@ int rpmb_send(struct storage_msg* msg, const void* r, size_t req_len) {
            msg->result = STORAGE_ERR_GENERIC;
            goto err_response;
        }
    } else if (dev_type == UFS_RPMB) {
        rc = send_ufs_rpmb_req(rpmb_fd, req);
        if (rc < 0) {
            ALOGE("send_ufs_rpmb_req failed: %d, %s\n", rc, strerror(errno));
            msg->result = STORAGE_ERR_GENERIC;
            goto err_response;
        }
    } else if ((dev_type == VIRT_RPMB) || (dev_type == SOCK_RPMB)) {
        size_t payload_size = req->reliable_write_size + req->write_size;
        rc = send_virt_rpmb_req(rpmb_fd, read_buf, req->read_size, req->payload, payload_size);
@@ -233,7 +351,7 @@ err_response:
}

int rpmb_open(const char* rpmb_devname, enum dev_type open_dev_type) {
    int rc;
    int rc, sg_version_num;
    dev_type = open_dev_type;

    if (dev_type != SOCK_RPMB) {
@@ -263,6 +381,16 @@ int rpmb_open(const char* rpmb_devname, enum dev_type open_dev_type) {
            return rc;
        }
    }

    /* For UFS, it is prudent to check we hava a sg device by calling an ioctl */
    if (dev_type == UFS_RPMB) {
        if ((ioctl(rc, SG_GET_VERSION_NUM, &sg_version_num) < 0) ||
            (sg_version_num < RPMB_MIN_SG_VERSION_NUM)) {
            ALOGE("%s is not a sg device, or old sg driver\n", rpmb_devname);
            return -1;
        }
    }
    rpmb_fd = rc;
    return 0;
}

+1 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@
#include <stdint.h>
#include <trusty/interface/storage.h>

enum dev_type { UNKNOWN_RPMB, MMC_RPMB, VIRT_RPMB, SOCK_RPMB };
enum dev_type { UNKNOWN_RPMB, MMC_RPMB, VIRT_RPMB, UFS_RPMB, SOCK_RPMB };

int rpmb_open(const char* rpmb_devname, enum dev_type dev_type);
int rpmb_send(struct storage_msg* msg, const void* r, size_t req_len);