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 -
Sorry - you also forgot to add the check of alternative boot support:
(ext_csd[EXT_CSD_BOOT_INFO] & EXT_CSD_BOOT_INFO_ALT)

Please do.

Thanks,
Avri
> 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