Compare commits

..

16 Commits

Author SHA1 Message Date
suchmememanyskill
ba0ded0f8b start of tsV2 2020-11-06 21:19:29 +01:00
aspargas2
024ef7cd6e fix github workflows CI (#28)
* switch github CI to docker

* empty commit to trigger CI
2020-10-29 02:21:34 +01:00
huhenU
4b445d6c9c Add check for unmounted SD card in emmc (#26)
* Add check for unmounted SD card

* Implement it the better way and remove message Meme doesn't like

* Remove comma and remove dump option if no sd is inserted

Hopefully the last commit to this PR. Hopefully.
2020-08-11 17:12:20 +02:00
suchmememanyskill
0991c73c60 (hopefully) fix workflow file 2020-08-03 13:19:50 +02:00
suchmememanyskill
3527b6ac4d Merge branch 'dev' 2020-08-03 13:10:42 +02:00
suchmememanyskill
0146f0ddb0 Bump version 2020-08-03 13:10:02 +02:00
SuchMemeManySkill
b42b52eb43 Include a (bad) method to dump with .cnmt.nca 2020-07-14 17:38:56 +02:00
Such Meme, Many Skill
81cf8c201c Fix a few bugs in the arg parser 2020-05-29 00:07:19 +02:00
Such Meme, Many Skill
34abed91a9 Bump version 2020-05-28 23:26:01 +02:00
suchmememanyskill
0382a17f87 Add fancy badges to readme 2020-05-28 23:14:16 +02:00
suchmememanyskill
d44178a863 Update README.md 2020-05-23 22:43:35 +02:00
Such Meme, Many Skill
abf814686d Change menu around a bit 2020-05-20 02:28:43 +02:00
Such Meme, Many Skill
f8394ae323 Merge branch 'Script_Fuckery' 2020-05-20 00:20:02 +02:00
Such Meme, Many Skill
fc69dc36ee Merge lockpickrcm changes 2020-05-19 18:20:19 +02:00
Such Meme, Many Skill
f61fcfea32 Empty strings should be valid 2020-05-17 01:04:33 +02:00
Such Meme, Many Skill
a872b90597 Change arg parser, add some commands, may break shit 2020-05-17 00:46:53 +02:00
60 changed files with 2187 additions and 1650 deletions

View File

@@ -8,27 +8,14 @@ on:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: devkitpro/devkita64_devkitarm
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v1
- name: Install devkitpro
run: |
wget https://github.com/devkitPro/pacman/releases/download/devkitpro-pacman-1.0.1/devkitpro-pacman.deb
sudo dpkg -i devkitpro-pacman.deb
sudo dkp-pacman -S switch-dev --noconfirm
sudo dkp-pacman -S devkitARM --noconfirm
- name: Build TegraExplorer - name: Build TegraExplorer
run: | run: make -j$(nproc)
echo # SETTING PATH #
export DEVKITPRO=/opt/devkitpro
export DEVKITARM=${DEVKITPRO}/devkitARM
export DEVKITPPC=${DEVKITPRO}/devkitPPC
export PATH=${DEVKITPRO}/tools/bin:$PATH
echo # MAKE #
make -j$(nproc)
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@master
with: with:

View File

@@ -8,10 +8,10 @@ include $(DEVKITARM)/base_rules
################################################################################ ################################################################################
IPL_LOAD_ADDR := 0x40008000 IPL_LOAD_ADDR := 0x40003000
LPVERSION_MAJOR := 3 LPVERSION_MAJOR := 3
LPVERSION_MINOR := 0 LPVERSION_MINOR := 0
LPVERSION_BUGFX := 2 LPVERSION_BUGFX := 4
################################################################################ ################################################################################

View File

@@ -1,24 +1,28 @@
# TegraExplorer # TegraExplorer
A payload-based file explorer for your switch!
![TegraExplorer builder](https://github.com/suchmememanyskill/TegraExplorer/workflows/TegraExplorer%20builder/badge.svg) [![TegraExplorer builder](https://github.com/suchmememanyskill/TegraExplorer/workflows/TegraExplorer%20builder/badge.svg)](https://github.com/suchmememanyskill/TegraExplorer/actions)
[![Downloads](https://img.shields.io/github/downloads/suchmememanyskill/TegraExplorer/total)](https://github.com/suchmememanyskill/TegraExplorer/releases)
[![Version](https://img.shields.io/github/v/release/suchmememanyskill/tegraexplorer)](https://github.com/suchmememanyskill/TegraExplorer/releases)
[![Donations](https://img.shields.io/badge/Support%20on-Ko--Fi-red)](https://ko-fi.com/suchmememanyskill)
A payload-based file explorer for your switch!
## Usage ## Usage
1. Get your favorite payload injector 1. Get your favorite payload injector
2. Inject TegraExplorer as a payload 2. Inject TegraExplorer as a payload
Navigate around the menus using the joycons. Navigate around the menus using the joycons.
A: Select - A: Select
B: Back - B: Back
Left Joystick up/down (Dpad or joystick): navigate menus up/down - Left Joystick up/down (Dpad or joystick): navigate menus up/down
Right Joystick up/down: fast menu navigation up/down - Right Joystick up/down: fast menu navigation up/down
Capture (Minerva only): Take a screenshot - Capture (Minerva only): Take a screenshot
L3/R3 (Press joysticks in): Recalibrate centerpoint - L3/R3 (Press joysticks in): Recalibrate centerpoint
If you do not have your joycons connected: If you do not have your joycons connected:
Power -> A - Power -> A
Vol+ -> Left Joystick up - Vol+ -> Left Joystick up
Vol- -> Left Joystick down - Vol- -> Left Joystick down
## Functions ## Functions
- Navigate the SD card - Navigate the SD card
@@ -56,6 +60,7 @@ Other awesome people:
- Huhen - Huhen
- Bleck9999 - Bleck9999
- Exelix - Exelix
- Emmo
## Screenshots ## Screenshots

View File

@@ -1,8 +1,8 @@
/* /*
* Common Gfx Header * Common Gfx Header
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer * Copyright (C) 2018 CTCaer
* Copyright (c) 2018 M4xw * Copyright (C) 2018 M4xw
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,

View File

@@ -1,6 +1,6 @@
/* /*
* Common Module Header * Common Module Header
* Copyright (c) 2018 M4xw * Copyright (C) 2018 M4xw
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,

View File

@@ -19,8 +19,8 @@
//#define IPL_STACK_TOP 0x4003FF00 //#define IPL_STACK_TOP 0x4003FF00
/* --- BIT/BCT: 0x40000000 - 0x40003000 --- */ /* --- BIT/BCT: 0x40000000 - 0x40003000 --- */
/* --- IPL: 0x40008000 - 0x40028000 --- */ /* --- IPL: 0x40003000 - 0x40028000 --- */
#define IPL_LOAD_ADDR 0x40008000 #define IPL_LOAD_ADDR 0x40003000
#define IPL_SZ_MAX 0x20000 // 128KB. #define IPL_SZ_MAX 0x20000 // 128KB.
//#define IRAM_LIB_ADDR 0x4002B000 //#define IRAM_LIB_ADDR 0x4002B000
#define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init. #define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init.

View File

@@ -540,6 +540,11 @@ void gfx_boxGrey(int x0, int y0, int x1, int y1, u8 shade){
memset(gfx_ctxt.fb + y * gfx_ctxt.stride + y0, shade, (y1 - y0 + 1) * 4); memset(gfx_ctxt.fb + y * gfx_ctxt.stride + y0, shade, (y1 - y0 + 1) * 4);
} }
} }
void gfx_setPixel(int x, int y, u32 color) {
*(gfx_ctxt.fb + (YLEFT - x) * gfx_ctxt.stride + y) = color;
}
/* /*
void gfx_boxGrey_old(int x0, int y0, int x1, int y1, u8 shade){ void gfx_boxGrey_old(int x0, int y0, int x1, int y1, u8 shade){
for (int y = y0; y <= y1; y++){ for (int y = y0; y <= y1; y++){

View File

@@ -53,6 +53,7 @@ void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 po
void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_box(int x0, int y0, int x1, int y1, u32 color); void gfx_box(int x0, int y0, int x1, int y1, u32 color);
void gfx_boxGrey(int x0, int y0, int x1, int y1, u8 shade); void gfx_boxGrey(int x0, int y0, int x1, int y1, u8 shade);
void gfx_setPixel(int x, int y, u32 color);
/* /*
#define GFX_SETPOSCORRECTED(x, y) gfx_con_setpos(y - YLEFT, x) #define GFX_SETPOSCORRECTED(x, y) gfx_con_setpos(y - YLEFT, x)

220
source/hos/fss.c Normal file
View File

@@ -0,0 +1,220 @@
/*
* Atmosphère Fusée Secondary Storage parser.
*
* Copyright (c) 2019-2020 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "fss.h"
// #include "hos.h"
#include "../config/config.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../storage/emummc.h"
#include "../storage/nx_sd.h"
#include "../gfx/gfx.h"
#define DPRINTF(...)
extern hekate_config h_cfg;
extern bool is_ipl_updated(void *buf, char *path, bool force);
// FSS0 Magic and Meta header offset.
#define FSS0_MAGIC 0x30535346
#define FSS0_META_OFFSET 0x4
// FSS0 Content Types.
#define CNT_TYPE_FSP 0
#define CNT_TYPE_EXO 1 // Exosphere (Secure Monitor).
#define CNT_TYPE_WBT 2 // Warmboot (SC7Exit fw).
#define CNT_TYPE_RBT 3 // Rebootstub (Warmboot based reboot fw).
#define CNT_TYPE_SP1 4 // Sept Primary (TSEC and Sept Secondary loader).
#define CNT_TYPE_SP2 5 // Sept Secondary (Acts as pkg11 and derives keys).
#define CNT_TYPE_KIP 6 // KIP1 (Used for replacement or addition).
#define CNT_TYPE_BMP 7
#define CNT_TYPE_EMC 8
#define CNT_TYPE_KLD 9 // Kernel Loader.
#define CNT_TYPE_KRN 10 // Kernel.
// FSS0 Content Flags.
#define CNT_FLAG0_EXPERIMENTAL (1 << 0)
// FSS0 Meta Header.
typedef struct _fss_meta_t
{
u32 magic;
u32 size;
u32 crt0_off;
u32 cnt_off;
u32 cnt_count;
u32 hos_ver;
u32 version;
u32 git_rev;
} fss_meta_t;
// FSS0 Content Header.
typedef struct _fss_content_t
{
u32 offset;
u32 size;
u8 type;
u8 flags0;
u8 flags1;
u8 flags2;
u32 rsvd1;
char name[0x10];
} fss_content_t;
int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt)
{
FIL fp;
bool stock = false;
int sept_used = 0;
if (!sept_ctxt)
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
{
if (!strcmp("stock", kv->key))
if (kv->val[0] == '1')
stock = true;
}
if (stock && ctxt->pkg1_id->kb <= KB_FIRMWARE_VERSION_620 && (!emu_cfg.enabled || h_cfg.emummc_force_disable))
return 1;
}
if (f_open(&fp, path, FA_READ) != FR_OK)
return 0;
void *fss = malloc(f_size(&fp));
// Read first 1024 bytes of the fss file.
f_read(&fp, fss, 1024, NULL);
// Get FSS0 Meta header offset.
u32 fss_meta_addr = *(u32 *)(fss + FSS0_META_OFFSET);
fss_meta_t *fss_meta = (fss_meta_t *)(fss + fss_meta_addr);
// Check if valid FSS0 and parse it.
if (fss_meta->magic == FSS0_MAGIC)
{
gfx_printf("Found FSS0, Atmosphere %d.%d.%d-%08x\n"
"Max HOS supported: %d.%d.%d\n"
"Unpacking and loading components.. ",
fss_meta->version >> 24, (fss_meta->version >> 16) & 0xFF, (fss_meta->version >> 8) & 0xFF, fss_meta->git_rev,
fss_meta->hos_ver >> 24, (fss_meta->hos_ver >> 16) & 0xFF, (fss_meta->hos_ver >> 8) & 0xFF);
if (!sept_ctxt)
{
ctxt->atmosphere = true;
ctxt->fss0_hosver = fss_meta->hos_ver;
}
// Parse FSS0 contents.
fss_content_t *curr_fss_cnt = (fss_content_t *)(fss + fss_meta->cnt_off);
void *content;
for (u32 i = 0; i < fss_meta->cnt_count; i++)
{
content = (void *)(fss + curr_fss_cnt[i].offset);
// Check if offset is inside limits.
if ((curr_fss_cnt[i].offset + curr_fss_cnt[i].size) > fss_meta->size)
continue;
// If content is experimental and experimental flag is not enabled, skip it.
if ((curr_fss_cnt[i].flags0 & CNT_FLAG0_EXPERIMENTAL) && !ctxt->fss0_enable_experimental)
continue;
// Parse content.
if (!sept_ctxt)
{
// Prepare content context.
switch (curr_fss_cnt[i].type)
{
case CNT_TYPE_KIP:
if (stock)
continue;
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = content;
list_append(&ctxt->kip1_list, &mkip1->link);
DPRINTF("Loaded %s.kip1 from FSS0 (size %08X)\n", curr_fss_cnt[i].name, curr_fss_cnt[i].size);
break;
case CNT_TYPE_EXO:
ctxt->secmon_size = curr_fss_cnt[i].size;
ctxt->secmon = content;
break;
case CNT_TYPE_WBT:
ctxt->warmboot_size = curr_fss_cnt[i].size;
ctxt->warmboot = content;
break;
default:
continue;
}
// Load content to launch context.
f_lseek(&fp, curr_fss_cnt[i].offset);
f_read(&fp, content, curr_fss_cnt[i].size, NULL);
}
else
{
// Load sept content directly to launch context.
switch (curr_fss_cnt[i].type)
{
case CNT_TYPE_SP1:
f_lseek(&fp, curr_fss_cnt[i].offset);
f_read(&fp, sept_ctxt->sept_primary, curr_fss_cnt[i].size, NULL);
break;
case CNT_TYPE_SP2:
if (!memcmp(curr_fss_cnt[i].name, (sept_ctxt->kb < KB_FIRMWARE_VERSION_810) ? "septsecondary00" : "septsecondary01", 15))
{
f_lseek(&fp, curr_fss_cnt[i].offset);
f_read(&fp, sept_ctxt->sept_secondary, curr_fss_cnt[i].size, NULL);
sept_used = 1;
goto out;
}
break;
default:
break;
}
}
}
out:
gfx_printf("Done!\n");
f_close(&fp);
return (!sept_ctxt ? 1 : sept_used);
}
f_close(&fp);
free(fss);
return 0;
}
int load_sept_from_ffs0(fss0_sept_t *sept_ctxt)
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &sept_ctxt->cfg_sec->kvs, link)
{
if (!strcmp("fss0", kv->key))
return parse_fss(NULL, kv->val, sept_ctxt);
}
return 0;
}

34
source/hos/fss.h Normal file
View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _FSS_H_
#define _FSS_H_
#include "hos.h"
typedef struct _fss0_sept_t
{
u32 kb;
ini_sec_t *cfg_sec;
void *sept_primary;
void *sept_secondary;
} fss0_sept_t;
int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt);
int load_sept_from_ffs0(fss0_sept_t *sept_ctxt);
#endif

120
source/hos/hos.h Normal file
View File

@@ -0,0 +1,120 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2020 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _HOS_H_
#define _HOS_H_
#include "pkg1.h"
#include "pkg2.h"
#include "../utils/types.h"
#include "../config/ini.h"
#include "../sec/tsec.h"
#include <assert.h>
#define KB_FIRMWARE_VERSION_100_200 0
#define KB_FIRMWARE_VERSION_300 1
#define KB_FIRMWARE_VERSION_301 2
#define KB_FIRMWARE_VERSION_400 3
#define KB_FIRMWARE_VERSION_500 4
#define KB_FIRMWARE_VERSION_600 5
#define KB_FIRMWARE_VERSION_620 6
#define KB_FIRMWARE_VERSION_700 7
#define KB_FIRMWARE_VERSION_810 8
#define KB_FIRMWARE_VERSION_900 9
#define KB_FIRMWARE_VERSION_910 10
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_910
#define HOS_PKG11_MAGIC 0x31314B50
#define HOS_EKS_MAGIC 0x30534B45
typedef struct _exo_ctxt_t
{
bool no_user_exceptions;
bool user_pmu;
bool *cal0_blank;
bool *cal0_allow_writes_sys;
} exo_ctxt_t;
typedef struct _hos_eks_keys_t
{
u8 dkg[0x10];
u8 mkk[0x10];
u8 fdk[0x10];
u8 dkk[0x10];
} hos_eks_keys_t;
typedef struct _hos_eks_mbr_t
{
u32 magic;
u32 enabled;
u32 sbk_low[2];
hos_eks_keys_t keys[6];
u32 magic2;
u32 rsvd2[3];
} hos_eks_mbr_t;
static_assert(sizeof(hos_eks_mbr_t) == 416, "HOS EKS storage bigger than MBR!");
typedef struct _launch_ctxt_t
{
void *keyblob;
void *pkg1;
const pkg1_id_t *pkg1_id;
const pkg2_kernel_id_t *pkg2_kernel_id;
void *warmboot;
u32 warmboot_size;
void *secmon;
u32 secmon_size;
void *pkg2;
u32 pkg2_size;
bool new_pkg2;
void *kernel;
u32 kernel_size;
link_t kip1_list;
char* kip1_patches;
u32 fss0_hosver;
bool svcperm;
bool debugmode;
bool stock;
bool atmosphere;
bool fss0_enable_experimental;
bool emummc_forced;
exo_ctxt_t exo_cfg;
ini_sec_t *cfg;
} launch_ctxt_t;
typedef struct _merge_kip_t
{
void *kip1;
link_t link;
} merge_kip_t;
void hos_eks_get();
void hos_eks_save(u32 kb);
void hos_eks_clear(u32 kb);
int hos_launch(ini_sec_t *cfg);
int hos_keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt);
#endif

View File

@@ -26,15 +26,15 @@
#include "../gfx/gfx.h" #include "../gfx/gfx.h"
u32 pkg2_newkern_ini1_val;
u32 pkg2_newkern_ini1_start;
u32 pkg2_newkern_ini1_end;
/*#include "util.h" /*#include "util.h"
#define DPRINTF(...) gfx_printf(__VA_ARGS__) #define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DEBUG_PRINTING*/ #define DEBUG_PRINTING*/
#define DPRINTF(...) #define DPRINTF(...)
u32 pkg2_newkern_ini1_val;
u32 pkg2_newkern_ini1_start;
u32 pkg2_newkern_ini1_end;
static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1) static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1)
{ {
u32 size = sizeof(pkg2_kip1_t); u32 size = sizeof(pkg2_kip1_t);

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (C) 2018-2020 CTCaer * Copyright (c) 2018-2020 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -32,6 +32,14 @@ extern u32 pkg2_newkern_ini1_val;
extern u32 pkg2_newkern_ini1_start; extern u32 pkg2_newkern_ini1_start;
extern u32 pkg2_newkern_ini1_end; extern u32 pkg2_newkern_ini1_end;
typedef struct _kernel_patch_t
{
u32 id;
u32 off;
u32 val;
u32 *ptr;
} kernel_patch_t;
typedef struct _pkg2_hdr_t typedef struct _pkg2_hdr_t
{ {
u8 ctr[0x10]; u8 ctr[0x10];
@@ -87,6 +95,12 @@ typedef struct _pkg2_kip1_info_t
link_t link; link_t link;
} pkg2_kip1_info_t; } pkg2_kip1_info_t;
typedef struct _pkg2_kernel_id_t
{
u8 hash[8];
kernel_patch_t *kernel_patchset;
} pkg2_kernel_id_t;
bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2); bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2);
int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp); int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp);
pkg2_hdr_t *pkg2_decrypt(void *data); pkg2_hdr_t *pkg2_decrypt(void *data);

View File

@@ -17,15 +17,20 @@
#include <string.h> #include <string.h>
#include "sept.h" #include "sept.h"
#include "../config/ini.h"
#include "../gfx/di.h" #include "../gfx/di.h"
#include "../hos/fss.h"
#include "../hos/hos.h"
#include "../libs/fatfs/ff.h" #include "../libs/fatfs/ff.h"
#include "../mem/heap.h" #include "../mem/heap.h"
#include "../soc/hw_init.h" #include "../soc/hw_init.h"
#include "../soc/pmc.h" #include "../soc/pmc.h"
#include "../soc/t210.h" #include "../soc/t210.h"
#include "../storage/nx_emmc.h" #include "../storage/nx_emmc.h"
#include "../storage/nx_sd.h"
#include "../storage/sdmmc.h" #include "../storage/sdmmc.h"
#include "../utils/btn.h" #include "../utils/btn.h"
#include "../utils/list.h"
#include "../utils/types.h" #include "../utils/types.h"
#include "../gfx/gfx.h" #include "../gfx/gfx.h"
@@ -58,48 +63,81 @@ u8 warmboot_reboot[] = {
extern u32 color_idx; extern u32 color_idx;
extern boot_cfg_t b_cfg; extern boot_cfg_t b_cfg;
extern void sd_unmount();
extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size); extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size);
int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb) int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb)
{ {
FIL fp; FIL fp;
bool fss0_sept_used = false;
// Copy warmboot reboot code and TSEC fw. // Copy warmboot reboot code and TSEC fw.
memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot)); memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot));
memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_size); memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_size);
*(vu32 *)SEPT_TCSZ_ADDR = tsec_size; *(vu32 *)SEPT_TCSZ_ADDR = tsec_size;
// Copy sept-primary. LIST_INIT(ini_sections);
if (f_open(&fp, "sd:/sept/sept-primary.bin", FA_READ)) if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
goto error; {
bool found = false;
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
{
// Only parse non config sections.
if (ini_sec->type == INI_CHOICE && strcmp(ini_sec->name, "config"))
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
if (!strcmp("fss0", kv->key))
{
fss0_sept_t sept_ctxt;
sept_ctxt.kb = kb;
sept_ctxt.sept_primary = (void *)SEPT_STG1_ADDR;
sept_ctxt.sept_secondary = (void *)SEPT_STG2_ADDR;
fss0_sept_used = parse_fss(NULL, kv->val, &sept_ctxt);
if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL)) found = true;
{ break;
f_close(&fp); }
goto error; }
}
if (found)
break;
}
} }
f_close(&fp);
// Copy sept-secondary.
if (kb < KB_FIRMWARE_VERSION_810) if (!fss0_sept_used)
{ {
if (f_open(&fp, "sd:/sept/sept-secondary_00.enc", FA_READ)) // Copy sept-primary.
if (f_open(&fp, "sd:/sept/sept-secondary.enc", FA_READ)) // Try the deprecated version. if (f_open(&fp, "sd:/sept/sept-primary.bin", FA_READ))
goto error;
}
else
{
if (f_open(&fp, "sd:/sept/sept-secondary_01.enc", FA_READ))
goto error; goto error;
}
if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL)) if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL))
{ {
f_close(&fp);
goto error;
}
f_close(&fp);
// Copy sept-secondary.
if (kb < KB_FIRMWARE_VERSION_810)
{
if (f_open(&fp, "sd:/sept/sept-secondary_00.enc", FA_READ))
if (f_open(&fp, "sd:/sept/sept-secondary.enc", FA_READ)) // Try the deprecated version.
goto error;
}
else
{
if (f_open(&fp, "sd:/sept/sept-secondary_01.enc", FA_READ))
goto error;
}
if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL))
{
f_close(&fp);
goto error;
}
f_close(&fp); f_close(&fp);
goto error;
} }
f_close(&fp);
// Save auto boot config to sept payload, if any. // Save auto boot config to sept payload, if any.
boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t)); boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t));
@@ -107,7 +145,8 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb)
tmp_cfg->boot_cfg |= BOOT_CFG_SEPT_RUN; tmp_cfg->boot_cfg |= BOOT_CFG_SEPT_RUN;
if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE)) { if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE))
{
free(tmp_cfg); free(tmp_cfg);
goto error; goto error;
} }

