// File: /workspace/github_c_makefile_star2_O0/dlbeer[P]ufat/ufat_mkfs.c
// Function: calculate_layout
static int calculate_layout(struct fs_layout *fl,
			    ufat_block_t nblk,
			    unsigned int log2_block_size)
{
	unsigned int log2_bps;
	unsigned int log2_spc;
	uint32_t nsect;
	ufat_cluster_t clusters_threshold;
	ufat_cluster_t est_clusters;
	uint32_t fat_bytes;

	/* Make sure the block size is less than or equal to maximum sector
	 * size (4 kB, log2(4096) = 12).
	 */
	if (log2_block_size > 12)
		return -UFAT_ERR_BLOCK_SIZE;

	/* Minimum sector size is 512 B (log2(512) = 9), but it cannot be
	 * smaller than block size.
	 */
	log2_bps = log2_block_size < 9 ? 9 - log2_block_size : 0;

	/* Increase sector size if we can't store the total logical sector count
	 * in a 32-bit variable.
	 */
	while (log2_block_size + log2_bps < 12 &&
	       nblk >> log2_bps > UINT32_MAX)
		++log2_bps;

	/* If we still can't fit it, we'll have to chop the device. */
	if (nblk >> log2_bps > UINT32_MAX)
		nblk = (ufat_block_t)UINT32_MAX << log2_bps;

	fl->log2_sector_size = log2_block_size + log2_bps;

	/* Calculate total logical sector count. */
	nsect = nblk >> log2_bps;

	/* Threshold values taken from "fatgen103.pdf" -
	 * https://staff.washington.edu/dittrich/misc/fatgen103.pdf - "FAT
	 * Volume Initialization" chapter.
	 *
	 * For a device with typical 512 B block size this selects FAT12 for
	 * device size less than ~4.1 MB, FAT16 for device size less than 512 MB
	 * and FAT32 otherwise.
	 */
	if (nsect < 8400) {
		fl->type = UFAT_TYPE_FAT12;
		clusters_threshold = 1 << 12;
		log2_spc = 1;
	} else if (nsect < 1048576) {
		fl->type = UFAT_TYPE_FAT16;
		clusters_threshold = 1 << 16;
		log2_spc = 1;
	} else {
		fl->type = UFAT_TYPE_FAT32;
		clusters_threshold = 2097152;
		log2_spc = 3;
	}

	/* Increase cluster size if the resulting number of clusters would be
	 * above the threshold, but keep it below 32 kB (log2(32768) = 15).
	 */
	while (log2_spc < 7 &&
	       fl->log2_sector_size + log2_spc < 15 &&
	       nsect >> log2_spc > clusters_threshold)
		++log2_spc;

	fl->log2_bpc = log2_bps + log2_spc;

	/* Calculate the number of reserved blocks.
	 *
	 * "fatgen103.pdf" -
	 * https://staff.washington.edu/dittrich/misc/fatgen103.pdf - "Boot
	 * Sector and BPB" chapter.
	 *
	 * FAT12 and FAT16 should have 1 reserved sector. Typical number of
	 * reserved sectors for FAT32 is 32.
	 */
	const ufat_block_t reserved_sectors =
		fl->type == UFAT_TYPE_FAT32 ? 32 : 1;
	fl->reserved_blocks = reserved_sectors << log2_bps;

	/* Estimate an upper bound on the cluster count and allocate blocks
	 * for the FAT.
	 */
	est_clusters = ((nblk - fl->reserved_blocks) >> fl->log2_bpc) + 2;

	if (fl->type == UFAT_TYPE_FAT32)
		fat_bytes = est_clusters << 2;
	else if (fl->type == UFAT_TYPE_FAT16)
		fat_bytes = est_clusters << 1;
	else
		fat_bytes = (est_clusters * 3 + 1) >> 1;

	fl->fat_blocks = bytes_to_blocks(log2_block_size, fat_bytes);

	/* Calculate the minimum size of the root directory. */
	fl->root_blocks = fl->type != UFAT_TYPE_FAT32 ?
	                  bytes_to_blocks(log2_block_size, 16384) : 0;

	/* Finalize the actual cluster count - it can't be greater than the
	 * estimate.
	 */
	fl->clusters = ((nblk - fl->reserved_blocks -
			 fl->root_blocks - fl->fat_blocks * 2) >>
			fl->log2_bpc) + 2;

	/* Expand root directory to fill unusable data space for FAT12/FAT16. */
	if (fl->type != UFAT_TYPE_FAT32)
		fl->root_blocks =
			nblk - fl->reserved_blocks - fl->fat_blocks * 2 -
			((fl->clusters - 2) << fl->log2_bpc);

	/* Set the block count to exactly fit the filesystem. */
	fl->logical_blocks = ((fl->clusters - 2) << fl->log2_bpc) +
		fl->fat_blocks * 2 + fl->reserved_blocks + fl->root_blocks;

	return 0;
}

