diff --git a/.gitignore b/.gitignore
index 768c7ab..273ba03 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
.vs
.vscode
-build_ipl/*
+build/*.o
+build/*.elf
+build/bin/ipl
diff --git a/Makefile b/Makefile
index ede5553..d6f6381 100644
--- a/Makefile
+++ b/Makefile
@@ -7,12 +7,12 @@ LD = $(DEVKITARM)/bin/arm-none-eabi-ld
OBJCOPY = $(DEVKITARM)/bin/arm-none-eabi-objcopy
TARGET := ipl
-BUILD := ipl
+BUILD := build
+BUILD_BINARY := build/bin
SOURCEDIR := ipl
OBJS = $(addprefix $(BUILD)/, \
start.o \
main.o \
- btn.o \
clock.o \
cluster.o \
fuse.o \
@@ -20,7 +20,6 @@ OBJS = $(addprefix $(BUILD)/, \
heap.o \
hos.o \
i2c.o \
- kfuse.o \
lz.o \
max7762x.o \
mc.o \
@@ -29,7 +28,6 @@ OBJS = $(addprefix $(BUILD)/, \
sdmmc_driver.o \
sdram.o \
sdram_lp0.o \
- tui.o \
util.o \
di.o \
gfx.o \
@@ -39,7 +37,6 @@ OBJS = $(addprefix $(BUILD)/, \
se.o \
tsec.o \
uart.o \
- ini.o \
)
OBJS += $(addprefix $(BUILD)/, diskio.o ff.o ffunicode.o)
@@ -49,14 +46,14 @@ LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections
.PHONY: all clean
-all: $(BUILD)/$(TARGET)
+all: $(BUILD_BINARY)/$(TARGET)
clean:
@rm -rf $(OBJS)
@rm -rf $(BUILD)/$(TARGET).elf
- @rm -rf $(BUILD)/$(TARGET)
+ @rm -rf $(BUILD_BINARY)/$(TARGET)
-$(BUILD)/$(TARGET): $(BUILD)/$(TARGET).elf
+$(BUILD_BINARY)/$(TARGET): $(BUILD)/$(TARGET).elf
$(OBJCOPY) -S -O binary $< $@
$(BUILD)/$(TARGET).elf: $(OBJS)
diff --git a/README.md b/README.md
index b4aca67..b3b68dc 100644
--- a/README.md
+++ b/README.md
@@ -1,20 +1,9 @@
-# hekate for 5.0.x
+# hekate for 4.x / 5.0.x
-DO NOT UPDATE TO 5.0.2 FOR THIS
+DO NOT UPDATE FOR THIS
Original by @nwert
![Image of Hekate](https://upload.wikimedia.org/wikipedia/commons/f/fc/H%C3%A9cate_-_Mallarm%C3%A9.png)
Nintendo Switch bootloader, firmware patcher, and more.
-
-## ipl config
-
-The ipl can be configured via 'hekate_ipl.ini' (if it is present on the SD card). Each ini section represents a boot entry, except for the special section 'config' that controls the global configuration.
-
-Possible key/value combinations:
-
- - warmboot={SD path}
- - secmon={SD path}
- - kernel={SD path}
- - kip1={SD path}
diff --git a/build/bin/DELETE_ME b/build/bin/DELETE_ME
new file mode 100644
index 0000000..e69de29
diff --git a/ipl/btn.c b/ipl/btn.c
deleted file mode 100644
index c346fce..0000000
--- a/ipl/btn.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
-* Copyright (c) 2018 naehrwert
-*
-* 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 .
-*/
-
-#include "btn.h"
-#include "i2c.h"
-#include "gpio.h"
-#include "t210.h"
-
-u32 btn_read()
-{
- u32 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;
- if (i2c_recv_byte(4, 0x3C, 0x15) & 0x4)
- res |= BTN_POWER;
- return res;
-}
-
-u32 btn_wait()
-{
- u32 res = 0, btn = btn_read();
- do
- {
- res = btn_read();
- } while (btn == res);
- return res;
-}
diff --git a/ipl/btn.h b/ipl/btn.h
deleted file mode 100644
index 8c5a8c5..0000000
--- a/ipl/btn.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
-* Copyright (c) 2018 naehrwert
-*
-* 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 .
-*/
-
-#ifndef _BTN_H_
-#define _BTN_H_
-
-#include "types.h"
-
-#define BTN_POWER 0x1
-#define BTN_VOL_DOWN 0x2
-#define BTN_VOL_UP 0x4
-
-u32 btn_read();
-u32 btn_wait();
-
-#endif
diff --git a/ipl/btn.o b/ipl/btn.o
deleted file mode 100644
index cbdac1a..0000000
Binary files a/ipl/btn.o and /dev/null differ
diff --git a/ipl/clock.o b/ipl/clock.o
deleted file mode 100644
index 4a6c71d..0000000
Binary files a/ipl/clock.o and /dev/null differ
diff --git a/ipl/cluster.o b/ipl/cluster.o
deleted file mode 100644
index b882f88..0000000
Binary files a/ipl/cluster.o and /dev/null differ
diff --git a/ipl/di.o b/ipl/di.o
deleted file mode 100644
index ee8712b..0000000
Binary files a/ipl/di.o and /dev/null differ
diff --git a/ipl/diskio.o b/ipl/diskio.o
deleted file mode 100644
index 7626cab..0000000
Binary files a/ipl/diskio.o and /dev/null differ
diff --git a/ipl/ff.o b/ipl/ff.o
deleted file mode 100644
index 6e19735..0000000
Binary files a/ipl/ff.o and /dev/null differ
diff --git a/ipl/ffunicode.o b/ipl/ffunicode.o
deleted file mode 100644
index cb2d2fb..0000000
Binary files a/ipl/ffunicode.o and /dev/null differ
diff --git a/ipl/fuse.o b/ipl/fuse.o
deleted file mode 100644
index 4ddb779..0000000
Binary files a/ipl/fuse.o and /dev/null differ
diff --git a/ipl/gfx.o b/ipl/gfx.o
deleted file mode 100644
index 68564da..0000000
Binary files a/ipl/gfx.o and /dev/null differ
diff --git a/ipl/gpio.o b/ipl/gpio.o
deleted file mode 100644
index 712ee3c..0000000
Binary files a/ipl/gpio.o and /dev/null differ
diff --git a/ipl/heap.o b/ipl/heap.o
deleted file mode 100644
index c7de54b..0000000
Binary files a/ipl/heap.o and /dev/null differ
diff --git a/ipl/hos.c b/ipl/hos.c
index 5c6454d..9a33805 100644
--- a/ipl/hos.c
+++ b/ipl/hos.c
@@ -265,42 +265,6 @@ out:;
return res;
}
-static int _config_warmboot(launch_ctxt_t *ctxt, const char *value)
-{
- FIL fp;
- if (f_open(&fp, value, FA_READ) != FR_OK)
- return 0;
- ctxt->warmboot_size = f_size(&fp);
- ctxt->warmboot = malloc(ctxt->warmboot_size);
- f_read(&fp, ctxt->warmboot, ctxt->warmboot_size, NULL);
- f_close(&fp);
- return 1;
-}
-
-static int _config_secmon(launch_ctxt_t *ctxt, const char *value)
-{
- FIL fp;
- if (f_open(&fp, value, FA_READ) != FR_OK)
- return 0;
- ctxt->secmon_size = f_size(&fp);
- ctxt->secmon = malloc(ctxt->secmon_size);
- f_read(&fp, ctxt->secmon, ctxt->secmon_size, NULL);
- f_close(&fp);
- return 1;
-}
-
-static int _config_kernel(launch_ctxt_t *ctxt, const char *value)
-{
- FIL fp;
- if (f_open(&fp, value, FA_READ) != FR_OK)
- return 0;
- ctxt->kernel_size = f_size(&fp);
- ctxt->kernel = malloc(ctxt->kernel_size);
- f_read(&fp, ctxt->kernel, ctxt->kernel_size, NULL);
- f_close(&fp);
- return 1;
-}
-
static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
@@ -315,30 +279,6 @@ DPRINTF("loaded kip from SD (size %08X)\n", f_size(&fp));
return 1;
}
-typedef struct _cfg_handler_t
-{
- const char *key;
- int (*handler)(launch_ctxt_t *ctxt, const char *value);
-} cfg_handler_t;
-
-static const cfg_handler_t _config_handlers[] = {
- { "warmboot", _config_warmboot },
- { "secmon", _config_secmon },
- { "kernel", _config_kernel },
- { "kip1", _config_kip1 },
- { NULL, NULL },
-};
-
-static int _config(launch_ctxt_t *ctxt, ini_sec_t *cfg)
-{
- LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
- for(u32 i = 0; _config_handlers[i].key; i++)
- if (!strcmp(_config_handlers[i].key, kv->key) &&
- !_config_handlers[i].handler(ctxt, kv->val))
- return 0;
- return 1;
-}
-
int hos_launch()
{
launch_ctxt_t ctxt;
diff --git a/ipl/hos.h b/ipl/hos.h
index 699bf03..4920796 100644
--- a/ipl/hos.h
+++ b/ipl/hos.h
@@ -18,7 +18,6 @@
#define _HOS_H_
#include "types.h"
-#include "ini.h"
int hos_launch();
diff --git a/ipl/hos.o b/ipl/hos.o
deleted file mode 100644
index 0a3bb9a..0000000
Binary files a/ipl/hos.o and /dev/null differ
diff --git a/ipl/i2c.o b/ipl/i2c.o
deleted file mode 100644
index a78b851..0000000
Binary files a/ipl/i2c.o and /dev/null differ
diff --git a/ipl/ini.c b/ipl/ini.c
deleted file mode 100644
index 8551203..0000000
--- a/ipl/ini.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
-* Copyright (c) 2018 naehrwert
-*
-* 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 .
-*/
-
-#include
-
-#include "ini.h"
-#include "ff.h"
-#include "heap.h"
-
-
-static char *_strdup(char *str)
-{
- char *res = malloc(strlen(str) + 1);
- strcpy(res, str);
- return res;
-}
-
-int ini_parse(link_t *dst, char *ini_path)
-{
- u32 lblen;
- char lbuf[512];
- FIL fp;
- ini_sec_t *csec = NULL;
-
- if (f_open(&fp, ini_path, FA_READ) != FR_OK)
- return 0;
-
- do
- {
- //Fetch one line.
- lbuf[0] = 0;
- f_gets(lbuf, 512, &fp);
- lblen = strlen(lbuf);
-
- //Skip empty lines and comments.
- if (lblen <= 1 || lbuf[0] == '#')
- continue;
-
- //Remove trailing newline.
- if (lbuf[lblen - 1] == '\n')
- lbuf[lblen - 1] = 0;
-
- if (lblen > 2 && lbuf[0] == '[') //Create new section.
- {
- if (csec)
- {
- list_append(dst, &csec->link);
- csec = NULL;
- }
-
- u32 i;
- for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != ']'; i++)
- ;
- lbuf[i] = 0;
-
- csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
- csec->name = _strdup(&lbuf[1]);
- list_init(&csec->kvs);
- }
- else if (csec) //Extract key/value.
- {
- u32 i;
- for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != '='; i++)
- ;
- lbuf[i] = 0;
-
- ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t));
- kv->key = _strdup(&lbuf[0]);
- kv->val = _strdup(&lbuf[i + 1]);
- list_append(&csec->kvs, &kv->link);
- }
- } while (!f_eof(&fp));
-
- f_close(&fp);
-
- if (csec)
- list_append(dst, &csec->link);
-
- return 1;
-}
diff --git a/ipl/ini.h b/ipl/ini.h
deleted file mode 100644
index 091009e..0000000
--- a/ipl/ini.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-* Copyright (c) 2018 naehrwert
-*
-* 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 .
-*/
-
-#ifndef _INI_H_
-#define _INI_H_
-
-#include "types.h"
-#include "list.h"
-
-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;
-} ini_sec_t;
-
-int ini_parse(link_t *dst, char *ini_path);
-
-#endif
diff --git a/ipl/ini.o b/ipl/ini.o
deleted file mode 100644
index 6482eac..0000000
Binary files a/ipl/ini.o and /dev/null differ
diff --git a/ipl/ipl.elf b/ipl/ipl.elf
deleted file mode 100644
index bbf450d..0000000
Binary files a/ipl/ipl.elf and /dev/null differ
diff --git a/ipl/kfuse.c b/ipl/kfuse.c
deleted file mode 100644
index 03d95bb..0000000
--- a/ipl/kfuse.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
-* Copyright (c) 2018 naehrwert
-*
-* 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 .
-*/
-
-#include "kfuse.h"
-#include "clock.h"
-#include "t210.h"
-
-int kfuse_read(u32 *buf)
-{
- int res = 0;
-
- clock_enable_kfuse();
-
- while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE))
- ;
-
- if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS))
- goto out;
-
- KFUSE(KFUSE_KEYADDR) = KFUSE_KEYADDR_AUTOINC;
- for (int i = 0; i < KFUSE_NUM_WORDS; i++)
- buf[i] = KFUSE(KFUSE_KEYS);
-
- res = 1;
-
-out:;
- clock_disable_kfuse();
- return res;
-}
diff --git a/ipl/kfuse.h b/ipl/kfuse.h
deleted file mode 100644
index 4aa1b09..0000000
--- a/ipl/kfuse.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-* Copyright (c) 2018 naehrwert
-*
-* 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 .
-*/
-
-#ifndef _KFUSE_H_
-#define _KFUSE_H_
-
-#include "types.h"
-
-#define KFUSE_STATE_SOFTRESET (1<<31)
-#define KFUSE_STATE_STOP (1<<25)
-#define KFUSE_STATE_RESTART (1<<24)
-#define KFUSE_STATE_CRCPASS (1<<17)
-#define KFUSE_STATE_DONE (1<<16)
-#define KFUSE_STATE_ERRBLOCK_MASK 0x3F00
-#define KFUSE_STATE_ERRBLOCK_SHIFT 8
-#define KFUSE_STATE_CURBLOCK_MASK 0x3F
-
-#define KFUSE_KEYADDR_AUTOINC (1<<16)
-
-#define KFUSE_STATE 0x80
-#define KFUSE_KEYADDR 0x88
-#define KFUSE_KEYS 0x8C
-
-#define KFUSE_NUM_WORDS 144
-
-int kfuse_read(u32 *buf);
-
-#endif
diff --git a/ipl/kfuse.o b/ipl/kfuse.o
deleted file mode 100644
index af2ca54..0000000
Binary files a/ipl/kfuse.o and /dev/null differ
diff --git a/ipl/lz.o b/ipl/lz.o
deleted file mode 100644
index 0bb9018..0000000
Binary files a/ipl/lz.o and /dev/null differ
diff --git a/ipl/main.c b/ipl/main.c
index 047d8af..62947cf 100644
--- a/ipl/main.c
+++ b/ipl/main.c
@@ -30,35 +30,14 @@
#include "fuse.h"
#include "util.h"
#include "gfx.h"
-#include "btn.h"
-#include "tsec.h"
-#include "kfuse.h"
#include "max77620.h"
-#include "max7762x.h"
#include "gpio.h"
#include "sdmmc.h"
#include "ff.h"
-#include "tui.h"
#include "heap.h"
-#include "list.h"
-#include "nx_emmc.h"
#include "se.h"
#include "se_t210.h"
#include "hos.h"
-#include "pkg1.h"
-
-void panic(u32 val)
-{
- //Set panic code.
- PMC(APBDEV_PMC_SCRATCH200) = val;
- //PMC(APBDEV_PMC_CRYPTO_OP) = 1; //Disable SE.
- TMR(0x18C) = 0xC45A;
- TMR(0x80) = 0xC0000000;
- TMR(0x180) = 0x8019;
- TMR(0x188) = 1;
- while (1)
- ;
-}
void config_oscillators()
{
@@ -239,99 +218,6 @@ void config_hw()
//TODO: ugly.
gfx_ctxt_t gfx_ctxt;
gfx_con_t gfx_con;
-
-void print_fuseinfo()
-{
- gfx_clear(&gfx_ctxt, 0xFF000000);
- gfx_con_setpos(&gfx_con, 0, 0);
-
- gfx_printf(&gfx_con, "%k(Unlocked) fuse cache:\n\n%k", 0xFFFF9955, 0xFFFFFFFF);
- gfx_hexdump(&gfx_con, 0x7000F900, (u8 *)0x7000F900, 0x2FC);
-
- sleep(100000);
- btn_wait();
-}
-
-void print_kfuseinfo()
-{
- gfx_clear(&gfx_ctxt, 0xFF000000);
- gfx_con_setpos(&gfx_con, 0, 0);
-
- gfx_printf(&gfx_con, "%kKFuse contents:\n\n%k", 0xFFFF9955, 0xFFFFFFFF);
- u32 buf[KFUSE_NUM_WORDS];
- if (!kfuse_read(buf))
- gfx_printf(&gfx_con, "%kCRC fail.\n", 0xFF0000FF);
- else
- gfx_hexdump(&gfx_con, 0, (u8 *)buf, KFUSE_NUM_WORDS * 4);
-
- sleep(100000);
- btn_wait();
-}
-
-void print_tsec_key()
-{
- gfx_clear(&gfx_ctxt, 0xFF000000);
- gfx_con_setpos(&gfx_con, 0, 0);
-
- sdmmc_storage_t storage;
- sdmmc_t sdmmc;
-
- sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
-
- //Read package1.
- u8 *pkg1 = (u8 *)malloc(0x40000);
- sdmmc_storage_set_mmc_partition(&storage, 1);
- sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
- const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
- if (!pkg1_id)
- {
- gfx_printf(&gfx_con, "%kCould not identify package 1 version to read TSEC firmware (= '%s').%k\n", 0xFF0000FF, (char *)pkg1 + 0x10, 0xFFFFFFFF);
- goto out;
- }
-
- for(u32 i = 1; i <= 3; i++)
- {
- u8 key[0x10];
- int res = tsec_query(key, i, pkg1 + pkg1_id->tsec_off);
-
- gfx_printf(&gfx_con, "%kTSEC key %d: %k", 0xFFFF9955, i, 0xFFFFFFFF);
- if (res >= 0)
- {
- for (u32 i = 0; i < 0x10; i++)
- gfx_printf(&gfx_con, "%02X", key[i]);
- }
- else
- gfx_printf(&gfx_con, "%kERROR %X", 0xFF0000FF, res);
- gfx_putc(&gfx_con, '\n');
- }
-
-out:;
- free(pkg1);
- sdmmc_storage_end(&storage);
- sleep(100000);
- btn_wait();
-}
-
-void reboot_normal()
-{
- panic(0x21); //Bypass fuse programming in package1.
-}
-
-void reboot_rcm()
-{
- PMC(APBDEV_PMC_SCRATCH0) = 2; //Reboot into rcm.
- PMC(0) |= 0x10;
- while (1)
- sleep(1);
-}
-
-void power_off()
-{
- //TODO: we should probably make sure all regulators are powered off properly.
- i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF);
-}
-
-//TODO: ugly.
sdmmc_t sd_sdmmc;
sdmmc_storage_t sd_storage;
FATFS sd_fs;
@@ -352,261 +238,30 @@ int sd_mount()
return 0;
}
-void *sd_file_read(char *path)
-{
- FIL fp;
- if (f_open(&fp, path, FA_READ) != FR_OK)
- return NULL;
-
- u32 size = f_size(&fp);
- void *buf = malloc(size);
-
- u8 *ptr = buf;
- while (size > 0)
- {
- u32 rsize = MIN(size, 512);
- if (f_read(&fp, ptr, rsize, NULL) != FR_OK)
- {
- free(buf);
- return NULL;
- }
-
- ptr += rsize;
- size -= rsize;
- }
-
- f_close(&fp);
-
- return buf;
-}
-
-int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
-{
- static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;
- static const u32 MULTIPART_SPLIT_SIZE = (1u << 31);
-
- u32 totalSectors = part->lba_end - part->lba_start + 1;
- char* outFilename = sd_path;
- u32 sdPathLen = strlen(sd_path);
- u32 numSplitParts = 0;
- if ((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT/NX_EMMC_BLOCKSIZE))
- {
- static const u32 MULTIPART_SPLIT_SECTORS = MULTIPART_SPLIT_SIZE/NX_EMMC_BLOCKSIZE;
- numSplitParts = (totalSectors+MULTIPART_SPLIT_SECTORS-1)/MULTIPART_SPLIT_SECTORS;
-
- outFilename = alloca(sdPathLen+4);
- memcpy(outFilename, sd_path, sdPathLen);
- outFilename[sdPathLen++] = '.';
-
- outFilename[sdPathLen] = '0';
- if (numSplitParts >= 10)
- {
- outFilename[sdPathLen+1] = '0';
- outFilename[sdPathLen+2] = 0;
- }
- else
- outFilename[sdPathLen+1] = 0;
- }
-
- FIL fp;
- if (f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
- return 0;
-
- static const u32 NUM_SECTORS_PER_ITER = 512;
- u8 *buf = (u8 *)malloc(NX_EMMC_BLOCKSIZE * NUM_SECTORS_PER_ITER);
-
- u32 lba_curr = part->lba_start;
- u32 bytesWritten = 0;
- u32 currPartIdx = 0;
- u32 prevPct=200;
- while(totalSectors > 0)
- {
- if (numSplitParts != 0 && bytesWritten >= MULTIPART_SPLIT_SIZE)
- {
- f_close(&fp);
- memset(&fp, 0, sizeof(fp));
- currPartIdx++;
-
- if (numSplitParts >= 10 && currPartIdx < 10)
- {
- outFilename[sdPathLen] = '0';
- itoa(currPartIdx, &outFilename[sdPathLen+1], 10);
- }
- else
- itoa(currPartIdx, &outFilename[sdPathLen], 10);
-
- if (f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
- {
- free(buf);
- return 0;
- }
- bytesWritten = 0;
- }
-
- int retryCount=0;
- u32 num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
- while(!sdmmc_storage_read(storage, lba_curr, num, buf))
- {
- gfx_printf(&gfx_con, "%kError reading %d blocks @ LBA %08X (try %d) %k\n",
- 0xFF0000FF, num, lba_curr, ++retryCount, 0xFFFFFFFF);
-
- sleep(500000);
- if (retryCount >= 3)
- goto out;
- }
- f_write(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
- u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
- if (pct != prevPct)
- {
- tui_pbar(&gfx_con, 0, gfx_con.y, pct);
- prevPct = pct;
- }
-
- lba_curr += num;
- totalSectors -= num;
- bytesWritten += num * NX_EMMC_BLOCKSIZE;
-
- //force a flush after a lot of data if not splitting
- if (numSplitParts == 0 && bytesWritten >= MULTIPART_SPLIT_SIZE)
- {
- f_sync(&fp);
- bytesWritten = 0;
- }
- }
- tui_pbar(&gfx_con, 0, gfx_con.y, 100);
-
-out:;
- free(buf);
- f_close(&fp);
- return 1;
-}
-
-typedef enum
-{
- DUMP_BOOT = 1,
- DUMP_SYSTEM = 2,
- DUMP_USER = 4,
- DUMP_RAW = 8
-} dumpType_t;
+void print_header() {
+ static const char switchblade[] =
+ " _____ _ __ __ ____ __ __ \n\n"
+ " / ___/ __(_) /______/ /_ / __ )/ /___ _____/ /__ \n\n"
+ " \\__ \\ | /| / / / __/ ___/ __ \\/ __ / / __ `/ __ / _ \'\n\n"
+ " ___/ / |/ |/ / / /_/ /__/ / / / /_/ / / /_/ / /_/ / __/\n\n"
+ "/____/|__/|__/_/\\__/\\___/_/ /_/_____/_/\\__,_/\\__,_/\\___/ \n\n"
+ " - v1.0 Wicked Fast Hekate Booter Payload (@StevenMattera & @shmadul)\n"
+ "Based on the awesome work of naehrwert, st4rk\n"
+ "Thanks to: derrek, nedwill, plutoo, shuffle2, smea, thexyz, yellows8\n"
+ "Greetings to: fincs, hexkyz, SciresM, Shiny Quagsire, WinterMute\n"
+ "Open source and free packages used:\n"
+ " - FatFs R0.13a (Copyright (C) 2017, ChaN)\n"
+ " - bcl-1.2.0 (Copyright (c) 2003-2006 Marcus Geelnard)\n\n";
-static void dump_emmc_selected(dumpType_t dumpType)
-{
gfx_clear(&gfx_ctxt, 0xFF000000);
gfx_con_setpos(&gfx_con, 0, 0);
- if (!sd_mount())
- {
- gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n", 0xFF0000FF, 0xFFFFFFFF);
- goto out;
- }
-
- sdmmc_storage_t storage;
- sdmmc_t sdmmc;
- if(!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
- {
- gfx_printf(&gfx_con, "%kFailed to init eMMC.%k\n", 0xFF0000FF, 0xFFFFFFFF);
- goto out;
- }
-
- int i = 0;
- if (dumpType & DUMP_BOOT)
- {
- static const u32 BOOT_PART_SIZE = 0x400000;
-
- emmc_part_t bootPart;
- memset(&bootPart, 0, sizeof(bootPart));
- bootPart.lba_start = 0;
- bootPart.lba_end = (BOOT_PART_SIZE/NX_EMMC_BLOCKSIZE)-1;
- for (i=0; i<2; i++)
- {
- memcpy(bootPart.name, "BOOT", 4);
- bootPart.name[4] = (u8)('0' + i);
- bootPart.name[5] = 0;
-
- gfx_printf(&gfx_con, "%02d: %s (%08X-%08X)\n", i,
- bootPart.name, bootPart.lba_start, bootPart.lba_end);
-
- sdmmc_storage_set_mmc_partition(&storage, i+1);
- dump_emmc_part(bootPart.name, &storage, &bootPart);
- gfx_putc(&gfx_con, '\n');
- }
- }
-
- if ((dumpType & DUMP_SYSTEM) || (dumpType & DUMP_USER) || (dumpType & DUMP_RAW))
- {
- sdmmc_storage_set_mmc_partition(&storage, 0);
-
- if ((dumpType & DUMP_SYSTEM) || (dumpType & DUMP_USER))
- {
- LIST_INIT(gpt);
- nx_emmc_gpt_parse(&gpt, &storage);
- LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
- {
- if ((dumpType & DUMP_USER) == 0 && !strcmp(part->name, "USER"))
- continue;
- if ((dumpType & DUMP_SYSTEM) == 0 && strcmp(part->name, "USER"))
- continue;
-
- gfx_printf(&gfx_con, "%02d: %s (%08X-%08X)\n", i++,
- part->name, part->lba_start, part->lba_end);
-
- dump_emmc_part(part->name, &storage, part);
- gfx_putc(&gfx_con, '\n');
- }
- }
-
- if (dumpType & DUMP_RAW)
- {
- static const u32 RAW_AREA_NUM_SECTORS = 0x3A3E000;
-
- emmc_part_t rawPart;
- memset(&rawPart, 0, sizeof(rawPart));
- rawPart.lba_start = 0;
- rawPart.lba_end = RAW_AREA_NUM_SECTORS-1;
- strcpy(rawPart.name, "RawNand.bin");
- {
- gfx_printf(&gfx_con, "%02d: %s (%08X-%08X)\n", i++,
- rawPart.name, rawPart.lba_start, rawPart.lba_end);
-
- dump_emmc_part(rawPart.name, &storage, &rawPart);
- gfx_putc(&gfx_con, '\n');
- }
- }
- }
-
- sdmmc_storage_end(&storage);
- gfx_puts(&gfx_con, "Done.\n");
-
-out:;
- sleep(100000);
- btn_wait();
+ gfx_printf(&gfx_con, switchblade, 0xFFFFCC00, 0xFFFFFFFF,
+ 0xFFFFCC00, 0xFFCCFF00, 0xFFFFCC00, 0xFFFFFFFF);
}
-void dump_emmc_system() { dump_emmc_selected(DUMP_SYSTEM); }
-void dump_emmc_user() { dump_emmc_selected(DUMP_USER); }
-void dump_emmc_boot() { dump_emmc_selected(DUMP_BOOT); }
-void dump_emmc_rawnand() { dump_emmc_selected(DUMP_RAW); }
-
void launch_firmware()
{
- ini_sec_t *cfg_sec = NULL;
- LIST_INIT(ini_sections);
-
-static const char switchblade[] =
- " _____ _ __ __ ____ __ __ \n\n"
- " / ___/ __(_) /______/ /_ / __ )/ /___ _____/ /__ \n\n"
- " \\__ \\ | /| / / / __/ ___/ __ \\/ __ / / __ `/ __ / _ \'\n\n"
- " ___/ / |/ |/ / / /_/ /__/ / / / /_/ / / /_/ / /_/ / __/\n\n"
- "/____/|__/|__/_/\\__/\\___/_/ /_/_____/_/\\__,_/\\__,_/\\___/ \n\n"
- " - v1.0 Wicked Fast Hekate Booter Payload (@StevenMattera & @shmadul)\n\n";
-
- gfx_clear(&gfx_ctxt, 0xFF000000);
- gfx_con_setpos(&gfx_con, 0, 0);
-
- gfx_printf(&gfx_con, switchblade, 0xFFFFCC00, 0xFFFFFFFF,
- 0xFFFFCC00, 0xFFCCFF00, 0xFFFFCC00, 0xFFFFFFFF);
- sleep(1.25);
-
if (sd_mount())
{
if (!hos_launch())
@@ -614,93 +269,8 @@ static const char switchblade[] =
}
else
gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n", 0xFF0000FF, 0xFFFFFFFF);
-
- if (!cfg_sec)
- gfx_printf(&gfx_con, "Using default launch configuration.\n");
-
-out:;
- sleep(200000);
- btn_wait();
-}
-
-void about()
-{
- static const char octopus[] =
- "hekate (c) 2018 naehrwert, st4rk\n\n"
- "Thanks to: %kderrek, nedwill, plutoo, shuffle2, smea, thexyz, yellows8%k\n\n"
- "Greetings to: fincs, hexkyz, SciresM, Shiny Quagsire, WinterMute\n\n"
- "Open source and free packages used:\n"
- " - FatFs R0.13a (Copyright (C) 2017, ChaN)\n"
- " - bcl-1.2.0 (Copyright (c) 2003-2006 Marcus Geelnard)\n\n"
- " %k___\n"
- " .-' `'.\n"
- " / \\\n"
- " | ;\n"
- " | | ___.--,\n"
- " _.._ |0) = (0) | _.---'`__.-( (_.\n"
- " __.--'`_.. '.__.\\ '--. \\_.-' ,.--'` `\"\"`\n"
- " ( ,.--'` ',__ /./; ;, '.__.'` __\n"
- " _`) ) .---.__.' / | |\\ \\__..--\"\" \"\"\"--.,_\n"
- " `---' .'.''-._.-'`_./ /\\ '. \\ _.--''````'''--._`-.__.'\n"
- " | | .' _.-' | | \\ \\ '. `----`\n"
- " \\ \\/ .' \\ \\ '. '-._)\n"
- " \\/ / \\ \\ `=.__`'-.\n"
- " / /\\ `) ) / / `\"\".`\\\n"
- " , _.-'.'\\ \\ / / ( ( / /\n"
- " `--'` ) ) .-'.' '.'. | (\n"
- " (/` ( (` ) ) '-; %k[switchbrew]%k\n"
- " ` '-; (-'%k";
-
- gfx_clear(&gfx_ctxt, 0xFF000000);
- gfx_con_setpos(&gfx_con, 0, 0);
-
- gfx_printf(&gfx_con, octopus, 0xFFFFCC00, 0xFFFFFFFF,
- 0xFFFFCC00, 0xFFCCFF00, 0xFFFFCC00, 0xFFFFFFFF);
-
- sleep(1000000);
- btn_wait();
}
-ment_t ment_cinfo[] = {
- MDEF_BACK(),
- MDEF_HANDLER("Print fuse info", print_fuseinfo),
- MDEF_HANDLER("Print kfuse info", print_kfuseinfo),
- MDEF_HANDLER("Print TSEC keys", print_tsec_key),
- MDEF_END()
-};
-menu_t menu_cinfo = {
- ment_cinfo,
- "Console info", 0, 0
-};
-
-ment_t ment_tools[] = {
- MDEF_BACK(),
- MDEF_HANDLER("Dump eMMC RawNand", dump_emmc_rawnand),
- MDEF_HANDLER("Dump eMMC SYS", dump_emmc_system),
- MDEF_HANDLER("Dump eMMC USER", dump_emmc_user),
- MDEF_HANDLER("Dump eMMC BOOT", dump_emmc_boot),
- MDEF_END()
-};
-menu_t menu_tools = {
- ment_tools,
- "Tools", 0, 0
-};
-
-ment_t ment_top[] = {
- MDEF_HANDLER("Launch firmware", launch_firmware),
- MDEF_MENU("Tools", &menu_tools),
- MDEF_MENU("Console info", &menu_cinfo),
- MDEF_HANDLER("Reboot (normal)", reboot_normal),
- MDEF_HANDLER("Reboot (rcm)", reboot_rcm),
- MDEF_HANDLER("Power off", power_off),
- MDEF_HANDLER("About", about),
- MDEF_END()
-};
-menu_t menu_top = {
- ment_top,
- "hekate - ipl", 0, 0
-};
-
extern void pivot_stack(u32 stack_top);
void ipl_main()
@@ -723,9 +293,6 @@ void ipl_main()
gfx_clear(&gfx_ctxt, 0xFF000000);
gfx_con_init(&gfx_con, &gfx_ctxt);
- while (1)
- launch_firmware();
-
- while (1)
- ;
+ print_header();
+ launch_firmware();
}
diff --git a/ipl/main.o b/ipl/main.o
deleted file mode 100644
index b70ae21..0000000
Binary files a/ipl/main.o and /dev/null differ
diff --git a/ipl/max7762x.o b/ipl/max7762x.o
deleted file mode 100644
index feb71ed..0000000
Binary files a/ipl/max7762x.o and /dev/null differ
diff --git a/ipl/mc.o b/ipl/mc.o
deleted file mode 100644
index cc4c65c..0000000
Binary files a/ipl/mc.o and /dev/null differ
diff --git a/ipl/nx_emmc.o b/ipl/nx_emmc.o
deleted file mode 100644
index 4cd93f2..0000000
Binary files a/ipl/nx_emmc.o and /dev/null differ
diff --git a/ipl/pinmux.o b/ipl/pinmux.o
deleted file mode 100644
index 12c0e2e..0000000
Binary files a/ipl/pinmux.o and /dev/null differ
diff --git a/ipl/pkg1.c b/ipl/pkg1.c
index b2b60cb..be00348 100644
--- a/ipl/pkg1.c
+++ b/ipl/pkg1.c
@@ -39,12 +39,22 @@ PATCHSET_DEF(_secmon_2_patchset,
{ 0xAC8 + 0xB3C, _NOP() }, //Version.
{ 0xAC8 + 0xB58, _NOP() } //Sections SHA2.
);
+
+PATCHSET_DEF(_secmon_5_patchset,
+ //Patch package2 decryption and signature/hash checks.
+ { 0x1218 + 0x6E68, _NOP() }, //Header signature.
+ { 0x1218 + 0x6E74, _NOP() }, //Version.
+ { 0x1218 + 0x6FE4, _NOP() }, //Sections SHA2.
+ { 0x1218 + 0x2DC, _NOP() } //Unknown.
+);
+
PATCHSET_DEF(_secmon_6_patchset,
- { 0x12b0 + 0x4d0, _NOP() },
- { 0x12b0 + 0x4dc, _NOP() },
- { 0x12b0 + 0x794, _NOP() },
- { 0x12b0 + 0xb30, _NOP() }//,
- //{ 0x12b0 + 0xa18 , _NOP() } // BootConfig Retail Check
+ //Patch package2 decryption and signature/hash checks.
+ { 0x12B0 + 0x4D0, _NOP() }, //Header signature.
+ { 0x12B0 + 0x4DC, _NOP() }, //Version.
+ { 0x12B0 + 0x794, _NOP() }, //Sections SHA2.
+ { 0x12B0 + 0xB30, _NOP() } /*,*/ //Unknown.
+ //{ 0x12B0 + 0xA18 , _NOP() } // BootConfig Retail Check
);
/*
@@ -63,7 +73,7 @@ static const pkg1_id_t _pkg1_ids[] = {
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, _secmon_2_patchset }, //2.0.0
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, NULL }, //3.0.0
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, NULL }, //3.0.1
- { "20170921172629", 3, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, NULL }, //4.0.0
+ { "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, _secmon_5_patchset }, //4.0.0
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, _secmon_6_patchset }, //5.0.0
{ NULL, 0, 0, 0, 0 } //End.
};
diff --git a/ipl/pkg1.o b/ipl/pkg1.o
deleted file mode 100644
index ba3a1de..0000000
Binary files a/ipl/pkg1.o and /dev/null differ
diff --git a/ipl/pkg2.o b/ipl/pkg2.o
deleted file mode 100644
index 8c583ef..0000000
Binary files a/ipl/pkg2.o and /dev/null differ
diff --git a/ipl/sdmmc.o b/ipl/sdmmc.o
deleted file mode 100644
index c1fb19d..0000000
Binary files a/ipl/sdmmc.o and /dev/null differ
diff --git a/ipl/sdmmc_driver.o b/ipl/sdmmc_driver.o
deleted file mode 100644
index b97ef28..0000000
Binary files a/ipl/sdmmc_driver.o and /dev/null differ
diff --git a/ipl/sdram.o b/ipl/sdram.o
deleted file mode 100644
index 86da92f..0000000
Binary files a/ipl/sdram.o and /dev/null differ
diff --git a/ipl/sdram_lp0.o b/ipl/sdram_lp0.o
deleted file mode 100644
index 181b6b1..0000000
Binary files a/ipl/sdram_lp0.o and /dev/null differ
diff --git a/ipl/tui.c b/ipl/tui.c
deleted file mode 100644
index ef3aff1..0000000
--- a/ipl/tui.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*{
-* Copyright (c) 2018 naehrwert
-*
-* 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 .
-*/
-
-#include "tui.h"
-#include "btn.h"
-
-void tui_pbar(gfx_con_t *con, int x, int y, u32 val)
-{
- u32 cx, cy;
-
- gfx_con_getpos(con, &cx, &cy);
-
- gfx_con_setpos(con, x, y);
-
- gfx_printf(con, "[%3d%%]", val);
-
- x += 7 * 8;
-
- for (int i = 0; i < 6; i++)
- {
- gfx_line(con->gfx_ctxt, x, y + i + 1, x + 3 * val, y + i + 1, 0xFFFFFFFF);
- gfx_line(con->gfx_ctxt, x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, 0xFF888888);
- }
-
- gfx_con_setpos(con, cx, cy);
-}
-
-void *tui_do_menu(gfx_con_t *con, menu_t *menu)
-{
- int idx = 0, cnt;
-
- gfx_clear(con->gfx_ctxt, 0xFF000000);
-
- while (1)
- {
- gfx_con_setcol(con, 0xFFFFFFFF, 1, 0xFF000000);
- gfx_con_setpos(con, menu->x, menu->y);
- gfx_printf(con, "[%s]\n\n", menu->caption);
-
- for (cnt = 0; menu->ents[cnt].type != MENT_END; cnt++)
- {
- if (cnt == idx)
- gfx_con_setcol(con, 0xFF000000, 1, 0xFFCCCCCC);
- else
- gfx_con_setcol(con, 0xFFFFFFFF, 1, 0xFF000000);
- con->x += 8;
- gfx_printf(con, "%s", menu->ents[cnt].caption);
- if(menu->ents[cnt].type == MENT_MENU)
- gfx_printf(con, "%k...", 0xFFEE9900);
- gfx_putc(con, '\n');
- }
-
- gfx_con_setcol(con, 0xFFFFFFFF, 1, 0xFF000000);
- gfx_putc(con, '\n');
-
- u32 btn = btn_wait();
-
- if (btn & BTN_VOL_DOWN && idx < cnt - 1)
- idx++;
- if (btn & BTN_VOL_UP && idx > 0)
- idx--;
- if (btn & BTN_POWER)
- {
- ment_t *ent = &menu->ents[idx];
- switch (ent->type)
- {
- case MENT_HANDLER:
- ent->handler(ent->data);
- break;
- case MENT_MENU:
- return tui_do_menu(con, ent->menu);
- break;
- case MENT_CHOICE:
- return ent->data;
- break;
- case MENT_BACK:
- return NULL;
- break;
- }
- gfx_clear(con->gfx_ctxt, 0xFF000000);
- }
- }
-
- return NULL;
-}
diff --git a/ipl/tui.h b/ipl/tui.h
deleted file mode 100644
index 6b1f2df..0000000
--- a/ipl/tui.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-* Copyright (c) 2018 naehrwert
-*
-* 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 .
-*/
-
-#ifndef _TUI_H_
-#define _TUI_H_
-
-#include "types.h"
-#include "gfx.h"
-
-#define MENT_END 0
-#define MENT_HANDLER 1
-#define MENT_MENU 2
-#define MENT_CHOICE 3
-#define MENT_BACK 4
-
-typedef struct _ment_t
-{
- u32 type;
- const char *caption;
- void *data;
- union
- {
- void(*handler)(void *);
- struct _menu_t *menu;
- };
-} ment_t;
-
-typedef struct _menu_t
-{
- ment_t *ents;
- const char *caption;
- u32 x;
- u32 y;
-} menu_t;
-
-#define MDEF_END() {MENT_END}
-#define MDEF_HANDLER(caption, _handler) { MENT_HANDLER, caption, NULL, { .handler = _handler } }
-#define MDEF_HANDLER_EX(caption, data, _handler) { MENT_HANDLER, caption, data, { .handler = _handler } }
-#define MDEF_MENU(caption, _menu) { MENT_MENU, caption, NULL, { .menu = _menu } }
-#define MDEF_BACK() { MENT_BACK, "Back" }
-
-void tui_pbar(gfx_con_t *con, int x, int y, u32 val);
-void *tui_do_menu(gfx_con_t *con, menu_t *menu);
-
-#endif