// File: /workspace/github_c_makefile_star2_O3/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 0x82ad
movq %rsi, %r14
movq 0x10(%rsi), %r12
movq %r12, %rdi
movl $0x2, %esi
xorl %eax, %eax
callq 0x31d0
testl %eax, %eax
js 0x82d4
movl %eax, %ebx
movq 0x8(%r14), %rdi
xorl %esi, %esi
xorl %eax, %eax
callq 0x31d0
testl %eax, %eax
js 0x82d9
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 0x7ef7
testq %r15, %r15
je 0x7ef7
leaq 0x20(%rsp), %rsi
movl %ebx, %edi
callq 0x3eac
testl %eax, %eax
je 0x7e55
movl %eax, %r13d
movq 0xf1aa(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
leaq 0x68b5(%rip), %rdx      # 0xe705
jmp 0x7f1f
cmpb $0x6, 0xe0(%rsp)
ja 0x7e75
movq 0xf18a(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
leaq 0x95e4(%rip), %rdx      # 0x11454
jmp 0x7f1c
testb $0x1, 0x20d(%rsp)
jne 0x7e95
movq 0xf16a(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
leaq 0x9612(%rip), %rdx      # 0x114a2
jmp 0x7f1c
testb $0x1, 0xc9(%rsp)
jne 0x7f0b
xorl %r13d, %r13d
movl %ebp, %edi
xorl %esi, %esi
movl $0x2, %edx
callq 0x3230
testq %rax, %rax
je 0x7f61
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 0x7f80
movq 0xf110(%rip), %rcx      # 0x16ff0
movq (%rcx), %rdi
leaq 0x9610(%rip), %rdx      # 0x114fa
xorl %r13d, %r13d
movl $0x1, %esi
movq %rax, %rcx
jmp 0x7f27
leaq 0x953c(%rip), %rdi      # 0x1143a
callq 0x31e0
movl $0xffffffea, %r13d      # imm = 0xFFFFFFEA
jmp 0x7f2e
movq 0xf0de(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
leaq 0x95a2(%rip), %rdx      # 0x114be
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 0xf088(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
leaq 0x9570(%rip), %rdx      # 0x114e2
movl $0x1, %esi
xorl %eax, %eax
callq 0x3240
jmp 0x7f2e
movb %dl, 0x8(%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 0x8108
xorl %eax, %eax
cmpb $0x0, 0x8(%rsp)
setne %al
leal (%rax,%rax,2), %eax
addl $0x9, %eax
movl %eax, 0x8(%rsp)
movl $0x3, 0xc(%rsp)
movl $0xc008b301, %esi       # imm = 0xC008B301
movl %ebx, %edi
movq %r15, %rdx
xorl %eax, %eax
callq 0x30f0
testl %eax, %eax
jne 0x8261
movl %ebx, %edi
leaq 0x20(%rsp), %rsi
callq 0x3eac
testl %eax, %eax
jne 0x7e3c
movl 0x14e(%rsp), %r13d
testl %r13d, %r13d
je 0x80ca
movq 0xef62(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
movl %r13d, %eax
movl 0x8(%rsp), %ecx
shll %cl, %eax
movl $0x1, %esi
leaq 0x94d5(%rip), %rdx      # 0x1157b
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 0x804d
jmp 0x811a
movl 0xc(%rsp), %ecx
movq 0xef1b(%rip), %rax      # 0x16ff0
subl $0x1, %ecx
jb 0x829b
movq (%rax), %rdi
xorl %r13d, %r13d
movl $0x1, %esi
leaq 0x9444(%rip), %rdx      # 0x11534
movl %ecx, 0xc(%rsp)
xorl %eax, %eax
callq 0x3240
movl %ebp, %edi
xorl %esi, %esi
xorl %edx, %edx
callq 0x3230
jmp 0x80b4
xorl %eax, %eax
cmpb $0x0, 0x8(%rsp)
setne %al
leal (%rax,%rax,2), %ecx
addl $0x9, %ecx
jmp 0x811e
movl 0x8(%rsp), %ecx
shll %cl, %r13d
movq 0xeec8(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
movq 0x18(%rsp), %rcx
cmpq %r13, %rcx
jne 0x822c
leaq 0x9454(%rip), %rdx      # 0x11594
xorl %r13d, %r13d
movl $0x1, %esi
movq %rcx, %r8
xorl %eax, %eax
callq 0x3240
movq 0xee97(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
leaq 0x944b(%rip), %rdx      # 0x115ae
movl $0x1, %esi
xorl %ecx, %ecx
xorl %eax, %eax
callq 0x3240
cmpb $0x0, 0x20c(%rsp)
movq 0xee70(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
je 0x8249
leaq 0x94bd(%rip), %rdx      # 0x1164d
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 0x826d
leaq 0x20(%rsp), %rsi
movl %ebx, %edi
callq 0x3eac
testl %eax, %eax
jne 0x7e3c
movzbl 0x3a(%rsp), %r13d
testl %r13d, %r13d
movq 0xede7(%rip), %rax      # 0x16ff0
je 0x8255
movq (%rax), %rdi
leaq 0x9482(%rip), %rdx      # 0x11697
movl $0x1, %esi
movq %r12, %rcx
movl %r13d, %r8d
xorl %eax, %eax
callq 0x3240
jmp 0x7f2e
leaq 0x93a1(%rip), %rdx      # 0x115d4
xorl %r13d, %r13d
movl $0x1, %esi
xorl %ecx, %ecx
xorl %eax, %eax
callq 0x3240
jmp 0x7f2e
leaq 0x93c6(%rip), %rdx      # 0x11616
jmp 0x7f1f
movq (%rax), %rdi
leaq 0x945a(%rip), %rdx      # 0x116b9
jmp 0x82a5
movl %eax, %r13d
leaq 0x92b9(%rip), %rdi      # 0x11524
jmp 0x8277
movl %eax, %r13d
leaq 0x93f4(%rip), %rdi      # 0x1166b
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 0x7f2e
movq (%rax), %rdi
leaq 0x92b5(%rip), %rdx      # 0x1155a
xorl %r13d, %r13d
jmp 0x7f72
movq 0xed3c(%rip), %rax      # 0x16ff0
movq (%rax), %rdi
leaq 0x912a(%rip), %rdx      # 0x113e8
movl $0x1, %esi
xorl %eax, %eax
callq 0x3240
movl $0x1, %edi
callq 0x3220
callq 0x3628
movl %ebx, %edi
callq 0x360a