// File: /workspace/github_c_makefile_star2_O1/blasphemy[P]mmc-utils/mmc_cmds.c
// Function: do_ffu
int do_ffu(int nargs, char **argv)
{
#ifndef MMC_IOC_MULTI_CMD
	fprintf(stderr, "mmc-utils has been compiled without MMC_IOC_MULTI_CMD"
			" support, needed by FFU.\n");
	exit(1);
#else
	int dev_fd, img_fd;
	int sect_done = 0, retry = 3, ret = -EINVAL;
	unsigned int sect_size;
	__u8 ext_csd[512];
	__u8 *buf;
	__u32 arg;
	off_t fw_size;
	ssize_t chunk_size;
	char *device;
	struct mmc_ioc_multi_cmd *multi_cmd;

	if (nargs != 3) {
		fprintf(stderr, "Usage: ffu <image name> </path/to/mmcblkX> \n");
		exit(1);
	}

	device = argv[2];
	dev_fd = open(device, O_RDWR);
	if (dev_fd < 0) {
		perror("device open failed");
		exit(1);
	}
	img_fd = open(argv[1], O_RDONLY);
	if (img_fd < 0) {
		perror("image open failed");
		close(dev_fd);
		exit(1);
	}

	buf = malloc(512);
	multi_cmd = calloc(1, sizeof(struct mmc_ioc_multi_cmd) +
				3 * sizeof(struct mmc_ioc_cmd));
	if (!buf || !multi_cmd) {
		perror("failed to allocate memory");
		goto out;
	}

	ret = read_extcsd(dev_fd, ext_csd);
	if (ret) {
		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
		goto out;
	}

	if (ext_csd[EXT_CSD_REV] < EXT_CSD_REV_V5_0) {
		fprintf(stderr,
			"The FFU feature is only available on devices >= "
			"MMC 5.0, not supported in %s\n", device);
		goto out;
	}

	if (!(ext_csd[EXT_CSD_SUPPORTED_MODES] & EXT_CSD_FFU)) {
		fprintf(stderr, "FFU is not supported in %s\n", device);
		goto out;
	}

	if (ext_csd[EXT_CSD_FW_CONFIG] & EXT_CSD_UPDATE_DISABLE) {
		fprintf(stderr, "Firmware update was disabled in %s\n", device);
		goto out;
	}

	fw_size = lseek(img_fd, 0, SEEK_END);

	if (fw_size == 0) {
		fprintf(stderr, "Firmware image is empty");
		goto out;
	}

	sect_size = (ext_csd[EXT_CSD_DATA_SECTOR_SIZE] == 0) ? 512 : 4096;
	if (fw_size % sect_size) {
		fprintf(stderr, "Firmware data size (%jd) is not aligned!\n", (intmax_t)fw_size);
		goto out;
	}

	/* set CMD ARG */
	arg = ext_csd[EXT_CSD_FFU_ARG_0] |
		ext_csd[EXT_CSD_FFU_ARG_1] << 8 |
		ext_csd[EXT_CSD_FFU_ARG_2] << 16 |
		ext_csd[EXT_CSD_FFU_ARG_3] << 24;

	/* prepare multi_cmd to be sent */
	multi_cmd->num_of_cmds = 3;

	/* put device into ffu mode */
	multi_cmd->cmds[0].opcode = MMC_SWITCH;
	multi_cmd->cmds[0].arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
			(EXT_CSD_MODE_CONFIG << 16) |
			(EXT_CSD_FFU_MODE << 8) |
			EXT_CSD_CMD_SET_NORMAL;
	multi_cmd->cmds[0].flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
	multi_cmd->cmds[0].write_flag = 1;

	/* send image chunk */
	multi_cmd->cmds[1].opcode = MMC_WRITE_BLOCK;
	multi_cmd->cmds[1].blksz = sect_size;
	multi_cmd->cmds[1].blocks = 1;
	multi_cmd->cmds[1].arg = arg;
	multi_cmd->cmds[1].flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
	multi_cmd->cmds[1].write_flag = 1;
	mmc_ioc_cmd_set_data(multi_cmd->cmds[1], buf);

	/* return device into normal mode */
	multi_cmd->cmds[2].opcode = MMC_SWITCH;
	multi_cmd->cmds[2].arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
			(EXT_CSD_MODE_CONFIG << 16) |
			(EXT_CSD_NORMAL_MODE << 8) |
			EXT_CSD_CMD_SET_NORMAL;
	multi_cmd->cmds[2].flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
	multi_cmd->cmds[2].write_flag = 1;

do_retry:
	/* read firmware chunk */
	lseek(img_fd, 0, SEEK_SET);
	chunk_size = read(img_fd, buf, 512);

	while (chunk_size > 0) {
		/* send ioctl with multi-cmd */
		ret = ioctl(dev_fd, MMC_IOC_MULTI_CMD, multi_cmd);

		if (ret) {
			perror("Multi-cmd ioctl");
			/* In case multi-cmd ioctl failed before exiting from ffu mode */
			ioctl(dev_fd, MMC_IOC_CMD, &multi_cmd->cmds[2]);
			goto out;
		}

		ret = read_extcsd(dev_fd, ext_csd);
		if (ret) {
			fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
			goto out;
		}

		/* Test if we need to restart the download */
		sect_done = ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG_0] |
				ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG_1] << 8 |
				ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG_2] << 16 |
				ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG_3] << 24;
		/* By spec, host should re-start download from the first sector if sect_done is 0 */
		if (sect_done == 0) {
			if (retry > 0) {
				retry--;
				fprintf(stderr, "Programming failed. Retrying... (%d)\n", retry);
				goto do_retry;
			}
			fprintf(stderr, "Programming failed! Aborting...\n");
			goto out;
		} else {
			fprintf(stderr, "Programmed %d/%jd bytes\r", sect_done * sect_size, (intmax_t)fw_size);
		}

		/* read the next firmware chunk (if any) */
		chunk_size = read(img_fd, buf, 512);
	}

	if ((sect_done * sect_size) == fw_size) {
		fprintf(stderr, "Programmed %jd/%jd bytes\n", (intmax_t)fw_size, (intmax_t)fw_size);
		fprintf(stderr, "Programming finished with status %d \n", ret);
	}
	else {
		fprintf(stderr, "FW size and number of sectors written mismatch. Status return %d\n", ret);
		goto out;
	}

	/* check mode operation for ffu install*/
	if (!ext_csd[EXT_CSD_FFU_FEATURES]) {
		fprintf(stderr, "Please reboot to complete firmware installation on %s\n", device);
	} else {
		fprintf(stderr, "Installing firmware on %s...\n", device);
		/* Re-enter ffu mode and install the firmware */
		multi_cmd->num_of_cmds = 2;

		/* set ext_csd to install mode */
		multi_cmd->cmds[1].opcode = MMC_SWITCH;
		multi_cmd->cmds[1].blksz = 0;
		multi_cmd->cmds[1].blocks = 0;
		multi_cmd->cmds[1].arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
				(EXT_CSD_MODE_OPERATION_CODES << 16) |
				(EXT_CSD_FFU_INSTALL << 8) |
				EXT_CSD_CMD_SET_NORMAL;
		multi_cmd->cmds[1].flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
		multi_cmd->cmds[1].write_flag = 1;

		/* send ioctl with multi-cmd */
		ret = ioctl(dev_fd, MMC_IOC_MULTI_CMD, multi_cmd);

		if (ret) {
			perror("Multi-cmd ioctl failed setting install mode");
			/* In case multi-cmd ioctl failed before exiting from ffu mode */
			ioctl(dev_fd, MMC_IOC_CMD, &multi_cmd->cmds[2]);
			goto out;
		}

		ret = read_extcsd(dev_fd, ext_csd);
		if (ret) {
			fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
			goto out;
		}

		/* return status */
		ret = ext_csd[EXT_CSD_FFU_STATUS];
		if (ret) {
			fprintf(stderr, "%s: error %d during FFU install:\n", device, ret);
			goto out;
		} else {
			fprintf(stderr, "FFU finished successfully\n");
		}
	}

