// Calculate number of additional pages required to be allocated on heap by bootloader. Result CalcRequiredAllocSizeFor3DSX(Handle file, u32* numOut) { _fseek(file, 0x0, SEEK_SET); _3DSX_Header hdr; if (_fread(&hdr, sizeof(hdr), file) != 0) return -1; if (hdr.magic != _3DSX_MAGIC) return -2; _3DSX_LoadInfo d; d.segSizes[0] = (hdr.codeSegSize+0xFFF) &~ 0xFFF; SEC_ASSERT(d.segSizes[0] >= hdr.codeSegSize); // int overflow d.segSizes[1] = (hdr.rodataSegSize+0xFFF) &~ 0xFFF; SEC_ASSERT(d.segSizes[1] >= hdr.rodataSegSize); // int overflow d.segSizes[2] = (hdr.dataSegSize+0xFFF) &~ 0xFFF; SEC_ASSERT(d.segSizes[2] >= hdr.dataSegSize); // int overflow // Calculate # of pages required. u32 pagesRequired = d.segSizes[0]/0x1000 + d.segSizes[1]/0x1000 + d.segSizes[2]/0x1000; // XXX: int overflow if(pagesRequired > CN_TOTAL3DSXPAGES) *numOut = pagesRequired - CN_TOTAL3DSXPAGES + 1; else *numOut = 0; //svc_closeHandle(file); return 0; }
/****************************************************************************** * CHECK IF SECURE USBDL IS ENABLED ******************************************************************************/ int sec_usbdl_enabled(void) { switch (rom_info.m_SEC_CTRL.m_sec_usb_dl) { case ATTR_SUSBDL_ENABLE: SMSG(bMsg, "[%s] SUSBDL is enabled\n", MOD); SMSG(bMsg, "0x%x, SD-FORCE\n", ATTR_SUSBDL_ENABLE); return 1; /* SUSBDL can't be disabled on security chip */ case ATTR_SUSBDL_DISABLE: case ATTR_SUSBDL_ONLY_ENABLE_ON_SCHIP: SMSG(bMsg, "[%s] SUSBDL is only enabled on S-CHIP\n", MOD); if (TRUE == masp_hal_sbc_enabled()) { SMSG(true, "0x%x, SD-SC\n", ATTR_SUSBDL_ONLY_ENABLE_ON_SCHIP); return 1; } else { SMSG(true, "0x%x, SD-NSC\n", ATTR_SUSBDL_ONLY_ENABLE_ON_SCHIP); return 0; } default: SMSG(true, "[%s] invalid susbdl config (SD-0x%x)\n", MOD, rom_info.m_SEC_CTRL.m_sec_usb_dl); SEC_ASSERT(0); return 1; } }
/****************************************************************************** * CHECK IF SECURE BOOT IS NEEDED ******************************************************************************/ int sec_boot_enabled (void) { switch(rom_info.m_SEC_CTRL.m_sec_boot) { case ATTR_SBOOT_ENABLE: SMSG(bMsg,"[%s] SBOOT is enabled\n",MOD); SMSG(bMsg,"0x%x, SB-FORCE\n",ATTR_SBOOT_ENABLE); return 1; /* secure boot can't be disabled on security chip */ case ATTR_SBOOT_DISABLE: case ATTR_SBOOT_ONLY_ENABLE_ON_SCHIP: SMSG(bMsg,"[%s] SBOOT is only enabled on S-CHIP\n",MOD); if(TRUE == masp_hal_sbc_enabled()) { SMSG(true,"0x%x, SB-SC\n",ATTR_SBOOT_ONLY_ENABLE_ON_SCHIP); return 1; } else { SMSG(true,"0x%x, SB-NSC\n",ATTR_SBOOT_ONLY_ENABLE_ON_SCHIP); return 0; } default: SMSG(true,"[%s] invalid sboot config (SB-0x%x)\n",MOD,rom_info.m_SEC_CTRL.m_sec_boot); SEC_ASSERT(0); } return 0; }
/****************************************************************************** * IMAGE HASH CHECK ******************************************************************************/ unsigned int img_hash_check(char *part_name) { unsigned int ret = SEC_OK; SEC_ASSERT(0); return ret; }
uint32 img_hash_check (char* part_name) { uint32 ret = SEC_OK; SEC_ASSERT(0); return ret; }
SEC_IMG_HEADER_VER get_shdr_ver(void) { switch (sec_ver) { case SEC_HDR_V1: case SEC_HDR_V2: case SEC_HDR_V3: return sec_ver; default: SEC_ASSERT(0); return 0; } }
void set_shdr_ver(SEC_IMG_HEADER_VER ver) { switch (ver) { case SEC_HDR_V1: case SEC_HDR_V2: case SEC_HDR_V3: sec_ver = ver; break; default: SEC_ASSERT(0); } }
/************************************************************************** * GET VALUE **************************************************************************/ uint32 shdr_magic(SEC_IMG_HEADER_U *sec_hdr) { switch (sec_ver) { case SEC_HDR_V1: return sec_hdr->v1.magic_number; case SEC_HDR_V2: return sec_hdr->v2.magic_number; case SEC_HDR_V3: return sec_hdr->v3.magic_number; default: SEC_ASSERT(0); return 0; } }
uint32 shdr_sig_len(SEC_IMG_HEADER_U *sec_hdr) { switch (sec_ver) { case SEC_HDR_V1: return sec_hdr->v1.signature_length; case SEC_HDR_V2: return sec_hdr->v2.signature_length; case SEC_HDR_V3: return sec_hdr->v3.signature_length; default: SEC_ASSERT(0); return 0; } }
/****************************************************************************** * SECCFG VERSION ******************************************************************************/ SECCFG_VER get_seccfg_ver(void) { switch (seccfg_ver) { case SECCFG_V1: case SECCFG_V1_2: return seccfg_ver; case SECCFG_V3: return seccfg_ver; default: SEC_ASSERT(0); } return 0; }
uint32 shdr_cust_name_len(SEC_IMG_HEADER_U *sec_hdr) { switch (sec_ver) { case SEC_HDR_V1: return sizeof(sec_hdr->v1.cust_name); case SEC_HDR_V2: return sizeof(sec_hdr->v2.cust_name); case SEC_HDR_V3: return sizeof(sec_hdr->v3.cust_name); default: SEC_ASSERT(0); return 0; } }
uint32 shdr_img_offset(SEC_IMG_HEADER_U *sec_hdr) { switch (sec_ver) { case SEC_HDR_V1: return sec_hdr->v1.image_offset; case SEC_HDR_V2: return sec_hdr->v2.image_offset; case SEC_HDR_V3: return sec_hdr->v3.image_offset; default: SEC_ASSERT(0); return 0; } }
uchar *shdr_cust_name(SEC_IMG_HEADER_U *sec_hdr) { switch (sec_ver) { case SEC_HDR_V1: return sec_hdr->v1.cust_name; case SEC_HDR_V2: return sec_hdr->v2.cust_name; case SEC_HDR_V3: return sec_hdr->v3.cust_name; default: SEC_ASSERT(0); return 0; } }
void set_seccfg_ver (SECCFG_VER val) { switch(val) { case SECCFG_V1: case SECCFG_V1_2: case SECCFG_V3: case SECCFG_UNSET: seccfg_ver = val; break; default: SEC_ASSERT(0); } }
void set_shdr_img_ver(SEC_IMG_HEADER_U *sec_hdr, uint32 ver) { switch (sec_ver) { case SEC_HDR_V1: sec_hdr->v1.image_version = ver; break; case SEC_HDR_V2: sec_hdr->v2.image_version = ver; break; case SEC_HDR_V3: sec_hdr->v3.image_version = ver; default: SEC_ASSERT(0); } }
/************************************************************************** * SET VALUE **************************************************************************/ void set_shdr_magic(SEC_IMG_HEADER_U *sec_hdr, uint32 val) { switch (sec_ver) { case SEC_HDR_V1: sec_hdr->v1.magic_number = val; break; case SEC_HDR_V2: sec_hdr->v2.magic_number = val; break; case SEC_HDR_V3: sec_hdr->v3.magic_number = val; default: SEC_ASSERT(0); } }
/************************************************************************** * GET MTD PARTITION OFFSET **************************************************************************/ uint32 sec_mtd_get_off(char* part_name) { uint32 i = 0; for(i = 0; i < MAX_MTD_PARTITIONS; i++) { if(0 == mcmp(mtd_part_map[i].name,part_name,strlen(mtd_part_map[i].name))) { return mtd_part_map[i].off; } } SEC_ASSERT(0); return 0; }
void set_shdr_sign_offset(SEC_IMG_HEADER_U *sec_hdr, uint32 val) { switch (sec_ver) { case SEC_HDR_V1: sec_hdr->v1.sign_offset = val; break; case SEC_HDR_V2: sec_hdr->v2.sign_offset = val; break; case SEC_HDR_V3: sec_hdr->v3.sign_offset = val; break; default: SEC_ASSERT(0); } }
void set_shdr_cust_name(SEC_IMG_HEADER_U *sec_hdr, uchar *name, uint32 len) { switch (sec_ver) { case SEC_HDR_V1: memset(sec_hdr->v1.cust_name, 0, sizeof(sec_hdr->v1.cust_name)); mcpy(sec_hdr->v1.cust_name, name, len); break; case SEC_HDR_V2: memset(sec_hdr->v2.cust_name, 0, sizeof(sec_hdr->v2.cust_name)); mcpy(sec_hdr->v2.cust_name, name, len); break; case SEC_HDR_V3: memset(sec_hdr->v3.cust_name, 0, sizeof(sec_hdr->v3.cust_name)); mcpy(sec_hdr->v3.cust_name, name, len); break; default: SEC_ASSERT(0); } }
/* not used */ int sec_sds_enabled (void) { switch(rom_info.m_SEC_CTRL.m_sec_sds_en) { case 0: SMSG(bMsg,"[%s] SDS is disabled\n",MOD); return 1; case 1: SMSG(bMsg,"[%s] SDS is enabled\n",MOD); return 1; default: SMSG(true,"[%s] invalid SDS config (0x%x)\n",MOD,rom_info.m_SEC_CTRL.m_sec_sds_en); SEC_ASSERT(0); } return 0; }
/****************************************************************************** * CHECK IF MODEM AUTH IS NEEDED ******************************************************************************/ int sec_modem_auth_enabled (void) { switch(rom_info.m_SEC_CTRL.m_sec_modem_auth) { case 0: SMSG(bMsg,"[%s] MODEM AUTH is disabled\n",MOD); return 0; case 1: SMSG(bMsg,"[%s] MODEM AUTH is enabled\n",MOD); return 1; default: SMSG(true,"[%s] invalid modem auth config (0x%x)\n",MOD,rom_info.m_SEC_CTRL.m_sec_modem_auth); SEC_ASSERT(0); } return 0; }
void img_hash_compute (uchar *buf, uint32 size) { SEC_ASSERT(0); }
/************************************************************************** * SEC DRIVER IOCTL **************************************************************************/ long sec_core_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int err = 0; int ret = 0; unsigned int cipher_len = 0; unsigned int rid[4]; unsigned char part_name[10]; META_CONTEXT meta_ctx; /* ---------------------------------- */ /* IOCTL */ /* ---------------------------------- */ if (_IOC_TYPE(cmd) != SEC_IOC_MAGIC) return -ENOTTY; if (_IOC_NR(cmd) > SEC_IOC_MAXNR) return -ENOTTY; if (_IOC_DIR(cmd) & _IOC_READ) err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); if (_IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); if (err) return -EFAULT; switch (cmd) { /* ---------------------------------- */ /* get random id */ /* ---------------------------------- */ case SEC_GET_RANDOM_ID: SMSG(bMsg,"[%s] CMD - SEC_GET_RANDOM_ID\n",MOD); sec_get_random_id(&rid[0]); ret = osal_copy_to_user((void __user *)arg, (void *)&rid[0], sizeof(unsigned int) * 4); break; /* ---------------------------------- */ /* init boot info */ /* ---------------------------------- */ case SEC_BOOT_INIT: SMSG(bMsg,"[%s] CMD - SEC_BOOT_INIT\n",MOD); ret = sec_boot_init(); ret = osal_copy_to_user((void __user *)arg, (void *)&ret, sizeof(int)); break; /* ---------------------------------- */ /* check if secure boot is enbaled */ /* ---------------------------------- */ case SEC_BOOT_IS_ENABLED: SMSG(bMsg,"[%s] CMD - SEC_BOOT_IS_ENABLED\n",MOD); ret = sec_boot_enabled(); ret = osal_copy_to_user((void __user *)arg, (void *)&ret, sizeof(int)); break; /* ---------------------------------- */ /* encrypt sec cfg */ /* ---------------------------------- */ case SEC_SECCFG_ENCRYPT: SMSG(bMsg,"[%s] CMD - SEC_SECCFG_ENCRYPT\n",MOD); if(copy_from_user((void *)&seccfg, (void __user *)arg, sizeof(SECCFG_U))) { return -EFAULT; } /* specify encrpytion length */ SMSG(true,"[%s] SECCFG v%d\n",MOD,get_seccfg_ver()); if (SEC_CFG_END_PATTERN == seccfg.v1.end_pattern) { if((SECCFG_V1 != get_seccfg_ver()) && (SECCFG_V1_2 != get_seccfg_ver())) { SMSG(true,"[%s] mismatch seccfg version v%d\n",MOD,get_seccfg_ver()); SEC_ASSERT(0); } cipher_len = get_seccfg_cipher_len(); sp_hacc_enc((unsigned char*)&seccfg.v1.image_info,cipher_len,rom_info.m_SEC_CTRL.m_seccfg_ac_en,HACC_USER1,FALSE); } else if (SEC_CFG_END_PATTERN == seccfg.v3.end_pattern) { if(SECCFG_V3 != get_seccfg_ver()) { SMSG(true,"[%s] mismatch seccfg version v%d\n",MOD,get_seccfg_ver()); SEC_ASSERT(0); } cipher_len = get_seccfg_cipher_len(); sp_hacc_enc((unsigned char*)&seccfg.v3.image_info,cipher_len,rom_info.m_SEC_CTRL.m_seccfg_ac_en,HACC_USER1,FALSE); } else { SMSG(true,"[%s] wrong seccfg version v%d\n",MOD,seccfg.v3.seccfg_ver) SEC_ASSERT(0); } ret = osal_copy_to_user((void __user *)arg, (void *)&seccfg, sizeof(SECCFG_U)); break; /* ---------------------------------- */ /* decrypt sec cfg */ /* ---------------------------------- */ case SEC_SECCFG_DECRYPT: SMSG(bMsg,"[%s] CMD - SEC_SECCFG_DECRYPT\n",MOD); if(copy_from_user((void *)&seccfg, (void __user *)arg, sizeof(SECCFG_U))) { return -EFAULT; } /* specify decrpytion length */ if (SEC_CFG_END_PATTERN == seccfg.v1.end_pattern) { /* seccfg version should be corrected by caller */ set_seccfg_ver(SECCFG_V1); cipher_len = get_seccfg_cipher_len(); sp_hacc_dec((unsigned char*)&seccfg.v1.image_info,cipher_len,rom_info.m_SEC_CTRL.m_seccfg_ac_en,HACC_USER1,FALSE); } else if (SEC_CFG_END_PATTERN == seccfg.v3.end_pattern) { /* seccfg version should be corrected by caller */ set_seccfg_ver(SECCFG_V3); cipher_len = get_seccfg_cipher_len(); sp_hacc_dec((unsigned char*)&seccfg.v3.image_info,cipher_len,rom_info.m_SEC_CTRL.m_seccfg_ac_en,HACC_USER1,FALSE); } else { SMSG(true,"[%s] wrong seccfg version v%d\n",MOD,seccfg.v3.seccfg_ver) SEC_ASSERT(0); } SMSG(bMsg,"[%s] SECCFG v%d\n",MOD,get_seccfg_ver()); ret = osal_copy_to_user((void __user *)arg, (void *)&seccfg, sizeof(SECCFG_U)); break; /* ---------------------------------- */ /* NVRAM HW encryption */ /* ---------------------------------- */ case SEC_NVRAM_HW_ENCRYPT: SMSG(bMsg,"[%s] CMD - SEC_NVRAM_HW_ENCRYPT\n",MOD); if(osal_copy_from_user((void *)&meta_ctx, (void __user *)arg, sizeof(meta_ctx))) { return -EFAULT; } /* TODO : double check if META register is correct ? */ sp_hacc_enc((unsigned char*)&(meta_ctx.data),NVRAM_CIPHER_LEN,TRUE,HACC_USER2,FALSE); meta_ctx.ret = SEC_OK; ret = osal_copy_to_user((void __user *)arg, (void *)&meta_ctx, sizeof(meta_ctx)); break; /* ---------------------------------- */ /* NVRAM HW decryption */ /* ---------------------------------- */ case SEC_NVRAM_HW_DECRYPT: SMSG(bMsg,"[%s] CMD - SEC_NVRAM_HW_DECRYPT\n",MOD); if(osal_copy_from_user((void *)&meta_ctx, (void __user *)arg, sizeof(meta_ctx))) { return -EFAULT; } sp_hacc_dec((unsigned char*)&(meta_ctx.data),NVRAM_CIPHER_LEN,TRUE,HACC_USER2,FALSE); meta_ctx.ret = SEC_OK; ret = osal_copy_to_user((void __user *)arg, (void *)&meta_ctx, sizeof(meta_ctx)); break; /* ---------------------------------- */ /* check if secure usbdl is enbaled */ /* ---------------------------------- */ case SEC_USBDL_IS_ENABLED: SMSG(bMsg,"[%s] CMD - SEC_USBDL_IS_ENABLED\n",MOD); ret = sec_usbdl_enabled(); ret = osal_copy_to_user((void __user *)arg, (void *)&ret, sizeof(int)); break; /* ---------------------------------- */ /* configure HACC HW (include SW KEY) */ /* ---------------------------------- */ case SEC_HACC_CONFIG: SMSG(bMsg,"[%s] CMD - SEC_HACC_CONFIG\n",MOD); ret = sec_boot_hacc_init(); ret = osal_copy_to_user((void __user *)arg, (void *)&ret, sizeof(int)); break; /* ---------------------------------- */ /* enable HACC HW clock */ /* ---------------------------------- */ case SEC_HACC_ENABLE_CLK: SMSG(bMsg,"[%s] CMD - SEC_HACC_ENABLE_CLK\n",MOD); ret = osal_copy_to_user((void __user *)arg, (void *)&ret, sizeof(int)); break; /* ---------------------------------- */ /* lock hacc function */ /* ---------------------------------- */ case SEC_HACC_LOCK: SMSG(bMsg,"[%s] CMD - SEC_HACC_LOCK\n",MOD); SMSG(bMsg,"[%s] lock\n",MOD); /* If the semaphore is successfully acquired, this function returns 0.*/ ret = osal_hacc_lock(); if(ret) { SMSG(true,"[%s] ERESTARTSYS\n",MOD); return -ERESTARTSYS; } return ret; /* ---------------------------------- */ /* unlock hacc function */ /* ---------------------------------- */ case SEC_HACC_UNLOCK: SMSG(bMsg,"[%s] CMD - SEC_HACC_UNLOCK\n",MOD); SMSG(bMsg,"[%s] unlock\n",MOD); osal_hacc_unlock(); break; /* ---------------------------------- */ /* check if secure boot check enabled */ /* ---------------------------------- */ case SEC_BOOT_PART_CHECK_ENABLE: SMSG(bMsg,"[%s] CMD -SEC_BOOT_PART_CHECK_ENABLE\n",MOD); if(copy_from_user((void *)part_name, (void __user *)arg, sizeof(part_name))) { return -EFAULT; } ret = sec_boot_check_part_enabled (part_name); SMSG(bMsg,"[%s] result '0x%x'\n",MOD,ret); return ret; /* ---------------------------------- */ /* notify mark incomplete */ /* ---------------------------------- */ case SEC_BOOT_NOTIFY_MARK_STATUS: SMSG(true,"[%s] mark status\n",MOD); /* may do some post process here ... */ break; /* ---------------------------------- */ /* notify check pass */ /* ---------------------------------- */ case SEC_BOOT_NOTIFY_PASS: SMSG(true,"[%s] sbchk pass\n",MOD); SMSG(true,"[%s] sbchk pass\n",MOD); SMSG(true,"[%s] sbchk pass\n",MOD); SMSG(true,"[%s] sbchk pass\n",MOD); SMSG(true,"[%s] sbchk pass\n",MOD); /* may do some post process here ... */ break; /* ---------------------------------- */ /* notify check fail */ /* ---------------------------------- */ case SEC_BOOT_NOTIFY_FAIL: if(osal_copy_from_user((void *)part_name, (void __user *)arg, sizeof(part_name))) { return -EFAULT; } SMSG(true,"[%s] sbchk fail '%s'\n",MOD,part_name); SMSG(true,"[%s] sbchk fail '%s'\n",MOD,part_name); SMSG(true,"[%s] sbchk fail '%s'\n",MOD,part_name); SMSG(true,"[%s] sbchk fail '%s'\n",MOD,part_name); SMSG(true,"[%s] sbchk fail '%s'\n",MOD,part_name); osal_msleep(3000); /* punishment ... */ SEC_ASSERT(0); break; /* ---------------------------------- */ /* notify recovery mode done */ /* ---------------------------------- */ case SEC_BOOT_NOTIFY_RMSDUP_DONE: SMSG(true,"[%s] recovery mode done\n",MOD); /* may do some post process here ... */ break; /* ---------------------------------- */ /* read rom info */ /* ---------------------------------- */ case SEC_READ_ROM_INFO: SMSG(bMsg,"[%s] read rom info\n",MOD); ret = osal_copy_to_user((void __user *)arg, (void *)&rom_info, sizeof(AND_ROMINFO_T)); break; } return 0; }
/****************************************************************************** * IMAGE HASH CALCULATION ******************************************************************************/ void img_hash_compute(unsigned char *buf, unsigned int size) { SEC_ASSERT(0); }
int Load3DSX(Handle file, Handle process, void* baseAddr, u32 heapAddr) { // Extra heap must be deallocated before loading a new 3DSX. if(hasExtraHeap) return -5; u32 i, j, k, m; u32 endAddr = 0x00100000+CN_NEWTOTALPAGES*0x1000; SEC_ASSERT(baseAddr >= (void*)0x00100000); SEC_ASSERT((((u32) baseAddr) & 0xFFF) == 0); // page alignment _fseek(file, 0x0, SEEK_SET); _3DSX_Header hdr; if (_fread(&hdr, sizeof(hdr), file) != 0) return -1; if (hdr.magic != _3DSX_MAGIC) return -2; _3DSX_LoadInfo d; d.segSizes[0] = (hdr.codeSegSize+0xFFF) &~ 0xFFF; SEC_ASSERT(d.segSizes[0] >= hdr.codeSegSize); // int overflow d.segSizes[1] = (hdr.rodataSegSize+0xFFF) &~ 0xFFF; SEC_ASSERT(d.segSizes[1] >= hdr.rodataSegSize); // int overflow d.segSizes[2] = (hdr.dataSegSize+0xFFF) &~ 0xFFF; SEC_ASSERT(d.segSizes[2] >= hdr.dataSegSize); // int overflow // Map extra heap. u32 pagesRequired = d.segSizes[0]/0x1000 + d.segSizes[1]/0x1000 + d.segSizes[2]/0x1000; // XXX: int overflow u32 extendedPagesSize = 0; if(pagesRequired > CN_TOTAL3DSXPAGES) { if(svc_unmapProcessMemory(process, 0x00100000, 0x02000000))return -12; u32 extendedPages = pagesRequired - CN_TOTAL3DSXPAGES + 1; u32 i; for(i=0; i<extendedPages; i++) { if(svc_controlProcessMemory(process, endAddr+i*0x1000, heapAddr+i*0x1000, 0x1000, MEMOP_MAP, 0x7)) return -4; } if(svc_controlProcessMemory(process, heapAddr, 0, extendedPages*0x1000, MEMOP_PROTECT, 0x1)) return -5; processHandle = process; hasExtraHeap = 1; extraHeapAddr = heapAddr; extraHeapPages = extendedPages; extendedPagesSize = extraHeapPages*0x1000; endAddr += extendedPagesSize; if(svc_mapProcessMemory(process, 0x00100000, 0x02000000))return -13; } u32 offsets[2] = { d.segSizes[0], d.segSizes[0] + d.segSizes[1] }; d.segPtrs[0] = baseAddr; d.segPtrs[1] = (char*)d.segPtrs[0] + d.segSizes[0]; SEC_ASSERT((u32)d.segPtrs[1] >= d.segSizes[0]); // int overflow d.segPtrs[2] = (char*)d.segPtrs[1] + d.segSizes[1]; SEC_ASSERT((u32)d.segPtrs[2] >= d.segSizes[1]); // int overflow SEC_ASSERT((u32)d.segPtrs[2] < endAddr); // within user memory // Skip header for future compatibility. _fseek(file, hdr.headerSize, SEEK_SET); // Read the relocation headers SEC_ASSERT(hdr.dataSegSize >= hdr.bssSize); // int underflow u32* relocs = (u32*)((char*)d.segPtrs[2] + hdr.dataSegSize - hdr.bssSize); SEC_ASSERT((u32)relocs >= (u32)d.segPtrs[2]); // int overflow SEC_ASSERT((u32)relocs < endAddr); // within user memory u32 nRelocTables = hdr.relocHdrSize/4; u32 relocsEnd = (u32)(relocs + 3*nRelocTables); SEC_ASSERT((u32)relocsEnd >= (u32)relocs); // int overflow SEC_ASSERT((u32)relocsEnd < endAddr); // within user memory // XXX: Ensure enough RW pages exist at baseAddr to hold a memory block of length "totalSize". // This also checks whether the memory region overflows into IPC data or loader data. for (i = 0; i < 3; i ++) if (_fread(&relocs[i*nRelocTables], nRelocTables*4, file) != 0) return -3; // Read the segments if (_fread(d.segPtrs[0], hdr.codeSegSize, file) != 0) return -4; if (_fread(d.segPtrs[1], hdr.rodataSegSize, file) != 0) return -5; if (_fread(d.segPtrs[2], hdr.dataSegSize - hdr.bssSize, file) != 0) return -6; // Relocate the segments for (i = 0; i < 3; i ++) { for (j = 0; j < nRelocTables; j ++) { u32 nRelocs = relocs[i*nRelocTables+j]; if (j >= 2) { // We are not using this table - ignore it _fseek(file, nRelocs*sizeof(_3DSX_Reloc), SEEK_CUR); continue; } static _3DSX_Reloc relocTbl[RELOCBUFSIZE]; u32* pos = (u32*)d.segPtrs[i]; u32* endPos = pos + (d.segSizes[i]/4); SEC_ASSERT(((u32) endPos) < endAddr); // within user memory while (nRelocs) { u32 toDo = nRelocs > RELOCBUFSIZE ? RELOCBUFSIZE : nRelocs; nRelocs -= toDo; if (_fread(relocTbl, toDo*sizeof(_3DSX_Reloc), file) != 0) return -7; for (k = 0; k < toDo && pos < endPos; k ++) { pos += relocTbl[k].skip; u32 num_patches = relocTbl[k].patch; for (m = 0; m < num_patches && pos < endPos; m ++) { void* addr = TranslateAddr(*pos, &d, offsets); SEC_ASSERT(((u32) pos) < endAddr); // within user memory switch (j) { case 0: *pos = (u32)addr; break; case 1: *pos = (int)addr - (int)pos; break; } pos++; } } } } } // Detect and fill _prm structure u32* prmStruct = (u32*)baseAddr + 1; if(prmStruct[0]==0x6D72705F) { // Write service handle table pointer // the actual structure has to be filled out by cn_bootloader prmStruct[1] = (u32)__service_ptr; // XXX: other fields that need filling: // prmStruct[2] <-- __apt_appid (default: 0x300) // prmStruct[3] <-- __heap_size (default: 24*1024*1024) // prmStruct[4] <-- __gsp_heap_size (default: 32*1024*1024) // prmStruct[5] <-- __system_arglist (default: NULL) prmStruct[2] = 0x300; prmStruct[3] = 29*1024*1024 - extendedPagesSize; prmStruct[4] = 32*1024*1024; prmStruct[5] = CN_ARGCV_LOC; prmStruct[6] = RUNFLAG_APTWORKAROUND; //__system_runflags // XXX: Notes on __system_arglist: // Contains a pointer to a u32 specifying the number of arguments immediately followed // by the NULL-terminated argument strings themselves (no pointers). The first argument // should always be the path to the file we are booting. Example: // \x02\x00\x00\x00sd:/dir/file.3dsx\x00Argument1\x00 // Above corresponds to { "sd:/dir/file.3dsx", "Argument1" }. } // Protect memory at d.segPtrs[0] as CODE (r-x) -- npages = d.segSizes[0] / 0x1000 for(i=0;i<d.segSizes[0]>>12;i++)svc_controlProcessMemory(process, (u32)d.segPtrs[0]+i*0x1000, 0x0, 0x00001000, MEMOP_PROTECT, 0x5); // Protect memory at d.segPtrs[1] as RODATA (r--) -- npages = d.segSizes[1] / 0x1000 for(i=0;i<d.segSizes[1]>>12;i++)svc_controlProcessMemory(process, (u32)d.segPtrs[1]+i*0x1000, 0x0, 0x00001000, MEMOP_PROTECT, 0x1); // Protect memory at d.segPtrs[2] as DATA (rw-) -- npages = d.segSizes[2] / 0x1000 for(i=0;i<d.segSizes[2]>>12;i++)svc_controlProcessMemory(process, (u32)d.segPtrs[2]+i*0x1000, 0x0, 0x00001000, MEMOP_PROTECT, 0x3); //svc_closeHandle(process); TODO //svc_closeHandle(file); return 0; // Success. }