RE: [PATCHv2] mmc-utils: Implement alternative boot operation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> Implements the alternative boot operation for eMMCs.
> Note the limitations of the help.
> 
> This is mostly useful for testing purposes if you set
> up the boot partition configuration correctly.
> 
> Usage:
> $ sudo dd if=/dev/mmcblk2boot0 of=bootdatammcblk count=2
> 2+0 records in
> 2+0 records out
> 1024 bytes (1.0 kB, 1.0 KiB) copied, 0.00482308 s, 212 kB/s
> 
> $ sudo ./mmc boot_operation bootdata /dev/mmcblk2
> 
> $ diff -s bootdata bootdatammcblk
> Files bootdata and bootdatammcblk are identical
> 
> Signed-off-by: Christian Loehle <cloehle@xxxxxxxxxxxxxx>
Few nits below.  Other than that - 
Reviewed-by: Avri Altman <avri.altman@xxxxxxx>

> ---
> -v2: Frees, closes, removal of boot_blocks parameter and boot ack check
>  mmc.c      | 12 +++++++
>  mmc.h      |  3 ++
>  mmc_cmds.c | 99
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  mmc_cmds.h |  1 +
>  4 files changed, 115 insertions(+)
> 
> diff --git a/mmc.c b/mmc.c
> index 170ee39..adcd814 100644
> --- a/mmc.c
> +++ b/mmc.c
> @@ -255,6 +255,18 @@ static struct Command commands[] = {
>           "Issues a CMD0 GO_PRE_IDLE",
>           NULL
>         },
> +       { do_alt_boot_op, -1,
> +         "boot_operation", "<boot_data_file> <device>\n"
> +         "Does the alternative boot operation and writes the specified starting
> blocks of boot data into the requested file.\n\n"
> +         "Note some limitations\n:"
> +         "1. The boot operation must be configured, e.g. for legacy speed:\n"
> +         "mmc-utils bootbus set single_backward retain x8 /dev/mmcblk2\n"
> +         "mmc-utils bootpart enable 1 0 /dev/mmcblk2\n"
> +         "2. The MMC must currently be running at the bus mode that is
> configured for the boot operation (HS200 and HS400 not supported at
> all).\n"
> +         "3. Only up to 512K bytes of boot data will be transferred.\n"
> +         "4. The MMC will perform a soft reset, if your system cannot handle
> that do not use the boot operation from mmc-utils.\n",
Theoretically, this shouldn't happen unless you send additional cmd0/0x0.
But I guess it's a reasonable decision for the device to make if it doesn't get one, or cmd1.

> +         NULL
> +       },
>         { 0, 0, 0, 0 }
>  };
> 
> diff --git a/mmc.h b/mmc.h
> index 6511dbc..4de0aae 100644
> --- a/mmc.h
> +++ b/mmc.h
> @@ -24,6 +24,7 @@
>  #define MMC_GO_IDLE_STATE         0   /* bc                          */
>  #define MMC_GO_IDLE_STATE_ARG          0x0
>  #define MMC_GO_PRE_IDLE_STATE_ARG      0xF0F0F0F0
> +#define MMC_BOOT_INITIATION_ARG                0xFFFFFFFA
>  #define MMC_SWITCH             6       /* ac   [31:0] See below        R1b */
>  #define MMC_SEND_EXT_CSD       8       /* adtc                         R1  */
>  #define MMC_SEND_STATUS                13      /* ac   [31:16] RCA        R1  */
> @@ -97,6 +98,7 @@
>  #define EXT_CSD_CACHE_SIZE_0           249
>  #define EXT_CSD_SEC_FEATURE_SUPPORT    231
>  #define EXT_CSD_BOOT_INFO              228     /* R/W */
> +#define EXT_CSD_BOOT_MULT              226     /* RO */
>  #define EXT_CSD_HC_ERASE_GRP_SIZE      224
>  #define EXT_CSD_HC_WP_GRP_SIZE         221
>  #define EXT_CSD_SEC_COUNT_3            215
> @@ -107,6 +109,7 @@
>  #define EXT_CSD_REV                    192
>  #define EXT_CSD_BOOT_CFG               179
>  #define EXT_CSD_PART_CONFIG            179
> +#define EXT_CSD_PART_CONFIG_BOOT_ACK   (1 << 6)
Already exist - EXT_CSD_PART_CONFIG_ACC_ACK

