Okay, let's review the high points of the nanddumper example app...
First, let's start with the external prx. This is no more than a library to be loaded and called by the main app. ALL kernel code must go into these for 3.xx. Here's the main.c file for the nanddumper.prx:
main.c
Code: Select all
#include <pspsdk.h>
#include <pspkernel.h>
#include <pspnand_driver.h>
#include <string.h>
PSP_MODULE_INFO("NandDumper", 0x1006, 1, 1);
PSP_MAIN_THREAD_ATTR(0);
int nandLocked = 0;
void LockNand()
{
if (!nandLocked)
sceNandLock(0);
nandLocked = 1;
}
void UnlockNand()
{
if (nandLocked)
sceNandUnlock();
nandLocked = 0;
}
int ReadBlock(u32 page, u8 *buffer)
{
u32 i, j;
u32 k1;
k1 = pspSdkSetK1(0);
LockNand();
if (sceNandIsBadBlock(page))
{
memset(buffer, 0xFF, 528);
UnlockNand();
pspSdkSetK1(k1);
return -1;
}
for (i = 0; i < 32; i++)
{
for (j = 0; j < 4; j++)
{
sceNandReadPagesRawAll(page, buffer, NULL, 1);
sceNandReadExtraOnly(page, buffer+512, 1);
}
page++;
buffer += 528;
}
UnlockNand();
pspSdkSetK1(k1);
return 0;
}
int module_start(SceSize args, void *argp)
{
return 0;
}
int module_stop()
{
return 0;
}
Notice its header:
Code: Select all
PSP_MODULE_INFO("NandDumper", 0x1006, 1, 1);
PSP_MAIN_THREAD_ATTR(0);
This shows this is a kernel mode prx. Notice how it has module_start() and module_stop(), both needed for external libs. Notice how it has a number of functions and no main() entry point. Notice the use of pspSdkSetK1(). Setting K1 to 0 around functions prevents the kernel from faulting when accessing areas like user-mode memory.
Its makefile appears this way:
makefile
Code: Select all
TARGET = nanddumper
OBJS = main.o
INCDIR =
CFLAGS = -O2 -G0 -Wall
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)
BUILD_PRX = 1
PRX_EXPORTS = nanddumper.exp
USE_KERNEL_LIBC=1
USE_KERNEL_LIBS=1
LIBDIR =
LDFLAGS = -mno-crt0 -nostartfiles
LIBS = -lpspnand_driver2
PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak
Notice how it uses no-crt0 and nostartfiles... that's because this is a plain lib, not an app. It doesn't need either of those. Notice the use of the kernel libs. Notice that there is a file called "nanddumper.exp" - that is where you declare which functions are seen externally when this prx is loaded.
Here's what that file looks like:
nanddumper.exp
Code: Select all
# Define the exports for the prx
PSP_BEGIN_EXPORTS
# These four lines are mandatory (although you can add other functions like module_stop)
# syslib is a psynonym for the single mandatory export.
PSP_EXPORT_START(syslib, 0, 0x8000)
PSP_EXPORT_FUNC_HASH(module_start)
PSP_EXPORT_VAR_HASH(module_info)
PSP_EXPORT_END
PSP_EXPORT_START(NandDumper, 0, 0x4001)
PSP_EXPORT_FUNC(ReadBlock)
PSP_EXPORT_END
PSP_END_EXPORTS
The lines must always be like that except for the PSP_EXPORT_FUNC() lines. That is where you set the exported functions from this lib. Oh, the NandDumper in the start line should match the NandDumper in the PSP_MODULE_INFO in main.c. Change both identically to make a different name. This file is also used to generate the .S file that you use in the main app to access these functions. To make the .S file, from a shell set to the directory with these files, run
Code: Select all
psp-build-exports -s nanddumper.exp
Copy that .S file to the same directory as the source for the main app, along with the .prx file you get when you run make.
That is all you do for the prx part. The above gives you a kernel-mode lib that does all the stuff you need via exported functions. Now let's move on to the main app.
main.c
Code: Select all
#include <pspsdk.h>
#include <pspkernel.h>
#include <stdio.h>
#include <string.h>
PSP_MODULE_INFO("NandDumperMain", 0, 1, 0);
PSP_MAIN_THREAD_ATTR(PSP_THREAD_ATTR_USER);
u8 block[32*32*528];
int ReadBlock(u32 page, u8 *buffer);
#define printf pspDebugScreenPrintf
int main()
{
pspDebugScreenInit();
SceUID mod = pspSdkLoadStartModule("nanddumper.prx", PSP_MEMORY_PARTITION_KERNEL);
if (mod < 0)
{
printf("Error 0x%08X loading/starting naddumper.prx.\n", mod);
}
else
{
SceUID fd = sceIoOpen("ms0:/nanddump.flash", PSP_O_WRONLY | PSP_O_CREAT | PSP_O_TRUNC, 0777);
printf("Dumping...\n");
int i, j;
for (i = 0; i < (2048*32); )
{
u8 *p = block;
memset(block, 0xff, sizeof(block));
for (j = 0; j < 32; j++)
{
if (ReadBlock(i, p) < 0)
{
printf("bad block at page %d block %d\n", i, i/32);
}
i += 32;
p += (528*32);
}
sceIoWrite(fd, block, sizeof(block));
}
sceIoClose(fd);
printf("Done. Exiting in 5 seconds\n");
}
sceKernelDelayThread(5*1000*1000);
sceKernelExitGame();
return 0;
}
Notice the header.
Code: Select all
PSP_MODULE_INFO("NandDumperMain", 0, 1, 0);
PSP_MAIN_THREAD_ATTR(PSP_THREAD_ATTR_USER);
This is a user-mode app. That is what you need for HEN and 3.xx on the slim. You may also need to set the heap size if you need to allocate lots of memory in the app. That would be done by putting a line after the above two lines that looks like this:
That sets the size of the heap in kBytes. So that line sets it to about 2.5 MB. Notice that the app also has declarations for all the functions that will be imported, as so:
Code: Select all
int ReadBlock(u32 page, u8 *buffer);
Note how the prx is loaded:
Code: Select all
SceUID mod = pspSdkLoadStartModule("nanddumper.prx", PSP_MEMORY_PARTITION_KERNEL);
Notice in that line how it's loaded into the kernel partition since it's a kernel mode lib. Also notice that you simply call the functions as normal. The .S file function entries will take care of switching back and forth between user and kernel mode.
DON'T FORGET!! All created threads must be USER threads. Set the attr arg in the createthread function to PSP_THREAD_ATTR_USER!
Now look at the makefile:
makefile
Code: Select all
release: all
mksfo 'NandDumper' PARAM.SFO
pack-pbp EBOOT.PBP PARAM.SFO NULL NULL NULL NULL NULL nanddumpermain.prx NULL
TARGET = nanddumpermain
OBJS = main.o NandDumper.o
INCDIR =
CFLAGS = -O2 -Wall
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)
BUILD_PRX = 1
LIBDIR =
LIBS =
LDFLAGS =
PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak
That's an "old-style" makefile as seen from it's use of mksfo and pack-pbp. You can instead use the newer makefile style as such:
makefile
Code: Select all
TARGET = nanddumpermain
OBJS = main.o NandDumper.o
INCDIR =
CFLAGS = -O2 -G0 -Wall
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)
BUILD_PRX = 1
LIBDIR =
LIBS =
LDFLAGS =
EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = NandDumper
PSP_EBOOT_ICON="icon0.png"
PSP_EBOOT_PIC1="pic1.png"
PSP_EBOOT_SND0="snd0.at3"
PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak
Note how the new style doesn't directly use mksfo or pack-pbp, but uses EXTRA_TARGETS and PSP_EBOOT_XXXX instead. It's equivalent, but easier to specify without goofing up the arguments to mksfo or pack-pbp. All those PSP_EBOOT_XXXX lines are optional.
Note that the makefile has "BUILD_PRX = 1". That seems to be the key for getting it to run as a 3xx app. notice how the .S file is included in the object list.
Doing all this gives you the two files you want: nanddumper.prx (the external prx library) and EBOOT.PBP (the main app). Copy those to a folder in PSP/GAME/ and you're all set.
I hope this brief review has given you some insight into how you make a user-mode app which call a kernel mode external library.