// File: /workspace/github_c_makefile_star2_O1/jogolden[P]ps4flashtool/flashtool.c
// Function: main
int main(int argc, char **argv) {
    int i;
    char *flashfile = NULL;
    char *flashout = NULL;
    char *extractdir = NULL;
    char *rawextractdir = NULL;
    char *emcipl = NULL;
    char *eapkbl = NULL;
    char *eapkern = NULL;

    char *keyfile = FLASHTOOL_KEYFILE;
    unsigned char *flashdata = NULL;
    unsigned char *ptr = NULL, *ptr2 = NULL;
    unsigned int len, len2;

    printf("~ PlayStation 4 flash tool " FLASHTOOL_VERSION " | by " FLASHTOOL_CREDITS " ~\n");

    if(argc == 1) {
        printf("try '%s --help' for more information\n", argv[0]);
        return 0;
    }

    // make sure this is zero
    verbose = 0;
    noverify = 0;

    for(i = 1; i < argc; i++) {
        char *opt = argv[i];
        char *arg = (i == argc - 1) ? NULL : argv[i + 1];

        if(opt[0] != '-') {
            printf("error: invalid argument syntax!\n");
            return 1;
        }
        if(opt[0] == '-') { opt++; }
        if(opt[0] == '-') { opt++; }
        
        if(opt[0] == 'h' || !strcmp(opt, "help")) {
            print_usage();
            return 1;
        } else if(opt[0] == 'v' || !strcmp(opt, "verbose")) {
            verbose = 1;
        } else if(opt[0] == 'i' || !strcmp(opt, "input")) {
            if(!arg) {
                printf("error: invalid flash input argument!\n");
                return 1;
            }
            flashfile = arg;
            i++;
        } else if(opt[0] == 'o' || !strcmp(opt, "output")) {
            if(!arg) {
                printf("error: invalid flash output argument!\n");
                return 1;
            }
            flashout = arg;
            i++;
        } else if(opt[0] == 'n' || !strcmp(opt, "noverify")) {
            noverify = 1;
        } else if(opt[0] == 'k' || !strcmp(opt, "keyfile")) {
            if(!arg) {
                printf("error: invalid keyfile argument!\n");
                return 1;
            }
            keyfile = arg;
            printf("* changed keyfile to '%s'\n", keyfile);
            i++;
        } else if(!strcmp(opt, "extract")) {
            if(!arg) {
                printf("error: invalid extract directory argument!\n");
                return 1;
            }
            extractdir = arg;
            i++;
        } else if(!strcmp(opt, "rawextract")) {
            if(!arg) {
                printf("error: invalid raw extract directory argument!\n");
                return 1;
            }
            rawextractdir = arg;
            i++;
        } else if(!strcmp(opt, "emcipl")) {
            if(!arg) {
                printf("error: invalid emcipl argument!\n");
                return 1;
            }
            emcipl = arg;
            i++;
        } else if(!strcmp(opt, "eapkbl")) {
            if(!arg) {
                printf("error: invalid eapkbl argument!\n");
                return 1;
            }
            eapkbl = arg;
            i++;
        } else if(!strcmp(opt, "eapkern")) {
            if(!arg) {
                printf("error: invalid eapkern argument!\n");
                return 1;
            }
            eapkern = arg;
            i++;
        } else {
            printf("error: unknown option '%s'\n", opt);
            printf("try '%s --help' for more information\n", argv[0]);
            return 1;
        }
    }

    if(eapkern) {
        char *comma = strstr(eapkern, ",");
        if(!comma) {
            printf("error: please use a comma between the input and output for EAP kernel decryption\n");
            goto end;
        }

        comma[0] = '\0';

        char *input = eapkern;
        char *output = comma + 1;
        
        if(readbin(input, &ptr, &len)) {
            printf("error: failed to read EAP kernel from file!\n");
            goto end;
        }

        printf("attempting to decrypt EAP kernel '%s' to '%s' ...\n", input, output);
        printf("* keys may or not work on your console model/firmware version\n");

        if(decrypt_decompress_eap_kernel(ptr, len, &ptr2, &len2)) {
            printf("error: failed to decrypt EAP kernel\n");
            goto end;
        }

        dumpbin(output, ptr2, len2);

        printf("wrote decrypted EAP kernel\n");

        free(ptr);
        free(ptr2);

        goto end;
    }

    if(!flashfile) {
        printf("error: please specify a PlayStation 4 flash file!\n");
        goto end;
    }
    
    // load flash
    flashdata = load_flashdump(flashfile);
    if(!flashdata) {
        printf("error: invalid flash file!\n");
        goto end;
    }
    
    print_flashinfo(flashdata);

    if(verbose) {
        find_and_print_slb2_info(flashdata);
    }
    
    // raw extract does not require a key file so do it before
    if(rawextractdir) {
        if(rawextract_flashdump(flashdata, rawextractdir)) {
            printf("error: raw extract failed!\n");
        }

        goto end;
    }

    // load the keys
    printf("loading key file '%s' ...\n", keyfile);
    if(keymgr_loadkeys(keyfile)) {
        return 1;
    }

    if(verbose) {
        keymgr_printkeys();
    }
    
    // check flash
    if(!noverify) {
        if(check_flashdump(flashdata)) {
            printf("error: invalid flash data detected!\n");
            goto end;
        }
    }
    
    // replace emc ipl
    if(emcipl) {
        printf("replacing EMC IPL in flash dump with '%s' ...\n", emcipl);

        if(readbin(emcipl, &ptr, &len)) {
            printf("error: failed to read EMC IPL from file!\n");
            goto end;
        }

        if(replace_emc_ipl(flashdata, ptr, len)) {
            printf("warning: failed to replace EMC IPL!\n");
        }

        free(ptr);
    }
    
    // replace eap kbl
    if(eapkbl) {
        printf("replacing EAP KBL in flash dump with '%s' ...\n", eapkbl);

        if(readbin(eapkbl, &ptr, &len)) {
            printf("error: failed to read EAP KBL from file!\n");
            goto end;
        }

        if(replace_eap_kbl(flashdata, ptr, len)) {
            printf("warning: failed to replace EAP KBL!\n");
        }

        free(ptr);
    }
    
    // extract parts
    if(extractdir) {
        if(extract_flashdump(flashdata, extractdir)) {
            printf("error: failed during flash extraction!\n");
            goto end;
        }
    }

    // write flashdata out
    if(flashout) {
        // enable uart ;)
        char uart = 1;
        nvs_write(flashdata, 0, 4, NVS_VAR_BLOCK4_ENABLE_UART, 1, &uart);

        if(verbose) {
            printf("* enabled uart in NVS region\n");
        }

        dumpbin(flashout, flashdata, FLASH_SIZE);
        printf("wrote final flash to '%s'\n", flashout);
    }

end:
    if(flashdata) {
        free(flashdata);
    }

    keymgr_cleanup();

    return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x78, %rsp
movq %rsi, %r14
movl %edi, %ebp
xorl %r12d, %r12d
movq %r12, 0x18(%rsp)
movq %r12, 0x68(%rsp)
leaq 0x4bdd(%rip), %rdi      # 0x8c6e
callq 0x2060
cmpl $0x1, %ebp
jne 0x40b1
movq (%r14), %rsi
leaq 0x46e3(%rip), %rdi      # 0x8788
xorl %eax, %eax
callq 0x20b0
jmp 0x460d
movl %r12d, 0x826c(%rip)     # 0xc324
movl %r12d, 0x8269(%rip)     # 0xc328
jle 0x442c
leal -0x1(%rbp), %eax
movl %eax, 0x74(%rsp)
leaq 0x46a9(%rip), %rax      # 0x877c
movq %rax, 0x48(%rsp)
movl $0x1, %r15d
xorl %r12d, %r12d
movq $0x0, 0x58(%rsp)
movq $0x0, 0x28(%rsp)
movq $0x0, 0x60(%rsp)
movq $0x0, 0x30(%rsp)
movq $0x0, 0x38(%rsp)
movq $0x0, 0x50(%rsp)
movq $0x0, 0x40(%rsp)
movq %rbp, 0x8(%rsp)
movslq %r15d, %rax
cmpl 0x74(%rsp), %eax
jne 0x4133
xorl %r13d, %r13d
jmp 0x4138
movq 0x8(%r14,%rax,8), %r13
movq (%r14,%rax,8), %rax
cmpb $0x2d, (%rax)
jne 0x4152
xorl %ecx, %ecx
cmpb $0x2d, 0x1(%rax)
sete %dl
je 0x416b
leaq 0x1(%rax), %rbp
jmp 0x416f
leaq 0x4eb3(%rip), %rdi      # 0x900c
callq 0x2060
movl $0x1, %r12d
xorl %ebx, %ebx
jmp 0x42f4
leaq 0x2(%rax), %rbp
movb %dl, %cl
movb 0x1(%rcx,%rax), %bl
cmpb $0x68, %bl
je 0x42d4
movq %rbp, %rdi
leaq 0x4460(%rip), %rsi      # 0x85e8
callq 0x2100
testl %eax, %eax
je 0x42d4
cmpb $0x76, %bl
je 0x42e3
movq %rbp, %rdi
leaq 0x4466(%rip), %rsi      # 0x860e
callq 0x2100
testl %eax, %eax
je 0x42e3
cmpb $0x69, %bl
je 0x430d
movq %rbp, %rdi
leaq 0x4485(%rip), %rsi      # 0x864d
callq 0x2100
testl %eax, %eax
je 0x430d
cmpb $0x6f, %bl
je 0x432f
movq %rbp, %rdi
leaq 0x4478(%rip), %rsi      # 0x8660
callq 0x2100
testl %eax, %eax
je 0x432f
cmpb $0x6e, %bl
je 0x4351
movq %rbp, %rdi
leaq 0x445f(%rip), %rsi      # 0x8667
callq 0x2100
testl %eax, %eax
je 0x4351
cmpb $0x6b, %bl
je 0x435d
movq %rbp, %rdi
leaq 0x446d(%rip), %rsi      # 0x8695
callq 0x2100
testl %eax, %eax
je 0x435d
movq %rbp, %rdi
leaq 0x448e(%rip), %rsi      # 0x86cd
callq 0x2100
testl %eax, %eax
je 0x4393
movq %rbp, %rdi
leaq 0x4474(%rip), %rsi      # 0x86ca
callq 0x2100
testl %eax, %eax
je 0x43a7
movq %rbp, %rdi
leaq 0x4487(%rip), %rsi      # 0x86f4
callq 0x2100
testl %eax, %eax
je 0x43bb
movq %rbp, %rdi
leaq 0x44a0(%rip), %rsi      # 0x8724
callq 0x2100
testl %eax, %eax
je 0x43d8
movq %rbp, %rdi
leaq 0x44b5(%rip), %rsi      # 0x8750
callq 0x2100
testl %eax, %eax
je 0x43f5
xorl %ebx, %ebx
leaq 0x4518(%rip), %rdi      # 0x87c9
movq %rbp, %rsi
xorl %eax, %eax
callq 0x20b0
movq (%r14), %rsi
leaq 0x44c3(%rip), %rdi      # 0x8788
xorl %eax, %eax
callq 0x20b0
movl $0x1, %r12d
jmp 0x42ef
callq 0x3c9d
movl $0x1, %r12d
xorl %ebx, %ebx
jmp 0x42ef
movl $0x1, 0x8037(%rip)      # 0xc324
movb $0x1, %bl
movq 0x8(%rsp), %rbp
testb %bl, %bl
je 0x460d
incl %r15d
cmpl %ebp, %r15d
jl 0x4125
jmp 0x4477
testq %r13, %r13
movq 0x8(%rsp), %rbp
je 0x4323
incl %r15d
movb $0x1, %bl
movq %r13, 0x58(%rsp)
jmp 0x42f4
leaq 0x4cbd(%rip), %rdi      # 0x8fe7
jmp 0x4159
testq %r13, %r13
movq 0x8(%rsp), %rbp
je 0x4345
incl %r15d
movb $0x1, %bl
movq %r13, 0x28(%rsp)
jmp 0x42f4
leaq 0x4c75(%rip), %rdi      # 0x8fc1
jmp 0x4159
movl $0x1, 0x7fcd(%rip)      # 0xc328
jmp 0x42ed
testq %r13, %r13
movq 0x8(%rsp), %rbp
je 0x4387
leaq 0x4440(%rip), %rdi      # 0x87ae
movq %r13, %rsi
xorl %eax, %eax
callq 0x20b0
incl %r15d
movb $0x1, %bl
movq %r13, 0x48(%rsp)
jmp 0x42f4
leaq 0x4c12(%rip), %rdi      # 0x8fa0
jmp 0x4159
testq %r13, %r13
je 0x43cf
incl %r15d
movb $0x1, %bl
movq %r13, 0x40(%rsp)
jmp 0x42ef
testq %r13, %r13
je 0x43ec
incl %r15d
movb $0x1, %bl
movq %r13, 0x50(%rsp)
jmp 0x42ef
testq %r13, %r13
je 0x4409
incl %r15d
movb $0x1, %bl
movq %r13, 0x38(%rsp)
jmp 0x42ef
leaq 0x4b0f(%rip), %rdi      # 0x8ee5
jmp 0x4422
testq %r13, %r13
je 0x4412
incl %r15d
movb $0x1, %bl
movq %r13, 0x30(%rsp)
jmp 0x42ef
leaq 0x4b1d(%rip), %rdi      # 0x8f10
jmp 0x4422
testq %r13, %r13
je 0x441b
incl %r15d
movb $0x1, %bl
movq %r13, 0x60(%rsp)
jmp 0x42ef
leaq 0x4b2f(%rip), %rdi      # 0x8f3f
jmp 0x4422
leaq 0x4b46(%rip), %rdi      # 0x8f5f
jmp 0x4422
leaq 0x4b5d(%rip), %rdi      # 0x8f7f
callq 0x2060
jmp 0x42d9
leaq 0x4349(%rip), %rax      # 0x877c
movq %rax, 0x48(%rsp)
movq $0x0, 0x40(%rsp)
movq $0x0, 0x50(%rsp)
movq $0x0, 0x38(%rsp)
movq $0x0, 0x30(%rsp)
movq $0x0, 0x60(%rsp)
movq $0x0, 0x28(%rsp)
movq $0x0, 0x58(%rsp)
movq 0x60(%rsp), %r14
testq %r14, %r14
je 0x44c3
movq %r14, %rdi
movl $0x2c, %esi
callq 0x20a0
testq %rax, %rax
je 0x458a
movq %rax, %rbx
movb $0x0, (%rax)
leaq 0x18(%rsp), %rsi
leaq 0x14(%rsp), %rdx
movq %r14, %rdi
callq 0x36f2
testl %eax, %eax
je 0x4593
leaq 0x49fb(%rip), %rdi      # 0x8eb9
jmp 0x45ef
movq 0x58(%rsp), %rdi
testq %rdi, %rdi
je 0x45df
callq 0x37a7
testq %rax, %rax
je 0x45e8
movq %rax, %rbx
movq %rax, %rdi
callq 0x3929
cmpl $0x0, 0x7e33(%rip)      # 0xc324
je 0x4572
movq %rbx, %rbp
addq $0x30, %rbp
leaq 0x43ca(%rip), %r15      # 0x88cb
xorl %r12d, %r12d
cmpl $0x32424c53, (%rbx,%r12) # imm = 0x32424C53
jne 0x4553
leaq 0x4397(%rip), %rdi      # 0x88ac
movq %r12, %rsi
xorl %eax, %eax
callq 0x20b0
cmpl $0x0, 0xc(%rbx,%r12)
je 0x4553
movq %rbp, %r13
xorl %r14d, %r14d
movl -0x10(%r13), %edx
movl -0xc(%r13), %ecx
movq %r15, %rdi
movq %r13, %rsi
xorl %eax, %eax
callq 0x20b0
incq %r14
movl 0xc(%rbx,%r12), %eax
addq $0x30, %r13
cmpq %rax, %r14
jb 0x452d
leaq 0x4(%r12), %rax
addq $0x4, %rbp
cmpq $0x1fffffc, %r12        # imm = 0x1FFFFFC
movq %rax, %r12
jb 0x4504
movl $0xa, %edi
callq 0x2040
movq 0x50(%rsp), %rsi
testq %rsi, %rsi
je 0x461f
movq %rbx, %rdi
callq 0x3b9d
jmp 0x45f6
leaq 0x485a(%rip), %rdi      # 0x8deb
jmp 0x45ef
incq %rbx
leaq 0x4248(%rip), %rdi      # 0x87e5
movq %r14, %rsi
movq %rbx, %rdx
xorl %eax, %eax
callq 0x20b0
leaq 0x488b(%rip), %rdi      # 0x8e3c
callq 0x2060
movq 0x18(%rsp), %rdi
movl 0x14(%rsp), %esi
leaq 0x68(%rsp), %rdx
leaq 0x24(%rsp), %rcx
callq 0x6f7f
testl %eax, %eax
je 0x46ab
leaq 0x48b8(%rip), %rdi      # 0x8e95
jmp 0x45ef
leaq 0x46b6(%rip), %rdi      # 0x8c9c
jmp 0x45ef
leaq 0x46df(%rip), %rdi      # 0x8cce
callq 0x2060
xorl %ebx, %ebx
testq %rbx, %rbx
je 0x4603
movq %rbx, %rdi
callq 0x2030
xorl %r12d, %r12d
xorl %eax, %eax
callq 0x4b1a
movl %r12d, %eax
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x41f2(%rip), %rdi      # 0x8818
movq 0x48(%rsp), %r14
movq %r14, %rsi
xorl %eax, %eax
callq 0x20b0
movq %r14, %rdi
callq 0x49f0
movl $0x1, %r12d
testl %eax, %eax
jne 0x460d
cmpl $0x0, 0x7cd6(%rip)      # 0xc324
je 0x4657
xorl %eax, %eax
callq 0x4b62
cmpl $0x0, 0x7cca(%rip)      # 0xc328
movq 0x40(%rsp), %r14
movq 0x30(%rsp), %r15
movq 0x38(%rsp), %r12
je 0x46e1
testq %r12, %r12
je 0x4724
leaq 0x41b4(%rip), %rdi      # 0x8833
movq %r12, %rsi
xorl %eax, %eax
callq 0x20b0
leaq 0x18(%rsp), %rsi
leaq 0x14(%rsp), %rdx
movq %r12, %rdi
callq 0x36f2
testl %eax, %eax
je 0x46f9
leaq 0x471c(%rip), %rdi      # 0x8dc2
jmp 0x479f
movq 0x68(%rsp), %rsi
movl 0x24(%rsp), %edx
movq %rbx, %rdi
callq 0x36ac
leaq 0x47b7(%rip), %rdi      # 0x8e7a
callq 0x2060
movq 0x18(%rsp), %rdi
callq 0x2030
movq 0x68(%rsp), %rdi
callq 0x2030
jmp 0x45f4
movq %rbx, %rdi
callq 0x3a06
testl %eax, %eax
je 0x466f
leaq 0x45f5(%rip), %rdi      # 0x8ce9
jmp 0x479f
movq 0x18(%rsp), %rsi
movl 0x14(%rsp), %edx
movq %rbx, %rdi
callq 0x6652
testl %eax, %eax
je 0x471a
leaq 0x45f8(%rip), %rdi      # 0x8d0d
callq 0x2060
movq 0x18(%rsp), %rdi
callq 0x2030
testq %r15, %r15
je 0x4784
leaq 0x4132(%rip), %rdi      # 0x8862
movq %r15, %rsi
xorl %eax, %eax
callq 0x20b0
leaq 0x18(%rsp), %rsi
leaq 0x14(%rsp), %rdx
movq %r15, %rdi
callq 0x36f2
testl %eax, %eax
je 0x4759
leaq 0x4642(%rip), %rdi      # 0x8d99
jmp 0x479f
movq 0x18(%rsp), %rsi
movl 0x14(%rsp), %edx
movq %rbx, %rdi
callq 0x6ae0
testl %eax, %eax
je 0x477a
leaq 0x45bc(%rip), %rdi      # 0x8d31
callq 0x2060
movq 0x18(%rsp), %rdi
callq 0x2030
testq %r14, %r14
je 0x47a9
movq %rbx, %rdi
movq %r14, %rsi
callq 0x3a3e
testl %eax, %eax
je 0x47a9
leaq 0x45d3(%rip), %rdi      # 0x8d72
callq 0x2060
jmp 0x45f6
cmpq $0x0, 0x28(%rsp)
je 0x45f6
leaq 0x24(%rsp), %r9
movb $0x1, (%r9)
movq %rbx, %rdi
xorl %esi, %esi
movl $0x4, %edx
movl $0x31f, %ecx            # imm = 0x31F
movl $0x1, %r8d
callq 0x4c9a
cmpl $0x0, 0x7b45(%rip)      # 0xc324
je 0x47ed
leaq 0x456d(%rip), %rdi      # 0x8d55
callq 0x2060
movq 0x28(%rsp), %r14
movq %r14, %rdi
movq %rbx, %rsi
movl $0x2000000, %edx        # imm = 0x2000000
callq 0x36ac
leaq 0x4088(%rip), %rdi      # 0x8891
movq %r14, %rsi
xorl %eax, %eax
callq 0x20b0
jmp 0x45f6