git subrepo pull --force emummc
subrepo: subdir: "emummc" merged: "2fc47cbb8" upstream: origin: "https://github.com/lulle2007200/emuMMC.git" branch: "develop" commit: "2fc47cbb8" git-subrepo: version: "0.4.9" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "30db3b8"
This commit is contained in:
37
emummc/source/fatal/bdk/utils/aarch64_util.h
vendored
Normal file
37
emummc/source/fatal/bdk/utils/aarch64_util.h
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* 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 _ARM64_H_
|
||||
#define _ARM64_H_
|
||||
|
||||
#include <utils/types.h>
|
||||
|
||||
#define LSL0 0
|
||||
#define LSL16 16
|
||||
#define LSL32 32
|
||||
|
||||
#define _PAGEOFF(x) ((x) & 0xFFFFF000)
|
||||
|
||||
#define _ADRP(r, o) (0x90000000 | ((((o) >> 12) & 0x3) << 29) | ((((o) >> 12) & 0x1FFFFC) << 3) | ((r) & 0x1F))
|
||||
#define _BL(a, o) (0x94000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF))
|
||||
#define _B(a, o) (0x14000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF))
|
||||
#define _MOVKX(r, i, s) (0xF2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F))
|
||||
#define _MOVZX(r, i, s) (0xD2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F))
|
||||
#define _MOVZW(r, i, s) (0x52800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F))
|
||||
#define _NOP() 0xD503201F
|
||||
|
||||
#endif
|
||||
120
emummc/source/fatal/bdk/utils/btn.c
vendored
Normal file
120
emummc/source/fatal/bdk/utils/btn.c
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2022 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 "btn.h"
|
||||
#include <soc/i2c.h>
|
||||
#include <soc/gpio.h>
|
||||
#include <soc/timer.h>
|
||||
#include <soc/t210.h>
|
||||
#include <power/max77620.h>
|
||||
|
||||
u8 btn_read()
|
||||
{
|
||||
u8 res = 0;
|
||||
if (!gpio_read(GPIO_PORT_X, GPIO_PIN_7))
|
||||
res |= BTN_VOL_DOWN;
|
||||
if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6))
|
||||
res |= BTN_VOL_UP;
|
||||
// HOAG can use the GPIO. Icosa/Iowa/AULA cannot. Traces are there but they miss a resistor.
|
||||
if (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFSTAT) & MAX77620_ONOFFSTAT_EN0)
|
||||
res |= BTN_POWER;
|
||||
return res;
|
||||
}
|
||||
|
||||
u8 btn_read_vol()
|
||||
{
|
||||
u8 res = 0;
|
||||
if (!gpio_read(GPIO_PORT_X, GPIO_PIN_7))
|
||||
res |= BTN_VOL_DOWN;
|
||||
if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6))
|
||||
res |= BTN_VOL_UP;
|
||||
return res;
|
||||
}
|
||||
|
||||
u8 btn_read_home()
|
||||
{
|
||||
return (!gpio_read(GPIO_PORT_Y, GPIO_PIN_1)) ? BTN_HOME : 0;
|
||||
}
|
||||
|
||||
u8 btn_wait()
|
||||
{
|
||||
u8 res = 0, btn = btn_read();
|
||||
bool pwr = false;
|
||||
|
||||
//Power button down, raise a filter.
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
pwr = true;
|
||||
btn &= ~BTN_POWER;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
res = btn_read();
|
||||
//Power button up, remove filter.
|
||||
if (!(res & BTN_POWER) && pwr)
|
||||
pwr = false;
|
||||
else if (pwr) //Power button still down.
|
||||
res &= ~BTN_POWER;
|
||||
} while (btn == res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u8 btn_wait_timeout(u32 time_ms, u8 mask)
|
||||
{
|
||||
u32 timeout = get_tmr_ms() + time_ms;
|
||||
u8 res = btn_read() & mask;
|
||||
|
||||
while (get_tmr_ms() < timeout)
|
||||
{
|
||||
if (res == mask)
|
||||
break;
|
||||
else
|
||||
res = btn_read() & mask;
|
||||
};
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u8 btn_wait_timeout_single(u32 time_ms, u8 mask)
|
||||
{
|
||||
u8 single_button = mask & BTN_SINGLE;
|
||||
mask &= ~BTN_SINGLE;
|
||||
|
||||
u32 timeout = get_tmr_ms() + time_ms;
|
||||
u8 res = btn_read();
|
||||
|
||||
while (get_tmr_ms() < timeout)
|
||||
{
|
||||
if ((res & mask) == mask)
|
||||
{
|
||||
if (single_button && (res & ~mask)) // Undesired button detected.
|
||||
res = btn_read();
|
||||
else
|
||||
return (res & mask);
|
||||
}
|
||||
else
|
||||
res = btn_read();
|
||||
};
|
||||
|
||||
// Timed out.
|
||||
if (!single_button || !time_ms)
|
||||
return (res & mask);
|
||||
else
|
||||
return 0; // Return no button press if single button requested.
|
||||
}
|
||||
36
emummc/source/fatal/bdk/utils/btn.h
vendored
Normal file
36
emummc/source/fatal/bdk/utils/btn.h
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2022 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 _BTN_H_
|
||||
#define _BTN_H_
|
||||
|
||||
#include <utils/types.h>
|
||||
|
||||
#define BTN_POWER BIT(0)
|
||||
#define BTN_VOL_DOWN BIT(1)
|
||||
#define BTN_VOL_UP BIT(2)
|
||||
#define BTN_HOME BIT(3)
|
||||
#define BTN_SINGLE BIT(7)
|
||||
|
||||
u8 btn_read();
|
||||
u8 btn_read_vol();
|
||||
u8 btn_read_home();
|
||||
u8 btn_wait();
|
||||
u8 btn_wait_timeout(u32 time_ms, u8 mask);
|
||||
u8 btn_wait_timeout_single(u32 time_ms, u8 mask);
|
||||
|
||||
#endif
|
||||
100
emummc/source/fatal/bdk/utils/dirlist.c
vendored
Normal file
100
emummc/source/fatal/bdk/utils/dirlist.c
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2024 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 <stdlib.h>
|
||||
|
||||
#include "dirlist.h"
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <mem/heap.h>
|
||||
#include <utils/types.h>
|
||||
|
||||
dirlist_t *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs)
|
||||
{
|
||||
int res = 0;
|
||||
u32 k = 0;
|
||||
DIR dir;
|
||||
FILINFO fno;
|
||||
|
||||
dirlist_t *dir_entries = (dirlist_t *)malloc(sizeof(dirlist_t));
|
||||
|
||||
// Setup pointer tree.
|
||||
for (u32 i = 0; i < DIR_MAX_ENTRIES; i++)
|
||||
dir_entries->name[i] = &dir_entries->data[i * 256];
|
||||
|
||||
if (!pattern && !f_opendir(&dir, directory))
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
res = f_readdir(&dir, &fno);
|
||||
if (res || !fno.fname[0])
|
||||
break;
|
||||
|
||||
bool curr_parse = parse_dirs ? (fno.fattrib & AM_DIR) : !(fno.fattrib & AM_DIR);
|
||||
|
||||
if (curr_parse)
|
||||
{
|
||||
if ((fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
|
||||
{
|
||||
strcpy(&dir_entries->data[k * 256], fno.fname);
|
||||
if (++k >= DIR_MAX_ENTRIES)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
f_closedir(&dir);
|
||||
}
|
||||
else if (pattern && !f_findfirst(&dir, &fno, directory, pattern) && fno.fname[0])
|
||||
{
|
||||
do
|
||||
{
|
||||
if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
|
||||
{
|
||||
strcpy(&dir_entries->data[k * 256], fno.fname);
|
||||
if (++k >= DIR_MAX_ENTRIES)
|
||||
break;
|
||||
}
|
||||
res = f_findnext(&dir, &fno);
|
||||
} while (fno.fname[0] && !res);
|
||||
f_closedir(&dir);
|
||||
}
|
||||
|
||||
if (!k)
|
||||
{
|
||||
free(dir_entries);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Terminate name list.
|
||||
dir_entries->name[k] = NULL;
|
||||
|
||||
// Reorder ini files by ASCII ordering.
|
||||
for (u32 i = 0; i < k - 1 ; i++)
|
||||
{
|
||||
for (u32 j = i + 1; j < k; j++)
|
||||
{
|
||||
if (strcmp(dir_entries->name[i], dir_entries->name[j]) > 0)
|
||||
{
|
||||
char *tmp = dir_entries->name[i];
|
||||
dir_entries->name[i] = dir_entries->name[j];
|
||||
dir_entries->name[j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dir_entries;
|
||||
}
|
||||
27
emummc/source/fatal/bdk/utils/dirlist.h
vendored
Normal file
27
emummc/source/fatal/bdk/utils/dirlist.h
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2024 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 <utils/types.h>
|
||||
|
||||
#define DIR_MAX_ENTRIES 64
|
||||
|
||||
typedef struct _dirlist_t
|
||||
{
|
||||
char *name[DIR_MAX_ENTRIES];
|
||||
char data[DIR_MAX_ENTRIES * 256];
|
||||
} dirlist_t;
|
||||
|
||||
dirlist_t *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs);
|
||||
227
emummc/source/fatal/bdk/utils/ini.c
vendored
Normal file
227
emummc/source/fatal/bdk/utils/ini.c
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2024 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 "ini.h"
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <mem/heap.h>
|
||||
#include <utils/dirlist.h>
|
||||
#include <utils/util.h>
|
||||
|
||||
u32 _find_section_name(char *lbuf, u32 lblen, char schar)
|
||||
{
|
||||
u32 i;
|
||||
// Depends on 'FF_USE_STRFUNC 2' that removes \r.
|
||||
for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n'; i++)
|
||||
;
|
||||
lbuf[i] = 0;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type)
|
||||
{
|
||||
if (csec)
|
||||
list_append(dst, &csec->link);
|
||||
|
||||
// Calculate total allocation size.
|
||||
u32 len = name ? strlen(name) + 1 : 0;
|
||||
char *buf = zalloc(sizeof(ini_sec_t) + len);
|
||||
|
||||
csec = (ini_sec_t *)buf;
|
||||
csec->name = strcpy_ns(buf + sizeof(ini_sec_t), name);
|
||||
csec->type = type;
|
||||
|
||||
// Initialize list.
|
||||
list_init(&csec->kvs);
|
||||
|
||||
return csec;
|
||||
}
|
||||
|
||||
int ini_parse(link_t *dst, const char *ini_path, bool is_dir)
|
||||
{
|
||||
FIL fp;
|
||||
u32 lblen;
|
||||
u32 k = 0;
|
||||
u32 pathlen = strlen(ini_path);
|
||||
ini_sec_t *csec = NULL;
|
||||
|
||||
char *lbuf = NULL;
|
||||
dirlist_t *filelist = NULL;
|
||||
char *filename = (char *)malloc(256);
|
||||
|
||||
strcpy(filename, ini_path);
|
||||
|
||||
// Get all ini filenames.
|
||||
if (is_dir)
|
||||
{
|
||||
filelist = dirlist(filename, "*.ini", false, false);
|
||||
if (!filelist)
|
||||
{
|
||||
free(filename);
|
||||
return 0;
|
||||
}
|
||||
strcpy(filename + pathlen, "/");
|
||||
pathlen++;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
// Copy ini filename in path string.
|
||||
if (is_dir)
|
||||
{
|
||||
if (filelist->name[k])
|
||||
{
|
||||
strcpy(filename + pathlen, filelist->name[k]);
|
||||
k++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// Open ini.
|
||||
if (f_open(&fp, filename, FA_READ) != FR_OK)
|
||||
{
|
||||
free(filelist);
|
||||
free(filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lbuf = malloc(512);
|
||||
|
||||
do
|
||||
{
|
||||
// Fetch one line.
|
||||
lbuf[0] = 0;
|
||||
f_gets(lbuf, 512, &fp);
|
||||
lblen = strlen(lbuf);
|
||||
|
||||
// Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \r.
|
||||
if (lblen && lbuf[lblen - 1] == '\n')
|
||||
lbuf[lblen - 1] = 0;
|
||||
|
||||
if (lblen > 2 && lbuf[0] == '[') // Create new section.
|
||||
{
|
||||
_find_section_name(lbuf, lblen, ']');
|
||||
|
||||
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE);
|
||||
}
|
||||
else if (lblen > 1 && lbuf[0] == '{') // Create new caption. Support empty caption '{}'.
|
||||
{
|
||||
_find_section_name(lbuf, lblen, '}');
|
||||
|
||||
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION);
|
||||
csec->color = 0xFF0AB9E6;
|
||||
}
|
||||
else if (lblen > 2 && lbuf[0] == '#') // Create comment.
|
||||
{
|
||||
csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT);
|
||||
}
|
||||
else if (lblen < 2) // Create empty line.
|
||||
{
|
||||
csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE);
|
||||
}
|
||||
else if (csec && csec->type == INI_CHOICE) // Extract key/value.
|
||||
{
|
||||
u32 i = _find_section_name(lbuf, lblen, '=');
|
||||
|
||||
// Calculate total allocation size.
|
||||
u32 klen = strlen(&lbuf[0]) + 1;
|
||||
u32 vlen = strlen(&lbuf[i + 1]) + 1;
|
||||
char *buf = zalloc(sizeof(ini_kv_t) + klen + vlen);
|
||||
|
||||
ini_kv_t *kv = (ini_kv_t *)buf;
|
||||
buf += sizeof(ini_kv_t);
|
||||
kv->key = strcpy_ns(buf, &lbuf[0]);
|
||||
buf += klen;
|
||||
kv->val = strcpy_ns(buf, &lbuf[i + 1]);
|
||||
list_append(&csec->kvs, &kv->link);
|
||||
}
|
||||
} while (!f_eof(&fp));
|
||||
|
||||
free(lbuf);
|
||||
|
||||
f_close(&fp);
|
||||
|
||||
if (csec)
|
||||
{
|
||||
list_append(dst, &csec->link);
|
||||
if (is_dir)
|
||||
csec = NULL;
|
||||
}
|
||||
} while (is_dir);
|
||||
|
||||
free(filename);
|
||||
free(filelist);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *ini_check_special_section(ini_sec_t *cfg)
|
||||
{
|
||||
if (cfg == NULL)
|
||||
return NULL;
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
|
||||
{
|
||||
if (!strcmp("l4t", kv->key))
|
||||
return ((kv->val[0] == '1') ? (char *)-1 : NULL);
|
||||
else if (!strcmp("payload", kv->key))
|
||||
return kv->val;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ini_free(link_t *src)
|
||||
{
|
||||
ini_sec_t *prev_sec = NULL;
|
||||
|
||||
// Parse and free all ini sections.
|
||||
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, src, link)
|
||||
{
|
||||
ini_kv_t *prev_kv = NULL;
|
||||
|
||||
// Free all ini key allocations if they exist.
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
|
||||
{
|
||||
// Free previous key.
|
||||
if (prev_kv)
|
||||
free(prev_kv);
|
||||
|
||||
// Set next key to free.
|
||||
prev_kv = kv;
|
||||
}
|
||||
|
||||
// Free last key.
|
||||
if (prev_kv)
|
||||
free(prev_kv);
|
||||
|
||||
// Free previous section.
|
||||
if (prev_sec)
|
||||
free(prev_sec);
|
||||
|
||||
// Set next section to free.
|
||||
prev_sec = ini_sec;
|
||||
}
|
||||
|
||||
// Free last section.
|
||||
if (prev_sec)
|
||||
free(prev_sec);
|
||||
}
|
||||
51
emummc/source/fatal/bdk/utils/ini.h
vendored
Normal file
51
emummc/source/fatal/bdk/utils/ini.h
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 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 _INI_H_
|
||||
#define _INI_H_
|
||||
|
||||
#include <utils/types.h>
|
||||
#include <utils/list.h>
|
||||
|
||||
#define INI_CHOICE 3
|
||||
#define INI_CAPTION 5
|
||||
#define INI_CHGLINE 6
|
||||
#define INI_NEWLINE 0xFE
|
||||
#define INI_COMMENT 0xFF
|
||||
|
||||
typedef struct _ini_kv_t
|
||||
{
|
||||
char *key;
|
||||
char *val;
|
||||
link_t link;
|
||||
} ini_kv_t;
|
||||
|
||||
typedef struct _ini_sec_t
|
||||
{
|
||||
char *name;
|
||||
link_t kvs;
|
||||
link_t link;
|
||||
u32 type;
|
||||
u32 color;
|
||||
} ini_sec_t;
|
||||
|
||||
int ini_parse(link_t *dst, const char *ini_path, bool is_dir);
|
||||
char *ini_check_special_section(ini_sec_t *cfg);
|
||||
void ini_free(link_t *src);
|
||||
|
||||
#endif
|
||||
|
||||
106
emummc/source/fatal/bdk/utils/list.h
vendored
Normal file
106
emummc/source/fatal/bdk/utils/list.h
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 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 _LIST_H_
|
||||
#define _LIST_H_
|
||||
|
||||
#include <utils/types.h>
|
||||
|
||||
/*! Initialize list. */
|
||||
#define LIST_INIT(name) link_t name = {&name, &name}
|
||||
|
||||
/*! Initialize static list. */
|
||||
#define LIST_INIT_STATIC(name) static link_t name = {&name, &name}
|
||||
|
||||
/*! Iterate over all list links. */
|
||||
#define LIST_FOREACH(iter, list) \
|
||||
for (link_t *iter = (list)->next; iter != (list); iter = iter->next)
|
||||
|
||||
/*! Iterate over all list links backwards. */
|
||||
#define LIST_FOREACH_INVERSE(iter, list) \
|
||||
for (link_t *iter = (list)->prev; iter != (list); iter = iter->prev)
|
||||
|
||||
/*! Safely iterate over all list links. */
|
||||
#define LIST_FOREACH_SAFE(iter, list) \
|
||||
for (link_t *iter = (list)->next, *safe = iter->next; iter != (list); iter = safe, safe = iter->next)
|
||||
|
||||
/*! Iterate over all list members and make sure that the list has at least one entry. */
|
||||
#define LIST_FOREACH_ENTRY(etype, iter, list, mn) \
|
||||
if ((list)->next != (list)) \
|
||||
for (etype *iter = CONTAINER_OF((list)->next, etype, mn); &iter->mn != (list); iter = CONTAINER_OF(iter->mn.next, etype, mn))
|
||||
|
||||
/* Iterate over all list members backwards and make sure that the list has at least one entry. */
|
||||
#define LIST_FOREACH_ENTRY_INVERSE(type, iter, list, mn) \
|
||||
if ((list)->prev != (list)) \
|
||||
for (type *iter = CONTAINER_OF((list)->prev, type, mn); &iter->mn != (list); iter = CONTAINER_OF(iter->mn.prev, type, mn))
|
||||
|
||||
typedef struct _link_t
|
||||
{
|
||||
struct _link_t *prev;
|
||||
struct _link_t *next;
|
||||
} link_t;
|
||||
|
||||
static inline void link_init(link_t *l)
|
||||
{
|
||||
l->prev = NULL;
|
||||
l->next = NULL;
|
||||
}
|
||||
|
||||
static inline int link_used(link_t *l)
|
||||
{
|
||||
if (l->next == NULL)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void list_init(link_t *lh)
|
||||
{
|
||||
lh->prev = lh;
|
||||
lh->next = lh;
|
||||
}
|
||||
|
||||
static inline void list_prepend(link_t *lh, link_t *l)
|
||||
{
|
||||
l->next = lh->next;
|
||||
l->prev = lh;
|
||||
lh->next->prev = l;
|
||||
lh->next = l;
|
||||
}
|
||||
|
||||
static inline void list_append(link_t *lh, link_t *l)
|
||||
{
|
||||
l->prev = lh->prev;
|
||||
l->next = lh;
|
||||
lh->prev->next = l;
|
||||
lh->prev = l;
|
||||
}
|
||||
|
||||
static inline void list_remove(link_t *l)
|
||||
{
|
||||
l->next->prev = l->prev;
|
||||
l->prev->next = l->next;
|
||||
link_init(l);
|
||||
}
|
||||
|
||||
static inline int list_empty(link_t *lh)
|
||||
{
|
||||
if (lh->next == lh)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
299
emummc/source/fatal/bdk/utils/sprintf.c
vendored
Normal file
299
emummc/source/fatal/bdk/utils/sprintf.c
vendored
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2019-2024 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 <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <utils/types.h>
|
||||
|
||||
char **sout_buf;
|
||||
|
||||
static void _s_putc(char c)
|
||||
{
|
||||
**sout_buf = c;
|
||||
*sout_buf += 1;
|
||||
}
|
||||
|
||||
static void _s_putspace(int fcnt)
|
||||
{
|
||||
if (fcnt <= 0)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < fcnt; i++)
|
||||
_s_putc(' ');
|
||||
}
|
||||
|
||||
static void _s_puts(char *s, char fill, int fcnt)
|
||||
{
|
||||
if (fcnt)
|
||||
{
|
||||
fcnt = fcnt - strlen(s);
|
||||
|
||||
// Left padding. Check if padding is not space based (dot counts as such).
|
||||
if (fill != '.')
|
||||
_s_putspace(fcnt);
|
||||
}
|
||||
|
||||
for (; *s; s++)
|
||||
_s_putc(*s);
|
||||
|
||||
// Right padding. Check if padding is space based (dot counts as such).
|
||||
if (fill == '.')
|
||||
_s_putspace(fcnt);
|
||||
}
|
||||
|
||||
static void _s_putn(u32 v, int base, char fill, int fcnt)
|
||||
{
|
||||
static const char digits[] = "0123456789ABCDEF";
|
||||
|
||||
char *p;
|
||||
char buf[65]; // Number char size + leftover for padding.
|
||||
int c = fcnt;
|
||||
bool negative = false;
|
||||
|
||||
if (base != 10 && base != 16)
|
||||
return;
|
||||
|
||||
// Account for negative numbers.
|
||||
if (base == 10 && v & 0x80000000)
|
||||
{
|
||||
negative = true;
|
||||
v = (int)v * -1;
|
||||
c--;
|
||||
}
|
||||
|
||||
p = buf + 64;
|
||||
*p = 0;
|
||||
do
|
||||
{
|
||||
c--;
|
||||
*--p = digits[v % base];
|
||||
v /= base;
|
||||
} while (v);
|
||||
|
||||
if (negative)
|
||||
*--p = '-';
|
||||
|
||||
if (fill != 0)
|
||||
{
|
||||
while (c > 0 && p > buf)
|
||||
{
|
||||
*--p = fill;
|
||||
c--;
|
||||
}
|
||||
}
|
||||
|
||||
_s_puts(p, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Padding:
|
||||
* Numbers:
|
||||
* %3d: Fill: ' ', Count: 3.
|
||||
* % 3d: Fill: ' ', Count: 3.
|
||||
* %.3d: Fill: '.', Count: 3.
|
||||
* %23d: Fill: '2', Count: 3.
|
||||
* % 23d: Fill: ' ', Count: 23.
|
||||
* %223d: Fill: '2', Count: 23.
|
||||
*
|
||||
* Strings, Fill: ' ':
|
||||
* %3s: Count: 5, Left.
|
||||
* %23s: Count: 5, Left.
|
||||
* %223s: Count: 25, Left.
|
||||
* %.3s: Count: 5, Right.
|
||||
* %.23s: Count: 25, Right.
|
||||
* %.223s: Count: 225, Right.
|
||||
*/
|
||||
|
||||
void s_printf(char *out_buf, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int fill, fcnt;
|
||||
|
||||
sout_buf = &out_buf;
|
||||
|
||||
va_start(ap, fmt);
|
||||
while (*fmt)
|
||||
{
|
||||
if (*fmt == '%')
|
||||
{
|
||||
fmt++;
|
||||
fill = 0;
|
||||
fcnt = 0;
|
||||
|
||||
// Check for padding. Number or space based (dot count as space for string).
|
||||
if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ' || *fmt == '.')
|
||||
{
|
||||
fcnt = *fmt; // Padding size or padding type.
|
||||
fmt++;
|
||||
|
||||
if (*fmt >= '0' && *fmt <= '9')
|
||||
{
|
||||
// Padding size exists. Previous char was type.
|
||||
fill = fcnt;
|
||||
fcnt = *fmt - '0';
|
||||
fmt++;
|
||||
parse_padding_dec:
|
||||
// Parse padding size extra digits.
|
||||
if (*fmt >= '0' && *fmt <= '9')
|
||||
{
|
||||
fcnt = fcnt * 10 + *fmt - '0';
|
||||
fmt++;
|
||||
goto parse_padding_dec;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No padding type, use space. (Max padding size is 9).
|
||||
fill = ' ';
|
||||
fcnt -= '0';
|
||||
}
|
||||
}
|
||||
|
||||
switch (*fmt)
|
||||
{
|
||||
case 'c':
|
||||
char c = va_arg(ap, u32);
|
||||
if (c != '\0')
|
||||
_s_putc(c);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
_s_puts(va_arg(ap, char *), fill, fcnt);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
_s_putn(va_arg(ap, u32), 10, fill, fcnt);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
case 'P':
|
||||
case 'x':
|
||||
case 'X':
|
||||
_s_putn(va_arg(ap, u32), 16, fill, fcnt);
|
||||
break;
|
||||
|
||||
case '%':
|
||||
_s_putc('%');
|
||||
break;
|
||||
|
||||
case '\0':
|
||||
goto out;
|
||||
|
||||
default:
|
||||
_s_putc('%');
|
||||
_s_putc(*fmt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
_s_putc(*fmt);
|
||||
fmt++;
|
||||
}
|
||||
|
||||
out:
|
||||
**sout_buf = '\0';
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void s_vprintf(char *out_buf, const char *fmt, va_list ap)
|
||||
{
|
||||
int fill, fcnt;
|
||||
|
||||
sout_buf = &out_buf;
|
||||
|
||||
while (*fmt)
|
||||
{
|
||||
if (*fmt == '%')
|
||||
{
|
||||
fmt++;
|
||||
fill = 0;
|
||||
fcnt = 0;
|
||||
|
||||
// Check for padding. Number or space based.
|
||||
if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ')
|
||||
{
|
||||
fcnt = *fmt; // Padding size or padding type.
|
||||
fmt++;
|
||||
|
||||
if (*fmt >= '0' && *fmt <= '9')
|
||||
{
|
||||
// Padding size exists. Previous char was type.
|
||||
fill = fcnt;
|
||||
fcnt = *fmt - '0';
|
||||
fmt++;
|
||||
parse_padding_dec:
|
||||
// Parse padding size extra digits.
|
||||
if (*fmt >= '0' && *fmt <= '9')
|
||||
{
|
||||
fcnt = fcnt * 10 + *fmt - '0';
|
||||
fmt++;
|
||||
goto parse_padding_dec;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No padding type, use space. (Max padding size is 9).
|
||||
fill = ' ';
|
||||
fcnt -= '0';
|
||||
}
|
||||
}
|
||||
|
||||
switch (*fmt)
|
||||
{
|
||||
case 'c':
|
||||
char c = va_arg(ap, u32);
|
||||
if (c != '\0')
|
||||
_s_putc(c);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
_s_puts(va_arg(ap, char *), fill, fcnt);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
_s_putn(va_arg(ap, u32), 10, fill, fcnt);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
case 'P':
|
||||
case 'x':
|
||||
case 'X':
|
||||
_s_putn(va_arg(ap, u32), 16, fill, fcnt);
|
||||
break;
|
||||
|
||||
case '%':
|
||||
_s_putc('%');
|
||||
break;
|
||||
|
||||
case '\0':
|
||||
goto out;
|
||||
|
||||
default:
|
||||
_s_putc('%');
|
||||
_s_putc(*fmt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
_s_putc(*fmt);
|
||||
fmt++;
|
||||
}
|
||||
|
||||
out:
|
||||
**sout_buf = '\0';
|
||||
}
|
||||
45
emummc/source/fatal/bdk/utils/sprintf.h
vendored
Normal file
45
emummc/source/fatal/bdk/utils/sprintf.h
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 _SPRINTF_H_
|
||||
#define _SPRINTF_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <utils/types.h>
|
||||
|
||||
/*
|
||||
* Padding:
|
||||
* Numbers:
|
||||
* %3d: Fill: ' ', Count: 3.
|
||||
* % 3d: Fill: ' ', Count: 3.
|
||||
* %23d: Fill: '2', Count: 3.
|
||||
* % 23d: Fill: ' ', Count: 23.
|
||||
* %223d: Fill: '2', Count: 23.
|
||||
*
|
||||
* Strings, Fill: ' ':
|
||||
* %3s: Count: 5, Left.
|
||||
* %23s: Count: 5, Left.
|
||||
* %223s: Count: 25, Left.
|
||||
* %.3s: Count: 5, Right.
|
||||
* %.23s: Count: 25, Right.
|
||||
* %.223s: Count: 225, Right.
|
||||
*/
|
||||
|
||||
void s_printf(char *out_buf, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
|
||||
void s_vprintf(char *out_buf, const char *fmt, va_list ap);
|
||||
|
||||
#endif
|
||||
168
emummc/source/fatal/bdk/utils/types.h
vendored
Normal file
168
emummc/source/fatal/bdk/utils/types.h
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2022 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 _TYPES_H_
|
||||
#define _TYPES_H_
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/* Types */
|
||||
typedef signed char s8;
|
||||
typedef short s16;
|
||||
typedef short SHORT;
|
||||
typedef int s32;
|
||||
typedef int INT;
|
||||
typedef int bool;
|
||||
typedef long LONG;
|
||||
typedef long long int s64;
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned short WCHAR;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned int UINT;
|
||||
typedef unsigned long DWORD;
|
||||
typedef unsigned long long QWORD;
|
||||
typedef unsigned long long int u64;
|
||||
|
||||
typedef volatile unsigned char vu8;
|
||||
typedef volatile unsigned short vu16;
|
||||
typedef volatile unsigned int vu32;
|
||||
|
||||
#ifdef __aarch64__
|
||||
typedef unsigned long long uptr;
|
||||
#else /* __arm__ or __thumb__ */
|
||||
typedef unsigned long uptr;
|
||||
#endif
|
||||
|
||||
/* Important */
|
||||
#define false 0
|
||||
#define true 1
|
||||
|
||||
#define NULL ((void *)0)
|
||||
|
||||
/* Misc */
|
||||
#define DISABLE 0
|
||||
#define ENABLE 1
|
||||
|
||||
/* Sizes */
|
||||
#define SZ_1K 0x400
|
||||
#define SZ_2K 0x800
|
||||
#define SZ_4K 0x1000
|
||||
#define SZ_8K 0x2000
|
||||
#define SZ_16K 0x4000
|
||||
#define SZ_32K 0x8000
|
||||
#define SZ_64K 0x10000
|
||||
#define SZ_128K 0x20000
|
||||
#define SZ_256K 0x40000
|
||||
#define SZ_512K 0x80000
|
||||
#define SZ_1M 0x100000
|
||||
#define SZ_2M 0x200000
|
||||
#define SZ_4M 0x400000
|
||||
#define SZ_8M 0x800000
|
||||
#define SZ_16M 0x1000000
|
||||
#define SZ_32M 0x2000000
|
||||
#define SZ_64M 0x4000000
|
||||
#define SZ_128M 0x8000000
|
||||
#define SZ_256M 0x10000000
|
||||
#define SZ_512M 0x20000000
|
||||
#define SZ_1G 0x40000000
|
||||
#define SZ_2G 0x80000000
|
||||
#define SZ_PAGE SZ_4K
|
||||
|
||||
/* Macros */
|
||||
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
||||
#define ALIGN_DOWN(x, a) ((x) & ~((a) - 1))
|
||||
#define BIT(n) (1U << (n))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
|
||||
|
||||
#define OFFSET_OF(t, m) ((uptr)&((t *)NULL)->m)
|
||||
#define CONTAINER_OF(mp, t, mn) ((t *)((uptr)mp - OFFSET_OF(t, mn)))
|
||||
|
||||
#define byte_swap_16(num) ((((num) >> 8) & 0xFF) | (((num) & 0xFF) << 8))
|
||||
#define byte_swap_32(num) ((((num) >> 24) & 0xFF) | (((num) & 0xFF00) << 8 ) | \
|
||||
(((num) >> 8 ) & 0xFF00) | (((num) & 0xFF) << 24))
|
||||
|
||||
#define likely(x) (__builtin_expect((x) != 0, 1))
|
||||
#define unlikely(x) (__builtin_expect((x) != 0, 0))
|
||||
|
||||
/* Bootloader/Nyx */
|
||||
#define BOOT_CFG_AUTOBOOT_EN BIT(0)
|
||||
#define BOOT_CFG_FROM_LAUNCH BIT(1)
|
||||
#define BOOT_CFG_FROM_ID BIT(2)
|
||||
#define BOOT_CFG_TO_EMUMMC BIT(3)
|
||||
|
||||
#define EXTRA_CFG_KEYS BIT(0)
|
||||
#define EXTRA_CFG_PAYLOAD BIT(1)
|
||||
#define EXTRA_CFG_MODULE BIT(2)
|
||||
|
||||
#define EXTRA_CFG_NYX_UMS BIT(5)
|
||||
#define EXTRA_CFG_NYX_RELOAD BIT(6)
|
||||
|
||||
typedef enum _nyx_ums_type
|
||||
{
|
||||
NYX_UMS_SD_CARD = 0,
|
||||
NYX_UMS_EMMC_BOOT0,
|
||||
NYX_UMS_EMMC_BOOT1,
|
||||
NYX_UMS_EMMC_GPP,
|
||||
NYX_UMS_EMUMMC_BOOT0,
|
||||
NYX_UMS_EMUMMC_BOOT1,
|
||||
NYX_UMS_EMUMMC_GPP
|
||||
} nyx_ums_type;
|
||||
|
||||
typedef struct __attribute__((__packed__)) _boot_cfg_t
|
||||
{
|
||||
u8 boot_cfg;
|
||||
u8 autoboot;
|
||||
u8 autoboot_list;
|
||||
u8 extra_cfg;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
char id[8]; // 7 char ASCII null terminated.
|
||||
char emummc_path[0x78]; // emuMMC/XXX, ASCII null terminated.
|
||||
};
|
||||
u8 ums; // nyx_ums_type.
|
||||
u8 xt_str[0x80];
|
||||
};
|
||||
} boot_cfg_t;
|
||||
|
||||
static_assert(sizeof(boot_cfg_t) == 0x84, "Boot cfg storage size is wrong!");
|
||||
|
||||
typedef struct __attribute__((__packed__)) _ipl_ver_meta_t
|
||||
{
|
||||
u32 magic;
|
||||
u32 version;
|
||||
u16 rsvd0;
|
||||
u16 rsvd1;
|
||||
} ipl_ver_meta_t;
|
||||
|
||||
typedef struct __attribute__((__packed__)) _reloc_meta_t
|
||||
{
|
||||
u32 start;
|
||||
u32 stack;
|
||||
u32 end;
|
||||
u32 ep;
|
||||
} reloc_meta_t;
|
||||
|
||||
#endif
|
||||
307
emummc/source/fatal/bdk/utils/util.c
vendored
Normal file
307
emummc/source/fatal/bdk/utils/util.c
vendored
Normal file
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2024 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 <mem/heap.h>
|
||||
#include <power/max77620.h>
|
||||
#include <rtc/max77620-rtc.h>
|
||||
#include <soc/bpmp.h>
|
||||
#include <soc/hw_init.h>
|
||||
#include <soc/i2c.h>
|
||||
#include <soc/pmc.h>
|
||||
#include <soc/timer.h>
|
||||
#include <soc/t210.h>
|
||||
#include <storage/sd.h>
|
||||
#include <utils/util.h>
|
||||
|
||||
u8 bit_count(u32 val)
|
||||
{
|
||||
u8 cnt = 0;
|
||||
for (u32 i = 0; i < 32; i++)
|
||||
{
|
||||
if ((val >> i) & 1)
|
||||
cnt++;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
u32 bit_count_mask(u8 bits)
|
||||
{
|
||||
u32 val = 0;
|
||||
for (u32 i = 0; i < bits; i++)
|
||||
val |= 1 << i;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
char *strcpy_ns(char *dst, char *src)
|
||||
{
|
||||
if (!src || !dst)
|
||||
return NULL;
|
||||
|
||||
// Remove starting space.
|
||||
u32 len = strlen(src);
|
||||
if (len && src[0] == ' ')
|
||||
{
|
||||
len--;
|
||||
src++;
|
||||
}
|
||||
|
||||
strcpy(dst, src);
|
||||
|
||||
// Remove trailing space.
|
||||
if (len && dst[len - 1] == ' ')
|
||||
dst[len - 1] = 0;
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
// Approximate square root finder for a 64-bit number.
|
||||
u64 sqrt64(u64 num)
|
||||
{
|
||||
u64 base = 0;
|
||||
u64 limit = num;
|
||||
u64 square_root = 0;
|
||||
|
||||
while (base <= limit)
|
||||
{
|
||||
u64 tmp_sqrt = (base + limit) / 2;
|
||||
|
||||
if (tmp_sqrt * tmp_sqrt == num) {
|
||||
square_root = tmp_sqrt;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tmp_sqrt * tmp_sqrt < num)
|
||||
{
|
||||
square_root = base;
|
||||
base = tmp_sqrt + 1;
|
||||
}
|
||||
else
|
||||
limit = tmp_sqrt - 1;
|
||||
}
|
||||
|
||||
return square_root;
|
||||
}
|
||||
|
||||
#define TULONG_MAX ((unsigned long)((unsigned long)(~0L)))
|
||||
#define TLONG_MAX ((long)(((unsigned long)(~0L)) >> 1))
|
||||
#define TLONG_MIN ((long)(~TLONG_MAX))
|
||||
#define ISSPACE(ch) ((ch >= '\t' && ch <= '\r') || (ch == ' '))
|
||||
#define ISDIGIT(ch) ( ch >= '0' && ch <= '9' )
|
||||
#define ISALPHA(ch) ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
|
||||
#define ISUPPER(ch) ( ch >= 'A' && ch <= 'Z' )
|
||||
|
||||
/*
|
||||
* Avoid using reentrant newlib version of strol. It's only used for errno.
|
||||
*
|
||||
* strol/atoi:
|
||||
* Copyright (c) 1990 The Regents of the University of California.
|
||||
*/
|
||||
long strtol(const char *nptr, char **endptr, register int base)
|
||||
{
|
||||
register const char *s = nptr;
|
||||
register unsigned long acc;
|
||||
register int c;
|
||||
register unsigned long cutoff;
|
||||
register int neg = 0, any, cutlim;
|
||||
|
||||
/*
|
||||
* Skip white space and pick up leading +/- sign if any.
|
||||
* If base is 0, allow 0x for hex and 0 for octal, else
|
||||
* assume decimal; if base is already 16, allow 0x.
|
||||
*/
|
||||
do {
|
||||
c = *s++;
|
||||
} while (ISSPACE(c));
|
||||
if (c == '-') {
|
||||
neg = 1;
|
||||
c = *s++;
|
||||
} else if (c == '+')
|
||||
c = *s++;
|
||||
if ((base == 0 || base == 16) &&
|
||||
c == '0' && (*s == 'x' || *s == 'X')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 16;
|
||||
}
|
||||
if (base == 0)
|
||||
base = c == '0' ? 8 : 10;
|
||||
|
||||
/*
|
||||
* Compute the cutoff value between legal numbers and illegal
|
||||
* numbers. That is the largest legal value, divided by the
|
||||
* base. An input number that is greater than this value, if
|
||||
* followed by a legal input character, is too big. One that
|
||||
* is equal to this value may be valid or not; the limit
|
||||
* between valid and invalid numbers is then based on the last
|
||||
* digit. For instance, if the range for longs is
|
||||
* [-2147483648..2147483647] and the input base is 10,
|
||||
* cutoff will be set to 214748364 and cutlim to either
|
||||
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
|
||||
* a value > 214748364, or equal but the next digit is > 7 (or 8),
|
||||
* the number is too big, and we will return a range error.
|
||||
*
|
||||
* Set any if any `digits' consumed; make it negative to indicate
|
||||
* overflow.
|
||||
*/
|
||||
cutoff = neg ? -(unsigned long)TLONG_MIN : (base == 16 ? TULONG_MAX : TLONG_MAX);
|
||||
cutlim = cutoff % (unsigned long)base;
|
||||
cutoff /= (unsigned long)base;
|
||||
for (acc = 0, any = 0;; c = *s++) {
|
||||
if (ISDIGIT(c))
|
||||
c -= '0';
|
||||
else if (ISALPHA(c))
|
||||
c -= ISUPPER(c) ? 'A' - 10 : 'a' - 10;
|
||||
else
|
||||
break;
|
||||
if (c >= base)
|
||||
break;
|
||||
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
|
||||
any = -1;
|
||||
else {
|
||||
any = 1;
|
||||
acc *= base;
|
||||
acc += c;
|
||||
}
|
||||
}
|
||||
if (any < 0) {
|
||||
acc = neg ? TLONG_MIN : TLONG_MAX;
|
||||
} else if (neg)
|
||||
acc = -acc;
|
||||
if (endptr != 0)
|
||||
*endptr = (char *) (any ? s - 1 : nptr);
|
||||
return (acc);
|
||||
}
|
||||
|
||||
int atoi(const char *nptr)
|
||||
{
|
||||
return (int)strtol(nptr, (char **)NULL, 10);
|
||||
}
|
||||
|
||||
void reg_write_array(u32 *base, const reg_cfg_t *cfg, u32 num_cfg)
|
||||
{
|
||||
// Expected register offset is a u32 array index.
|
||||
for (u32 i = 0; i < num_cfg; i++)
|
||||
base[cfg[i].idx] = cfg[i].val;
|
||||
}
|
||||
|
||||
u32 crc32_calc(u32 crc, const u8 *buf, u32 len)
|
||||
{
|
||||
const u8 *p, *q;
|
||||
static u32 *table = NULL;
|
||||
|
||||
// Calculate CRC table.
|
||||
if (!table)
|
||||
{
|
||||
table = zalloc(256 * sizeof(u32));
|
||||
for (u32 i = 0; i < 256; i++)
|
||||
{
|
||||
u32 rem = i;
|
||||
for (u32 j = 0; j < 8; j++)
|
||||
{
|
||||
if (rem & 1)
|
||||
{
|
||||
rem >>= 1;
|
||||
rem ^= 0xedb88320;
|
||||
}
|
||||
else
|
||||
rem >>= 1;
|
||||
}
|
||||
table[i] = rem;
|
||||
}
|
||||
}
|
||||
|
||||
crc = ~crc;
|
||||
q = buf + len;
|
||||
for (p = buf; p < q; p++)
|
||||
{
|
||||
u8 oct = *p;
|
||||
crc = (crc >> 8) ^ table[(crc & 0xff) ^ oct];
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
void panic(u32 val)
|
||||
{
|
||||
// Set panic code.
|
||||
PMC(APBDEV_PMC_SCRATCH200) = val;
|
||||
|
||||
// Disable SE.
|
||||
//PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_DISABLE;
|
||||
|
||||
// Immediately cause a full system reset.
|
||||
watchdog_start(0, TIMER_PMCRESET_EN);
|
||||
|
||||
while (true);
|
||||
}
|
||||
|
||||
void power_set_state(power_state_t state)
|
||||
{
|
||||
u8 reg;
|
||||
|
||||
// Unmount and power down sd card.
|
||||
// sd_end();
|
||||
|
||||
// De-initialize and power down various hardware.
|
||||
hw_deinit(false, 0);
|
||||
|
||||
// Set power state.
|
||||
switch (state)
|
||||
{
|
||||
case REBOOT_RCM:
|
||||
PMC(APBDEV_PMC_SCRATCH0) = PMC_SCRATCH0_MODE_RCM; // Enable RCM path.
|
||||
PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST; // PMC reset.
|
||||
break;
|
||||
|
||||
case REBOOT_BYPASS_FUSES:
|
||||
panic(0x21); // Bypass fuse programming in package1.
|
||||
break;
|
||||
|
||||
case POWER_OFF:
|
||||
// Initiate power down sequence and do not generate a reset (regulators retain state after POR).
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF);
|
||||
break;
|
||||
|
||||
case POWER_OFF_RESET:
|
||||
case POWER_OFF_REBOOT:
|
||||
default:
|
||||
// Enable/Disable soft reset wake event.
|
||||
reg = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG2);
|
||||
if (state == POWER_OFF_RESET) // Do not wake up after power off.
|
||||
reg &= ~(MAX77620_ONOFFCNFG2_SFT_RST_WK | MAX77620_ONOFFCNFG2_WK_ALARM1 | MAX77620_ONOFFCNFG2_WK_ALARM2);
|
||||
else // POWER_OFF_REBOOT. Wake up after power off.
|
||||
reg |= MAX77620_ONOFFCNFG2_SFT_RST_WK;
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG2, reg);
|
||||
|
||||
// Initiate power down sequence and generate a reset (regulators' state resets after POR).
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_SFT_RST);
|
||||
break;
|
||||
}
|
||||
|
||||
while (true)
|
||||
bpmp_halt();
|
||||
}
|
||||
|
||||
void power_set_state_ex(void *param)
|
||||
{
|
||||
power_state_t *state = (power_state_t *)param;
|
||||
power_set_state(*state);
|
||||
}
|
||||
97
emummc/source/fatal/bdk/utils/util.h
vendored
Normal file
97
emummc/source/fatal/bdk/utils/util.h
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2024 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 _UTIL_H_
|
||||
#define _UTIL_H_
|
||||
|
||||
#include <utils/types.h>
|
||||
#include <mem/minerva.h>
|
||||
|
||||
#define NYX_NEW_INFO 0x3058594E
|
||||
|
||||
typedef enum
|
||||
{
|
||||
REBOOT_RCM, // PMC reset. Enter RCM mode.
|
||||
REBOOT_BYPASS_FUSES, // PMC reset via watchdog. Enter Normal mode. Bypass fuse programming in package1.
|
||||
|
||||
POWER_OFF, // Power off PMIC. Do not reset regulators.
|
||||
POWER_OFF_RESET, // Power off PMIC. Reset regulators.
|
||||
POWER_OFF_REBOOT, // Power off PMIC. Reset regulators. Power on.
|
||||
} power_state_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NYX_CFG_UMS = BIT(6),
|
||||
|
||||
NYX_CFG_EXTRA = 0xFF << 24
|
||||
} nyx_cfg_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ERR_LIBSYS_LP0 = BIT(0),
|
||||
ERR_SYSOLD_NYX = BIT(1),
|
||||
ERR_LIBSYS_MTC = BIT(2),
|
||||
ERR_SD_BOOT_EN = BIT(3),
|
||||
ERR_PANIC_CODE = BIT(4),
|
||||
ERR_L4T_KERNEL = BIT(24),
|
||||
ERR_EXCEPTION = BIT(31),
|
||||
} hekate_errors_t;
|
||||
|
||||
typedef struct _reg_cfg_t
|
||||
{
|
||||
u32 idx;
|
||||
u32 val;
|
||||
} reg_cfg_t;
|
||||
|
||||
typedef struct _nyx_info_t
|
||||
{
|
||||
u32 magic;
|
||||
u32 sd_init;
|
||||
u32 sd_errors[3];
|
||||
u8 rsvd[0x1000];
|
||||
u32 disp_id;
|
||||
u32 errors;
|
||||
} nyx_info_t;
|
||||
|
||||
typedef struct _nyx_storage_t
|
||||
{
|
||||
u32 version;
|
||||
u32 cfg;
|
||||
u8 irama[0x8000];
|
||||
u8 hekate[0x30000];
|
||||
u8 rsvd[SZ_8M - sizeof(nyx_info_t)];
|
||||
nyx_info_t info;
|
||||
mtc_config_t mtc_cfg;
|
||||
emc_table_t mtc_table[11]; // 10 + 1.
|
||||
} nyx_storage_t;
|
||||
|
||||
u8 bit_count(u32 val);
|
||||
u32 bit_count_mask(u8 bits);
|
||||
char *strcpy_ns(char *dst, char *src);
|
||||
u64 sqrt64(u64 num);
|
||||
long strtol(const char *nptr, char **endptr, register int base);
|
||||
int atoi(const char *nptr);
|
||||
|
||||
void reg_write_array(u32 *base, const reg_cfg_t *cfg, u32 num_cfg);
|
||||
u32 crc32_calc(u32 crc, const u8 *buf, u32 len);
|
||||
|
||||
void panic(u32 val);
|
||||
void power_set_state(power_state_t state);
|
||||
void power_set_state_ex(void *param);
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user