View File

@@ -81,8 +81,10 @@ static inline void _gf256_mul_x_le(void *block) {
static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_tweak, u32 tweak_exp, u64 sec, void *dst, void *src, u32 secsize) { static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_tweak, u32 tweak_exp, u64 sec, void *dst, void *src, u32 secsize) {
int res = 0; int res = 0;
u8 *pdst = (u8 *)dst; u8 *temptweak = (u8 *)malloc(0x10);
u8 *psrc = (u8 *)src; u32 *pdst = (u32 *)dst;
u32 *psrc = (u32 *)src;
u32 *ptweak = (u32 *)tweak;
if (regen_tweak) { if (regen_tweak) {
for (int i = 0xF; i >= 0; i--) { for (int i = 0xF; i >= 0; i--) {
@@ -96,34 +98,33 @@ static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_twe
for (u32 i = 0; i < tweak_exp * 0x20; i++) for (u32 i = 0; i < tweak_exp * 0x20; i++)
_gf256_mul_x_le(tweak); _gf256_mul_x_le(tweak);
u8 temptweak[0x10];
memcpy(temptweak, tweak, 0x10); memcpy(temptweak, tweak, 0x10);
//We are assuming a 0x10-aligned sector size in this implementation. //We are assuming a 0x10-aligned sector size in this implementation.
for (u32 i = 0; i < secsize / 0x10; i++) { for (u32 i = 0; i < secsize / 0x10; i++) {
for (u32 j = 0; j < 0x10; j++) for (u32 j = 0; j < 4; j++)
pdst[j] = psrc[j] ^ tweak[j]; pdst[j] = psrc[j] ^ ptweak[j];
_gf256_mul_x_le(tweak); _gf256_mul_x_le(tweak);
psrc += 0x10; psrc += 4;
pdst += 0x10; pdst += 4;
} }
se_aes_crypt_ecb(ks2, enc, dst, secsize, dst, secsize); se_aes_crypt_ecb(ks2, enc, dst, secsize, dst, secsize);
pdst = (u8 *)dst; pdst = (u32 *)dst;
memcpy(tweak, temptweak, 0x10); memcpy(tweak, temptweak, 0x10);
for (u32 i = 0; i < secsize / 0x10; i++) { for (u32 i = 0; i < secsize / 0x10; i++) {
for (u32 j = 0; j < 0x10; j++) for (u32 j = 0; j < 4; j++)
pdst[j] = pdst[j] ^ tweak[j]; pdst[j] = pdst[j] ^ ptweak[j];
_gf256_mul_x_le(tweak); _gf256_mul_x_le(tweak);
pdst += 0x10; pdst += 4;
} }
res = 1; res = 1;
out:; out:;
free(temptweak);
return res; return res;
} }

View File

@@ -4056,216 +4056,7 @@ FRESULT f_write (
LEAVE_FF(fs, FR_OK); LEAVE_FF(fs, FR_OK);
} }
#ifdef FF_FASTFS
/*-----------------------------------------------------------------------*/
/* Fast Read Aligned Sized File Without a Cache */
/*-----------------------------------------------------------------------*/
#if FF_USE_FASTSEEK
FRESULT f_read_fast (
FIL* fp, /* Pointer to the file object */
const void* buff, /* Pointer to the data to be written */
UINT btr /* Number of bytes to read */
)
{
if (btr % 65536 != 0)
return f_read(fp, buff, btr, NULL);
FRESULT res;
FATFS *fs;
UINT csize_bytes;
DWORD clst;
UINT count = 0;
FSIZE_t work_sector = 0;
FSIZE_t sector_base = 0;
BYTE *wbuff = (BYTE*)buff;
// TODO support sector reading inside a cluster
res = validate(&fp->obj, &fs); /* Check validity of the file object */
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {
EFSPRINTF("FOV");
LEAVE_FF(fs, res); /* Check validity */
}
if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
FSIZE_t remain = fp->obj.objsize - fp->fptr;
if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
csize_bytes = fs->csize * SS(fs);
if (!fp->fptr) { /* On the top of the file? */
clst = fp->obj.sclust; /* Follow from the origin */
} else {
if (fp->cltbl) clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
else { EFSPRINTF("CLTBL"); ABORT(fs, FR_CLTBL_NO_INIT); }
}
if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); }
else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); }
fp->clust = clst; /* Set working cluster */
sector_base = clst2sect(fs, fp->clust);
count += fs->csize;
btr -= csize_bytes;
fp->fptr += csize_bytes;
while (btr) {
clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
if (clst < 2) { EFSPRINTF("CCHK2"); ABORT(fs, FR_INT_ERR); }
else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); }
fp->clust = clst;
work_sector = clst2sect(fs, fp->clust);
if ((work_sector - sector_base) == count) count += fs->csize;
else {
if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);
wbuff += count * SS(fs);
sector_base = work_sector;
count = fs->csize;
}
fp->fptr += MIN(btr, csize_bytes);
btr -= MIN(btr, csize_bytes);
// TODO: what about if data is smaller than cluster?
// Must read-write back that cluster.
if (!btr) { /* Final cluster/sectors read. */
if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);
}
}
LEAVE_FF(fs, FR_OK);
}
#endif
#endif
#ifdef FF_FASTFS
/*-----------------------------------------------------------------------*/
/* Fast Write Aligned Sized File Without a Cache */
/*-----------------------------------------------------------------------*/
#if FF_USE_FASTSEEK
FRESULT f_write_fast (
FIL* fp, /* Pointer to the file object */
const void* buff, /* Pointer to the data to be written */
UINT btw /* Number of bytes to write */
)
{
if (btw % 65536 != 0)
return f_write(fp, buff, btw, NULL);
FRESULT res;
FATFS *fs;
UINT csize_bytes;
DWORD clst;
UINT count = 0;
FSIZE_t work_sector = 0;
FSIZE_t sector_base = 0;
const BYTE *wbuff = (const BYTE*)buff;
// TODO support sector writing inside a cluster
res = validate(&fp->obj, &fs); /* Check validity of the file object */
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {
EFSPRINTF("FOV");
LEAVE_FF(fs, res); /* Check validity */
}
if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
/* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */
if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) {
btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr);
}
csize_bytes = fs->csize * SS(fs);
if (!fp->fptr) { /* On the top of the file? */
clst = fp->obj.sclust; /* Follow from the origin */
} else {
if (fp->cltbl) clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
else { EFSPRINTF("CLTBL"); ABORT(fs, FR_CLTBL_NO_INIT); }
}
if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); }
else if (clst == 0xFFFFFFFF) { EFSPRINTF("DERR"); ABORT(fs, FR_DISK_ERR); }
fp->clust = clst; /* Set working cluster */
sector_base = clst2sect(fs, fp->clust);
count += fs->csize;
btw -= csize_bytes;
fp->fptr += csize_bytes;
while (btw) {
clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
if (clst < 2) { EFSPRINTF("CCHK2"); ABORT(fs, FR_INT_ERR); }
else if (clst == 0xFFFFFFFF) { EFSPRINTF("DERR"); ABORT(fs, FR_DISK_ERR); }
fp->clust = clst;
work_sector = clst2sect(fs, fp->clust);
if ((work_sector - sector_base) == count) count += fs->csize;
else {
if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);
wbuff += count * SS(fs);
sector_base = work_sector;
count = fs->csize;
}
fp->fptr += MIN(btw, csize_bytes);
btw -= MIN(btw, csize_bytes);
// what about if data is smaller than cluster?
// Probably must read-write back that cluster.
if (!btw) { /* Final cluster/sectors write. */
if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);
fp->flag &= (BYTE)~FA_DIRTY;
}
}
fp->flag |= FA_MODIFIED; /* Set file change flag */
LEAVE_FF(fs, FR_OK);
}
#endif
#endif
#ifdef FF_FASTFS
#if FF_USE_FASTSEEK
/*-----------------------------------------------------------------------*/
/* Seek File Read/Write Pointer */
/*-----------------------------------------------------------------------*/
DWORD *f_expand_cltbl (
FIL* fp, /* Pointer to the file object */
UINT tblsz, /* Size of table */
FSIZE_t ofs /* File pointer from top of file */
)
{
if (fp->flag & FA_WRITE) f_lseek(fp, ofs); /* Expand file if write is enabled */
if (!fp->cltbl) { /* Allocate memory for cluster link table */
fp->cltbl = (DWORD *)ff_memalloc(tblsz);
fp->cltbl[0] = tblsz;
}
if (f_lseek(fp, CREATE_LINKMAP)) { /* Create cluster link table */
ff_memfree(fp->cltbl);
fp->cltbl = NULL;
EFSPRINTF("CLTBLSZ");
return NULL;
}
f_lseek(fp, 0);
return fp->cltbl;
}
#endif
#endif
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@@ -4378,13 +4169,6 @@ FRESULT f_close (
#endif #endif
} }
} }
if (fp->cltbl != NULL){
ff_memfree(fp->cltbl);
fp->cltbl = NULL;
}
return res; return res;
} }

View File

@@ -246,10 +246,7 @@ typedef enum {
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
FR_INVALID_PARAMETER, /* (19) Given parameter is invalid */ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
#ifdef FF_FASTFS
FR_CLTBL_NO_INIT /* (20) The cluster table for fast seek/read/write was not created */
#endif
} FRESULT; } FRESULT;
@@ -291,11 +288,6 @@ int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
#ifdef FF_FASTFS
FRESULT f_read_fast (FIL* fp, const void* buff, UINT btr); /* Fast read data from the file */
FRESULT f_write_fast (FIL* fp, const void* buff, UINT btw); /* Fast write data to the file */
DWORD *f_expand_cltbl (FIL* fp, UINT tblsz, FSIZE_t ofs); /* Expand file and populate cluster table */
#endif
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
#define f_error(fp) ((fp)->err) #define f_error(fp) ((fp)->err)

View File

@@ -42,13 +42,7 @@
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define FF_FASTFS 1
#ifdef FF_FASTFS
#define FF_USE_FASTSEEK 1
#else
#define FF_USE_FASTSEEK 0 #define FF_USE_FASTSEEK 0
#endif
/* This option switches fast seek function. (0:Disable or 1:Enable) */ /* This option switches fast seek function. (0:Disable or 1:Enable) */
@@ -293,5 +287,3 @@
/*--- End of configuration options ---*/ /*--- End of configuration options ---*/

View File

@@ -136,7 +136,7 @@ void *malloc(u32 size)
void *calloc(u32 num, u32 size) void *calloc(u32 num, u32 size)
{ {
void *res = (void *)_heap_alloc(&_heap, num * size); void *res = (void *)_heap_alloc(&_heap, num * size);
memset(res, 0, num * size); memset(res, 0, ALIGN(num * size, sizeof(hnode_t))); // Clear the aligned size.
return res; return res;
} }

View File

@@ -2,7 +2,7 @@
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
* *
* Copyright (c) 2018-2019 CTCaer * Copyright (c) 2018-2019 CTCaer
* Copyright (c) 2019 shchmue * Copyright (c) 2019-2020 shchmue
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -35,10 +35,10 @@ void max77620_rtc_get_time(rtc_time_t *time)
// Get time. // Get time.
time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F; time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F;
time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F; time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F;
u8 hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG);
time->hour = hour & 0x1F;
if (!(val & MAX77620_RTC_24H) && (hour & MAX77620_RTC_HOUR_PM_MASK)) time->hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG) & 0x1F;
if (!(val & MAX77620_RTC_24H) && time->hour & MAX77620_RTC_HOUR_PM_MASK)
time->hour = (time->hour & 0xF) + 12; time->hour = (time->hour & 0xF) + 12;
// Get day of week. 1: Monday to 7: Sunday. // Get day of week. 1: Monday to 7: Sunday.

