Kernel mode
This is the biggie. You can't currently use any kernel-mode features in v2.0 homebrew. Here's what that means in practice:
- You can request kernel-mode (in the PSPSDK, this means that the second argument to MODULE_INFO() is '0x1000'), so long as you don't break any of the rules below. The loader will attempt to automatically patch up your app to remove typical 'unnecessary' kernel access (e.g. stdio handlers, exception handlers) that cannot be supported in user mode. This also usually means that your init() function will not get called. Preferably, you should use user-mode, to avoid any problems, but this level of kernel-mode tolerance means that you can usually get away with using a single source for 1.5 and 2.0, with better debugging support etc. on the 1.5 platform.
- You can use wi-fi, so long as the users use the special wifi hack for the loader. If you are going to use wifi, you should use the new PSPSDK support for loading the network modules, because the loader can automatically patch this when starting the app. PSPPet's wifi sample code will also usually work, depending on how heavily you modified it. Other methods for starting the network modules may not be supported.
- You can use stdio stream handlers, but they won't have any effect.
- You can install exception handlers, but they won't have any effect.
- You can't access kernel-space memory.
The environment when running under v2.0 is pretty close to that under v1.5 - once loaded, your app will make system calls in exactly the same way, will be loaded in memory in exactly the same place, etc. There are some small differences you might want to be aware of, because these can help improve your stability on 2.0.
- Memory allocation: The environment that the loader starts in has a restricted global heap, with only approx 3Mb left in the official sceKernelAllocPartitionMemory() user partition (#2). Because of this, the loader hooks the memory management APIs, and uses any spare RAM not being used by the program code to provide an additional pool. Typically this gives an average-sized app approx another 16Mb to use.
Access to this memory is transparent to your app, so long as you use the standard sceKernelAllocPartitionMemory calls, as before. (The extra memory is added to partition 2, so you don't need to change any parameters). A few notes:- Alloc calls will be offered to the official Alloc API first. The extra pool is only used if the API can't satisfy the alloc request.
- The extra pool only supports the 'allocate from lowest memory' option.
- Re-merge handling of freed memory is limited. Freeing anything except the most-recently allocated memory from the extra pool will result in a leak.
- It seems that libnewlibc provides its own malloc manager, rather than passing calls directly to the Sony API. It allocates the largest single memory block available at initialisation (this will be the entire extra pool), and services mallocs from that block. So, if you want the maximum available RAM, it is probably best to use sceKernelAllocPartitionMe mory() etc. rather than malloc, when running with libnewlibc.
- Thread management : The loader also hooks some thread management calls (sceKernelRunThread(), sceKernelExitThread(), etc.) so that it can keep track of whether the app has exited.
General tips
A few general coding tips, to make it easier for people running your code under v2.0:- Although there's handling in place in the loader to check for hard-coded file paths, and warn the user, it's best to avoid these altogether. Various development libraries provide support for relative (rather than absolute) file paths, and even if you're not using one of those, you can easily make your app use relative paths by checking argv[0] in main() : this will contain the full absolute path to your EBOOT.PBP file, so you can process this to build the correct absolute paths to your files without having to assume that your app will be installed in a specific path.
- Make sure you're using the latest PSPSDK toolchain, because that's the version the loader is usually tested against. Older versions of the SDK may use different startup code, which may not behave quite as expected under 2.0.
- Try to use a unique module name in the MODULE_INFO() statement. This helps to distinguish between apps for special case handling. There are an awful lot of apps that still use "HelloWorld" or "SDKSample" or similar as their module name.
- Include an alternative way to exit your app, rather than relying just on the HOME button. HOME doesn't work on v2.0 homebrew (yet), and the available workaround has limitations. Far better to have a menu option that just calls SceExitGame().