From abee7fe14b747c3c258d88187c4cc96b1b56990b Mon Sep 17 00:00:00 2001 From: Mateico <116546494+mateicoes@users.noreply.github.com> Date: Sat, 25 Apr 2026 18:47:24 +0200 Subject: [PATCH] cleaning + notifications + autosleep --- include/loader.h | 1 - include/utils.h | 17 +++++++---------- shellcode_hypervisor/main.c | 12 ++++++------ shellcode_hypervisor/utils.c | 4 ++-- shellcode_kernel/kernel_code.c | 11 +++++------ shellcode_kernel/kernel_code.h | 6 ------ shellcode_kernel/main.c | 29 +++++++++++++++-------------- shellcode_kernel/main.h | 17 +++++++---------- shellcode_kernel/utils.c | 4 ++-- source/loader.c | 19 ++++++++----------- source/main.c | 17 ++++++++++------- source/offsets.c | 9 --------- source/utils.c | 33 ++++++++++++++++++++++++++++++++- 13 files changed, 94 insertions(+), 85 deletions(-) diff --git a/include/loader.h b/include/loader.h index b8b91e8..2fac189 100644 --- a/include/loader.h +++ b/include/loader.h @@ -7,5 +7,4 @@ static void install_page(uintptr_t pml4, vm_offset_t va, vm_paddr_t pa, void pte_store(uintptr_t ptep, uint64_t pte); static int read_file(const char *path, void *buf, size_t bufsize); static void trim_newline(char *s); -static size_t fetch_file(int port, void *buf, size_t bufsize); int fetch_linux(struct linux_info *info); diff --git a/include/utils.h b/include/utils.h index ee3855a..e6a3f3c 100644 --- a/include/utils.h +++ b/include/utils.h @@ -9,6 +9,10 @@ int sceKernelGetCurrentCpu(); int sceKernelSendNotificationRequest(int, void *, size_t, int); +int sceKernelOpenEventFlag(void*, const char *); +int sceKernelNotifySystemSuspendStart(void); +int sceKernelSetEventFlag(void *, int); +int sceKernelCloseEventFlag(void*); typedef struct _sysent { uint32_t n_arg; @@ -142,16 +146,9 @@ uint64_t get_pml4(uint64_t pmap); int pin_to_core(int n); int pin_to_first_available_core(void); void unpin(void); -static inline void notify(uint8_t *msg) { - struct { - char pad[45]; - char msg[3075]; - } req; - uint64_t len = - strlen(msg) < (sizeof(req.msg) - 1) ? strlen(msg) : (sizeof(req.msg) - 1); - memcpy(req.msg, msg, len); - sceKernelSendNotificationRequest(0, &req, sizeof(req), 0); -} +void notify(const char *fmt, ...); +void notify_internal(uint8_t *msg); +void enter_rest_mode(void); #if DEBUG #define DEBUG_PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__) diff --git a/shellcode_hypervisor/main.c b/shellcode_hypervisor/main.c index 4028c1e..8cd8ebe 100644 --- a/shellcode_hypervisor/main.c +++ b/shellcode_hypervisor/main.c @@ -1,12 +1,12 @@ -#include "main.h" -#include "../include/config.h" -#include "boot_linux.h" -#include "utils.h" +#include #include #include #include #include -#include +#include "main.h" +#include "../include/config.h" +#include "boot_linux.h" +#include "utils.h" __attribute__((section(".entry_point"), naked)) uint32_t main(void) { @@ -31,7 +31,7 @@ __attribute__((section(".entry_point"), naked)) uint32_t main(void) { "movq %%rsp, %%rbp \n\t" : : "r"(new_rsp) - : "rsp", "rbp", "memory"); + : "rbp", "memory"); entry(); } \ No newline at end of file diff --git a/shellcode_hypervisor/utils.c b/shellcode_hypervisor/utils.c index 2c0d2d7..2d5c44c 100644 --- a/shellcode_hypervisor/utils.c +++ b/shellcode_hypervisor/utils.c @@ -5,8 +5,8 @@ extern shellcode_hypervisor_args args; __attribute__((noinline, optimize("O0"))) uint32_t putc_uart(uint8_t tx_byte) { - volatile uint32_t *uart_tx = 0xc1010104ULL; - volatile uint32_t *uart_busy = 0xc101010cULL; + volatile uint32_t *uart_tx = (volatile uint32_t *) 0xc1010104ULL; + volatile uint32_t *uart_busy = (volatile uint32_t *) 0xc101010cULL; uint64_t timeout = 0xFFFFFFFF; do { timeout--; diff --git a/shellcode_kernel/kernel_code.c b/shellcode_kernel/kernel_code.c index fcdffbd..1c0b145 100644 --- a/shellcode_kernel/kernel_code.c +++ b/shellcode_kernel/kernel_code.c @@ -117,8 +117,7 @@ static void patch_hv(void) { } // Install hv_shellcode 2 - uint64_t hv_shellcode = cave_hv; - memcpy((void *)PHYS_TO_DMAP(hv_shellcode), shellcode_hypervisor, + memcpy((void *)PHYS_TO_DMAP(cave_hv_code), shellcode_hypervisor, shellcode_hypervisor_len); // Jump to shellcode final identity mapping @@ -130,8 +129,8 @@ static void patch_hv(void) { // Update code cave in hv 1:1 region *(uint32_t *)(&shellcode_jmp[3]) = (uint32_t)args.hv_code_cave_pa; - // Just patch the VMEXIT handler directly, avoiding all checks (0x6282b45d) - memcpy(PHYS_TO_DMAP(args.hv_handle_vmexit_pa), shellcode_jmp, + // Just patch the VMEXIT handler directly, avoiding all checks + memcpy((void *)PHYS_TO_DMAP(args.hv_handle_vmexit_pa), shellcode_jmp, sizeof(shellcode_jmp)); uint8_t shellcode_identity_and_jmp[] = { @@ -149,7 +148,7 @@ static void patch_hv(void) { *(uint64_t *)(&shellcode_identity_and_jmp[15]) = cave_hv_code; // Install shellcode 1 to update CR3 and jump to main HV shellcode - memcpy(PHYS_TO_DMAP(args.hv_code_cave_pa), shellcode_identity_and_jmp, + memcpy((void *)PHYS_TO_DMAP(args.hv_code_cave_pa), shellcode_identity_and_jmp, sizeof(shellcode_identity_and_jmp)); } @@ -157,7 +156,7 @@ void boot_linux(void) { patch_hv(); - memcpy((void *)PHYS_TO_DMAP(0xC0000), g_vbios, 0x10000); + memcpy((void *)PHYS_TO_DMAP(0xC0000), (void *)g_vbios, 0x10000); // Enable DP phys link. dp_enable_link_phy(4, 30); diff --git a/shellcode_kernel/kernel_code.h b/shellcode_kernel/kernel_code.h index 72f9378..5f72a62 100644 --- a/shellcode_kernel/kernel_code.h +++ b/shellcode_kernel/kernel_code.h @@ -3,12 +3,6 @@ #include -#define cave 0x100000000ULL -#define cave_hv_paging cave -#define cave_hv cave_hv_paging + 0x3000 -#define cave_linux cave_hv + 0x2000 - -#define PAGE_SIZE 4096 #define ALIGN_UP(size, align) (((size) + (align) - 1) & ~((align) - 1)) static int dp_enable_link_phy(int lanenum, int linkrate); diff --git a/shellcode_kernel/main.c b/shellcode_kernel/main.c index 98b9d68..5a1835c 100644 --- a/shellcode_kernel/main.c +++ b/shellcode_kernel/main.c @@ -55,7 +55,7 @@ __attribute__((section(".entry_point"))) uint32_t main(uint64_t add1, // Reconfigure IOMMU calling the HV int ret = ((uint64_t(*)(uint64_t, uint64_t, uint64_t, uint64_t, int *))args_ptr->fun_hv_iommu_set_buffers)( - iommu_cb2_pa, iommu_cb3_pa, iommu_eb_pa, &unk, &n_devices); + iommu_cb2_pa, iommu_cb3_pa, iommu_eb_pa, (uint64_t) &unk, &n_devices); if (ret != 0) { putc_uart(args_ptr->dmap_base, 'I'); @@ -126,7 +126,7 @@ __attribute__((section(".entry_point"))) uint32_t main(uint64_t add1, // Re-do this to force a VMEXIT without HV injecting faults ((uint64_t(*)(uint64_t, uint64_t, uint64_t, uint64_t, int *))args_ptr->fun_hv_iommu_set_buffers)( - iommu_cb2_pa, iommu_cb3_pa, iommu_eb_pa, &unk, &n_devices); + iommu_cb2_pa, iommu_cb3_pa, iommu_eb_pa, (uint64_t) &unk, &n_devices); ((uint64_t(*)(void))args_ptr->fun_hv_iommu_wait_completion)(); putc_uart(args_ptr->dmap_base, 'B'); @@ -195,7 +195,7 @@ void halt(void) { __asm__ __volatile__("hlt"); } // Submit a single 16-byte command and wait for completion __attribute__((noinline, optimize("O0"))) void -iommu_submit_cmd(shellcode_kernel_args *args_ptr, uint64_t *cmd) { +iommu_submit_cmd(volatile shellcode_kernel_args *args_ptr, uint64_t *cmd) { // Read the offset of current tail of command list uint64_t curr_tail = *( (uint64_t *)args_ptr->iommu_mmio_va + @@ -206,7 +206,7 @@ iommu_submit_cmd(shellcode_kernel_args *args_ptr, uint64_t *cmd) { // We write the command in the current empty entry uint64_t *cmd_buffer = - args_ptr->iommu_cb2_va + curr_tail / 8; // Downscale the size of the ptr + (uint64_t *)args_ptr->iommu_cb2_va + curr_tail / 8; // Downscale the size of the ptr // Copy 0x10 bytes (CMD Size) cmd_buffer[0] = cmd[0]; cmd_buffer[1] = cmd[1]; @@ -224,7 +224,7 @@ iommu_submit_cmd(shellcode_kernel_args *args_ptr, uint64_t *cmd) { // Write 8 bytes to a physical address using IOMMU completion wait store __attribute__((noinline, optimize("O0"))) void -iommu_write8_pa(shellcode_kernel_args *args_ptr, uint64_t pa, uint64_t val) { +iommu_write8_pa(volatile shellcode_kernel_args *args_ptr, uint64_t pa, uint64_t val) { uint32_t cmd[4] = {0}; cmd[0] = (uint32_t)(pa & 0xFFFFFFF8) | 0x05; cmd[1] = ((uint32_t)(pa >> 32) & 0xFFFFF) | 0x10000000; @@ -234,7 +234,7 @@ iommu_write8_pa(shellcode_kernel_args *args_ptr, uint64_t pa, uint64_t val) { } __attribute__((noinline, optimize("O0"))) void -patch_vmcb(shellcode_kernel_args *args_ptr) { +patch_vmcb(volatile shellcode_kernel_args *args_ptr) { for (int i = 0; i < 16; i++) { uint64_t pa = args_ptr->vmcb[i]; // args_ptr->fun_printf("Patching core: %02d VMCB_PA: 0x%016lx\n", i, @@ -281,16 +281,17 @@ __attribute__((noinline, optimize("O0"))) int tmr_disable(uint64_t dmap) { return 0; } -void init_global_pointers(shellcode_kernel_args *args_ptr) { +void init_global_pointers(volatile shellcode_kernel_args *args_ptr) { - memcpy(&args, args_ptr, sizeof(args)); + memcpy(&args, (void *)args_ptr, sizeof(args)); - printf = args.fun_printf; - smp_rendezvous = args.fun_smp_rendezvous; - smp_no_rendevous_barrier = args.fun_smp_no_rendevous_barrier; + printf = (void (*)(const char *, ...)) args.fun_printf; + smp_rendezvous = (void (*)(void (*)(void), void (*)(void), + void (*)(void), void *)) args.fun_smp_rendezvous; + smp_no_rendevous_barrier = (void (*)(void)) args.fun_smp_no_rendevous_barrier; - transmitter_control = args.fun_transmitter_control; - mp3_initialize = args.fun_mp3_initialize; - mp3_invoke = args.fun_mp3_invoke; + transmitter_control = (int (*) (int, void*)) args.fun_transmitter_control; + mp3_initialize = (int (*) (int)) args.fun_mp3_initialize; + mp3_invoke = (int (*) (int, void*, void*)) args.fun_mp3_invoke; g_vbios = args.g_vbios; } \ No newline at end of file diff --git a/shellcode_kernel/main.h b/shellcode_kernel/main.h index 50295fd..3913770 100644 --- a/shellcode_kernel/main.h +++ b/shellcode_kernel/main.h @@ -13,11 +13,8 @@ uint64_t (*kernel_va_to_pa)(uint64_t va); uint32_t (*hv_iommu_set_buffers)(uint64_t cb2_pa, uint64_t cb3_pa, uint64_t eb_pa, uint64_t unk, int *n_devices); uint32_t (*hv_iommu_wait_completion)(void); -void (*smp_rendezvous)(void (*setup_func)(void *), void (*action_func)(void *), - void (*teardown_func)(void *), void *arg); -void (*smp_rendezvous_cpus)(cpuset_t map, void (*setup_func)(void *), - void (*action_func)(void *), - void (*teardown_func)(void *), void *arg); +void (*smp_rendezvous)(void (*setup_func)(void), void (*action_func)(void), + void (*teardown_func)(void), void *arg); void (*smp_no_rendevous_barrier)(void); // We are being called instead of AcpiSetFirmwareWakingVector from @@ -44,8 +41,7 @@ uint64_t rdmsr(uint32_t msr); uint32_t tmr_read(uint64_t dmap, uint32_t addr); void tmr_write(uint64_t dmap, uint32_t addr, uint32_t val); - -int tmr_relax(void); +int tmr_disable(uint64_t dmap); // Command buffer MMIO offsets #define IOMMU_MMIO_CB_HEAD 0xa000 @@ -57,15 +53,16 @@ int tmr_relax(void); #define IOMMU_CMD_ENTRY_SIZE 0x10 // Submit a single 16-byte command and wait for completion -void iommu_submit_cmd(shellcode_kernel_args *args_ptr, uint64_t *cmd); +void iommu_submit_cmd(volatile shellcode_kernel_args *args_ptr, uint64_t *cmd); // Write 8 bytes to a physical address using IOMMU completion wait store -void iommu_write8_pa(shellcode_kernel_args *args_ptr, uint64_t pa, +void iommu_write8_pa(volatile shellcode_kernel_args *args_ptr, uint64_t pa, uint64_t val); -void patch_vmcb(shellcode_kernel_args *args_ptr); +void patch_vmcb(volatile shellcode_kernel_args *args_ptr); #define NULL (void *)0 void vmmcall_dummy(void); void halt(void); +void init_global_pointers(volatile shellcode_kernel_args *args_ptr); #endif \ No newline at end of file diff --git a/shellcode_kernel/utils.c b/shellcode_kernel/utils.c index 69c1cc2..90ea533 100644 --- a/shellcode_kernel/utils.c +++ b/shellcode_kernel/utils.c @@ -60,8 +60,8 @@ uint64_t va_to_pa_custom(uint64_t va, uint64_t cr3_custom) { __attribute__((noinline, optimize("O0"))) uint32_t putc_uart(uint64_t dmap, uint8_t tx_byte) { - volatile uint32_t *uart_tx = dmap + 0xc1010104ULL; - volatile uint32_t *uart_busy = dmap + 0xc101010cULL; + volatile uint32_t *uart_tx = (uint32_t *) (dmap + 0xc1010104ULL); + volatile uint32_t *uart_busy = (uint32_t *) (dmap + 0xc101010cULL); uint64_t timeout = 0xFFFFFFFF; do { timeout--; diff --git a/source/loader.c b/source/loader.c index e4ab277..2f41b44 100644 --- a/source/loader.c +++ b/source/loader.c @@ -91,7 +91,7 @@ long find_and_get_size_of_file(const char *filename, char *found_path) { snprintf(full_path, sizeof(full_path), "%s%s", file_paths[i], filename); if (stat(full_path, &st) == 0) { - printf("File '%s' found in '%s'\n", filename, file_paths[i]); + notify("File '%s' found in '%s'\n", filename, file_paths[i]); strcpy(found_path, full_path); return st.st_size; } @@ -111,7 +111,7 @@ static int find_and_read_file(const char *filename, void *buf, size_t bufsize) { snprintf(full_path, sizeof(full_path), "%s%s", file_paths[i], filename); if (stat(full_path, &st) == 0) { - printf("File '%s' found in '%s'\n", filename, file_paths[i]); + notify("File '%s' found in '%s'\n", filename, file_paths[i]); return read_file(full_path, buf, bufsize); } } @@ -139,9 +139,6 @@ static void trim_newline(char *s) { } int fetch_linux(struct linux_info *info) { - uintptr_t self_pmap = getpmap(kernel_get_proc(getpid())); - uintptr_t self_pml4 = kread64(self_pmap + 0x20); - uintptr_t syscore_pmap = getpmap(kernel_get_proc(MINI_SYSCORE_PID)); uintptr_t syscore_pml4 = kread64(syscore_pmap + 0x20); @@ -150,7 +147,7 @@ int fetch_linux(struct linux_info *info) { size_t bzimage_size = find_and_get_size_of_file("bzImage", bzimage_path); if (bzimage_size < 0) { - printf("File bzImage not found at default paths - Aborting\n"); + notify("File bzImage not found at default paths - Aborting\n"); return -1; } @@ -158,20 +155,20 @@ int fetch_linux(struct linux_info *info) { mmap(NULL, ALIGN_UP(bzimage_size, 0x1000), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); if (bzimage == MAP_FAILED) { - printf("[-] Error could not allocate bzimage.\n"); + notify("[-] Error could not allocate bzimage.\n"); return -1; } bzimage_size = read_file(bzimage_path, bzimage, ALIGN_UP(bzimage_size, 0x1000)); if (bzimage_size < 0) { - printf("Something went wrong while reading bzImage - Aborting\n"); + notify("Something went wrong while reading bzImage - Aborting\n"); return -1; } size_t initrd_size = find_and_get_size_of_file("initrd.img", initrd_path); if (bzimage_size < 0) { - printf("File bzImage not found at default paths - Aborting\n"); + notify("File bzImage not found at default paths - Aborting\n"); return -1; } @@ -179,13 +176,13 @@ int fetch_linux(struct linux_info *info) { mmap(NULL, ALIGN_UP(initrd_size, 0x1000), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); if (initrd == MAP_FAILED) { - printf("[-] Error could not allocate initrd.\n"); + notify("[-] Error could not allocate initrd.\n"); return -1; } initrd_size = read_file(initrd_path, initrd, ALIGN_UP(initrd_size, 0x1000)); if (initrd_size < 0) { - printf("Something went wrong while reading initrd - Aborting\n"); + notify("Something went wrong while reading initrd - Aborting\n"); return -1; } diff --git a/source/main.c b/source/main.c index d5ef32a..ec9f54f 100644 --- a/source/main.c +++ b/source/main.c @@ -10,29 +10,32 @@ int main(void) { if (setup_env()) { - printf("Something went wrong while initiating.\nPlease make sure your fw " + notify("Something went wrong while initiating.\nPlease make sure your fw " "is supported."); return -1; } if (hv_defeat()) { - printf("Something went wrong while defeating Hypervisor.\nPlease make sure " + notify("Something went wrong while defeating Hypervisor.\nPlease make sure " "your fw is supported."); return -1; } if (fetch_linux(&linux_i)) { - printf("Something went wrong while installing linux files.\n"); + notify("Something went wrong while installing linux files.\n"); return -1; } if (prepare_resume()) { - printf("Something went wrong while preparing resume.\n"); + notify("Something went wrong while preparing resume.\n"); return -1; } - printf("Everything done. Go to rest mode, wait for the orange light to stop " + notify("Finished preparation. Going to rest mode in 5 seconds.\nPlease wait for the orange light to stop " "blinking and then wakeup to Linux :)\n"); + sleep(5); + enter_rest_mode(); + while (1) { sleep(30); } @@ -41,7 +44,7 @@ int main(void) { } int setup_env(void) { - printf("Welcome to ps5-linux-loader. We'll defeat HV and prepare the system " + notify("Welcome to ps5-linux-loader. We'll defeat HV and prepare the system " "to boot Linux on sleep resume.\n"); if (set_offsets()) return -1; @@ -145,7 +148,7 @@ int prepare_resume(void) { } } if (offset == -1) { - printf("Could not find offset of args_ptr address - Aborting\n"); + notify("Could not find offset of args_ptr address - Aborting\n"); } kwrite64(dest_text + offset, dest_data); diff --git a/source/offsets.c b/source/offsets.c index 75280af..c90edbb 100644 --- a/source/offsets.c +++ b/source/offsets.c @@ -2,7 +2,6 @@ offset_list off_0300 = { .PMAP_STORE = 0x3D8E218, - .HV_BSS_OFF = 0x16000, .HV_VCPU_ARRAY_OFF = 0x5D0, .HV_VCPU_STRIDE = 0x320, .HV_VCPU_VMCB_PTR = 0x08, @@ -35,7 +34,6 @@ offset_list off_0300 = { offset_list off_0310 = { .PMAP_STORE = 0x3D8E218, - .HV_BSS_OFF = 0x16000, .HV_VCPU_ARRAY_OFF = 0x5D0, .HV_VCPU_STRIDE = 0x320, .HV_VCPU_VMCB_PTR = 0x08, @@ -68,7 +66,6 @@ offset_list off_0310 = { offset_list off_0320 = { .PMAP_STORE = 0x3D8E218, - .HV_BSS_OFF = 0x16000, .HV_VCPU_ARRAY_OFF = 0x5D0, .HV_VCPU_STRIDE = 0x320, .HV_VCPU_VMCB_PTR = 0x08, @@ -101,7 +98,6 @@ offset_list off_0320 = { offset_list off_0321 = { .PMAP_STORE = 0x3D8E218, - .HV_BSS_OFF = 0x16000, .HV_VCPU_ARRAY_OFF = 0x5D0, .HV_VCPU_STRIDE = 0x320, .HV_VCPU_VMCB_PTR = 0x08, @@ -134,7 +130,6 @@ offset_list off_0321 = { offset_list off_0400 = { .PMAP_STORE = 0x3E57A78, - .HV_BSS_OFF = 0x14000, .HV_VCPU_ARRAY_OFF = 0x5D0, .HV_VCPU_STRIDE = 0x320, .HV_VCPU_VMCB_PTR = 0x08, @@ -167,7 +162,6 @@ offset_list off_0400 = { offset_list off_0402 = { .PMAP_STORE = 0x3E57A78, - .HV_BSS_OFF = 0x14000, .HV_VCPU_ARRAY_OFF = 0x5D0, .HV_VCPU_STRIDE = 0x320, .HV_VCPU_VMCB_PTR = 0x08, @@ -200,7 +194,6 @@ offset_list off_0402 = { offset_list off_0403 = { .PMAP_STORE = 0x3E57A78, - .HV_BSS_OFF = 0x14000, .HV_VCPU_ARRAY_OFF = 0x5D0, .HV_VCPU_STRIDE = 0x320, .HV_VCPU_VMCB_PTR = 0x08, @@ -233,7 +226,6 @@ offset_list off_0403 = { offset_list off_0450 = { .PMAP_STORE = 0x3E57A78, - .HV_BSS_OFF = 0x14000, .HV_VCPU_ARRAY_OFF = 0x5D0, .HV_VCPU_STRIDE = 0x320, .HV_VCPU_VMCB_PTR = 0x08, @@ -266,7 +258,6 @@ offset_list off_0450 = { offset_list off_0451 = { .PMAP_STORE = 0x3E57A78, - .HV_BSS_OFF = 0x14000, .HV_VCPU_ARRAY_OFF = 0x5D0, .HV_VCPU_STRIDE = 0x320, .HV_VCPU_VMCB_PTR = 0x08, diff --git a/source/utils.c b/source/utils.c index 62f29aa..3f3e18c 100644 --- a/source/utils.c +++ b/source/utils.c @@ -99,7 +99,6 @@ uint64_t va_to_pa_custom(uint64_t va, uint64_t cr3_custom) { int shift = 39 - (level * 9); uint64_t idx = (va >> shift) & 0x1FF; uint64_t entry; - uint64_t entry_va = dmap + PAGE_PA(table_phys) + idx * 8; kread(dmap + PAGE_PA(table_phys) + idx * 8, &entry, sizeof(entry)); @@ -216,4 +215,36 @@ int pin_to_first_available_core(void) { void unpin(void) { uint64_t m[2] = {0xFFFF, 0}; cpuset_setaffinity(3, 1, -1, 0x10, (const cpuset_t *)m); +} + +void notify(const char *fmt, ...) { + static char buffer[2048]; + va_list args; + + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + + notify_internal(buffer); + printf(buffer); +} + +void notify_internal(uint8_t *msg) { + struct { + char pad[45]; + char msg[3075]; + } req; + bzero(&req, sizeof(req)); + uint64_t len = + strlen(msg) < (sizeof(req.msg) - 1) ? strlen(msg) : (sizeof(req.msg) - 1); + memcpy(req.msg, msg, len); + sceKernelSendNotificationRequest(0, &req, sizeof(req), 0); +} + +void enter_rest_mode(void) { + void *event = NULL; + sceKernelOpenEventFlag(&event, "SceSystemStateMgrStatus"); + sceKernelNotifySystemSuspendStart(); + sceKernelSetEventFlag(event, 0x400); + sceKernelCloseEventFlag(&event); } \ No newline at end of file