View File

@@ -19,6 +19,7 @@
#include <string.h> #include <string.h>
#include "../../common/memory_map.h"
#include "../sec/se.h" #include "../sec/se.h"
#include "../mem/heap.h" #include "../mem/heap.h"
#include "../soc/bpmp.h" #include "../soc/bpmp.h"
@@ -94,7 +95,12 @@ static int _se_wait()
static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size) static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size)
{ {
se_ll_t *ll_dst = (se_ll_t *)0xECFFFFE0, *ll_src = (se_ll_t *)0xECFFFFF0; static se_ll_t *ll_dst = NULL, *ll_src = NULL;
if (!ll_dst)
{
ll_dst = (se_ll_t *)malloc(sizeof(se_ll_t));
ll_src = (se_ll_t *)malloc(sizeof(se_ll_t));
}
if (dst) if (dst)
{ {
@@ -234,6 +240,16 @@ void se_aes_key_set(u32 ks, const void *key, u32 size)
} }
} }
void se_aes_iv_set(u32 ks, const void *iv, u32 size)
{
u32 *data = (u32 *)iv;
for (u32 i = 0; i < size / 4; i++)
{
SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | 8 | i;
SE(SE_KEYTABLE_DATA0_REG_OFFSET) = data[i];
}
}
void se_aes_key_read(u32 ks, void *key, u32 size) void se_aes_key_read(u32 ks, void *key, u32 size)
{ {
u32 *data = (u32 *)key; u32 *data = (u32 *)key;
@@ -320,12 +336,90 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s
return 1; return 1;
} }
// random calls were derived from Atmosphère's
int se_initialize_rng(u32 ks)
{
u8 *output_buf = (u8 *)malloc(0x10);
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) |
SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(RNG_MODE_FORCE_INSTANTION) | SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY);
SE(SE_RNG_RESEED_INTERVAL_REG_OFFSET) = 70001;
SE(SE_RNG_SRC_CONFIG_REG_OFFSET) = SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(RNG_SRC_RO_ENT_LOCK_ENABLE);
SE(SE_BLOCK_COUNT_REG_OFFSET) = 0;
int res =_se_execute(OP_START, output_buf, 0x10, NULL, 0);
free(output_buf);
return res;
}
int se_generate_random(u32 ks, void *dst, u32 size)
{
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) |
SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(RNG_MODE_NORMAL) | SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY);
u32 num_blocks = size >> 4;
u32 aligned_size = num_blocks << 4;
if (num_blocks)
{
SE(SE_BLOCK_COUNT_REG_OFFSET) = num_blocks - 1;
if (!_se_execute(OP_START, dst, aligned_size, NULL, 0))
return 0;
}
if (size > aligned_size)
return _se_execute_one_block(OP_START, dst + aligned_size, size - aligned_size, NULL, 0);
return 1;
}
int se_generate_random_key(u32 ks_dst, u32 ks_src)
{
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks_src) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) |
SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(RNG_MODE_NORMAL) | SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY);
SE(SE_CRYPTO_KEYTABLE_DST_REG_OFFSET) = SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(ks_dst);
if (!_se_execute(OP_START, NULL, 0, NULL, 0))
return 0;
SE(SE_CRYPTO_KEYTABLE_DST_REG_OFFSET) = SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(ks_dst) | 1;
if (!_se_execute(OP_START, NULL, 0, NULL, 0))
return 0;
return 1;
}
int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size)
{
if (enc)
{
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) |
SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_TOP) | SE_CRYPTO_INPUT_SEL(INPUT_AHB) |
SE_CRYPTO_IV_SEL(IV_ORIGINAL);
}
else
{
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVAHB) |
SE_CRYPTO_CORE_SEL(CORE_DECRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_AHB) |
SE_CRYPTO_IV_SEL(IV_ORIGINAL);
}
SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1;
return _se_execute(OP_START, dst, dst_size, src, src_size);
}
int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize) int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize)
{ {
int res = 0; int res = 0;
u8 *tweak = (u8 *)malloc(0x10); u8 *tweak = (u8 *)malloc(0x10);
u8 *pdst = (u8 *)dst; u8 *temptweak = (u8 *)malloc(0x10);
u8 *psrc = (u8 *)src; u32 *pdst = (u32 *)dst;
u32 *psrc = (u32 *)src;
u32 *ptweak = (u32 *)tweak;
//Generate tweak. //Generate tweak.
for (int i = 0xF; i >= 0; i--) for (int i = 0xF; i >= 0; i--)
@@ -336,23 +430,35 @@ int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const vo
if (!se_aes_crypt_block_ecb(ks1, 1, tweak, tweak)) if (!se_aes_crypt_block_ecb(ks1, 1, tweak, tweak))
goto out; goto out;
memcpy(temptweak, tweak, 0x10);
//We are assuming a 0x10-aligned sector size in this implementation. //We are assuming a 0x10-aligned sector size in this implementation.
for (u32 i = 0; i < secsize / 0x10; i++) for (u32 i = 0; i < secsize / 0x10; i++)
{ {
for (u32 j = 0; j < 0x10; j++) for (u32 j = 0; j < 4; j++)
pdst[j] = psrc[j] ^ tweak[j]; pdst[j] = psrc[j] ^ ptweak[j];
if (!se_aes_crypt_block_ecb(ks2, enc, pdst, pdst))
goto out;
for (u32 j = 0; j < 0x10; j++)
pdst[j] = pdst[j] ^ tweak[j];
_gf256_mul_x_le(tweak); _gf256_mul_x_le(tweak);
psrc += 0x10; psrc += 4;
pdst += 0x10; pdst += 4;
}
se_aes_crypt_ecb(ks2, enc, dst, secsize, dst, secsize);
pdst = (u32 *)dst;
memcpy(tweak, temptweak, 0x10);
for (u32 i = 0; i < secsize / 0x10; i++)
{
for (u32 j = 0; j < 4; j++)
pdst[j] = pdst[j] ^ ptweak[j];
_gf256_mul_x_le(tweak);
pdst += 4;
} }
res = 1; res = 1;
out:; out:;
free(temptweak);
free(tweak); free(tweak);
return res; return res;
} }
@@ -390,17 +496,21 @@ int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size)
se_aes_key_iv_clear(ks); se_aes_key_iv_clear(ks);
u32 num_blocks = (src_size + 0xf) >> 4; u32 num_blocks = (src_size + 0xf) >> 4;
if (num_blocks > 1) { if (num_blocks > 1)
{
SE(SE_BLOCK_COUNT_REG_OFFSET) = num_blocks - 2; SE(SE_BLOCK_COUNT_REG_OFFSET) = num_blocks - 2;
if (!_se_execute(OP_START, NULL, 0, src, src_size)) if (!_se_execute(OP_START, NULL, 0, src, src_size))
goto out; goto out;
SE(SE_CRYPTO_REG_OFFSET) |= SE_CRYPTO_IV_SEL(IV_UPDATED); SE(SE_CRYPTO_REG_OFFSET) |= SE_CRYPTO_IV_SEL(IV_UPDATED);
} }
if (src_size & 0xf) { if (src_size & 0xf)
{
memcpy(last_block, src + (src_size & ~0xf), src_size & 0xf); memcpy(last_block, src + (src_size & ~0xf), src_size & 0xf);
last_block[src_size & 0xf] = 0x80; last_block[src_size & 0xf] = 0x80;
} else if (src_size >= 0x10) { }
else if (src_size >= 0x10)
{
memcpy(last_block, src + src_size - 0x10, 0x10); memcpy(last_block, src + src_size - 0x10, 0x10);
} }
@@ -447,7 +557,8 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size)
return res; return res;
} }
int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size) { int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size)
{
int res = 0; int res = 0;
u8 *secret = (u8 *)malloc(0x40); u8 *secret = (u8 *)malloc(0x40);
u8 *ipad = (u8 *)malloc(0x40 + src_size); u8 *ipad = (u8 *)malloc(0x40 + src_size);

View File

@@ -25,12 +25,17 @@ void se_rsa_key_clear(u32 ks);
int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size); int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size);
void se_key_acc_ctrl(u32 ks, u32 flags); void se_key_acc_ctrl(u32 ks, u32 flags);
void se_aes_key_set(u32 ks, const void *key, u32 size); void se_aes_key_set(u32 ks, const void *key, u32 size);
void se_aes_iv_set(u32 ks, const void *iv, u32 size);
void se_aes_key_read(u32 ks, void *key, u32 size); void se_aes_key_read(u32 ks, void *key, u32 size);
void se_aes_key_clear(u32 ks); void se_aes_key_clear(u32 ks);
int se_initialize_rng(u32 ks);
int se_generate_random(u32 ks, void *dst, u32 size);
int se_generate_random_key(u32 ks_dst, u32 ks_src);
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input); int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input);
int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size);
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src); int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src);
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr); int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr);
int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size);
int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize); int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize);
int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize, u32 num_secs); int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize, u32 num_secs);
int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size); int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size);

View File

@@ -18,6 +18,7 @@
#include <string.h> #include <string.h>
#include "../hos/hos.h"
#include "../sec/tsec.h" #include "../sec/tsec.h"
#include "../sec/tsec_t210.h" #include "../sec/tsec_t210.h"
#include "../sec/se_t210.h" #include "../sec/se_t210.h"
@@ -80,7 +81,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
kfuse_wait_ready(); kfuse_wait_ready();
// Configure Falcon. //Configure Falcon.
TSEC(TSEC_DMACTL) = 0; TSEC(TSEC_DMACTL) = 0;
TSEC(TSEC_IRQMSET) = TSEC(TSEC_IRQMSET) =
TSEC_IRQMSET_EXT(0xFF) | TSEC_IRQMSET_EXT(0xFF) |
@@ -102,7 +103,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
goto out; goto out;
} }
// Load firmware or emulate memio environment for newer TSEC fw. //Load firmware or emulate memio environment for newer TSEC fw.
if (kb == KB_FIRMWARE_VERSION_620) if (kb == KB_FIRMWARE_VERSION_620)
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8; TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
else else
@@ -126,7 +127,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
{ {
// Init SMMU translation for TSEC. // Init SMMU translation for TSEC.
pdir = smmu_init_for_tsec(); pdir = smmu_init_for_tsec();
smmu_init(tsec_ctxt->secmon_base); smmu_init(0x4002B000);
// Enable SMMU // Enable SMMU
if (!smmu_is_used()) if (!smmu_is_used())
smmu_enable(); smmu_enable();
@@ -169,7 +170,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
iram = page_alloc(0x30); iram = page_alloc(0x30);
memcpy(iram, tsec_ctxt->pkg1, 0x30000); memcpy(iram, tsec_ctxt->pkg1, 0x30000);
// PKG1.1 magic offset. // PKG1.1 magic offset.
pkg11_magic_off = (u32 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / 4)); pkg11_magic_off = (u32 *)(iram + (0x7000 / 4));
smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE); smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE);
// Exception vectors // Exception vectors
@@ -177,7 +178,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE); smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE);
} }
// Execute firmware. //Execute firmware.
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA; HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA;
TSEC(TSEC_STATUS) = 0; TSEC(TSEC_STATUS) = 0;
TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1. TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1.
@@ -254,7 +255,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
goto out_free; goto out_free;
} }
// Fetch result. //Fetch result.
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0; HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0;
u32 buf[4]; u32 buf[4];
buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB); buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB);
@@ -274,7 +275,7 @@ out_free:;
out:; out:;
// Disable clocks. //Disable clocks.
clock_disable_kfuse(); clock_disable_kfuse();
clock_disable_sor1(); clock_disable_sor1();
clock_disable_sor0(); clock_disable_sor0();

View File

@@ -27,8 +27,6 @@ typedef struct _tsec_ctxt_t
void *fw; void *fw;
u32 size; u32 size;
void *pkg1; void *pkg1;
u32 pkg11_off;
u32 secmon_base;
} tsec_ctxt_t; } tsec_ctxt_t;
typedef struct _tsec_key_data_t typedef struct _tsec_key_data_t

View File

@@ -26,7 +26,6 @@
#include "pinmux.h" #include "pinmux.h"
#include "pmc.h" #include "pmc.h"
#include "t210.h" #include "t210.h"
#include "uart.h"
#include "../gfx/di.h" #include "../gfx/di.h"
#include "../mem/mc.h" #include "../mem/mc.h"
#include "../mem/minerva.h" #include "../mem/minerva.h"
@@ -102,7 +101,7 @@ void _config_gpios()
pinmux_config_i2c(I2C_1); pinmux_config_i2c(I2C_1);
pinmux_config_i2c(I2C_5); pinmux_config_i2c(I2C_5);
pinmux_config_uart(UART_A); pinmux_config_uart(0);
// Configure volume up/down as inputs. // Configure volume up/down as inputs.
gpio_config(GPIO_PORT_X, GPIO_PIN_6, GPIO_MODE_GPIO); gpio_config(GPIO_PORT_X, GPIO_PIN_6, GPIO_MODE_GPIO);
@@ -295,11 +294,6 @@ void config_hw()
APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0; APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0;
_config_gpios(); _config_gpios();
#ifdef DEBUG_UART_PORT
clock_enable_uart(DEBUG_UART_PORT);
uart_init(DEBUG_UART_PORT, 115200);
#endif
clock_enable_cl_dvfs(); clock_enable_cl_dvfs();
clock_enable_i2c(I2C_1); clock_enable_i2c(I2C_1);
@@ -319,6 +313,7 @@ void config_hw()
sdram_init(); sdram_init();
bpmp_mmu_enable(); bpmp_mmu_enable();
mc_enable_ahb_redirect();
// Clear flags from PMC_SCRATCH0 // Clear flags from PMC_SCRATCH0
PMC(APBDEV_PMC_SCRATCH0) &= ~PMC_SCRATCH0_MODE_PAYLOAD; PMC(APBDEV_PMC_SCRATCH0) &= ~PMC_SCRATCH0_MODE_PAYLOAD;
@@ -334,7 +329,7 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
// Re-enable clocks to Audio Processing Engine as a workaround to hanging. // Re-enable clocks to Audio Processing Engine as a workaround to hanging.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock. CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock. CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock.
if (extra_reconfig) if (extra_reconfig)
{ {
@@ -357,7 +352,7 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
if (magic == 0xBAADF00D) if (magic == 0xBAADF00D)
{ {
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22); CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22);
sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, 0); sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0);
clock_disable_cl_dvfs(); clock_disable_cl_dvfs();
msleep(200); msleep(200);

View File

@@ -116,3 +116,5 @@ extern gpt_entry_rule gpt_fs_rules[];
extern menu_entry mmcmenu_start[]; extern menu_entry mmcmenu_start[];
extern menu_entry mmcmenu_filemenu[]; extern menu_entry mmcmenu_filemenu[];
extern menu_entry fwDump_typeMenu[];

View File

@@ -93,3 +93,10 @@ menu_entry mmcmenu_filemenu[] = {
{"\nBack", COLOR_WHITE, {ISMENU}}, {"\nBack", COLOR_WHITE, {ISMENU}},
{"Dump to SD", COLOR_YELLOW, {ISMENU}} {"Dump to SD", COLOR_YELLOW, {ISMENU}}
}; };
menu_entry fwDump_typeMenu[] = {
{"Back\n", COLOR_WHITE, {ISMENU}},
{"Firmware format type:", COLOR_WHITE, {ISMENU | ISSKIP}},
{"Daybreak (prod.keys required!)", COLOR_BLUE, {ISMENU}},
{"ChoiNX", COLOR_VIOLET, {ISMENU}}
};

View File

