// File: /workspace/github_c_makefile_star2_O0/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
movq %rsp, %rbp
subq $0x260, %rsp            # imm = 0x260
movl %edi, -0x4(%rbp)
movq %rsi, -0x10(%rbp)
movl $0x0, -0x1c(%rbp)
movl $0x3, -0x20(%rbp)
movl $0xffffffea, -0x24(%rbp) # imm = 0xFFFFFFEA
cmpl $0x3, -0x4(%rbp)
je 0x985f
movq 0x117ac(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
leaq 0xcbd3(%rip), %rsi      # 0x16421
movb $0x0, %al
callq 0x3180
movl $0x1, %edi
callq 0x3240
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x258(%rbp)
movq -0x258(%rbp), %rdi
movl $0x2, %esi
movb $0x0, %al
callq 0x31e0
movl %eax, -0x14(%rbp)
cmpl $0x0, -0x14(%rbp)
jge 0x98a0
leaq 0xcbbd(%rip), %rdi      # 0x1644e
callq 0x3200
movl $0x1, %edi
callq 0x3240
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
xorl %esi, %esi
movb $0x0, %al
callq 0x31e0
movl %eax, -0x18(%rbp)
cmpl $0x0, -0x18(%rbp)
jge 0x98d8
leaq 0xcba0(%rip), %rdi      # 0x16461
callq 0x3200
movl -0x14(%rbp), %edi
callq 0x3110
movl $0x1, %edi
callq 0x3240
movl $0x200, %edi            # imm = 0x200
callq 0x31c0
movq %rax, -0x238(%rbp)
movl $0x1, %edi
movl $0xe0, %esi
callq 0x3160
movq %rax, -0x260(%rbp)
cmpq $0x0, -0x238(%rbp)
je 0x9913
cmpq $0x0, -0x260(%rbp)
jne 0x9924
leaq 0xcb59(%rip), %rdi      # 0x16473
callq 0x3200
jmp 0x9f22
movl -0x14(%rbp), %edi
leaq -0x230(%rbp), %rsi
callq 0x3e90
movl %eax, -0x24(%rbp)
cmpl $0x0, -0x24(%rbp)
je 0x9960
movq 0x116ad(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
movq -0x258(%rbp), %rdx
leaq 0x9da1(%rip), %rsi      # 0x136f5
movb $0x0, %al
callq 0x3180
jmp 0x9f22
movzbl -0x170(%rbp), %eax
cmpl $0x7, %eax
jge 0x9990
movq 0x1167d(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
movq -0x258(%rbp), %rdx
leaq 0xcb09(%rip), %rsi      # 0x1648d
movb $0x0, %al
callq 0x3180
jmp 0x9f22
movzbl -0x43(%rbp), %eax
andl $0x1, %eax
cmpl $0x0, %eax
jne 0x99c0
movq 0x1164d(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
movq -0x258(%rbp), %rdx
leaq 0xcb27(%rip), %rsi      # 0x164db
movb $0x0, %al
callq 0x3180
jmp 0x9f22
movzbl -0x187(%rbp), %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x99f3
movq 0x1161a(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
movq -0x258(%rbp), %rdx
leaq 0xcb10(%rip), %rsi      # 0x164f7
movb $0x0, %al
callq 0x3180
jmp 0x9f22
movl -0x18(%rbp), %edi
xorl %eax, %eax
movl %eax, %esi
movl $0x2, %edx
callq 0x3250
movq %rax, -0x248(%rbp)
cmpq $0x0, -0x248(%rbp)
jne 0x9a32
movq 0x115d4(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
leaq 0xcaf5(%rip), %rsi      # 0x1651b
movb $0x0, %al
callq 0x3180
jmp 0x9f22
movzbl -0x1f3(%rbp), %edx
movl $0x1000, %eax           # imm = 0x1000
movl $0x200, %ecx            # imm = 0x200
cmpl $0x0, %edx
cmovel %ecx, %eax
movl %eax, -0x28(%rbp)
movq -0x248(%rbp), %rax
movl -0x28(%rbp), %ecx
cqto
idivq %rcx
cmpq $0x0, %rdx
je 0x9a85
movq 0x11588(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
movq -0x248(%rbp), %rdx
leaq 0xcaba(%rip), %rsi      # 0x16533
movb $0x0, %al
callq 0x3180
jmp 0x9f22
movzbl -0x49(%rbp), %eax
movzbl -0x48(%rbp), %ecx
shll $0x8, %ecx
orl %ecx, %eax
movzbl -0x47(%rbp), %ecx
shll $0x10, %ecx
orl %ecx, %eax
movzbl -0x46(%rbp), %ecx
shll $0x18, %ecx
orl %ecx, %eax
movl %eax, -0x23c(%rbp)
movq -0x260(%rbp), %rax
movq $0x3, (%rax)
movq -0x260(%rbp), %rax
movl $0x6, 0x10(%rax)
movq -0x260(%rbp), %rax
movl $0x31e0101, 0x14(%rax)  # imm = 0x31E0101
movq -0x260(%rbp), %rax
movl $0x49d, 0x28(%rax)      # imm = 0x49D
movq -0x260(%rbp), %rax
movl $0x1, 0x8(%rax)
movq -0x260(%rbp), %rax
movl $0x18, 0x58(%rax)
movl -0x28(%rbp), %ecx
movq -0x260(%rbp), %rax
movl %ecx, 0x74(%rax)
movq -0x260(%rbp), %rax
movl $0x1, 0x78(%rax)
movl -0x23c(%rbp), %ecx
movq -0x260(%rbp), %rax
movl %ecx, 0x5c(%rax)
movq -0x260(%rbp), %rax
movl $0xb5, 0x70(%rax)
movq -0x260(%rbp), %rax
movl $0x1, 0x50(%rax)
movq -0x238(%rbp), %rcx
movq -0x260(%rbp), %rax
movq %rcx, 0x90(%rax)
movq -0x260(%rbp), %rax
movl $0x6, 0xa0(%rax)
movq -0x260(%rbp), %rax
movl $0x31e0001, 0xa4(%rax)  # imm = 0x31E0001
movq -0x260(%rbp), %rax
movl $0x49d, 0xb8(%rax)      # imm = 0x49D
movq -0x260(%rbp), %rax
movl $0x1, 0x98(%rax)
movl -0x18(%rbp), %edi
xorl %eax, %eax
movl %eax, %esi
xorl %edx, %edx
callq 0x3250
movl -0x18(%rbp), %edi
movq -0x238(%rbp), %rsi
movl $0x200, %edx            # imm = 0x200
callq 0x3120
movq %rax, -0x250(%rbp)
cmpq $0x0, -0x250(%rbp)
jle 0x9d28
movl -0x14(%rbp), %edi
movq -0x260(%rbp), %rdx
movl $0xc008b301, %esi       # imm = 0xC008B301
movb $0x0, %al
callq 0x3100
movl %eax, -0x24(%rbp)
cmpl $0x0, -0x24(%rbp)
je 0x9c26
leaq 0xc962(%rip), %rdi      # 0x1655d
callq 0x3200
movl -0x14(%rbp), %edi
movq -0x260(%rbp), %rdx
addq $0x8, %rdx
addq $0x90, %rdx
movl $0xc048b300, %esi       # imm = 0xC048B300
movb $0x0, %al
callq 0x3100
jmp 0x9f22
movl -0x14(%rbp), %edi
leaq -0x230(%rbp), %rsi
callq 0x3e90
movl %eax, -0x24(%rbp)
cmpl $0x0, -0x24(%rbp)
je 0x9c62
movq 0x113ab(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
movq -0x258(%rbp), %rdx
leaq 0x9a9f(%rip), %rsi      # 0x136f5
movb $0x0, %al
callq 0x3180
jmp 0x9f22
movzbl -0x102(%rbp), %eax
movzbl -0x101(%rbp), %ecx
shll $0x8, %ecx
orl %ecx, %eax
movzbl -0x100(%rbp), %ecx
shll $0x10, %ecx
orl %ecx, %eax
movzbl -0xff(%rbp), %ecx
shll $0x18, %ecx
orl %ecx, %eax
movl %eax, -0x1c(%rbp)
cmpl $0x0, -0x1c(%rbp)
jne 0x9ce2
cmpl $0x0, -0x20(%rbp)
jle 0x9cc5
movl -0x20(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x20(%rbp)
movq 0x11344(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
movl -0x20(%rbp), %edx
leaq 0xc8b4(%rip), %rsi      # 0x1656d
movb $0x0, %al
callq 0x3180
jmp 0x9b9e
movq 0x11324(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
leaq 0xc8bd(%rip), %rsi      # 0x16593
movb $0x0, %al
callq 0x3180
jmp 0x9f22
movq 0x11307(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
movl -0x1c(%rbp), %edx
imull -0x28(%rbp), %edx
movq -0x248(%rbp), %rcx
leaq 0xc8b3(%rip), %rsi      # 0x165b4
movb $0x0, %al
callq 0x3180
movl -0x18(%rbp), %edi
movq -0x238(%rbp), %rsi
movl $0x200, %edx            # imm = 0x200
callq 0x3120
movq %rax, -0x250(%rbp)
jmp 0x9bc7
movl -0x1c(%rbp), %eax
imull -0x28(%rbp), %eax
movl %eax, %eax
cmpq -0x248(%rbp), %rax
jne 0x9d7d
movq 0x112af(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
movq -0x248(%rbp), %rdx
movq -0x248(%rbp), %rcx
leaq 0xc874(%rip), %rsi      # 0x165cd
movb $0x0, %al
callq 0x3180
movq 0x11289(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
movl -0x24(%rbp), %edx
leaq 0xc873(%rip), %rsi      # 0x165e7
movb $0x0, %al
callq 0x3180
jmp 0x9d9d
movq 0x1126c(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
movl -0x24(%rbp), %edx
leaq 0xc87c(%rip), %rsi      # 0x1660d
movb $0x0, %al
callq 0x3180
jmp 0x9f22
cmpb $0x0, -0x44(%rbp)
jne 0x9dc7
movq 0x11246(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
movq -0x258(%rbp), %rdx
leaq 0xc894(%rip), %rsi      # 0x1664f
movb $0x0, %al
callq 0x3180
jmp 0x9f20
movq 0x11222(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
movq -0x258(%rbp), %rdx
leaq 0xc8a7(%rip), %rsi      # 0x16686
movb $0x0, %al
callq 0x3180
movq -0x260(%rbp), %rax
movq $0x2, (%rax)
movq -0x260(%rbp), %rax
movl $0x6, 0x58(%rax)
movq -0x260(%rbp), %rax
movl $0x0, 0x74(%rax)
movq -0x260(%rbp), %rax
movl $0x0, 0x78(%rax)
movq -0x260(%rbp), %rax
movl $0x31d0101, 0x5c(%rax)  # imm = 0x31D0101
movq -0x260(%rbp), %rax
movl $0x49d, 0x70(%rax)      # imm = 0x49D
movq -0x260(%rbp), %rax
movl $0x1, 0x50(%rax)
movl -0x14(%rbp), %edi
movq -0x260(%rbp), %rdx
movl $0xc008b301, %esi       # imm = 0xC008B301
movb $0x0, %al
callq 0x3100
movl %eax, -0x24(%rbp)
cmpl $0x0, -0x24(%rbp)
je 0x9e99
leaq 0xc836(%rip), %rdi      # 0x166a4
callq 0x3200
movl -0x14(%rbp), %edi
movq -0x260(%rbp), %rdx
addq $0x8, %rdx
addq $0x90, %rdx
movl $0xc048b300, %esi       # imm = 0xC048B300
movb $0x0, %al
callq 0x3100
jmp 0x9f22
movl -0x14(%rbp), %edi
leaq -0x230(%rbp), %rsi
callq 0x3e90
movl %eax, -0x24(%rbp)
cmpl $0x0, -0x24(%rbp)
je 0x9ed2
movq 0x11138(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
movq -0x258(%rbp), %rdx
leaq 0x982c(%rip), %rsi      # 0x136f5
movb $0x0, %al
callq 0x3180
jmp 0x9f22
movzbl -0x216(%rbp), %eax
movl %eax, -0x24(%rbp)
cmpl $0x0, -0x24(%rbp)
je 0x9f06
movq 0x11107(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
movq -0x258(%rbp), %rdx
movl -0x24(%rbp), %ecx
leaq 0xc7d3(%rip), %rsi      # 0x166d0
movb $0x0, %al
callq 0x3180
jmp 0x9f22
movq 0x110e3(%rip), %rax     # 0x1aff0
movq (%rax), %rdi
leaq 0xc7db(%rip), %rsi      # 0x166f2
movb $0x0, %al
callq 0x3180
jmp 0x9f20
jmp 0x9f22
movq -0x238(%rbp), %rdi
callq 0x3030
movq -0x260(%rbp), %rdi
callq 0x3030
movl -0x18(%rbp), %edi
callq 0x3110
movl -0x14(%rbp), %edi
callq 0x3110
movl -0x24(%rbp), %eax
addq $0x260, %rsp            # imm = 0x260
popq %rbp
retq
nopw %cs:(%rax,%rax)