out:
	free(buf);
	free(multi_cmd);
	close(img_fd);
	close(dev_fd);
	return ret;
#endif
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x228, %rsp            # imm = 0x228
cmpl $0x3, %edi
jne 0x83b5
movq %rsi, %r14
movq 0x10(%rsi), %r12
movq %r12, %rdi
movl $0x2, %esi
xorl %eax, %eax
callq 0x31d0
testl %eax, %eax
js 0x83dc
movl %eax, %ebx
movq 0x8(%r14), %rdi
xorl %esi, %esi
xorl %eax, %eax
callq 0x31d0
testl %eax, %eax
js 0x83e1
movl %eax, %ebp
movl $0x200, %edi            # imm = 0x200
callq 0x31a0
movq %rax, %r14
movl $0x1, %edi
movl $0xe0, %esi
callq 0x3140
movq %rax, %r15
testq %r14, %r14
je 0x8005
testq %r15, %r15
je 0x8005
leaq 0x20(%rsp), %rsi
movl %ebx, %edi
callq 0x3ef8
testl %eax, %eax
je 0x7f63
movl %eax, %r13d
movq 0xf09c(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
leaq 0x67a7(%rip), %rdx      # 0xe705
jmp 0x802d
cmpb $0x6, 0xe0(%rsp)
ja 0x7f83
movq 0xf07c(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
leaq 0x94e5(%rip), %rdx      # 0x11463
jmp 0x802a
testb $0x1, 0x20d(%rsp)
jne 0x7fa3
movq 0xf05c(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
leaq 0x9513(%rip), %rdx      # 0x114b1
jmp 0x802a
testb $0x1, 0xc9(%rsp)
jne 0x8019
xorl %r13d, %r13d
movl %ebp, %edi
xorl %esi, %esi
movl $0x2, %edx
callq 0x3230
testq %rax, %rax
je 0x806f
movb 0x5d(%rsp), %dl
testb %dl, %dl
movl $0x200, %ecx            # imm = 0x200
movl $0x1000, %edi           # imm = 0x1000
cmovel %ecx, %edi
leaq -0x1(%rdi), %rcx
testq %rax, %rcx
je 0x808e
movq 0xf002(%rip), %rcx      # 0x16ff0
movq (%rcx), %rdi
leaq 0x9511(%rip), %rdx      # 0x11509
xorl %r13d, %r13d
movl $0x1, %esi
movq %rax, %rcx
jmp 0x8035
leaq 0x943d(%rip), %rdi      # 0x11449
callq 0x31e0
movl $0xffffffea, %r13d      # imm = 0xFFFFFFEA
jmp 0x803c
movq 0xefd0(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
leaq 0x94a3(%rip), %rdx      # 0x114cd
xorl %r13d, %r13d
movl $0x1, %esi
movq %r12, %rcx
xorl %eax, %eax
callq 0x3240
movq %r14, %rdi
callq 0x3030
movq %r15, %rdi
callq 0x3030
movl %ebp, %edi
callq 0x3100
movl %ebx, %edi
callq 0x3100
movl %r13d, %eax
addq $0x228, %rsp            # imm = 0x228
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0xef7a(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
leaq 0x9471(%rip), %rdx      # 0x114f1
movl $0x1, %esi
xorl %eax, %eax
callq 0x3240
jmp 0x803c
movb %dl, 0x7(%rsp)
movq %rax, 0x18(%rsp)
movl 0x207(%rsp), %ecx
movq $0x3, (%r15)
movabsq $0x31e010100000006, %rdx # imm = 0x31E010100000006
movq %rdx, 0x10(%r15)
movl $0x49d, %edx            # imm = 0x49D
movl %edx, 0x28(%r15)
movl $0x1, %esi
movl %esi, 0x8(%r15)
movl $0x18, 0x58(%r15)
movl %edi, 0x74(%r15)
movl %esi, 0x78(%r15)
movl %ecx, 0x5c(%r15)
movl $0xb5, 0x70(%r15)
movl %esi, 0x50(%r15)
movq %r14, 0x90(%r15)
movq %r15, %rax
addq $0x98, %rax
movq %rax, 0x10(%rsp)
movabsq $0x31e000100000006, %rax # imm = 0x31E000100000006
movq %rax, 0xa0(%r15)
movl %edx, 0xb8(%r15)
movl %esi, 0x98(%r15)
xorl %r13d, %r13d
movl %ebp, %edi
xorl %esi, %esi
xorl %edx, %edx
callq 0x3230
movl $0x200, %edx            # imm = 0x200
movl %ebp, %edi
movq %r14, %rsi
callq 0x3110
testq %rax, %rax
jle 0x8216
xorl %eax, %eax
cmpb $0x0, 0x7(%rsp)
setne %al
leal (%rax,%rax,2), %eax
addl $0x9, %eax
movl %eax, 0xc(%rsp)
movl $0x3, 0x8(%rsp)
movl $0xc008b301, %esi       # imm = 0xC008B301
movl %ebx, %edi
movq %r15, %rdx
xorl %eax, %eax
callq 0x30f0
testl %eax, %eax
jne 0x8369
movl %ebx, %edi
leaq 0x20(%rsp), %rsi
callq 0x3ef8
testl %eax, %eax
jne 0x7f4a
movl 0x14e(%rsp), %r13d
testl %r13d, %r13d
je 0x81d8
movq 0xee54(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
movl %r13d, %eax
movl 0xc(%rsp), %ecx
shll %cl, %eax
movl $0x1, %esi
leaq 0x93d6(%rip), %rdx      # 0x1158a
movl %eax, %ecx
movq 0x18(%rsp), %r8
xorl %eax, %eax
callq 0x3240
movl $0x200, %edx            # imm = 0x200
movl %ebp, %edi
movq %r14, %rsi
callq 0x3110
testq %rax, %rax
jg 0x815b
jmp 0x8216
movl 0x8(%rsp), %ecx
movq 0xee0d(%rip), %rax      # 0x16ff0
subl $0x1, %ecx
jb 0x83a3
movq (%rax), %rdi
xorl %r13d, %r13d
movl $0x1, %esi
leaq 0x9345(%rip), %rdx      # 0x11543
movl %ecx, 0x8(%rsp)
xorl %eax, %eax
callq 0x3240
movl %ebp, %edi
xorl %esi, %esi
xorl %edx, %edx
callq 0x3230
jmp 0x81c2
xorl %eax, %eax
cmpb $0x0, 0x7(%rsp)
setne %al
leal (%rax,%rax,2), %ecx
addl $0x9, %ecx
shll %cl, %r13d
movq 0xedc0(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
movq 0x18(%rsp), %rcx
cmpq %r13, %rcx
jne 0x8334
leaq 0x935b(%rip), %rdx      # 0x115a3
xorl %r13d, %r13d
movl $0x1, %esi
movq %rcx, %r8
xorl %eax, %eax
callq 0x3240
movq 0xed8f(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
leaq 0x9352(%rip), %rdx      # 0x115bd
movl $0x1, %esi
xorl %ecx, %ecx
xorl %eax, %eax
callq 0x3240
cmpb $0x0, 0x20c(%rsp)
movq 0xed68(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
je 0x8351
leaq 0x93c4(%rip), %rdx      # 0x1165c
movl $0x1, %esi
movq %r12, %rcx
xorl %eax, %eax
callq 0x3240
movq $0x2, (%r15)
movabsq $0x31d010100000006, %rax # imm = 0x31D010100000006
movq %rax, 0x58(%r15)
movl $0x0, 0x78(%r15)
movq $0x49d, 0x70(%r15)      # imm = 0x49D
movl $0x1, 0x50(%r15)
movl $0xc008b301, %esi       # imm = 0xC008B301
movl %ebx, %edi
movq %r15, %rdx
xorl %eax, %eax
callq 0x30f0
testl %eax, %eax
jne 0x8375
leaq 0x20(%rsp), %rsi
movl %ebx, %edi
callq 0x3ef8
testl %eax, %eax
jne 0x7f4a
movzbl 0x3a(%rsp), %r13d
testl %r13d, %r13d
movq 0xecdf(%rip), %rax      # 0x16ff0
je 0x835d
movq (%rax), %rdi
leaq 0x9389(%rip), %rdx      # 0x116a6
movl $0x1, %esi
movq %r12, %rcx
movl %r13d, %r8d
xorl %eax, %eax
callq 0x3240
jmp 0x803c
leaq 0x92a8(%rip), %rdx      # 0x115e3
xorl %r13d, %r13d
movl $0x1, %esi
xorl %ecx, %ecx
xorl %eax, %eax
callq 0x3240
jmp 0x803c
leaq 0x92cd(%rip), %rdx      # 0x11625
jmp 0x802d
movq (%rax), %rdi
leaq 0x9361(%rip), %rdx      # 0x116c8
jmp 0x83ad
movl %eax, %r13d
leaq 0x91c0(%rip), %rdi      # 0x11533
jmp 0x837f
movl %eax, %r13d
leaq 0x92fb(%rip), %rdi      # 0x1167a
callq 0x31e0
movl $0xc008b301, %esi       # imm = 0xC008B301
addq $0x3fffff, %rsi         # imm = 0x3FFFFF
movl %ebx, %edi
movq 0x10(%rsp), %rdx
xorl %eax, %eax
callq 0x30f0
jmp 0x803c
movq (%rax), %rdi
leaq 0x91bc(%rip), %rdx      # 0x11569
xorl %r13d, %r13d
jmp 0x8080
movq 0xec34(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
leaq 0x9031(%rip), %rdx      # 0x113f7
movl $0x1, %esi
xorl %eax, %eax
callq 0x3240
movl $0x1, %edi
callq 0x3220
callq 0x3614
movl %ebx, %edi
callq 0x35f6