@@ -59,3 +59,5 @@ typedef struct {
#define isFS 0x80 #define isFS 0x80
#define isBOOT 0x2 #define isBOOT 0x2
typedef void (*func_void_ptr)();

View File

@@ -219,9 +219,6 @@ int dump_biskeys(){
//nx_emmc_gpt_parse(&sys_gpt, &storage); //nx_emmc_gpt_parse(&sys_gpt, &storage);
se_aes_key_set(8, bis_key[2] + 0x00, 0x10);
se_aes_key_set(9, bis_key[2] + 0x10, 0x10);
pkg1inf.ver = pkg1_id->kb; pkg1inf.ver = pkg1_id->kb;
strcpy(pkg1inf.id, pkg1_id->id); strcpy(pkg1inf.id, pkg1_id->id);
return 0; return 0;

View File

@@ -28,6 +28,7 @@ extern sdmmc_storage_t storage;
extern emmc_part_t *system_part; extern emmc_part_t *system_part;
extern char *clipboard; extern char *clipboard;
extern u8 clipboardhelper; extern u8 clipboardhelper;
extern bool sd_mounted;
void addEntry(emmc_part_t *part, u8 property_GPT, int spot){ void addEntry(emmc_part_t *part, u8 property_GPT, int spot){
@@ -73,6 +74,12 @@ int fillMmcMenu(short mmcType){
mu_createObjects(count, &mmcMenuEntries); mu_createObjects(count, &mmcMenuEntries);
if (!sd_mounted)
sd_mount();
SETBIT(mmcmenu_filemenu[3].property, ISHIDE, !sd_mounted);
SETBIT(mmcmenu_start[1].property, ISHIDE, !sd_mounted);
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
mu_copySingle(mmcmenu_start[i].name, mmcmenu_start[i].storage, mmcmenu_start[i].property, &mmcMenuEntries[i]); mu_copySingle(mmcmenu_start[i].name, mmcmenu_start[i].storage, mmcmenu_start[i].property, &mmcMenuEntries[i]);

View File

@@ -191,6 +191,7 @@ int filemenu(menu_entry file){
break; break;
} }
fsreader_readfolder(currentpath);
break; break;
case FILE_PAYLOAD: case FILE_PAYLOAD:
launch_payload(fsutil_getnextloc(currentpath, file.name)); launch_payload(fsutil_getnextloc(currentpath, file.name));
@@ -203,7 +204,8 @@ int filemenu(menu_entry file){
while (hidRead()->buttons); while (hidRead()->buttons);
*/ */
runScript(fsutil_getnextloc(currentpath, file.name)); startScript(fsutil_getnextloc(currentpath, file.name));
fsreader_readfolder(currentpath);
break; break;
case FILE_HEXVIEW: case FILE_HEXVIEW:
viewbytes(fsutil_getnextloc(currentpath, file.name)); viewbytes(fsutil_getnextloc(currentpath, file.name));
@@ -211,6 +213,7 @@ int filemenu(menu_entry file){
case FILE_DUMPBIS: case FILE_DUMPBIS:
gfx_clearscreen(); gfx_clearscreen();
extract_bis_file(fsutil_getnextloc(currentpath, file.name), currentpath); extract_bis_file(fsutil_getnextloc(currentpath, file.name), currentpath);
fsreader_readfolder(currentpath);
hidWait(); hidWait();
break; break;
case FILE_SIGN: case FILE_SIGN:
@@ -228,6 +231,5 @@ int filemenu(menu_entry file){
return -1; return -1;
} }
fsreader_readfolder(currentpath);
return 0; return 0;
} }

View File

@@ -16,7 +16,7 @@ int fsact_copy(const char *locin, const char *locout, u8 options){
FILINFO in_info; FILINFO in_info;
u64 sizeRemaining, toCopy; u64 sizeRemaining, toCopy;
u8 *buff, toPrint = options & COPY_MODE_PRINT, toCancel = options & COPY_MODE_CANCEL; u8 *buff, toPrint = options & COPY_MODE_PRINT, toCancel = options & COPY_MODE_CANCEL;
u32 x, y, i = 11, toSpeed; u32 x, y, i = 11;
int res; int res;
gfx_con_getpos(&x, &y); gfx_con_getpos(&x, &y);
@@ -52,18 +52,15 @@ int fsact_copy(const char *locin, const char *locout, u8 options){
sizeRemaining = f_size(&in); sizeRemaining = f_size(&in);
const u64 totalsize = sizeRemaining; const u64 totalsize = sizeRemaining;
DWORD *clmt_in = f_expand_cltbl(&in, BUFSIZE / 4, 0);
DWORD *clmt_out = f_expand_cltbl(&out, BUFSIZE / 4, totalsize);
while (sizeRemaining > 0){ while (sizeRemaining > 0){
toCopy = MIN(sizeRemaining, BUFSIZE); toCopy = MIN(sizeRemaining, BUFSIZE);
if ((res = f_read_fast(&in, buff, toCopy))){ if ((res = f_read(&in, buff, toCopy, NULL))){
gfx_errDisplay("copy", res, 5); gfx_errDisplay("copy", res, 5);
break; break;
} }
if ((res = f_write_fast(&out, buff, toCopy))){ if ((res = f_write(&out, buff, toCopy, NULL))){
gfx_errDisplay("copy", res, 6); gfx_errDisplay("copy", res, 6);
break; break;
} }

View File

@@ -0,0 +1,62 @@
#include "keys.h"
#include "../../utils/types.h"
#include "../../libs/fatfs/ff.h"
#include "../../sec/se.h"
#include "../../mem/heap.h"
#include "../gfx/gfxutils.h"
#include "../../config/ini.h"
#include "../common/common.h"
#include <string.h>
char *getKey(const char *search, link_t *inilist){
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, inilist, link){
if (ini_sec->type == INI_CHOICE){
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
if (!strcmp(search, kv->key))
return kv->val;
}
}
}
return NULL;
}
u8 getHexSingle(const char c) {
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
}
u8 *getHex(const char *in){
u32 len = strlen(in), count = 0;
u8 *out = calloc(len / 2, sizeof(u8));
for (u32 i = 0; i < len; i += 2){
out[count++] = (u8)(getHexSingle(in[i]) << 4) | (getHexSingle(in[i + 1]));
}
return out;
}
u8 *GetKey(const char *keypath, const char *keyName){
LIST_INIT(inilist);
char *key;
u8 *hex = NULL;
if (!ini_parse(&inilist, keypath, false)){
gfx_errDisplay("GetKey", ERR_INI_PARSE_FAIL, 1);
goto out_free;
}
if ((key = getKey(keyName, &inilist)) == NULL){
gfx_errDisplay("GetKey", ERR_INI_PARSE_FAIL, 2);
goto out_free;
}
hex = getHex(key);
out_free:;
list_empty(&inilist);
return hex;
}

View File

@@ -0,0 +1,4 @@
#pragma once
#include "../../utils/types.h"
u8 *GetKey(const char *keypath, const char *keyName);

View File

@@ -0,0 +1,46 @@
#include "nca.h"
#include "keys.h"
#include "../../utils/types.h"
#include "../../libs/fatfs/ff.h"
#include "../../sec/se.h"
#include "../../mem/heap.h"
#include "../gfx/gfxutils.h"
#include "../../config/ini.h"
#include "../common/common.h"
#include <string.h>
int SetHeaderKey(){
u8 *header_key = GetKey("sd:/switch/prod.keys", "header_key");
if (header_key == NULL)
return -1;
se_aes_key_set(4, header_key + 0x00, 0x10);
se_aes_key_set(5, header_key + 0x10, 0x10);
return 0;
}
int GetNcaType(char *ncaPath){
FIL fp;
u32 read_bytes = 0;
if (f_open(&fp, ncaPath, FA_READ | FA_OPEN_EXISTING))
return -1;
u8 *dec_header = (u8*)malloc(0x600);
if (f_lseek(&fp, 0x200) || f_read(&fp, dec_header, 32, &read_bytes) || read_bytes != 32){
f_close(&fp);
free(dec_header);
return -1;
}
se_aes_xts_crypt(5,4,0,1,dec_header + 0x200, dec_header, 32, 1);
u8 ContentType = dec_header[0x205];
f_close(&fp);
free(dec_header);
return ContentType;
}

View File

@@ -0,0 +1,4 @@
#pragma once
int GetNcaType(char *ncaPath);
int SetHeaderKey();

View File

@@ -1,4 +1,5 @@
#include "savesign.h" #include "savesign.h"
#include "keys.h"
#include "../../utils/types.h" #include "../../utils/types.h"
#include "../../libs/fatfs/ff.h" #include "../../libs/fatfs/ff.h"
#include "../../sec/se.h" #include "../../sec/se.h"
@@ -62,62 +63,15 @@ out_free:;
return success; return success;
} }
char *getKey(const char *search, link_t *inilist){
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, inilist, link){
if (ini_sec->type == INI_CHOICE){
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
if (!strcmp(search, kv->key))
return kv->val;
}
}
}
return NULL;
}
u8 getHexSingle(const char c) {
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
}
u8 *getHex(const char *in){
u32 len = strlen(in), count = 0;
u8 *out = calloc(len / 2, sizeof(u8));
for (u32 i = 0; i < len; i += 2){
out[count++] = (u8)(getHexSingle(in[i]) << 4) | (getHexSingle(in[i + 1]));
}
return out;
}
bool save_sign(const char *keypath, const char *savepath){ bool save_sign(const char *keypath, const char *savepath){
LIST_INIT(inilist); u8 *key = GetKey(keypath, "save_mac_key");
char *key;
u8 *hex;
bool success = false;
if (!ini_parse(&inilist, keypath, false)){ if (key == NULL){
gfx_errDisplay("save_sign", ERR_INI_PARSE_FAIL, 1); return false;
goto out_free;
} }
if ((key = getKey("save_mac_key", &inilist)) == NULL){ if (!save_commit(savepath, key))
gfx_errDisplay("save_sign", ERR_INI_PARSE_FAIL, 2); return false;
goto out_free;
}
hex = getHex(key); return true;
if (!save_commit(savepath, hex))
goto out_free;
success = true;
out_free:;
list_empty(&inilist);
return success;
} }

View File

@@ -23,7 +23,7 @@ void gfx_clearscreen(){
gfx_boxGrey(0, 703, 1279, 719, 0xFF); gfx_boxGrey(0, 703, 1279, 719, 0xFF);
gfx_boxGrey(0, 0, 1279, 15, 0xFF); gfx_boxGrey(0, 0, 1279, 15, 0xFF);
gfx_con_setpos(0, 0); gfx_con_setpos(0, 0);
gfx_printf("Tegraexplorer v2.0.2 | Battery: %3d%%\n", battery >> 8); gfx_printf("Tegraexplorer v2.0.4 | Battery: %3d%%\n", battery >> 8);
RESETCOLOR; RESETCOLOR;
} }

View File