// Assembly:
subq $0x58, %rsp
movq %rdi, 0x48(%rsp)
movq %rsi, 0x40(%rsp)
movl %edx, 0x3c(%rsp)
cmpl $0xc, 0x3c(%rsp)
jbe 0x7dd6
movl $0xfffffffe, 0x54(%rsp) # imm = 0xFFFFFFFE
jmp 0x811c
cmpl $0x9, 0x3c(%rsp)
jae 0x7dec
movl $0x9, %eax
subl 0x3c(%rsp), %eax
movl %eax, 0x14(%rsp)
jmp 0x7df4
xorl %eax, %eax
movl %eax, 0x14(%rsp)
jmp 0x7df4
movl 0x14(%rsp), %eax
movl %eax, 0x38(%rsp)
movl 0x3c(%rsp), %ecx
addl 0x38(%rsp), %ecx
xorl %eax, %eax
cmpl $0xc, %ecx
movb %al, 0x13(%rsp)
jae 0x7e2a
movq 0x40(%rsp), %rax
movl 0x38(%rsp), %ecx
shrq %cl, %rax
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
cmpq %rcx, %rax
seta %al
movb %al, 0x13(%rsp)
movb 0x13(%rsp), %al
testb $0x1, %al
jne 0x7e34
jmp 0x7e41
movl 0x38(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x38(%rsp)
jmp 0x7dfc
movq 0x40(%rsp), %rax
movl 0x38(%rsp), %ecx
shrq %cl, %rax
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
cmpq %rcx, %rax
jbe 0x7e6a
movl 0x38(%rsp), %eax
movl %eax, %ecx
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
shlq %cl, %rax
movq %rax, 0x40(%rsp)
movl 0x3c(%rsp), %ecx
addl 0x38(%rsp), %ecx
movq 0x48(%rsp), %rax
movl %ecx, (%rax)
movq 0x40(%rsp), %rax
movl 0x38(%rsp), %ecx
shrq %cl, %rax
movl %eax, 0x30(%rsp)
cmpl $0x20d0, 0x30(%rsp)     # imm = 0x20D0
jae 0x7eb1
movq 0x48(%rsp), %rax
movl $0xc, 0x2c(%rax)
movl $0x1000, 0x2c(%rsp)     # imm = 0x1000
movl $0x1, 0x34(%rsp)
jmp 0x7ef7
cmpl $0x100000, 0x30(%rsp)   # imm = 0x100000
jae 0x7ed9
movq 0x48(%rsp), %rax
movl $0x10, 0x2c(%rax)
movl $0x10000, 0x2c(%rsp)    # imm = 0x10000
movl $0x1, 0x34(%rsp)
jmp 0x7ef5
movq 0x48(%rsp), %rax
movl $0x20, 0x2c(%rax)
movl $0x200000, 0x2c(%rsp)   # imm = 0x200000
movl $0x3, 0x34(%rsp)
jmp 0x7ef7
jmp 0x7ef9
xorl %eax, %eax
cmpl $0x7, 0x34(%rsp)
movb %al, 0x12(%rsp)
jae 0x7f31
movq 0x48(%rsp), %rax
movl (%rax), %ecx
addl 0x34(%rsp), %ecx
xorl %eax, %eax
cmpl $0xf, %ecx
movb %al, 0x12(%rsp)
jae 0x7f31
movl 0x30(%rsp), %eax
movl 0x34(%rsp), %ecx
shrl %cl, %eax
cmpl 0x2c(%rsp), %eax
seta %al
movb %al, 0x12(%rsp)
movb 0x12(%rsp), %al
testb $0x1, %al
jne 0x7f3b
jmp 0x7f48
movl 0x34(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x34(%rsp)
jmp 0x7ef9
movl 0x38(%rsp), %ecx
addl 0x34(%rsp), %ecx
movq 0x48(%rsp), %rax
movl %ecx, 0x4(%rax)
movq 0x48(%rsp), %rax
movl 0x2c(%rax), %edx
movl $0x1, %eax
movl $0x20, %ecx
cmpl $0x20, %edx
cmovel %ecx, %eax
cltq
movq %rax, 0x18(%rsp)
movq 0x18(%rsp), %rax
movl 0x38(%rsp), %ecx
shlq %cl, %rax
movq %rax, %rcx
movq 0x48(%rsp), %rax
movq %rcx, 0x8(%rax)
movq 0x40(%rsp), %rax
movq 0x48(%rsp), %rcx
subq 0x8(%rcx), %rax
movq 0x48(%rsp), %rcx
movl 0x4(%rcx), %ecx
shrq %cl, %rax
addq $0x2, %rax
movl %eax, 0x28(%rsp)
movq 0x48(%rsp), %rax
cmpl $0x20, 0x2c(%rax)
jne 0x7fc8
movl 0x28(%rsp), %eax
shll $0x2, %eax
movl %eax, 0x24(%rsp)
jmp 0x7fef
movq 0x48(%rsp), %rax
cmpl $0x10, 0x2c(%rax)
jne 0x7fdf
movl 0x28(%rsp), %eax
shll %eax
movl %eax, 0x24(%rsp)
jmp 0x7fed
imull $0x3, 0x28(%rsp), %eax
addl $0x1, %eax
shrl %eax
movl %eax, 0x24(%rsp)
jmp 0x7fef
movl 0x3c(%rsp), %edi
movl 0x24(%rsp), %esi
callq 0x8bb0
movq %rax, %rcx
movq 0x48(%rsp), %rax
movq %rcx, 0x18(%rax)
movq 0x48(%rsp), %rax
cmpl $0x20, 0x2c(%rax)
je 0x8028
movl 0x3c(%rsp), %edi
movl $0x4000, %esi           # imm = 0x4000
callq 0x8bb0
movq %rax, 0x8(%rsp)
jmp 0x8031
xorl %eax, %eax
movq %rax, 0x8(%rsp)
jmp 0x8031
movq 0x8(%rsp), %rcx
movq 0x48(%rsp), %rax
movq %rcx, 0x10(%rax)
movq 0x40(%rsp), %rax
movq 0x48(%rsp), %rcx
subq 0x8(%rcx), %rax
movq 0x48(%rsp), %rcx
subq 0x10(%rcx), %rax
movq 0x48(%rsp), %rcx
movq 0x18(%rcx), %rcx
shlq %rcx
subq %rcx, %rax
movq 0x48(%rsp), %rcx
movl 0x4(%rcx), %ecx
shrq %cl, %rax
addq $0x2, %rax
movl %eax, %ecx
movq 0x48(%rsp), %rax
movl %ecx, 0x28(%rax)
movq 0x48(%rsp), %rax
cmpl $0x20, 0x2c(%rax)
je 0x80d1
movq 0x40(%rsp), %rax
movq 0x48(%rsp), %rcx
subq 0x8(%rcx), %rax
movq 0x48(%rsp), %rcx
movq 0x18(%rcx), %rcx
shlq %rcx
subq %rcx, %rax
movq %rax, (%rsp)
movq 0x48(%rsp), %rax
movl 0x28(%rax), %eax
subl $0x2, %eax
movq 0x48(%rsp), %rcx
movl 0x4(%rcx), %ecx
shll %cl, %eax
movq (%rsp), %rcx
movl %eax, %eax
subq %rax, %rcx
movq 0x48(%rsp), %rax
movq %rcx, 0x10(%rax)
movq 0x48(%rsp), %rax
movl 0x28(%rax), %eax
subl $0x2, %eax
movq 0x48(%rsp), %rcx
movl 0x4(%rcx), %ecx
shll %cl, %eax
movl %eax, %eax
movl %eax, %ecx
movq 0x48(%rsp), %rax
movq 0x18(%rax), %rax
shlq %rax
addq %rax, %rcx
movq 0x48(%rsp), %rax
addq 0x8(%rax), %rcx
movq 0x48(%rsp), %rax
addq 0x10(%rax), %rcx
movq 0x48(%rsp), %rax
movq %rcx, 0x20(%rax)
movl $0x0, 0x54(%rsp)
movl 0x54(%rsp), %eax
addq $0x58, %rsp
retq
nopw %cs:(%rax,%rax)