Suspend

From Vita Development Wiki
Jump to navigation Jump to search

When the system is suspended, it enters a low power state where the main application processor is turned off. The main DRAM state is preserved so upon resume, the kernel does not have to be reloaded.

Suspending

To suspend the system, the Vita saves the current context into a buffer and sends it to the syscon. Then it issues a syscon request to enter the low-power state.

Context Buffer

Offset Size Description
0x0 0x4 Size of buffer (0x68)
0x4 0x4 Same as unk field of syscon_reset_device call
0x8 0x4 Some virtual address of buffer (unused?)
0xC 0x4 Virtual address of resume function with the following args:
(u32 TTBR1, u32 CONTEXTIDR, u32 DACR)
0x10 0x4 Saved SCTLR
0x14 0x4 Saved ACTLR
0x18 0x4 Saved CPACR
0x1C 0x4 Saved TTBR0
0x20 0x4 Saved TTBR1
0x24 0x4 Saved TTBCR
0x28 0x4 Saved DACR
0x2C 0x4 Saved PRRR
0x30 0x4 Saved NMRR
0x34 0x4 Saved VBAR
0x38 0x4 Saved CONTEXTIDR
0x3C 0x4 Saved TPIDRURW
0x40 0x4 Saved TPIDRURO
0x44 0x4 Saved TPIDRPRW
0x48 0x18 Unknown/unused
0x60 0x8 System time

Saving Context

The context buffer defined above is built and the physical address of the buffer is sent to the Syscon with command 12. It calls Send command with syscon_send_command(12, &paddr, 4). Then it issues the command to suspend the device.

Resuming

Upon power up, the Boot Sequence is the same until the point where the secure kernel loader would jump into the non-secure kernel loader at 0x51000000. Instead, it copies the context resume function to the scratch buffer at 0x1F000000 and the context buffer to 0x1F001000. The resume function clears the caches and then enables the MMU. Next, it uses the context buffer to restore CP15 registers that were saved. On 1.69, it does not seem to restore ACTLR, TTBR1, or DACR. After the CP15 registers are restored, the translation tables should be restored and it then calls the resume function.

Rebooting with Patches

By abusing the way resume works, we can reboot the device into a custom firmware by patching the non-secure kernel loader. The general framework to do this is (enso): first, patch the non-secure kernel bootloader in RAM to accept unsigned SELFs and load a custom skprx after psp2bootconfig.skprx. It could be the case that by the time your exploit runs the DRAM region containing the kernel loader has been wiped (enso) / reused (webkit). If so, you must use a lower level exploit (shell exploit / h-encore) to dump the loader. It may even be possible to dump the compressed version of the NSBL, in that case you wouldn't even need to perform cleanup. Your custom skrpx (taihen.skprx) will be loaded after the bare essential kernel libraries are loaded (memory management, threads, file IO, etc) and it can then patch the full module loader to accept unsigned SELFs as well as any other patches (henkaku.skprx).

Cleaning up Bootloader

Ideally, if we can get the original compressed version of the non-secure bootloader that is extracted from kernel_boot_loader.self, we can load that to memory and jump to it from our resume function. However, by the time the system is in a state we control, usually that data would be corrupted. What we are left with is the non-secure kernel loader in the state after bootup is completed. In order to get it to run successfully again in our resume function, we need to clean up the data it uses.

1.50 cleanup

Physical Address Size Data Notes
0x51002024 0x4 0x0 Interrupt registering returns error if not 0
0x5100203C 0x4 0x0 Interrupt registering returns error if not 0
0x5100205C 0x4 0x0 Interrupt registering returns error if not 0
0x51002074 0x4 0x0 Interrupt registering returns error if not 0
0x51002090 0x4 0x0 Interrupt registering returns error if not 0
0x510020D0 0x4 0x0 Interrupt registering returns error if not 0
0x51002110 0x4 0x0 Interrupt registering returns error if not 0
0x510021A4 0x4 0x0 Interrupt registering returns error if not 0
0x510023FC 0x4 0x0 Interrupt registering returns error if not 0
0x51002604 0x4 0x0 Interrupt registering returns error if not 0
0x51002A40 0x4 0x0 Interrupt registering returns error if not 0
0x5102A014 0x4 0x0 Eventually gets some pointer
0x5102A020 0x4 0x1 Read Block Count (start at 1)
0x5102A024 0x4 0x1 Set to 0 after psp2bootconfig.skprx loads for hacky lock handling
0x5102A02C 0x4 0xFFFFFFFF Memory block id after allocation
0x5102A030 0x4 0x600BF34C Random number set after each boot to ensure integrity
0x5102A034 0x4 0xFF Boot State ID
0x5102A050 0x4 0xFFFFFFFF Memory block id after allocation
0x40300100 0x100 Sysroot data Sysroot buffer copied from vaddr 0x46C0

1.69 cleanup

Physical Address Size Data Notes
0x51002A40 0x4 0x0 Interrupt registering returns error if not 0
0x51002024 0x4 0x0 Interrupt registering returns error if not 0
0x5100203C 0x4 0x0 Interrupt registering returns error if not 0
0x5100205C 0x4 0x0 Interrupt registering returns error if not 0
0x51002074 0x4 0x0 Interrupt registering returns error if not 0
0x51002118 0x4 0x0 Interrupt registering returns error if not 0
0x510020D4 0x4 0x0 Interrupt registering returns error if not 0
0x51002090 0x4 0x0 Interrupt registering returns error if not 0
0x51002614 0x4 0x0 Interrupt registering returns error if not 0
0x5100240C 0x4 0x0 Interrupt registering returns error if not 0
0x510021B4 0x4 0x0 Interrupt registering returns error if not 0
0x5102A02C 0x4 0xFFFFFFFF Memory block id after allocation
0x5102A050 0x4 0xFFFFFFFF Memory block id after allocation
0x5102A030 0x4 0x600BF34C Random number set after each boot to ensure integrity
0x5102A024 0x4 0x1 Set to 0 after psp2bootconfig.skprx loads for hacky lock handling
0x40300100 0x100 Sysroot data Sysroot buffer copied from vaddr 0x46C0