@@ -18,6 +18,9 @@ extern bool sd_inited;
#pragma GCC optimize ("O2") #pragma GCC optimize ("O2")
void _printentry(menu_entry *entry, bool highlighted, bool refresh, const char *path){ void _printentry(menu_entry *entry, bool highlighted, bool refresh, const char *path){
if (entry->isHide)
return;
u32 color = (entry->isMenu) ? entry->storage : ((entry->isDir) ? COLOR_WHITE : COLOR_VIOLET); u32 color = (entry->isMenu) ? entry->storage : ((entry->isDir) ? COLOR_WHITE : COLOR_VIOLET);
SWAPALLCOLOR((highlighted) ? COLOR_DEFAULT : color, (highlighted) ? color : COLOR_DEFAULT); SWAPALLCOLOR((highlighted) ? COLOR_DEFAULT : color, (highlighted) ? color : COLOR_DEFAULT);
@@ -62,7 +65,7 @@ void _printentry(menu_entry *entry, bool highlighted, bool refresh, const char *
bool disableB = false; bool disableB = false;
int menu_make(menu_entry *entries, int amount, const char *toptext){ int menu_make(menu_entry *entries, int amount, const char *toptext){
int currentpos = 0, offset = 0, delay = 300, minscreen = 0, maxscreen = 39, calculatedamount = 0; int currentpos = 0, offset = 0, delay = 300, minscreen = 0, calculatedamount = 0, cursub = 0, temp;
u32 scrolltimer, timer, sideY; u32 scrolltimer, timer, sideY;
bool refresh = true; bool refresh = true;
Inputs *input = hidRead(); Inputs *input = hidRead();
@@ -95,56 +98,53 @@ int menu_make(menu_entry *entries, int amount, const char *toptext){
gfx_sideprintf("\n\n\n"); gfx_sideprintf("\n\n\n");
} }
gfx_drawScrollBar(minscreen, maxscreen, amount); for (;;){
while (!(input->a)){
gfx_con_setpos(0, 48); gfx_con_setpos(0, 48);
timer = get_tmr_ms(); timer = get_tmr_ms();
if (!currentpos){ if (!currentpos)
while (currentpos < amount && entries[currentpos].property & (ISSKIP | ISHIDE)) cursub = 1;
currentpos++; else if (currentpos == amount - 1)
} cursub = -1;
if (currentpos == amount - 1){ else
while (currentpos >= 1 && entries[currentpos].property & (ISSKIP | ISHIDE)) cursub = 0;
currentpos--;
}
if (currentpos > maxscreen){ while (entries[currentpos].property & (ISSKIP | ISHIDE))
offset += currentpos - maxscreen; currentpos += cursub;
minscreen += currentpos - maxscreen;
maxscreen += currentpos - maxscreen;
if (currentpos > (minscreen + SCREENMAXOFFSET)){
offset += currentpos - (minscreen + SCREENMAXOFFSET);
minscreen += currentpos - (minscreen + SCREENMAXOFFSET);
refresh = true; refresh = true;
} }
else if (currentpos < minscreen){
if (currentpos < minscreen){
offset -= minscreen - currentpos; offset -= minscreen - currentpos;
maxscreen -= minscreen - currentpos;
minscreen -= minscreen - currentpos; minscreen -= minscreen - currentpos;
refresh = true; refresh = true;
} }
if (refresh || currentfolder == NULL || !calculatedamount){ if (refresh || currentfolder == NULL || !calculatedamount){
for (int i = 0 + offset; i < amount && i < 40 + offset; i++) for (int i = 0 + offset; i < amount && i < SCREENMAXOFFSET + 1 + offset; i++)
if (!(entries[i].isHide)) _printentry(&entries[i], (i == currentpos), refresh, toptext);
_printentry(&entries[i], (i == currentpos), refresh, toptext);
} }
else { else {
if (currentpos - minscreen > 0){ temp = (currentpos - minscreen > 0) ? 0 : 16;
gfx_con_setpos(0, 32 + (currentpos - minscreen) * 16); gfx_con_setpos(0, 32 + temp + (currentpos - minscreen) * 16);
if (!temp)
_printentry(&entries[currentpos - 1], false, false, toptext); _printentry(&entries[currentpos - 1], false, false, toptext);
}
else
gfx_con_setpos(0, 48 + (currentpos - minscreen) * 16);
_printentry(&entries[currentpos], true, false, toptext); _printentry(&entries[currentpos], true, false, toptext);
if (currentpos < amount - 1 && currentpos < maxscreen) if (currentpos < MIN(amount - 1, minscreen + SCREENMAXOFFSET))
_printentry(&entries[currentpos + 1], false, false, toptext); _printentry(&entries[currentpos + 1], false, false, toptext);
} }
RESETCOLOR; RESETCOLOR;
sideY = gfx_sideGetY(); sideY = gfx_sideGetY();
if (!(entries[currentpos].isMenu)){ if (!(entries[currentpos].isMenu)){
gfx_sideprintf("Current selection:\n"); gfx_sideprintf("Current selection:\n");
@@ -158,12 +158,14 @@ int menu_make(menu_entry *entries, int amount, const char *toptext){
gfx_boxGrey(800, sideY, 1279, sideY + 48, 0x1B); gfx_boxGrey(800, sideY, 1279, sideY + 48, 0x1B);
gfx_con_setpos(0, 703); gfx_con_setpos(0, 703);
SWAPCOLOR(COLOR_DEFAULT); SWAPALLCOLOR(COLOR_DEFAULT, COLOR_WHITE);
SWAPBGCOLOR(COLOR_WHITE);
gfx_printf("Time taken for screen draw: %dms ", get_tmr_ms() - timer); gfx_printf("Time taken for screen draw: %dms ", get_tmr_ms() - timer);
if (refresh) if (refresh)
gfx_drawScrollBar(minscreen, maxscreen, amount); gfx_drawScrollBar(minscreen, minscreen + SCREENMAXOFFSET, amount);
refresh = false;
while (hidRead()->buttons & (KEY_B | KEY_A)); while (hidRead()->buttons & (KEY_B | KEY_A));
@@ -182,14 +184,12 @@ int menu_make(menu_entry *entries, int amount, const char *toptext){
continue; continue;
} }
if (input->buttons & (KEY_RDOWN | KEY_RUP)){ if (input->buttons & (KEY_RDOWN | KEY_RUP)){
delay = 1; delay = 1;
input->Lup = input->Rup; input->Lup = input->Rup;
input->Ldown = input->Rdown; input->Ldown = input->Rdown;
} }
if (delay < 300){ if (delay < 300){
if (scrolltimer + delay < get_tmr_ms()){ if (scrolltimer + delay < get_tmr_ms()){
break; break;
@@ -200,27 +200,32 @@ int menu_make(menu_entry *entries, int amount, const char *toptext){
} }
} }
if (delay > 46)
delay -= 45;
if (input->Lup && currentpos >= 1){ if (input->a){
currentpos--; break;
while(entries[currentpos].property & (ISSKIP | ISHIDE) && currentpos >= 1)
currentpos--;
} }
if (input->b && !disableB){
else if (input->Ldown && currentpos < amount - 1){
currentpos++;
while(entries[currentpos].property & (ISSKIP | ISHIDE) && currentpos < amount - 1)
currentpos++;
}
else if (input->b && !disableB){
currentpos = 0; currentpos = 0;
break; break;
} }
refresh = false;
if (delay > 46)
delay -= 45;
if (input->Lup && currentpos > 0)
cursub = -1;
else if (input->Ldown && currentpos < amount - 1)
cursub = 1;
else
cursub = 0;
if (cursub){
do {
currentpos += cursub;
} while (currentpos < amount - 1 && currentpos > 0 && entries[currentpos].property & (ISSKIP | ISHIDE));
}
} }
minerva_periodic_training(); minerva_periodic_training();

View File

@@ -1,4 +1,6 @@
#pragma once #pragma once
#include "../common/types.h" #include "../common/types.h"
#define SCREENMAXOFFSET 39
int menu_make(menu_entry *entries, int amount, const char *toptext); int menu_make(menu_entry *entries, int amount, const char *toptext);

View File

@@ -60,7 +60,10 @@ void MainMenu_Tools(){
displaygpio(); displaygpio();
break; break;
case TOOLS_DUMPFIRMWARE: case TOOLS_DUMPFIRMWARE:
dumpfirmware(SYSMMC); res = menu_make(fwDump_typeMenu, 4, "-- Fw Type --");
if (res >= 2)
dumpfirmware(SYSMMC, (res == 2));
break; break;
} }
} }

View File

@@ -0,0 +1,281 @@
#include "args.h"
#include "parser.h"
#include "scriptCtx.h"
#include "lexer.h"
#include "functions.h"
#include "list.h"
#include <string.h>
#include "../../mem/heap.h"
#include "../utils/utils.h"
// do not include first openToken!
int distanceBetweenTokens(lexarToken_t* tokens, u32 len, int openToken, int closeToken) {
int i = 0;
int layer = 0;
for (; i < len; i++) {
if (tokens[i].token == openToken)
layer++;
else if (tokens[i].token == closeToken) {
if (layer == 0)
return i;
layer--;
}
}
return -1;
}
dictValue_t getVarFromToken(scriptCtx_t* ctx, lexarToken_t* tokens, int* index, u32 maxLen) {
dictValue_t val = { 0 };
val.free = 0;
int i = *index;
u8 not = 0;
if (tokens[i].token == Not) {
not = 1;
i++;
}
if (tokens[i].token == Not)
return ErrDictValue(ERRDOUBLENOT);
if (tokens[i].token == Variable) {
char* funcName = tokens[i].text;
if (tokens[i + 1].token == LBracket) {
i += 2;
int argCount = distanceBetweenTokens(&tokens[i], maxLen - 2, LBracket, RBracket);
if (argCount < 0)
return ErrDictValue(ERRSYNTAX);
ctx->args_loc.tokens = &tokens[i];
ctx->args_loc.stored = argCount;
val = executeFunction(ctx, funcName);
i += argCount;
}
else if (tokens[i + 1].token == LSBracket) {
dictValue_t* var = varVectorFind(&ctx->vars, tokens[i].text);
i += 2;
if (var == NULL)
return ErrDictValue(ERRNOVAR);
int argCount = distanceBetweenTokens(&tokens[i], maxLen - 2, LSBracket, RSBracket);
if (argCount < 0)
return ErrDictValue(ERRSYNTAX);
dictValue_t index = solveEquation(ctx, &tokens[i], argCount);
i += argCount;
if (index.varType != IntType)
return ErrDictValue(ERRINVALIDTYPE);
if (var->arrayLen <= index.integer || index.integer < 0)
return ErrDictValue(ERRSYNTAX);
switch (var->varType) {
case StringArrayType:
val = StrDictValue(var->stringArray[index.integer]);
break;
case IntArrayType:
val = IntDictValue(var->integerArray[index.integer]);
break;
case ByteArrayType:
val = IntDictValue(var->byteArray[index.integer]);
break;
default:
return ErrDictValue(ERRINVALIDTYPE);
}
}
else {
dictValue_t* var = varVectorFind(&ctx->vars, tokens[i].text);
if (var != NULL) {
if (var->type == IntType) {
val = IntDictValue(var->integer);
}
else if (var->type == StringType){
val = StrDictValue(util_cpyStr(var->string));
val.free = 1;
}
else {
val = *var;
val.free = 0;
}
}
else
return ErrDictValue(ERRNOVAR);
}
}
else if (tokens[i].token == LSBracket) {
i++;
int argCount = distanceBetweenTokens(&tokens[i], maxLen - 1, LSBracket, RSBracket);
if (argCount <= 0)
return ErrDictValue(-5);
varVector_t arrayVars = extractVars(ctx, &tokens[i], argCount);
int type = arrayVars.vars[0].value.varType;
if (!(type == StringType || type == IntType))
return ErrDictValue(ERRINVALIDTYPE);
val.type = (type + 2) | FREEINDICT;
val.arrayLen = arrayVars.stored;
val.integerArray = calloc(val.arrayLen, (type == IntType) ? sizeof(int) : sizeof(char*));
val.free = (type == StringType) ? 1 : 0;
for (int i = 0; i < arrayVars.stored; i++) {
if (arrayVars.vars[i].value.varType != type)
return ErrDictValue(ERRINVALIDTYPE); // Free-ing issue!!
if (type == StringType) {
val.stringArray[i] = util_cpyStr(arrayVars.vars[i].value.string);
}
else {
val.integerArray[i] = arrayVars.vars[i].value.integer;
}
}
i += argCount;
varVectorFree(&arrayVars);
}
else if (tokens[i].token == LBracket) {
i += 1;
int argCount = distanceBetweenTokens(&tokens[i], maxLen - 1, LBracket, RBracket);
if (argCount < 0)
return ErrDictValue(ERRSYNTAX);
val = solveEquation(ctx, &tokens[i], argCount);
i += argCount;
}
else if (tokens[i].token == IntLit) {
val = IntDictValue(tokens[i].val);
}
else if (tokens[i].token == StrLit) {
val = StrDictValue(tokens[i].text); // Do we need to copy the string here? if we set var.free = 0, it shouldn't matter
val.free = 0;
}
else {
// ERR
return ErrDictValue(ERRNOVAR);
}
if (not) {
if (val.type == IntType)
val.integer = !val.integer;
else
return ErrDictValue(ERRINVALIDTYPE);
}
*index = i;
return val;
}
int matchTypes(dictValue_t d1, dictValue_t d2, int type) {
return (d1.varType == d2.varType && d1.varType == type);
}
#define ELIFT(token) else if (localOpToken == token)
dictValue_t solveEquation(scriptCtx_t *ctx, lexarToken_t* tokens, u32 len) {
dictValue_t res = { 0 };
u16 lastToken = 0;
for (int i = 0; i < len; i++) {
if (tokens[i].token == Variable || tokens[i].token == StrLit || tokens[i].token == IntLit || tokens[i].token == Not || tokens[i].token == LBracket || tokens[i].token == LSBracket){
dictValue_t val = getVarFromToken(ctx, tokens, &i, len - i);
if (val.type == ErrType)
return val;
if (lastToken) {
u16 localOpToken = lastToken; // do we need local op token?
lastToken = 0;
if (matchTypes(res, val, IntType)) {
if (localOpToken == Plus)
res.integer += val.integer;
ELIFT(Minus)
res.integer -= val.integer;
ELIFT(Multiply)
res.integer *= val.integer;
ELIFT(Division)
res.integer /= val.integer;
ELIFT(Mod)
res.integer %= val.integer;
ELIFT(Smaller)
res.integer = res.integer < val.integer;
ELIFT(SmallerEqual)
res.integer = res.integer <= val.integer;
ELIFT(Bigger)
res.integer = res.integer > val.integer;
ELIFT(BiggerEqual)
res.integer = res.integer >= val.integer;
ELIFT(EqualEqual)
res.integer = res.integer == val.integer;
ELIFT(NotEqual)
res.integer = res.integer != val.integer;
ELIFT(LogicAND) {
res.integer = res.integer && val.integer;
if (!res.integer)
break;
}
ELIFT(LogicOR) {
res.integer = res.integer || val.integer;
if (res.integer)
break;
}
ELIFT(AND)
res.integer = res.integer & val.integer;
ELIFT(OR)
res.integer = res.integer | val.integer;
else
return ErrDictValue(ERRBADOPERATOR);
}
else if (matchTypes(res, val, StringType)) {
if (localOpToken == Plus) {
char* buff = calloc(strlen(res.string) + strlen(val.string) + 1, 1);
strcpy(buff, res.string);
strcat(buff, val.string);
if (res.free)
free(res.string);
if (val.free)
free(val.string);
res.string = buff;
}
ELIFT(EqualEqual) {
res.type = IntType;
int compRes = !strcmp(res.string, val.string);
if (res.free)
free(res.string);
if (val.free)
free(val.string);
res.integer = compRes;
res.free = 0;
}
ELIFT(Minus) {
if (!strcmp(res.string + strlen(res.string) - strlen(val.string), val.string)) {
*(res.string + strlen(res.string) - strlen(val.string)) = 0;
}
free(val.string);
}
else
return ErrDictValue(ERRBADOPERATOR);
}
else
return ErrDictValue(ERRBADOPERATOR);
}
else {
res = val;
}
}
else if (tokens[i].token >= Plus && tokens[i].token <= OR) {
lastToken = tokens[i].token;
}
}
return res;
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include "types.h"
char* createStrOutTextHolder(textHolder_t t);
dictValue_t solveEquation(scriptCtx_t* ctx, lexarToken_t* tokens, u32 len);
int distanceBetweenTokens(lexarToken_t* tokens, u32 len, int openToken, int closeToken);

View File

@@ -1,608 +1,177 @@
#include <string.h>
#include <stdlib.h>
#include "../../mem/heap.h"
#include "../gfx/gfxutils.h"
#include "../emmc/emmc.h"
#include "../../utils/types.h"
#include "../../libs/fatfs/ff.h"
#include "../../utils/sprintf.h"
#include "../../hid/hid.h"
#include "../../gfx/gfx.h"
#include "../../utils/util.h"
#include "../../storage/emummc.h"
#include "parser.h"
#include "../common/common.h"
#include "../fs/fsactions.h"
#include "variables.h"
#include "../utils/utils.h"
#include "functions.h" #include "functions.h"
#include "../fs/fsutils.h" #include "list.h"
#include "../../utils/sprintf.h" #include "args.h"
#include "../fs/fsactions.h" #include "parser.h"
#include "../emmc/emmcoperations.h" #include "lexer.h"
#include "../emmc/emmcmenu.h" #include "types.h"
#include "scriptCtx.h"
#include "../../gfx/gfx.h"
#include "../../mem/heap.h"
#include <string.h>
#include "../../hid/hid.h"
extern FIL scriptin; dictValue_t funcPrint(scriptCtx_t* ctx, varVector_t* args) {
extern char **argv; for (int i = 0; i < args->stored; i++) {
extern u32 argc; switch (args->vars[i].value.varType) {
extern int forceExit; case IntType:
extern short currentlyMounted; gfx_printf("%d", args->vars[i].value.integer);
break;
case StringType:
gfx_printf("%s", args->vars[i].value.string);
break;
}
}
int parseIntInput(char *in, int *out){ return NullDictValue();
if (in[0] == '@'){
if (str_int_find(in, out))
return -1;
}
else
*out = atoi(in);
return 0;
}
/*
int parseJmpInput(char *in, u64 *out){
if (in[0] == '?'){
if (str_jmp_find(in, out))
return -1;
else
return 0;
}
else
return -1;
}
*/
int parseStringInput(char *in, char **out){
if (in[0] == '$'){
if (str_str_find(in, out))
return -1;
else
return 0;
}
else{
*out = in;
return 0;
}
} }
#pragma GCC push_options dictValue_t funcPrintln(scriptCtx_t* ctx, varVector_t* args) {
#pragma GCC optimize ("Os") funcPrint(ctx, args);
gfx_printf("\n");
u32 currentcolor = COLOR_WHITE; return NullDictValue();
int part_printf(){
SWAPCOLOR(currentcolor);
for (int i = 0; i < argc; i++){
if (argv[i][0] == '@'){
int toprintint;
if (parseIntInput(argv[i], &toprintint))
return INFUNC_FAIL;
gfx_printf("%d", toprintint);
}
else {
char *toprintstring;
if (parseStringInput(argv[i], &toprintstring))
return INFUNC_FAIL;
gfx_printf(toprintstring);
}
}
gfx_printf("\n");
return 0;
} }
int part_print_int(){ dictValue_t funcIf(scriptCtx_t* ctx, varVector_t* args) {
int toprint; if (args->vars[0].value.varType == IntType) {
if (parseIntInput(argv[0], &toprint)) setCurIndentInstruction(ctx, (args->vars[0].value.integer == 0), -1);
return INFUNC_FAIL; return NullDictValue();
}
SWAPCOLOR(currentcolor); return ErrDictValue(ERRINVALIDTYPE);
gfx_printf("%s: %d\n", argv[0], toprint);
return 0;
} }
int part_Wait(){ dictValue_t scriptElse(scriptCtx_t* ctx, varVector_t* args) {
int arg; indentInstructor_t curInstruction = getCurIndentInstruction(ctx);
u32 begintime; setCurIndentInstruction(ctx, !curInstruction.skip, -1);
SWAPCOLOR(currentcolor); return NullDictValue();
if (parseIntInput(argv[0], &arg))
return INFUNC_FAIL;
begintime = get_tmr_s();
while (begintime + arg > get_tmr_s()){
gfx_printf("\r<Wait %d seconds> ", (begintime + arg) - get_tmr_s());
}
gfx_printf("\r \r");
return 0;
} }
int part_Check(){ dictValue_t scriptWhile(scriptCtx_t* ctx, varVector_t* args) {
int left, right; if (args->vars[0].value.varType == IntType) {
if (parseIntInput(argv[0], &left)) setCurIndentInstruction(ctx, (args->vars[0].value.integer == 0), ctx->lastTokenPos);
return INFUNC_FAIL; return NullDictValue();
if (parseIntInput(argv[2], &right)) }
return INFUNC_FAIL;
if (!strcmp(argv[1], "==")) return ErrDictValue(ERRINVALIDTYPE);
return (left == right);
else if (!strcmp(argv[1], "!="))
return (left != right);
else if (!strcmp(argv[1], ">="))
return (left >= right);
else if (!strcmp(argv[1], "<="))
return (left <= right);
else if (!strcmp(argv[1], ">"))
return (left > right);
else if (!strcmp(argv[1], "<"))
return (left < right);
else
return INFUNC_FAIL;
} }
int part_if(){ dictValue_t scriptLen(scriptCtx_t* ctx, varVector_t* args) {
int condition; if (args->vars[0].value.varType >= IntArrayType && args->vars[0].value.varType <= ByteArrayType)
if (parseIntInput(argv[0], &condition)) return IntDictValue(args->vars[0].value.arrayLen);
return INFUNC_FAIL; else if (args->vars[0].value.varType == StringType) {
if (args->vars[0].value.string != NULL)
return IntDictValue(strlen(args->vars[0].value.string));
}
getfollowingchar('{'); return ErrDictValue(ERRINVALIDTYPE);
if (!condition)
skipbrackets();
return 0;
/*
if (condition)
return 0;
else {
skipbrackets();
return 0;
}
*/
} }
int part_if_args(){ dictValue_t scriptMakeByteArray(scriptCtx_t* ctx, varVector_t* args) {
int condition; if (args->vars[0].value.varType == IntArrayType) {
if ((condition = part_Check()) < 0) u8* buff = calloc(args->vars[0].value.arrayLen, 1);
return INFUNC_FAIL; for (int i = 0; i < args->vars[0].value.arrayLen; i++) {
buff[i] = (u8)(args->vars[0].value.integerArray[i] & 0xFF);
}
getfollowingchar('{'); return DictValueCreate(ByteArrayType | FREEINDICT, args->vars[0].value.arrayLen, buff);
}
if (!condition) return ErrDictValue(ERRINVALIDTYPE);
skipbrackets();
return 0;
} }
int part_Math(){ dictValue_t scriptWait(scriptCtx_t*ctx, varVector_t* args){
int left, right; Inputs* input = hidWait();
if (parseIntInput(argv[0], &left))
return INFUNC_FAIL;
if (parseIntInput(argv[2], &right))
return INFUNC_FAIL;
switch (argv[1][0]){ return IntDictValue(input->buttons);
case '+':
return left + right;
case '-':
return left - right;
case '*':
return left * right;
case '/':
return left / right;
}
return INFUNC_FAIL;
} }
int part_SetInt(){ dictValue_t scriptSetPixel(scriptCtx_t *ctx, varVector_t* args){
int out; int pixelArgs[5] = {0};
parseIntInput(argv[0], &out);
return out; for (int i = 0; i < args->stored; i++){
if (args->vars[i].value.varType != IntType)
return ErrDictValue(ERRINVALIDTYPE);
pixelArgs[i] = args->vars[i].value.integer;
}
u32 color = 0xFF000000 | ((pixelArgs[2] & 0xFF) << 16) | ((pixelArgs[3] & 0xFF) << 8) | ((pixelArgs[4] & 0xFF));
gfx_setPixel(pixelArgs[0], pixelArgs[1], color);
return NullDictValue();
} }
int part_SetString(){ const static str_fnc_struct functions[] = {
char *arg0; {"print", funcPrint, {0x40}},
if (parseStringInput(argv[0], &arg0)) {"println", funcPrintln, {0x40}},
return INFUNC_FAIL; {"if", funcIf, {1}},
if (argv[1][0] != '$') {"while", scriptWhile, {1}},
return INFUNC_FAIL; {"else", scriptElse, {0}},
{"len", scriptLen, {1}},
str_str_add(argv[1], arg0); {"byte", scriptMakeByteArray, {1}},
return 0; {"wait", scriptWait, {0}},
} {"setPixel", scriptSetPixel, {5}},
{NULL, NULL, {0}},
int part_SetStringIndex(){
int index;
char *out;
if (parseIntInput(argv[0], &index))
return INFUNC_FAIL;
if (argv[1][0] != '$')
return INFUNC_FAIL;
if (str_str_index(index, &out))
return INFUNC_FAIL;
str_str_add(argv[1], out);
return 0;
}
int part_goto(){
int target = 0;
if (parseIntInput(argv[0], &target))
return INFUNC_FAIL;
str_int_add("@RETURN", (int)f_tell(&scriptin));
f_lseek(&scriptin, target);
return 0;
}
int part_invert(){
int arg;
if (parseIntInput(argv[0], &arg))
return INFUNC_FAIL;
return (arg) ? 0 : 1;
}
int part_fs_exists(){
char *path;
if (parseStringInput(argv[0], &path))
return INFUNC_FAIL;
return fsutil_checkfile(path);
}
int part_ConnectMMC(){
char *arg;
parseStringInput(argv[0], &arg);
if (!strcmp(arg, "SYSMMC"))
connect_mmc(SYSMMC);
else if (!strcmp(arg, "EMUMMC"))
connect_mmc(EMUMMC);
else
return INFUNC_FAIL;
return 0;
}
int part_MountMMC(){
char *arg;
parseStringInput(argv[0], &arg);
return mount_mmc(arg, 2);
}
int part_Pause(){
Inputs *input = hidWaitMask(KEY_A | KEY_B | KEY_X | KEY_Y | KEY_POW | KEY_VOLP | KEY_VOLM | KEY_LUP | KEY_LDOWN | KEY_LLEFT | KEY_LRIGHT);
str_int_add("@BTN_POWER", input->pow);
str_int_add("@BTN_VOL+", input->volp);
str_int_add("@BTN_VOL-", input->volm);
str_int_add("@BTN_A", input->a);
str_int_add("@BTN_B", input->b);
str_int_add("@BTN_X", input->x);
str_int_add("@BTN_Y", input->y);
str_int_add("@BTN_UP", input->Lup);
str_int_add("@BTN_DOWN", input->Ldown);
str_int_add("@BTN_LEFT", input->Lleft);
str_int_add("@BTN_RIGHT", input->Lright);
return input->buttons;
}
int part_addstrings(){
char *combined, *left, *middle;
if (parseStringInput(argv[0], &left))
return INFUNC_FAIL;
if (parseStringInput(argv[1], &middle))
return INFUNC_FAIL;
if (argv[2][0] != '$')
return INFUNC_FAIL;
combined = calloc(strlen(left) + strlen(middle) + 1, sizeof(char));
sprintf(combined, "%s%s", left, middle);
str_str_add(argv[2], combined);
free(combined);
return 0;
}
int part_setColor(){
char *arg;
if (parseStringInput(argv[0], &arg))
return INFUNC_FAIL;
if (!strcmp(arg, "RED"))
currentcolor = COLOR_RED;
else if (!strcmp(arg, "ORANGE"))
currentcolor = COLOR_ORANGE;
else if (!strcmp(arg, "YELLOW"))
currentcolor = COLOR_YELLOW;
else if (!strcmp(arg, "GREEN"))
currentcolor = COLOR_GREEN;
else if (!strcmp(arg, "BLUE"))
currentcolor = COLOR_BLUE;
else if (!strcmp(arg, "VIOLET"))
currentcolor = COLOR_VIOLET;
else if (!strcmp(arg, "WHITE"))
currentcolor = COLOR_WHITE;
else
return INFUNC_FAIL;
return 0;
}
int part_Exit(){
forceExit = true;
return 0;
}
int part_fs_Move(){
char *left, *right;
if (parseStringInput(argv[0], &left))
return INFUNC_FAIL;
if (parseStringInput(argv[1], &right))
return INFUNC_FAIL;
int res;
res = f_rename(left, right);
if (res)
res = f_rename(left, right);
return res;
}
int part_fs_Delete(){
char *arg;
if (parseStringInput(argv[0], &arg))
return INFUNC_FAIL;
int res;
res = f_unlink(arg);
if (res)
res = f_unlink(arg);
return res;
}
int part_fs_DeleteRecursive(){
char *arg;
if (parseStringInput(argv[0], &arg))
return INFUNC_FAIL;
return fsact_del_recursive(arg);
}
int part_fs_Copy(){
char *left, *right;
if (parseStringInput(argv[0], &left))
return INFUNC_FAIL;
if (parseStringInput(argv[1], &right))
return INFUNC_FAIL;
return fsact_copy(left, right, COPY_MODE_PRINT);
}
int part_fs_CopyRecursive(){
char *left, *right;
if (parseStringInput(argv[0], &left))
return INFUNC_FAIL;
if (parseStringInput(argv[1], &right))
return INFUNC_FAIL;
return fsact_copy_recursive(left, right);
}
int part_fs_MakeDir(){
char *arg;
if (parseStringInput(argv[0], &arg))
return INFUNC_FAIL;
int res;
res = f_mkdir(arg);
if (res)
res = f_mkdir(arg);
return res;
}
DIR dir;
FILINFO fno;
int isdirvalid = false;
int part_fs_OpenDir(){
char *path;
if (parseStringInput(argv[0], &path))
return INFUNC_FAIL;
if (f_opendir(&dir, path))
return INFUNC_FAIL;
isdirvalid = true;
str_int_add("@ISDIRVALID", isdirvalid);
return 0;
}
int part_fs_CloseDir(){
if (!isdirvalid)
return 0;
f_closedir(&dir);
isdirvalid = false;
str_int_add("@ISDIRVALID", isdirvalid);
return 0;
}
int part_fs_ReadDir(){
if (!isdirvalid)
return INFUNC_FAIL;
if (!f_readdir(&dir, &fno) && fno.fname[0]){
str_str_add("$FILENAME", fno.fname);
str_int_add("@ISDIR", (fno.fattrib & AM_DIR) ? 1 : 0);
}
else {
part_fs_CloseDir();
}
return 0;
}
int part_setPrintPos(){
int left, right;
if (parseIntInput(argv[0], &left))
return INFUNC_FAIL;
if (parseIntInput(argv[1], &right))
return INFUNC_FAIL;
if (left > 78)
return INFUNC_FAIL;
if (right > 42)
return INFUNC_FAIL;
gfx_con_setpos(left * 16, right * 16);
return 0;
}
int part_stringcompare(){
char *left, *right;
if (parseStringInput(argv[0], &left))
return INFUNC_FAIL;
if (parseStringInput(argv[1], &right))
return INFUNC_FAIL;
return (strcmp(left, right)) ? 0 : 1;
}
int part_fs_combinePath(){
char *combined, *left, *middle;
if (parseStringInput(argv[0], &left))
return INFUNC_FAIL;
if (parseStringInput(argv[1], &middle))
return INFUNC_FAIL;
if (argv[2][0] != '$')
return INFUNC_FAIL;
combined = fsutil_getnextloc(left, middle);
str_str_add(argv[2], combined);
free(combined);
return 0;
}
int part_mmc_dumpPart(){
char *left, *right;
if (parseStringInput(argv[0], &left))
return INFUNC_FAIL;
if (parseStringInput(argv[1], &right))
return INFUNC_FAIL;
if (!strcmp(left, "BOOT")){
return emmcDumpBoot(right);
}
else {
return emmcDumpSpecific(left, right);
}
}
int part_mmc_restorePart(){
char *path;
if (parseStringInput(argv[0], &path))
return INFUNC_FAIL;
if (currentlyMounted < 0)
return INFUNC_FAIL;
return mmcFlashFile(path, currentlyMounted, false);
}
int part_fs_extractBisFile(){
char *path, *outfolder;
if (parseStringInput(argv[0], &path))
return INFUNC_FAIL;
if (parseStringInput(argv[1], &outfolder))
return INFUNC_FAIL;
return extract_bis_file(path, outfolder);
}
int part_clearscreen(){
gfx_clearscreen();
return 0;
}
int part_getPos(){
return (int)f_tell(&scriptin);
}
str_fnc_struct functions[] = {
{"printf", part_printf, 255},
{"printInt", part_print_int, 1},
{"setPrintPos", part_setPrintPos, 2},
{"clearscreen", part_clearscreen, 0},
{"if", part_if, 1},
{"if", part_if_args, 3}, // function overloading
{"math", part_Math, 3},
{"check", part_Check, 3},
{"setInt", part_SetInt, 1},
{"goto", part_goto, 1},
{"setString", part_SetString, 2},
{"setStringIndex", part_SetStringIndex, 2},
{"setColor", part_setColor, 1},
{"combineStrings", part_addstrings, 3},
{"compareStrings", part_stringcompare, 2},
{"invert", part_invert, 1},
{"fs_exists", part_fs_exists, 1},
{"fs_move", part_fs_Move, 2},
{"fs_mkdir", part_fs_MakeDir, 1},
{"fs_del", part_fs_Delete, 1},
{"fs_delRecursive", part_fs_DeleteRecursive, 1},
{"fs_copy", part_fs_Copy, 2},
{"fs_copyRecursive", part_fs_CopyRecursive, 2},
{"fs_openDir", part_fs_OpenDir, 1},
{"fs_closeDir", part_fs_CloseDir, 0},
{"fs_readDir", part_fs_ReadDir, 0},
{"fs_combinePath", part_fs_combinePath, 3},
{"fs_extractBisFile", part_fs_extractBisFile, 2},
{"mmc_connect", part_ConnectMMC, 1},
{"mmc_mount", part_MountMMC, 1},
{"mmc_dumpPart", part_mmc_dumpPart, 2},
{"mmc_restorePart", part_mmc_restorePart, 1},
{"getPosition", part_getPos, 0},
{"pause", part_Pause, 0},
{"wait", part_Wait, 1},
{"exit", part_Exit, 0},
{NULL, NULL, 0}
}; };
#pragma GCC pop_options varVector_t extractVars(scriptCtx_t* ctx, lexarToken_t* tokens, u32 len) {
varVector_t args = varVectorInit(4);
int lastLoc = 0;
for (int i = 0; i < len; i++) {
if (tokens[i].token == LSBracket) {
int distance = distanceBetweenTokens(&tokens[i + 1], len - i - 1, LSBracket, RSBracket);
i += distance + 1;
}
if (tokens[i].token == Seperator) {
dictValue_t res = solveEquation(ctx, &tokens[lastLoc], i - lastLoc);
lastLoc = i + 1;
varVectorAdd(&args, DictCreate(NULL, res));
}
int run_function(char *func_name, int *out){ if (i + 1 >= len) {
for (u32 i = 0; functions[i].key != NULL; i++){ dictValue_t res = solveEquation(ctx, &tokens[lastLoc], i + 1 - lastLoc);
if (!strcmp(functions[i].key, func_name)){ varVectorAdd(&args, DictCreate(NULL, res));
if (argc != functions[i].arg_count && functions[i].arg_count != 255) }
continue; }
*out = functions[i].value(); return args;
return (*out == INFUNC_FAIL) ? -1 : 0; }
}
} dictValue_t executeFunction(scriptCtx_t* ctx, char* func_name) {
return -2; int argCount = 0;
varVector_t args = { 0 };
if (ctx->args_loc.stored > 0) {
args = extractVars(ctx, ctx->args_loc.tokens, ctx->args_loc.stored);
for (int i = 0; i < args.stored; i++) {
if (args.vars[i].value.varType == ErrType)
return args.vars[i].value;
}
argCount = args.stored;
}
for (u32 i = 0; functions[i].key != NULL; i++) {
if (!strcmp(functions[i].key, func_name)) {
if (argCount != functions[i].argCount && !functions[i].varArgs)
continue;
dictValue_t val = functions[i].value(ctx, &args);
// free args
varVectorFree(&args);
return val;
}
}
dictValue_t* var = varVectorFind(&ctx->vars, func_name);
if (var != NULL) {
if (var->type == JumpType) {
setCurIndentInstruction(ctx, 0, ctx->curPos);
ctx->curPos = var->integer - 1;
ctx->lastToken.token = Invalid;
return NullDictValue();
}
}
return ErrDictValue(ERRNOFUNC);
} }

View File

@@ -1,13 +1,10 @@
#pragma once #pragma once
#include "../../utils/types.h" #include "types.h"
typedef void (*func_void_ptr)(); #define BIT(n) (1U << n)
typedef int (*func_int_ptr)();
typedef struct { #define VARARGS(x) {x, 1, 0}
char *key; #define OPERATORARGS(x) {x, 0, 1}
func_int_ptr value;
u8 arg_count;
} str_fnc_struct;
int run_function(char *func_name, int *out); dictValue_t executeFunction(scriptCtx_t* ctx, char* func_name);
varVector_t extractVars(scriptCtx_t* ctx, lexarToken_t* tokens, u32 len);

View File

@@ -0,0 +1,195 @@
#include "lexer.h"
#include "parser.h"
#include "args.h"
#include "../utils/utils.h"
#include "../../mem/heap.h"
#include <string.h>
static inline int isValidWord(char c) {
char r = c | 0x20;
return (r >= 'a' && r <= 'z');
}
static inline int isValidVar(char c) {
char r = c | 0x20;
return ((r >= 'a' && r <= 'z') || (r >= '0' && r <= '9'));
}
static inline int isValidNum(char c) {
return (c >= '0' && c <= '9');
}
static inline int isValidHexNum(char c) {
char r = c | 0x20;
return (isValidNum(r) || (r >= 'a' && r <= 'f'));
}
#define makeLexarToken(token, var) (lexarToken_t) {token, {var}}
#define makeLexarIntToken(intVar) (lexarToken_t) {IntLit, .val = intVar}
typedef struct {
u8 tokenC;
u16 tokenN;
} lexarTranslation_t;
lexarTranslation_t lexarTranslations[] = {
{'(', LBracket},
{')', RBracket},
{'{', LCBracket},
{'}', RCBracket},
{',', Seperator},
{'+', Plus},
{'-', Minus},
{'*', Multiply},
{'/', Division},
{'%', Mod},
{'<', Smaller},
{'>', Bigger},
{'=', Equal},
{'!', Not},
{'[', LSBracket},
{']', RSBracket},
{'\0', 0},
};
char lexarDebugGetTokenC(u16 tokenN) {
for (int i = 0; lexarTranslations[i].tokenC; i++) {
if (lexarTranslations[i].tokenN == tokenN) {
return lexarTranslations[i].tokenC;
}
}
return '?';
}
lexarVector_t lexarVectorInit(int startSize) {
lexarVector_t l = { 0 };
l.tokens = calloc(startSize, sizeof(lexarVector_t));
l.len = startSize;
l.stored = 0;
return l;
}
void lexarVectorAdd(lexarVector_t* vec, lexarToken_t token) {
if (vec->stored >= vec->len) {
vec->len *= 2;
//vec->tokens = realloc(vec->tokens, vec->len * sizeof(lexarToken_t));
void *temp = calloc(vec->len, sizeof(lexarToken_t));
memcpy(temp, vec->tokens, vec->len / 2 * sizeof(lexarToken_t));
free(vec->tokens);
vec->tokens = temp;
}
vec->tokens[vec->stored++] = token;
}
void lexarVectorClear(lexarVector_t* vec) {
for (int i = 0; i < vec->stored; i++) {
if (vec->tokens[i].token == Variable || vec->tokens[i].token == StrLit)
if (vec->tokens[i].text != NULL)
free(vec->tokens[i].text);
}
free(vec->tokens);
}
#define ELIFC(c) else if (*in == c)
lexarVector_t lexarGo(const char* in) {
lexarVector_t vec = lexarVectorInit(16);
while (*in) {
if (isValidWord(*in)) {
char* startWord = in;
in++;
while (isValidVar(*in))
in++;
lexarVectorAdd(&vec, makeLexarToken(Variable, utils_copyStringSize(startWord, in - startWord)));
continue;
}
else if (isValidNum(*in) || (*in == '-' && isValidNum(in[1]))) {
int parse = 0;
u8 negative = (*in == '-');
if (negative)
in++;
if (*in == '0' && (in[1] | 0x20) == 'x') {
in += 2;
while (isValidHexNum(*in)) {
parse = parse * 16 + (*in & 0x0F) + (*in >= 'A' ? 9 : 0);
in++;
}
}
else while (isValidNum(*in)) {
parse = parse * 10 + *in++ - '0';
}
if (negative)
parse *= -1;
lexarVectorAdd(&vec, makeLexarIntToken(parse));
continue;
}
ELIFC('"') {
char* startStr = ++in;
while (*in != '"')
in++;
lexarVectorAdd(&vec, makeLexarToken(StrLit, utils_copyStringSize(startStr, in - startStr)));
in++;
continue;
}
ELIFC('#') {
while (*in != '\n')
in++;
in++;
continue;
}
ELIFC('&') {
if (in[1] == '&') {
lexarVectorAdd(&vec, makeLexarToken(LogicAND, 0));
in++;
}
else {
lexarVectorAdd(&vec, makeLexarToken(AND, 0));
}
in++;
continue;
}
ELIFC('|') {
if (in[1] == '|') {
lexarVectorAdd(&vec, makeLexarToken(LogicOR, 0));
in++;
}
else {
lexarVectorAdd(&vec, makeLexarToken(OR, 0));
}
in++;
continue;
}
int val = 0;
for (int i = 0; lexarTranslations[i].tokenC; i++) {
if (lexarTranslations[i].tokenC == *in) {
val = lexarTranslations[i].tokenN;
break;
}
}
in++;
if (*in == '=' && val >= Smaller && val <= Not) {
val++;
in++;
}
if (val != Invalid)
lexarVectorAdd(&vec, makeLexarToken(val, 0));
}
return vec;
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include "types.h"
lexarVector_t lexarGo(const char* in);
char lexarDebugGetTokenC(u16 tokenN);
void lexarVectorClear(lexarVector_t* vec);

View File

@@ -0,0 +1,88 @@
#include "list.h"
#include <string.h>
#include "types.h"
#include "../../mem/heap.h"
void freeDictValue(dictValue_t dv) {
if (dv.string == NULL)
return;
switch (dv.varType) {
case StringType:
case IntArrayType:
case ByteArrayType: // As it's a union with the biggest object being a pointer, this should be the same
free(dv.string);
break;
case StringArrayType:
for (unsigned int i = 0; i < dv.arrayLen; i++)
free(dv.stringArray[i]);
free(dv.stringArray);
}
}
void freeDict(dict_t* dict) {
freeDictValue(dict->value);
free(dict->key);
free(dict);
}
varVector_t varVectorInit(int startSize) {
varVector_t vec = { 0 };
vec.vars = calloc(startSize, sizeof(dict_t));
vec.len = startSize;
vec.stored = 0;
return vec;
}
dictValue_t* varVectorFind(varVector_t* vec, const char* key) {
for (int i = 0; i < vec->stored; i++) {
if (!strcmp(vec->vars[i].key, key))
return &vec->vars[i].value;
}
return NULL;
}
void varVectorAdd(varVector_t* vec, dict_t add) {
dictValue_t* var = NULL;
if (add.key != NULL)
var = varVectorFind(vec, add.key);
if (var != NULL) {
freeDictValue(*var);
*var = add.value;
free(add.key);
return;
}
if (vec->stored >= vec->len) {
vec->len *= 2;
dict_t* old = vec->vars;
//vec->vars = realloc(old, vec->len * sizeof(dict_t));
void *temp = calloc(vec->len, sizeof(dict_t));
memcpy(temp, vec->vars, vec->len / 2 * sizeof(dict_t));
free(vec->vars);
vec->vars = temp;
if (vec->vars == NULL) {
free(old);
}
}
vec->vars[vec->stored] = add;
vec->stored++;
}
void varVectorFree(varVector_t* vec) {
for (int i = 0; i < vec->stored; i++) {
dict_t *var = &vec->vars[i];
if (var->key != NULL) {
free(var->key);
var->key = NULL;
}
if (var->value.free)
freeDictValue(var->value);
}
free(vec->vars);
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "types.h"
#define dictValSetInt(dictVal, i) dictVal.integer = i; dictVal.type = IntType;
#define dictValSetStr(dictVal, str) dictVal.string = strdup(str); dictVal.type = StringType;
#define dictValSetJump(dictVal, i) dictVal.integer = i; dictVal.type = JumpType;
#define dictValInt(i) (dictValue_t) {IntType, 0, i}
#define DictCreate(key, value) (dict_t) {key, value}
#define DictValueCreate(type, arrayLen, val) (dictValue_t) {type, arrayLen, val}
void freeDictValue(dictValue_t dv);
void freeDict(dict_t* dict);
varVector_t varVectorInit(int startSize);
void varVectorAdd(varVector_t* vec, dict_t add);
dictValue_t* varVectorFind(varVector_t* vec, const char* key);
static inline void freeDictValueOnVar(dictValue_t dv) {
if (dv.free)
freeDictValue(dv);
}
void varVectorFree(varVector_t* vec);

View File

@@ -1,319 +1,263 @@
#include "args.h"
#include "parser.h"
#include "types.h"
#include "list.h"
#include "functions.h"
#include "scriptCtx.h"
#include "lexer.h"
#include <string.h> #include <string.h>
#include "../../mem/heap.h" #include "../../mem/heap.h"
#include "../gfx/gfxutils.h"
#include "../emmc/emmc.h"
#include "../../utils/types.h"
#include "../../libs/fatfs/ff.h"
#include "../../utils/sprintf.h"
#include "../../utils/btn.h"
#include "../../gfx/gfx.h"
#include "../../utils/util.h"
#include "../../storage/emummc.h"
#include "parser.h"
#include "../common/common.h"
#include "../fs/fsactions.h"
#include "functions.h"
#include "variables.h"
#include "../fs/fsreader.h"
#include "../utils/utils.h" #include "../utils/utils.h"
#include "../../storage/nx_sd.h"
#include "../../gfx/gfx.h"
#include "../../hid/hid.h"
#include "../gfx/gfxutils.h"
u32 countchars(char* in, char target) { //#define DPRINTF(str, ...) printf(str, __VA_ARGS__)
u32 len = strlen(in); #define DPRINTF
u32 count = 0;
for (u32 i = 0; i < len; i++) { #define findNextCharsCtx(ctx, targets) findNextChars(&(ctx->curPos), targets)
if (in[i] == '"'){
int checkIfVar(u16 token) {
return (token == StrLit || token == IntLit || token == Variable || token == RSBracket);
}
void printToken(lexarToken_t* token) {
switch (token->token) {
case 1:
gfx_printf("%s ", token->text);
break;
case 6:
//printf("%d: '%s'\n", vec.tokens[i].token, vec.tokens[i].text);
gfx_printf("\"%s\" ", token->text);
break;
case 7:
//printf("%d: %d\n", vec.tokens[i].token, vec.tokens[i].val);
gfx_printf("%d ", token->val);
break;
default:
//printf("%d: %c\n", vec.tokens[i].token, lexarDebugGetTokenC(vec.tokens[i].token));
gfx_printf("%c ", lexarDebugGetTokenC(token->token));
break;
}
}
scriptResult_t runFunction(scriptCtx_t* ctx) {
dictValue_t res = solveEquation(ctx, &ctx->script->tokens[ctx->startEq], ctx->curPos - ctx->startEq);
if (res.varType == ErrType)
return scriptResultCreate(res.integer, &ctx->script->tokens[ctx->startEq]);
ctx->startEq = ctx->curPos;
if (ctx->varToken.token != Invalid) { // we should not assign null's
ctx->varToken.token = Invalid;
if (ctx->varIndexSet) {
ctx->varIndexSet = 0;
dictValue_t* arrayVal = varVectorFind(&ctx->vars, ctx->varToken.text);
if (!(arrayVal == NULL || arrayVal->arrayLen <= ctx->varIndex)) {
if (arrayVal->varType == IntArrayType && res.varType == IntType) {
arrayVal->integerArray[ctx->varIndex] = res.integer;
}
else if (arrayVal->varType == StringArrayType && res.varType == StringType) {
free(arrayVal->stringArray[ctx->varIndex]);
arrayVal->stringArray[ctx->varIndex] = res.string;
}
else if (arrayVal->varType == ByteArrayType && res.varType == IntType) {
arrayVal->byteArray[ctx->varIndex] = (u8)(res.integer & 0xFF);
}
else {
return scriptResultCreate(ERRINVALIDTYPE, &ctx->script->tokens[ctx->startEq]);
}
}
else {
return scriptResultCreate(ERRNOVAR, &ctx->script->tokens[ctx->startEq]);
}
}
else {
varVectorAdd(&ctx->vars, DictCreate(util_cpyStr(ctx->varToken.text), res));
}
}
else {
freeDictValueOnVar(res);
}
return scriptResultCreate(0, 0);
}
// TODO
// Make sure mem gets free'd properly
// Fix bug that custom functions cannot be run from end of script
// add arrays
#define RUNFUNCWITHPANIC(ctx) scriptResult_t res = runFunction(ctx); if (res.resCode != 0) return res
scriptResult_t mainLoop(scriptCtx_t* ctx) {
for (ctx->curPos = 0; ctx->curPos < ctx->script->stored; ctx->curPos++) {
u32 i = ctx->curPos;
lexarToken_t curToken = ctx->script->tokens[i];
//printToken(&curToken);
if (checkIfVar(ctx->lastToken.token) && curToken.token == Variable) {
RUNFUNCWITHPANIC(ctx);
}
else if (curToken.token == Equal) {
// Set last var to lastToken, if lastToken is var
if (ctx->lastToken.token == RSBracket) {
int layer = 0;
i = ctx->lastTokenPos - 1;
for (; i > 0; i--) {
if (ctx->script->tokens[i].token == RSBracket)
layer++;
else if (ctx->script->tokens[i].token == LSBracket) {
if (layer == 0)
break;
layer--;
}
}
i--;
if (ctx->script->tokens[i].token == Variable) {
dictValue_t index = solveEquation(ctx, &ctx->script->tokens[i + 2], ctx->lastTokenPos - i - 2);
ctx->lastTokenPos = i;
ctx->lastToken = ctx->script->tokens[i];
if (index.varType == IntType) {
ctx->varIndex = index.integer;
ctx->varIndexSet = 1;
if (ctx->varIndexSet) {
dictValue_t* arrayVal = varVectorFind(&ctx->vars, ctx->varToken.text);
if (arrayVal == NULL) {
return scriptResultCreate(ERRSYNTAX, &ctx->script->tokens[ctx->curPos]);
}
if (ctx->varIndex < 0 || ctx->varIndex >= arrayVal->arrayLen || arrayVal->varType < IntArrayType)
return scriptResultCreate(ERRSYNTAX, &ctx->script->tokens[ctx->curPos]);
}
}
else
return scriptResultCreate(ERRINVALIDTYPE, &ctx->script->tokens[ctx->curPos]);
}
else
return scriptResultCreate(ERRSYNTAX, &ctx->script->tokens[ctx->curPos]);
}
if (ctx->lastToken.token == Variable) {
ctx->startEq = ctx->curPos + 1;
ctx->varToken = ctx->lastToken;
}
else
return scriptResultCreate(ERRSYNTAX, &ctx->script->tokens[ctx->curPos]);
//printf("Setting token %s to next assignment", ctx->lastToken.text);
// !! check prev for ] for arrays
}
else if (curToken.token == LBracket) {
i++; i++;
while (in[i] != '"'){ int distance = distanceBetweenTokens(&ctx->script->tokens[i], ctx->script->stored - i, LBracket, RBracket);
i++; if (distance < 0)
if (i >= len) return scriptResultCreate(ERRSYNTAX, &ctx->script->tokens[ctx->curPos]);
return -1;
i += distance;
ctx->curPos = i;
if (ctx->curPos + 1 >= ctx->script->stored && checkIfVar(ctx->lastToken.token)) {
solveEquation(ctx, &ctx->script->tokens[ctx->startEq], i + 1 - ctx->startEq);
} }
}
if (in[i] == target)
count++;
}
return count;
}
char **argv = NULL;
u32 argc;
u32 splitargs(char* in) {
// arg like '5, "6", @arg7'
u32 i, current = 0, count = 1, len = strlen(in), curcount = 0;
if ((count += countchars(in, ',')) < 0){
return 0;
}
/*
if (argv != NULL) {
for (i = 0; argv[i] != NULL; i++)
free(argv[i]);
free(argv);
}
*/
argv = calloc(count + 1, sizeof(char*));
for (i = 0; i < count; i++)
argv[i] = calloc(96, sizeof(char));
for (i = 0; i < len && curcount < count; i++) {
if (in[i] == ',') {
curcount++;
current = 0;
}
else if (in[i] == '@' || in[i] == '$') {
while (strrchr(", )", in[i]) == NULL && i < len) {
argv[curcount][current++] = in[i++];
}
i--;
}
//else if ((in[i] >= '0' && in[i] <= '9') || (in[i] >= '<' && in[i] <= '>') || in[i] == '+' || in[i] == '-' || in[i] == '*' || in[i] == '/')
else if (strrchr("0123456789<=>+-*/", in[i]) != NULL)
argv[curcount][current++] = in[i];
else if (in[i] == '"') {
i++;
while (in[i] != '"') {
argv[curcount][current++] = in[i++];
}
}
}
return count;
}
FIL scriptin;
UINT endByte = 0;
int forceExit = false;
char currentchar = 0;
char getnextchar(){
f_read(&scriptin, &currentchar, sizeof(char), &endByte);
if (sizeof(char) != endByte)
forceExit = true;
//gfx_printf("|%c|", currentchar);
return currentchar;
}
void getfollowingchar(char end){
while (currentchar != end && !f_eof(&scriptin)){
if (currentchar == '"'){
while (getnextchar() != '"' && !f_eof(&scriptin));
}
getnextchar();
}
}
void getnextvalidchar(){
while ((!((currentchar >= '?' && currentchar <= 'Z') || (currentchar >= 'a' && currentchar <= 'z') || currentchar == '#') && !f_eof(&scriptin)) /*|| currentchar == ';' */)
getnextchar();
}
char *makestr(u32 size, char ignore){
char *str;
u32 count = 0;
str = calloc(size + 1, sizeof(char));
for (u32 i = 0; i < size; i++){
getnextchar();
if (ignore != 0 && ignore == currentchar)
continue; continue;
}
else if (curToken.token == LCBracket) {
if (ctx->lastToken.token == Equal && ctx->varToken.token == Variable) {
varVectorAdd(&ctx->vars, DictCreate(util_cpyStr(ctx->varToken.text), DictValueCreate(JumpType, 0, ctx->curPos)));
ctx->varToken.token = Invalid;
setCurIndentInstruction(ctx, 1, -1);
}
str[count++] = currentchar; if (checkIfVar(ctx->lastToken.token)) {
} RUNFUNCWITHPANIC(ctx);
}
return str; ctx->startEq = ctx->curPos + 1;
}
char *readtilchar(char end, char ignore){ indentInstructor_t ins = getCurIndentInstruction(ctx);
FSIZE_t offset, size; if (ins.active) {
if (ins.skip) {
int distance = distanceBetweenTokens(&ctx->script->tokens[i + 1], ctx->script->stored - i - 1, LCBracket, RCBracket);
if (distance < 0)
return scriptResultCreate(ERRSYNTAX, &ctx->script->tokens[ctx->curPos]);
ctx->curPos += distance + 1;
ctx->startEq = ctx->curPos + 1;
}
else {
ctx->indentLevel++;
}
}
else
return scriptResultCreate(ERRINACTIVEINDENT, &ctx->script->tokens[ctx->curPos]);
}
else if (curToken.token == RCBracket) {
if (checkIfVar(ctx->lastToken.token)) {
RUNFUNCWITHPANIC(ctx);
if (i != ctx->curPos)
continue;
}
offset = f_tell(&scriptin); ctx->indentLevel--;
getfollowingchar(end);
size = f_tell(&scriptin) - offset;
if (size <= 0) indentInstructor_t ins = getCurIndentInstruction(ctx);
return NULL; if (ins.active && ins.jump) {
ctx->curPos = ins.jumpLoc - 1;
}
f_lseek(&scriptin, offset - 1); ctx->startEq = ctx->curPos + 1;
}
return makestr((u32)size, ignore); else if (ctx->curPos + 1 >= ctx->script->stored && checkIfVar(ctx->lastToken.token)) {
} solveEquation(ctx, &ctx->script->tokens[ctx->startEq], i + 1 - ctx->startEq);
char *funcbuff = NULL;
void functionparser(){
char *unsplitargs;
/*
if (funcbuff != NULL)
free(funcbuff);
*/
funcbuff = readtilchar('(', ' ');
getfollowingchar('(');
getnextchar();
unsplitargs = readtilchar(')', 0);
if (unsplitargs != NULL){
argc = splitargs(unsplitargs);
getnextchar();
}
else {
argc = 0;
}
getnextchar();
free(unsplitargs);
}
char *gettargetvar(){
char *variable = NULL;
variable = readtilchar('=', ' ');
getfollowingchar('=');
getnextchar();
return variable;
}
void mainparser(){
char *variable = NULL;
int res, out = 0;
getnextvalidchar();
if (f_eof(&scriptin))
return;
if (currentchar == '#'){
getfollowingchar('\n');
return;
}
if (currentchar == '@'){
variable = gettargetvar();
getnextvalidchar();
}
/*
if (currentchar == '?'){
char *jumpname;
jumpname = readtilchar(';', ' ');
getnextchar();
str_jmp_add(jumpname, f_tell(&scriptin));
getfollowingchar('\n');
return;
}
*/
functionparser();
res = run_function(funcbuff, &out);
if (res < 0){
printerrors = true;
//gfx_printf("%s|%s|%d", funcbuff, argv[0], argc);
//btn_wait();
int lineNumber = 1;
u64 end = f_tell(&scriptin);
f_lseek(&scriptin, 0);
while (f_tell(&scriptin) < end && !f_eof(&scriptin)){
if (getnextchar() == '\n')
lineNumber++;
} }
gfx_errDisplay((res == -1) ? funcbuff : "run_function", (res == -1) ? ERR_IN_FUNC : ERR_SCRIPT_LOOKUP_FAIL, lineNumber); ctx->lastToken = ctx->script->tokens[ctx->curPos];
forceExit = true; ctx->lastTokenPos = ctx->curPos;
//gfx_printf("Func: %s\nArg1: %s\n", funcbuff, argv[0]);
}
else {
str_int_add("@RESULT", out);
if (variable != NULL)
str_int_add(variable, out);
} }
//gfx_printf("\nGoing to next func %c\n", currentchar); return scriptResultCreate(0, 0);
if (funcbuff != NULL){
free(funcbuff);
funcbuff = NULL;
}
if (argv != NULL) {
for (int i = 0; argv[i] != NULL; i++)
free(argv[i]);
free(argv);
argv = NULL;
}
if (variable != NULL){
free(variable);
}
} }
void skipbrackets(){ const char* functionFails[] = {
u32 bracketcounter = 0; "An invalid operation was performed",
"Double Nots are not allowed",
"A syntax error was found",
"The recieved type was incorrect",
"The variable could not be found",
"The specified function could not be found",
"An inactive indent was found"
};
getfollowingchar('{'); void startScript(char* path) {
getnextchar(); char* file = sd_file_read(path, NULL);
while ((currentchar != '}' || bracketcounter != 0) && !f_eof(&scriptin)){ if (file == NULL)
if (currentchar == '{')
bracketcounter++;
else if (currentchar == '}')
bracketcounter--;
getnextchar();
}
}
extern u32 currentcolor;
extern char *currentpath;
void runScript(char *path){
int res;
char *path_local = NULL;
forceExit = false;
currentchar = 0;
currentcolor = COLOR_WHITE;
gfx_clearscreen();
utils_copystring(path, &path_local);
res = f_open(&scriptin, path, FA_READ | FA_OPEN_EXISTING);
DWORD *clmt_in = f_expand_cltbl(&scriptin, BUFSIZE / 4, 0);
if (res != FR_OK){
gfx_errDisplay("ParseScript", res, 1);
return; return;
gfx_clearscreen();
scriptCtx_t ctx = createScriptCtx();
lexarVector_t vec = lexarGo(file);
free(file);
ctx.script = &vec;
scriptResult_t res = mainLoop(&ctx);
gfx_printf("end of script\n");
if (res.resCode) {
gfx_printf("[ERROR] %d\n%s\nNear:", res.resCode, functionFails[res.resCode - 1]);
printToken(res.nearToken);
} }
printerrors = false; gfx_printf("\n\n");
//mainLoop2(&ctx, &vec);
//add builtin vars lexarVectorClear(&vec);
str_int_add("@EMUMMC", emu_cfg.enabled); destroyScriptCtx(&ctx);
str_int_add("@RESULT", 0); hidWait();
str_str_add("$CURRENTPATH", currentpath);
//str_int_printall();
while (!f_eof(&scriptin) && !forceExit){
mainparser();
}
printerrors = true;
//str_int_printall();
f_close(&scriptin);
str_int_clear();
//str_jmp_clear();
str_str_clear();
free(path_local);
//btn_wait();
} }

View File

@@ -1,7 +1,9 @@
#pragma once #pragma once
#define INFUNC_FAIL (int)0xC0000000 #include "types.h"
//#define DictValue(type, val, len) (dictValue_t) {type, len, val}
void runScript(char *path); #define scriptResultCreate(resCode, funcName) (scriptResult_t) {resCode, funcName}
void skipbrackets();
void getfollowingchar(char end); void startScript(char* path);
char* readFile(char* path);

View File

@@ -0,0 +1,37 @@
#include "scriptCtx.h"
#include "list.h"
#include "malloc.h"
#include "types.h"
scriptCtx_t createScriptCtx() {
scriptCtx_t ctx;
ctx.indentInstructors = calloc(sizeof(indentInstructor_t), 64);
ctx.indentLevel = 0;
ctx.vars = varVectorInit(16);
ctx.script = NULL;
ctx.lastToken.token = 0;
ctx.varToken.token = 0;
ctx.startEq = 0;
ctx.varIndexStruct = 0;
return ctx;
}
void destroyScriptCtx(scriptCtx_t* ctx) {
// TODO
varVectorFree(&ctx->vars);
free(ctx->indentInstructors);
}
u8 setIndentInstruction(scriptCtx_t* ctx, u8 level, u8 skip, int jumpLoc) {
if (level >= 64)
return 1;
ctx->indentInstructors[level].skip = skip;
ctx->indentInstructors[level].active = 1;
ctx->indentInstructors[level].jump = (jumpLoc >= 0) ? 1 : 0;
ctx->indentInstructors[level].jumpLoc = jumpLoc;
return 0;
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include "types.h"
#define TEXTHOLDEREMPTY() (textHolder_t) {0}
#define TEXTHOLDER(start, len) (textHolder_t) {start, len, 1}
u8 setIndentInstruction(scriptCtx_t* ctx, u8 level, u8 skip, int jumpLoc);
void destroyScriptCtx(scriptCtx_t* ctx);
scriptCtx_t createScriptCtx();
static inline indentInstructor_t getCurIndentInstruction(scriptCtx_t* ctx);
static inline u8 setCurIndentInstruction(scriptCtx_t* ctx, u8 skip, int jumpLoc);
static inline u8 setCurIndentInstruction(scriptCtx_t* ctx, u8 skip, int jumpLoc) {
return setIndentInstruction(ctx, ctx->indentLevel, skip, jumpLoc);
}
static inline indentInstructor_t getCurIndentInstruction(scriptCtx_t* ctx) {
return ctx->indentInstructors[ctx->indentLevel];
}

View File

@@ -0,0 +1,174 @@
#pragma once
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef struct {
u16 token;
union {
char* text;
int val;
};
} lexarToken_t;
typedef struct {
lexarToken_t* tokens;
u32 len;
u32 stored;
} lexarVector_t;
enum Tokens {
Invalid = 0,
Variable = 1,
LBracket,
RBracket,
RCBracket,
LCBracket,
StrLit,
IntLit,
Seperator,
Plus,
Minus,
Multiply,
Division,
Mod,
Smaller,
SmallerEqual,
Bigger,
BiggerEqual,
Equal,
EqualEqual,
Not,
NotEqual,
LogicAND,
LogicOR,
LSBracket,
RSBracket,
AND,
OR
};
enum Errors {
ERRBADOPERATOR = 1,
ERRDOUBLENOT,
ERRSYNTAX,
ERRINVALIDTYPE,
ERRNOVAR,
ERRNOFUNC,
ERRINACTIVEINDENT
};
typedef struct { // this is to keep track of how many {} we passed. Keep an internal var with the "indentation level", +1 for {, -1 for }. have an array with the following def on what to do (on func: enter, set indentation & jump back, on while, jump to while, use while as if, on if simply set true or false)
union {
struct {
u8 active : 1;
u8 skip : 1;
u8 jump : 1;
};
u8 container;
};
int jumpLoc;
} indentInstructor_t;
typedef struct {
char* start;
u32 len;
union {
struct {
u8 set : 1;
};
u8 options;
};
} textHolder_t;
typedef struct {
int resCode;
lexarToken_t* nearToken;
} scriptResult_t;
#define JumpDictValue(jump) (dictValue_t) {{JumpType}, 0, .integer = jump}
#define StrDictValue(str) (dictValue_t) {{StringType}, 0, .string = str}
#define ErrDictValue(err) (dictValue_t) {{ErrType}, 0, .integer = err}
#define NullDictValue() (dictValue_t) {{NullType}, 0, .integer = 0}
#define IntArrDictValue(arr, len) (dictValue_t) {{IntArrayType}, len, .integerArray = arr}
#define StringArrDictValue(arr, len) (dictValue_t) {{StringArrayType}, len, .stringArray = arr}
#define IntDictValue(i) (dictValue_t) {{IntType}, 0, .integer = i}
enum {
IntType = 0,
StringType,
IntArrayType,
StringArrayType,
ByteArrayType,
JumpType,
DictType,
NullType,
ErrType,
};
typedef struct {
union {
u8 type;
struct {
u8 varType : 7;
u8 free : 1;
};
};
unsigned int arrayLen;
union {
int integer;
char* string;
unsigned char* byteArray;
int* integerArray;
char** stringArray;
};
} dictValue_t;
typedef struct {
char* key;
dictValue_t value;
} dict_t;
typedef struct {
dict_t* vars;
u32 len;
u32 stored;
} varVector_t;
typedef struct {
indentInstructor_t* indentInstructors;
u8 indentLevel; // -> max 63
varVector_t vars;
lexarVector_t* script;
lexarToken_t lastToken;
lexarToken_t varToken;
u32 startEq;
u32 curPos;
u32 lastTokenPos;
lexarVector_t args_loc;
union {
u32 varIndexStruct;
struct {
u32 varIndex : 31;
u32 varIndexSet : 1;
};
};
} scriptCtx_t;
typedef dictValue_t(*func_int_ptr)(scriptCtx_t* ctx, varVector_t* args);
typedef struct {
char* key;
func_int_ptr value;
union {
u8 args;
struct {
u8 argCount : 6;
u8 varArgs : 1;
u8 operatorParse : 1;
};
};
} str_fnc_struct;
#define FREEINDICT 0x80

View File

@@ -1,250 +0,0 @@
#include <string.h>
#include "../../mem/heap.h"
#include "../gfx/gfxutils.h"
#include "../emmc/emmc.h"
#include "../../utils/types.h"
#include "../../libs/fatfs/ff.h"
#include "../../utils/sprintf.h"
#include "../../utils/btn.h"
#include "../../gfx/gfx.h"
#include "../../utils/util.h"
#include "../../storage/emummc.h"
#include "parser.h"
#include "../common/common.h"
#include "../fs/fsactions.h"
#include "variables.h"
#include "../utils/utils.h"
static dict_str_int *str_int_table = NULL;
static dict_str_str *str_str_table = NULL;
//static dict_str_loc *str_jmp_table = NULL;
int str_int_add(char *key, int value){
char *key_local;
dict_str_int *keyvaluepair;
utils_copystring(key, &key_local);
keyvaluepair = calloc(1, sizeof(dict_str_int));
keyvaluepair->key = key_local;
keyvaluepair->value = value;
keyvaluepair->next = NULL;
if (str_int_table == NULL){
str_int_table = keyvaluepair;
}
else {
dict_str_int *temp;
temp = str_int_table;
while (temp != NULL){
if (!strcmp(temp->key, key_local)){
free(keyvaluepair);
free(key_local);
temp->value = value;
return 0;
}
if (temp->next == NULL){
temp->next = keyvaluepair;
return 0;
}
temp = temp->next;
}
}
return 0;
}
int str_int_find(char *key, int *out){
dict_str_int *temp;
temp = str_int_table;
while (temp != NULL){
if (!strcmp(temp->key, key)){
*out = temp->value;
return 0;
}
temp = temp->next;
}
return -1;
}
void str_int_clear(){
dict_str_int *cur, *next;
cur = str_int_table;
while (cur != NULL){
next = cur->next;
free(cur->key);
free(cur);
cur = next;
}
str_int_table = NULL;
}
void str_int_printall(){
dict_str_int *temp;
temp = str_int_table;
while (temp != NULL){
gfx_printf("%s -> %d\n", temp->key, temp->value);
temp = temp->next;
}
}
/*
int str_jmp_add(char *key, u64 value){
char *key_local;
dict_str_loc *keyvaluepair;
//gfx_printf("Adding |%s|\n", key_local);
utils_copystring(key, &key_local);
keyvaluepair = calloc(1, sizeof(dict_str_loc));
keyvaluepair->key = key_local;
keyvaluepair->value = value;
keyvaluepair->next = NULL;
if (str_jmp_table == NULL){
str_jmp_table = keyvaluepair;
}
else {
dict_str_loc *temp;
temp = str_jmp_table;
while (temp != NULL){
if (!strcmp(temp->key, key_local)){
free(keyvaluepair);
free(key_local);
temp->value = value;
return 0;
}
if (temp->next == NULL){
temp->next = keyvaluepair;
return 0;
}
temp = temp->next;
}
}
return 0;
}
int str_jmp_find(char *key, u64 *out){
dict_str_loc *temp;
temp = str_jmp_table;
//gfx_printf("Searching |%s|\n", key);
while (temp != NULL){
if (!strcmp(temp->key, key)){
//gfx_printf("Key found!\n", temp->value);
*out = temp->value;
return 0;
}
temp = temp->next;
}
//gfx_printf("no key!\n");
return -1;
}
void str_jmp_clear(){
dict_str_loc *cur, *next;
cur = str_jmp_table;
while (cur != NULL){
next = cur->next;
free(cur->key);
free(cur);
cur = next;
}
str_jmp_table = NULL;
}
*/
int str_str_add(char *key, char *value){
char *key_local, *value_local;
dict_str_str *keyvaluepair;
//gfx_printf("Adding |%s|\n", key_local);
utils_copystring(value, &value_local);
utils_copystring(key, &key_local);
keyvaluepair = calloc(1, sizeof(dict_str_str));
keyvaluepair->key = key_local;
keyvaluepair->value = value_local;
keyvaluepair->next = NULL;
if (str_str_table == NULL){
str_str_table = keyvaluepair;
}
else {
dict_str_str *temp;
temp = str_str_table;
while (temp != NULL){
if (!strcmp(temp->key, key_local)){
free(keyvaluepair);
free(key_local);
free(temp->value);
temp->value = value_local;
return 0;
}
if (temp->next == NULL){
temp->next = keyvaluepair;
return 0;
}
temp = temp->next;
}
}
return 0;
}
int str_str_find(char *key, char **out){
dict_str_str *temp;
temp = str_str_table;
while (temp != NULL){
if (!strcmp(temp->key, key)){
*out = temp->value;
return 0;
}
temp = temp->next;
}
return -1;
}
int str_str_index(int index, char **out){
dict_str_str *temp;
temp = str_str_table;
for (int i = 0; i < index; i++){
if (temp == NULL)
return -1;
temp = temp->next;
}
if (temp == NULL)
return -1;
*out = temp->value;
return 0;
}
void str_str_clear(){
dict_str_str *cur, *next;
cur = str_str_table;
while (cur != NULL){
next = cur->next;
free(cur->key);
free(cur->value);
free(cur);
cur = next;
}
str_str_table = NULL;
}

View File

@@ -1,34 +0,0 @@
#pragma once
#include "../../utils/types.h"
typedef struct _dict_str_int {
char *key;
int value;
struct _dict_str_int *next;
} dict_str_int;
typedef struct _dict_str_str {
char *key;
char *value;
struct _dict_str_str *next;
} dict_str_str;
typedef struct _dict_str_loc {
char *key;
u64 value;
struct _dict_str_loc *next;
} dict_str_loc;
int str_int_add(char *key, int value);
int str_int_find(char *key, int *out);
void str_int_clear();
void str_int_printall();
/*
int str_jmp_add(char *key, u64 value);
int str_jmp_find(char *key, u64 *out);
void str_jmp_clear();
*/
int str_str_add(char *key, char *value);
int str_str_find(char *key, char **out);
int str_str_index(int index, char **out);
void str_str_clear();

View File

@@ -17,6 +17,7 @@
#include "../fs/fsutils.h" #include "../fs/fsutils.h"
#include "../../mem/heap.h" #include "../../mem/heap.h"
#include "../utils/utils.h" #include "../utils/utils.h"
#include "../fs/nca.h"
extern bool sd_mount(); extern bool sd_mount();
extern void sd_unmount(); extern void sd_unmount();
@@ -93,7 +94,9 @@ void displaygpio(){
} }
} }
int dumpfirmware(int mmc){
// bad code ahead aaaa
int dumpfirmware(int mmc, bool daybreak){
DIR dir; DIR dir;
FILINFO fno; FILINFO fno;
bool fail = false; bool fail = false;
@@ -107,6 +110,22 @@ int dumpfirmware(int mmc){
connect_mmc(mmc); connect_mmc(mmc);
mount_mmc("SYSTEM", 2); mount_mmc("SYSTEM", 2);
if (daybreak){
if (!fsutil_checkfile("sd:/switch/prod.keys")){
SWAPCOLOR(COLOR_RED);
gfx_printf("prod.keys not found.\nPress any button to exit");
hidWait();
return true;
}
if (SetHeaderKey()){
SWAPCOLOR(COLOR_RED);
gfx_printf("Failed to find header key.\nPress any button to exit");
hidWait();
return true;
}
}
gfx_printf("PKG1 version: %d\n", pkg1.ver); gfx_printf("PKG1 version: %d\n", pkg1.ver);
gfx_printf("Creating folders...\n"); gfx_printf("Creating folders...\n");
@@ -115,7 +134,24 @@ int dumpfirmware(int mmc){
sdbase = calloc(32 + strlen(pkg1.id), sizeof(char)); sdbase = calloc(32 + strlen(pkg1.id), sizeof(char));
sprintf(sdbase, "sd:/tegraexplorer/Firmware/%d (%s)", pkg1.ver, pkg1.id); sprintf(sdbase, "sd:/tegraexplorer/Firmware/%d (%s)", pkg1.ver, pkg1.id);
gfx_printf("Out: %s\n", sdbase);
if (fsutil_checkfile(sdbase)){
SWAPCOLOR(COLOR_RED);
gfx_printf("Destination folder already exists.\nPress X to delete this folder, any other button to cancel\nPath: %s", sdbase);
Inputs *input = hidWait();
if (!input->x){
free(sdbase);
return true;
}
else {
SWAPCOLOR(COLOR_WHITE);
gfx_printf("\nDeleting folder..\n");
fsact_del_recursive(sdbase);
}
}
gfx_printf("\rOut: %s\n", sdbase);
f_mkdir(sdbase); f_mkdir(sdbase);
if ((ret = f_opendir(&dir, sysbase))) if ((ret = f_opendir(&dir, sysbase)))
@@ -127,16 +163,39 @@ int dumpfirmware(int mmc){
printerrors = 0; printerrors = 0;
while(!f_readdir(&dir, &fno) && fno.fname[0] && !fail){ while(!f_readdir(&dir, &fno) && fno.fname[0] && !fail){
utils_copystring(fsutil_getnextloc(sdbase, fno.fname), &sdpath);
utils_copystring(fsutil_getnextloc(sysbase, fno.fname), &syspathtemp); utils_copystring(fsutil_getnextloc(sysbase, fno.fname), &syspathtemp);
if (fno.fattrib & AM_DIR){ if (fno.fattrib & AM_DIR){
utils_copystring(fsutil_getnextloc(syspathtemp, "00"), &syspath); utils_copystring(fsutil_getnextloc(syspathtemp, "00"), &syspath);
free(syspathtemp);
} }
else else
syspath = syspathtemp; syspath = syspathtemp;
if (daybreak){
u8 ContentType = GetNcaType(syspath);
if (ContentType < 0){
fail = true;
continue;
}
char *temp;
utils_copystring(fsutil_getnextloc(sdbase, fno.fname), &temp);
if (ContentType == 0x01){
sdpath = calloc(strlen(temp) + 6, 1);
strcpy(sdpath, temp);
memcpy(sdpath + strlen(temp) - 4, ".cnmt.nca", 10);
free(temp);
}
else {
sdpath = temp;
}
}
else
utils_copystring(fsutil_getnextloc(sdbase, fno.fname), &sdpath);
ret = fsact_copy(syspath, sdpath, 0); ret = fsact_copy(syspath, sdpath, 0);
gfx_printf("%d %s\r", ++amount, fno.fname); gfx_printf("%d %s\r", ++amount, fno.fname);
@@ -145,7 +204,9 @@ int dumpfirmware(int mmc){
fail = true; fail = true;
free(sdpath); free(sdpath);
free(syspath); free(syspathtemp);
if (syspath != syspathtemp)
free(syspath);
} }
printerrors = 1; printerrors = 1;

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "../../utils/types.h"
void displayinfo(); void displayinfo();
void displaygpio(); void displaygpio();
int format(int mode); int format(int mode);
int dumpfirmware(int mmc); int dumpfirmware(int mmc, bool daybreak);

View File

@@ -193,3 +193,19 @@ char *utils_InputText(char *start, int maxLen){
return buff; return buff;
} }
char *utils_copyStringSize(const char *in, int size){
if (size > strlen(in) || size < 0)
size = strlen(in);
char *out = calloc(size + 1, 1);
//strncpy(out, in, size);
memcpy(out, in, size);
return out;
}
char* util_cpyStr(const char* in){
char *out = malloc(strlen(in) + 1);
strcpy(out, in);
return out;
}

View File

@@ -24,3 +24,5 @@ int utils_mmcMenu();
void utils_copystring(const char *in, char **out); void utils_copystring(const char *in, char **out);
char *utils_InputText(char *start, int maxLen); char *utils_InputText(char *start, int maxLen);
void utils_takeScreenshot(); void utils_takeScreenshot();
char *utils_copyStringSize(const char *in, int size);
char* util_cpyStr(const char* in);