mirror of
https://github.com/CTCaer/hekate
synced 2024-12-22 11:21:23 +00:00
Small fixes and whitespace
Additionally make info functions smaller and show available fuses.
This commit is contained in:
parent
e105634b0d
commit
4ae42c3a9d
10 changed files with 46 additions and 29 deletions
|
@ -54,6 +54,9 @@ extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_st
|
||||||
#define WPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
|
#define WPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
|
||||||
#define WPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
|
#define WPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
|
||||||
|
|
||||||
|
#pragma GCC push_options
|
||||||
|
#pragma GCC optimize ("Os")
|
||||||
|
|
||||||
void print_fuseinfo()
|
void print_fuseinfo()
|
||||||
{
|
{
|
||||||
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
|
||||||
|
@ -77,7 +80,7 @@ void print_fuseinfo()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gfx_printf(&gfx_con, "Sdram ID: %d\n", (fuse_read_odm(4) >> 3) & 0x1F);
|
gfx_printf(&gfx_con, "Sdram ID: %d\n", (fuse_read_odm(4) >> 3) & 0x1F);
|
||||||
gfx_printf(&gfx_con, "Burnt fuses: %d\n", burntFuses);
|
gfx_printf(&gfx_con, "Burnt fuses: %d / 64\n", burntFuses);
|
||||||
gfx_printf(&gfx_con, "Secure key: %08X%08X%08X%08X\n\n\n",
|
gfx_printf(&gfx_con, "Secure key: %08X%08X%08X%08X\n\n\n",
|
||||||
byte_swap_32(FUSE(FUSE_PRIVATE_KEY0)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY1)),
|
byte_swap_32(FUSE(FUSE_PRIVATE_KEY0)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY1)),
|
||||||
byte_swap_32(FUSE(FUSE_PRIVATE_KEY2)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY3)));
|
byte_swap_32(FUSE(FUSE_PRIVATE_KEY2)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY3)));
|
||||||
|
@ -704,3 +707,6 @@ void bootrom_ipatches_info()
|
||||||
btn_wait();
|
btn_wait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma GCC pop_options
|
||||||
|
|
||||||
|
|
|
@ -553,8 +553,10 @@ void fix_battery_desync()
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
//#include "../modules/hekate_libsys_minerva/mtc.h"
|
#include "../modules/hekate_libsys_minerva/mtc.h"
|
||||||
//mtc_config_t mtc_cfg;
|
#include "../ianos/ianos.h"
|
||||||
|
#include "../soc/fuse.h"
|
||||||
|
mtc_config_t mtc_cfg;
|
||||||
|
|
||||||
void minerva()
|
void minerva()
|
||||||
{
|
{
|
||||||
|
@ -582,6 +584,9 @@ void minerva()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Change DRAM voltage.
|
||||||
|
//i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD1, 42); //40 = (1000 * 1100 - 600000) / 12500 -> 1.1V
|
||||||
|
|
||||||
mtc_cfg.rate_from = mtc_cfg.mtc_table[curr_ram_idx].rate_khz;
|
mtc_cfg.rate_from = mtc_cfg.mtc_table[curr_ram_idx].rate_khz;
|
||||||
mtc_cfg.rate_to = 800000;
|
mtc_cfg.rate_to = 800000;
|
||||||
mtc_cfg.train_mode = OP_TRAIN_SWITCH;
|
mtc_cfg.train_mode = OP_TRAIN_SWITCH;
|
||||||
|
@ -590,7 +595,7 @@ void minerva()
|
||||||
|
|
||||||
// Thefollowing frequency needs periodic training every 100ms.
|
// Thefollowing frequency needs periodic training every 100ms.
|
||||||
//msleep(200);
|
//msleep(200);
|
||||||
|
|
||||||
//mtc_cfg.rate_to = 1600000;
|
//mtc_cfg.rate_to = 1600000;
|
||||||
//gfx_printf(&gfx_con, "Training and switching %7d -> %7d\n\n", mtc_cfg.current_emc_table->rate_khz, 1600000);
|
//gfx_printf(&gfx_con, "Training and switching %7d -> %7d\n\n", mtc_cfg.current_emc_table->rate_khz, 1600000);
|
||||||
//ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);
|
//ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);
|
||||||
|
|
|
@ -23,5 +23,6 @@ void fix_sd_all_attr();
|
||||||
void fix_sd_nin_attr();
|
void fix_sd_nin_attr();
|
||||||
void fix_battery_desync();
|
void fix_battery_desync();
|
||||||
void menu_autorcm();
|
void menu_autorcm();
|
||||||
|
//void minerva();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -238,6 +238,10 @@
|
||||||
#define DC_WINBUF_ADDR_H_OFFSET 0x806
|
#define DC_WINBUF_ADDR_H_OFFSET 0x806
|
||||||
#define DC_WINBUF_ADDR_V_OFFSET 0x808
|
#define DC_WINBUF_ADDR_V_OFFSET 0x808
|
||||||
#define DC_WINBUF_SURFACE_KIND 0x80B
|
#define DC_WINBUF_SURFACE_KIND 0x80B
|
||||||
|
#define PITCH (0 << 0)
|
||||||
|
#define TILED (1 << 0)
|
||||||
|
#define BLOCK (2 << 0)
|
||||||
|
#define BLOCK_HEIGHT(x) (((x) & 0x7) << 4)
|
||||||
|
|
||||||
/*! Display serial interface registers. */
|
/*! Display serial interface registers. */
|
||||||
#define _DSIREG(reg) ((reg) * 4)
|
#define _DSIREG(reg) ((reg) * 4)
|
||||||
|
|
|
@ -15,13 +15,12 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "di.h"
|
||||||
#include "tui.h"
|
#include "tui.h"
|
||||||
#include "../utils/btn.h"
|
#include "../utils/btn.h"
|
||||||
#include "../config/config.h"
|
#include "../config/config.h"
|
||||||
#include "../power/max17050.h"
|
#include "../power/max17050.h"
|
||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
#include "../config/config.h"
|
|
||||||
#include "di.h"
|
|
||||||
|
|
||||||
#ifdef MENU_LOGO_ENABLE
|
#ifdef MENU_LOGO_ENABLE
|
||||||
extern u8 *Kc_MENU_LOGO;
|
extern u8 *Kc_MENU_LOGO;
|
||||||
|
|
|
@ -503,7 +503,9 @@ int hos_launch(ini_sec_t *cfg)
|
||||||
{
|
{
|
||||||
gfx_printf(&gfx_con, "%kREQUESTED PATCH '%s' NOT APPLIED!%k\n", 0xFFFF0000, unappliedPatch, 0xFFCCCCCC);
|
gfx_printf(&gfx_con, "%kREQUESTED PATCH '%s' NOT APPLIED!%k\n", 0xFFFF0000, unappliedPatch, 0xFFCCCCCC);
|
||||||
sd_unmount(); // Just exiting is not enough until pkg2_patch_kips stops modifying the string passed into it.
|
sd_unmount(); // Just exiting is not enough until pkg2_patch_kips stops modifying the string passed into it.
|
||||||
while(1) {} // MUST stop here, because if user requests 'nogc' but it's not applied, their GC controller gets updated!
|
|
||||||
|
_free_launch_components(&ctxt);
|
||||||
|
return 0; // MUST stop here, because if user requests 'nogc' but it's not applied, their GC controller gets updated!
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rebuild and encrypt package2.
|
// Rebuild and encrypt package2.
|
||||||
|
|
|
@ -571,7 +571,7 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
|
||||||
memcpy(&hdr, ki->kip1, sizeof(hdr));
|
memcpy(&hdr, ki->kip1, sizeof(hdr));
|
||||||
|
|
||||||
unsigned int newKipSize = sizeof(hdr);
|
unsigned int newKipSize = sizeof(hdr);
|
||||||
for (u32 sectIdx=0; sectIdx<KIP1_NUM_SECTIONS; sectIdx++)
|
for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++)
|
||||||
{
|
{
|
||||||
u32 sectCompBit = 1u << sectIdx;
|
u32 sectCompBit = 1u << sectIdx;
|
||||||
// For compressed, cant get actual decompressed size without doing it, so use safe "output size".
|
// For compressed, cant get actual decompressed size without doing it, so use safe "output size".
|
||||||
|
@ -584,7 +584,7 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
|
||||||
pkg2_kip1_t* newKip = malloc(newKipSize);
|
pkg2_kip1_t* newKip = malloc(newKipSize);
|
||||||
unsigned char* dstDataPtr = newKip->data;
|
unsigned char* dstDataPtr = newKip->data;
|
||||||
const unsigned char* srcDataPtr = ki->kip1->data;
|
const unsigned char* srcDataPtr = ki->kip1->data;
|
||||||
for (u32 sectIdx=0; sectIdx<KIP1_NUM_SECTIONS; sectIdx++)
|
for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++)
|
||||||
{
|
{
|
||||||
u32 sectCompBit = 1u << sectIdx;
|
u32 sectCompBit = 1u << sectIdx;
|
||||||
// Easy copy path for uncompressed or ones we dont want to uncompress.
|
// Easy copy path for uncompressed or ones we dont want to uncompress.
|
||||||
|
@ -638,7 +638,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||||
static const u32 MAX_NUM_PATCHES_REQUESTED = sizeof(u32)*8;
|
static const u32 MAX_NUM_PATCHES_REQUESTED = sizeof(u32)*8;
|
||||||
char* patches[MAX_NUM_PATCHES_REQUESTED];
|
char* patches[MAX_NUM_PATCHES_REQUESTED];
|
||||||
|
|
||||||
u32 numPatches=1;
|
u32 numPatches = 1;
|
||||||
patches[0] = patchNames;
|
patches[0] = patchNames;
|
||||||
{
|
{
|
||||||
for (char* p = patchNames; *p != 0; p++)
|
for (char* p = patchNames; *p != 0; p++)
|
||||||
|
@ -646,7 +646,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||||
if (*p == ',')
|
if (*p == ',')
|
||||||
{
|
{
|
||||||
*p = 0;
|
*p = 0;
|
||||||
patches[numPatches++] = p+1;
|
patches[numPatches++] = p + 1;
|
||||||
if (numPatches >= MAX_NUM_PATCHES_REQUESTED)
|
if (numPatches >= MAX_NUM_PATCHES_REQUESTED)
|
||||||
return "too_many_patches";
|
return "too_many_patches";
|
||||||
}
|
}
|
||||||
|
@ -656,10 +656,10 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 patchesApplied = 0; // Bitset over patches.
|
u32 patchesApplied = 0; // Bitset over patches.
|
||||||
for (u32 i=0; i<numPatches; i++)
|
for (u32 i = 0; i < numPatches; i++)
|
||||||
{
|
{
|
||||||
// Eliminate leading spaces.
|
// Eliminate leading spaces.
|
||||||
for (const char* p=patches[i]; *p!=0; p++)
|
for (const char* p = patches[i]; *p != 0; p++)
|
||||||
{
|
{
|
||||||
if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
|
if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
|
||||||
patches[i]++;
|
patches[i]++;
|
||||||
|
@ -671,7 +671,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Eliminate trailing spaces.
|
// Eliminate trailing spaces.
|
||||||
for (int chIdx=valueLen-1; chIdx>=0; chIdx--)
|
for (int chIdx=valueLen - 1; chIdx >= 0; chIdx--)
|
||||||
{
|
{
|
||||||
const char* p = patches[i] + chIdx;
|
const char* p = patches[i] + chIdx;
|
||||||
if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
|
if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
|
||||||
|
@ -684,11 +684,11 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||||
DPRINTF("Requested patch: '%s'\n", patches[i]);
|
DPRINTF("Requested patch: '%s'\n", patches[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 shaBuf[32/sizeof(u32)];
|
u32 shaBuf[32 / sizeof(u32)];
|
||||||
LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link)
|
LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link)
|
||||||
{
|
{
|
||||||
shaBuf[0] = 0; // sha256 for this kip not yet calculated.
|
shaBuf[0] = 0; // sha256 for this kip not yet calculated.
|
||||||
for (u32 currKipIdx=0; currKipIdx<(sizeof(_kip_ids)/sizeof(_kip_ids[0])); currKipIdx++)
|
for (u32 currKipIdx = 0; currKipIdx < (sizeof(_kip_ids) / sizeof(_kip_ids[0])); currKipIdx++)
|
||||||
{
|
{
|
||||||
if (strncmp((const char*)ki->kip1->name, _kip_ids[currKipIdx].name, sizeof(ki->kip1->name)) != 0)
|
if (strncmp((const char*)ki->kip1->name, _kip_ids[currKipIdx].name, sizeof(ki->kip1->name)) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
@ -697,7 +697,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||||
kip1_patchset_t* currPatchset = _kip_ids[currKipIdx].patchset;
|
kip1_patchset_t* currPatchset = _kip_ids[currKipIdx].patchset;
|
||||||
while (currPatchset != NULL && currPatchset->name != NULL)
|
while (currPatchset != NULL && currPatchset->name != NULL)
|
||||||
{
|
{
|
||||||
for (u32 i=0; i<numPatches; i++)
|
for (u32 i = 0; i < numPatches; i++)
|
||||||
{
|
{
|
||||||
if (strcmp(currPatchset->name, patches[i]) != 0)
|
if (strcmp(currPatchset->name, patches[i]) != 0)
|
||||||
{
|
{
|
||||||
|
@ -728,7 +728,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||||
{
|
{
|
||||||
if (currPatchset->patches != NULL)
|
if (currPatchset->patches != NULL)
|
||||||
{
|
{
|
||||||
for (u32 currEnabIdx=0; currEnabIdx<numPatches; currEnabIdx++)
|
for (u32 currEnabIdx = 0; currEnabIdx < numPatches; currEnabIdx++)
|
||||||
{
|
{
|
||||||
if (strcmp(currPatchset->name, patches[currEnabIdx]))
|
if (strcmp(currPatchset->name, patches[currEnabIdx]))
|
||||||
continue;
|
continue;
|
||||||
|
@ -752,13 +752,13 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||||
if (!se_calc_sha256(shaBuf, ki->kip1, ki->size))
|
if (!se_calc_sha256(shaBuf, ki->kip1, ki->size))
|
||||||
memset(shaBuf, 0, sizeof(shaBuf));
|
memset(shaBuf, 0, sizeof(shaBuf));
|
||||||
|
|
||||||
DPRINTF("%dms %s KIP1 size %d hash %08X\n", (postDecompTime-preDecompTime)/1000, ki->kip1->name, (int)ki->size, __builtin_bswap32(shaBuf[0]));
|
DPRINTF("%dms %s KIP1 size %d hash %08X\n", (postDecompTime-preDecompTime) / 1000, ki->kip1->name, (int)ki->size, __builtin_bswap32(shaBuf[0]));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
currPatchset = _kip_ids[currKipIdx].patchset;
|
currPatchset = _kip_ids[currKipIdx].patchset;
|
||||||
while (currPatchset != NULL && currPatchset->name != NULL)
|
while (currPatchset != NULL && currPatchset->name != NULL)
|
||||||
{
|
{
|
||||||
for (u32 currEnabIdx=0; currEnabIdx<numPatches; currEnabIdx++)
|
for (u32 currEnabIdx = 0; currEnabIdx < numPatches; currEnabIdx++)
|
||||||
{
|
{
|
||||||
if (strcmp(currPatchset->name, patches[currEnabIdx]))
|
if (strcmp(currPatchset->name, patches[currEnabIdx]))
|
||||||
continue;
|
continue;
|
||||||
|
@ -772,7 +772,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char* kipSectData = ki->kip1->data;
|
unsigned char* kipSectData = ki->kip1->data;
|
||||||
for (u32 currSectIdx=0; currSectIdx<KIP1_NUM_SECTIONS; currSectIdx++)
|
for (u32 currSectIdx = 0; currSectIdx < KIP1_NUM_SECTIONS; currSectIdx++)
|
||||||
{
|
{
|
||||||
if (bitsAffected & (1u << currSectIdx))
|
if (bitsAffected & (1u << currSectIdx))
|
||||||
{
|
{
|
||||||
|
@ -806,7 +806,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 i=0; i<numPatches; i++)
|
for (u32 i = 0; i < numPatches; i++)
|
||||||
{
|
{
|
||||||
if ((patchesApplied & (1u << i)) == 0)
|
if ((patchesApplied & (1u << i)) == 0)
|
||||||
return patches[i];
|
return patches[i];
|
||||||
|
|
|
@ -84,7 +84,7 @@ void ianos_print_error(int errorno)
|
||||||
gfx_printf(&gfx_con, "Error loading ELF!\n");
|
gfx_printf(&gfx_con, "Error loading ELF!\n");
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
gfx_printf(&gfx_con, "Error relcating ELF!\n");
|
gfx_printf(&gfx_con, "Error relocating ELF!\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -509,7 +509,7 @@ sdram_params_t *sdram_get_params()
|
||||||
* If the boot_rom_patch_control's MSB is set, it uses it as an index to
|
* If the boot_rom_patch_control's MSB is set, it uses it as an index to
|
||||||
* APB_MISC_BASE (u32 array) and sets it to the value of boot_rom_patch_data.
|
* APB_MISC_BASE (u32 array) and sets it to the value of boot_rom_patch_data.
|
||||||
* (The MSB falls out when it gets multiplied by sizeof(u32)).
|
* (The MSB falls out when it gets multiplied by sizeof(u32)).
|
||||||
* Because the bootrom does not do any the boundary checks, it lets us write anywhere and anything.
|
* Because the bootrom does not do any boundary checks, it lets us write anywhere and anything.
|
||||||
* Ipatch hardware let us apply 12 changes to the bootrom and can be changed any time.
|
* Ipatch hardware let us apply 12 changes to the bootrom and can be changed any time.
|
||||||
* The first patch is not needed any more when the exploit is triggered, so we overwrite that.
|
* The first patch is not needed any more when the exploit is triggered, so we overwrite that.
|
||||||
* 0x10459E is the address where it returns an error when the signature is not valid.
|
* 0x10459E is the address where it returns an error when the signature is not valid.
|
||||||
|
|
|
@ -22,11 +22,11 @@
|
||||||
/* clock_t: reset, enable, source, index, clk_src, clk_div */
|
/* clock_t: reset, enable, source, index, clk_src, clk_div */
|
||||||
|
|
||||||
static const clock_t _clock_uart[] = {
|
static const clock_t _clock_uart[] = {
|
||||||
/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 0 },
|
/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 0 },
|
||||||
/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 0 },
|
/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 0 },
|
||||||
/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 0x17, 0, 0 },
|
/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 0x17, 0, 0 },
|
||||||
/* UART D */ { 0 },
|
/* UART D */ { 0 },
|
||||||
/* UART E */ { 0 }
|
/* UART E */ { 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const clock_t _clock_i2c[] = {
|
static const clock_t _clock_i2c[] = {
|
||||||
|
|
Loading…
Reference in a new issue