>  #define EXT_CSD_BOOT_BUS_CONDITIONS    177
>  #define EXT_CSD_ERASE_GROUP_DEF                175
>  #define EXT_CSD_BOOT_WP_STATUS         174
> diff --git a/mmc_cmds.c b/mmc_cmds.c
> index 3db17e1..b7efe5a 100644
> --- a/mmc_cmds.c
> +++ b/mmc_cmds.c
> @@ -3101,3 +3101,102 @@ int do_preidle(int nargs, char **argv)
> 
>         return 0;
>  }
> +
> +int do_alt_boot_op(int nargs, char **argv)
> +{
> +       int fd, ret, boot_data_fd;
> +       char *device, *boot_data_file;
> +       struct mmc_ioc_multi_cmd *mioc;
> +       __u8 ext_csd[512];
> +       __u8 *boot_buf;
> +       unsigned int boot_blocks, ext_csd_boot_size;
> +
> +       if (nargs != 3) {
> +               fprintf(stderr, "Usage: mmc boot_op <boot_data_file>
> </path/to/mmcblkX>\n");
> +               exit(1);
> +       }
> +       boot_data_file = argv[1];
> +       device = argv[2];
> +
> +       fd = open(device, O_RDWR);
> +       if (fd < 0) {
> +               perror("open device");
> +               exit(1);
> +       }
> +
> +       ret = read_extcsd(fd, ext_csd);
> +       if (ret) {
> +               perror("read extcsd");
> +               goto dev_fd_close;
> +       }
> +       if ((ext_csd[EXT_CSD_PART_CONFIG] &
> EXT_CSD_PART_CONFIG_BOOT_ACK)
> +                       == EXT_CSD_PART_CONFIG_BOOT_ACK) {
Redundant rhs?

> +               perror("Boot Ack must not be enabled");
> +               ret = -EINVAL;
> +               goto dev_fd_close;
> +       }
> +       ext_csd_boot_size = ext_csd[EXT_CSD_BOOT_MULT] * 128 * 1024;
> +       boot_blocks = ext_csd_boot_size / 512;
> +       if (ext_csd_boot_size > MMC_IOC_MAX_BYTES) {
> +               printf("Boot partition size is bigger than IOCTL limit, limiting to
> 512K\n");
> +               boot_blocks = MMC_IOC_MAX_BYTES / 512;
> +       }
> +
> +       boot_data_fd = open(boot_data_file, O_WRONLY | O_CREAT, 0644);
> +       if (boot_data_fd < 0) {
> +               perror("open boot data file");
> +               ret = 1;
> +               goto boot_data_close;
> +       }
> +
> +       boot_buf = calloc(1, sizeof(__u8) * boot_blocks * 512);
> +       mioc = calloc(1, sizeof(struct mmc_ioc_multi_cmd) +
> +                          2 * sizeof(struct mmc_ioc_cmd));
> +       if (!mioc || !boot_buf) {
> +               perror("Failed to allocate memory");
> +               ret = -ENOMEM;
> +               goto alloced_error;
> +       }
> +
> +       mioc->num_of_cmds = 2;
> +       mioc->cmds[0].opcode = MMC_GO_IDLE_STATE;
> +       mioc->cmds[0].arg = MMC_GO_PRE_IDLE_STATE_ARG;
> +       mioc->cmds[0].flags = MMC_RSP_NONE | MMC_CMD_AC;
> +       mioc->cmds[0].write_flag = 0;
> +
> +       mioc->cmds[1].opcode = MMC_GO_IDLE_STATE;
> +       mioc->cmds[1].arg = MMC_BOOT_INITIATION_ARG;
> +       mioc->cmds[1].flags = MMC_RSP_NONE | MMC_CMD_ADTC;
> +       mioc->cmds[1].write_flag = 0;
> +       mioc->cmds[1].blksz = 512;
> +       mioc->cmds[1].blocks = boot_blocks;
> +       /* Access time of boot part differs wildly, spec mandates 1s */
> +       mioc->cmds[1].data_timeout_ns = 2 * 1000 * 1000 * 1000;
> +       mmc_ioc_cmd_set_data(mioc->cmds[1], boot_buf);
> +
> +       ret = ioctl(fd, MMC_IOC_MULTI_CMD, mioc);
> +       if (ret) {
> +               perror("multi-cmd ioctl error\n");
> +               goto alloced_error;
> +       }
> +
> +       ret = DO_IO(write, boot_data_fd, boot_buf, boot_blocks * 512);
> +       if (ret < 0) {
> +               perror("Write error\n");
> +               goto alloced_error;
> +       }
> +       ret = 0;
> +
> +alloced_error:
> +       if (mioc)
> +               free(mioc);
> +       if (boot_buf)
> +               free(boot_buf);
> +boot_data_close:
> +       close(boot_data_fd);
> +dev_fd_close:
> +       close(fd);
> +       if (ret)
> +               exit(1);
> +       return 0;
> +}
> diff --git a/mmc_cmds.h b/mmc_cmds.h
> index faab362..5f2bef1 100644
> --- a/mmc_cmds.h
> +++ b/mmc_cmds.h
> @@ -49,3 +49,4 @@ int do_erase(int nargs, char **argv);
>  int do_general_cmd_read(int nargs, char **argv);
>  int do_softreset(int nargs, char **argv);
>  int do_preidle(int nargs, char **argv);
> +int do_alt_boot_op(int nargs, char **argv);
> --
> 2.37.3
> 
> Hyperstone GmbH | Reichenaustr. 39a  | 78467 Konstanz
> Managing Director: Dr. Jan Peter Berns.
> Commercial register of local courts: Freiburg HRB381782





[Index of Archives]     [Linux Memonry Technology]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux